diff options
| -rw-r--r-- | CHANGELOG | 1 | ||||
| -rw-r--r-- | program/lib/Roundcube/rcube_imap_generic.php | 184 | 
2 files changed, 93 insertions, 92 deletions
| @@ -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);                      } -                    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"; -                } +                    $bytes -= $len; -                if ($file) { -                    if (fwrite($file, $line) === false) -                        break; +                    // 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"; +                    } + +                    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; | 
