- 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
| | |
| | | - 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 |
| | | ---------------- |
| | |
| | | |
| | | |
| | | /** |
| | | * 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 |
| | | * |
| | | * @param string Editor mode |
| | |
| | | '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 |
| | |
| | | */ |
| | | 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; |
| | | } |
| | | |
| | | |
| | |
| | | * @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); |
| | | |
| | |
| | | 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(); |
| | |
| | | { |
| | | public $error; |
| | | public $errornum; |
| | | public $result; |
| | | public $resultcode; |
| | | public $data = array(); |
| | | public $flags = array( |
| | | 'SEEN' => '\\Seen', |
| | |
| | | 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; |
| | |
| | | $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') { |
| | |
| | | $this->errornum = self::ERROR_BYE; |
| | | } |
| | | |
| | | if ($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; |
| | |
| | | } |
| | | } |
| | | |
| | | $this->data['READ-WRITE'] = $this->resultcode != 'READ-ONLY'; |
| | | |
| | | $this->selected = $mailbox; |
| | | return true; |
| | | } |
| | |
| | | function expunge($mailbox, $messages=NULL) |
| | | { |
| | | if (!$this->select($mailbox)) { |
| | | return false; |
| | | } |
| | | |
| | | if (!$this->data['READ-WRITE']) { |
| | | $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'EXPUNGE'); |
| | | return false; |
| | | } |
| | | |
| | |
| | | { |
| | | $num_in_trash = $this->countMessages($mailbox); |
| | | if ($num_in_trash > 0) { |
| | | $this->delete($mailbox, '1:*'); |
| | | $res = $this->delete($mailbox, '1:*'); |
| | | } |
| | | |
| | | if ($res) { |
| | | if ($this->selected == $mailbox) |
| | | $res = $this->close(); |
| | | // $res = $this->expunge($mailbox); |
| | | else |
| | | $res = $this->expunge($mailbox); |
| | | } |
| | | |
| | | return $res; |
| | | } |
| | |
| | | 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']); |
| | |
| | | |
| | | 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) { |
| | |
| | | $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); |
| | |
| | | $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!'; |
| | |
| | | $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'; |
| | |
| | | $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ń'; |
| | | |
| | | ?> |
| | |
| | | |
| | | if (!$copied) { |
| | | // send error message |
| | | $OUTPUT->show_message('errorcopying', 'error'); |
| | | rcmail_display_server_error('errorcopying'); |
| | | $OUTPUT->send(); |
| | | exit; |
| | | } |
| | |
| | | |
| | | // send response |
| | | $OUTPUT->send(); |
| | | |
| | | |
| | |
| | | $mbox = get_input_value('_mbox', RCUBE_INPUT_POST, true); |
| | | |
| | | // send EXPUNGE command |
| | | if ($RCMAIL->action=='expunge') |
| | | { |
| | | if ($RCMAIL->action == 'expunge') { |
| | | |
| | | $success = $IMAP->expunge($mbox); |
| | | |
| | | // reload message list if current mailbox |
| | | if ($success && !empty($_REQUEST['_reload'])) |
| | | { |
| | | 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 |
| | | $commands = "// expunged: $success\n"; |
| | | } |
| | | else { |
| | | rcmail_display_server_error(); |
| | | } |
| | | } |
| | | |
| | | // clear mailbox |
| | |
| | | |
| | | // 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)) |
| | | { |
| | | || preg_match($trash_regexp, $mbox) || preg_match($junk_regexp, $mbox) |
| | | ) { |
| | | $success = $IMAP->clear_mailbox($mbox); |
| | | |
| | | if ($success && !empty($_REQUEST['_reload'])) |
| | | { |
| | | if ($success) { |
| | | $OUTPUT->show_message('folderpurged', 'confirmation'); |
| | | |
| | | if (!empty($_REQUEST['_reload'])) { |
| | | $OUTPUT->set_env('messagecount', 0); |
| | | $OUTPUT->set_env('pagecount', 0); |
| | | $OUTPUT->command('message_list.clear'); |
| | |
| | | $OUTPUT->command('set_quota', rcmail_quota_content()); |
| | | rcmail_set_unseen_count($mbox, 0); |
| | | } |
| | | else |
| | | $commands = "// purged: $success"; |
| | | } |
| | | else { |
| | | rcmail_display_server_error(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | $OUTPUT->send($commands); |
| | | |
| | | |
| | | $OUTPUT->send(); |
| | |
| | | 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'); |
| | |
| | | // send error message |
| | | if ($_POST['_from'] != 'show') |
| | | $OUTPUT->command('list_mailbox'); |
| | | $OUTPUT->show_message('errormarking', 'error'); |
| | | rcmail_display_server_error('errormarking'); |
| | | $OUTPUT->send(); |
| | | exit; |
| | | } |
| | |
| | | // send error message |
| | | if ($_POST['_from'] != 'show') |
| | | $OUTPUT->command('list_mailbox'); |
| | | $OUTPUT->show_message('errormoving', 'error'); |
| | | rcmail_display_server_error('errormoving'); |
| | | $OUTPUT->send(); |
| | | exit; |
| | | } |
| | |
| | | // send error message |
| | | if ($_POST['_from'] != 'show') |
| | | $OUTPUT->command('list_mailbox'); |
| | | $OUTPUT->show_message('errordeleting', 'error'); |
| | | rcmail_display_server_error('errordeleting'); |
| | | $OUTPUT->send(); |
| | | exit; |
| | | } |
| | |
| | | } |
| | | // 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'); |
| | |
| | | |
| | | // 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) { |
| | |
| | | if ($result) |
| | | $OUTPUT->show_message('foldersubscribed', 'confirmation'); |
| | | else |
| | | $OUTPUT->show_message('errorsaving', 'error'); |
| | | rcmail_display_server_error('errorsaving'); |
| | | } |
| | | } |
| | | |
| | |
| | | if ($result) |
| | | $OUTPUT->show_message('folderunsubscribed', 'confirmation'); |
| | | else |
| | | $OUTPUT->show_message('errorsaving', 'error'); |
| | | rcmail_display_server_error('errorsaving'); |
| | | } |
| | | } |
| | | |
| | |
| | | $OUTPUT->command('set_quota', rcmail_quota_content()); |
| | | } |
| | | else if (!$deleted) { |
| | | $OUTPUT->show_message('errorsaving', 'error'); |
| | | rcmail_display_server_error('errorsaving'); |
| | | } |
| | | } |
| | | |
| | |
| | | rcube_charset_convert($name, 'UTF7-IMAP'), $display_rename, $before); |
| | | } |
| | | else if (!$rename) { |
| | | $OUTPUT->show_message('errorsaving', 'error'); |
| | | rcmail_display_server_error('errorsaving'); |
| | | } |
| | | } |
| | | |
| | |
| | | $OUTPUT->command('show_folder', $mbox_utf8, null, true); |
| | | } |
| | | else { |
| | | $OUTPUT->show_message('errorsaving', 'error'); |
| | | rcmail_display_server_error('errorsaving'); |
| | | } |
| | | } |
| | | |
| | |
| | | if ($size !== false) { |
| | | $OUTPUT->command('folder_size_update', show_bytes($size)); |
| | | } |
| | | else { |
| | | rcmail_display_server_error(); |
| | | } |
| | | } |
| | | |
| | | if ($OUTPUT->ajax_call) |