summaryrefslogtreecommitdiff
path: root/program/include/rcube_imap.php
diff options
context:
space:
mode:
Diffstat (limited to 'program/include/rcube_imap.php')
-rw-r--r--program/include/rcube_imap.php327
1 files changed, 205 insertions, 122 deletions
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 212e8865e..5715459a8 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
@@ -156,21 +166,20 @@ class rcube_imap
$this->ssl = $use_ssl;
if ($this->conn->connected()) {
- // print trace messages
- if ($this->conn->message && ($this->debug_level & 8)) {
- console($this->conn->message);
- }
// get namespace and delimiter
$this->set_env();
-
return true;
}
// write error log
else if ($this->conn->error) {
- if ($pass && $user)
+ if ($pass && $user) {
+ $message = sprintf("Login failed for %s from %s. %s",
+ $user, rcmail_remote_ip(), $this->conn->error);
+
raise_error(array('code' => 403, 'type' => 'imap',
'file' => __FILE__, 'line' => __LINE__,
- 'message' => $this->conn->error), true, false);
+ 'message' => $message), true, false);
+ }
}
return false;
@@ -185,7 +194,7 @@ class rcube_imap
*/
function close()
{
- $this->conn->close();
+ $this->conn->closeConnection();
$this->write_cache();
}
@@ -198,11 +207,11 @@ class rcube_imap
*/
function reconnect()
{
- $this->close();
- $this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl);
+ $this->conn->closeConnection();
+ $connected = $this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl);
// issue SELECT command to restore connection status
- if ($this->mailbox)
+ if ($connected && strlen($this->mailbox))
$this->conn->select($this->mailbox);
}
@@ -225,7 +234,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;
}
@@ -300,9 +353,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);
@@ -493,56 +546,56 @@ class rcube_imap
$imap_shared = $config->get('imap_ns_shared');
$imap_delimiter = $config->get('imap_delimiter');
- if ($imap_delimiter) {
- $this->delimiter = $imap_delimiter;
- }
-
if (!$this->conn)
return;
$ns = $this->conn->getNamespace();
- // NAMESPACE supported
+ // Set namespaces (NAMESPACE supported)
if (is_array($ns)) {
$this->namespace = $ns;
-
- if (empty($this->delimiter))
- $this->delimiter = $ns['personal'][0][1];
- if (empty($this->delimiter))
- $this->delimiter = $this->conn->getHierarchyDelimiter();
- if (empty($this->delimiter))
- $this->delimiter = '/';
}
- // not supported, get namespace from config
- else if ($imap_personal !== null || $imap_shared !== null || $imap_other !== null) {
- if (empty($this->delimiter))
- $this->delimiter = $this->conn->getHierarchyDelimiter();
- if (empty($this->delimiter))
- $this->delimiter = '/';
-
+ else {
$this->namespace = array(
'personal' => NULL,
'other' => NULL,
'shared' => NULL,
);
+ }
- if ($imap_personal !== null) {
- foreach ((array)$imap_personal as $dir) {
- $this->namespace['personal'][] = array($dir, $this->delimiter);
- }
+ if ($imap_delimiter) {
+ $this->delimiter = $imap_delimiter;
+ }
+ if (empty($this->delimiter)) {
+ $this->delimiter = $this->namespace['personal'][0][1];
+ }
+ if (empty($this->delimiter)) {
+ $this->delimiter = $this->conn->getHierarchyDelimiter();
+ }
+ if (empty($this->delimiter)) {
+ $this->delimiter = '/';
+ }
+
+ // Overwrite namespaces
+ if ($imap_personal !== null) {
+ $this->namespace['personal'] = NULL;
+ foreach ((array)$imap_personal as $dir) {
+ $this->namespace['personal'][] = array($dir, $this->delimiter);
}
- if ($imap_other !== null) {
- foreach ((array)$imap_other as $dir) {
- if ($dir) {
- $this->namespace['other'][] = array($dir, $this->delimiter);
- }
+ }
+ if ($imap_other !== null) {
+ $this->namespace['other'] = NULL;
+ foreach ((array)$imap_other as $dir) {
+ if ($dir) {
+ $this->namespace['other'][] = array($dir, $this->delimiter);
}
}
- if ($imap_shared !== null) {
- foreach ((array)$imap_shared as $dir) {
- if ($dir) {
- $this->namespace['shared'][] = array($dir, $this->delimiter);
- }
+ }
+ if ($imap_shared !== null) {
+ $this->namespace['shared'] = NULL;
+ foreach ((array)$imap_shared as $dir) {
+ if ($dir) {
+ $this->namespace['shared'][] = array($dir, $this->delimiter);
}
}
}
@@ -617,7 +670,7 @@ class rcube_imap
}
// RECENT count is fetched a bit different
else if ($mode == 'RECENT') {
- $count = $this->conn->checkForRecent($mailbox);
+ $count = $this->conn->countRecent($mailbox);
}
// use SEARCH for message counting
else if ($this->skip_deleted) {
@@ -2376,20 +2429,21 @@ class rcube_imap
// TODO: Add caching for message parts
- if (!$part) $part = 'TEXT';
+ if (!$part) {
+ $part = 'TEXT';
+ }
$body = $this->conn->handlePartBody($this->mailbox, $uid, true, $part,
$o_part->encoding, $print, $fp);
- if ($fp || $print)
+ if ($fp || $print) {
return true;
+ }
- // convert charset (if text or message part)
- if ($body && ($o_part->ctype_primary == 'text' || $o_part->ctype_primary == 'message')) {
- // assume default if no charset specified
- if (empty($o_part->charset) || strtolower($o_part->charset) == 'us-ascii')
- $o_part->charset = $this->default_charset;
-
+ // convert charset (if text or message part) and part's charset is specified
+ if ($body && $o_part->charset
+ && preg_match('/^(text|message)$/', $o_part->ctype_primary)
+ ) {
$body = rcube_charset_convert($body, $o_part->charset);
}
@@ -2553,6 +2607,9 @@ class rcube_imap
$to_mbox = $this->mod_mailbox($to_mbox);
$from_mbox = strlen($from_mbox) ? $this->mod_mailbox($from_mbox) : $this->mailbox;
+ if ($to_mbox === $from_mbox)
+ return false;
+
list($uids, $all_mode) = $this->_parse_uids($uids, $from_mbox);
// exit if no message uids are specified
@@ -2771,7 +2828,23 @@ class rcube_imap
else
$a_uids = NULL;
- $result = $this->conn->expunge($mailbox, $a_uids);
+ // 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();
+ else
+ $result = $this->conn->expunge($mailbox, $a_uids);
if ($result && $clear_cache) {
$this->clear_message_cache($mailbox.'.msg');
@@ -3009,6 +3082,26 @@ class rcube_imap
/**
+ * Get mailbox size (size of all messages in a mailbox)
+ *
+ * @param string $name Mailbox name
+ * @return int Mailbox size in bytes, False on error
+ */
+ function get_mailbox_size($name)
+ {
+ $name = $this->mod_mailbox($name);
+
+ // @TODO: could we try to use QUOTA here?
+ $result = $this->conn->fetchHeaderIndex($name, '1:*', 'SIZE', false);
+
+ if (is_array($result))
+ $result = array_sum($result);
+
+ return $result;
+ }
+
+
+ /**
* Subscribe to a specific mailbox(es)
*
* @param array $a_mboxes Mailbox name(s)
@@ -3043,130 +3136,120 @@ class rcube_imap
/**
* Create a new mailbox on the server and register it in local cache
*
- * @param string $name New mailbox name (as utf-7 string)
+ * @param string $name New mailbox name
* @param boolean $subscribe True if the new mailbox should be subscribed
- * @param string Name of the created mailbox, false on error
+ * @param boolean True on success
*/
function create_mailbox($name, $subscribe=false)
{
- $result = false;
-
- // reduce mailbox name to 100 chars
- $name = substr($name, 0, 100);
+ $result = false;
$abs_name = $this->mod_mailbox($name);
- $result = $this->conn->createFolder($abs_name);
+ $result = $this->conn->createFolder($abs_name);
// try to subscribe it
if ($result && $subscribe)
$this->subscribe($name);
- return $result ? $name : false;
+ return $result;
}
/**
* Set a new name to an existing mailbox
*
- * @param string $mbox_name Mailbox to rename (as utf-7 string)
- * @param string $new_name New mailbox name (as utf-7 string)
- * @return string Name of the renames mailbox, False on error
+ * @param string $mbox_name Mailbox to rename
+ * @param string $new_name New mailbox name
+ *
+ * @return boolean True on success
*/
function rename_mailbox($mbox_name, $new_name)
{
$result = false;
- // encode mailbox name and reduce it to 100 chars
- $name = substr($new_name, 0, 100);
-
// make absolute path
- $mailbox = $this->mod_mailbox($mbox_name);
- $abs_name = $this->mod_mailbox($name);
-
- // check if mailbox is subscribed
- $a_subscribed = $this->_list_mailboxes();
- $subscribed = in_array($mailbox, $a_subscribed);
+ $mailbox = $this->mod_mailbox($mbox_name);
+ $abs_name = $this->mod_mailbox($new_name);
+ $delm = $this->get_hierarchy_delimiter();
- // unsubscribe folder
- if ($subscribed)
- $this->conn->unsubscribe($mailbox);
+ // get list of subscribed folders
+ if ((strpos($mailbox, '%') === false) && (strpos($mailbox, '*') === false)) {
+ $a_subscribed = $this->_list_mailboxes('', $mbox_name . $delm . '*');
+ $subscribed = $this->mailbox_exists($mbox_name, true);
+ }
+ else {
+ $a_subscribed = $this->_list_mailboxes();
+ $subscribed = in_array($mailbox, $a_subscribed);
+ }
if (strlen($abs_name))
$result = $this->conn->renameFolder($mailbox, $abs_name);
if ($result) {
- $delm = $this->get_hierarchy_delimiter();
+ // unsubscribe the old folder, subscribe the new one
+ if ($subscribed) {
+ $this->conn->unsubscribe($mailbox);
+ $this->conn->subscribe($abs_name);
+ }
// check if mailbox children are subscribed
- foreach ($a_subscribed as $c_subscribed)
+ foreach ($a_subscribed as $c_subscribed) {
if (preg_match('/^'.preg_quote($mailbox.$delm, '/').'/', $c_subscribed)) {
$this->conn->unsubscribe($c_subscribed);
$this->conn->subscribe(preg_replace('/^'.preg_quote($mailbox, '/').'/',
$abs_name, $c_subscribed));
}
+ }
// clear cache
$this->clear_message_cache($mailbox.'.msg');
$this->clear_cache('mailboxes');
}
- // try to subscribe it
- if ($result && $subscribed)
- $this->conn->subscribe($abs_name);
-
- return $result ? $name : false;
+ return $result;
}
/**
- * Remove mailboxes from server
+ * Remove mailbox from server
+ *
+ * @param string $mbox_name Mailbox name
*
- * @param string|array $mbox_name sMailbox name(s) string/array
* @return boolean True on success
*/
function delete_mailbox($mbox_name)
{
- $deleted = false;
+ $result = false;
+ $mailbox = $this->mod_mailbox($mbox_name);
+ $delm = $this->get_hierarchy_delimiter();
- if (is_array($mbox_name))
- $a_mboxes = $mbox_name;
- else if (is_string($mbox_name) && strlen($mbox_name))
- $a_mboxes = explode(',', $mbox_name);
+ // get list of folders
+ if ((strpos($mailbox, '%') === false) && (strpos($mailbox, '*') === false))
+ $sub_mboxes = $this->list_unsubscribed('', $mailbox . $delm . '*');
+ else
+ $sub_mboxes = $this->list_unsubscribed();
- if (is_array($a_mboxes)) {
- $delimiter = $this->get_hierarchy_delimiter();
-
- foreach ($a_mboxes as $mbox_name) {
- $mailbox = $this->mod_mailbox($mbox_name);
- $sub_mboxes = $this->conn->listMailboxes('', $mbox_name . $delimiter . '*');
+ // send delete command to server
+ $result = $this->conn->deleteFolder($mailbox);
- // unsubscribe mailbox before deleting
- $this->conn->unsubscribe($mailbox);
+ if ($result) {
+ // unsubscribe mailbox
+ $this->conn->unsubscribe($mailbox);
- // send delete command to server
- $result = $this->conn->deleteFolder($mailbox);
- if ($result) {
- $deleted = true;
- $this->clear_message_cache($mailbox.'.msg');
- }
-
- foreach ($sub_mboxes as $c_mbox) {
- if ($c_mbox != 'INBOX') {
- $this->conn->unsubscribe($c_mbox);
- $result = $this->conn->deleteFolder($c_mbox);
- if ($result) {
- $deleted = true;
- $this->clear_message_cache($c_mbox.'.msg');
- }
+ foreach ($sub_mboxes as $c_mbox) {
+ if (preg_match('/^'.preg_quote($mailbox.$delm, '/').'/', $c_mbox)) {
+ $this->conn->unsubscribe($c_mbox);
+ if ($this->conn->deleteFolder($c_mbox)) {
+ $this->clear_message_cache($c_mbox.'.msg');
}
}
}
- }
- // clear mailboxlist cache
- if ($deleted)
+ // clear mailbox-related cache
+ $this->clear_message_cache($mailbox.'.msg');
$this->clear_cache('mailboxes');
+ }
- return $deleted;
+ return $result;
}
@@ -3208,7 +3291,7 @@ class rcube_imap
}
else {
$a_folders = $this->conn->listMailboxes('', $mbox);
- }
+ }
if (is_array($a_folders) && in_array($mbox, $a_folders)) {
$this->icache[$key][] = $mbox;