diff options
Diffstat (limited to 'program/include')
-rw-r--r-- | program/include/main.inc | 32 | ||||
-rw-r--r-- | program/include/rcube_imap.php | 72 | ||||
-rw-r--r-- | program/include/rcube_imap_generic.php | 62 |
3 files changed, 153 insertions, 13 deletions
diff --git a/program/include/main.inc b/program/include/main.inc index ad0bccd48..160c835c9 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -1616,6 +1616,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 * * @param string Editor mode diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index f0d11194c..d1947c4a3 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -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(); diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index 10bc6d06b..b2346ba13 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -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); |