From 7eb7806b211147b40c191d17a983ba34f26b8f1c Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 29 Nov 2012 13:51:49 +0100 Subject: Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836) --- program/lib/Roundcube/rcube_imap_generic.php | 186 +++++++++++++-------------- 1 file changed, 93 insertions(+), 93 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index ae0bfdd6c..0f32d83d1 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -2410,8 +2410,9 @@ class rcube_imap_generic $partial = $max_bytes ? sprintf('<0.%d>', $max_bytes) : ''; // format request - $key = $this->nextTag(); - $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id ($fetch_mode.PEEK[$part]$partial)"; + $key = $this->nextTag(); + $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id ($fetch_mode.PEEK[$part]$partial)"; + $result = false; // send request if (!$this->putLine($request)) { @@ -2424,118 +2425,117 @@ class rcube_imap_generic $mode = -1; } - // receive reply line do { - $line = rtrim($this->readLine(1024)); - $a = explode(' ', $line); - } while (!($end = $this->startsWith($line, $key, true)) && $a[2] != 'FETCH'); - - $len = strlen($line); - $result = false; + $line = trim($this->readLine(1024)); - if ($a[2] != 'FETCH') { - } - // handle empty "* X FETCH ()" response - else if ($line[$len-1] == ')' && $line[$len-2] != '(') { - // one line response, get everything between first and last quotes - if (substr($line, -4, 3) == 'NIL') { - // NIL response - $result = ''; - } else { - $from = strpos($line, '"') + 1; - $to = strrpos($line, '"'); - $len = $to - $from; - $result = substr($line, $from, $len); + if (!$line) { + break; } - if ($mode == 1) { - $result = base64_decode($result); - } - else if ($mode == 2) { - $result = quoted_printable_decode($result); - } - else if ($mode == 3) { - $result = convert_uudecode($result); + if (!preg_match('/^\* ([0-9]+) FETCH (.*)$/', $line, $m)) { + continue; } - } else if ($line[$len-1] == '}') { - // multi-line request, find sizes of content and receive that many bytes - $from = strpos($line, '{') + 1; - $to = strrpos($line, '}'); - $len = $to - $from; - $sizeStr = substr($line, $from, $len); - $bytes = (int)$sizeStr; - $prev = ''; + $line = $m[2]; + $last = substr($line, -1); - while ($bytes > 0) { - $line = $this->readLine(8192); + // handle one line response + if ($line[0] == '(' && $last == ')') { + // tokenize content inside brackets + $tokens = $this->tokenizeResponse(preg_replace('/(^\(|\$)/', '', $line)); + $result = count($tokens) == 1 ? $tokens[0] : false; - if ($line === NULL) { - break; + if ($result !== false) { + if ($mode == 1) { + $result = base64_decode($result); + } + else if ($mode == 2) { + $result = quoted_printable_decode($result); + } + else if ($mode == 3) { + $result = convert_uudecode($result); + } } + } + // response with string literal + else if (preg_match('/\{([0-9]+)\}$/', $line, $m)) { + $bytes = (int) $m[1]; + $prev = ''; + + while ($bytes > 0) { + $line = $this->readLine(8192); - $len = strlen($line); + if ($line === NULL) { + break; + } - if ($len > $bytes) { - $line = substr($line, 0, $bytes); $len = strlen($line); - } - $bytes -= $len; - - // BASE64 - if ($mode == 1) { - $line = rtrim($line, "\t\r\n\0\x0B"); - // create chunks with proper length for base64 decoding - $line = $prev.$line; - $length = strlen($line); - if ($length % 4) { - $length = floor($length / 4) * 4; - $prev = substr($line, $length); - $line = substr($line, 0, $length); + + if ($len > $bytes) { + $line = substr($line, 0, $bytes); + $len = strlen($line); + } + $bytes -= $len; + + // BASE64 + if ($mode == 1) { + $line = rtrim($line, "\t\r\n\0\x0B"); + // create chunks with proper length for base64 decoding + $line = $prev.$line; + $length = strlen($line); + if ($length % 4) { + $length = floor($length / 4) * 4; + $prev = substr($line, $length); + $line = substr($line, 0, $length); + } + else { + $prev = ''; + } + $line = base64_decode($line); + } + // QUOTED-PRINTABLE + else if ($mode == 2) { + $line = rtrim($line, "\t\r\0\x0B"); + $line = quoted_printable_decode($line); + } + // UUENCODE + else if ($mode == 3) { + $line = rtrim($line, "\t\r\n\0\x0B"); + if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line)) { + continue; + } + $line = convert_uudecode($line); + } + // default + else if ($formatted) { + $line = rtrim($line, "\t\r\n\0\x0B") . "\n"; } - else - $prev = ''; - $line = base64_decode($line); - // QUOTED-PRINTABLE - } else if ($mode == 2) { - $line = rtrim($line, "\t\r\0\x0B"); - $line = quoted_printable_decode($line); - // UUENCODE - } else if ($mode == 3) { - $line = rtrim($line, "\t\r\n\0\x0B"); - if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line)) - continue; - $line = convert_uudecode($line); - // default - } else if ($formatted) { - $line = rtrim($line, "\t\r\n\0\x0B") . "\n"; - } - if ($file) { - if (fwrite($file, $line) === false) - break; + if ($file) { + if (fwrite($file, $line) === false) { + break; + } + } + else if ($print) { + echo $line; + } + else { + $result .= $line; + } } - else if ($print) - echo $line; - else - $result .= $line; } - } - - // read in anything up until last line - if (!$end) - do { - $line = $this->readLine(1024); - } while (!$this->startsWith($line, $key, true)); + } while (!$this->startsWith($line, $key, true)); if ($result !== false) { if ($file) { return fwrite($file, $result); - } else if ($print) { + } + else if ($print) { echo $result; - } else - return $result; - return true; + return true; + } + + return $result; } return false; -- cgit v1.2.3