Aleksander Machniak
2013-01-17 8e8f3b96b51fde1df953de7398b15e0f01e10777
program/lib/Roundcube/rcube_imap_generic.php
@@ -2,8 +2,6 @@
/**
 +-----------------------------------------------------------------------+
 | program/include/rcube_imap_generic.php                                |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
 | Copyright (C) 2011-2012, Kolab Systems AG                             |
@@ -19,13 +17,11 @@
 |   functionality built-in.                                             |
 |                                                                       |
 |   Based on Iloha IMAP Library. See http://ilohamail.org/ for details  |
 |                                                                       |
 +-----------------------------------------------------------------------+
 | Author: Aleksander Machniak <alec@alec.pl>                            |
 | Author: Ryo Chijiiwa <Ryo@IlohaMail.org>                              |
 +-----------------------------------------------------------------------+
*/
/**
 * PHP based wrapper class to connect to an IMAP server
@@ -757,12 +753,16 @@
        $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']);
        if (!$this->fp) {
            if (!$errstr) {
                $errstr = "Unknown reason (fsockopen() function disabled?)";
            }
            $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr));
            return false;
        }
        if ($this->prefs['timeout'] > 0)
        if ($this->prefs['timeout'] > 0) {
            stream_set_timeout($this->fp, $this->prefs['timeout']);
        }
        $line = trim(fgets($this->fp, 8192));
@@ -1310,6 +1310,11 @@
                // * LIST (<options>) <delimiter> <mailbox>
                if ($cmd == 'LIST' || $cmd == 'LSUB') {
                    list($opts, $delim, $mailbox) = $this->tokenizeResponse($line, 3);
                    // Remove redundant separator at the end of folder name, UW-IMAP bug? (#1488879)
                    if ($delim) {
                        $mailbox = rtrim($mailbox, $delim);
                    }
                    // Add to result array
                    if (!$lstatus) {
@@ -2410,8 +2415,9 @@
        $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 +2430,117 @@
            $mode = -1;
        }
        // receive reply line
        do {
            $line = rtrim($this->readLine(1024));
            $a    = explode(' ', $line);
        } while (!($end = $this->startsWith($line, $key, true)) && $a[2] != 'FETCH');
            $line = trim($this->readLine(1024));
        $len    = strlen($line);
        $result = false;
        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;
                }
                $len = strlen($line);
                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 ($result !== false) {
                    if ($mode == 1) {
                        $result = base64_decode($result);
                    }
                    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 if ($mode == 2) {
                        $result = quoted_printable_decode($result);
                    }
                    else if ($mode == 3) {
                        $result = convert_uudecode($result);
                    }
                }
                if ($file) {
                    if (fwrite($file, $line) === false)
                        break;
                }
                else if ($print)
                    echo $line;
                else
                    $result .= $line;
            }
        }
            // response with string literal
            else if (preg_match('/\{([0-9]+)\}$/', $line, $m)) {
                $bytes = (int) $m[1];
                $prev  = '';
        // read in anything up until last line
        if (!$end)
            do {
                $line = $this->readLine(1024);
            } while (!$this->startsWith($line, $key, true));
                while ($bytes > 0) {
                    $line = $this->readLine(8192);
                    if ($line === NULL) {
                        break;
                    }
                    $len = strlen($line);
                    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";
                    }
                    if ($file) {
                        if (fwrite($file, $line) === false) {
                            break;
                        }
                    }
                    else if ($print) {
                        echo $line;
                    }
                    else {
                        $result .= $line;
                    }
                }
            }
        } 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;
@@ -2548,10 +2553,11 @@
     * @param string $message Message content
     * @param array  $flags   Message flags
     * @param string $date    Message internal date
     * @param bool   $binary  Enable BINARY append (RFC3516)
     *
     * @return string|bool On success APPENDUID response (if available) or True, False on failure
     */
    function append($mailbox, &$message, $flags = array(), $date = null)
    function append($mailbox, &$message, $flags = array(), $date = null, $binary = false)
    {
        unset($this->data['APPENDUID']);
@@ -2559,8 +2565,13 @@
            return false;
        }
        $message = str_replace("\r", '', $message);
        $message = str_replace("\n", "\r\n", $message);
        $binary       = $binary && $this->getCapability('BINARY');
        $literal_plus = !$binary && $this->prefs['literal+'];
        if (!$binary) {
            $message = str_replace("\r", '', $message);
            $message = str_replace("\n", "\r\n", $message);
        }
        $len = strlen($message);
        if (!$len) {
@@ -2573,12 +2584,12 @@
        if (!empty($date)) {
            $request .= ' ' . $this->escape($date);
        }
        $request .= ' {' . $len . ($this->prefs['literal+'] ? '+' : '') . '}';
        $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}';
        // send APPEND command
        if ($this->putLine($request)) {
            // Do not wait when LITERAL+ is supported
            if (!$this->prefs['literal+']) {
            if (!$literal_plus) {
                $line = $this->readReply();
                if ($line[0] != '+') {
@@ -2620,10 +2631,11 @@
     * @param string $headers Message headers
     * @param array  $flags   Message flags
     * @param string $date    Message internal date
     * @param bool   $binary  Enable BINARY append (RFC3516)
     *
     * @return string|bool On success APPENDUID response (if available) or True, False on failure
     */
    function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null)
    function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null, $binary = false)
    {
        unset($this->data['APPENDUID']);
@@ -2654,18 +2666,21 @@
            $len += strlen($headers) + strlen($body_separator);
        }
        $binary       = $binary && $this->getCapability('BINARY');
        $literal_plus = !$binary && $this->prefs['literal+'];
        // build APPEND command
        $key = $this->nextTag();
        $request = "$key APPEND " . $this->escape($mailbox) . ' (' . $this->flagsToStr($flags) . ')';
        if (!empty($date)) {
            $request .= ' ' . $this->escape($date);
        }
        $request .= ' {' . $len . ($this->prefs['literal+'] ? '+' : '') . '}';
        $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}';
        // send APPEND command
        if ($this->putLine($request)) {
            // Don't wait when LITERAL+ is supported
            if (!$this->prefs['literal+']) {
            if (!$literal_plus) {
                $line = $this->readReply();
                if ($line[0] != '+') {