alecpl
2011-03-09 3e398182213cb66057ff40b605296092bb9fe83d
program/include/rcube_imap_generic.php
@@ -5,7 +5,7 @@
 | program/include/rcube_imap_generic.php                                |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2010, Roundcube Dev. - Switzerland                 |
 | Copyright (C) 2005-2010, The Roundcube Dev Team                       |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | PURPOSE:                                                              |
@@ -213,31 +213,26 @@
    {
        $line = '';
        if (!$this->fp) {
            return NULL;
        }
        if (!$size) {
            $size = 1024;
        }
        do {
            if (feof($this->fp)) {
            if ($this->eof()) {
                return $line ? $line : NULL;
            }
            $buffer = fgets($this->fp, $size);
            if ($buffer === false) {
                @fclose($this->fp);
                $this->fp = null;
                $this->closeSocket();
                break;
            }
            if ($this->_debug) {
                $this->debug('S: '. rtrim($buffer));
            }
            $line .= $buffer;
        } while ($buffer[strlen($buffer)-1] != "\n");
        } while (substr($buffer, -1) != "\n");
        return $line;
    }
@@ -267,7 +262,7 @@
    {
        $data = '';
        $len  = 0;
        while ($len < $bytes && !feof($this->fp))
        while ($len < $bytes && !$this->eof())
        {
            $d = fread($this->fp, $bytes-$len);
            if ($this->_debug) {
@@ -312,8 +307,7 @@
            } else if ($res == 'BAD') {
                $this->errornum = self::ERROR_BAD;
            } else if ($res == 'BYE') {
                @fclose($this->fp);
                $this->fp = null;
                $this->closeSocket();
                $this->errornum = self::ERROR_BYE;
            }
@@ -339,6 +333,32 @@
        return self::ERROR_UNKNOWN;
    }
    private function eof()
    {
        if (!is_resource($this->fp)) {
            return true;
        }
        // If a connection opened by fsockopen() wasn't closed
        // by the server, feof() will hang.
        $start = microtime(true);
        if (feof($this->fp) ||
            ($this->prefs['timeout'] && (microtime(true) - $start > $this->prefs['timeout']))
        ) {
            $this->closeSocket();
            return true;
        }
        return false;
    }
    private function closeSocket()
    {
        @fclose($this->fp);
        $this->fp = null;
    }
    function setError($code, $msg='')
    {
        $this->errornum = $code;
@@ -360,8 +380,7 @@
        }
        if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) {
            if (strtoupper($m[1]) == 'BYE') {
                @fclose($this->fp);
                $this->fp = null;
                $this->closeSocket();
            }
            return true;
        }
@@ -701,11 +720,12 @@
            $host = $this->prefs['ssl_mode'] . '://' . $host;
        }
        if ($this->prefs['timeout'] <= 0) {
            $this->prefs['timeout'] = ini_get('default_socket_timeout');
        }
        // Connect
        if ($this->prefs['timeout'] > 0)
            $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']);
        else
            $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr);
        $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']);
        if (!$this->fp) {
            $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr));
@@ -759,6 +779,11 @@
            }
        }
        // Send ID info
        if (!empty($this->prefs['ident']) && $this->getCapability('ID')) {
            $this->id($this->prefs['ident']);
        }
        $auth_methods = array();
        $result       = null;
@@ -777,6 +802,13 @@
            else if (!$login_disabled) {
                $auth_methods[] = 'LOGIN';
            }
            // Use best (for security) supported authentication method
            foreach (array('DIGEST-MD5', 'CRAM-MD5', 'CRAM_MD5', 'PLAIN', 'LOGIN') as $auth_method) {
                if (in_array($auth_method, $auth_methods)) {
                    break;
                }
            }
        }
        else {
            // Prevent from sending credentials in plain text when connection is not secure
@@ -786,32 +818,28 @@
                return false;
            }
            // replace AUTH with CRAM-MD5 for backward compat.
            $auth_methods[] = $auth_method == 'AUTH' ? 'CRAM-MD5' : $auth_method;
            if ($auth_method == 'AUTH') {
                $auth_method = 'CRAM-MD5';
            }
        }
        // pre-login capabilities can be not complete
        $this->capability_readed = false;
        // Authenticate
        foreach ($auth_methods as $method) {
            switch ($method) {
        switch ($auth_method) {
            case 'CRAM_MD5':
                $method = 'CRAM-MD5';
                $auth_method = 'CRAM-MD5';
            case 'CRAM-MD5':
            case 'DIGEST-MD5':
            case 'PLAIN':
                $result = $this->authenticate($user, $password, $method);
                $result = $this->authenticate($user, $password, $auth_method);
                break;
            case 'LOGIN':
                $result = $this->login($user, $password);
                break;
            default:
                $this->setError(self::ERROR_BAD, "Configuration error. Unknown auth method: $method");
            }
            if (is_resource($result)) {
                break;
            }
                $this->setError(self::ERROR_BAD, "Configuration error. Unknown auth method: $auth_method");
        }
        // Connected and authenticated
@@ -840,8 +868,7 @@
            $this->readReply();
        }
        @fclose($this->fp);
        $this->fp = false;
        $this->closeSocket();
    }
    /**
@@ -1157,6 +1184,44 @@
        return false;
    }
    /**
     * Executes ID command (RFC2971)
     *
     * @param array $items Client identification information key/value hash
     *
     * @return array Server identification information key/value hash
     * @access public
     * @since 0.6
     */
    function id($items=array())
    {
        if (is_array($items) && !empty($items)) {
            foreach ($items as $key => $value) {
                $args[] = $this->escape($key);
                $args[] = $this->escape($value);
            }
        }
        list($code, $response) = $this->execute('ID', array(
            !empty($args) ? '(' . implode(' ', (array) $args) . ')' : $this->escape(null)
        ));
        if ($code == self::ERROR_OK && preg_match('/\* ID /i', $response)) {
            $response = substr($response, 5); // remove prefix "* ID "
            $items    = $this->tokenizeResponse($response);
            $result   = null;
            for ($i=0, $len=count($items); $i<$len; $i += 2) {
                $result[$items[$i]] = $items[$i+1];
            }
            return $result;
        }
        return false;
    }
    function sort($mailbox, $field, $add='', $is_uid=FALSE, $encoding = 'US-ASCII')
    {
        $field = strtoupper($field);
@@ -1298,7 +1363,7 @@
                        $result[$id] = '';
                    }
                } else if ($mode == 2) {
                    if (preg_match('/\((UID|RFC822\.SIZE) ([0-9]+)/', $line, $matches)) {
                    if (preg_match('/(UID|RFC822\.SIZE) ([0-9]+)/', $line, $matches)) {
                        $result[$id] = trim($matches[2]);
                    } else {
                        $result[$id] = 0;
@@ -1494,7 +1559,7 @@
                // INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...)
                // BODY[HEADER.FIELDS ...
                if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/s', $line, $matches)) {
                if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/sU', $line, $matches)) {
                    $str = $matches[1];
                    // swap parents with quotes, then explode
@@ -1531,7 +1596,7 @@
                    // BODYSTRUCTURE
                    if ($bodystr) {
                        while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) {
                        while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/sU', $line, $m)) {
                            $line2 = $this->readLine(1024);
                            $line .= $this->multLine($line2, true);
                        }
@@ -1631,7 +1696,7 @@
                        break;
                        case 'content-type':
                            $ctype_parts = preg_split('/[; ]/', $string);
                            $result[$id]->ctype = array_shift($ctype_parts);
                            $result[$id]->ctype = strtolower(array_shift($ctype_parts));
                            if (preg_match('/charset\s*=\s*"?([a-z0-9\-\.\_]+)"?/i', $string, $regs)) {
                                $result[$id]->charset = $regs[1];
                            }
@@ -3223,21 +3288,7 @@
     */
    private function strToTime($date)
    {
        // support non-standard "GMTXXXX" literal
        $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date);
        // if date parsing fails, we have a date in non-rfc format.
        // remove token from the end and try again
        while ((($ts = @strtotime($date))===false) || ($ts < 0)) {
            $d = explode(' ', $date);
            array_pop($d);
            if (!$d) {
                break;
            }
            $date = implode(' ', $d);
        }
        $ts = (int) $ts;
        $ts = (int) rcube_strtotime($date);
        return $ts < 0 ? 0 : $ts;
    }
@@ -3284,11 +3335,12 @@
        else if ($string === '') {
            return '""';
        }
        // need quoted-string? find special chars: SP, CTL, (, ), {, %, *, ", \, ]
        // plus [ character as a workaround for DBMail's bug (#1487766)
        else if ($force_quotes ||
            preg_match('/([\x00-\x20\x28-\x29\x7B\x25\x2A\x22\x5C\x5D\x7F]+)/', $string)
            preg_match('/([\x00-\x20\x28-\x29\x7B\x25\x2A\x22\x5B\x5C\x5D\x7F]+)/', $string)
        ) {
            // string: special chars: SP, CTL, (, ), {, %, *, ", \, ]
            return '"' . strtr($string, array('"'=>'\\"', '\\' => '\\\\')) . '"';
            return '"' . addcslashes($string, '\\"') . '"';
        }
        // atom
@@ -3297,7 +3349,7 @@
    static function unEscape($string)
    {
        return strtr($string, array('\\"'=>'"', '\\\\' => '\\'));
        return stripslashes($string);
    }
    /**