From cb8ebfcbf8cf72f1aeb44b4fcdd62e071cc00368 Mon Sep 17 00:00:00 2001 From: thomascube <thomas@roundcube.net> Date: Wed, 06 Oct 2010 04:02:47 -0400 Subject: [PATCH] Hotfixes for release 0.4.1 building new 0.4.2 version --- program/include/rcube_imap_generic.php | 287 ++++++++++++++++++++++++++------------------------------- 1 files changed, 132 insertions(+), 155 deletions(-) diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index ab37902..bfbf072 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -4,8 +4,8 @@ +-----------------------------------------------------------------------+ | program/include/rcube_imap_generic.php | | | - | This file is part of the RoundCube Webmail client | - | Copyright (C) 2005-2010, RoundCube Dev. - Switzerland | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2005-2010, Roundcube Dev. - Switzerland | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -119,7 +119,7 @@ { } - private function putLine($string, $endln=true) + function putLine($string, $endln=true) { if (!$this->fp) return false; @@ -128,14 +128,21 @@ write_log('imap', 'C: '. rtrim($string)); } - return fputs($this->fp, $string . ($endln ? "\r\n" : '')); + $res = fwrite($this->fp, $string . ($endln ? "\r\n" : '')); + + if ($res === false) { + @fclose($this->fp); + $this->fp = null; + } + + return $res; } // $this->putLine replacement with Command Continuation Requests (RFC3501 7.5) support - private function putLineC($string, $endln=true) + function putLineC($string, $endln=true) { if (!$this->fp) - return NULL; + return false; if ($endln) $string .= "\r\n"; @@ -166,7 +173,7 @@ return $res; } - private function readLine($size=1024) + function readLine($size=1024) { $line = ''; @@ -191,7 +198,7 @@ break; } if (!empty($this->prefs['debug_mode'])) { - write_log('imap', 'S: '. chop($buffer)); + write_log('imap', 'S: '. rtrim($buffer)); } $line .= $buffer; } while ($buffer[strlen($buffer)-1] != "\n"); @@ -199,9 +206,9 @@ return $line; } - private function multLine($line, $escape=false) + function multLine($line, $escape=false) { - $line = chop($line); + $line = rtrim($line); if (preg_match('/\{[0-9]+\}$/', $line)) { $out = ''; @@ -220,7 +227,7 @@ return $line; } - private function readBytes($bytes) + function readBytes($bytes) { $data = ''; $len = 0; @@ -242,7 +249,7 @@ } // don't use it in loops, until you exactly know what you're doing - private function readReply(&$untagged=null) + function readReply(&$untagged=null) { do { $line = trim($this->readLine(1024)); @@ -257,7 +264,7 @@ return $line; } - private function parseResult($string) + function parseResult($string) { $a = explode(' ', trim($string)); if (count($a) >= 2) { @@ -278,7 +285,7 @@ } // check if $string starts with $match (or * BYE/BAD) - private function startsWith($string, $match, $error=false, $nonempty=false) + function startsWith($string, $match, $error=false, $nonempty=false) { $len = strlen($match); if ($len == 0) { @@ -288,31 +295,6 @@ return true; } if (strncmp($string, $match, $len) == 0) { - return true; - } - if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) { - if (strtoupper($m[1]) == 'BYE') { - @fclose($this->fp); - $this->fp = null; - } - return true; - } - if ($nonempty && !strlen($string)) { - return true; - } - return false; - } - - private function startsWithI($string, $match, $error=false, $nonempty=false) - { - $len = strlen($match); - if ($len == 0) { - return false; - } - if (!$this->fp) { - return true; - } - if (strncasecmp($string, $match, $len) == 0) { return true; } if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) { @@ -346,14 +328,10 @@ } do { $line = trim($this->readLine(1024)); - $a = explode(' ', $line); - if ($line[0] == '*') { - while (list($k, $w) = each($a)) { - if ($w != '*' && $w != 'CAPABILITY') - $this->capability[] = strtoupper($w); - } - } - } while ($a[0] != 'cp01'); + if (preg_match('/^\* CAPABILITY (.+)/i', $line, $matches)) { + $this->capability = explode(' ', strtoupper($matches[1])); + } + } while (!$this->startsWith($line, 'cp01', true)); $this->capability_readed = true; @@ -445,23 +423,7 @@ return true; } - if (!$this->getCapability('NAMESPACE')) { - return false; - } - - if (!$this->putLine("ns1 NAMESPACE")) { - return false; - } - do { - $line = $this->readLine(1024); - if ($this->startsWith($line, '* NAMESPACE')) { - $i = 0; - $line = $this->unEscape($line); - $data = $this->parseNamespace(substr($line,11), $i, 0, 0); - } - } while (!$this->startsWith($line, 'ns1', true, true)); - - if (!is_array($data)) { + if (!is_array($data = $this->_namespace())) { return false; } @@ -510,13 +472,9 @@ } do { - $line = $this->readLine(500); - if ($line[0] == '*') { - $line = rtrim($line); - $a = rcube_explode_quoted_string(' ', $this->unEscape($line)); - if ($a[0] == '*') { - $delimiter = str_replace('"', '', $a[count($a)-2]); - } + $line = $this->readLine(1024); + if (preg_match('/^\* LIST \([^\)]*\) "*([^"]+)"* ""/', $line, $m)) { + $delimiter = $this->unEscape($m[1]); } } while (!$this->startsWith($line, 'ghd', true, true)); @@ -526,22 +484,9 @@ // if that fails, try namespace extension // try to fetch namespace data - if (!$this->putLine("ns1 NAMESPACE")) { + if (!is_array($data = $this->_namespace())) { return false; } - - do { - $line = $this->readLine(1024); - if ($this->startsWith($line, '* NAMESPACE')) { - $i = 0; - $line = $this->unEscape($line); - $data = $this->parseNamespace(substr($line,11), $i, 0, 0); - } - } while (!$this->startsWith($line, 'ns1', true, true)); - - if (!is_array($data)) { - return false; - } // extract user space data (opposed to global/shared space) $user_space_data = $data[0]; @@ -559,6 +504,31 @@ $delimiter = $first_userspace[1]; return $delimiter; + } + + function _namespace() + { + if (!$this->getCapability('NAMESPACE')) { + return false; + } + + if (!$this->putLine("ns1 NAMESPACE")) { + return false; + } + + do { + $line = $this->readLine(1024); + if (preg_match('/^\* NAMESPACE/', $line)) { + $i = 0; + $data = $this->parseNamespace(substr($line,11), $i, 0, 0); + } + } while (!$this->startsWith($line, 'ns1', true, true)); + + if (!is_array($data)) { + return false; + } + + return $data; } function connect($host, $user, $password, $options=null) @@ -655,7 +625,7 @@ $this->putLine("tls0 STARTTLS"); $line = $this->readLine(4096); - if (!$this->startsWith($line, "tls0 OK")) { + if (!preg_match('/^tls0 OK/', $line)) { $this->error = "Server responded to STARTTLS with: $line"; $this->errornum = -2; return false; @@ -716,6 +686,7 @@ } $this->getNamespace(); $this->logged = true; + return true; } else { return false; @@ -729,7 +700,7 @@ function close() { - if ($this->putLine("I LOGOUT")) { + if ($this->logged && $this->putLine("I LOGOUT")) { if (!feof($this->fp)) fgets($this->fp, 1024); } @@ -748,31 +719,24 @@ if ($this->putLine("sel1 SELECT \"".$this->escape($mailbox).'"')) { do { - $line = chop($this->readLine(300)); - $a = explode(' ', $line); - if (count($a) == 3) { - $token = strtoupper($a[2]); - if ($token == 'EXISTS') { - $this->exists = (int) $a[1]; - } - else if ($token == 'RECENT') { - $this->recent = (int) $a[1]; - } + $line = rtrim($this->readLine(512)); + + if (preg_match('/^\* ([0-9]+) (EXISTS|RECENT)$/', $line, $m)) { + $token = strtolower($m[2]); + $this->$token = (int) $m[1]; } else if (preg_match('/\[?PERMANENTFLAGS\s+\(([^\)]+)\)\]/U', $line, $match)) { $this->permanentflags = explode(' ', $match[1]); } } while (!$this->startsWith($line, 'sel1', true, true)); - if (strcasecmp($a[1], 'OK') == 0) { + if ($this->parseResult($line) == 0) { $this->selected = $mailbox; return true; } - else { - $this->error = "Couldn't select $mailbox"; - } } + $this->error = "Couldn't select $mailbox"; return false; } @@ -830,7 +794,8 @@ $add = $this->compressMessageSet(join(',', $add)); $command = "s ".$is_uid."SORT ($field) $encoding ALL"; - $line = $data = ''; + $line = ''; + $data = ''; if (!empty($add)) $command .= ' '.$add; @@ -839,8 +804,8 @@ return false; } do { - $line = chop($this->readLine()); - if ($this->startsWith($line, '* SORT')) { + $line = rtrim($this->readLine()); + if (!$data && preg_match('/^\* SORT/', $line)) { $data .= substr($line, 7); } else if (preg_match('/^[0-9 ]+$/', $line)) { $data .= $line; @@ -923,7 +888,7 @@ $result = array(); do { - $line = chop($this->readLine(200)); + $line = rtrim($this->readLine(200)); $line = $this->multLine($line); if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { @@ -1052,7 +1017,7 @@ $result = -1; if ($this->putLine("fuid FETCH $id (UID)")) { do { - $line = chop($this->readLine(1024)); + $line = rtrim($this->readLine(1024)); if (preg_match("/^\* $id FETCH \(UID (.*)\)/i", $line, $r)) { $result = $r[1]; } @@ -1110,10 +1075,8 @@ if (!$line) break; - $a = explode(' ', $line); - - if (($line[0] == '*') && ($a[2] == 'FETCH')) { - $id = $a[1]; + if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { + $id = $m[1]; $result[$id] = new rcube_mail_header; $result[$id]->id = $id; @@ -1187,7 +1150,7 @@ // to the next valid header line. do { - $line = chop($this->readLine(300), "\r\n"); + $line = rtrim($this->readLine(300), "\r\n"); // The preg_match below works around communigate imap, which outputs " UID <number>)". // Without this, the while statement continues on and gets the "FH0 OK completed" message. @@ -1266,7 +1229,7 @@ } break; case 'in-reply-to': - $result[$id]->in_reply_to = preg_replace('/[\n<>]/', '', $string); + $result[$id]->in_reply_to = str_replace(array("\n", '<', '>'), '', $string); break; case 'references': $result[$id]->references = $string; @@ -1289,8 +1252,6 @@ break; } // end switch () } // end while () - } else { - $a = explode(' ', $line); } // process flags @@ -1299,7 +1260,6 @@ $flags_a = explode(' ', $flags_str); if (is_array($flags_a)) { - // reset($flags_a); foreach($flags_a as $flag) { $flag = strtoupper($flag); if ($flag == 'SEEN') { @@ -1450,7 +1410,7 @@ } do { - $line = $this->readLine(1000); + $line = $this->readLine(); if ($line[0] == '*') { $c++; } @@ -1506,7 +1466,7 @@ { $node = array(); if ($str[$begin] != '(') { - $stop = $begin + strspn($str, "1234567890", $begin, $end - $begin); + $stop = $begin + strspn($str, '1234567890', $begin, $end - $begin); $msg = substr($str, $begin, $stop - $begin); if ($msg == 0) return $node; @@ -1552,30 +1512,40 @@ function thread($folder, $algorithm='REFERENCES', $criteria='', $encoding='US-ASCII') { + $old_sel = $this->selected; + if (!$this->select($folder)) { - return false; + return false; + } + + // return empty result when folder is empty and we're just after SELECT + if ($old_sel != $folder && !$this->exists) { + return array(array(), array(), array()); } $encoding = $encoding ? trim($encoding) : 'US-ASCII'; $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES'; $criteria = $criteria ? 'ALL '.trim($criteria) : 'ALL'; + $data = ''; if (!$this->putLineC("thrd1 THREAD $algorithm $encoding $criteria")) { return false; } do { - $line = trim($this->readLine(10000)); - if (preg_match('/^\* THREAD/', $line)) { - $str = trim(substr($line, 8)); - $depthmap = array(); - $haschildren = array(); - $tree = $this->parseThread($str, 0, strlen($str), null, null, 0, $depthmap, $haschildren); + $line = trim($this->readLine()); + if (!$data && preg_match('/^\* THREAD/', $line)) { + $data .= substr($line, 9); + } else if (preg_match('/^[0-9() ]+$/', $line)) { + $data .= $line; } } while (!$this->startsWith($line, 'thrd1', true, true)); $result_code = $this->parseResult($line); if ($result_code == 0) { - return array($tree, $depthmap, $haschildren); + $depthmap = array(); + $haschildren = array(); + $tree = $this->parseThread($data, 0, strlen($data), null, null, 0, $depthmap, $haschildren); + return array($tree, $depthmap, $haschildren); } $this->error = "Thread: $line"; @@ -1596,7 +1566,7 @@ } $data = ''; - $query = 'srch1 ' . ($return_uid ? 'UID ' : '') . 'SEARCH ' . chop($criteria); + $query = 'srch1 ' . ($return_uid ? 'UID ' : '') . 'SEARCH ' . trim($criteria); if (!$this->putLineC($query)) { return false; @@ -1604,7 +1574,7 @@ do { $line = trim($this->readLine()); - if ($this->startsWith($line, '* SEARCH')) { + if (!$data && preg_match('/^\* SEARCH/', $line)) { $data .= substr($line, 8); } else if (preg_match('/^[0-9 ]+$/', $line)) { $data .= $line; @@ -1663,8 +1633,11 @@ $command = 'LIST'; } + $ref = $this->escape($ref); + $mailbox = $this->escape($mailbox); + // send command - if (!$this->putLine($key." ".$command." \"". $this->escape($ref) ."\" \"". $this->escape($mailbox) ."\"")) { + if (!$this->putLine($key." ".$command." \"". $ref ."\" \"". $mailbox ."\"")) { $this->error = "Couldn't send $command command"; return false; } @@ -1673,16 +1646,15 @@ do { $line = $this->readLine(500); $line = $this->multLine($line, true); - $a = explode(' ', $line); + $line = trim($line); - if (($line[0] == '*') && ($a[1] == $command)) { - $line = rtrim($line); - // split one line - $a = rcube_explode_quoted_string(' ', $line); - // last string is folder name - $folders[] = preg_replace(array('/^"/', '/"$/'), '', $this->unEscape($a[count($a)-1])); - // second from last is delimiter - $delim = trim($a[count($a)-2], '"'); + if (preg_match('/^\* '.$command.' \(([^\)]*)\) "*([^"]+)"* (.*)$/', $line, $m)) { + // folder name + $folders[] = preg_replace(array('/^"/', '/"$/'), '', $this->unEscape($m[3])); + // attributes +// $attrib = explode(' ', $this->unEscape($m[1])); + // delimiter +// $delim = $this->unEscape($m[2]); } } while (!$this->startsWith($line, $key, true)); @@ -1721,7 +1693,7 @@ } do { - $line = $this->readLine(1000); + $line = $this->readLine(1024); $line = $this->multLine($line); if (preg_match('/BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) { @@ -1765,12 +1737,11 @@ $mode = 0; } - $reply_key = '* ' . $id; - $result = false; - // format request - $key = 'ftch0'; - $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id (BODY.PEEK[$part])"; + $reply_key = '* ' . $id; + $key = 'ftch0'; + $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id (BODY.PEEK[$part])"; + // send request if (!$this->putLine($request)) { return false; @@ -1778,11 +1749,12 @@ // receive reply line do { - $line = chop($this->readLine(1000)); + $line = rtrim($this->readLine(1024)); $a = explode(' ', $line); } while (!($end = $this->startsWith($line, $key, true)) && $a[2] != 'FETCH'); - $len = strlen($line); + $len = strlen($line); + $result = false; // handle empty "* X FETCH ()" response if ($line[$len-1] == ')' && $line[$len-2] != '(') { @@ -1815,6 +1787,10 @@ while ($bytes > 0) { $line = $this->readLine(1024); + + if ($line === NULL) + break; + $len = strlen($line); if ($len > $bytes) { @@ -1878,7 +1854,7 @@ $line = $this->readLine(1024); } while (!$this->startsWith($line, $key, true)); - if ($result) { + if ($result !== false) { if ($file) { fwrite($file, $result); } else if ($print) { @@ -1995,7 +1971,7 @@ return false; } - function appendFromFile($folder, $path, $headers=null, $separator="\n\n") + function appendFromFile($folder, $path, $headers=null) { if (!$folder) { return false; @@ -2011,14 +1987,16 @@ return false; } + $body_separator = "\r\n\r\n"; $len = filesize($path); + if (!$len) { return false; } if ($headers) { $headers = preg_replace('/[\r\n]+$/', '', $headers); - $len += strlen($headers) + strlen($separator); + $len += strlen($headers) + strlen($body_separator); } // send APPEND command @@ -2034,7 +2012,7 @@ // send headers with body separator if ($headers) { - $this->putLine($headers . $separator, false); + $this->putLine($headers . $body_separator, false); } // send file @@ -2102,8 +2080,8 @@ // get line(s) containing quota info if ($this->putLine('QUOT1 GETQUOTAROOT "INBOX"')) { do { - $line = chop($this->readLine(5000)); - if ($this->startsWith($line, '* QUOTA ')) { + $line = rtrim($this->readLine(5000)); + if (preg_match('/^\* QUOTA /', $line)) { $quota_lines[] = $line; } } while (!$this->startsWith($line, 'QUOT1', true, true)); @@ -2112,7 +2090,7 @@ // return false if not found, parse if found $min_free = PHP_INT_MAX; foreach ($quota_lines as $key => $quota_line) { - $quota_line = preg_replace('/[()]/', '', $quota_line); + $quota_line = str_replace(array('(', ')'), '', $quota_line); $parts = explode(' ', $quota_line); $storage_part = array_search('STORAGE', $parts); @@ -2187,7 +2165,7 @@ $in_quotes = false; $elem = 0; - for ($i;$i<$len;$i++) { + for ($i; $i<$len; $i++) { $c = (string)$str[$i]; if ($c == '(' && !$in_quotes) { $i++; @@ -2198,7 +2176,7 @@ } else if ($c == '\\') { $i++; if ($in_quotes) { - $data[$elem] .= $c.$str[$i]; + $data[$elem] .= $str[$i]; } } else if ($c == '"') { $in_quotes = !$in_quotes; @@ -2225,4 +2203,3 @@ } -?> -- Gitblit v1.9.1