- Better support for READ-ONLY and NOPERM responses handling (#1487083)

- Add confirmation message on purge/expunge commands response
- Fix CLOSE was called on unselected mailbox
release-0.6
alecpl 14 years ago
parent 5be0d000ac
commit 90f81a6c8d

@ -16,6 +16,8 @@ CHANGELOG Roundcube Webmail
- Improve performance of moving or copying of all messages in a folder
- Fix plaintext versions of HTML messages don't contain placeholders for emotions (#1485206)
- Improve performance of folder rename and delete actions
- Better support for READ-ONLY and NOPERM responses handling (#1487083)
- Add confirmation message on purge/expunge command response
RELEASE 0.5-BETA
----------------

@ -1615,6 +1615,38 @@ function rcmail_quota_content($attrib=NULL)
}
/**
* Outputs error message according to server error/response codes
*
* @param string Fallback message label
* @param string Fallback message label arguments
*
* @return void
*/
function rcmail_display_server_error($fallback=null, $fallback_args=null)
{
global $RCMAIL;
$err_code = $RCMAIL->imap->get_error_code();
$res_code = $RCMAIL->imap->get_response_code();
if ($res_code == rcube_imap::NOPERM) {
$RCMAIL->output->show_message('errornoperm', 'error');
}
else if ($res_code == rcube_imap::READONLY) {
$RCMAIL->output->show_message('errorreadonly', 'error');
}
else if ($err_code && ($err_str = $RCMAIL->imap->get_error_str())) {
$RCMAIL->output->show_message('servererrormsg', 'error', array('msg' => $err_str));
}
else if ($fallback) {
$RCMAIL->output->show_message($fallback, 'error', $fallback_args);
}
return true;
}
/**
* Output HTML editor scripts
*

@ -100,6 +100,16 @@ class rcube_imap
'RETURN-PATH',
);
const UNKNOWN = 0;
const NOPERM = 1;
const READONLY = 2;
const TRYCREATE = 3;
const INUSE = 4;
const OVERQUOTA = 5;
const ALREADYEXISTS = 6;
const NONEXISTENT = 7;
const CONTACTADMIN = 8;
/**
* Object constructor
@ -220,7 +230,51 @@ class rcube_imap
*/
function get_error_str()
{
return ($this->conn) ? $this->conn->error : '';
return ($this->conn) ? $this->conn->error : null;
}
/**
* Returns code of last command response
*
* @return int Response code
*/
function get_response_code()
{
if (!$this->conn)
return self::UNKNOWN;
switch ($this->conn->resultcode) {
case 'NOPERM':
return self::NOPERM;
case 'READ-ONLY':
return self::READONLY;
case 'TRYCREATE':
return self::TRYCREATE;
case 'INUSE':
return self::INUSE;
case 'OVERQUOTA':
return self::OVERQUOTA;
case 'ALREADYEXISTS':
return self::ALREADYEXISTS;
case 'NONEXISTENT':
return self::NONEXISTENT;
case 'CONTACTADMIN':
return self::CONTACTADMIN;
default:
return self::UNKNOWN;
}
}
/**
* Returns last command response
*
* @return string Response
*/
function get_response_str()
{
return ($this->conn) ? $this->conn->result : null;
}
@ -295,9 +349,9 @@ class rcube_imap
* @param string $mailbox Mailbox/Folder name
* @access public
*/
function select_mailbox($mailbox)
function select_mailbox($mailbox=null)
{
$mailbox = $this->mod_mailbox($mailbox);
$mailbox = strlen($mailbox) ? $this->mod_mailbox($mailbox) : $this->mailbox;
$selected = $this->conn->select($mailbox);
@ -2769,6 +2823,18 @@ class rcube_imap
else
$a_uids = NULL;
// force mailbox selection and check if mailbox is writeable
// to prevent a situation when CLOSE is executed on closed
// or EXPUNGE on read-only mailbox
$result = $this->conn->select($mailbox);
if (!$result) {
return false;
}
if (!$this->conn->data['READ-WRITE']) {
$this->conn->setError(rcube_imap_generic::ERROR_READONLY, "Mailbox is read-only");
return false;
}
// CLOSE(+SELECT) should be faster than EXPUNGE
if (empty($a_uids) || $a_uids == '1:*')
$result = $this->conn->close();

@ -85,6 +85,8 @@ class rcube_imap_generic
{
public $error;
public $errornum;
public $result;
public $resultcode;
public $data = array();
public $flags = array(
'SEEN' => '\\Seen',
@ -112,8 +114,9 @@ class rcube_imap_generic
const ERROR_NO = -1;
const ERROR_BAD = -2;
const ERROR_BYE = -3;
const ERROR_COMMAND = -5;
const ERROR_UNKNOWN = -4;
const ERROR_COMMAND = -5;
const ERROR_READONLY = -6;
const COMMAND_NORESPONSE = 1;
const COMMAND_CAPABILITY = 2;
@ -302,7 +305,7 @@ class rcube_imap_generic
$str = trim($matches[2]);
if ($res == 'OK') {
return $this->errornum = self::ERROR_OK;
$this->errornum = self::ERROR_OK;
} else if ($res == 'NO') {
$this->errornum = self::ERROR_NO;
} else if ($res == 'BAD') {
@ -313,15 +316,29 @@ class rcube_imap_generic
$this->errornum = self::ERROR_BYE;
}
if ($str)
$this->error = $err_prefix ? $err_prefix.$str : $str;
if ($str) {
$str = trim($str);
// get response string and code (RFC5530)
if (preg_match("/^\[([a-z-]+)\]/i", $str, $m)) {
$this->resultcode = strtoupper($m[1]);
$str = trim(substr($str, strlen($m[1]) + 2));
}
else {
$this->resultcode = null;
}
$this->result = $str;
if ($this->errornum != self::ERROR_OK) {
$this->error = $err_prefix ? $err_prefix.$str : $str;
}
}
return $this->errornum;
}
return self::ERROR_UNKNOWN;
}
private function setError($code, $msg='')
function setError($code, $msg='')
{
$this->errornum = $code;
$this->error = $msg;
@ -838,6 +855,8 @@ class rcube_imap_generic
}
}
$this->data['READ-WRITE'] = $this->resultcode != 'READ-ONLY';
$this->selected = $mailbox;
return true;
}
@ -906,6 +925,11 @@ class rcube_imap_generic
return false;
}
if (!$this->data['READ-WRITE']) {
$this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'EXPUNGE');
return false;
}
// Clear internal status cache
unset($this->data['STATUS:'.$mailbox]);
@ -1001,11 +1025,15 @@ class rcube_imap_generic
{
$num_in_trash = $this->countMessages($mailbox);
if ($num_in_trash > 0) {
$this->delete($mailbox, '1:*');
$res = $this->delete($mailbox, '1:*');
}
$res = $this->close();
// $res = $this->expunge($mailbox);
if ($res) {
if ($this->selected == $mailbox)
$res = $this->close();
else
$res = $this->expunge($mailbox);
}
return $res;
}
@ -1715,6 +1743,11 @@ class rcube_imap_generic
return false;
}
if (!$this->data['READ-WRITE']) {
$this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE');
return false;
}
// Clear internal status cache
if ($flag == 'SEEN') {
unset($this->data['STATUS:'.$mailbox]['UNSEEN']);
@ -1758,6 +1791,15 @@ class rcube_imap_generic
function move($messages, $from, $to)
{
if (!$this->select($from)) {
return false;
}
if (!$this->data['READ-WRITE']) {
$this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE');
return false;
}
$r = $this->copy($messages, $from, $to);
if ($r) {
@ -2963,9 +3005,9 @@ class rcube_imap_generic
$this->parseCapability($matches[1], true);
}
// return last line only (without command tag and result)
// return last line only (without command tag, result and response code)
if ($line && ($options & self::COMMAND_LASTLINE)) {
$response = preg_replace("/^$tag (OK|NO|BAD|BYE|PREAUTH)?\s*/i", '', trim($line));
$response = preg_replace("/^$tag (OK|NO|BAD|BYE|PREAUTH)?\s*(\[[a-z-]+\])?\s*/i", '', trim($line));
}
return $noresp ? $code : array($code, $response);

@ -24,6 +24,8 @@ $messages['sessionerror'] = 'Your session is invalid or expired';
$messages['imaperror'] = 'Connection to IMAP server failed';
$messages['servererror'] = 'Server Error!';
$messages['servererrormsg'] = 'Server Error: $msg';
$messages['errorreadonly'] = 'Unable to perform operation. Folder is read-only';
$messages['errornoperm'] = 'Unable to perform operation. Permission denied';
$messages['invalidrequest'] = 'Invalid request! No data was saved.';
$messages['nomessagesfound'] = 'No messages found in this mailbox';
$messages['loggedout'] = 'You have successfully terminated the session. Good bye!';
@ -81,6 +83,7 @@ $messages['folderdeleted'] = 'Folder successfully deleted';
$messages['foldersubscribed'] = 'Folder successfully subscribed';
$messages['folderunsubscribed'] = 'Folder successfully unsubscribed';
$messages['folderpurged'] = 'Folder successfully purged';
$messages['folderexpunged'] = 'Folder successfully emptied';
$messages['deletedsuccessfully'] = 'Successfully deleted';
$messages['converting'] = 'Removing formatting...';
$messages['messageopenerror'] = 'Could not load message from server';

@ -135,9 +135,12 @@ $messages['folderunsubscribing'] = 'Odsubskrybowanie folderu...';
$messages['foldersubscribed'] = 'Folder pomyślnie zasubskrybowany';
$messages['folderunsubscribed'] = 'Folder pomyślnie odsubskrybowany';
$messages['folderpurged'] = 'Folder pomyślnie wyczyszczony';
$messages['folderexpunged'] = 'Folder pomyślnie opróżniony';
$messages['namecannotbeempty'] = 'Nazwa nie może być pusta';
$messages['nametoolong'] = 'Name jest zbyt długa';
$messages['folderupdated'] = 'Folder pomyślnie zaktualizowany';
$messages['foldercreated'] = 'Folder pomyślnie utworzony';
$messages['errorreadonly'] = 'Nie można wykonać operacji. Folder tylko do odczytu';
$messages['errornoperm'] = 'Nie można wykonać operacji. Brak uprawnień';
?>

@ -33,7 +33,7 @@ if (!empty($_POST['_uid']) && !empty($_POST['_target_mbox'])) {
if (!$copied) {
// send error message
$OUTPUT->show_message('errorcopying', 'error');
rcmail_display_server_error('errorcopying');
$OUTPUT->send();
exit;
}
@ -52,5 +52,3 @@ else {
// send response
$OUTPUT->send();

@ -20,55 +20,61 @@
// only process ajax requests
if (!$OUTPUT->ajax_call)
return;
return;
$mbox = get_input_value('_mbox', RCUBE_INPUT_POST, true);
// send EXPUNGE command
if ($RCMAIL->action=='expunge')
{
$success = $IMAP->expunge($mbox);
if ($RCMAIL->action == 'expunge') {
// reload message list if current mailbox
if ($success && !empty($_REQUEST['_reload']))
{
$OUTPUT->command('set_quota', rcmail_quota_content());
$OUTPUT->command('message_list.clear');
$RCMAIL->action = 'list';
return;
}
else
$commands = "// expunged: $success\n";
$success = $IMAP->expunge($mbox);
// reload message list if current mailbox
if ($success) {
$OUTPUT->show_message('folderexpunged', 'confirmation');
if (!empty($_REQUEST['_reload'])) {
$OUTPUT->command('set_quota', rcmail_quota_content());
$OUTPUT->command('message_list.clear');
$RCMAIL->action = 'list';
return;
}
}
else {
rcmail_display_server_error();
}
}
// clear mailbox
else if ($RCMAIL->action=='purge')
else if ($RCMAIL->action == 'purge')
{
$delimiter = $IMAP->get_hierarchy_delimiter();
$trash_regexp = '/^' . preg_quote($CONFIG['trash_mbox'] . $delimiter, '/') . '/';
$junk_regexp = '/^' . preg_quote($CONFIG['junk_mbox'] . $delimiter, '/') . '/';
$delimiter = $IMAP->get_hierarchy_delimiter();
$trash_regexp = '/^' . preg_quote($CONFIG['trash_mbox'] . $delimiter, '/') . '/';
$junk_regexp = '/^' . preg_quote($CONFIG['junk_mbox'] . $delimiter, '/') . '/';
// we should only be purging trash and junk (or their subfolders)
if ($mbox == $CONFIG['trash_mbox'] || $mbox == $CONFIG['junk_mbox']
|| preg_match($trash_regexp, $mbox) || preg_match($junk_regexp, $mbox)
) {
$success = $IMAP->clear_mailbox($mbox);
// we should only be purging trash and junk (or their subfolders)
if ($mbox == $CONFIG['trash_mbox'] || $mbox == $CONFIG['junk_mbox']
|| preg_match($trash_regexp, $mbox) || preg_match($junk_regexp, $mbox))
{
$success = $IMAP->clear_mailbox($mbox);
if ($success) {
$OUTPUT->show_message('folderpurged', 'confirmation');
if ($success && !empty($_REQUEST['_reload']))
{
$OUTPUT->set_env('messagecount', 0);
$OUTPUT->set_env('pagecount', 0);
$OUTPUT->command('message_list.clear');
$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text());
$OUTPUT->command('set_unread_count', $mbox, 0);
$OUTPUT->command('set_quota', rcmail_quota_content());
rcmail_set_unseen_count($mbox, 0);
if (!empty($_REQUEST['_reload'])) {
$OUTPUT->set_env('messagecount', 0);
$OUTPUT->set_env('pagecount', 0);
$OUTPUT->command('message_list.clear');
$OUTPUT->command('set_rowcount', rcmail_get_messagecount_text());
$OUTPUT->command('set_unread_count', $mbox, 0);
$OUTPUT->command('set_quota', rcmail_quota_content());
rcmail_set_unseen_count($mbox, 0);
}
}
else {
rcmail_display_server_error();
}
}
else
$commands = "// purged: $success";
}
}
$OUTPUT->send($commands);
$OUTPUT->send();

@ -106,8 +106,7 @@ if (isset($a_headers) && count($a_headers))
else {
// handle IMAP errors (e.g. #1486905)
if ($err_code = $IMAP->get_error_code()) {
$err_str = $IMAP->get_error_str();
$OUTPUT->show_message('servererrormsg', 'error', array('msg' => $err_str));
rcmail_display_server_error();
}
else if ($search_request)
$OUTPUT->show_message('searchnomatch', 'notice');

@ -47,7 +47,7 @@ if (($uids = get_input_value('_uid', RCUBE_INPUT_POST)) && ($flag = get_input_va
// send error message
if ($_POST['_from'] != 'show')
$OUTPUT->command('list_mailbox');
$OUTPUT->show_message('errormarking', 'error');
rcmail_display_server_error('errormarking');
$OUTPUT->send();
exit;
}

@ -39,7 +39,7 @@ if ($RCMAIL->action=='moveto' && !empty($_POST['_uid']) && strlen($_POST['_targe
// send error message
if ($_POST['_from'] != 'show')
$OUTPUT->command('list_mailbox');
$OUTPUT->show_message('errormoving', 'error');
rcmail_display_server_error('errormoving');
$OUTPUT->send();
exit;
}
@ -60,7 +60,7 @@ else if ($RCMAIL->action=='delete' && !empty($_POST['_uid'])) {
// send error message
if ($_POST['_from'] != 'show')
$OUTPUT->command('list_mailbox');
$OUTPUT->show_message('errordeleting', 'error');
rcmail_display_server_error('errordeleting');
$OUTPUT->send();
exit;
}

@ -124,8 +124,7 @@ if (!empty($result_h)) {
}
// handle IMAP errors (e.g. #1486905)
else if ($err_code = $IMAP->get_error_code()) {
$err_str = $IMAP->get_error_str();
$OUTPUT->show_message('servererrormsg', 'error', array('msg' => $err_str));
rcmail_display_server_error();
}
else {
$OUTPUT->show_message('searchnomatch', 'notice');

@ -34,7 +34,7 @@ if ($RCMAIL->action == 'subscribe')
// Handle virtual (non-existing) folders
if (!$result && $IMAP->get_error_code() == -1 &&
strpos($IMAP->get_error_str(), '[TRYCREATE]')
$IMAP->get_response_code() == rcube_imap::TRYCREATE
) {
$result = $IMAP->create_mailbox($mbox, true);
if ($result) {
@ -45,7 +45,7 @@ if ($RCMAIL->action == 'subscribe')
if ($result)
$OUTPUT->show_message('foldersubscribed', 'confirmation');
else
$OUTPUT->show_message('errorsaving', 'error');
rcmail_display_server_error('errorsaving');
}
}
@ -58,7 +58,7 @@ else if ($RCMAIL->action == 'unsubscribe')
if ($result)
$OUTPUT->show_message('folderunsubscribed', 'confirmation');
else
$OUTPUT->show_message('errorsaving', 'error');
rcmail_display_server_error('errorsaving');
}
}
@ -92,7 +92,7 @@ else if ($RCMAIL->action == 'delete-folder')
$OUTPUT->command('set_quota', rcmail_quota_content());
}
else if (!$deleted) {
$OUTPUT->show_message('errorsaving', 'error');
rcmail_display_server_error('errorsaving');
}
}
@ -141,7 +141,7 @@ else if ($RCMAIL->action == 'rename-folder')
rcube_charset_convert($name, 'UTF7-IMAP'), $display_rename, $before);
}
else if (!$rename) {
$OUTPUT->show_message('errorsaving', 'error');
rcmail_display_server_error('errorsaving');
}
}
@ -179,7 +179,7 @@ else if ($RCMAIL->action == 'purge')
$OUTPUT->command('show_folder', $mbox_utf8, null, true);
}
else {
$OUTPUT->show_message('errorsaving', 'error');
rcmail_display_server_error('errorsaving');
}
}
@ -195,6 +195,9 @@ else if ($RCMAIL->action == 'folder-size')
if ($size !== false) {
$OUTPUT->command('folder_size_update', show_bytes($size));
}
else {
rcmail_display_server_error();
}
}
if ($OUTPUT->ajax_call)

Loading…
Cancel
Save