From 66773789e392305bba4cdf7ed8e6ae3b8380de51 Mon Sep 17 00:00:00 2001 From: svncommit <devs@roundcube.net> Date: Thu, 27 Oct 2005 09:45:33 -0400 Subject: [PATCH] --- program/include/rcube_imap.inc | 316 +++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 247 insertions(+), 69 deletions(-) diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc index 2143416..8253442 100644 --- a/program/include/rcube_imap.inc +++ b/program/include/rcube_imap.inc @@ -23,11 +23,13 @@ require_once('lib/imap.inc'); require_once('lib/mime.inc'); +require_once('lib/utf7.inc'); class rcube_imap { var $conn; + var $root_ns = ''; var $root_dir = ''; var $mailbox = 'INBOX'; var $list_page = 1; @@ -54,46 +56,54 @@ } - function iloha_imap($connection='') - { - if ($connection) - { - $a_url = parse_url($connection); - $scheme = $a_url['scheme'] ? $a_url['scheme'] : 'imap'; - $port = $a_url['port'] ? $a_url['port'] : ($scheme=='imaps' ? 993 : 143); - $host = $a_url['host']; - $user = $a_url['user']; - $pass = $a_url['pass']; - - //var_dump($a_url); - - $this->connect($host, $user, $pass, $port); - } - } - - function connect($host, $user, $pass, $port=143, $use_ssl=FALSE) { - global $ICL_PORT, $CONFIG; + global $ICL_SSL, $ICL_PORT, $CONFIG; // check for Open-SSL support in PHP build if ($use_ssl && in_array('openssl', get_loaded_extensions())) $ICL_SSL = TRUE; + else if ($use_ssl) + { + raise_error(array('code' => 403, + 'type' => 'imap', + 'file' => __FILE__, + 'message' => 'Open SSL not available;'), TRUE, FALSE); + $port = 143; + } $ICL_PORT = $port; $this->conn = iil_Connect($host, $user, $pass, array('imap' => 'check')); $this->host = $host; $this->user = $user; $this->pass = $pass; + $this->port = $port; + $this->ssl = $use_ssl; + // print trace mesages if ($this->conn && ($CONFIG['debug_level'] & 8)) - print $this->conn->message; - + console($this->conn->message); + + // write error log else if (!$this->conn && $GLOBALS['iil_error']) { raise_error(array('code' => 403, 'type' => 'imap', 'message' => $GLOBALS['iil_error']), TRUE, FALSE); + } + + // get account namespace + if ($this->conn) + { + iil_C_NameSpace($this->conn); + + if (!empty($this->conn->delimiter)) + $this->delimiter = $this->conn->delimiter; + if (!empty($this->conn->rootdir)) + { + $this->set_rootdir($this->conn->rootdir); + $this->root_ns = ereg_replace('[\.\/]$', '', $this->conn->rootdir); + } } return $this->conn ? TRUE : FALSE; @@ -107,12 +117,22 @@ } + function reconnect() + { + $this->close(); + $this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl); + } + + function set_rootdir($root) { - if (substr($root, -1, 1)==='/') + if (ereg('[\.\/]$', $root)) //(substr($root, -1, 1)==='/') $root = substr($root, 0, -1); $this->root_dir = $root; + + if (empty($this->delimiter)) + $this->get_hierarchy_delimiter(); } @@ -169,6 +189,9 @@ { if ($this->conn && empty($this->delimiter)) $this->delimiter = iil_C_GetHierarchyDelimiter($this->conn); + + if (empty($this->delimiter)) + $this->delimiter = '/'; return $this->delimiter; } @@ -253,8 +276,6 @@ else $count = iil_C_CountMessages($this->conn, $mailbox); -//print "/**** get messagecount for $mailbox ($mode): $count ****/\n"; - if (is_array($a_mailbox_cache[$mailbox])) $a_mailbox_cache[$mailbox] = array(); @@ -262,8 +283,6 @@ // write back to cache $this->update_cache('messagecount', $a_mailbox_cache); - -//var_dump($a_mailbox_cache); return (int)$count; } @@ -279,45 +298,132 @@ // private method for listing message header - function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC') + // by DrSlump <drslump@drslump.biz> + function __list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC') { - $max = $this->_messagecount($mailbox /*, 'ALL', TRUE*/); $a_out = array(); - + $cached_count = 0; + if (!strlen($mailbox)) return $a_out; + $mbox_count = $this->_messagecount($mailbox /*, 'ALL', TRUE*/); - // get cached headers - $a_msg_headers = $this->get_cache($mailbox.'.msg'); - -// print "/**** count = $max; headers = ".sizeof($a_msg_headers)." ****/\n"; - - // retrieve headers from IMAP - if (!is_array($a_msg_headers) || sizeof($a_msg_headers) != $max) + $revalidate = false; + if ($mbox_count) { - $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, "1:$max"); - $a_msg_headers = array(); - foreach ($a_header_index as $i => $headers) - $a_msg_headers[$headers->uid] = $headers; - -// print "/**** fetch headers ****/\n"; + // get cached headers + $a_out = $this->get_cache($mailbox.'.msg'); + $a_out = is_array($a_out) ? $a_out : array(); // make sure we get an array + + $cached_count = count($a_out); + $a_new = array(); + $revalidate = true; // revalidate by default + + // if the cache count is greater then there have been changes for sure + if ($cached_count <= $mbox_count) + { + $from = $cached_count?$cached_count:1; + + //get new headers (at least one is returned) + $a_temp = iil_C_FetchHeaders($this->conn, $mailbox, $from . ':' . $mbox_count); + $duplicated = $cached_count?true:false; + + foreach ($a_temp as $hdr) + { + //skip the first one if duplicated + if ($duplicated) + { + //check for changes using the UID + $lastCacheHdr = end($a_out); + if ($hdr->uid === $lastCacheHdr->uid) + $revalidate = false; + + $duplicated = false; + continue; + } + + //skip deleted ones + if (! $hdr->deleted) + $a_new[ $hdr->uid ] = $hdr; + } + } + + //revalidate cache if needed + $to = $mbox_count - count($a_new); + if ($revalidate && $to !== 0) //we'll need to reindex the array so we have to make a copy + { + $a_dirty = $a_out; + $a_out = array(); + $a_buffers = array(); + + //fetch chunks of 20 headers + $step = 20; + $found = false; + + //fetch headers in blocks starting from new to old + do { + $from = $to-$step; + if ($from < 1) $from = 1; + + //store the block in a temporal buffer + $a_buffers[$from] = iil_C_FetchHeaders($this->conn, $mailbox, $from . ':' . $to); + + //compare the fetched headers with the ones in the cache + $idx = 0; + foreach ($a_buffers[$from] as $k=>$hdr) + { + //if it's different the comparison ends + if (!isset($a_dirty[$hdr->uid]) || $a_dirty[$hdr->uid]->id !== $hdr->id) + break; + + //if we arrive here then we know that the older messages in cache are ok + $found = $hdr->id; + $idx++; + } + + //remove from the buffer the headers which are already cached + if ($found) + $a_buffers[$from] = array_splice($a_buffers[$from], 0, $idx ); + + $to = $from-1; + } + while ($found===false && $from > 1); + + //just keep the headers we are certain that didn't change in the cache + if ($found !== false) + { + foreach ($a_dirty as $hdr) + { + if ($hdr->id > $found) break; + $a_out[$hdr->uid] = $hdr; + } + } + + //we builded the block buffers from new to older, we process them in reverse order + ksort($a_buffers, SORT_NUMERIC); + foreach ($a_buffers as $a_buff) + { + foreach ($a_buff as $hdr) + { + if (! $hdr->deleted) + $a_out[$hdr->uid] = $hdr; + } + } + } + + //array_merge() would reindex the keys, so we use this 'hack' + $a_out += $a_new; } - else - $headers_cached = TRUE; + + //write headers list to cache if needed + if ($revalidate || count($a_out)!=$cached_count) { + $this->update_cache($mailbox.'.msg', $a_out); + } - // sort headers by a specific col - $a_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order); - - // write headers list to cache - if (!$headers_cached) - $this->update_cache($mailbox.'.msg', $a_msg_headers); - - if (is_array($a_headers)) - foreach ($a_headers as $header) - if (!$header->deleted) - $a_out[] = $header; - + //sort headers by a specific col + $a_out = iil_SortHeaders( $a_out, $sort_field, $sort_order ); + // return complete list of messages if (strtolower($page)=='all') return $a_out; @@ -326,6 +432,57 @@ return array_slice($a_out, $start_msg, $this->page_size); } + + // original function; replaced 2005/10/18 + // private method for listing message header + function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC') + { + $max = $this->_messagecount($mailbox); + + if (!strlen($mailbox)) + return array(); + + // get cached headers + $a_msg_headers = $this->get_cache($mailbox.'.msg'); + + // retrieve headers from IMAP + if (!is_array($a_msg_headers) || sizeof($a_msg_headers) != $max) + { + $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, "1:$max"); + $a_msg_headers = array(); + + if (!empty($a_header_index)) + foreach ($a_header_index as $i => $headers) + if (!$headers->deleted) + $a_msg_headers[$headers->uid] = $headers; + } + else + $headers_cached = TRUE; + + if (!is_array($a_msg_headers)) + return array(); + + // sort headers by a specific col + $a_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order); + + // free memory + unset($a_msg_headers); + + // write headers list to cache + if (!$headers_cached) + $this->update_cache($mailbox.'.msg', $a_headers); + + if (empty($a_headers)) + return array(); + + // return complete list of messages + if (strtolower($page)=='all') + return $a_headers; + + $start_msg = ($this->list_page-1) * $this->page_size; + return array_slice($a_headers, $start_msg, $this->page_size); + } + // return sorted array of message UIDs function message_index($mbox='', $sort_field='date', $sort_order='DESC') @@ -368,10 +525,10 @@ // return cached header if ($a_msg_headers[$uid]) return $a_msg_headers[$uid]; - + $msg_id = $this->_uid2id($uid); $header = iil_C_FetchHeader($this->conn, $mailbox, $msg_id); - + // write headers cache $a_msg_headers[$uid] = $header; $this->update_cache($mailbox.'.msg', $a_msg_headers); @@ -427,11 +584,13 @@ else $result = iil_C_Flag($this->conn, $this->mailbox, join(',', $msg_ids), $flag); - // reload message headers if cached $cache_key = $this->mailbox.'.msg'; - if ($result && ($a_cached_headers = $this->get_cache($cache_key))) + if ($this->caching_enabled && $result && ($a_cached_headers = $this->get_cache($cache_key))) { + // close and re-open connection + $this->reconnect(); + foreach ($uids as $uid) { if (isset($a_cached_headers[$uid])) @@ -492,12 +651,12 @@ // exit if no message uids are specified if (!is_array($a_uids)) return false; - + // convert uids to message ids $a_mids = array(); foreach ($a_uids as $uid) $a_mids[] = $this->_uid2id($uid, $from_mbox); - + $moved = iil_C_Move($this->conn, join(',', $a_mids), $from_mbox, $to_mbox); // send expunge command in order to have the moved message @@ -562,7 +721,19 @@ } return $deleted; + } + + // clear all messages in a specific mailbox + function clear_mailbox($mbox) + { + $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox; + $msg_count = $this->_messagecount($mailbox, 'ALL'); + + if ($msg_count>0) + return iil_C_ClearFolder($this->conn, $mailbox); + else + return 0; } @@ -644,17 +815,21 @@ function create_mailbox($name, $subscribe=FALSE) { $result = FALSE; - $abs_name = $this->_mod_mailbox($name); + $name_enc = UTF7EncodeString($name); + $abs_name = $this->_mod_mailbox($name_enc); $a_mailbox_cache = $this->get_cache('mailboxes'); + + //if (strlen($this->root_ns)) + // $abs_name = $this->root_ns.$abs_name; if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache))) $result = iil_C_CreateFolder($this->conn, $abs_name); // update mailboxlist cache if ($result && $subscribe) - $this->subscribe($name); + $this->subscribe($name_enc); - return $result; + return $result ? $name : FALSE; } @@ -897,7 +1072,7 @@ // convert body chars according to the ctype_parameters function charset_decode($body, $ctype_param) { - if (is_array($ctype_param) && strlen($ctype_param['charset'])) + if (is_array($ctype_param) && !empty($ctype_param['charset'])) return decode_specialchars($body, $ctype_param['charset']); return $body; @@ -911,9 +1086,12 @@ function _mod_mailbox($mbox, $mode='in') { - if ($this->root_dir && $mode=='in') - $mbox = $this->root_dir.'/'.$mbox; - else if ($this->root_dir && $mode=='out') + if ((!empty($this->root_ns) && $this->root_ns == $mbox) || ($mbox == 'INBOX' && $mode == 'in')) + return $mbox; + + if (!empty($this->root_dir) && $mode=='in') + $mbox = $this->root_dir.$this->delimiter.$mbox; + else if (strlen($this->root_dir) && $mode=='out') $mbox = substr($mbox, strlen($this->root_dir)+1); return $mbox; -- Gitblit v1.9.1