Changeset 5557 in subversion for trunk/roundcubemail/program/include/rcube_imap_generic.php
- Timestamp:
- Dec 7, 2011 3:44:48 AM (18 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/roundcubemail/program/include/rcube_imap_generic.php
r5400 r5557 26 26 27 27 */ 28 29 28 30 29 /** … … 1219 1218 // Invoke SEARCH as a fallback 1220 1219 $index = $this->search($mailbox, 'ALL UNSEEN', false, array('COUNT')); 1221 if ( is_array($index)) {1222 return (int) $index['COUNT'];1220 if (!$index->isError()) { 1221 return $index->count(); 1223 1222 } 1224 1223 … … 1294 1293 } 1295 1294 1296 function sort($mailbox, $field, $add='', $is_uid=FALSE, $encoding = 'US-ASCII') 1297 { 1295 /** 1296 * Executes SORT command 1297 * 1298 * @param string $mailbox Mailbox name 1299 * @param string $field Field to sort by (ARRIVAL, CC, DATE, FROM, SIZE, SUBJECT, TO) 1300 * @param string $add Searching criteria 1301 * @param bool $return_uid Enables UID SORT usage 1302 * @param string $encoding Character set 1303 * 1304 * @return rcube_result_index Response data 1305 */ 1306 function sort($mailbox, $field, $add='', $return_uid=false, $encoding = 'US-ASCII') 1307 { 1308 require_once dirname(__FILE__) . '/rcube_result_index.php'; 1309 1298 1310 $field = strtoupper($field); 1299 1311 if ($field == 'INTERNALDATE') { … … 1305 1317 1306 1318 if (!$fields[$field]) { 1307 return false;1319 return new rcube_result_index($mailbox); 1308 1320 } 1309 1321 1310 1322 if (!$this->select($mailbox)) { 1311 return false;1323 return new rcube_result_index($mailbox); 1312 1324 } 1313 1325 … … 1316 1328 $add = $this->compressMessageSet($add); 1317 1329 1318 list($code, $response) = $this->execute($ is_uid ? 'UID SORT' : 'SORT',1330 list($code, $response) = $this->execute($return_uid ? 'UID SORT' : 'SORT', 1319 1331 array("($field)", $encoding, 'ALL' . (!empty($add) ? ' '.$add : ''))); 1320 1332 1321 if ($code == self::ERROR_OK) { 1322 // remove prefix and unilateral untagged server responses 1323 $response = substr($response, stripos($response, '* SORT') + 7); 1324 if ($pos = strpos($response, '*')) { 1325 $response = substr($response, 0, $pos); 1326 } 1327 return preg_split('/[\s\r\n]+/', $response, -1, PREG_SPLIT_NO_EMPTY); 1328 } 1329 1330 return false; 1331 } 1332 1333 function fetchHeaderIndex($mailbox, $message_set, $index_field='', $skip_deleted=true, $uidfetch=false) 1333 if ($code != self::ERROR_OK) { 1334 $response = null; 1335 } 1336 1337 return new rcube_result_index($mailbox, $response); 1338 } 1339 1340 /** 1341 * Simulates SORT command by using FETCH and sorting. 1342 * 1343 * @param string $mailbox Mailbox name 1344 * @param string|array $message_set Searching criteria (list of messages to return) 1345 * @param string $index_field Field to sort by (ARRIVAL, CC, DATE, FROM, SIZE, SUBJECT, TO) 1346 * @param bool $skip_deleted Makes that DELETED messages will be skipped 1347 * @param bool $uidfetch Enables UID FETCH usage 1348 * @param bool $return_uid Enables returning UIDs instead of IDs 1349 * 1350 * @return rcube_result_index Response data 1351 */ 1352 function index($mailbox, $message_set, $index_field='', $skip_deleted=true, 1353 $uidfetch=false, $return_uid=false) 1354 { 1355 require_once dirname(__FILE__) . '/rcube_result_index.php'; 1356 1357 $msg_index = $this->fetchHeaderIndex($mailbox, $message_set, 1358 $index_field, $skip_deleted, $uidfetch, $return_uid); 1359 1360 if (!empty($msg_index)) { 1361 asort($msg_index); // ASC 1362 $msg_index = array_keys($msg_index); 1363 $msg_index = '* SEARCH ' . implode(' ', $msg_index); 1364 } 1365 else { 1366 $msg_index = is_array($msg_index) ? '* SEARCH' : null; 1367 } 1368 1369 return new rcube_result_index($mailbox, $msg_index); 1370 } 1371 1372 function fetchHeaderIndex($mailbox, $message_set, $index_field='', $skip_deleted=true, 1373 $uidfetch=false, $return_uid=false) 1334 1374 { 1335 1375 if (is_array($message_set)) { … … 1371 1411 1372 1412 // build FETCH command string 1373 $key = $this->nextTag(); 1374 $cmd = $uidfetch ? 'UID FETCH' : 'FETCH'; 1375 $deleted = $skip_deleted ? ' FLAGS' : ''; 1376 1377 if ($mode == 1 && $index_field == 'DATE') 1378 $request = " $cmd $message_set (INTERNALDATE BODY.PEEK[HEADER.FIELDS (DATE)]$deleted)"; 1379 else if ($mode == 1) 1380 $request = " $cmd $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)]$deleted)"; 1413 $key = $this->nextTag(); 1414 $cmd = $uidfetch ? 'UID FETCH' : 'FETCH'; 1415 $fields = array(); 1416 1417 if ($return_uid) 1418 $fields[] = 'UID'; 1419 if ($skip_deleted) 1420 $fields[] = 'FLAGS'; 1421 1422 if ($mode == 1) { 1423 if ($index_field == 'DATE') 1424 $fields[] = 'INTERNALDATE'; 1425 $fields[] = "BODY.PEEK[HEADER.FIELDS ($index_field)]"; 1426 } 1381 1427 else if ($mode == 2) { 1382 1428 if ($index_field == 'SIZE') 1383 $request = " $cmd $message_set (RFC822.SIZE$deleted)"; 1384 else 1385 $request = " $cmd $message_set ($index_field$deleted)"; 1386 } else if ($mode == 3) 1387 $request = " $cmd $message_set (FLAGS)"; 1388 else // 4 1389 $request = " $cmd $message_set (INTERNALDATE$deleted)"; 1390 1391 $request = $key . $request; 1429 $fields[] = 'RFC822.SIZE'; 1430 else if (!$return_uid || $index_field != 'UID') 1431 $fields[] = $index_field; 1432 } 1433 else if ($mode == 3 && !$skip_deleted) 1434 $fields[] = 'FLAGS'; 1435 else if ($mode == 4) 1436 $fields[] = 'INTERNALDATE'; 1437 1438 $request = "$key $cmd $message_set (" . implode(' ', $fields) . ")"; 1392 1439 1393 1440 if (!$this->putLine($request)) { … … 1406 1453 $flags = NULL; 1407 1454 1455 if ($return_uid) { 1456 if (preg_match('/UID ([0-9]+)/', $line, $matches)) 1457 $id = (int) $matches[1]; 1458 else 1459 continue; 1460 } 1408 1461 if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { 1409 1462 $flags = explode(' ', strtoupper($matches[1])); … … 1535 1588 { 1536 1589 if ($uid > 0) { 1537 $id_a = $this->search($mailbox, "UID $uid"); 1538 if (is_array($id_a) && count($id_a) == 1) { 1539 return (int) $id_a[0]; 1590 $index = $this->search($mailbox, "UID $uid"); 1591 1592 if ($index->count() == 1) { 1593 $arr = $index->get(); 1594 return (int) $arr[0]; 1540 1595 } 1541 1596 } … … 1561 1616 } 1562 1617 1563 list($code, $response) = $this->execute('FETCH', array($id, '(UID)')); 1564 1565 if ($code == self::ERROR_OK && preg_match("/^\* $id FETCH \(UID (.*)\)/i", $response, $m)) { 1566 return (int) $m[1]; 1618 $index = $this->search($mailbox, $id, true); 1619 1620 if ($index->count() == 1) { 1621 $arr = $index->get(); 1622 return (int) $arr[0]; 1567 1623 } 1568 1624 1569 1625 return null; 1570 }1571 1572 function fetchUIDs($mailbox, $message_set=null)1573 {1574 if (empty($message_set))1575 $message_set = '1:*';1576 1577 return $this->fetchHeaderIndex($mailbox, $message_set, 'UID', false);1578 1626 } 1579 1627 … … 1971 2019 } 1972 2020 1973 // Don't be tempted to change $str to pass by reference to speed this up - it will slow it down by about 1974 // 7 times instead :-) See comments on http://uk2.php.net/references and this article: 1975 // http://derickrethans.nl/files/phparch-php-variables-article.pdf 1976 private function parseThread($str, $begin, $end, $root, $parent, $depth, &$depthmap, &$haschildren) 1977 { 1978 $node = array(); 1979 if ($str[$begin] != '(') { 1980 $stop = $begin + strspn($str, '1234567890', $begin, $end - $begin); 1981 $msg = substr($str, $begin, $stop - $begin); 1982 if ($msg == 0) 1983 return $node; 1984 if (is_null($root)) 1985 $root = $msg; 1986 $depthmap[$msg] = $depth; 1987 $haschildren[$msg] = false; 1988 if (!is_null($parent)) 1989 $haschildren[$parent] = true; 1990 if ($stop + 1 < $end) 1991 $node[$msg] = $this->parseThread($str, $stop + 1, $end, $root, $msg, $depth + 1, $depthmap, $haschildren); 1992 else 1993 $node[$msg] = array(); 1994 } else { 1995 $off = $begin; 1996 while ($off < $end) { 1997 $start = $off; 1998 $off++; 1999 $n = 1; 2000 while ($n > 0) { 2001 $p = strpos($str, ')', $off); 2002 if ($p === false) { 2003 error_log("Mismatched brackets parsing IMAP THREAD response:"); 2004 error_log(substr($str, ($begin < 10) ? 0 : ($begin - 10), $end - $begin + 20)); 2005 error_log(str_repeat(' ', $off - (($begin < 10) ? 0 : ($begin - 10)))); 2006 return $node; 2007 } 2008 $p1 = strpos($str, '(', $off); 2009 if ($p1 !== false && $p1 < $p) { 2010 $off = $p1 + 1; 2011 $n++; 2012 } else { 2013 $off = $p + 1; 2014 $n--; 2015 } 2016 } 2017 $node += $this->parseThread($str, $start + 1, $off - 1, $root, $parent, $depth, $depthmap, $haschildren); 2018 } 2019 } 2020 2021 return $node; 2022 } 2023 2024 function thread($mailbox, $algorithm='REFERENCES', $criteria='', $encoding='US-ASCII') 2025 { 2021 /** 2022 * Executes THREAD command 2023 * 2024 * @param string $mailbox Mailbox name 2025 * @param string $algorithm Threading algorithm (ORDEREDSUBJECT, REFERENCES, REFS) 2026 * @param string $criteria Searching criteria 2027 * @param bool $return_uid Enables UIDs in result instead of sequence numbers 2028 * @param string $encoding Character set 2029 * 2030 * @return rcube_result_thread Thread data 2031 */ 2032 function thread($mailbox, $algorithm='REFERENCES', $criteria='', $return_uid=false, $encoding='US-ASCII') 2033 { 2034 require_once dirname(__FILE__) . '/rcube_result_thread.php'; 2035 2026 2036 $old_sel = $this->selected; 2027 2037 2028 2038 if (!$this->select($mailbox)) { 2029 return false;2039 return new rcube_result_thread($mailbox); 2030 2040 } 2031 2041 2032 2042 // return empty result when folder is empty and we're just after SELECT 2033 2043 if ($old_sel != $mailbox && !$this->data['EXISTS']) { 2034 return array(array(), array(), array());2044 return new rcube_result_thread($mailbox); 2035 2045 } 2036 2046 … … 2040 2050 $data = ''; 2041 2051 2042 list($code, $response) = $this->execute('THREAD', array( 2043 $algorithm, $encoding, $criteria)); 2044 2045 if ($code == self::ERROR_OK) { 2046 // remove prefix... 2047 $response = substr($response, stripos($response, '* THREAD') + 9); 2048 // ...unilateral untagged server responses 2049 if ($pos = strpos($response, '*')) { 2050 $response = substr($response, 0, $pos); 2051 } 2052 2053 $response = str_replace("\r\n", '', $response); 2054 $depthmap = array(); 2055 $haschildren = array(); 2056 2057 $tree = $this->parseThread($response, 0, strlen($response), 2058 null, null, 0, $depthmap, $haschildren); 2059 2060 return array($tree, $depthmap, $haschildren); 2061 } 2062 2063 return false; 2052 list($code, $response) = $this->execute($return_uid ? 'UID THREAD' : 'THREAD', 2053 array($algorithm, $encoding, $criteria)); 2054 2055 if ($code != self::ERROR_OK) { 2056 $response = null; 2057 } 2058 2059 return new rcube_result_thread($mailbox, $response); 2064 2060 } 2065 2061 … … 2072 2068 * @param array $items Return items (MIN, MAX, COUNT, ALL) 2073 2069 * 2074 * @return array Message identifiers or item-value hash2070 * @return rcube_result_index Result data 2075 2071 */ 2076 2072 function search($mailbox, $criteria, $return_uid=false, $items=array()) 2077 2073 { 2074 require_once dirname(__FILE__) . '/rcube_result_index.php'; 2075 2078 2076 $old_sel = $this->selected; 2079 2077 2080 2078 if (!$this->select($mailbox)) { 2081 return false;2079 return new rcube_result_index($mailbox); 2082 2080 } 2083 2081 2084 2082 // return empty result when folder is empty and we're just after SELECT 2085 2083 if ($old_sel != $mailbox && !$this->data['EXISTS']) { 2086 if (!empty($items)) 2087 return array_combine($items, array_fill(0, count($items), 0)); 2088 else 2089 return array(); 2084 return new rcube_result_index($mailbox, '* SEARCH'); 2085 } 2086 2087 // If ESEARCH is supported always use ALL 2088 // but not when items are specified or using simple id2uid search 2089 if (empty($items) && ((int) $criteria != $criteria)) { 2090 $items = array('ALL'); 2090 2091 } 2091 2092 … … 2098 2099 $params .= 'RETURN (' . implode(' ', $items) . ')'; 2099 2100 } 2101 2100 2102 if (!empty($criteria)) { 2101 2103 $modseq = stripos($criteria, 'MODSEQ') !== false; … … 2109 2111 array($params)); 2110 2112 2111 if ($code == self::ERROR_OK) { 2112 // remove prefix... 2113 $response = substr($response, stripos($response, 2114 $esearch ? '* ESEARCH' : '* SEARCH') + ($esearch ? 10 : 9)); 2115 // ...and unilateral untagged server responses 2116 if ($pos = strpos($response, '*')) { 2117 $response = rtrim(substr($response, 0, $pos)); 2118 } 2119 2120 // remove MODSEQ response 2121 if ($modseq) { 2122 if (preg_match('/\(MODSEQ ([0-9]+)\)$/', $response, $m)) { 2123 $response = substr($response, 0, -strlen($m[0])); 2124 } 2125 } 2126 2127 if ($esearch) { 2128 // Skip prefix: ... (TAG "A285") UID ... 2129 $this->tokenizeResponse($response, $return_uid ? 2 : 1); 2130 2131 $result = array(); 2132 for ($i=0; $i<count($items); $i++) { 2133 // If the SEARCH returns no matches, the server MUST NOT 2134 // include the item result option in the ESEARCH response 2135 if ($ret = $this->tokenizeResponse($response, 2)) { 2136 list ($name, $value) = $ret; 2137 $result[$name] = $value; 2138 } 2139 } 2140 2141 return $result; 2142 } 2143 else { 2144 $response = preg_split('/[\s\r\n]+/', $response, -1, PREG_SPLIT_NO_EMPTY); 2145 2146 if (!empty($items)) { 2147 $result = array(); 2148 if (in_array('COUNT', $items)) { 2149 $result['COUNT'] = count($response); 2150 } 2151 if (in_array('MIN', $items)) { 2152 $result['MIN'] = !empty($response) ? min($response) : 0; 2153 } 2154 if (in_array('MAX', $items)) { 2155 $result['MAX'] = !empty($response) ? max($response) : 0; 2156 } 2157 if (in_array('ALL', $items)) { 2158 $result['ALL'] = $this->compressMessageSet($response, true); 2159 } 2160 2161 return $result; 2162 } 2163 else { 2164 return $response; 2165 } 2166 } 2167 } 2168 2169 return false; 2113 if ($code != self::ERROR_OK) { 2114 $response = null; 2115 } 2116 2117 return new rcube_result_index($mailbox, $response); 2170 2118 } 2171 2119
Note: See TracChangeset
for help on using the changeset viewer.
