thomascube
2011-01-29 6039aae3878aa5880415290cbc41af4bac4fdcb5
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:                                                              |
@@ -371,10 +371,43 @@
        return false;
    }
    function getCapability($name)
    private function hasCapability($name)
    {
        if (empty($this->capability) || $name == '') {
            return false;
        }
        if (in_array($name, $this->capability)) {
            return true;
        }
        else if (strpos($name, '=')) {
            return false;
        }
        $result = array();
        foreach ($this->capability as $cap) {
            $entry = explode('=', $cap);
            if ($entry[0] == $name) {
                $result[] = $entry[1];
            }
        }
        return !empty($result) ? $result : false;
    }
    /**
     * Capabilities checker
     *
     * @param string $name Capability name
     *
     * @return mixed Capability values array for key=value pairs, true/false for others
     */
    function getCapability($name)
    {
        $result = $this->hasCapability($name);
        if (!empty($result)) {
            return $result;
        }
        else if ($this->capability_readed) {
            return false;
@@ -390,11 +423,7 @@
        $this->capability_readed = true;
        if (in_array($name, $this->capability)) {
            return true;
        }
        return false;
        return $this->hasCapability($name);
    }
    function clearCapability()
@@ -735,17 +764,17 @@
        // check for supported auth methods
        if ($auth_method == 'CHECK') {
            if ($this->getCapability('AUTH=DIGEST-MD5')) {
                $auth_methods[] = 'DIGEST-MD5';
            }
            if ($this->getCapability('AUTH=CRAM-MD5') || $this->getCapability('AUTH=CRAM_MD5')) {
                $auth_methods[] = 'CRAM-MD5';
            }
            if ($this->getCapability('AUTH=PLAIN')) {
                $auth_methods[] = 'PLAIN';
            if ($auth_caps = $this->getCapability('AUTH')) {
                $auth_methods = $auth_caps;
            }
            // RFC 2595 (LOGINDISABLED) LOGIN disabled when connection is not secure
            if (!$this->getCapability('LOGINDISABLED')) {
            $login_disabled = $this->getCapability('LOGINDISABLED');
            if (($key = array_search('LOGIN', $auth_methods)) !== false) {
                if ($login_disabled) {
                    unset($auth_methods[$key]);
                }
            }
            else if (!$login_disabled) {
                $auth_methods[] = 'LOGIN';
            }
        }
@@ -766,8 +795,10 @@
        // Authenticate
        foreach ($auth_methods as $method) {
            switch ($method) {
            case 'DIGEST-MD5':
            case 'CRAM_MD5':
                $method = 'CRAM-MD5';
            case 'CRAM-MD5':
            case 'DIGEST-MD5':
            case 'PLAIN':
                $result = $this->authenticate($user, $password, $method);
                break;
@@ -2606,13 +2637,13 @@
     */
    function getACL($mailbox)
    {
        list($code, $response) = $this->execute('GETACL', $this->escape($mailbox));
        list($code, $response) = $this->execute('GETACL', array($this->escape($mailbox)));
        if ($code == self::ERROR_OK && preg_match('/^\* ACL /i', $response)) {
            // Parse server response (remove "* ACL ")
            $response = substr($response, 6);
            $ret  = $this->tokenizeResponse($response);
            $mbox = array_unshift($ret);
            $mbox = array_shift($ret);
            $size = count($ret);
            // Create user-rights hash array
@@ -2679,7 +2710,7 @@
     */
    function myRights($mailbox)
    {
        list($code, $response) = $this->execute('MYRIGHTS', array($this->escape(mailbox)));
        list($code, $response) = $this->execute('MYRIGHTS', array($this->escape($mailbox)));
        if ($code == self::ERROR_OK && preg_match('/^\* MYRIGHTS /i', $response)) {
            // Parse server response (remove "* MYRIGHTS ")
@@ -2806,37 +2837,46 @@
        list($code, $response) = $this->execute('GETMETADATA', array(
            $this->escape($mailbox), $optlist));
        if ($code == self::ERROR_OK && preg_match('/^\* METADATA /i', $response)) {
            // Parse server response (remove "* METADATA ")
            $response = substr($response, 11);
            $ret_mbox = $this->tokenizeResponse($response, 1);
            $data     = $this->tokenizeResponse($response);
        if ($code == self::ERROR_OK) {
            $result = array();
            $data   = $this->tokenizeResponse($response);
            // The METADATA response can contain multiple entries in a single
            // response or multiple responses for each entry or group of entries
            if (!empty($data) && ($size = count($data))) {
                for ($i=0; $i<$size; $i++) {
                    if (is_array($data[$i])) {
                    if (isset($mbox) && is_array($data[$i])) {
                        $size_sub = count($data[$i]);
                        for ($x=0; $x<$size_sub; $x++) {
                            $data[$data[$i][$x]] = $data[$i][++$x];
                            $result[$mbox][$data[$i][$x]] = $data[$i][++$x];
                        }
                        unset($data[$i]);
                    }
                    else if ($data[$i] == '*' && $data[$i+1] == 'METADATA') {
                        unset($data[$i]);   // "*"
                        unset($data[++$i]); // "METADATA"
                        unset($data[++$i]); // Mailbox
                    else if ($data[$i] == '*') {
                        if ($data[$i+1] == 'METADATA') {
                            $mbox = $data[$i+2];
                            unset($data[$i]);   // "*"
                            unset($data[++$i]); // "METADATA"
                            unset($data[++$i]); // Mailbox
                        }
                        // get rid of other untagged responses
                        else {
                            unset($mbox);
                            unset($data[$i]);
                        }
                    }
                    else {
                        $data[$data[$i]] = $data[++$i];
                    else if (isset($mbox)) {
                        $result[$mbox][$data[$i]] = $data[++$i];
                        unset($data[$i]);
                        unset($data[$i-1]);
                    }
                    else {
                        unset($data[$i]);
                    }
                }
            }
            return $data;
            return $result;
        }
        return NULL;
@@ -2872,8 +2912,9 @@
                $value = sprintf("{%d}\r\n%s", strlen($value), $value);
            }
            // ANNOTATEMORE drafts before version 08 require quoted parameters
            $entries[] = sprintf('%s (%s %s)',
                $this->escape($name), $this->escape($attr), $value);
                $this->escape($name, true), $this->escape($attr, true), $value);
        }
        $entries = implode(' ', $entries);
@@ -2923,8 +2964,9 @@
            $entries = array($entries);
        }
        // create entries string
        // ANNOTATEMORE drafts before version 08 require quoted parameters
        foreach ($entries as $idx => $name) {
            $entries[$idx] = $this->escape($name);
            $entries[$idx] = $this->escape($name, true);
        }
        $entries = '(' . implode(' ', $entries) . ')';
@@ -2933,50 +2975,65 @@
        }
        // create entries string
        foreach ($attribs as $idx => $name) {
            $attribs[$idx] = $this->escape($name);
            $attribs[$idx] = $this->escape($name, true);
        }
        $attribs = '(' . implode(' ', $attribs) . ')';
        list($code, $response) = $this->execute('GETANNOTATION', array(
            $this->escape($mailbox), $entries, $attribs));
        if ($code == self::ERROR_OK && preg_match('/^\* ANNOTATION /i', $response)) {
            // Parse server response (remove "* ANNOTATION ")
            $response = substr($response, 13);
            $ret_mbox = $this->tokenizeResponse($response, 1);
            $data     = $this->tokenizeResponse($response);
            $res      = array();
        if ($code == self::ERROR_OK) {
            $result = array();
            $data   = $this->tokenizeResponse($response);
            // Here we returns only data compatible with METADATA result format
            if (!empty($data) && ($size = count($data))) {
                for ($i=0; $i<$size; $i++) {
                    $entry = $data[$i++];
                    if (is_array($entry)) {
                    $entry = $data[$i];
                    if (isset($mbox) && is_array($entry)) {
                        $attribs = $entry;
                        $entry   = $last_entry;
                    }
                    else
                        $attribs = $data[$i++];
                    else if ($entry == '*') {
                        if ($data[$i+1] == 'ANNOTATION') {
                            $mbox = $data[$i+2];
                            unset($data[$i]);   // "*"
                            unset($data[++$i]); // "ANNOTATION"
                            unset($data[++$i]); // Mailbox
                        }
                        // get rid of other untagged responses
                        else {
                            unset($mbox);
                            unset($data[$i]);
                        }
                        continue;
                    }
                    else if (isset($mbox)) {
                        $attribs = $data[++$i];
                    }
                    else {
                        unset($data[$i]);
                        continue;
                    }
                    if (!empty($attribs)) {
                        for ($x=0, $len=count($attribs); $x<$len;) {
                            $attr  = $attribs[$x++];
                            $value = $attribs[$x++];
                            if ($attr == 'value.priv') {
                                $res['/private' . $entry] = $value;
                                $result[$mbox]['/private' . $entry] = $value;
                            }
                            else if ($attr == 'value.shared') {
                                $res['/shared' . $entry] = $value;
                                $result[$mbox]['/shared' . $entry] = $value;
                            }
                        }
                    }
                    $last_entry = $entry;
                    unset($data[$i-1]);
                    unset($data[$i-2]);
                    unset($data[$i]);
                }
            }
            return $res;
            return $result;
        }
        return NULL;
@@ -3166,21 +3223,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;
    }
@@ -3213,12 +3256,13 @@
    /**
     * Escapes a string when it contains special characters (RFC3501)
     *
     * @param string $string IMAP string
     * @param string  $string       IMAP string
     * @param boolean $force_quotes Forces string quoting
     *
     * @return string Escaped string
     * @todo String literals, lists
     */
    static function escape($string)
    static function escape($string, $force_quotes=false)
    {
        if ($string === null) {
            return 'NIL';
@@ -3226,7 +3270,9 @@
        else if ($string === '') {
            return '""';
        }
        else if (preg_match('/([\x00-\x20\x28-\x29\x7B\x25\x2A\x22\x5C\x5D\x7F]+)/', $string)) {
        else if ($force_quotes ||
            preg_match('/([\x00-\x20\x28-\x29\x7B\x25\x2A\x22\x5C\x5D\x7F]+)/', $string)
        ) {
            // string: special chars: SP, CTL, (, ), {, %, *, ", \, ]
            return '"' . strtr($string, array('"'=>'\\"', '\\' => '\\\\')) . '"';
        }