From b8d96f6e609f3bb8a72fa724bc273175c8e7dbb1 Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Thu, 16 Sep 2010 09:02:27 -0400
Subject: [PATCH] - Use random sleep interval up to 3 sec. in 'get' action when IMAP conn. fails
---
program/include/rcube_imap.php | 345 +++++++++++++++++++++++++++++++--------------------------
1 files changed, 187 insertions(+), 158 deletions(-)
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index cdf346a..043d902 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -297,7 +297,9 @@
{
if (is_array($str) && $msgs == null)
list($str, $msgs, $charset, $sort_field, $threads) = $str;
- if ($msgs != null && !is_array($msgs))
+ if ($msgs === false)
+ $msgs = array();
+ else if ($msgs != null && !is_array($msgs))
$msgs = explode(',', $msgs);
$this->search_string = $str;
@@ -472,14 +474,9 @@
// get message count and store in cache
if ($mode == 'UNSEEN')
$search_str .= " UNSEEN";
-
// get message count using SEARCH
// not very performant but more precise (using UNDELETED)
- // disable THREADS for this request
- $threads = $this->threading;
- $this->threading = false;
- $index = $this->_search_index($mailbox, $search_str);
- $this->threading = $threads;
+ $index = $this->conn->search($mailbox, $search_str);
$count = is_array($index) ? count($index) : 0;
@@ -608,7 +605,7 @@
else
$msg_index = array();
- if ($slice)
+ if ($slice && $msg_index)
$msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice);
// fetch reqested headers from server
@@ -823,8 +820,11 @@
return $this->_list_thread_header_set($mailbox, $page, $sort_field, $sort_order, $slice);
// search set is threaded, we need a new one
- if ($this->search_threads)
+ if ($this->search_threads) {
+ if (empty($this->search_set['tree']))
+ return array();
$this->search('', $this->search_string, $this->search_charset, $sort_field);
+ }
$msgs = $this->search_set;
$a_msg_headers = array();
@@ -946,8 +946,15 @@
private function _list_thread_header_set($mailbox, $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0)
{
// update search_set if previous data was fetched with disabled threading
- if (!$this->search_threads)
+ if (!$this->search_threads) {
+ if (empty($this->search_set))
+ return array();
$this->search('', $this->search_string, $this->search_charset, $sort_field);
+ }
+
+ // empty result
+ if (empty($this->search_set['tree']))
+ return array();
$thread_tree = $this->search_set['tree'];
$msg_depth = $this->search_set['depth'];
@@ -1188,20 +1195,20 @@
$a_index = range(1, $max);
}
- if ($this->sort_order == 'DESC')
+ if ($a_index !== false && $this->sort_order == 'DESC')
$a_index = array_reverse($a_index);
$this->cache[$key] = $a_index;
}
// fetch complete message index
else if ($this->get_capability('SORT')) {
- if ($a_index = $this->conn->sort($mailbox,
- $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')) {
- if ($this->sort_order == 'DESC')
- $a_index = array_reverse($a_index);
+ $a_index = $this->conn->sort($mailbox,
+ $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '');
- $this->cache[$key] = $a_index;
- }
+ if ($a_index !== false && $this->sort_order == 'DESC')
+ $a_index = array_reverse($a_index);
+
+ $this->cache[$key] = $a_index;
}
else if ($a_index = $this->conn->fetchHeaderIndex(
$mailbox, "1:*", $this->sort_field, $this->skip_deleted)) {
@@ -1213,7 +1220,7 @@
$this->cache[$key] = array_keys($a_index);
}
- return $this->cache[$key];
+ return $this->cache[$key] !== false ? $this->cache[$key] : array();
}
@@ -1288,8 +1295,10 @@
$all_ids = array();
foreach($msg_index as $root) {
$all_ids[] = $root;
- if (!empty($thread_tree[$root]))
- $all_ids = array_merge($all_ids, array_keys_recursive($thread_tree[$root]));
+ if (!empty($thread_tree[$root])) {
+ foreach (array_keys_recursive($thread_tree[$root]) as $val)
+ $all_ids[] = $val;
+ }
}
return $all_ids;
@@ -1370,32 +1379,6 @@
$results = $this->_search_index($mailbox, $str, $charset, $sort_field);
- // try search with US-ASCII charset (should be supported by server)
- // only if UTF-8 search is not supported
- if (empty($results) && !is_array($results) && !empty($charset) && $charset != 'US-ASCII')
- {
- // convert strings to US_ASCII
- if(preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) {
- $last = 0; $res = '';
- foreach($matches[1] as $m)
- {
- $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
- $string = substr($str, $string_offset - 1, $m[0]);
- $string = rcube_charset_convert($string, $charset, 'US-ASCII');
- if (!$string)
- continue;
- $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string);
- $last = $m[0] + $string_offset - 1;
- }
- if ($last < strlen($str))
- $res .= substr($str, $last, strlen($str)-$last);
- }
- else // strings for conversion not found
- $res = $str;
-
- $results = $this->search($mbox_name, $res, NULL, $sort_field);
- }
-
$this->set_search_set($str, $results, $charset, $sort_field, (bool)$this->threading);
return $results;
@@ -1417,21 +1400,32 @@
$criteria = 'UNDELETED '.$criteria;
if ($this->threading) {
- list ($thread_tree, $msg_depth, $has_children) = $this->conn->thread(
- $mailbox, $this->threading, $criteria, $charset);
+ $a_messages = $this->conn->thread($mailbox, $this->threading, $criteria, $charset);
- $a_messages = array(
- 'tree' => $thread_tree,
- 'depth' => $msg_depth,
- 'children' => $has_children
- );
+ // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8,
+ // but I've seen that Courier doesn't support UTF-8)
+ if ($a_messages === false && $charset && $charset != 'US-ASCII')
+ $a_messages = $this->conn->thread($mailbox, $this->threading,
+ $this->convert_criteria($criteria, $charset), 'US-ASCII');
+
+ if ($a_messages !== false) {
+ list ($thread_tree, $msg_depth, $has_children) = $a_messages;
+ $a_messages = array(
+ 'tree' => $thread_tree,
+ 'depth' => $msg_depth,
+ 'children' => $has_children
+ );
+ }
}
else if ($sort_field && $this->get_capability('SORT')) {
$charset = $charset ? $charset : $this->default_charset;
$a_messages = $this->conn->sort($mailbox, $sort_field, $criteria, false, $charset);
- if (!$a_messages)
- return array();
+ // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8,
+ // but I've seen that Courier doesn't support UTF-8)
+ if ($a_messages === false && $charset && $charset != 'US-ASCII')
+ $a_messages = $this->conn->sort($mailbox, $sort_field,
+ $this->convert_criteria($criteria, $charset), false, 'US-ASCII');
}
else {
if ($orig_criteria == 'ALL') {
@@ -1440,14 +1434,16 @@
}
else {
$a_messages = $this->conn->search($mailbox,
- ($charset ? "CHARSET $charset " : '') . $criteria);
+ ($charset ? "CHARSET $charset " : '') . $criteria);
- if (!$a_messages)
- return array();
+ // Error, try with US-ASCII (some servers may support only US-ASCII)
+ if ($a_messages === false && $charset && $charset != 'US-ASCII')
+ $a_messages = $this->conn->search($mailbox,
+ 'CHARSET US-ASCII ' . $this->convert_criteria($criteria, $charset));
- // I didn't found that SEARCH always returns sorted IDs
- if (!$this->sort_field)
- sort($a_messages);
+ // I didn't found that SEARCH should return sorted IDs
+ if (is_array($a_messages) && !$this->sort_field)
+ sort($a_messages);
}
}
@@ -1478,6 +1474,39 @@
$mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox;
return $this->conn->search($mailbox, $str, $ret_uid);
+ }
+
+
+ /**
+ * Converts charset of search criteria string
+ *
+ * @param string Search string
+ * @param string Original charset
+ * @param string Destination charset (default US-ASCII)
+ * @return string Search string
+ * @access private
+ */
+ private function convert_criteria($str, $charset, $dest_charset='US-ASCII')
+ {
+ // convert strings to US_ASCII
+ if (preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) {
+ $last = 0; $res = '';
+ foreach ($matches[1] as $m) {
+ $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
+ $string = substr($str, $string_offset - 1, $m[0]);
+ $string = rcube_charset_convert($string, $charset, $dest_charset);
+ if (!$string)
+ continue;
+ $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string);
+ $last = $m[0] + $string_offset - 1;
+ }
+ if ($last < strlen($str))
+ $res .= substr($str, $last, strlen($str)-$last);
+ }
+ else // strings for conversion not found
+ $res = $str;
+
+ return $res;
}
@@ -1675,14 +1704,22 @@
else
$this->struct_charset = $this->_structure_charset($structure);
+ $headers->ctype = strtolower($headers->ctype);
+
// Here we can recognize malformed BODYSTRUCTURE and
// 1. [@TODO] parse the message in other way to create our own message structure
// 2. or just show the raw message body.
// Example of structure for malformed MIME message:
- // ("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 2154 70 NIL NIL NIL)
- if ($headers->ctype && $headers->ctype != 'text/plain'
- && $structure[0] == 'text' && $structure[1] == 'plain') {
- return false;
+ // ("text" "plain" NIL NIL NIL "7bit" 2154 70 NIL NIL NIL)
+ if ($headers->ctype && !is_array($structure[0]) && $headers->ctype != 'text/plain'
+ && strtolower($structure[0].'/'.$structure[1]) == 'text/plain') {
+ // we can handle single-part messages, by simple fix in structure (#1486898)
+ if (preg_match('/^(text|application)\/(.*)/', $headers->ctype, $m)) {
+ $structure[0] = $m[1];
+ $structure[1] = $m[2];
+ }
+ else
+ return false;
}
$struct = &$this->_structure_part($structure);
@@ -1709,7 +1746,7 @@
*
* @access private
*/
- function &_structure_part($part, $count=0, $parent='', $mime_headers=null, $raw_headers=null)
+ function &_structure_part($part, $count=0, $parent='', $mime_headers=null)
{
$struct = new rcube_message_part;
$struct->mime_id = empty($parent) ? (string)$count : "$parent.$count";
@@ -1717,6 +1754,18 @@
// multipart
if (is_array($part[0])) {
$struct->ctype_primary = 'multipart';
+
+ /* RFC3501: BODYSTRUCTURE fields of multipart part
+ part1 array
+ part2 array
+ part3 array
+ ....
+ 1. subtype
+ 2. parameters (optional)
+ 3. description (optional)
+ 4. language (optional)
+ 5. location (optional)
+ */
// find first non-array entry
for ($i=1; $i<count($part); $i++) {
@@ -1729,19 +1778,18 @@
$struct->mimetype = 'multipart/'.$struct->ctype_secondary;
// build parts list for headers pre-fetching
- for ($i=0, $count=0; $i<count($part); $i++) {
- if (is_array($part[$i]) && count($part[$i]) > 3) {
- // fetch message headers if message/rfc822
- // or named part (could contain Content-Location header)
- if (!is_array($part[$i][0])) {
- $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
- if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
- $raw_part_headers[] = $tmp_part_id;
- $mime_part_headers[] = $tmp_part_id;
- }
- else if (in_array('name', (array)$part[$i][2]) && (empty($part[$i][3]) || $part[$i][3]=='NIL')) {
- $mime_part_headers[] = $tmp_part_id;
- }
+ for ($i=0; $i<count($part); $i++) {
+ if (!is_array($part[$i]))
+ break;
+ // fetch message headers if message/rfc822
+ // or named part (could contain Content-Location header)
+ if (!is_array($part[$i][0])) {
+ $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
+ if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
+ $mime_part_headers[] = $tmp_part_id;
+ }
+ else if (in_array('name', (array)$part[$i][2]) && (empty($part[$i][3]) || $part[$i][3]=='NIL')) {
+ $mime_part_headers[] = $tmp_part_id;
}
}
}
@@ -1753,22 +1801,39 @@
$mime_part_headers = $this->conn->fetchMIMEHeaders($this->mailbox,
$this->_msg_id, $mime_part_headers);
}
- // we'll need a real content-type of message/rfc822 part
- if ($raw_part_headers) {
- $raw_part_headers = $this->conn->fetchMIMEHeaders($this->mailbox,
- $this->_msg_id, $raw_part_headers, false);
- }
+
$struct->parts = array();
for ($i=0, $count=0; $i<count($part); $i++) {
- if (is_array($part[$i]) && count($part[$i]) > 3) {
- $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
- $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id,
- $mime_part_headers[$tmp_part_id], $raw_part_headers[$tmp_part_id]);
- }
+ if (!is_array($part[$i]))
+ break;
+ $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
+ $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id,
+ $mime_part_headers[$tmp_part_id]);
}
return $struct;
}
+
+ /* RFC3501: BODYSTRUCTURE fields of non-multipart part
+ 0. type
+ 1. subtype
+ 2. parameters
+ 3. id
+ 4. description
+ 5. encoding
+ 6. size
+ -- text
+ 7. lines
+ -- message/rfc822
+ 7. envelope structure
+ 8. body structure
+ 9. lines
+ --
+ x. md5 (optional)
+ x. disposition (optional)
+ x. language (optional)
+ x. location (optional)
+ */
// regular part
$struct->ctype_primary = strtolower($part[0]);
@@ -1796,9 +1861,11 @@
$struct->size = intval($part[6]);
// read part disposition
- $di = count($part) - 2;
- if ((is_array($part[$di]) && count($part[$di]) == 2 && is_array($part[$di][1])) ||
- (is_array($part[--$di]) && count($part[$di]) == 2)) {
+ $di = 8;
+ if ($struct->ctype_primary == 'text') $di += 1;
+ else if ($struct->mimetype == 'message/rfc822') $di += 3;
+
+ if (is_array($part[$di]) && count($part[$di]) == 2) {
$struct->disposition = strtolower($part[$di][0]);
if (is_array($part[$di][1]))
@@ -1806,12 +1873,14 @@
$struct->d_parameters[strtolower($part[$di][1][$n])] = $part[$di][1][$n+1];
}
- // get child parts
+ // get message/rfc822's child-parts
if (is_array($part[8]) && $di != 8) {
$struct->parts = array();
- for ($i=0, $count=0; $i<count($part[8]); $i++)
- if (is_array($part[8][$i]) && count($part[8][$i]) > 5)
- $struct->parts[] = $this->_structure_part($part[8][$i], ++$count, $struct->mime_id);
+ for ($i=0, $count=0; $i<count($part[8]); $i++) {
+ if (!is_array($part[8][$i]))
+ break;
+ $struct->parts[] = $this->_structure_part($part[8][$i], ++$count, $struct->mime_id);
+ }
}
// get part ID
@@ -1831,24 +1900,24 @@
}
$struct->headers = $this->_parse_headers($mime_headers) + $struct->headers;
- // get real headers for message of type 'message/rfc822'
+ // get real content-type of message/rfc822
if ($struct->mimetype == 'message/rfc822') {
- if (empty($raw_headers)) {
- $raw_headers = $this->conn->fetchMIMEHeaders(
- $this->mailbox, $this->_msg_id, (array)$struct->mime_id, false);
- }
- $struct->real_headers = $this->_parse_headers($raw_headers);
-
- // get real content-type of message/rfc822
- if (preg_match('/^([a-z0-9_\/-]+)/i', $struct->real_headers['content-type'], $matches)) {
- $struct->real_mimetype = strtolower($matches[1]);
+ // single-part
+ if (!is_array($part[8][0]))
+ $struct->real_mimetype = strtolower($part[8][0] . '/' . $part[8][1]);
+ // multi-part
+ else {
+ for ($n=0; $n<count($part[8]); $n++)
+ if (!is_array($part[8][$n]))
+ break;
+ $struct->real_mimetype = 'multipart/' . strtolower($part[8][$n]);
}
}
- }
- if ($struct->ctype_primary=='message') {
- if (is_array($part[8]) && $di != 8 && empty($struct->parts))
- $struct->parts[] = $this->_structure_part($part[8], ++$count, $struct->mime_id);
+ if ($struct->ctype_primary == 'message' && empty($struct->parts)) {
+ if (is_array($part[8]) && $di != 8)
+ $struct->parts[] = $this->_structure_part($part[8], ++$count, $struct->mime_id);
+ }
}
// normalize filename property
@@ -2034,7 +2103,7 @@
return true;
// convert charset (if text or message part)
- if ($o_part->ctype_primary=='text' || $o_part->ctype_primary=='message') {
+ 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;
@@ -2170,11 +2239,8 @@
// make sure mailbox exists
if ($this->mailbox_exists($mbox_name, true)) {
- if ($is_file) {
- $separator = rcmail::get_instance()->config->header_delimiter();
- $saved = $this->conn->appendFromFile($mailbox, $message,
- $headers, $separator.$separator);
- }
+ if ($is_file)
+ $saved = $this->conn->appendFromFile($mailbox, $message, $headers);
else
$saved = $this->conn->append($mailbox, $message);
}
@@ -2560,7 +2626,7 @@
$a_defaults = $a_out = array();
// Give plugins a chance to provide a list of mailboxes
- $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes',
+ $data = rcmail::get_instance()->plugins->exec_hook('mailboxes_list',
array('root' => $root, 'filter' => $filter, 'mode' => 'LSUB'));
if (isset($data['folders'])) {
@@ -2591,7 +2657,7 @@
function list_unsubscribed($root='', $filter='*')
{
// Give plugins a chance to provide a list of mailboxes
- $data = rcmail::get_instance()->plugins->exec_hook('list_mailboxes',
+ $data = rcmail::get_instance()->plugins->exec_hook('mailboxes_list',
array('root' => $root, 'filter' => $filter, 'mode' => 'LIST'));
if (isset($data['folders'])) {
@@ -2601,7 +2667,7 @@
// retrieve list of folders from IMAP server
$a_mboxes = $this->conn->listMailboxes($this->mod_mailbox($root), $filter);
}
-
+
$a_folders = array();
if (!is_array($a_mboxes))
$a_mboxes = array();
@@ -3360,7 +3426,7 @@
$name = trim($val['name']);
if (preg_match('/^[\'"]/', $name) && preg_match('/[\'"]$/', $name))
- $name = preg_replace(array('/^[\'"]/', '/[\'"]$/'), '', $name);
+ $name = trim($name, '\'"');
if ($name && $address && $name != $address)
$string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address);
@@ -3383,43 +3449,6 @@
/**
- * Decode a Microsoft Outlook TNEF part (winmail.dat)
- *
- * @param object rcube_message_part Message part to decode
- * @param string UID of the message
- * @return array List of rcube_message_parts extracted from windmail.dat
- */
- function tnef_decode(&$part, $uid)
- {
- 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();
- $tnef_arr = tnef_decode($part->body);
-
- foreach ($tnef_arr as $winatt) {
- $tpart = new rcube_message_part;
- $tpart->filename = trim($winatt['name']);
- $tpart->encoding = 'stream';
- $tpart->ctype_primary = trim(strtolower($winatt['type0']));
- $tpart->ctype_secondary = trim(strtolower($winatt['type1']));
- $tpart->mimetype = $tpart->ctype_primary . '/' . $tpart->ctype_secondary;
- $tpart->mime_id = "winmail." . $part->mime_id . ".$pid";
- $tpart->size = $winatt['size'];
- $tpart->body = $winatt['stream'];
-
- $tnef_parts[] = $tpart;
- $pid++;
- }
-
- return $tnef_parts;
- }
-
-
- /**
* Decode a message header value
*
* @param string Header value
@@ -3429,7 +3458,7 @@
function decode_header($input, $remove_quotes=false)
{
$str = rcube_imap::decode_mime_string((string)$input, $this->default_charset);
- if ($str{0}=='"' && $remove_quotes)
+ if ($str[0] == '"' && $remove_quotes)
$str = str_replace('"', '', $str);
return $str;
--
Gitblit v1.9.1