From bb8012cfcde4ee598c2281373252a84ce0c96cc2 Mon Sep 17 00:00:00 2001 From: alecpl <alec@alec.pl> Date: Thu, 13 May 2010 05:13:25 -0400 Subject: [PATCH] - Extend contact groups support (#1486682) --- program/include/rcube_imap.php | 209 +++++++++++++++++++++++++++++++++++---------------- 1 files changed, 143 insertions(+), 66 deletions(-) diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 26d0ef4..1a66576 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -21,16 +21,13 @@ */ -require_once('lib/mime.inc'); -require_once('lib/tnef_decoder.inc'); - - /** * Interface class for accessing an IMAP server * * @package Mail * @author Thomas Bruederli <roundcube@gmail.com> - * @version 1.6 + * @author Aleksander Machniak <alec@alec.pl> + * @version 2.0 */ class rcube_imap { @@ -95,7 +92,7 @@ */ function connect($host, $user, $pass, $port=143, $use_ssl=null) { - // check for Open-SSL support in PHP build + // check for OpenSSL support in PHP build if ($use_ssl && extension_loaded('openssl')) $this->options['ssl_mode'] = $use_ssl == 'imaps' ? 'ssl' : $use_ssl; else if ($use_ssl) { @@ -412,16 +409,18 @@ /** * Get message count for a specific mailbox * - * @param string Mailbox/folder name - * @param string Mode for count [ALL|THREADS|UNSEEN|RECENT] - * @param boolean Force reading from server and update cache - * @return int Number of messages - * @access public + * @param string Mailbox/folder name + * @param string Mode for count [ALL|THREADS|UNSEEN|RECENT] + * @param boolean Force reading from server and update cache + * @param boolean Enables storing folder status info (max UID/count), + * required for mailbox_status() + * @return int Number of messages + * @access public */ - function messagecount($mbox_name='', $mode='ALL', $force=false) + function messagecount($mbox_name='', $mode='ALL', $force=false, $status=true) { $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox; - return $this->_messagecount($mailbox, $mode, $force); + return $this->_messagecount($mailbox, $mode, $force, $status); } @@ -431,7 +430,7 @@ * @access private * @see rcube_imap::messagecount() */ - private function _messagecount($mailbox='', $mode='ALL', $force=false) + private function _messagecount($mailbox='', $mode='ALL', $force=false, $status=true) { $mode = strtoupper($mode); @@ -457,7 +456,10 @@ if ($mode == 'THREADS') { $count = $this->_threadcount($mailbox, $msg_count); - $_SESSION['maxuid'][$mailbox] = $msg_count ? $this->_id2uid($msg_count) : 0; + if ($status) { + $this->set_folder_stats($mailbox, 'cnt', $msg_count); + $this->set_folder_stats($mailbox, 'maxuid', $msg_count ? $this->_id2uid($msg_count, $mailbox) : 0); + } } // RECENT count is fetched a bit different else if ($mode == 'RECENT') { @@ -481,15 +483,20 @@ $count = is_array($index) ? count($index) : 0; - if ($mode == 'ALL') - $_SESSION['maxuid'][$mailbox] = $index ? $this->_id2uid(max($index)) : 0; + if ($mode == 'ALL' && $status) { + $this->set_folder_stats($mailbox, 'cnt', $count); + $this->set_folder_stats($mailbox, 'maxuid', $index ? $this->_id2uid(max($index), $mailbox) : 0); + } } else { if ($mode == 'UNSEEN') $count = $this->conn->countUnseen($mailbox); else { $count = $this->conn->countMessages($mailbox); - $_SESSION['maxuid'][$mailbox] = $count ? $this->_id2uid($count) : 0; + if ($status) { + $this->set_folder_stats($mailbox,'cnt', $count); + $this->set_folder_stats($mailbox, 'maxuid', $count ? $this->_id2uid($count, $mailbox) : 0); + } } } @@ -1033,32 +1040,70 @@ return count($a_msg_headers); } + /** - * Fetches IDS of pseudo recent messages. + * Returns current status of mailbox * * We compare the maximum UID to determine the number of * new messages because the RECENT flag is not reliable. * - * @param string Mailbox/folder name - * @return array List of recent message UIDs + * @param string Mailbox/folder name + * @return int Folder status */ - function recent_uids($mbox_name = null, $nofetch = false) + function mailbox_status($mbox_name = null) { $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox; - $old_maxuid = intval($_SESSION['maxuid'][$mailbox]); - - // refresh message count -> will update $_SESSION['maxuid'][$mailbox] + $old = $this->get_folder_stats($mailbox); + + // refresh message count -> will update $this->_messagecount($mailbox, 'ALL', true); - - if ($_SESSION['maxuid'][$mailbox] > $old_maxuid) { - $maxuid = max(1, $old_maxuid+1); - return array_values((array)$this->conn->fetchHeaderIndex( - $mailbox, "$maxuid:*", 'UID', $this->skip_deleted, true)); - } - - return array(); + + $result = 0; + $new = $this->get_folder_stats($mailbox); + + // got new messages + if ($new['maxuid'] > $old['maxuid']) + $result += 1; + // some messages has been deleted + if ($new['cnt'] < $old['cnt']) + $result += 2; + + // @TODO: optional checking for messages flags changes (?) + // @TODO: UIDVALIDITY checking + + return $result; } - + + + /** + * Stores folder statistic data in session + * @TODO: move to separate DB table (cache?) + * + * @param string Mailbox name + * @param string Data name + * @param mixed Data value + */ + private function set_folder_stats($mbox_name, $name, $data) + { + $_SESSION['folders'][$mbox_name][$name] = $data; + } + + + /** + * Gets folder statistic data + * + * @param string Mailbox name + * @return array Stats data + */ + private function get_folder_stats($mbox_name) + { + if ($_SESSION['folders'][$mbox_name]) + return (array) $_SESSION['folders'][$mbox_name]; + else + return array(); + } + + /** * Return sorted array of message IDs (not UIDs) * @@ -1414,6 +1459,27 @@ return $a_messages; } + + /** + * Direct (real and simple) SEARCH request to IMAP server, + * without result sorting and caching + * + * @param string Mailbox name to search in + * @param string Search string + * @param boolean True if UIDs should be returned + * @return array Search results as list of message IDs or UIDs + * @access public + */ + function search_once($mbox_name='', $str=NULL, $ret_uid=false) + { + if (!$str) + return false; + + $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox; + + return $this->conn->search($mailbox, $str, $ret_uid); + } + /** * Sort thread @@ -1517,9 +1583,8 @@ { if (!empty($this->search_string)) $this->search_set = $this->search('', $this->search_string, $this->search_charset, + $this->search_sort_field, $this->search_threads); - $this->search_sort_field, $this->search_threads); - return $this->get_search_set(); } @@ -1554,7 +1619,7 @@ function get_headers($id, $mbox_name=NULL, $is_uid=true, $bodystr=false) { $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox; - $uid = $is_uid ? $id : $this->_id2uid($id); + $uid = $is_uid ? $id : $this->_id2uid($id, $mailbox); // get cached headers if ($uid && ($headers = &$this->get_cached_message($mailbox.'.msg', $uid))) @@ -1568,7 +1633,7 @@ if ($headers->uid && $headers->id) $this->uid_id_map[$mailbox][$headers->uid] = $headers->id; - $this->add_message_cache($mailbox.'.msg', $headers->id, $headers, NULL, true); + $this->add_message_cache($mailbox.'.msg', $headers->id, $headers, NULL); } return $headers; @@ -1593,9 +1658,10 @@ return $headers->structure; } - if (!$structure_str) + if (!$structure_str) { $structure_str = $this->conn->fetchStructureString($this->mailbox, $uid, true); - $structure = iml_GetRawStructureArray($structure_str); + } + $structure = rcube_mime_struct::parseStructure($structure_str); $struct = false; // parse structure and add headers @@ -1945,16 +2011,16 @@ // get part encoding if not provided if (!is_object($o_part)) { $structure_str = $this->conn->fetchStructureString($this->mailbox, $uid, true); - $structure = iml_GetRawStructureArray($structure_str); + $structure = new rcube_mime_struct(); // error or message not found - if (empty($structure)) + if (!$structure->loadStructure($structure_str)) { return false; + } - $part_type = iml_GetPartTypeCode($structure, $part); $o_part = new rcube_message_part; - $o_part->ctype_primary = $part_type==0 ? 'text' : ($part_type==2 ? 'message' : 'other'); - $o_part->encoding = strtolower(iml_GetPartEncodingString($structure, $part)); - $o_part->charset = iml_GetPartCharset($structure, $part); + $o_part->ctype_primary = strtolower($structure->getPartType($part)); + $o_part->encoding = strtolower($structure->getPartEncoding($part)); + $o_part->charset = $structure->getPartCharset($part); } // TODO: Add caching for message parts @@ -2460,10 +2526,10 @@ $a_out = array(); $a_mboxes = $this->_list_mailboxes($root, $filter); - foreach ($a_mboxes as $mbox_row) { - $name = $this->mod_mailbox($mbox_row, 'out'); - if (strlen($name)) + foreach ($a_mboxes as $idx => $mbox_row) { + if ($name = $this->mod_mailbox($mbox_row, 'out')) $a_out[] = $name; + unset($a_mboxes[$idx]); } // INBOX should always be available @@ -2523,24 +2589,28 @@ */ function list_unsubscribed($root='') { - static $sa_unsubscribed; + static $a_folders; - if (is_array($sa_unsubscribed)) - return $sa_unsubscribed; + if (is_array($a_folders)) + return $a_folders; // retrieve list of folders from IMAP server $a_mboxes = $this->conn->listMailboxes($this->mod_mailbox($root), '*'); // modify names with root dir - foreach ($a_mboxes as $mbox_name) { - $name = $this->mod_mailbox($mbox_name, 'out'); - if (strlen($name)) + foreach ($a_mboxes as $idx => $mbox_name) { + if ($name = $this->mod_mailbox($mbox_name, 'out')) $a_folders[] = $name; + unset($a_mboxes[$idx]); } + // INBOX should always be available + if (!in_array('INBOX', $a_folders)) + array_unshift($a_folders, 'INBOX'); + // filter folders and sort them - $sa_unsubscribed = $this->_sort_mailbox_list($a_folders); - return $sa_unsubscribed; + $a_folders = $this->_sort_mailbox_list($a_folders); + return $a_folders; } @@ -2687,7 +2757,7 @@ foreach ($a_mboxes as $mbox_name) { $mailbox = $this->mod_mailbox($mbox_name); $sub_mboxes = $this->conn->listMailboxes($this->mod_mailbox(''), - $mbox_name . $this->delimiter . '*'); + $mbox_name . $this->delimiter . '*'); // unsubscribe mailbox before deleting $this->conn->unsubscribe($mailbox); @@ -2698,7 +2768,7 @@ $deleted = true; $this->clear_message_cache($mailbox.'.msg'); } - + foreach ($sub_mboxes as $c_mbox) { if ($c_mbox != 'INBOX') { $this->conn->unsubscribe($c_mbox); @@ -2748,14 +2818,19 @@ if ($mbox_name == 'INBOX') return true; + $key = $subscription ? 'subscribed' : 'existing'; + if (is_array($this->icache[$key]) && in_array($mbox_name, $this->icache[$key])) + return true; + if ($subscription) { - if ($a_folders = $this->conn->listSubscribed($this->mod_mailbox(''), $mbox_name)) - return true; + $a_folders = $this->conn->listSubscribed($this->mod_mailbox(''), $mbox_name); } else { - $a_folders = $this->conn->listMailboxes($this->mod_mailbox(''), $mbox_mbox); - - if (is_array($a_folders) && in_array($this->mod_mailbox($mbox_name), $a_folders)) + $a_folders = $this->conn->listMailboxes($this->mod_mailbox(''), $mbox_name); + } + + if (is_array($a_folders) && in_array($this->mod_mailbox($mbox_name), $a_folders)) { + $this->icache[$key][] = $mbox_name; return true; } } @@ -3129,7 +3204,7 @@ if (!$this->caching_enabled) return; - // check for an existing record (probly headers are cached but structure not) + // check for an existing record (probably headers are cached but structure not) if (!$force) { $sql_result = $this->db->query( "SELECT message_id". @@ -3309,6 +3384,8 @@ { if (!isset($part->body)) $part->body = $this->get_message_part($uid, $part->mime_id, $part); + + require_once('lib/tnef_decoder.inc'); $pid = 0; $tnef_parts = array(); @@ -3513,7 +3590,7 @@ if (($p = array_search($folder, $this->default_folders)) !== false && !$a_defaults[$p]) $a_defaults[$p] = $folder; else - $folders[$folder] = mb_strtolower(rcube_charset_convert($folder, 'UTF7-IMAP')); + $folders[$folder] = rcube_charset_convert($folder, 'UTF7-IMAP'); } // sort folders and place defaults on the top -- Gitblit v1.9.1