alecpl
2011-12-01 14b342b03aaedadb67244149e7dea3210c6ac0ed
program/include/rcube_imap_generic.php
@@ -6,6 +6,7 @@
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2005-2010, The Roundcube Dev Team                       |
 | Copyright (C) 2011, Kolab Systems AG                                  |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | PURPOSE:                                                              |
@@ -54,15 +55,8 @@
    public $references;
    public $priority;
    public $mdn_to;
    public $flags;
    public $mdnsent = false;
    public $seen = false;
    public $deleted = false;
    public $answered = false;
    public $forwarded = false;
    public $flagged = false;
    public $others = array();
    public $flags = array();
}
// For backward compatibility with cached messages (#1486602)
@@ -316,6 +310,10 @@
                }
                else {
                    $this->resultcode = null;
                    // parse response for [APPENDUID 1204196876 3456]
                    if (preg_match("/^\[APPENDUID [0-9]+ ([0-9,:*]+)\]/i", $str, $m)) {
                        $this->data['APPENDUID'] = $m[1];
                    }
                }
                $this->result = $str;
@@ -678,8 +676,8 @@
            $this->prefs = $options;
        }
        // set auth method
        if (!empty($this->prefs['auth_method'])) {
            $auth_method = strtoupper($this->prefs['auth_method']);
        if (!empty($this->prefs['auth_type'])) {
            $auth_method = strtoupper($this->prefs['auth_type']);
        } else {
            $auth_method = 'CHECK';
        }
@@ -689,7 +687,7 @@
        // initialize connection
        $this->error    = '';
        $this->errornum = self::ERROR_OK;
        $this->selected = '';
        $this->selected = null;
        $this->user     = $user;
        $this->host     = $host;
        $this->logged   = false;
@@ -886,7 +884,7 @@
            return false;
        }
        if ($this->selected == $mailbox) {
        if ($this->selected === $mailbox) {
            return true;
        }
/*
@@ -1049,7 +1047,7 @@
            $result = $this->execute('EXPUNGE', null, self::COMMAND_NORESPONSE);
        if ($result == self::ERROR_OK) {
            $this->selected = ''; // state has changed, need to reselect
            $this->selected = null; // state has changed, need to reselect
            return true;
        }
@@ -1067,7 +1065,7 @@
        $result = $this->execute('CLOSE', NULL, self::COMMAND_NORESPONSE);
        if ($result == self::ERROR_OK) {
            $this->selected = '';
            $this->selected = null;
            return true;
        }
@@ -1134,7 +1132,7 @@
        }
        if ($res) {
            if ($this->selected == $mailbox)
            if ($this->selected === $mailbox)
                $res = $this->close();
            else
                $res = $this->expunge($mailbox);
@@ -1153,10 +1151,10 @@
    function countMessages($mailbox, $refresh = false)
    {
        if ($refresh) {
            $this->selected = '';
            $this->selected = null;
        }
        if ($this->selected == $mailbox) {
        if ($this->selected === $mailbox) {
            return $this->data['EXISTS'];
        }
@@ -1190,7 +1188,7 @@
        $this->select($mailbox);
        if ($this->selected == $mailbox) {
        if ($this->selected === $mailbox) {
            return $this->data['RECENT'];
        }
@@ -1676,31 +1674,10 @@
                    else if ($name == 'FLAGS') {
                        if (!empty($value)) {
                            foreach ((array)$value as $flag) {
                                $flag = str_replace('\\', '', $flag);
                                $flag = str_replace(array('$', '\\'), '', $flag);
                                $flag = strtoupper($flag);
                                switch (strtoupper($flag)) {
                                case 'SEEN':
                                    $result[$id]->seen = true;
                                    break;
                                case 'DELETED':
                                    $result[$id]->deleted = true;
                                    break;
                                case 'ANSWERED':
                                    $result[$id]->answered = true;
                                    break;
                                case '$FORWARDED':
                                    $result[$id]->forwarded = true;
                                    break;
                                case '$MDNSENT':
                                    $result[$id]->mdnsent = true;
                                    break;
                                case 'FLAGGED':
                                    $result[$id]->flagged = true;
                                    break;
                                default:
                                    $result[$id]->flags[] = $flag;
                                    break;
                                }
                                $result[$id]->flags[$flag] = true;
                            }
                        }
                    }
@@ -1812,7 +1789,7 @@
            // VANISHED response (QRESYNC RFC5162)
            // Sample: * VANISHED (EARLIER) 300:310,405,411
            else if (preg_match('/^\* VANISHED [EARLIER]*/i', $line, $match)) {
            else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) {
                $line   = substr($line, strlen($match[0]));
                $v_data = $this->tokenizeResponse($line, 1);
@@ -2265,12 +2242,29 @@
        list($code, $response) = $this->execute($subscribed ? 'LSUB' : 'LIST', $args);
        if ($code == self::ERROR_OK) {
            $folders = array();
            while ($this->tokenizeResponse($response, 1) == '*') {
                $cmd = strtoupper($this->tokenizeResponse($response, 1));
            $folders  = array();
            $last     = 0;
            $pos      = 0;
            $response .= "\r\n";
            while ($pos = strpos($response, "\r\n", $pos+1)) {
                // literal string, not real end-of-command-line
                if ($response[$pos-1] == '}') {
                    continue;
                }
                $line = substr($response, $last, $pos - $last);
                $last = $pos + 2;
                if (!preg_match('/^\* (LIST|LSUB|STATUS) /i', $line, $m)) {
                    continue;
                }
                $cmd  = strtoupper($m[1]);
                $line = substr($line, strlen($m[0]));
                // * LIST (<options>) <delimiter> <mailbox>
                if ($cmd == 'LIST' || $cmd == 'LSUB') {
                    list($opts, $delim, $mailbox) = $this->tokenizeResponse($response, 3);
                    list($opts, $delim, $mailbox) = $this->tokenizeResponse($line, 3);
                    // Add to result array
                    if (!$lstatus) {
@@ -2281,30 +2275,20 @@
                    }
                    // Add to options array
                    if (!empty($opts)) {
                        if (empty($this->data['LIST'][$mailbox]))
                            $this->data['LIST'][$mailbox] = $opts;
                        else
                            $this->data['LIST'][$mailbox] = array_unique(array_merge(
                                $this->data['LIST'][$mailbox], $opts));
                    }
                    if (empty($this->data['LIST'][$mailbox]))
                        $this->data['LIST'][$mailbox] = $opts;
                    else if (!empty($opts))
                        $this->data['LIST'][$mailbox] = array_unique(array_merge(
                            $this->data['LIST'][$mailbox], $opts));
                }
                // * STATUS <mailbox> (<result>)
                else if ($cmd == 'STATUS') {
                    list($mailbox, $status) = $this->tokenizeResponse($response, 2);
                    list($mailbox, $status) = $this->tokenizeResponse($line, 2);
                    for ($i=0, $len=count($status); $i<$len; $i += 2) {
                        list($name, $value) = $this->tokenizeResponse($status, 2);
                        $folders[$mailbox][$name] = $value;
                    }
                }
                // other untagged response line, skip it
                else {
                    $response = ltrim($response);
                    if (($position = strpos($response, "\n")) !== false)
                        $response = substr($response, $position+1);
                    else
                        $response = '';
                }
            }
@@ -2323,12 +2307,11 @@
        $result = false;
        $parts  = (array) $parts;
        $key    = $this->nextTag();
        $peeks  = '';
        $idx    = 0;
        $peeks  = array();
        $type   = $mime ? 'MIME' : 'HEADER';
        // format request
        foreach($parts as $part) {
        foreach ($parts as $part) {
            $peeks[] = "BODY.PEEK[$part.$type]";
        }
@@ -2342,13 +2325,25 @@
        do {
            $line = $this->readLine(1024);
            $line = $this->multLine($line);
            if (preg_match('/BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) {
                $idx = $matches[1];
                $result[$idx] = preg_replace('/^(\* [0-9]+ FETCH \()?\s*BODY\['.$idx.'\.'.$type.'\]\s+/', '', $line);
                $result[$idx] = trim($result[$idx], '"');
                $result[$idx] = rtrim($result[$idx], "\t\r\n\0\x0B");
            if (preg_match('/^\* [0-9]+ FETCH [0-9UID( ]+BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) {
                $idx     = $matches[1];
                $headers = '';
                // get complete entry
                if (preg_match('/\{([0-9]+)\}\r\n$/', $line, $m)) {
                    $bytes = $m[1];
                    $out   = '';
                    while (strlen($out) < $bytes) {
                        $out = $this->readBytes($bytes);
                        if ($out === null)
                            break;
                        $headers .= $out;
                    }
                }
                $result[$idx] = trim($headers);
            }
        } while (!$this->startsWith($line, $key, true));
@@ -2405,8 +2400,10 @@
        $len    = strlen($line);
        $result = false;
        if ($a[2] != 'FETCH') {
        }
        // handle empty "* X FETCH ()" response
        if ($line[$len-1] == ')' && $line[$len-2] != '(') {
        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
@@ -2525,8 +2522,18 @@
        return ($result == self::ERROR_OK);
    }
    /**
     * Handler for IMAP APPEND command
     *
     * @param string $mailbox Mailbox name
     * @param string $message Message content
     *
     * @return string|bool On success APPENDUID response (if available) or True, False on failure
     */
    function append($mailbox, &$message)
    {
        unset($this->data['APPENDUID']);
        if (!$mailbox) {
            return false;
        }
@@ -2565,7 +2572,12 @@
            // Clear internal status cache
            unset($this->data['STATUS:'.$mailbox]);
            return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK);
            if ($this->parseResult($line, 'APPEND: ') != self::ERROR_OK)
                return false;
            else if (!empty($this->data['APPENDUID']))
                return $this->data['APPENDUID'];
            else
                return true;
        }
        else {
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
@@ -2574,8 +2586,19 @@
        return false;
    }
    /**
     * Handler for IMAP APPEND command.
     *
     * @param string $mailbox Mailbox name
     * @param string $path    Path to the file with message body
     * @param string $headers Message headers
     *
     * @return string|bool On success APPENDUID response (if available) or True, False on failure
     */
    function appendFromFile($mailbox, $path, $headers=null)
    {
        unset($this->data['APPENDUID']);
        if (!$mailbox) {
            return false;
        }
@@ -2642,7 +2665,12 @@
            // Clear internal status cache
            unset($this->data['STATUS:'.$mailbox]);
            return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK);
            if ($this->parseResult($line, 'APPEND: ') != self::ERROR_OK)
                return false;
            else if (!empty($this->data['APPENDUID']))
                return $this->data['APPENDUID'];
            else
                return true;
        }
        else {
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
@@ -3155,47 +3183,48 @@
        return false;
    }
    static function getStructurePartType($structure, $part)
    /**
     * Returns data of a message part according to specified structure.
     *
     * @param array  $structure Message structure (getStructure() result)
     * @param string $part      Message part identifier
     *
     * @return array Part data as hash array (type, encoding, charset, size)
     */
    static function getStructurePartData($structure, $part)
    {
       $part_a = self::getStructurePartArray($structure, $part);
       if (!empty($part_a)) {
          if (is_array($part_a[0]))
                return 'multipart';
          else if ($part_a[0])
                return $part_a[0];
       }
       $data   = array();
        return 'other';
    }
       if (empty($part_a)) {
            return $data;
        }
    static function getStructurePartEncoding($structure, $part)
    {
       $part_a = self::getStructurePartArray($structure, $part);
       if ($part_a) {
          if (!is_array($part_a[0]))
                return $part_a[5];
       }
        // content-type
        if (is_array($part_a[0])) {
            $data['type'] = 'multipart';
        }
        else {
            $data['type'] = strtolower($part_a[0]);
        return '';
    }
            // encoding
            $data['encoding'] = strtolower($part_a[5]);
    static function getStructurePartCharset($structure, $part)
    {
       $part_a = self::getStructurePartArray($structure, $part);
       if ($part_a) {
          if (is_array($part_a[0]))
                return '';
          else {
             if (is_array($part_a[2])) {
                $name = '';
                while (list($key, $val) = each($part_a[2]))
                        if (strcasecmp($val, 'charset') == 0)
                            return $part_a[2][$key+1];
             }
          }
       }
            // charset
            if (is_array($part_a[2])) {
               while (list($key, $val) = each($part_a[2])) {
                    if (strcasecmp($val, 'charset') == 0) {
                        $data['charset'] = $part_a[2][$key+1];
                        break;
                    }
                }
            }
        }
        return '';
        // size
        $data['size'] = intval($part_a[6]);
        return $data;
    }
    static function getStructurePartArray($a, $part)
@@ -3227,7 +3256,6 @@
          return $a;
       }
    }
    /**
     * Creates next command identifier (tag)
@@ -3371,14 +3399,9 @@
            // String atom, number, NIL, *, %
            default:
                // empty or one character
                if ($str === '') {
                // empty string
                if ($str === '' || $str === null) {
                    break 2;
                }
                if (strlen($str) < 2) {
                    $result[] = $str;
                    $str = '';
                    break;
                }
                // excluded chars: SP, CTL, ), [, ]