alecpl
2010-11-05 c0ed783aa1b3fcad7937a8b321756cf87cbe69d0
program/include/rcube_imap_generic.php
@@ -321,7 +321,7 @@
       return self::ERROR_UNKNOWN;
    }
    private function set_error($code, $msg='')
    private function setError($code, $msg='')
    {
        $this->errornum = $code;
        $this->error    = $msg;
@@ -398,12 +398,12 @@
    {
        if ($type == 'CRAM-MD5' || $type == 'DIGEST-MD5') {
            if ($type == 'DIGEST-MD5' && !class_exists('Auth_SASL')) {
                $this->set_error(self::ERROR_BYE,
                $this->setError(self::ERROR_BYE,
                    "The Auth_SASL package is required for DIGEST-MD5 authentication");
             return self::ERROR_BAD;
            }
          $this->putLine($this->next_tag() . " AUTHENTICATE $type");
          $this->putLine($this->nextTag() . " AUTHENTICATE $type");
          $line = trim($this->readLine(1024));
          if ($line[0] == '+') {
@@ -455,7 +455,7 @@
                // send result
                $this->putLine($reply);
                $line = $this->readLine(1024);
                if ($line[0] == '+') {
                 $challenge = substr($line, 2);
                }
@@ -466,7 +466,7 @@
                // check response
                $challenge = base64_decode($challenge);
                if (strpos($challenge, 'rspauth=') === false) {
                    $this->set_error(self::ERROR_BAD,
                    $this->setError(self::ERROR_BAD,
                        "Unexpected response from server to DIGEST-MD5 response");
                    return self::ERROR_BAD;
                }
@@ -495,7 +495,7 @@
                    self::COMMAND_NORESPONSE | self::COMMAND_CAPABILITY);
            }
            else {
              $this->putLine($this->next_tag() . " AUTHENTICATE PLAIN");
              $this->putLine($this->nextTag() . " AUTHENTICATE PLAIN");
              $line = trim($this->readLine(1024));
              if ($line[0] != '+') {
@@ -517,7 +517,7 @@
            return $this->fp;
        }
        else {
            $this->set_error($result, "Unable to authenticate user ($type): $line");
            $this->setError($result, "Unable to authenticate user ($type): $line");
        }
        return $result;
@@ -643,7 +643,7 @@
        if (array_key_exists('namespace', $this->prefs)) {
            return $this->prefs['namespace'];
        }
        if (!$this->getCapability('NAMESPACE')) {
           return self::ERROR_BAD;
       }
@@ -692,15 +692,15 @@
       // check input
       if (empty($host)) {
          $this->set_error(self::ERROR_BAD, "Empty host");
          $this->setError(self::ERROR_BAD, "Empty host");
          return false;
       }
        if (empty($user)) {
          $this->set_error(self::ERROR_NO, "Empty user");
          $this->setError(self::ERROR_NO, "Empty user");
          return false;
       }
       if (empty($password)) {
          $this->set_error(self::ERROR_NO, "Empty password");
          $this->setError(self::ERROR_NO, "Empty password");
          return false;
       }
@@ -719,7 +719,7 @@
           $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr);
       if (!$this->fp) {
          $this->set_error(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr));
          $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr));
          return false;
       }
@@ -739,7 +739,7 @@
          else
             $error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']);
           $this->set_error(self::ERROR_BAD, $error);
           $this->setError(self::ERROR_BAD, $error);
            $this->close();
           return false;
       }
@@ -762,7 +762,7 @@
                }
             if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                $this->set_error(self::ERROR_BAD, "Unable to negotiate TLS");
                $this->setError(self::ERROR_BAD, "Unable to negotiate TLS");
                    $this->close();
                return false;
             }
@@ -794,7 +794,7 @@
        else {
            // Prevent from sending credentials in plain text when connection is not secure
          if ($auth_method == 'LOGIN' && $this->getCapability('LOGINDISABLED')) {
             $this->set_error(self::ERROR_BAD, "Login disabled by IMAP server");
             $this->setError(self::ERROR_BAD, "Login disabled by IMAP server");
                $this->close();
             return false;
            }
@@ -817,7 +817,7 @@
                  $result = $this->login($user, $password);
                break;
            default:
                $this->set_error(self::ERROR_BAD, "Configuration error. Unknown auth method: $method");
                $this->setError(self::ERROR_BAD, "Configuration error. Unknown auth method: $method");
            }
          if (is_resource($result)) {
@@ -849,7 +849,7 @@
    function close()
    {
       if ($this->putLine($this->next_tag() . ' LOGOUT')) {
       if ($this->putLine($this->nextTag() . ' LOGOUT')) {
           $this->readReply();
        }
@@ -900,17 +900,26 @@
     * Executes STATUS comand
     *
     * @param string $mailbox Mailbox name
     * @param array  $items   Requested item names
     * @param array  $items   Additional requested item names. By default
     *                        MESSAGES and UNSEEN are requested. Other defined
     *                        in RFC3501: UIDNEXT, UIDVALIDITY, RECENT
     *
     * @return array Status item-value hash
     * @access public
     * @since 0.5-beta
     */
    function status($mailbox, $items)
    function status($mailbox, $items=array())
    {
       if (empty($mailbox) || empty($items)) {
       if (empty($mailbox)) {
          return false;
       }
        if (!in_array('MESSAGES', $items)) {
            $items[] = 'MESSAGES';
        }
        if (!in_array('UNSEEN', $items)) {
            $items[] = 'UNSEEN';
        }
        list($code, $response) = $this->execute('STATUS', array($this->escape($mailbox),
            '(' . implode(' ', (array) $items) . ')'));
@@ -924,6 +933,8 @@
            for ($i=0, $len=count($items); $i<$len; $i += 2) {
                $result[$items[$i]] = (int) $items[$i+1];
            }
            $this->data['STATUS:'.$mailbox] = $result;
         return $result;
      }
@@ -955,8 +966,14 @@
          return $this->data['EXISTS'];
       }
        // Try STATUS, should be faster
        $counts = $this->status($mailbox, array('MESSAGES'));
        // Check internal cache
        $cache = $this->data['STATUS:'.$mailbox];
        if (!empty($cache) && isset($cache['MESSAGES'])) {
            return (int) $cache['MESSAGES'];
        }
        // Try STATUS (should be faster than SELECT)
        $counts = $this->status($mailbox);
        if (is_array($counts)) {
            return (int) $counts['MESSAGES'];
        }
@@ -974,8 +991,14 @@
     */
    function countUnseen($mailbox)
    {
        // Try STATUS, should be faster
        $counts = $this->status($mailbox, array('UNSEEN'));
        // Check internal cache
        $cache = $this->data['STATUS:'.$mailbox];
        if (!empty($cache) && isset($cache['UNSEEN'])) {
            return (int) $cache['UNSEEN'];
        }
        // Try STATUS (should be faster than SELECT+SEARCH)
        $counts = $this->status($mailbox);
        if (is_array($counts)) {
            return (int) $counts['UNSEEN'];
        }
@@ -1063,7 +1086,7 @@
       }
       // build FETCH command string
       $key     = $this->next_tag();
       $key     = $this->nextTag();
       $cmd     = $uidfetch ? 'UID FETCH' : 'FETCH';
       $deleted = $skip_deleted ? ' FLAGS' : '';
@@ -1084,7 +1107,7 @@
       $request = $key . $request;
       if (!$this->putLine($request)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
          return false;
        }
@@ -1251,7 +1274,7 @@
           return    null;
       }
       if (!$this->select($folder)) {
       if (!$this->select($mailbox)) {
            return null;
        }
@@ -1288,7 +1311,7 @@
          $add = ' '.trim($add);
       /* FETCH uid, size, flags and headers */
       $key       = $this->next_tag();
       $key       = $this->nextTag();
       $request  = $key . ($uidfetch ? ' UID' : '') . " FETCH $message_set ";
       $request .= "(UID RFC822.SIZE FLAGS INTERNALDATE ";
       if ($bodystr)
@@ -1297,11 +1320,11 @@
       $request .= "LIST-POST DISPOSITION-NOTIFICATION-TO".$add.")])";
       if (!$this->putLine($request)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
          return false;
       }
       do {
          $line = $this->readLine(1024);
          $line = $this->readLine(4096);
          $line = $this->multLine($line);
            if (!$line)
@@ -1542,17 +1565,15 @@
       if ($field == 'date' || $field == 'internaldate') {
           $field = 'timestamp';
       }
       if (empty($flag)) {
           $flag = 'ASC';
       } else {
           $flag = strtoupper($flag);
        }
       $stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ','"') : array('"');
       $c = count($a);
       if ($c > 0) {
         // Strategy:
         // First, we'll create an "index" array.
         // Then, we'll use sort() on that array,
@@ -1570,14 +1591,17 @@
             } else {
                $data = $val->$field;
                if (is_string($data)) {
                   $data = strtoupper(str_replace($stripArr, '', $data));
                    $data = str_replace('"', '', $data);
                       if ($field == 'subject') {
                        $data = preg_replace('/^(Re: \s*|Fwd:\s*|Fw:\s*)+/i', '', $data);
                        }
                   $data = strtoupper($data);
                  }
             }
             $index[$key]=$data;
             $index[$key] = $data;
          }
          // sort index
          $i = 0;
          if ($flag == 'ASC') {
             asort($index);
          } else {
@@ -1588,8 +1612,7 @@
          $result = array();
          reset($index);
          while (list($key, $val) = each($index)) {
             $result[$key]=$a[$key];
             $i++;
             $result[$key] = $a[$key];
          }
       }
@@ -1601,6 +1624,9 @@
       if (!$this->select($mailbox)) {
            return false;
        }
        // Clear internal status cache
        unset($this->data['STATUS:'.$mailbox]);
      $result = $this->execute($messages ? 'UID EXPUNGE' : 'EXPUNGE',
          array($messages), self::COMMAND_NORESPONSE);
@@ -1622,6 +1648,11 @@
       if (!$this->select($mailbox)) {
           return false;
       }
        // Clear internal status cache
        if ($flag == 'SEEN') {
            unset($this->data['STATUS:'.$mailbox]['UNSEEN']);
        }
       $flag   = $this->flags[strtoupper($flag)];
        $result = $this->execute('UID STORE', array(
@@ -1653,6 +1684,9 @@
           return false;
       }
        // Clear internal status cache
        unset($this->data['STATUS:'.$to]);
        $result = $this->execute('UID COPY', array(
            $this->compressMessageSet($messages), $this->escape($to)),
            self::COMMAND_NORESPONSE);
@@ -1669,6 +1703,9 @@
        $r = $this->copy($messages, $from, $to);
        if ($r) {
            // Clear internal status cache
            unset($this->data['STATUS:'.$from]);
            return $this->delete($from, $messages);
        }
        return $r;
@@ -1725,16 +1762,16 @@
       return $node;
    }
    function thread($folder, $algorithm='REFERENCES', $criteria='', $encoding='US-ASCII')
    function thread($mailbox, $algorithm='REFERENCES', $criteria='', $encoding='US-ASCII')
    {
        $old_sel = $this->selected;
       if (!$this->select($folder)) {
       if (!$this->select($mailbox)) {
          return false;
       }
        // return empty result when folder is empty and we're just after SELECT
        if ($old_sel != $folder && !$this->data['EXISTS']) {
        if ($old_sel != $mailbox && !$this->data['EXISTS']) {
            return array(array(), array(), array());
       }
@@ -1811,7 +1848,7 @@
           $response = str_replace("\r\n", '', $response);
            if ($esearch) {
                // Skip prefix: ... (TAG "A285") UID ...
                // Skip prefix: ... (TAG "A285") UID ...
                $this->tokenizeResponse($response, $return_uid ? 2 : 1);
                $result = array();
@@ -1840,7 +1877,7 @@
                    if (in_array('ALL', $items))
                        $result['ALL'] = $this->compressMessageSet($response, true);
                    return $result;
                    return $result;
                }
                else {
                    return $response;
@@ -1936,32 +1973,32 @@
                $cmd = strtoupper($this->tokenizeResponse($response, 1));
                // * LIST (<options>) <delimiter> <mailbox>
                if (!$lstatus || $cmd == 'LIST' || $cmd == 'LSUB') {
                    list($opts, $delim, $folder) = $this->tokenizeResponse($response, 3);
                    list($opts, $delim, $mailbox) = $this->tokenizeResponse($response, 3);
                    // Add to result array
                    if (!$lstatus) {
                        $folders[] = $folder;
                        $folders[] = $mailbox;
                    }
                    else {
                        $folders[$folder] = array();
                        $folders[$mailbox] = array();
                    }
                    // Add to options array
                    if (!empty($opts)) {
                        if (empty($this->data['LIST'][$folder]))
                            $this->data['LIST'][$folder] = $opts;
                        if (empty($this->data['LIST'][$mailbox]))
                            $this->data['LIST'][$mailbox] = $opts;
                        else
                            $this->data['LIST'][$folder] = array_unique(array_merge(
                                $this->data['LIST'][$folder], $opts));
                            $this->data['LIST'][$mailbox] = array_unique(array_merge(
                                $this->data['LIST'][$mailbox], $opts));
                    }
                }
                // * STATUS <mailbox> (<result>)
                else if ($cmd == 'STATUS') {
                    list($folder, $status) = $this->tokenizeResponse($response, 2);
                    list($mailbox, $status) = $this->tokenizeResponse($response, 2);
                    for ($i=0, $len=count($status); $i<$len; $i += 2) {
                        list($name, $value) = $this->tokenizeResponse($status, 2);
                        $folders[$folder][$name] = $value;
                        $folders[$mailbox][$name] = $value;
                    }
                }
          }
@@ -1980,7 +2017,7 @@
       $result = false;
       $parts  = (array) $parts;
       $key    = $this->next_tag();
       $key    = $this->nextTag();
       $peeks  = '';
       $idx    = 0;
        $type   = $mime ? 'MIME' : 'HEADER';
@@ -1993,7 +2030,7 @@
       // send request
       if (!$this->putLine($request)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
           return false;
       }
@@ -2044,12 +2081,12 @@
       // format request
         $reply_key = '* ' . $id;
      $key       = $this->next_tag();
      $key       = $this->nextTag();
      $request   = $key . ($is_uid ? ' UID' : '') . " FETCH $id (BODY.PEEK[$part])";
       // send request
      if (!$this->putLine($request)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
          return false;
         }
@@ -2173,9 +2210,9 @@
       return false;
    }
    function createFolder($folder)
    function createFolder($mailbox)
    {
        $result = $this->execute('CREATE', array($this->escape($folder)),
        $result = $this->execute('CREATE', array($this->escape($mailbox)),
           self::COMMAND_NORESPONSE);
       return ($result == self::ERROR_OK);
@@ -2189,42 +2226,42 @@
      return ($result == self::ERROR_OK);
    }
    function deleteFolder($folder)
    function deleteFolder($mailbox)
    {
        $result = $this->execute('DELETE', array($this->escape($folder)),
        $result = $this->execute('DELETE', array($this->escape($mailbox)),
           self::COMMAND_NORESPONSE);
       return ($result == self::ERROR_OK);
    }
    function clearFolder($folder)
    function clearFolder($mailbox)
    {
       $num_in_trash = $this->countMessages($folder);
       $num_in_trash = $this->countMessages($mailbox);
       if ($num_in_trash > 0) {
          $this->delete($folder, '1:*');
          $this->delete($mailbox, '1:*');
       }
       return ($this->expunge($folder) >= 0);
       return ($this->expunge($mailbox) >= 0);
    }
    function subscribe($folder)
    function subscribe($mailbox)
    {
       $result = $this->execute('SUBSCRIBE', array($this->escape($folder)),
       $result = $this->execute('SUBSCRIBE', array($this->escape($mailbox)),
           self::COMMAND_NORESPONSE);
       return ($result == self::ERROR_OK);
    }
    function unsubscribe($folder)
    function unsubscribe($mailbox)
    {
       $result = $this->execute('UNSUBSCRIBE', array($this->escape($folder)),
       $result = $this->execute('UNSUBSCRIBE', array($this->escape($mailbox)),
           self::COMMAND_NORESPONSE);
       return ($result == self::ERROR_OK);
    }
    function append($folder, &$message)
    function append($mailbox, &$message)
    {
       if (!$folder) {
       if (!$mailbox) {
          return false;
       }
@@ -2236,8 +2273,8 @@
          return false;
       }
        $key = $this->next_tag();
       $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($folder),
        $key = $this->nextTag();
       $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($mailbox),
            $len, ($this->prefs['literal+'] ? '+' : ''));
       if ($this->putLine($request)) {
@@ -2259,18 +2296,21 @@
             $line = $this->readLine();
          } while (!$this->startsWith($line, $key, true, true));
            // Clear internal status cache
            unset($this->data['STATUS:'.$mailbox]);
          return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK);
       }
        else {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
        }
       return false;
    }
    function appendFromFile($folder, $path, $headers=null)
    function appendFromFile($mailbox, $path, $headers=null)
    {
       if (!$folder) {
       if (!$mailbox) {
           return false;
       }
@@ -2280,7 +2320,7 @@
          $in_fp = fopen($path, 'r');
       }
       if (!$in_fp) {
          $this->set_error(self::ERROR_UNKNOWN, "Couldn't open $path for reading");
          $this->setError(self::ERROR_UNKNOWN, "Couldn't open $path for reading");
          return false;
       }
@@ -2297,8 +2337,8 @@
        }
       // send APPEND command
       $key = $this->next_tag();
       $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($folder),
       $key = $this->nextTag();
       $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($mailbox),
            $len, ($this->prefs['literal+'] ? '+' : ''));
       if ($this->putLine($request)) {
@@ -2333,23 +2373,25 @@
             $line = $this->readLine();
          } while (!$this->startsWith($line, $key, true, true));
            // Clear internal status cache
            unset($this->data['STATUS:'.$mailbox]);
          return ($this->parseResult($line, 'APPEND: ') == self::ERROR_OK);
       }
        else {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $request");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $request");
        }
       return false;
    }
    function fetchStructureString($folder, $id, $is_uid=false)
    function fetchStructureString($mailbox, $id, $is_uid=false)
    {
       if (!$this->select($folder)) {
       if (!$this->select($mailbox)) {
            return false;
        }
      $key = $this->next_tag();
      $key = $this->nextTag();
       $result = false;
        $command = $key . ($is_uid ? ' UID' : '') ." FETCH $id (BODYSTRUCTURE)";
@@ -2364,7 +2406,7 @@
         $result = trim(substr($result, strpos($result, 'BODYSTRUCTURE')+13, -1));
      }
        else {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $command");
        }
       return $result;
@@ -2380,7 +2422,7 @@
         */
       $result      = false;
       $quota_lines = array();
       $key         = $this->next_tag();
       $key         = $this->nextTag();
        $command     = $key . ' GETQUOTAROOT INBOX';
       // get line(s) containing quota info
@@ -2393,7 +2435,7 @@
          } while (!$this->startsWith($line, $key, true, true));
       }
        else {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $command");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $command");
        }
       // return false if not found, parse if found
@@ -2501,7 +2543,7 @@
                return $ret;
            }
            $this->set_error(self::ERROR_COMMAND, "Incomplete ACL response");
            $this->setError(self::ERROR_COMMAND, "Incomplete ACL response");
            return NULL;
        }
@@ -2580,7 +2622,7 @@
    function setMetadata($mailbox, $entries)
    {
        if (!is_array($entries) || empty($entries)) {
            $this->set_error(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command");
            $this->setError(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command");
            return false;
        }
@@ -2618,7 +2660,7 @@
            $entries = explode(' ', $entries);
        if (empty($entries)) {
            $this->set_error(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command");
            $this->setError(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command");
            return false;
        }
@@ -2723,7 +2765,7 @@
    function setAnnotation($mailbox, $data)
    {
        if (!is_array($data) || empty($data)) {
            $this->set_error(self::ERROR_COMMAND, "Wrong argument for SETANNOTATION command");
            $this->setError(self::ERROR_COMMAND, "Wrong argument for SETANNOTATION command");
            return false;
        }
@@ -2763,7 +2805,7 @@
    function deleteAnnotation($mailbox, $data)
    {
        if (!is_array($data) || empty($data)) {
            $this->set_error(self::ERROR_COMMAND, "Wrong argument for SETANNOTATION command");
            $this->setError(self::ERROR_COMMAND, "Wrong argument for SETANNOTATION command");
            return false;
        }
@@ -2852,7 +2894,7 @@
     * @access public
     * @since 0.5-beta
     */
    function next_tag()
    function nextTag()
    {
        $this->cmd_num++;
        $this->cmd_tag = sprintf('A%04d', $this->cmd_num);
@@ -2873,7 +2915,7 @@
     */
    function execute($command, $arguments=array(), $options=0)
    {
        $tag      = $this->next_tag();
        $tag      = $this->nextTag();
        $query    = $tag . ' ' . $command;
        $noresp   = ($options & self::COMMAND_NORESPONSE);
        $response = $noresp ? null : '';
@@ -2883,7 +2925,7 @@
        // Send command
       if (!$this->putLineC($query)) {
            $this->set_error(self::ERROR_COMMAND, "Unable to send command: $query");
            $this->setError(self::ERROR_COMMAND, "Unable to send command: $query");
          return $noresp ? self::ERROR_COMMAND : array(self::ERROR_COMMAND, '');
       }
@@ -3036,7 +3078,7 @@
       return $ts < 0 ? 0 : $ts;
    }
    private function SplitHeaderLine($string)
    private function splitHeaderLine($string)
    {
       $pos = strpos($string, ':');
       if ($pos>0) {