From ab0b51a1fef87bcc643c3aaf2e635c811b28ccd8 Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Tue, 15 Feb 2011 06:10:59 -0500
Subject: [PATCH] - Use only one from IMAP authentication methods to prevent login delays (1487784)

---
 program/include/rcube_imap.php |  226 ++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 163 insertions(+), 63 deletions(-)

diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 5aa23fa..f5a9368 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -5,7 +5,7 @@
  | program/include/rcube_imap.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:                                                              |
@@ -148,6 +148,18 @@
 
         $this->options['port'] = $port;
 
+        if ($this->options['debug']) {
+            $this->conn->setDebug(true, array($this, 'debug_handler'));
+
+            $this->options['ident'] = array(
+                'name' => 'Roundcube Webmail',
+                'version' => RCMAIL_VERSION,
+                'php' => PHP_VERSION,
+                'os' => PHP_OS,
+                'command' => $_SERVER['REQUEST_URI'],
+            );
+        }
+
         $attempt = 0;
         do {
             $data = rcmail::get_instance()->plugins->exec_hook('imap_connect',
@@ -223,7 +235,7 @@
      */
     function get_error_code()
     {
-        return ($this->conn) ? $this->conn->errornum : 0;
+        return $this->conn->errornum;
     }
 
 
@@ -234,7 +246,7 @@
      */
     function get_error_str()
     {
-        return ($this->conn) ? $this->conn->error : null;
+        return $this->conn->error;
     }
 
 
@@ -245,9 +257,6 @@
      */
     function get_response_code()
     {
-        if (!$this->conn)
-            return self::UNKNOWN;
-
         switch ($this->conn->resultcode) {
             case 'NOPERM':
                 return self::NOPERM;
@@ -278,7 +287,7 @@
      */
     function get_response_str()
     {
-        return ($this->conn) ? $this->conn->result : null;
+        return $this->conn->result;
     }
 
 
@@ -470,12 +479,12 @@
     {
         $this->threading = false;
 
-        if ($enable) {
-            if ($this->get_capability('THREAD=REFS'))
+        if ($enable && ($caps = $this->get_capability('THREAD'))) {
+            if (in_array('REFS', $caps))
                 $this->threading = 'REFS';
-            else if ($this->get_capability('THREAD=REFERENCES'))
+            else if (in_array('REFERENCES', $caps))
                 $this->threading = 'REFERENCES';
-            else if ($this->get_capability('THREAD=ORDEREDSUBJECT'))
+            else if (in_array('ORDEREDSUBJECT', $caps))
                 $this->threading = 'ORDEREDSUBJECT';
         }
 
@@ -546,56 +555,56 @@
         $imap_shared    = $config->get('imap_ns_shared');
         $imap_delimiter = $config->get('imap_delimiter');
 
-        if ($imap_delimiter) {
-            $this->delimiter = $imap_delimiter;
-        }
-
-        if (!$this->conn)
+        if (!$this->conn->connected())
             return;
 
         $ns = $this->conn->getNamespace();
 
-        // NAMESPACE supported
+        // Set namespaces (NAMESPACE supported)
         if (is_array($ns)) {
             $this->namespace = $ns;
-
-            if (empty($this->delimiter))
-                $this->delimiter = $ns['personal'][0][1];
-            if (empty($this->delimiter))
-                $this->delimiter = $this->conn->getHierarchyDelimiter();
-            if (empty($this->delimiter))
-                $this->delimiter = '/';
         }
-        // not supported, get namespace from config
-        else if ($imap_personal !== null || $imap_shared !== null || $imap_other !== null) {
-            if (empty($this->delimiter))
-                $this->delimiter = $this->conn->getHierarchyDelimiter();
-            if (empty($this->delimiter))
-                $this->delimiter = '/';
-
+        else {
             $this->namespace = array(
                 'personal' => NULL,
                 'other'    => NULL,
                 'shared'   => NULL,
             );
+        }
 
-            if ($imap_personal !== null) {
-                foreach ((array)$imap_personal as $dir) {
-                    $this->namespace['personal'][] = array($dir, $this->delimiter);
+        if ($imap_delimiter) {
+            $this->delimiter = $imap_delimiter;
+        }
+        if (empty($this->delimiter)) {
+            $this->delimiter = $this->namespace['personal'][0][1];
+        }
+        if (empty($this->delimiter)) {
+            $this->delimiter = $this->conn->getHierarchyDelimiter();
+        }
+        if (empty($this->delimiter)) {
+            $this->delimiter = '/';
+        }
+
+        // Overwrite namespaces
+        if ($imap_personal !== null) {
+            $this->namespace['personal'] = NULL;
+            foreach ((array)$imap_personal as $dir) {
+                $this->namespace['personal'][] = array($dir, $this->delimiter);
+            }
+        }
+        if ($imap_other !== null) {
+            $this->namespace['other'] = NULL;
+            foreach ((array)$imap_other as $dir) {
+                if ($dir) {
+                    $this->namespace['other'][] = array($dir, $this->delimiter);
                 }
             }
-            if ($imap_other !== null) {
-                foreach ((array)$imap_other as $dir) {
-                    if ($dir) {
-                        $this->namespace['other'][] = array($dir, $this->delimiter);
-                    }
-                }
-            }
-            if ($imap_shared !== null) {
-                foreach ((array)$imap_shared as $dir) {
-                    if ($dir) {
-                        $this->namespace['shared'][] = array($dir, $this->delimiter);
-                    }
+        }
+        if ($imap_shared !== null) {
+            $this->namespace['shared'] = NULL;
+            foreach ((array)$imap_shared as $dir) {
+                if ($dir) {
+                    $this->namespace['shared'][] = array($dir, $this->delimiter);
                 }
             }
         }
@@ -2053,7 +2062,7 @@
                 return false;
         }
 
-        $struct = &$this->_structure_part($structure);
+        $struct = &$this->_structure_part($structure, 0, '', $headers);
         $struct->headers = get_object_vars($headers);
 
         // don't trust given content-type
@@ -2185,6 +2194,11 @@
                 $struct->charset = $struct->ctype_parameters['charset'];
         }
 
+        // #1487700: workaround for lack of charset in malformed structure
+        if (empty($struct->charset) && !empty($mime_headers) && $mime_headers->charset) {
+            $struct->charset = $mime_headers->charset;
+        }
+
         // read content encoding
         if (!empty($part[5]) && $part[5]!='NIL') {
             $struct->encoding = strtolower($part[5]);
@@ -2233,7 +2247,11 @@
                 $mime_headers = $this->conn->fetchPartHeader(
                     $this->mailbox, $this->_msg_id, false, $struct->mime_id);
             }
-            $struct->headers = $this->_parse_headers($mime_headers) + $struct->headers;
+
+            if (is_string($mime_headers))
+                $struct->headers = $this->_parse_headers($mime_headers) + $struct->headers;
+            else if (is_object($mime_headers))
+                $struct->headers = get_object_vars($mime_headers) + $struct->headers;
 
             // get real content-type of message/rfc822
             if ($struct->mimetype == 'message/rfc822') {
@@ -3318,32 +3336,26 @@
             // If folder contains namespace prefix, don't modify it
             if (is_array($this->namespace['shared'])) {
                 foreach ($this->namespace['shared'] as $ns) {
-                    foreach ((array)$ns as $root) {
-                        if ($root[0] && strpos($mbox_name, $root[0]) === 0) {
-                            return $mbox_name;
-                        }
+                    if ($ns[0] && strpos($mbox_name, $ns[0]) === 0) {
+                        return $mbox_name;
                     }
                 }
             }
             if (is_array($this->namespace['other'])) {
                 foreach ($this->namespace['other'] as $ns) {
-                    foreach ((array)$ns as $root) {
-                        if ($root[0] && strpos($mbox_name, $root[0]) === 0) {
-                            return $mbox_name;
-                        }
+                    if ($ns[0] && strpos($mbox_name, $ns[0]) === 0) {
+                        return $mbox_name;
                     }
                 }
             }
             if (is_array($this->namespace['personal'])) {
                 foreach ($this->namespace['personal'] as $ns) {
-                    foreach ((array)$ns as $root) {
-                        if ($root[0] && strpos($mbox_name, $root[0]) === 0) {
-                            return $mbox_name;
-                        }
+                    if ($ns[0] && strpos($mbox_name, $ns[0]) === 0) {
+                        return $mbox_name;
                     }
                 }
                 // Add prefix if first personal namespace is non-empty
-                if ($this->namespace['personal'][0][0]) {
+                if ($mbox_name != 'INBOX' && $this->namespace['personal'][0][0]) {
                     return $this->namespace['personal'][0][0].$mbox_name;
                 }
             }
@@ -4697,10 +4709,13 @@
     private function _parse_address_list($str, $decode=true)
     {
         // remove any newlines and carriage returns before
-        $a = rcube_explode_quoted_string('[,;]', preg_replace( "/[\r\n]/", " ", $str));
+        $str = preg_replace('/\r?\n(\s|\t)?/', ' ', $str);
+
+        // extract list items, remove comments
+        $str = self::explode_header_string(',;', $str, true);
         $result = array();
 
-        foreach ($a as $key => $val) {
+        foreach ($str as $key => $val) {
             $name    = '';
             $address = '';
             $val     = trim($val);
@@ -4740,6 +4755,91 @@
         return $result;
     }
 
+
+    /**
+     * Explodes header (e.g. address-list) string into array of strings
+     * using specified separator characters with proper handling
+     * of quoted-strings and comments (RFC2822)
+     *
+     * @param string $separator       String containing separator characters
+     * @param string $str             Header string
+     * @param bool   $remove_comments Enable to remove comments
+     *
+     * @return array Header items
+     */
+    static function explode_header_string($separator, $str, $remove_comments=false)
+    {
+        $length  = strlen($str);
+        $result  = array();
+        $quoted  = false;
+        $comment = 0;
+        $out     = '';
+
+        for ($i=0; $i<$length; $i++) {
+            // we're inside a quoted string
+            if ($quoted) {
+                if ($str[$i] == '"') {
+                    $quoted = false;
+                }
+                else if ($str[$i] == '\\') {
+                    if ($comment <= 0) {
+                        $out .= '\\';
+                    }
+                    $i++;
+                }
+            }
+            // we're inside a comment string
+            else if ($comment > 0) {
+                    if ($str[$i] == ')') {
+                        $comment--;
+                    }
+                    else if ($str[$i] == '(') {
+                        $comment++;
+                    }
+                    else if ($str[$i] == '\\') {
+                        $i++;
+                    }
+                    continue;
+            }
+            // separator, add to result array
+            else if (strpos($separator, $str[$i]) !== false) {
+                    if ($out) {
+                        $result[] = $out;
+                    }
+                    $out = '';
+                    continue;
+            }
+            // start of quoted string
+            else if ($str[$i] == '"') {
+                    $quoted = true;
+            }
+            // start of comment
+            else if ($remove_comments && $str[$i] == '(') {
+                    $comment++;
+            }
+
+            if ($comment <= 0) {
+                $out .= $str[$i];
+            }
+        }
+
+        if ($out && $comment <= 0) {
+            $result[] = $out;
+        }
+
+        return $result;
+    }
+
+
+    /**
+     * This is our own debug handler for the IMAP connection
+     * @access public
+     */
+    public function debug_handler(&$imap, $message)
+    {
+        write_log('imap', $message);
+    }
+
 }  // end class rcube_imap
 
 

--
Gitblit v1.9.1