summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Machniak <alec@alec.pl>2012-11-29 13:51:49 +0100
committerAleksander Machniak <alec@alec.pl>2012-11-29 13:51:49 +0100
commit7eb7806b211147b40c191d17a983ba34f26b8f1c (patch)
tree6278491d67eb483162e05ac7ce355856090baf72
parent876d31d5940f3c4c2f683891130db0201f4a3913 (diff)
Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836)
-rw-r--r--CHANGELOG1
-rw-r--r--program/lib/Roundcube/rcube_imap_generic.php186
2 files changed, 94 insertions, 93 deletions
diff --git a/CHANGELOG b/CHANGELOG
index ae6d27398..a47c95dcf 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
+- Fix broken message/part bodies when FETCH response contains more untagged lines (#1488836)
- Fix empty email on identities list after identity update (#1488834)
- Add new identities_level: (4) one identity with possibility to edit only signature
- Use Delivered-To header as a last resort for identity selection (#1488840)
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;