Changeset 1d51658 in github
- Timestamp:
- May 18, 2010 7:58:12 AM (3 years ago)
- Branches:
- master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
- Children:
- 6a86d272
- Parents:
- 30aa4cc
- Files:
-
- 2 edited
-
CHANGELOG (modified) (1 diff)
-
program/include/rcube_imap_generic.php (modified) (79 diffs)
Legend:
- Unmodified
- Added
- Removed
-
CHANGELOG
r30aa4cc r1d51658 2 2 =========================== 3 3 4 - Parse untagged CAPABILITY response for LOGIN command (#1486742) 4 5 - Renamed all php-cli scripts to use .sh extension 5 6 - Some files from /bin + spellchecking actions moved to the new 'utils' task -
program/include/rcube_imap_generic.php
r3978cbf4 r1d51658 31 31 * 32 32 * @package Mail 33 * @author Aleksander Machniak <alec@alec.pl> 33 * @author Aleksander Machniak <alec@alec.pl> 34 34 */ 35 35 class rcube_mail_header … … 81 81 * 82 82 * @package Mail 83 * @author Aleksander Machniak <alec@alec.pl> 83 * @author Aleksander Machniak <alec@alec.pl> 84 84 */ 85 85 class rcube_imap_generic … … 119 119 { 120 120 } 121 121 122 122 private function putLine($string, $endln=true) 123 123 { … … 128 128 write_log('imap', 'C: '. rtrim($string)); 129 129 } 130 130 131 131 return fputs($this->fp, $string . ($endln ? "\r\n" : '')); 132 132 } … … 174 174 return NULL; 175 175 } 176 176 177 177 if (!$size) { 178 178 $size = 1024; 179 179 } 180 180 181 181 do { 182 182 if (feof($this->fp)) { 183 183 return $line ? $line : NULL; 184 184 } 185 185 186 186 $buffer = fgets($this->fp, $size); 187 187 … … 205 205 if (preg_match('/\{[0-9]+\}$/', $line)) { 206 206 $out = ''; 207 207 208 208 preg_match_all('/(.*)\{([0-9]+)\}$/', $line, $a); 209 209 $bytes = $a[2][0]; 210 210 while (strlen($out) < $bytes) { 211 $line = $this->readBytes($bytes); 211 $line = $this->readBytes($bytes); 212 212 if ($line === NULL) 213 213 break; … … 217 217 $line = $a[1][0] . '"' . ($escape ? $this->Escape($out) : $out) . '"'; 218 218 } 219 219 220 220 return $line; 221 221 } … … 238 238 $len = $data_len; 239 239 } 240 240 241 241 return $data; 242 242 } 243 243 244 244 // don't use it in loops, until you exactly know what you're doing 245 private function readReply( )245 private function readReply($untagged=null) 246 246 { 247 247 do { 248 248 $line = trim($this->readLine(1024)); 249 // store untagged response lines 250 if ($line[0] == '*') 251 $untagged[] = $line; 249 252 } while ($line[0] == '*'); 253 254 if ($untagged) 255 $untagged = join("\n", $untagged); 250 256 251 257 return $line; … … 332 338 } 333 339 334 // get capabilities (only once) because initial 340 // get capabilities (only once) because initial 335 341 // optional CAPABILITY response may differ 336 342 $this->capability = array(); … … 349 355 } 350 356 } while ($a[0] != 'cp01'); 351 357 352 358 $this->capability_readed = true; 353 359 … … 369 375 $ipad = ''; 370 376 $opad = ''; 371 377 372 378 // initialize ipad, opad 373 379 for ($i=0; $i<64; $i++) { … … 381 387 $pass .= chr(0); 382 388 } 383 389 384 390 // generate hash 385 391 $hash = md5($this->_xor($pass,$opad) . pack("H*", md5($this->_xor($pass, $ipad) . base64_decode($encChallenge)))); 386 392 387 393 // generate reply 388 394 $reply = base64_encode($user . ' ' . $hash); 389 395 390 396 // send result, get reply 391 397 $this->putLine($reply); 392 398 $line = $this->readLine(1024); 393 399 394 400 // process result 395 401 $result = $this->parseResult($line); … … 409 415 $this->putLine('a001 LOGIN "'.$this->escape($user).'" "'.$this->escape($password).'"'); 410 416 411 $line = $this->readReply(); 417 $line = $this->readReply($untagged); 418 419 // re-set capabilities list if untagged CAPABILITY response provided 420 if (preg_match('/\* CAPABILITY (.+)/i', $untagged, $matches)) { 421 $this->capability = explode(' ', strtoupper($matches[1])); 422 } 412 423 413 424 // process result … … 421 432 @fclose($this->fp); 422 433 $this->fp = false; 423 434 424 435 $this->error = "Authentication for $user failed (LOGIN): $line"; 425 436 $this->errornum = $result; … … 434 445 return true; 435 446 } 436 447 437 448 if (!$this->getCapability('NAMESPACE')) { 438 449 return false; 439 450 } 440 451 441 452 if (!$this->putLine("ns1 NAMESPACE")) { 442 453 return false; … … 464 475 return false; 465 476 } 466 477 467 478 $this->rootdir = $first_userspace[0]; 468 479 $this->delimiter = $first_userspace[1]; 469 480 $this->prefs['rootdir'] = substr($this->rootdir, 0, -1); 470 481 $this->prefs['delimiter'] = $this->delimiter; 471 482 472 483 return true; 473 484 } … … 479 490 * INBOX/foo -> / 480 491 * INBOX\foo -> \ 481 * 482 * @return mixed A delimiter (string), or false. 492 * 493 * @return mixed A delimiter (string), or false. 483 494 * @see connect() 484 495 */ … … 498 509 return false; 499 510 } 500 511 501 512 do { 502 513 $line = $this->readLine(500); … … 532 543 return false; 533 544 } 534 545 535 546 // extract user space data (opposed to global/shared space) 536 547 $user_space_data = $data[0]; … … 546 557 547 558 // extract delimiter 548 $delimiter = $first_userspace[1]; 559 $delimiter = $first_userspace[1]; 549 560 550 561 return $delimiter; … … 567 578 568 579 $result = false; 569 580 570 581 // initialize connection 571 582 $this->error = ''; … … 649 660 return false; 650 661 } 651 662 652 663 // Now we're authenticated, capabilities need to be reread 653 664 $this->clearCapability(); … … 676 687 // got a challenge string, try CRAM-MD5 677 688 $result = $this->authenticate($user, $password, substr($line,2)); 678 689 679 690 // stop if server sent BYE response 680 691 if ($result == -3) { … … 682 693 } 683 694 } 684 695 685 696 if (!is_resource($result) && $orig_method == 'CHECK') { 686 697 $auth_method = 'PLAIN'; 687 698 } 688 699 } 689 700 690 701 if ($auth_method == 'PLAIN') { 691 702 // do plain text auth … … 728 739 return true; 729 740 } 730 741 731 742 if ($this->putLine("sel1 SELECT \"".$this->escape($mailbox).'"')) { 732 743 do { … … 764 775 $mailbox = 'INBOX'; 765 776 } 766 777 767 778 $this->select($mailbox); 768 779 if ($this->selected == $mailbox) { … … 778 789 $this->selected = ''; 779 790 } 780 791 781 792 $this->select($mailbox); 782 793 if ($this->selected == $mailbox) { … … 793 804 $field = 'ARRIVAL'; 794 805 } 795 806 796 807 $fields = array('ARRIVAL' => 1,'CC' => 1,'DATE' => 1, 797 808 'FROM' => 1, 'SIZE' => 1, 'SUBJECT' => 1, 'TO' => 1); … … 805 816 return false; 806 817 } 807 818 808 819 $is_uid = $is_uid ? 'UID ' : ''; 809 820 810 821 // message IDs 811 822 if (is_array($add)) … … 829 840 } 830 841 } while (!$this->startsWith($line, 's ', true, true)); 831 842 832 843 $result_code = $this->parseResult($line); 833 844 834 845 if ($result_code != 0) { 835 846 $this->error = "Sort: $line"; 836 847 return false; 837 848 } 838 849 839 850 return preg_split('/\s+/', $data, -1, PREG_SPLIT_NO_EMPTY); 840 851 } … … 852 863 } 853 864 } 854 865 855 866 $index_field = empty($index_field) ? 'DATE' : strtoupper($index_field); 856 867 857 868 $fields_a['DATE'] = 1; 858 869 $fields_a['INTERNALDATE'] = 4; … … 878 889 return false; 879 890 } 880 891 881 892 // build FETCH command string 882 893 $key = 'fhi0'; … … 913 924 $id = $m[1]; 914 925 $flags = NULL; 915 926 916 927 if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { 917 928 $flags = explode(' ', strtoupper($matches[1])); … … 963 974 } while (!$this->startsWith($line, $key, true, true)); 964 975 965 return $result; 976 return $result; 966 977 } 967 978 968 979 private function compressMessageSet($message_set) 969 980 { 970 // given a comma delimited list of independent mid's, 981 // given a comma delimited list of independent mid's, 971 982 // compresses by grouping sequences together 972 983 973 984 // if less than 255 bytes long, let's not bother 974 985 if (strlen($message_set)<255) { 975 986 return $message_set; 976 987 } 977 988 978 989 // see if it's already been compress 979 990 if (strpos($message_set, ':') !== false) { 980 991 return $message_set; 981 992 } 982 993 983 994 // separate, then sort 984 995 $ids = explode(',', $message_set); 985 996 sort($ids); 986 997 987 998 $result = array(); 988 999 $start = $prev = $ids[0]; … … 1007 1018 $result[] = $start.':'.$prev; 1008 1019 } 1009 1020 1010 1021 // return as comma separated string 1011 1022 return implode(',', $result); … … 1052 1063 else if (empty($message_set)) 1053 1064 $message_set = '1:*'; 1054 1065 1055 1066 return $this->fetchHeaderIndex($mailbox, $message_set, 'UID', false); 1056 1067 } … … 1059 1070 { 1060 1071 $result = array(); 1061 1072 1062 1073 if (!$this->select($mailbox)) { 1063 1074 return false; … … 1090 1101 $line = $this->readLine(1024); 1091 1102 $line = $this->multLine($line); 1092 1103 1093 1104 if (!$line) 1094 1105 break; 1095 1106 1096 1107 $a = explode(' ', $line); 1097 1108 1098 1109 if (($line[0] == '*') && ($a[2] == 'FETCH')) { 1099 1110 $id = $a[1]; 1100 1111 1101 1112 $result[$id] = new rcube_mail_header; 1102 1113 $result[$id]->id = $id; … … 1134 1145 1135 1146 $time_str = str_replace('"', '', $time_str); 1136 1147 1137 1148 // if time is gmt... 1138 1149 $time_str = str_replace('GMT','+0000',$time_str); 1139 1150 1140 1151 $result[$id]->internaldate = $time_str; 1141 1152 $result[$id]->timestamp = $this->StrToTime($time_str); … … 1143 1154 } 1144 1155 1145 // BODYSTRUCTURE 1156 // BODYSTRUCTURE 1146 1157 if($bodystr) { 1147 1158 while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) { … … 1169 1180 // process the previous line. Otherwise, we'll keep adding the strings until we come 1170 1181 // to the next valid header line. 1171 1182 1172 1183 do { 1173 1184 $line = chop($this->readLine(300), "\r\n"); … … 1175 1186 // The preg_match below works around communigate imap, which outputs " UID <number>)". 1176 1187 // Without this, the while statement continues on and gets the "FH0 OK completed" message. 1177 // If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249. 1188 // If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249. 1178 1189 // This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing 1179 1190 // If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin … … 1199 1210 } while ($line[0] != ')' && !$this->startsWith($line, $key, true)); 1200 1211 1201 if (strncmp($line, $key, strlen($key))) { 1212 if (strncmp($line, $key, strlen($key))) { 1202 1213 // process header, fill rcube_mail_header obj. 1203 1214 // initialize … … 1212 1223 while ( list($lines_key, $str) = each($lines) ) { 1213 1224 list($field, $string) = $this->splitHeaderLine($str); 1214 1225 1215 1226 $field = strtolower($field); 1216 1227 $string = preg_replace('/\n\s*/', ' ', $string); 1217 1228 1218 1229 switch ($field) { 1219 1230 case 'date'; … … 1281 1292 $flags_str = preg_replace('/[\\\"]/', '', $flags_str); 1282 1293 $flags_a = explode(' ', $flags_str); 1283 1294 1284 1295 if (is_array($flags_a)) { 1285 1296 // reset($flags_a); … … 1344 1355 $c = count($a); 1345 1356 if ($c > 0) { 1346 1357 1347 1358 // Strategy: 1348 1359 // First, we'll create an "index" array. 1349 // Then, we'll use sort() on that array, 1360 // Then, we'll use sort() on that array, 1350 1361 // and use that to sort the main array. 1351 1362 1352 1363 // create "index" array 1353 1364 $index = array(); … … 1367 1378 $index[$key]=$data; 1368 1379 } 1369 1380 1370 1381 // sort index 1371 1382 $i = 0; … … 1376 1387 } 1377 1388 1378 // form new array based on index 1389 // form new array based on index 1379 1390 $result = array(); 1380 1391 reset($index); … … 1384 1395 } 1385 1396 } 1386 1397 1387 1398 return $result; 1388 1399 } … … 1393 1404 return -1; 1394 1405 } 1395 1406 1396 1407 $c = 0; 1397 1408 $command = $messages ? "UID EXPUNGE $messages" : "EXPUNGE"; … … 1407 1418 } 1408 1419 } while (!$this->startsWith($line, 'exp1', true, true)); 1409 1420 1410 1421 if ($this->parseResult($line) == 0) { 1411 1422 $this->selected = ''; // state has changed, need to reselect … … 1421 1432 return -1; 1422 1433 } 1423 1434 1424 1435 $flag = $this->flags[strtoupper($flag)]; 1425 1436 1426 1437 if (!$this->select($mailbox)) { 1427 1438 return -1; 1428 1439 } 1429 1440 1430 1441 $c = 0; 1431 1442 if (!$this->putLine("flg UID STORE $messages {$mod}FLAGS ($flag)")) { … … 1465 1476 return -1; 1466 1477 } 1467 1478 1468 1479 if (!$this->select($from)) { 1469 1480 return -1; 1470 1481 } 1471 1482 1472 1483 $this->putLine("cpy1 UID COPY $messages \"".$this->escape($to)."\""); 1473 1484 $line = $this->readReply(); … … 1530 1541 } 1531 1542 } 1532 1543 1533 1544 return $node; 1534 1545 } … … 1543 1554 $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES'; 1544 1555 $criteria = $criteria ? 'ALL '.trim($criteria) : 'ALL'; 1545 1556 1546 1557 if (!$this->putLineC("thrd1 THREAD $algorithm $encoding $criteria")) { 1547 1558 return false; … … 1563 1574 1564 1575 $this->error = "Thread: $line"; 1565 return false; 1576 return false; 1566 1577 } 1567 1578 … … 1594 1605 1595 1606 $this->error = "Search: $line"; 1596 return false; 1607 return false; 1597 1608 } 1598 1609 … … 1602 1613 return -1; 1603 1614 } 1604 1615 1605 1616 $r = $this->copy($messages, $from, $to); 1606 1617 … … 1626 1637 $mailbox = '*'; 1627 1638 } 1628 1639 1629 1640 if (empty($ref) && $this->rootdir) { 1630 1641 $ref = $this->rootdir; 1631 1642 } 1632 1643 1633 1644 if ($subscribed) { 1634 1645 $key = 'lsb'; … … 1645 1656 return false; 1646 1657 } 1647 1658 1648 1659 // get folder list 1649 1660 do { … … 1678 1689 return false; 1679 1690 } 1680 1691 1681 1692 $result = false; 1682 1693 $parts = (array) $parts; … … 1689 1700 foreach($parts as $part) 1690 1701 $peeks[] = "BODY.PEEK[$part.$type]"; 1691 1702 1692 1703 $request = "$key FETCH $id (" . implode(' ', $peeks) . ')'; 1693 1704 … … 1696 1707 return false; 1697 1708 } 1698 1709 1699 1710 do { 1700 1711 $line = $this->readLine(1000); … … 1741 1752 $mode = 0; 1742 1753 } 1743 1754 1744 1755 $reply_key = '* ' . $id; 1745 1756 $result = false; … … 1789 1800 $bytes = (int)$sizeStr; 1790 1801 $prev = ''; 1791 1802 1792 1803 while ($bytes > 0) { 1793 1804 $line = $this->readLine(1024); 1794 1805 $len = strlen($line); 1795 1806 1796 1807 if ($len > $bytes) { 1797 1808 $line = substr($line, 0, $bytes); … … 1812 1823 else 1813 1824 $prev = ''; 1814 1825 1815 1826 if ($file) 1816 1827 fwrite($file, base64_decode($line)); … … 1848 1859 } 1849 1860 } 1850 1861 1851 1862 // read in anything up until last line 1852 1863 if (!$end) … … 1923 1934 $query = 'usub1 UNSUBSCRIBE "' . $this->escape($folder) . '"'; 1924 1935 $this->putLine($query); 1925 1936 1926 1937 $line = trim($this->readLine(512)); 1927 1938 return ($this->parseResult($line) == 0); … … 1960 1971 $line = $this->readLine(); 1961 1972 } while (!$this->startsWith($line, 'a ', true, true)); 1962 1973 1963 1974 $result = ($this->parseResult($line) == 0); 1964 1975 if (!$result) { … … 1977 1988 return false; 1978 1989 } 1979 1990 1980 1991 // open message file 1981 1992 $in_fp = false; … … 1983 1994 $in_fp = fopen($path, 'r'); 1984 1995 } 1985 if (!$in_fp) { 1996 if (!$in_fp) { 1986 1997 $this->error = "Couldn't open $path for reading"; 1987 1998 return false; 1988 1999 } 1989 2000 1990 2001 $len = filesize($path); 1991 2002 if (!$len) { … … 2037 2048 return $result; 2038 2049 } 2039 2050 2040 2051 $this->error = "Couldn't send command \"$request\""; 2041 2052 return false; … … 2075 2086 $result = false; 2076 2087 $quota_lines = array(); 2077 2088 2078 2089 // get line(s) containing quota info 2079 2090 if ($this->putLine('QUOT1 GETQUOTAROOT "INBOX"')) { … … 2085 2096 } while (!$this->startsWith($line, 'QUOT1', true, true)); 2086 2097 } 2087 2098 2088 2099 // return false if not found, parse if found 2089 2100 $min_free = PHP_INT_MAX; … … 2092 2103 $parts = explode(' ', $quota_line); 2093 2104 $storage_part = array_search('STORAGE', $parts); 2094 2105 2095 2106 if (!$storage_part) 2096 2107 continue; 2097 2108 2098 2109 $used = intval($parts[$storage_part+1]); 2099 2110 $total = intval($parts[$storage_part+2]); 2100 $free = $total - $used; 2101 2111 $free = $total - $used; 2112 2102 2113 // return lowest available space from all quotas 2103 if ($free < $min_free) { 2104 $min_free = $free; 2114 if ($free < $min_free) { 2115 $min_free = $free; 2105 2116 $result['used'] = $used; 2106 2117 $result['total'] = $total; … … 2138 2149 $ts = (int) $ts; 2139 2150 2140 return $ts < 0 ? 0 : $ts; 2151 return $ts < 0 ? 0 : $ts; 2141 2152 } 2142 2153 … … 2163 2174 $in_quotes = false; 2164 2175 $elem = 0; 2165 2176 2166 2177 for ($i;$i<$len;$i++) { 2167 2178 $c = (string)$str[$i]; … … 2186 2197 } 2187 2198 } 2188 2199 2189 2200 return $data; 2190 2201 } … … 2192 2203 private function escape($string) 2193 2204 { 2194 return strtr($string, array('"'=>'\\"', '\\' => '\\\\')); 2205 return strtr($string, array('"'=>'\\"', '\\' => '\\\\')); 2195 2206 } 2196 2207 2197 2208 private function unEscape($string) 2198 2209 { 2199 return strtr($string, array('\\"'=>'"', '\\\\' => '\\')); 2210 return strtr($string, array('\\"'=>'"', '\\\\' => '\\')); 2200 2211 } 2201 2212
Note: See TracChangeset
for help on using the changeset viewer.
