From aa07b2290640061a65c9f90d5f30cfc5d4ada195 Mon Sep 17 00:00:00 2001 From: alecpl Date: Tue, 8 Nov 2011 11:22:14 +0000 Subject: - Fix so folders with \Noinferiors attribute aren't listed in parent selector - Add LIST result and folder attributes cache - rcmail_render_folder_tree_select(): fix 'exceptions' parameter, add 'skip_noinferiors' option --- CHANGELOG | 1 + program/include/main.inc | 48 +++++++++++++---------- program/include/rcube_imap.php | 69 ++++++++++++++++++++++------------ program/include/rcube_imap_generic.php | 12 +++--- program/steps/settings/edit_folder.inc | 3 +- program/steps/settings/folders.inc | 4 +- 6 files changed, 83 insertions(+), 54 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0e72c41e8..ffd8498cc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix so folders with \Noinferiors attribute aren't listed in parent selector - Fix handling of curly brackets in URLs (#1488168) - Fix handling of dates (birthday/anniversary) in contact data (#1488147) - Fix error on opening searched LDAP contact (#1488144) diff --git a/program/include/main.inc b/program/include/main.inc index 7e31c012f..95d422d6a 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -1232,7 +1232,7 @@ function rcmail_mailbox_select($p = array()) if ($p['noselection']) $select->add($p['noselection'], ''); - rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p['exceptions']); + rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p); return $select; } @@ -1281,9 +1281,9 @@ function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='') $path .= $prefix.$currentFolder; if (!isset($arrFolders[$currentFolder])) { - // Check \Noselect option (if options are in cache) - if (!$virtual && ($opts = $RCMAIL->imap->mailbox_options($path))) { - $virtual = in_array('\\Noselect', $opts); + // Check \Noselect attribute (if attributes are in cache) + if (!$virtual && ($attrs = $RCMAIL->imap->mailbox_attributes($path))) { + $virtual = in_array('\\Noselect', $attrs); } $arrFolders[$currentFolder] = array( @@ -1402,30 +1402,40 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at * @access private * @return string */ -function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $exceptions=array()) +function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $opts=array()) { + global $RCMAIL; + $out = ''; foreach ($arrFolders as $key => $folder) { - if (empty($exceptions) || !in_array($folder['id'], $exceptions)) { - if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) - $foldername = rcube_label($folder_class); - else { - $foldername = $folder['name']; - - // shorten the folder name to a given length - if ($maxlength && $maxlength>1) - $foldername = abbreviate_string($foldername, $maxlength); - } - - $select->add(str_repeat(' ', $nestLevel*4) . $foldername, $folder['id']); + // skip exceptions (and its subfolders) + if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { + continue; } - else if ($nestLevel) + + // skip folders in which it isn't possible to create subfolders + if (!empty($opts['skip_noinferiors']) && ($attrs = $RCMAIL->imap->mailbox_attributes($folder['id'])) + && in_array('\\Noinferiors', $attrs) + ) { continue; + } + + if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id']))) + $foldername = rcube_label($folder_class); + else { + $foldername = $folder['name']; + + // shorten the folder name to a given length + if ($maxlength && $maxlength>1) + $foldername = abbreviate_string($foldername, $maxlength); + } + + $select->add(str_repeat(' ', $nestLevel*4) . $foldername, $folder['id']); if (!empty($folder['folders'])) $out .= rcmail_render_folder_tree_select($folder['folders'], $mbox_name, $maxlength, - $select, $realnames, $nestLevel+1, $exceptions); + $select, $realnames, $nestLevel+1, $opts); } return $out; diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 43d35908f..7508acda5 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -3087,7 +3087,19 @@ class rcube_imap */ function list_unsubscribed($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) { - // @TODO: caching + $cache_key = $root.':'.$name; + if (!empty($filter)) { + $cache_key .= ':'.(is_string($filter) ? $filter : serialize($filter)); + } + $cache_key .= ':'.$rights; + $cache_key = 'mailboxes.list.'.md5($cache_key); + + // get cached folder list + $a_mboxes = $this->get_cache($cache_key); + if (is_array($a_mboxes)) { + return $a_mboxes; + } + // Give plugins a chance to provide a list of mailboxes $data = rcmail::get_instance()->plugins->exec_hook('mailboxes_list', array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LIST')); @@ -3109,6 +3121,11 @@ class rcube_imap array_unshift($a_mboxes, 'INBOX'); } + // cache folder attributes + if ($root == '' && $name == '*' && empty($filter)) { + $this->update_cache('mailboxes.attributes', $this->conn->data['LIST']); + } + // filter folders list according to rights requirements if ($rights && $this->get_capability('ACL')) { $a_folders = $this->filter_rights($a_folders, $rights); @@ -3119,6 +3136,9 @@ class rcube_imap $a_mboxes = $this->_sort_mailbox_list($a_mboxes); } + // write mailboxlist to cache + $this->update_cache($cache_key, $a_mboxes); + return $a_mboxes; } @@ -3450,30 +3470,29 @@ class rcube_imap /** - * Gets folder options from LIST response, e.g. \Noselect, \Noinferiors + * Gets folder attributes from LIST response, e.g. \Noselect, \Noinferiors * * @param string $mailbox Folder name - * @param bool $force Set to True if options should be refreshed - * Options are available after LIST command only + * @param bool $force Set to True if attributes should be refreshed * * @return array Options list */ - function mailbox_options($mailbox, $force=false) + function mailbox_attributes($mailbox, $force=false) { - if ($mailbox == 'INBOX') { - return array(); + // get attributes directly from LIST command + if (!empty($this->conn->data['LIST']) && is_array($this->conn->data['LIST'][$mailbox])) { + $opts = $this->conn->data['LIST'][$mailbox]; } - - if (!is_array($this->conn->data['LIST']) || !is_array($this->conn->data['LIST'][$mailbox])) { - if ($force) { - $this->conn->listMailboxes('', $mailbox); - } - else { - return array(); - } + // get cached folder attributes + else if (!$force) { + $opts = $this->get_cache('mailboxes.attributes'); + $opts = $opts[$mailbox]; } - $opts = $this->conn->data['LIST'][$mailbox]; + if (!is_array($opts)) { + $this->conn->listMailboxes('', $mailbox); + $opts = $this->conn->data['LIST'][$mailbox]; + } return is_array($opts) ? $opts : array(); } @@ -3556,17 +3575,17 @@ class rcube_imap } } - $options['name'] = $mailbox; - $options['options'] = $this->mailbox_options($mailbox, true); - $options['namespace'] = $this->mailbox_namespace($mailbox); - $options['rights'] = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array(); - $options['special'] = in_array($mailbox, $this->default_folders); + $options['name'] = $mailbox; + $options['attributes'] = $this->mailbox_attributes($mailbox, true); + $options['namespace'] = $this->mailbox_namespace($mailbox); + $options['rights'] = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array(); + $options['special'] = in_array($mailbox, $this->default_folders); // Set 'noselect' and 'norename' flags - if (is_array($options['options'])) { - foreach ($options['options'] as $opt) { - $opt = strtolower($opt); - if ($opt == '\noselect' || $opt == '\nonexistent') { + if (is_array($options['attributes'])) { + foreach ($options['attributes'] as $attrib) { + $attrib = strtolower($attrib); + if ($attrib == '\noselect' || $attrib == '\nonexistent') { $options['noselect'] = true; } } diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index 5c7a41c73..f200e17ca 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -2258,13 +2258,11 @@ class rcube_imap_generic } // 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 () else if ($cmd == 'STATUS') { diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index 36a4b28ba..e9566f7aa 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -119,7 +119,8 @@ function rcmail_folder_form($attrib) 'realnames' => false, 'maxlength' => 150, 'unsubscribed' => true, - 'exceptions' => array($mbox_imap), + 'skip_noinferiors' => true, + 'exceptions' => array($mbox_imap), )); $form['props']['fieldsets']['location']['content']['path'] = array( diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 206f62c60..77cbb5571 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -283,8 +283,8 @@ function rcube_subscription_form($attrib) } if (!$protected) { - $opts = $IMAP->mailbox_options($folder['id']); - $noselect = in_array('\\Noselect', $opts); + $attrs = $IMAP->mailbox_attributes($folder['id']); + $noselect = in_array('\\Noselect', $attrs); } $disabled = (($protected && $subscribed) || $noselect); -- cgit v1.2.3