From dc0b500e78aae13349b848303302a213ed3a1e65 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Tue, 01 Apr 2014 13:27:07 -0400
Subject: [PATCH] Removed redundant default_folders config option (#1489737) Implemented IMAP SPECIAL-USE extension support [RFC6154] (#1487830)

---
 program/lib/Roundcube/rcube.php              |   33 +++
 CHANGELOG                                    |    2 
 plugins/archive/archive.php                  |   21 -
 program/steps/settings/folders.inc           |   23 +-
 program/lib/Roundcube/rcube_imap.php         |  141 ++++++++++++-----
 plugins/archive/archive.js                   |    2 
 program/lib/Roundcube/rcube_storage.php      |   82 +++++++---
 program/steps/settings/save_prefs.inc        |   28 +--
 installer/rcube_install.php                  |   14 -
 program/include/rcmail.php                   |   17 -
 program/steps/settings/func.inc              |   19 +-
 program/lib/Roundcube/rcube_imap_generic.php |   40 +++-
 config/defaults.inc.php                      |   11 -
 13 files changed, 263 insertions(+), 170 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 93f9b85..aaa7c8e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,8 @@
 - Improve UI integration of ACL settings
 - Drop support for PHP < 5.3.7
 - Set In-Reply-To and References for forwarded messages (#1489593)
+- Removed redundant default_folders config option (#1489737)
+- Implemented IMAP SPECIAL-USE extension support [RFC6154] (#1487830)
 - Fix directories check in Installer on Windows (#1489576)
 - Fix issue when default_addressbook option is set to integer value (#1489407)
 - Fix Opera > 15 detection (#1489562)
diff --git a/config/defaults.inc.php b/config/defaults.inc.php
index 8c9b96f..5c5fccb 100644
--- a/config/defaults.inc.php
+++ b/config/defaults.inc.php
@@ -561,20 +561,15 @@
 // NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
 $config['trash_mbox'] = 'Trash';
 
-// display these folders separately in the mailbox list.
-// these folders will also be displayed with localized names
-// NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
-$config['default_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash');
-
-// Disable localization of the default folder names listed above
-$config['show_real_foldernames'] = false;
-
 // automatically create the above listed default folders on first login
 $config['create_default_folders'] = false;
 
 // protect the default folders from renames, deletes, and subscription changes
 $config['protect_default_folders'] = true;
 
+// Disable localization of the default folder names listed above
+$config['show_real_foldernames'] = false;
+
 // if in your system 0 quota means no limit set this option to true 
 $config['quota_zero_as_unlimited'] = false;
 
diff --git a/installer/rcube_install.php b/installer/rcube_install.php
index 2fae3c5..b047156 100644
--- a/installer/rcube_install.php
+++ b/installer/rcube_install.php
@@ -42,7 +42,6 @@
     'addrbook_show_images' => 'show_images',
     'imap_root'            => 'imap_ns_personal',
     'pagesize'             => 'mail_pagesize',
-    'default_imap_folders' => 'default_folders',
     'top_posting'          => 'reply_mode',
     'keep_alive'           => 'refresh_interval',
     'min_keep_alive'       => 'min_refresh_interval',
@@ -227,19 +226,6 @@
       }
       else if ($prop == 'smtp_pass' && !empty($_POST['_smtp_user_u'])) {
         $value = '%p';
-      }
-      else if ($prop == 'default_folders') {
-        $value = array();
-        foreach ($this->config['default_folders'] as $_folder) {
-          switch ($_folder) {
-          case 'Drafts': $_folder = $this->config['drafts_mbox']; break;
-          case 'Sent':   $_folder = $this->config['sent_mbox']; break;
-          case 'Junk':   $_folder = $this->config['junk_mbox']; break;
-          case 'Trash':  $_folder = $this->config['trash_mbox']; break;
-          }
-        if (!in_array($_folder, $value))
-          $value[] = $_folder;
-        }
       }
       else if (is_bool($default)) {
         $value = (bool)$value;
diff --git a/plugins/archive/archive.js b/plugins/archive/archive.js
index 8130334..c0d074c 100644
--- a/plugins/archive/archive.js
+++ b/plugins/archive/archive.js
@@ -1,6 +1,6 @@
 /**
  * Archive plugin script
- * @version 2.1
+ * @version 2.2
  */
 
 function rcmail_archive(prop)
diff --git a/plugins/archive/archive.php b/plugins/archive/archive.php
index a0fd2ef..8c0a89d 100644
--- a/plugins/archive/archive.php
+++ b/plugins/archive/archive.php
@@ -6,22 +6,22 @@
  * Plugin that adds a new button to the mailbox toolbar
  * to move messages to a (user selectable) archive folder.
  *
- * @version 2.1
+ * @version 2.2
  * @license GNU GPLv3+
  * @author Andre Rodier, Thomas Bruederli, Aleksander Machniak
  */
 class archive extends rcube_plugin
 {
-  public $task = 'mail|settings';
-
   function init()
   {
     $rcmail = rcmail::get_instance();
 
-    // There is no "Archived flags"
-    // $GLOBALS['IMAP_FLAGS']['ARCHIVED'] = 'Archive';
+    // register special folder type
+    rcube_storage::$folder_types[] = 'archive';
+
     if ($rcmail->task == 'mail' && ($rcmail->action == '' || $rcmail->action == 'show')
-        && ($archive_folder = $rcmail->config->get('archive_mbox'))) {
+        && ($archive_folder = $rcmail->config->get('archive_mbox'))
+    ) {
       $skin_path = $this->local_skin_path();
       if (is_file($this->home . "/$skin_path/archive.css"))
         $this->include_stylesheet("$skin_path/archive.css");
@@ -48,12 +48,6 @@
       // set env variables for client
       $rcmail->output->set_env('archive_folder', $archive_folder);
       $rcmail->output->set_env('archive_type', $rcmail->config->get('archive_type',''));
-
-      // add archive folder to the list of default mailboxes
-      if (($default_folders = $rcmail->config->get('default_folders')) && !in_array($archive_folder, $default_folders)) {
-        $default_folders[] = $archive_folder;
-        $rcmail->config->set('default_folders', $default_folders);
-      }
     }
     else if ($rcmail->task == 'mail') {
       // handler for ajax request
@@ -99,7 +93,7 @@
         return true;
       } else if (!empty($item['folders']))
         if ($this->_mod_folder_name($list[$idx]['folders'], $folder, $new_name))
-        return true;
+          return true;
     }
     return false;
   }
@@ -286,7 +280,6 @@
   function save_prefs($args)
   {
     if ($args['section'] == 'folders') {
-      $args['prefs']['archive_mbox'] = rcube_utils::get_input_value('_archive_mbox', rcube_utils::INPUT_POST);
       $args['prefs']['archive_type'] = rcube_utils::get_input_value('_archive_type', rcube_utils::INPUT_POST);
       return $args;
     }
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index 0fe5dbc..9e57a8e 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -644,10 +644,8 @@
             // fix some old settings according to namespace prefix
             $this->fix_namespace_settings($user);
 
-            // create default folders on login
-            if ($this->config->get('create_default_folders')) {
-                $storage->create_default_folders();
-            }
+            // set/create special folders
+            $this->set_special_folders();
 
             // clear all mailboxes related cache(s)
             $storage->clear_cache('mailboxes', true);
@@ -923,14 +921,6 @@
             if ($value = $prefs[$opt]) {
                 if ($value != 'INBOX' && !preg_match($regexp, $value)) {
                     $prefs[$opt] = $prefix.$value;
-                }
-            }
-        }
-
-        if (!empty($prefs['default_folders'])) {
-            foreach ($prefs['default_folders'] as $idx => $name) {
-                if ($name != 'INBOX' && !preg_match($regexp, $name)) {
-                    $prefs['default_folders'][$idx] = $prefix.$name;
                 }
             }
         }
@@ -1646,14 +1636,13 @@
     public function localize_folderpath($path)
     {
         $protect_folders = $this->config->get('protect_default_folders');
-        $default_folders = (array) $this->config->get('default_folders');
         $delimiter       = $this->storage->get_hierarchy_delimiter();
         $path            = explode($delimiter, $path);
         $result          = array();
 
         foreach ($path as $idx => $dir) {
             $directory = implode($delimiter, array_slice($path, 0, $idx+1));
-            if ($protect_folders && in_array($directory, $default_folders)) {
+            if ($protect_folders && $this->storage->is_special_folder($directory)) {
                 unset($result);
                 $result[] = $this->localize_foldername($directory);
             }
diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php
index 69d95f0..4ff0a00 100644
--- a/program/lib/Roundcube/rcube.php
+++ b/program/lib/Roundcube/rcube.php
@@ -420,9 +420,6 @@
 
         $storage->set_charset($this->config->get('default_charset', RCUBE_CHARSET));
 
-        if ($default_folders = $this->config->get('default_folders')) {
-            $storage->set_default_folders($default_folders);
-        }
         if (isset($_SESSION['mbox'])) {
             $storage->set_folder($_SESSION['mbox']);
         }
@@ -433,6 +430,36 @@
 
 
     /**
+     * Set special folders type association.
+     * This must be done AFTER connecting to the server!
+     */
+    protected function set_special_folders()
+    {
+        $storage = $this->get_storage();
+        $folders = $storage->get_special_folders(true);
+        $prefs   = array();
+
+        // check SPECIAL-USE flags on IMAP folders
+        foreach ($folders as $type => $folder) {
+            $idx = $type . '_mbox';
+            if ($folder !== $this->config->get($idx)) {
+                $prefs[$idx] = $folder;
+            }
+        }
+
+        // Some special folders differ, update user preferences
+        if (!empty($prefs) && $this->user) {
+            $this->user->save_prefs($prefs);
+        }
+
+        // create default folders (on login)
+        if ($this->config->get('create_default_folders')) {
+            $storage->create_default_folders();
+        }
+    }
+
+
+    /**
      * Create session object and start the session.
      */
     public function session_init()
diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php
index 4322270..628338a 100644
--- a/program/lib/Roundcube/rcube_imap.php
+++ b/program/lib/Roundcube/rcube_imap.php
@@ -2365,19 +2365,7 @@
             return false;
         }
 
-        // make sure folder exists
-        if ($to_mbox != 'INBOX' && !$this->folder_exists($to_mbox)) {
-            if (in_array($to_mbox, $this->default_folders)) {
-                if (!$this->create_folder($to_mbox, true)) {
-                    return false;
-                }
-            }
-            else {
-                return false;
-            }
-        }
-
-        $config = rcube::get_instance()->config;
+        $config   = rcube::get_instance()->config;
         $to_trash = $to_mbox == $config->get('trash_mbox');
 
         // flag messages as read before moving them
@@ -2446,18 +2434,6 @@
 
         if (!$this->check_connection()) {
             return false;
-        }
-
-        // make sure folder exists
-        if ($to_mbox != 'INBOX' && !$this->folder_exists($to_mbox)) {
-            if (in_array($to_mbox, $this->default_folders)) {
-                if (!$this->create_folder($to_mbox, true)) {
-                    return false;
-                }
-            }
-            else {
-                return false;
-            }
         }
 
         // copy messages
@@ -2975,16 +2951,17 @@
      *
      * @param string  $folder    New folder name
      * @param boolean $subscribe True if the new folder should be subscribed
+     * @param string  $type      Optional folder type (junk, trash, drafts, sent, archive)
      *
      * @return boolean True on success
      */
-    public function create_folder($folder, $subscribe=false)
+    public function create_folder($folder, $subscribe = false, $type = null)
     {
         if (!$this->check_connection()) {
             return false;
         }
 
-        $result = $this->conn->createFolder($folder);
+        $result = $this->conn->createFolder($folder, $type ? array("\\" . ucfirst($type)) : null);
 
         // try to subscribe it
         if ($result) {
@@ -3109,19 +3086,84 @@
 
 
     /**
-     * Create all folders specified as default
+     * Detect special folder associations stored in storage backend
      */
-    public function create_default_folders()
+    public function get_special_folders($forced = false)
     {
-        // create default folders if they do not exist
-        foreach ($this->default_folders as $folder) {
-            if (!$this->folder_exists($folder)) {
-                $this->create_folder($folder, true);
-            }
-            else if (!$this->folder_exists($folder, true)) {
-                $this->subscribe($folder);
+        $result = parent::get_special_folders();
+
+        if (isset($this->icache['special-use'])) {
+            return array_merge($result, $this->icache['special-use']);
+        }
+
+        if (!$forced || !$this->get_capability('SPECIAL-USE')) {
+            return $result;
+        }
+
+        if (!$this->check_connection()) {
+            return $result;
+        }
+
+        $types   = array_map(function($value) { return "\\" . ucfirst($value); }, rcube_storage::$folder_types);
+        $special = array();
+
+        // request \Subscribed flag in LIST response as performance improvement for folder_exists()
+        $folders = $this->conn->listMailboxes('', '*', array('SUBSCRIBED'), array('SPECIAL-USE'));
+
+        foreach ($folders as $folder) {
+            if ($flags = $this->conn->data['LIST'][$folder]) {
+                foreach ($types as $type) {
+                    if (in_array($type, $flags)) {
+                        $type           = strtolower(substr($type, 1));
+                        $special[$type] = $folder;
+                    }
+                }
             }
         }
+
+        $this->icache['special-use'] = $special;
+        unset($this->icache['special-folders']);
+
+        return array_merge($result, $special);
+    }
+
+
+    /**
+     * Set special folder associations stored in storage backend
+     */
+    public function set_special_folders($specials)
+    {
+        if (!$this->get_capability('SPECIAL-USE') || !$this->get_capability('METADATA')) {
+            return false;
+        }
+
+        if (!$this->check_connection()) {
+            return false;
+        }
+
+        $folders = $this->get_special_folders(true);
+        $old     = (array) $this->icache['special-use'];
+
+        foreach ($specials as $type => $folder) {
+            if (in_array($type, rcube_storage::$folder_types)) {
+                $old_folder = $old[$type];
+                if ($old_folder !== $folder) {
+                    // unset old-folder metadata
+                    if ($old_folder !== null) {
+                        $this->delete_metadata($old_folder, array('/private/specialuse'));
+                    }
+                    // set new folder metadata
+                    if ($folder) {
+                        $this->set_metadata($folder, array('/private/specialuse' => "\\" . ucfirst($type)));
+                    }
+                }
+            }
+        }
+
+        $this->icache['special-use'] = $specials;
+        unset($this->icache['special-folders']);
+
+        return true;
     }
 
 
@@ -3133,13 +3175,13 @@
      *
      * @return boolean TRUE or FALSE
      */
-    public function folder_exists($folder, $subscription=false)
+    public function folder_exists($folder, $subscription = false)
     {
         if ($folder == 'INBOX') {
             return true;
         }
 
-        $key  = $subscription ? 'subscribed' : 'existing';
+        $key = $subscription ? 'subscribed' : 'existing';
 
         if (is_array($this->icache[$key]) && in_array($folder, $this->icache[$key])) {
             return true;
@@ -3150,10 +3192,24 @@
         }
 
         if ($subscription) {
-            $a_folders = $this->conn->listSubscribed('', $folder);
+            // It's possible we already called LIST command, check LIST data
+            if (!empty($this->conn->data['LIST']) && !empty($this->conn->data['LIST'][$folder])
+                && in_array('\\Subscribed', $this->conn->data['LIST'][$folder])
+            ) {
+                $a_folders = array($folder);
+            }
+            else {
+                $a_folders = $this->conn->listSubscribed('', $folder);
+            }
         }
         else {
-            $a_folders = $this->conn->listMailboxes('', $folder);
+            // It's possible we already called LIST command, check LIST data
+            if (!empty($this->conn->data['LIST']) && isset($this->conn->data['LIST'][$folder])) {
+                $a_folders = array($folder);
+            }
+            else {
+                $a_folders = $this->conn->listMailboxes('', $folder);
+            }
         }
 
         if (is_array($a_folders) && in_array($folder, $a_folders)) {
@@ -3364,7 +3420,7 @@
         $options['name']       = $folder;
         $options['attributes'] = $this->folder_attributes($folder, true);
         $options['namespace']  = $this->folder_namespace($folder);
-        $options['special']    = in_array($folder, $this->default_folders);
+        $options['special']    = $this->is_special_folder($folder);
 
         // Set 'noselect' flag
         if (is_array($options['attributes'])) {
@@ -3902,6 +3958,7 @@
         $a_out = $a_defaults = $folders = array();
 
         $delimiter = $this->get_hierarchy_delimiter();
+        $specials  = array_merge(array('INBOX'), array_values($this->get_special_folders()));
 
         // find default folders and skip folders starting with '.'
         foreach ($a_folders as $folder) {
@@ -3909,7 +3966,7 @@
                 continue;
             }
 
-            if (!$skip_default && ($p = array_search($folder, $this->default_folders)) !== false && !$a_defaults[$p]) {
+            if (!$skip_default && ($p = array_search($folder, $specials)) !== false && !$a_defaults[$p]) {
                 $a_defaults[$p] = $folder;
             }
             else {
diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php
index 4f57079..f45694d 100644
--- a/program/lib/Roundcube/rcube_imap_generic.php
+++ b/program/lib/Roundcube/rcube_imap_generic.php
@@ -1191,13 +1191,20 @@
      * Folder creation (CREATE)
      *
      * @param string $mailbox Mailbox name
+     * @param array  $types    Optional folder types (RFC 6154)
      *
      * @return bool True on success, False on error
      */
-    function createFolder($mailbox)
+    function createFolder($mailbox, $types = null)
     {
-        $result = $this->execute('CREATE', array($this->escape($mailbox)),
-            self::COMMAND_NORESPONSE);
+        $args = array($this->escape($mailbox));
+
+        // RFC 6154: CREATE-SPECIAL-USE
+        if (!empty($types) && $this->getCapability('CREATE-SPECIAL-USE')) {
+            $args[] = '(USE (' . implode(' ', $types) . '))';
+        }
+
+        $result = $this->execute('CREATE', $args, self::COMMAND_NORESPONSE);
 
         return ($result == self::ERROR_OK);
     }
@@ -1293,10 +1300,12 @@
      * @param string $ref         Reference name
      * @param string $mailbox     Mailbox name
      * @param bool   $subscribed  Enables returning subscribed mailboxes only
-     * @param array  $status_opts List of STATUS options (RFC5819: LIST-STATUS)
-     *                            Possible: MESSAGES, RECENT, UIDNEXT, UIDVALIDITY, UNSEEN
+     * @param array  $status_opts List of STATUS options
+     *                            (RFC5819: LIST-STATUS:  MESSAGES, RECENT, UIDNEXT, UIDVALIDITY, UNSEEN)
+     *                            or RETURN options (RFC5258: LIST_EXTENDED: SUBSCRIBED, CHILDREN)
      * @param array  $select_opts List of selection options (RFC5258: LIST-EXTENDED)
-     *                            Possible: SUBSCRIBED, RECURSIVEMATCH, REMOTE
+     *                            Possible: SUBSCRIBED, RECURSIVEMATCH, REMOTE,
+     *                                      SPECIAL-USE (RFC6154)
      *
      * @return array List of mailboxes or hash of options if $status_ops argument
      *               is non-empty.
@@ -1309,6 +1318,7 @@
         }
 
         $args = array();
+        $rets = array();
 
         if (!empty($select_opts) && $this->getCapability('LIST-EXTENDED')) {
             $select_opts = (array) $select_opts;
@@ -1319,11 +1329,21 @@
         $args[] = $this->escape($ref);
         $args[] = $this->escape($mailbox);
 
-        if (!empty($status_opts) && $this->getCapability('LIST-STATUS')) {
-            $status_opts = (array) $status_opts;
-            $lstatus = true;
+        if (!empty($status_opts) && $this->getCapability('LIST-EXTENDED')) {
+            $rets = array_intersect($status_opts, array('SUBSCRIBED', 'CHILDREN'));
+        }
 
-            $args[] = 'RETURN (STATUS (' . implode(' ', $status_opts) . '))';
+        if (!empty($status_opts) && $this->getCapability('LIST-STATUS')) {
+            $status_opts = array_intersect($status_opts, array('MESSAGES', 'RECENT', 'UIDNEXT', 'UIDVALIDITY', 'UNSEEN'));
+
+            if (!empty($status_opts)) {
+                $lstatus = true;
+                $rets[] = 'STATUS (' . implode(' ', $status_opts) . ')';
+            }
+        }
+
+        if (!empty($rets)) {
+            $args[] = 'RETURN (' . implode(' ', $rets) . ')';
         }
 
         list($code, $response) = $this->execute($subscribed ? 'LSUB' : 'LIST', $args);
diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php
index c09f053..69d6d2f 100644
--- a/program/lib/Roundcube/rcube_storage.php
+++ b/program/lib/Roundcube/rcube_storage.php
@@ -35,9 +35,15 @@
      */
     public $conn;
 
+    /**
+     * List of supported special folder types
+     *
+     * @var array
+     */
+    public static $folder_types = array('drafts', 'sent', 'junk', 'trash');
+
     protected $folder = 'INBOX';
     protected $default_charset = 'ISO-8859-1';
-    protected $default_folders = array('INBOX');
     protected $search_set;
     protected $options = array('auth_type' => 'check');
     protected $page_size = 10;
@@ -163,24 +169,6 @@
     public function set_charset($cs)
     {
         $this->default_charset = $cs;
-    }
-
-
-    /**
-     * This list of folders will be listed above all other folders
-     *
-     * @param  array $arr Indexed list of folder names
-     */
-    public function set_default_folders($arr)
-    {
-        if (is_array($arr)) {
-            $this->default_folders = $arr;
-
-            // add inbox if not included
-            if (!in_array('INBOX', $this->default_folders)) {
-                array_unshift($this->default_folders, 'INBOX');
-            }
-        }
     }
 
 
@@ -858,19 +846,63 @@
      */
     public function create_default_folders()
     {
+        $rcube = rcube::get_instance();
+
         // create default folders if they do not exist
-        foreach ($this->default_folders as $folder) {
-            if (!$this->folder_exists($folder)) {
-                $this->create_folder($folder, true);
-            }
-            else if (!$this->folder_exists($folder, true)) {
-                $this->subscribe($folder);
+        foreach (self::$folder_types as $type) {
+            if ($folder = $rcube->config->get($type . '_mbox')) {
+                if (!$this->folder_exists($folder)) {
+                    $this->create_folder($folder, true, $type);
+                }
+                else if (!$this->folder_exists($folder, true)) {
+                    $this->subscribe($folder);
+                }
             }
         }
     }
 
 
     /**
+     * Check if specified folder is a special folder
+     */
+    public function is_special_folder($name)
+    {
+        return $name == 'INBOX' || in_array($name, $this->get_special_folders());
+    }
+
+
+    /**
+     * Return configured special folders
+     */
+    public function get_special_folders($forced = false)
+    {
+        // getting config might be expensive, store special folders in memory
+        if (!isset($this->icache['special-folders'])) {
+            $rcube = rcube::get_instance();
+            $this->icache['special-folders'] = array();
+
+            foreach (self::$folder_types as $type) {
+                if ($folder = $rcube->config->get($type . '_mbox')) {
+                    $this->icache['special-folders'][$type] = $folder;
+                }
+            }
+        }
+
+        return $this->icache['special-folders'];
+    }
+
+
+    /**
+     * Set special folder associations stored in backend
+     */
+    public function set_special_folders($specials)
+    {
+        // should be overriden by storage class if backend supports special folders (SPECIAL-USE)
+        unset($this->icache['special-folders']);
+    }
+
+
+    /**
      * Get mailbox quota information.
      *
      * @return mixed Quota info or False if not supported
diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc
index b09ea03..1bcfb4c 100644
--- a/program/steps/settings/folders.inc
+++ b/program/steps/settings/folders.inc
@@ -45,7 +45,7 @@
         if ($result) {
             // Handle subscription of protected folder (#1487656)
             if ($RCMAIL->config->get('protect_default_folders')
-                && in_array($mbox, (array)$RCMAIL->config->get('default_folders'))
+                && $STORAGE->is_special_folder($mbox)
             ) {
                 $OUTPUT->command('disable_subscription', $mbox);
             }
@@ -221,16 +221,15 @@
     // get folders from server
     $STORAGE->clear_cache('mailboxes', true);
 
-    $a_unsubscribed = $STORAGE->list_folders();
-    $a_subscribed   = $STORAGE->list_folders_subscribed('', '*', null, null, true); // unsorted
-    $delimiter      = $STORAGE->get_hierarchy_delimiter();
-    $namespace      = $STORAGE->get_namespace();
-    $a_js_folders   = array();
-    $seen           = array();
-    $list_folders   = array();
-
-    $default_folders = (array) $RCMAIL->config->get('default_folders');
+    $a_unsubscribed  = $STORAGE->list_folders();
+    $a_subscribed    = $STORAGE->list_folders_subscribed('', '*', null, null, true); // unsorted
+    $delimiter       = $STORAGE->get_hierarchy_delimiter();
+    $namespace       = $STORAGE->get_namespace();
+    $special_folders = array_flip(array_merge(array('inbox' => 'INBOX'), $STORAGE->get_special_folders()));
     $protect_default = $RCMAIL->config->get('protect_default_folders');
+    $a_js_folders    = array();
+    $seen            = array();
+    $list_folders    = array();
 
     // pre-process folders list
     foreach ($a_unsubscribed as $i => $folder) {
@@ -291,7 +290,7 @@
         $idx        = $i + 1;
         $sub_key    = array_search($folder['id'], $a_subscribed);
         $subscribed = $sub_key !== false;
-        $protected  = $protect_default && in_array($folder['id'], $default_folders);
+        $protected  = $protect_default && isset($special_folders[$folder['id']]);
         $noselect   = false;
         $classes    = array($i%2 ? 'even' : 'odd');
 
@@ -368,7 +367,7 @@
 
     $OUTPUT->add_gui_object('subscriptionlist', $attrib['id']);
     $OUTPUT->set_env('subscriptionrows', $a_js_folders);
-    $OUTPUT->set_env('defaultfolders', $default_folders);
+    $OUTPUT->set_env('defaultfolders', array_keys($special_folders));
     $OUTPUT->set_env('delimiter', $delimiter);
 
     return $form_start . $table->show($attrib) . $form_end;
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index 307be8c..47efa5a 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -1035,7 +1035,8 @@
             }
 
             // Configure special folders
-            if (!isset($no_override['default_folders']) && $current) {
+            $set = array('drafts_mbox', 'sent_mbox', 'junk_mbox', 'trash_mbox');
+            if ($current && count(array_intersect($no_override, $set)) < 4) {
                 $select = $RCMAIL->folder_selector(array(
                     'noselection'   => '---',
                     'realnames'     => true,
@@ -1043,10 +1044,10 @@
                     'folder_filter' => 'mail',
                     'folder_rights' => 'w',
                 ));
-            }
 
-            // #1486114, #1488279, #1489219
-            $onchange = "if ($(this).val() == 'INBOX') $(this).val('')";
+                // #1486114, #1488279, #1489219
+                $onchange = "if ($(this).val() == 'INBOX') $(this).val('')";
+            }
 
             if (!isset($no_override['drafts_mbox'])) {
                 if (!$current) {
@@ -1287,13 +1288,11 @@
 {
     global $RCMAIL, $OUTPUT;
 
-    $default_folders = (array) $RCMAIL->config->get('default_folders');
     $protect_folders = $RCMAIL->config->get('protect_default_folders');
-
-    $storage      = $RCMAIL->get_storage();
-    $delimiter    = $storage->get_hierarchy_delimiter();
-    $name_utf8    = rcube_charset::convert($name, 'UTF7-IMAP');
-    $protected    = $protect_folders && in_array($name, $default_folders);
+    $storage         = $RCMAIL->get_storage();
+    $delimiter       = $storage->get_hierarchy_delimiter();
+    $name_utf8       = rcube_charset::convert($name, 'UTF7-IMAP');
+    $protected       = $protect_folders && $storage->is_special_folder($name);
 
     $foldersplit  = explode($delimiter, $storage->mod_folder($name));
     $level        = count($foldersplit) - 1;
diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc
index f71eee3..7a17f21 100644
--- a/program/steps/settings/save_prefs.inc
+++ b/program/steps/settings/save_prefs.inc
@@ -121,11 +121,11 @@
 case 'folders':
     $a_user_prefs = array(
         'show_real_foldernames' => isset($_POST['_show_real_foldernames']) ? true : false,
-        'drafts_mbox' => rcube_utils::get_input_value('_drafts_mbox', rcube_utils::INPUT_POST, true),
-        'sent_mbox'   => rcube_utils::get_input_value('_sent_mbox', rcube_utils::INPUT_POST, true),
-        'junk_mbox'   => rcube_utils::get_input_value('_junk_mbox', rcube_utils::INPUT_POST, true),
-        'trash_mbox'  => rcube_utils::get_input_value('_trash_mbox', rcube_utils::INPUT_POST, true),
     );
+
+    foreach (rcube_storage::$folder_types as $type) {
+        $a_user_prefs[$type . '_mbox'] = rcube_utils::get_input_value('_' . $type . '_mbox', rcube_utils::INPUT_POST, true);
+    };
 
     break;
 }
@@ -191,20 +191,14 @@
     break;
 
 case 'folders':
-    // special handling for 'default_folders'
-    if (in_array('default_folders', (array)$CONFIG['dont_override'])) {
-        foreach (array('drafts_mbox','sent_mbox','junk_mbox','trash_mbox') as $p) {
-            $a_user_prefs[$p] = $CONFIG[$p];
-        }
+    $storage  = $RCMAIL->get_storage();
+    $specials = array();
+
+    foreach (rcube_storage::$folder_types as $type) {
+        $specials[$type] = $a_user_prefs[$type . '_mbox'];
     }
-    else {
-        $a_user_prefs['default_folders'] = array('INBOX');
-        foreach (array('drafts_mbox','sent_mbox','junk_mbox','trash_mbox') as $p) {
-            if ($a_user_prefs[$p]) {
-                $a_user_prefs['default_folders'][] = $a_user_prefs[$p];
-            }
-        }
-    }
+
+    $storage->set_special_folders($specials);
 
     break;
 }

--
Gitblit v1.9.1