From 5587b34cfa5d04fec8e009288cabd0ffdbf39413 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Wed, 30 Nov 2011 06:05:50 -0500
Subject: [PATCH] Enable buttons having an inner <span> for better CSS styling capabilities
---
program/include/rcube_imap.php | 362 +++++++++++++++++++++++++++++++++++++--------------
1 files changed, 261 insertions(+), 101 deletions(-)
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 03dc90a..50656f2 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -32,7 +32,6 @@
*/
class rcube_imap
{
- public $debug_level = 1;
public $skip_deleted = false;
public $page_size = 10;
public $list_page = 1;
@@ -318,6 +317,19 @@
/**
+ * Activate/deactivate debug mode
+ *
+ * @param boolean $dbg True if IMAP conversation should be logged
+ * @access public
+ */
+ function set_debug($dbg = true)
+ {
+ $this->options['debug'] = $dbg;
+ $this->conn->setDebug($dbg, array($this, 'debug_handler'));
+ }
+
+
+ /**
* Set default message charset
*
* This will be used for message decoding if a charset specification is not available
@@ -466,7 +478,7 @@
*/
function get_mailbox_name()
{
- return $this->conn->connected() ? $this->mailbox : '';
+ return $this->mailbox;
}
@@ -917,7 +929,6 @@
$msg_index = array_keys($msg_index);
list($begin, $end) = $this->_get_message_range(count($msg_index), $page);
$msg_index = array_slice($msg_index, $begin, $end-$begin);
- $is_uid = true;
if ($slice)
$msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice);
@@ -1362,6 +1373,11 @@
$this->_messagecount($mailbox, 'ALL', true);
$result = 0;
+
+ if (empty($old)) {
+ return $result;
+ }
+
$new = $this->get_folder_stats($mailbox);
// got new messages
@@ -1509,7 +1525,7 @@
// I didn't found that SEARCH should return sorted IDs
if (is_array($a_index))
sort($a_index);
- } else if ($max = $this->_messagecount($mailbox)) {
+ } else if ($max = $this->_messagecount($mailbox, 'ALL', true, false)) {
$a_index = range(1, $max);
}
@@ -1695,7 +1711,7 @@
}
if ($orig_criteria == 'ALL') {
- $max = $this->_messagecount($mailbox);
+ $max = $this->_messagecount($mailbox, 'ALL', true, false);
$a_messages = $max ? range(1, $max) : array();
}
else {
@@ -1962,6 +1978,10 @@
}
$headers = $this->get_headers($uid, $mailbox);
+
+ // message doesn't exist?
+ if (empty($headers))
+ return null;
// structure might be cached
if (!empty($headers->structure))
@@ -2321,9 +2341,14 @@
// decode filename
if (!empty($filename_mime)) {
- $part->filename = rcube_imap::decode_mime_string($filename_mime,
- $part->charset ? $part->charset : ($this->struct_charset ? $this->struct_charset :
- rc_detect_encoding($filename_mime, $this->default_charset)));
+ if (!empty($part->charset))
+ $charset = $part->charset;
+ else if (!empty($this->struct_charset))
+ $charset = $this->struct_charset;
+ else
+ $charset = rc_detect_encoding($filename_mime, $this->default_charset);
+
+ $part->filename = rcube_imap::decode_mime_string($filename_mime, $charset);
}
else if (!empty($filename_encoded)) {
// decode filename according to RFC 2231, Section 4
@@ -2331,6 +2356,7 @@
$filename_charset = $fmatches[1];
$filename_encoded = $fmatches[2];
}
+
$part->filename = rcube_charset_convert(urldecode($filename_encoded), $filename_charset);
}
}
@@ -2367,24 +2393,22 @@
*/
function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false)
{
- // get part encoding if not provided
+ // get part data if not provided
if (!is_object($o_part)) {
$structure = $this->conn->getStructure($this->mailbox, $uid, true);
+ $part_data = rcube_imap_generic::getStructurePartData($structure, $part);
$o_part = new rcube_message_part;
- $o_part->ctype_primary = strtolower(rcube_imap_generic::getStructurePartType($structure, $part));
- $o_part->encoding = strtolower(rcube_imap_generic::getStructurePartEncoding($structure, $part));
- $o_part->charset = rcube_imap_generic::getStructurePartCharset($structure, $part);
+ $o_part->ctype_primary = $part_data['type'];
+ $o_part->encoding = $part_data['encoding'];
+ $o_part->charset = $part_data['charset'];
+ $o_part->size = $part_data['size'];
}
- // TODO: Add caching for message parts
-
- if (!$part) {
- $part = 'TEXT';
+ if ($o_part && $o_part->size) {
+ $body = $this->conn->handlePartBody($this->mailbox, $uid, true,
+ $part ? $part : 'TEXT', $o_part->encoding, $print, $fp);
}
-
- $body = $this->conn->handlePartBody($this->mailbox, $uid, true, $part,
- $o_part->encoding, $print, $fp);
if ($fp || $print) {
return true;
@@ -2392,12 +2416,18 @@
// convert charset (if text or message part)
if ($body && preg_match('/^(text|message)$/', $o_part->ctype_primary)) {
- // Remove NULL characters (#1486189)
- $body = str_replace("\x00", '', $body);
+ // Remove NULL characters if any (#1486189)
+ if (strpos($body, "\x00") !== false) {
+ $body = str_replace("\x00", '', $body);
+ }
- if (!$skip_charset_conv) {
+ if (!$skip_charset_conv) {
if (!$o_part->charset || strtoupper($o_part->charset) == 'US-ASCII') {
- $o_part->charset = $this->default_charset;
+ // try to extract charset information from HTML meta tag (#1488125)
+ if ($o_part->ctype_secondary == 'html' && preg_match('/<meta[^>]+charset=([a-z0-9-_]+)/i', $body, $m))
+ $o_part->charset = strtoupper($m[1]);
+ else
+ $o_part->charset = $this->default_charset;
}
$body = rcube_charset_convert($body, $o_part->charset);
}
@@ -2532,7 +2562,7 @@
* @param string $headers Headers string if $message contains only the body
* @param boolean $is_file True if $message is a filename
*
- * @return boolean True on success, False on error
+ * @return int|bool Appended message UID or True on success, False on error
*/
function save_message($mailbox, &$message, $headers='', $is_file=false)
{
@@ -2583,10 +2613,14 @@
// make sure mailbox exists
if ($to_mbox != 'INBOX' && !$this->mailbox_exists($to_mbox)) {
- if (in_array($to_mbox, $this->default_folders))
- $this->create_mailbox($to_mbox, true);
- else
+ if (in_array($to_mbox, $this->default_folders)) {
+ if (!$this->create_mailbox($to_mbox, true)) {
+ return false;
+ }
+ }
+ else {
return false;
+ }
}
$config = rcmail::get_instance()->config;
@@ -2664,10 +2698,14 @@
// make sure mailbox exists
if ($to_mbox != 'INBOX' && !$this->mailbox_exists($to_mbox)) {
- if (in_array($to_mbox, $this->default_folders))
- $this->create_mailbox($to_mbox, true);
- else
+ if (in_array($to_mbox, $this->default_folders)) {
+ if (!$this->create_mailbox($to_mbox, true)) {
+ return false;
+ }
+ }
+ else {
return false;
+ }
}
// copy messages
@@ -2915,47 +2953,22 @@
/**
* Public method for listing subscribed folders
*
- * @param string $root Optional root folder
- * @param string $name Optional name pattern
- * @param string $filter Optional filter
+ * @param string $root Optional root folder
+ * @param string $name Optional name pattern
+ * @param string $filter Optional filter
+ * @param string $rights Optional ACL requirements
+ * @param bool $skip_sort Enable to return unsorted list (for better performance)
*
- * @return array List of mailboxes/folders
+ * @return array List of folders
* @access public
*/
- function list_mailboxes($root='', $name='*', $filter=null)
- {
- $a_mboxes = $this->_list_mailboxes($root, $name, $filter);
-
- // INBOX should always be available
- if ((!$filter || $filter == 'mail') && !in_array('INBOX', $a_mboxes)) {
- array_unshift($a_mboxes, 'INBOX');
- }
-
- // sort mailboxes
- $a_mboxes = $this->_sort_mailbox_list($a_mboxes);
-
- return $a_mboxes;
- }
-
-
- /**
- * Private method for mailbox listing
- *
- * @param string $root Optional root folder
- * @param string $name Optional name pattern
- * @param mixed $filter Optional filter
- *
- * @return array List of mailboxes/folders
- * @see rcube_imap::list_mailboxes()
- * @access private
- */
- private function _list_mailboxes($root='', $name='*', $filter=null)
+ function list_mailboxes($root='', $name='*', $filter=null, $rights=null, $skip_sort=false)
{
$cache_key = $root.':'.$name;
if (!empty($filter)) {
$cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter));
}
-
+ $cache_key .= ':'.$rights;
$cache_key = 'mailboxes.'.md5($cache_key);
// get cached folder list
@@ -2964,6 +2977,48 @@
return $a_mboxes;
}
+ $a_mboxes = $this->_list_mailboxes($root, $name, $filter, $rights);
+
+ if (!is_array($a_mboxes)) {
+ return array();
+ }
+
+ // filter folders list according to rights requirements
+ if ($rights && $this->get_capability('ACL')) {
+ $a_mboxes = $this->filter_rights($a_mboxes, $rights);
+ }
+
+ // INBOX should always be available
+ if ((!$filter || $filter == 'mail') && !in_array('INBOX', $a_mboxes)) {
+ array_unshift($a_mboxes, 'INBOX');
+ }
+
+ // sort mailboxes (always sort for cache)
+ if (!$skip_sort || $this->cache) {
+ $a_mboxes = $this->_sort_mailbox_list($a_mboxes);
+ }
+
+ // write mailboxlist to cache
+ $this->update_cache($cache_key, $a_mboxes);
+
+ return $a_mboxes;
+ }
+
+
+ /**
+ * Private method for mailbox listing (LSUB)
+ *
+ * @param string $root Optional root folder
+ * @param string $name Optional name pattern
+ * @param mixed $filter Optional filter
+ * @param string $rights Optional ACL requirements
+ *
+ * @return array List of subscribed folders
+ * @see rcube_imap::list_mailboxes()
+ * @access private
+ */
+ private function _list_mailboxes($root='', $name='*', $filter=null, $rights=null)
+ {
$a_defaults = $a_out = array();
// Give plugins a chance to provide a list of mailboxes
@@ -2974,7 +3029,7 @@
$a_folders = $data['folders'];
}
else if (!$this->conn->connected()) {
- return array();
+ return null;
}
else {
// Server supports LIST-EXTENDED, we can use selection options
@@ -3022,9 +3077,6 @@
$a_folders = array();
}
- // write mailboxlist to cache
- $this->update_cache($cache_key, $a_folders);
-
return $a_folders;
}
@@ -3032,15 +3084,29 @@
/**
* Get a list of all folders available on the IMAP server
*
- * @param string $root IMAP root dir
- * @param string $name Optional name pattern
- * @param mixed $filter Optional filter
+ * @param string $root IMAP root dir
+ * @param string $name Optional name pattern
+ * @param mixed $filter Optional filter
+ * @param string $rights Optional ACL requirements
+ * @param bool $skip_sort Enable to return unsorted list (for better performance)
*
* @return array Indexed array with folder names
*/
- function list_unsubscribed($root='', $name='*', $filter=null)
+ function list_unsubscribed($root='', $name='*', $filter=null, $rights=null, $skip_sort=false)
{
- // @TODO: caching
+ $cache_key = $root.':'.$name;
+ if (!empty($filter)) {
+ $cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter));
+ }
+ $cache_key .= ':'.$rights;
+ $cache_key = 'mailboxes.list.'.md5($cache_key);
+
+ // get cached folder list
+ $a_mboxes = $this->get_cache($cache_key);
+ if (is_array($a_mboxes)) {
+ return $a_mboxes;
+ }
+
// Give plugins a chance to provide a list of mailboxes
$data = rcmail::get_instance()->plugins->exec_hook('mailboxes_list',
array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LIST'));
@@ -3050,7 +3116,7 @@
}
else {
// retrieve list of folders from IMAP server
- $a_mboxes = $this->conn->listMailboxes($root, $name);
+ $a_mboxes = $this->_list_unsubscribed($root, $name);
}
if (!is_array($a_mboxes)) {
@@ -3062,10 +3128,105 @@
array_unshift($a_mboxes, 'INBOX');
}
+ // cache folder attributes
+ if ($root == '' && $name == '*' && empty($filter)) {
+ $this->update_cache('mailboxes.attributes', $this->conn->data['LIST']);
+ }
+
+ // filter folders list according to rights requirements
+ if ($rights && $this->get_capability('ACL')) {
+ $a_folders = $this->filter_rights($a_folders, $rights);
+ }
+
// filter folders and sort them
- $a_mboxes = $this->_sort_mailbox_list($a_mboxes);
+ if (!$skip_sort) {
+ $a_mboxes = $this->_sort_mailbox_list($a_mboxes);
+ }
+
+ // write mailboxlist to cache
+ $this->update_cache($cache_key, $a_mboxes);
return $a_mboxes;
+ }
+
+
+ /**
+ * Private method for mailbox listing (LIST)
+ *
+ * @param string $root Optional root folder
+ * @param string $name Optional name pattern
+ *
+ * @return array List of folders
+ * @see rcube_imap::list_unsubscribed()
+ */
+ private function _list_unsubscribed($root='', $name='*')
+ {
+ $result = $this->conn->listMailboxes($root, $name);
+
+ if (!is_array($result)) {
+ return array();
+ }
+
+ // #1486796: some server configurations doesn't
+ // return folders in all namespaces, we'll try to detect that situation
+ // and ask for these namespaces separately
+ if ($root == '' && $name == '*') {
+ $delim = $this->get_hierarchy_delimiter();
+ $namespace = $this->get_namespace();
+ $search = array();
+
+ // build list of namespace prefixes
+ foreach ((array)$namespace as $ns) {
+ if (is_array($ns)) {
+ foreach ($ns as $ns_data) {
+ if (strlen($ns_data[0])) {
+ $search[] = $ns_data[0];
+ }
+ }
+ }
+ }
+
+ if (!empty($search)) {
+ // go through all folders detecting namespace usage
+ foreach ($result as $folder) {
+ foreach ($search as $idx => $prefix) {
+ if (strpos($folder, $prefix) === 0) {
+ unset($search[$idx]);
+ }
+ }
+ if (empty($search)) {
+ break;
+ }
+ }
+
+ // get folders in hidden namespaces and add to the result
+ foreach ($search as $prefix) {
+ $list = $this->conn->listMailboxes($prefix, $name);
+
+ if (!empty($list)) {
+ $result = array_merge($result, $list);
+ }
+ }
+ }
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * Filter the given list of folders according to access rights
+ */
+ private function filter_rights($a_folders, $rights)
+ {
+ $regex = '/('.$rights.')/';
+ foreach ($a_folders as $idx => $folder) {
+ $myrights = join('', (array)$this->my_rights($folder));
+ if ($myrights !== null && !preg_match($regex, $myrights))
+ unset($a_folders[$idx]);
+ }
+
+ return $a_folders;
}
@@ -3325,8 +3486,8 @@
foreach ($this->namespace as $type => $namespace) {
if (is_array($namespace)) {
foreach ($namespace as $ns) {
- if (strlen($ns[0])) {
- if ((strlen($ns[0])>1 && $mailbox == substr($ns[0], 0, -1))
+ if ($len = strlen($ns[0])) {
+ if (($len > 1 && $mailbox == substr($ns[0], 0, -1))
|| strpos($mailbox, $ns[0]) === 0
) {
return $type;
@@ -3380,30 +3541,29 @@
/**
- * Gets folder options from LIST response, e.g. \Noselect, \Noinferiors
+ * Gets folder attributes from LIST response, e.g. \Noselect, \Noinferiors
*
* @param string $mailbox Folder name
- * @param bool $force Set to True if options should be refreshed
- * Options are available after LIST command only
+ * @param bool $force Set to True if attributes should be refreshed
*
* @return array Options list
*/
- function mailbox_options($mailbox, $force=false)
+ function mailbox_attributes($mailbox, $force=false)
{
- if ($mailbox == 'INBOX') {
- return array();
+ // get attributes directly from LIST command
+ if (!empty($this->conn->data['LIST']) && is_array($this->conn->data['LIST'][$mailbox])) {
+ $opts = $this->conn->data['LIST'][$mailbox];
+ }
+ // get cached folder attributes
+ else if (!$force) {
+ $opts = $this->get_cache('mailboxes.attributes');
+ $opts = $opts[$mailbox];
}
- if (!is_array($this->conn->data['LIST']) || !is_array($this->conn->data['LIST'][$mailbox])) {
- if ($force) {
- $this->conn->listMailboxes('', $mailbox);
- }
- else {
- return array();
- }
+ if (!is_array($opts)) {
+ $this->conn->listMailboxes('', $mailbox);
+ $opts = $this->conn->data['LIST'][$mailbox];
}
-
- $opts = $this->conn->data['LIST'][$mailbox];
return is_array($opts) ? $opts : array();
}
@@ -3486,17 +3646,17 @@
}
}
- $options['name'] = $mailbox;
- $options['options'] = $this->mailbox_options($mailbox, true);
- $options['namespace'] = $this->mailbox_namespace($mailbox);
- $options['rights'] = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array();
- $options['special'] = in_array($mailbox, $this->default_folders);
+ $options['name'] = $mailbox;
+ $options['attributes'] = $this->mailbox_attributes($mailbox, true);
+ $options['namespace'] = $this->mailbox_namespace($mailbox);
+ $options['rights'] = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array();
+ $options['special'] = in_array($mailbox, $this->default_folders);
// Set 'noselect' and 'norename' flags
- if (is_array($options['options'])) {
- foreach ($options['options'] as $opt) {
- $opt = strtolower($opt);
- if ($opt == '\noselect' || $opt == '\nonexistent') {
+ if (is_array($options['attributes'])) {
+ foreach ($options['attributes'] as $attrib) {
+ $attrib = strtolower($attrib);
+ if ($attrib == '\noselect' || $attrib == '\nonexistent') {
$options['noselect'] = true;
}
}
@@ -3747,7 +3907,7 @@
// @TODO: Honor MAXSIZE and DEPTH options
foreach ($queries as $attrib => $entry)
if ($result = $this->conn->getAnnotation($mailbox, $entry, $attrib))
- $res = array_merge($res, $result);
+ $res = array_merge_recursive($res, $result);
return $res;
}
--
Gitblit v1.9.1