summaryrefslogtreecommitdiff
path: root/program/include
diff options
context:
space:
mode:
Diffstat (limited to 'program/include')
-rw-r--r--program/include/main.inc32
-rw-r--r--program/include/rcube_imap.php72
-rw-r--r--program/include/rcube_imap_generic.php62
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);