From 939380da27f3502847fc1f18e8b67f3fb6d6742f Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 21 May 2014 19:48:16 +0200 Subject: Don't list empty (nil) metadata entries to save memory anc caching space --- program/lib/Roundcube/rcube_imap_generic.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index f45694dd0..3b5be15db 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -3143,7 +3143,8 @@ class rcube_imap_generic if (isset($mbox) && is_array($data[$i])) { $size_sub = count($data[$i]); for ($x=0; $x<$size_sub; $x++) { - $result[$mbox][$data[$i][$x]] = $data[$i][++$x]; + if ($data[$i][$x+1] !== null) + $result[$mbox][$data[$i][$x]] = $data[$i][++$x]; } unset($data[$i]); } @@ -3161,7 +3162,8 @@ class rcube_imap_generic } } else if (isset($mbox)) { - $result[$mbox][$data[$i]] = $data[++$i]; + if ($data[$i+1] !== null) + $result[$mbox][$data[$i]] = $data[++$i]; unset($data[$i]); unset($data[$i-1]); } @@ -3306,10 +3308,10 @@ class rcube_imap_generic for ($x=0, $len=count($attribs); $x<$len;) { $attr = $attribs[$x++]; $value = $attribs[$x++]; - if ($attr == 'value.priv') { + if ($attr == 'value.priv' && $value !== null) { $result[$mbox]['/private' . $entry] = $value; } - else if ($attr == 'value.shared') { + else if ($attr == 'value.shared' && $value !== null) { $result[$mbox]['/shared' . $entry] = $value; } } -- cgit v1.2.3 From 232bcde1c2222b24ff659882355b048b1f4295cd Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 1 Jun 2014 18:53:33 +0200 Subject: Change private vars/methods to protected --- program/lib/Roundcube/rcube_imap_generic.php | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 3b5be15db..e4c9b7eb8 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -50,17 +50,17 @@ class rcube_imap_generic public static $mupdate; - private $fp; - private $host; - private $logged = false; - private $capability = array(); - private $capability_readed = false; - private $prefs; - private $cmd_tag; - private $cmd_num = 0; - private $resourceid; - private $_debug = false; - private $_debug_handler = false; + protected $fp; + protected $host; + protected $logged = false; + protected $capability = array(); + protected $capability_readed = false; + protected $prefs; + protected $cmd_tag; + protected $cmd_num = 0; + protected $resourceid; + protected $_debug = false; + protected $_debug_handler = false; const ERROR_OK = 0; const ERROR_NO = -1; @@ -352,7 +352,7 @@ class rcube_imap_generic * * @return bool True if connection is closed */ - private function eof() + protected function eof() { if (!is_resource($this->fp)) { return true; @@ -375,7 +375,7 @@ class rcube_imap_generic /** * Closes connection stream. */ - private function closeSocket() + protected function closeSocket() { @fclose($this->fp); $this->fp = null; @@ -421,7 +421,7 @@ class rcube_imap_generic return false; } - private function hasCapability($name) + protected function hasCapability($name) { if (empty($this->capability) || $name == '') { return false; @@ -1310,7 +1310,7 @@ class rcube_imap_generic * @return array List of mailboxes or hash of options if $status_ops argument * is non-empty. */ - private function _listMailboxes($ref, $mailbox, $subscribed=false, + protected function _listMailboxes($ref, $mailbox, $subscribed=false, $status_opts=array(), $select_opts=array()) { if (!strlen($mailbox)) { @@ -1985,7 +1985,7 @@ class rcube_imap_generic * * @return bool True on success, False on failure */ - private function modFlag($mailbox, $messages, $flag, $mod = '+') + protected function modFlag($mailbox, $messages, $flag, $mod = '+') { if ($mod != '+' && $mod != '-') { $mod = '+'; @@ -3681,7 +3681,7 @@ class rcube_imap_generic return $result; } - private function _xor($string, $string2) + protected function _xor($string, $string2) { $result = ''; $size = strlen($string); @@ -3700,7 +3700,7 @@ class rcube_imap_generic * * @return string Space-separated list of flags */ - private function flagsToStr($flags) + protected function flagsToStr($flags) { foreach ((array)$flags as $idx => $flag) { if ($flag = $this->flags[strtoupper($flag)]) { @@ -3752,7 +3752,7 @@ class rcube_imap_generic /** * CAPABILITY response parser */ - private function parseCapability($str, $trusted=false) + protected function parseCapability($str, $trusted=false) { $str = preg_replace('/^\* CAPABILITY /i', '', $str); @@ -3829,7 +3829,7 @@ class rcube_imap_generic * * @since 0.5-stable */ - private function debug($message) + protected function debug($message) { if (($len = strlen($message)) > self::DEBUG_LINE_LENGTH) { $diff = $len - self::DEBUG_LINE_LENGTH; -- cgit v1.2.3 From 109bcce470b789dac498d0fba8fb9673b988f867 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 16 Jun 2014 14:13:58 +0200 Subject: Add config option to specify IMAP connection socket parameters - imap_conn_options (#1489948) --- CHANGELOG | 1 + config/defaults.inc.php | 37 ++++-- program/lib/Roundcube/rcube.php | 19 +-- program/lib/Roundcube/rcube_imap.php | 12 +- program/lib/Roundcube/rcube_imap_generic.php | 181 +++++++++++++++------------ 5 files changed, 145 insertions(+), 105 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/CHANGELOG b/CHANGELOG index 9e26b9501..d2fc4faaf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Add config option to specify IMAP connection socket parameters - imap_conn_options (#1489948) - Password: Add option to force new users to change their password (#1486884) - Improve support for screen readers and assistive technology using WCAG 2.0 and WAI ARIA standards - Enable basic keyboard navigation throughout the UI (#1487845) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index 859378624..c20a06bf7 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -123,6 +123,27 @@ $config['default_port'] = 143; // best server supported one) $config['imap_auth_type'] = null; +// IMAP socket context options +// See http://php.net/manual/en/context.ssl.php +// The example below enables server certificate validation +//$config['imap_conn_options'] = array( +// 'ssl' => array( +// 'verify_peer' => true, +// 'verify_depth' => 3, +// 'cafile' => '/etc/openssl/certs/ca.crt', +// ), +// ); +$config['imap_conn_options'] = null; + +// IMAP connection timeout, in seconds. Default: 0 (use default_socket_timeout) +$config['imap_timeout'] = 0; + +// Optional IMAP authentication identifier to be used as authorization proxy +$config['imap_auth_cid'] = null; + +// Optional IMAP authentication password to be used for imap_auth_cid +$config['imap_auth_pw'] = null; + // If you know your imap's folder delimiter, you can specify it here. // Otherwise it will be determined automatically $config['imap_delimiter'] = null; @@ -160,15 +181,6 @@ $config['imap_force_ns'] = false; // Note: Because the list is cached, re-login is required after change. $config['imap_disabled_caps'] = array(); -// IMAP connection timeout, in seconds. Default: 0 (use default_socket_timeout) -$config['imap_timeout'] = 0; - -// Optional IMAP authentication identifier to be used as authorization proxy -$config['imap_auth_cid'] = null; - -// Optional IMAP authentication password to be used for imap_auth_cid -$config['imap_auth_pw'] = null; - // Type of IMAP indexes cache. Supported values: 'db', 'apc' and 'memcache'. $config['imap_cache'] = null; @@ -244,13 +256,14 @@ $config['smtp_timeout'] = 0; // requires 'smtp_timeout' to be non zero. // $config['smtp_conn_options'] = array( // 'ssl' => array( -// 'verify_peer' => true, -// 'verify_depth => 3, -// 'cafile' => '/etc/openssl/certs/ca.crt', +// 'verify_peer' => true, +// 'verify_depth' => 3, +// 'cafile' => '/etc/openssl/certs/ca.crt', // ), // ); $config['smtp_conn_options'] = null; + // ---------------------------------- // LDAP // ---------------------------------- diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php index d618fb64d..cf54c3c12 100644 --- a/program/lib/Roundcube/rcube.php +++ b/program/lib/Roundcube/rcube.php @@ -357,15 +357,16 @@ class rcube // set class options $options = array( - 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'), - 'auth_cid' => $this->config->get("{$driver}_auth_cid"), - 'auth_pw' => $this->config->get("{$driver}_auth_pw"), - 'debug' => (bool) $this->config->get("{$driver}_debug"), - 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"), - 'disabled_caps' => $this->config->get("{$driver}_disabled_caps"), - 'timeout' => (int) $this->config->get("{$driver}_timeout"), - 'skip_deleted' => (bool) $this->config->get('skip_deleted'), - 'driver' => $driver, + 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'), + 'auth_cid' => $this->config->get("{$driver}_auth_cid"), + 'auth_pw' => $this->config->get("{$driver}_auth_pw"), + 'debug' => (bool) $this->config->get("{$driver}_debug"), + 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"), + 'disabled_caps' => $this->config->get("{$driver}_disabled_caps"), + 'socket_options' => $this->config->get("{$driver}_conn_options"), + 'timeout' => (int) $this->config->get("{$driver}_timeout"), + 'skip_deleted' => (bool) $this->config->get('skip_deleted'), + 'driver' => $driver, ); if (!empty($_SESSION['storage_host'])) { diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index e29bfc46b..109886f8d 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -110,13 +110,13 @@ class rcube_imap extends rcube_storage /** * Connect to an IMAP server * - * @param string $host Host to connect - * @param string $user Username for IMAP account - * @param string $pass Password for IMAP account - * @param integer $port Port to connect to - * @param string $use_ssl SSL schema (either ssl or tls) or null if plain connection + * @param string $host Host to connect + * @param string $user Username for IMAP account + * @param string $pass Password for IMAP account + * @param integer $port Port to connect to + * @param string $use_ssl SSL schema (either ssl or tls) or null if plain connection * - * @return boolean TRUE on success, FALSE on failure + * @return boolean True on success, False on failure */ public function connect($host, $user, $pass, $port=143, $use_ssl=null) { diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index e4c9b7eb8..5aaad0a00 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -723,110 +723,38 @@ class rcube_imap_generic // configure $this->set_prefs($options); - $auth_method = $this->prefs['auth_type']; - $result = false; - - // initialize connection - $this->error = ''; - $this->errornum = self::ERROR_OK; - $this->selected = null; - $this->user = $user; $this->host = $host; + $this->user = $user; $this->logged = false; + $this->selected = null; // check input if (empty($host)) { $this->setError(self::ERROR_BAD, "Empty host"); return false; } + if (empty($user)) { $this->setError(self::ERROR_NO, "Empty user"); return false; } + if (empty($password)) { $this->setError(self::ERROR_NO, "Empty password"); return false; } - if (!$this->prefs['port']) { - $this->prefs['port'] = 143; - } - // check for SSL - if ($this->prefs['ssl_mode'] && $this->prefs['ssl_mode'] != 'tls') { - $host = $this->prefs['ssl_mode'] . '://' . $host; - } - - if ($this->prefs['timeout'] <= 0) { - $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout'))); - } - // Connect - $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']); - - if (!$this->fp) { - if (!$errstr) { - $errstr = "Unknown reason (fsockopen() function disabled?)"; - } - $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr)); - return false; - } - - if ($this->prefs['timeout'] > 0) { - stream_set_timeout($this->fp, $this->prefs['timeout']); - } - - $line = trim(fgets($this->fp, 8192)); - - if ($this->_debug) { - // set connection identifier for debug output - preg_match('/#([0-9]+)/', (string)$this->fp, $m); - $this->resourceid = strtoupper(substr(md5($m[1].$this->user.microtime()), 0, 4)); - - if ($line) - $this->debug('S: '. $line); - } - - // Connected to wrong port or connection error? - if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) { - if ($line) - $error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $this->prefs['port'], $line); - else - $error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']); - - $this->setError(self::ERROR_BAD, $error); - $this->closeConnection(); + if (!$this->_connect($host)) { return false; } - // RFC3501 [7.1] optional CAPABILITY response - if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { - $this->parseCapability($matches[1], true); - } - - // TLS connection - if ($this->prefs['ssl_mode'] == 'tls' && $this->getCapability('STARTTLS')) { - $res = $this->execute('STARTTLS'); - - if ($res[0] != self::ERROR_OK) { - $this->closeConnection(); - return false; - } - - if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { - $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); - $this->closeConnection(); - return false; - } - - // Now we're secure, capabilities need to be reread - $this->clearCapability(); - } - // Send ID info if (!empty($this->prefs['ident']) && $this->getCapability('ID')) { $this->id($this->prefs['ident']); } + $auth_method = $this->prefs['auth_type']; $auth_methods = array(); $result = null; @@ -900,6 +828,103 @@ class rcube_imap_generic return false; } + /** + * Connects to IMAP server. + * + * @param string $host Server hostname or IP + * + * @return bool True on success, False on failure + */ + protected function _connect($host) + { + // initialize connection + $this->error = ''; + $this->errornum = self::ERROR_OK; + + if (!$this->prefs['port']) { + $this->prefs['port'] = 143; + } + + // check for SSL + if ($this->prefs['ssl_mode'] && $this->prefs['ssl_mode'] != 'tls') { + $host = $this->prefs['ssl_mode'] . '://' . $host; + } + + if ($this->prefs['timeout'] <= 0) { + $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout'))); + } + + if (!empty($this->prefs['socket_options'])) { + $context = stream_context_create($this->prefs['socket_options']); + $this->fp = stream_socket_client($host . ':' . $this->prefs['port'], $errno, $errstr, + $this->prefs['timeout'], STREAM_CLIENT_CONNECT, $context); + } + else { + $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']); + } + + if (!$this->fp) { + $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", + $host, $this->prefs['port'], $errstr ?: "Unknown reason")); + + return false; + } + + if ($this->prefs['timeout'] > 0) { + stream_set_timeout($this->fp, $this->prefs['timeout']); + } + + $line = trim(fgets($this->fp, 8192)); + + if ($this->_debug) { + // set connection identifier for debug output + preg_match('/#([0-9]+)/', (string) $this->fp, $m); + $this->resourceid = strtoupper(substr(md5($m[1].$this->user.microtime()), 0, 4)); + + if ($line) { + $this->debug('S: '. $line); + } + } + + // Connected to wrong port or connection error? + if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) { + if ($line) + $error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $this->prefs['port'], $line); + else + $error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']); + + $this->setError(self::ERROR_BAD, $error); + $this->closeConnection(); + return false; + } + + // RFC3501 [7.1] optional CAPABILITY response + if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { + $this->parseCapability($matches[1], true); + } + + // TLS connection + if ($this->prefs['ssl_mode'] == 'tls' && $this->getCapability('STARTTLS')) { + $res = $this->execute('STARTTLS'); + + if ($res[0] != self::ERROR_OK) { + $this->closeConnection(); + return false; + } + + if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { + $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); + $this->closeConnection(); + return false; + } + + // Now we're secure, capabilities need to be reread + $this->clearCapability(); + } + + return true; + } + /** * Initializes environment */ -- cgit v1.2.3 From 07893b3cdd5ed8c4291d6f2928bded1bc5713dc7 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 22 Jun 2014 11:32:16 +0200 Subject: Support LIST-MYRIGHTS extension in rcube_imap_generic (#1489665) --- program/lib/Roundcube/rcube_imap_generic.php | 64 +++++++++++++++++----------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 5aaad0a00..7b9ba2ec8 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -1293,15 +1293,15 @@ class rcube_imap_generic * * @param string $ref Reference name * @param string $mailbox Mailbox name - * @param array $status_opts (see self::_listMailboxes) + * @param array $return_opts (see self::_listMailboxes) * @param array $select_opts (see self::_listMailboxes) * - * @return array List of mailboxes or hash of options if $status_opts argument + * @return array List of mailboxes or hash of options if $return_opts argument * is non-empty. */ - function listMailboxes($ref, $mailbox, $status_opts=array(), $select_opts=array()) + function listMailboxes($ref, $mailbox, $return_opts=array(), $select_opts=array()) { - return $this->_listMailboxes($ref, $mailbox, false, $status_opts, $select_opts); + return $this->_listMailboxes($ref, $mailbox, false, $return_opts, $select_opts); } /** @@ -1309,14 +1309,14 @@ class rcube_imap_generic * * @param string $ref Reference name * @param string $mailbox Mailbox name - * @param array $status_opts (see self::_listMailboxes) + * @param array $return_opts (see self::_listMailboxes) * - * @return array List of mailboxes or hash of options if $status_opts argument + * @return array List of mailboxes or hash of options if $return_opts argument * is non-empty. */ - function listSubscribed($ref, $mailbox, $status_opts=array()) + function listSubscribed($ref, $mailbox, $return_opts=array()) { - return $this->_listMailboxes($ref, $mailbox, true, $status_opts, NULL); + return $this->_listMailboxes($ref, $mailbox, true, $return_opts, NULL); } /** @@ -1325,9 +1325,9 @@ class rcube_imap_generic * @param string $ref Reference name * @param string $mailbox Mailbox name * @param bool $subscribed Enables returning subscribed mailboxes only - * @param array $status_opts List of STATUS options - * (RFC5819: LIST-STATUS: MESSAGES, RECENT, UIDNEXT, UIDVALIDITY, UNSEEN) - * or RETURN options (RFC5258: LIST_EXTENDED: SUBSCRIBED, CHILDREN) + * @param array $return_opts List of RETURN options (RFC5819: LIST-STATUS, RFC5258: LIST-EXTENDED) + * Possible: MESSAGES, RECENT, UIDNEXT, UIDVALIDITY, UNSEEN, + * MYRIGHTS, SUBSCRIBED, CHILDREN * @param array $select_opts List of selection options (RFC5258: LIST-EXTENDED) * Possible: SUBSCRIBED, RECURSIVEMATCH, REMOTE, * SPECIAL-USE (RFC6154) @@ -1336,7 +1336,7 @@ class rcube_imap_generic * is non-empty. */ protected function _listMailboxes($ref, $mailbox, $subscribed=false, - $status_opts=array(), $select_opts=array()) + $return_opts=array(), $select_opts=array()) { if (!strlen($mailbox)) { $mailbox = '*'; @@ -1354,17 +1354,23 @@ class rcube_imap_generic $args[] = $this->escape($ref); $args[] = $this->escape($mailbox); - if (!empty($status_opts) && $this->getCapability('LIST-EXTENDED')) { - $rets = array_intersect($status_opts, array('SUBSCRIBED', 'CHILDREN')); + if (!empty($return_opts) && $this->getCapability('LIST-EXTENDED')) { + $rets = array_intersect($return_opts, array('SUBSCRIBED', 'CHILDREN')); } - if (!empty($status_opts) && $this->getCapability('LIST-STATUS')) { - $status_opts = array_intersect($status_opts, array('MESSAGES', 'RECENT', 'UIDNEXT', 'UIDVALIDITY', 'UNSEEN')); + if (!empty($return_opts) && $this->getCapability('LIST-STATUS')) { + $lstatus = true; + $status_opts = array('MESSAGES', 'RECENT', 'UIDNEXT', 'UIDVALIDITY', 'UNSEEN'); + $opts = array_diff($return_opts, $status_opts); + $status_opts = array_diff($return_opts, $opts); if (!empty($status_opts)) { - $lstatus = true; $rets[] = 'STATUS (' . implode(' ', $status_opts) . ')'; } + + if (!empty($opts)) { + $rets = array_merge($rets, $opts); + } } if (!empty($rets)) { @@ -1388,9 +1394,10 @@ class rcube_imap_generic $line = substr($response, $last, $pos - $last); $last = $pos + 2; - if (!preg_match('/^\* (LIST|LSUB|STATUS) /i', $line, $m)) { + if (!preg_match('/^\* (LIST|LSUB|STATUS|MYRIGHTS) /i', $line, $m)) { continue; } + $cmd = strtoupper($m[1]); $line = substr($line, strlen($m[0])); @@ -1421,13 +1428,20 @@ class rcube_imap_generic $this->data['LIST'][$mailbox], $opts)); } } - // * STATUS () - else if ($cmd == 'STATUS') { - list($mailbox, $status) = $this->tokenizeResponse($line, 2); - - for ($i=0, $len=count($status); $i<$len; $i += 2) { - list($name, $value) = $this->tokenizeResponse($status, 2); - $folders[$mailbox][$name] = $value; + else if ($lstatus) { + // * STATUS () + if ($cmd == 'STATUS') { + list($mailbox, $status) = $this->tokenizeResponse($line, 2); + + for ($i=0, $len=count($status); $i<$len; $i += 2) { + list($name, $value) = $this->tokenizeResponse($status, 2); + $folders[$mailbox][$name] = $value; + } + } + // * MYRIGHTS + else if ($cmd == 'MYRIGHTS') { + list($mailbox, $acl) = $this->tokenizeResponse($line, 2); + $folders[$mailbox]['MYRIGHTS'] = $acl; } } } -- cgit v1.2.3 From 6fa1a0da1f0902f10be8fc4eb24180f8e3453c17 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 24 Jun 2014 19:16:18 +0200 Subject: Extend get_quota() so it's possible to specify GETQUOTAROOT folder and return full quota info (including all roots and types, e.g. MESSAGE) - for future use --- program/include/rcmail.php | 1 + program/lib/Roundcube/rcube_imap.php | 7 ++- program/lib/Roundcube/rcube_imap_generic.php | 91 +++++++++++++++------------- program/lib/Roundcube/rcube_storage.php | 4 +- 4 files changed, 57 insertions(+), 46 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/program/include/rcmail.php b/program/include/rcmail.php index f4689215c..29ed66a43 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -1678,6 +1678,7 @@ class rcmail extends rcube $quota = $this->storage->get_quota(); $quota = $this->plugins->exec_hook('quota', $quota); + unset($quota['abort']); $quota_result = (array) $quota; $quota_result['type'] = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : ''; diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index 109886f8d..858db7b5b 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -3067,14 +3067,15 @@ class rcube_imap extends rcube_storage /** * Get mailbox quota information - * added by Nuny + * + * @param string $folder Folder name * * @return mixed Quota info or False if not supported */ - public function get_quota() + public function get_quota($folder = null) { if ($this->get_capability('QUOTA') && $this->check_connection()) { - return $this->conn->getQuota(); + return $this->conn->getQuota($folder); } return false; diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 7b9ba2ec8..032506412 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -2873,59 +2873,66 @@ class rcube_imap_generic /** * Returns QUOTA information * + * @param string $mailbox Mailbox name + * * @return array Quota information */ - function getQuota() - { - /* - * GETQUOTAROOT "INBOX" - * QUOTAROOT INBOX user/rchijiiwa1 - * QUOTA user/rchijiiwa1 (STORAGE 654 9765) - * OK Completed - */ - $result = false; - $quota_lines = array(); - $key = $this->nextTag(); - $command = $key . ' GETQUOTAROOT INBOX'; - - // get line(s) containing quota info - if ($this->putLine($command)) { - do { - $line = rtrim($this->readLine(5000)); - if (preg_match('/^\* QUOTA /', $line)) { - $quota_lines[] = $line; - } - } while (!$this->startsWith($line, $key, true, true)); - } - else { - $this->setError(self::ERROR_COMMAND, "Unable to send command: $command"); + function getQuota($mailbox = null) + { + if ($mailbox === null || $mailbox === '') { + $mailbox = 'INBOX'; } - // return false if not found, parse if found + // a0001 GETQUOTAROOT INBOX + // * QUOTAROOT INBOX user/sample + // * QUOTA user/sample (STORAGE 654 9765) + // a0001 OK Completed + + list($code, $response) = $this->execute('GETQUOTAROOT', array($this->escape($mailbox))); + + $result = false; $min_free = PHP_INT_MAX; - foreach ($quota_lines as $key => $quota_line) { - $quota_line = str_replace(array('(', ')'), '', $quota_line); - $parts = explode(' ', $quota_line); - $storage_part = array_search('STORAGE', $parts); + $all = array(); - if (!$storage_part) { - continue; - } + if ($code == self::ERROR_OK) { + foreach (explode("\n", $response) as $line) { + if (preg_match('/^\* QUOTA /', $line)) { + list(, , $quota_root) = $this->tokenizeResponse($line, 3); + + while ($line) { + list($type, $used, $total) = $this->tokenizeResponse($line, 1); + $type = strtolower($type); + + if ($type && $total) { + $all[$quota_root][$type]['used'] = intval($used); + $all[$quota_root][$type]['total'] = intval($total); + } + } + + if (empty($all[$quota_root]['storage'])) { + continue; + } - $used = intval($parts[$storage_part+1]); - $total = intval($parts[$storage_part+2]); - $free = $total - $used; + $used = $all[$quota_root]['storage']['used']; + $total = $all[$quota_root]['storage']['total']; + $free = $total - $used; - // return lowest available space from all quotas - if ($free < $min_free) { - $min_free = $free; - $result['used'] = $used; - $result['total'] = $total; - $result['percent'] = min(100, round(($used/max(1,$total))*100)); - $result['free'] = 100 - $result['percent']; + // calculate lowest available space from all storage quotas + if ($free < $min_free) { + $min_free = $free; + $result['used'] = $used; + $result['total'] = $total; + $result['percent'] = min(100, round(($used/max(1,$total))*100)); + $result['free'] = 100 - $result['percent']; + } + } } } + if (!empty($result)) { + $result['all'] = $all; + } + return $result; } diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php index c1293961c..ccb28c680 100644 --- a/program/lib/Roundcube/rcube_storage.php +++ b/program/lib/Roundcube/rcube_storage.php @@ -918,9 +918,11 @@ abstract class rcube_storage /** * Get mailbox quota information. * + * @param string $folder Folder name + * * @return mixed Quota info or False if not supported */ - abstract function get_quota(); + abstract function get_quota($folder = null); /* ----------------------------------------- -- cgit v1.2.3 From 4922e55d582fb1907211bba8cc539551475f280f Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 11 Jul 2014 09:28:36 +0200 Subject: Fix sorting messages by size on servers without SORT capability (#1489981) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_imap_generic.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/CHANGELOG b/CHANGELOG index aa22fb0e3..79148e033 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -57,6 +57,7 @@ CHANGELOG Roundcube Webmail - Fix Delete button state after deleting identity/response (#1489972) - Fix bug where contacts with no email address were listed on compose addressbook (#1489970) - Fix images import from various vCard formats (#1489977) +- Fix sorting messages by size on servers without SORT capability (#1489981) RELEASE 1.0.1 ------------- diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 032506412..99fb6d861 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -1916,8 +1916,8 @@ class rcube_imap_generic $result[$id] = ''; } } else if ($mode == 2) { - if (preg_match('/(UID|RFC822\.SIZE) ([0-9]+)/', $line, $matches)) { - $result[$id] = trim($matches[2]); + if (preg_match('/' . $index_field . ' ([0-9]+)/', $line, $matches)) { + $result[$id] = trim($matches[1]); } else { $result[$id] = 0; } -- cgit v1.2.3 From e0492d213b4c087b7092fa6bdc3dfecbc14f9bcf Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 14 Jul 2014 08:56:59 +0200 Subject: Fix "Illegal offset type" error (#1489985) --- program/lib/Roundcube/rcube_imap.php | 14 ++++++++------ program/lib/Roundcube/rcube_imap_generic.php | 16 +++++++++------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index 858db7b5b..9a07711c2 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -3298,12 +3298,14 @@ class rcube_imap extends rcube_storage // request \Subscribed flag in LIST response as performance improvement for folder_exists() $folders = $this->conn->listMailboxes('', '*', array('SUBSCRIBED'), array('SPECIAL-USE')); - foreach ($folders as $folder) { - if ($flags = $this->conn->data['LIST'][$folder]) { - foreach ($types as $type) { - if (in_array($type, $flags)) { - $type = strtolower(substr($type, 1)); - $special[$type] = $folder; + if (!empty($folders)) { + foreach ($folders as $folder) { + if ($flags = $this->conn->data['LIST'][$folder]) { + foreach ($types as $type) { + if (in_array($type, $flags)) { + $type = strtolower(substr($type, 1)); + $special[$type] = $folder; + } } } } diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 99fb6d861..d76014f89 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -1296,8 +1296,8 @@ class rcube_imap_generic * @param array $return_opts (see self::_listMailboxes) * @param array $select_opts (see self::_listMailboxes) * - * @return array List of mailboxes or hash of options if $return_opts argument - * is non-empty. + * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response + * is requested, False on error. */ function listMailboxes($ref, $mailbox, $return_opts=array(), $select_opts=array()) { @@ -1311,8 +1311,8 @@ class rcube_imap_generic * @param string $mailbox Mailbox name * @param array $return_opts (see self::_listMailboxes) * - * @return array List of mailboxes or hash of options if $return_opts argument - * is non-empty. + * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response + * is requested, False on error. */ function listSubscribed($ref, $mailbox, $return_opts=array()) { @@ -1332,8 +1332,8 @@ class rcube_imap_generic * Possible: SUBSCRIBED, RECURSIVEMATCH, REMOTE, * SPECIAL-USE (RFC6154) * - * @return array List of mailboxes or hash of options if $status_ops argument - * is non-empty. + * @return array|bool List of mailboxes or hash of options if STATUS/MYROGHTS response + * is requested, False on error. */ protected function _listMailboxes($ref, $mailbox, $subscribed=false, $return_opts=array(), $select_opts=array()) @@ -1355,7 +1355,9 @@ class rcube_imap_generic $args[] = $this->escape($mailbox); if (!empty($return_opts) && $this->getCapability('LIST-EXTENDED')) { - $rets = array_intersect($return_opts, array('SUBSCRIBED', 'CHILDREN')); + $ext_opts = array('SUBSCRIBED', 'CHILDREN'); + $rets = array_intersect($return_opts, $ext_opts); + $return_opts = array_diff($return_opts, $rets); } if (!empty($return_opts) && $this->getCapability('LIST-STATUS')) { -- cgit v1.2.3 From e1567419411fbd56a3f3ac5f0a805b1e345fa0cc Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 28 Jul 2014 19:03:16 +0200 Subject: Fix bug where $Forwarded flag was being set even if server didn't support it (#1490000) --- CHANGELOG | 1 + program/lib/Roundcube/rcube_imap_generic.php | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/CHANGELOG b/CHANGELOG index 6ca28478d..a6ade5bfc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -40,6 +40,7 @@ CHANGELOG Roundcube Webmail - Fix mbox files import - Fix some mime-type to extension mapping checks in Installer (#1489983) - Fix errors when using localStorage in Safari's private browsing mode (#1489996) +- Fix bug where $Forwarded flag was being set even if server didn't support it (#1490000) RELEASE 1.0.2 ------------- diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index d76014f89..a43dfeeed 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -2028,10 +2028,6 @@ class rcube_imap_generic */ protected function modFlag($mailbox, $messages, $flag, $mod = '+') { - if ($mod != '+' && $mod != '-') { - $mod = '+'; - } - if (!$this->select($mailbox)) { return false; } @@ -2041,12 +2037,25 @@ class rcube_imap_generic return false; } + if ($this->flags[strtoupper($flag)]) { + $flag = $this->flags[strtoupper($flag)]; + } + + if (!$flag || !in_array($flag, (array) $this->data['PERMANENTFLAGS']) + || !in_array('\\*', (array) $this->data['PERMANENTFLAGS']) + ) { + return false; + } + // Clear internal status cache if ($flag == 'SEEN') { unset($this->data['STATUS:'.$mailbox]['UNSEEN']); } - $flag = $this->flags[strtoupper($flag)]; + if ($mod != '+' && $mod != '-') { + $mod = '+'; + } + $result = $this->execute('UID STORE', array( $this->compressMessageSet($messages), $mod . 'FLAGS.SILENT', "($flag)"), self::COMMAND_NORESPONSE); -- cgit v1.2.3 From 35b39c8d7d2a994e6aa0d8e700d2c912d3483a85 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 26 Aug 2014 19:22:53 +0200 Subject: Fix PERMANENTFLAGS checking in modFlag() --- program/lib/Roundcube/rcube_imap_generic.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'program/lib/Roundcube/rcube_imap_generic.php') diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index a43dfeeed..68d9c6a2c 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -2041,8 +2041,8 @@ class rcube_imap_generic $flag = $this->flags[strtoupper($flag)]; } - if (!$flag || !in_array($flag, (array) $this->data['PERMANENTFLAGS']) - || !in_array('\\*', (array) $this->data['PERMANENTFLAGS']) + if (!$flag || (!in_array($flag, (array) $this->data['PERMANENTFLAGS']) + && !in_array('\\*', (array) $this->data['PERMANENTFLAGS'])) ) { return false; } -- cgit v1.2.3