From 3fec6952ddbff1b5b487ea2927928338f39e4fef Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Tue, 15 Nov 2011 05:50:30 -0500
Subject: [PATCH] - Applied fixes from trunk up to r5425

---
 CHANGELOG                            |    4 
 plugins/password/drivers/sql.php     |   36 +++++-
 program/js/common.js                 |   11 +
 program/include/main.inc             |   31 +----
 program/include/rcube_imap.php       |   79 ++++++++++++++-
 program/steps/mail/autocomplete.inc  |   34 ++++--
 program/include/rcmail.php           |   11 +
 config/main.inc.php.dist             |    5 
 plugins/password/config.inc.php.dist |    4 
 plugins/password/password.php        |    6 
 plugins/password/package.xml         |   25 ++++
 11 files changed, 183 insertions(+), 63 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 909a9f3..c585c12 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,10 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Fix listing of folders in hidden namespaces (#1486796)
+- Don't consider \Noselect flag when building folders tree (#1488004)
+- Fix sorting autocomplete results (#1488084)
+- Add option to set session name (#1486433)
 - Add option to skip alternative email addresses in autocompletion
 - Fix inconsistent behaviour of Compose button in Drafts folder, add Edit button for drafts
 - Fix problem with parsing HTML message body with non-unicode characters (#1487813)
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index fe58350..d07a3b3 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -222,6 +222,9 @@
 // session domain: .example.org
 $rcmail_config['session_domain'] = '';
 
+// session name. Default: 'roundcube_sessid'
+$rcmail_config['session_name'] = null;
+
 // Backend to use for session storage. Can either be 'db' (default) or 'memcache'
 // If set to memcache, a list of servers need to be specified in 'memcache_hosts'
 // Make sure the Memcache extension (http://pecl.php.net/package/memcache) version >= 2.0.0 is installed
@@ -418,7 +421,7 @@
 // NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
 $rcmail_config['default_imap_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash');
 
-// automatically create the above listed default folders on login
+// automatically create the above listed default folders on first login
 $rcmail_config['create_default_folders'] = false;
 
 // protect the default folders from renames, deletes, and subscription changes
diff --git a/plugins/password/config.inc.php.dist b/plugins/password/config.inc.php.dist
index 94af6d7..313e47f 100644
--- a/plugins/password/config.inc.php.dist
+++ b/plugins/password/config.inc.php.dist
@@ -47,6 +47,10 @@
 // Default: "SELECT update_passwd(%c, %u)"
 $rcmail_config['password_query'] = 'SELECT update_passwd(%c, %u)';
 
+// By default domains in variables are using unicode.
+// Enable this option to use punycoded names
+$rcmail_config['password_idn_ascii'] = false;
+
 // Path for dovecotpw (if not in $PATH)
 // $rcmail_config['password_dovecotpw'] = '/usr/local/sbin/dovecotpw';
 
diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php
index 836a58a..06a6b75 100644
--- a/plugins/password/drivers/sql.php
+++ b/plugins/password/drivers/sql.php
@@ -37,16 +37,21 @@
     // crypted password
     if (strpos($sql, '%c') !== FALSE) {
         $salt = '';
-        if (CRYPT_MD5) { 
-    	    $len = rand(3, CRYPT_SALT_LENGTH);
+        if (CRYPT_MD5) {
+            // Always use eight salt characters for MD5 (#1488136)
+    	    $len = 8;
         } else if (CRYPT_STD_DES) {
     	    $len = 2;
         } else {
     	    return PASSWORD_CRYPT_ERROR;
         }
+
+        //Restrict the character set used as salt (#1488136)
+        $seedchars = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
         for ($i = 0; $i < $len ; $i++) {
-    	    $salt .= chr(rand(ord('.'), ord('z')));
+    	    $salt .= $seedchars[rand(0, 63)];
         }
+
         $sql = str_replace('%c',  $db->quote(crypt($passwd, CRYPT_MD5 ? '$1$'.$salt.'$' : $salt)), $sql);
     }
 
@@ -125,11 +130,28 @@
         }
     }
 
+    $local_part  = $rcmail->user->get_username('local');
+    $domain_part = $rcmail->user->get_username('domain');
+    $username    = $_SESSION['username'];
+    $host        = $_SESSION['imap_host'];
+
+    // convert domains to/from punnycode
+    if ($rcmail->config->get('password_idn_ascii')) {
+        $domain_part = rcube_idn_to_ascii($domain_part);
+        $username    = rcube_idn_to_ascii($username);
+        $host        = rcube_idn_to_ascii($host);
+    }
+    else {
+        $domain_part = rcube_idn_to_utf8($domain_part);
+        $username    = rcube_idn_to_utf8($username);
+        $host        = rcube_idn_to_utf8($host);
+    }
+
     // at least we should always have the local part
-    $sql = str_replace('%l', $db->quote($rcmail->user->get_username('local'), 'text'), $sql);
-    $sql = str_replace('%d', $db->quote($rcmail->user->get_username('domain'), 'text'), $sql);
-    $sql = str_replace('%u', $db->quote($_SESSION['username'],'text'), $sql);
-    $sql = str_replace('%h', $db->quote($_SESSION['imap_host'],'text'), $sql);
+    $sql = str_replace('%l', $db->quote($local_part, 'text'), $sql);
+    $sql = str_replace('%d', $db->quote($domain_part, 'text'), $sql);
+    $sql = str_replace('%u', $db->quote($username, 'text'), $sql);
+    $sql = str_replace('%h', $db->quote($host, 'text'), $sql);
 
     $res = $db->query($sql, $sql_vars);
 
diff --git a/plugins/password/package.xml b/plugins/password/package.xml
index 69cef07..d3f4bea 100644
--- a/plugins/password/package.xml
+++ b/plugins/password/package.xml
@@ -27,10 +27,7 @@
 	</stability>
 	<license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license>
 	<notes>
-- When old and new passwords are the same, do nothing, return success (#1487823)
-- Fixed Samba password hashing in 'ldap' driver
-- Added 'password_change' hook for plugin actions after successful password change
-- Fixed bug where 'doveadm pw' command was used as dovecotpw utility
+- Added option to use punycode or unicode for domain names (#1488103)
     </notes>
 	<contents>
 		<dir baseinstalldir="/" name="/">
@@ -264,5 +261,25 @@
 - Virtualmin driver: Add option for setting username format (#1487781)
             </notes>
         </release>
+        <release>
+        	<date>2011-10-26</date>
+	        <time>12:00</time>
+        	<version>
+		        <release>2.3</release>
+        		<api>1.6</api>
+        	</version>
+	        <stability>
+        		<release>stable</release>
+		        <api>stable</api>
+        	</stability>
+        	<license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license>
+	        <notes>
+- When old and new passwords are the same, do nothing, return success (#1487823)
+- Fixed Samba password hashing in 'ldap' driver
+- Added 'password_change' hook for plugin actions after successful password change
+- Fixed bug where 'doveadm pw' command was used as dovecotpw utility
+- Improve generated crypt() passwords (#1488136)
+            </notes>
+        </release>
     </changelog>
 </package>
diff --git a/plugins/password/password.php b/plugins/password/password.php
index b1c7863..06e3448 100644
--- a/plugins/password/password.php
+++ b/plugins/password/password.php
@@ -223,7 +223,7 @@
     {
         $config = rcmail::get_instance()->config;
         $driver = $this->home.'/drivers/'.$config->get('password_driver', 'sql').'.php';
-    
+
         if (!is_readable($driver)) {
             raise_error(array(
                 'code' => 600,
@@ -233,7 +233,7 @@
             ), true, false);
             return $this->gettext('internalerror');
         }
-    
+
         include($driver);
 
         if (!function_exists('password_save')) {
@@ -270,5 +270,5 @@
         }
 
         return $reason;
-    }                                     
+    }
 }
diff --git a/program/include/main.inc b/program/include/main.inc
index 95d422d..c84e5ad 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -1281,11 +1281,6 @@
   $path .= $prefix.$currentFolder;
 
   if (!isset($arrFolders[$currentFolder])) {
-    // Check \Noselect attribute (if attributes are in cache)
-    if (!$virtual && ($attrs = $RCMAIL->imap->mailbox_attributes($path))) {
-      $virtual = in_array('\\Noselect', $attrs);
-    }
-
     $arrFolders[$currentFolder] = array(
       'id' => $path,
       'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'),
@@ -1313,12 +1308,14 @@
   $realnames = (bool)$attrib['realnames'];
   $msgcounts = $RCMAIL->imap->get_cache('messagecount');
 
-  $idx = 0;
   $out = '';
   foreach ($arrFolders as $key => $folder) {
-    $title = null;
+    $title        = null;
+    $folder_class = rcmail_folder_classname($folder['id']);
+    $collapsed    = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false;
+    $unread       = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0;
 
-    if (($folder_class = rcmail_folder_classname($folder['id'])) && !$realnames) {
+    if ($folder_class && !$realnames) {
       $foldername = rcube_label($folder_class);
     }
     else {
@@ -1338,24 +1335,11 @@
     $classes = array('mailbox');
 
     // set special class for Sent, Drafts, Trash and Junk
-    if ($folder['id'] == $CONFIG['sent_mbox'])
-      $classes[] = 'sent';
-    else if ($folder['id'] == $CONFIG['drafts_mbox'])
-      $classes[] = 'drafts';
-    else if ($folder['id'] == $CONFIG['trash_mbox'])
-      $classes[] = 'trash';
-    else if ($folder['id'] == $CONFIG['junk_mbox'])
-      $classes[] = 'junk';
-    else if ($folder['id'] == 'INBOX')
-      $classes[] = 'inbox';
-    else
-      $classes[] = '_'.asciiwords($folder_class ? $folder_class : strtolower($folder['id']), true);
+    if ($folder_class)
+      $classes[] = $folder_class;
 
     if ($folder['id'] == $mbox_name)
       $classes[] = 'selected';
-
-    $collapsed = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false;
-    $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0;
 
     if ($folder['virtual'])
       $classes[] = 'virtual';
@@ -1390,7 +1374,6 @@
     }
 
     $out .= "</li>\n";
-    $idx++;
   }
 
   return $out;
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index 969e101..e06594f 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -678,18 +678,21 @@
     if (session_id())
       return;
 
+    $sess_name   = $this->config->get('session_name');
+    $sess_domain = $this->config->get('session_domain');
+    $lifetime    = $this->config->get('session_lifetime', 0) * 60;
+
     // set session domain
-    if ($domain = $this->config->get('session_domain')) {
-      ini_set('session.cookie_domain', $domain);
+    if ($sess_domain) {
+      ini_set('session.cookie_domain', $sess_domain);
     }
     // set session garbage collecting time according to session_lifetime
-    $lifetime = $this->config->get('session_lifetime', 0) * 60;
     if ($lifetime) {
       ini_set('session.gc_maxlifetime', $lifetime * 2);
     }
 
     ini_set('session.cookie_secure', rcube_https_check());
-    ini_set('session.name', 'roundcube_sessid');
+    ini_set('session.name', $sess_name ? $sess_name : 'roundcube_sessid');
     ini_set('session.use_cookies', 1);
     ini_set('session.use_only_cookies', 1);
     ini_set('session.serialize_handler', 'php');
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 8c1fab8..d56da3d 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -1373,6 +1373,11 @@
         $this->_messagecount($mailbox, 'ALL', true);
 
         $result = 0;
+
+        if (empty($old)) {
+            return $result;
+        }
+
         $new = $this->get_folder_stats($mailbox);
 
         // got new messages
@@ -2999,14 +3004,14 @@
 
 
     /**
-     * Private method for mailbox listing
+     * Private method for mailbox listing (LSUB)
      *
      * @param   string  $root   Optional root folder
      * @param   string  $name   Optional name pattern
      * @param   mixed   $filter Optional filter
      * @param   string  $rights Optional ACL requirements
      *
-     * @return  array   List of mailboxes/folders
+     * @return  array   List of subscribed folders
      * @see     rcube_imap::list_mailboxes()
      * @access  private
      */
@@ -3109,7 +3114,7 @@
         }
         else {
             // retrieve list of folders from IMAP server
-            $a_mboxes = $this->conn->listMailboxes($root, $name);
+            $a_mboxes = $this->_list_unsubscribed($root, $name);
         }
 
         if (!is_array($a_mboxes)) {
@@ -3140,6 +3145,70 @@
         $this->update_cache($cache_key, $a_mboxes);
 
         return $a_mboxes;
+    }
+
+
+    /**
+     * Private method for mailbox listing (LIST)
+     *
+     * @param   string  $root   Optional root folder
+     * @param   string  $name   Optional name pattern
+     *
+     * @return  array   List of folders
+     * @see     rcube_imap::list_unsubscribed()
+     */
+    private function _list_unsubscribed($root='', $name='*')
+    {
+        $result = $this->conn->listMailboxes($root, $name);
+
+        if (!is_array($result)) {
+            return array();
+        }
+
+        // #1486796: some server configurations doesn't
+        // return folders in all namespaces, we'll try to detect that situation
+        // and ask for these namespaces separately
+        if ($root == '' && $name = '*') {
+            $delim     = $this->get_hierarchy_delimiter();
+            $namespace = $this->get_namespace();
+            $search    = array();
+
+            // build list of namespace prefixes
+            foreach ((array)$namespace as $ns) {
+                if (is_array($ns)) {
+                    foreach ($ns as $ns_data) {
+                        if (strlen($ns_data[0])) {
+                            $search = $ns_data[0];
+                        }
+                    }
+                }
+            }
+
+            if (!empty($search)) {
+                // go through all folders detecting namespace usage
+                foreach ($result as $folder) {
+                    foreach ($search as $idx => $prefix) {
+                        if (strpos($folder, $prefix) === 0) {
+                            unset($search[$idx]);
+                        }
+                    }
+                    if (empty($search)) {
+                        break;
+                    }
+                }
+
+                // get folders in hidden namespaces and add to the result
+                foreach ($search as $prefix) {
+                    $list = $this->conn->listMailboxes($prefix, $name);
+
+                    if (!empty($list)) {
+                        $result = array_merge($result, $list);
+                    }
+                }
+            }
+        }
+
+        return $result;
     }
 
 
@@ -3415,8 +3484,8 @@
         foreach ($this->namespace as $type => $namespace) {
             if (is_array($namespace)) {
                 foreach ($namespace as $ns) {
-                    if (strlen($ns[0])) {
-                        if ((strlen($ns[0])>1 && $mailbox == substr($ns[0], 0, -1))
+                    if ($len = strlen($ns[0])) {
+                        if (($len > 1 && $mailbox == substr($ns[0], 0, -1))
                             || strpos($mailbox, $ns[0]) === 0
                         ) {
                             return $type;
diff --git a/program/js/common.js b/program/js/common.js
index 831e44a..c13d95e 100644
--- a/program/js/common.js
+++ b/program/js/common.js
@@ -542,10 +542,17 @@
   return out;
 };
 
-// make a string URL safe
+// make a string URL safe (and compatible with PHP's rawurlencode())
 function urlencode(str)
 {
-  return window.encodeURIComponent ? encodeURIComponent(str) : escape(str);
+  if (window.encodeURIComponent)
+    return encodeURIComponent(str).replace('*', '%2A');
+
+  return escape(str)
+    .replace('+', '%2B')
+    .replace('*', '%2A')
+    .replace('/', '%2F')
+    .replace('@', '%40');
 };
 
 
diff --git a/program/steps/mail/autocomplete.inc b/program/steps/mail/autocomplete.inc
index e40bb76..281a4e9 100644
--- a/program/steps/mail/autocomplete.inc
+++ b/program/steps/mail/autocomplete.inc
@@ -54,6 +54,7 @@
 
 if (!empty($book_types) && strlen($search)) {
   $contacts  = array();
+  $sort_keys = array();
   $books_num = count($book_types);
   $search_lc = mb_strtolower($search);
 
@@ -66,6 +67,7 @@
         // Contact can have more than one e-mail address
         $email_arr = (array)$abook->get_col_values('email', $sql_arr, true);
         $email_cnt = count($email_arr);
+        $idx = 0;
         foreach ($email_arr as $email) {
           if (empty($email)) {
             continue;
@@ -80,7 +82,9 @@
 
           // skip duplicates
           if (!in_array($contact, $contacts)) {
-            $contacts[] = $contact;
+            $contacts[]  = $contact;
+            $sort_keys[] = sprintf('%s %03d', $sql_arr['name'] , $idx++);
+
             if (count($contacts) >= $MAXNUM)
               break 2;
           }
@@ -102,15 +106,20 @@
 
         // group (distribution list) with email address(es)
         if ($group_prop['email']) {
+            $idx = 0;
             foreach ((array)$group_prop['email'] as $email) {
-                $contacts[] = format_email_recipient($email, $group['name']);
+                $contacts[]  = format_email_recipient($email, $group['name']);
+                $sort_keys[] = sprintf('%s %03d', $group['name'] , $idx++);
+
                 if (count($contacts) >= $MAXNUM)
                   break 2;
             }
         }
         // show group with count
         else if (($result = $abook->count()) && $result->count) {
-          $contacts[] = array('name' => $group['name'] . ' (' . intval($result->count) . ')', 'id' => $group['ID'], 'source' => $id);
+          $contacts[]  = array('name' => $group['name'] . ' (' . intval($result->count) . ')', 'id' => $group['ID'], 'source' => $id);
+          $sort_keys[] = $group['name'];
+
           if (count($contacts) >= $MAXNUM)
             break;
         }
@@ -118,17 +127,16 @@
     }
   }
 
-  usort($contacts, 'contact_results_sort');
+  if (count($contacts)) {
+    // sort contacts index
+    asort($sort_keys, SORT_LOCALE_STRING);
+    // re-sort contacts according to index
+    foreach ($sort_keys as $idx => $val) {
+      $sort_keys[$idx] = $contacts[$idx];
+    }
+    $contacts = array_values($sort_keys);
+  }
 }
 
 $OUTPUT->command('ksearch_query_results', $contacts, $search, $sid);
 $OUTPUT->send();
-
-
-function contact_results_sort($a, $b)
-{
-  $name_a = is_array($a) ? $a['name'] : $a;
-  $name_b = is_array($b) ? $b['name'] : $b;
-  return strcoll(trim($name_a, '" '), trim($name_b, '" '));
-}
-

--
Gitblit v1.9.1