alecpl
2010-11-09 00290a603237e719cc4ec3db65e6661ba7d46a51
- Add support for shared folders (#1403507)


6 files modified
322 ■■■■■ changed files
CHANGELOG 1 ●●●● patch | view | raw | blame | history
config/main.inc.php.dist 12 ●●●● patch | view | raw | blame | history
installer/rcube_install.php 20 ●●●●● patch | view | raw | blame | history
program/include/rcmail.php 6 ●●●●● patch | view | raw | blame | history
program/include/rcube_imap.php 214 ●●●● patch | view | raw | blame | history
program/include/rcube_imap_generic.php 69 ●●●●● patch | view | raw | blame | history
CHANGELOG
@@ -65,6 +65,7 @@
- Improve responsiveness of messages displaying (#1486986)
- Add option for minimum length of autocomplete's string (#1486428)
- Fix operations on messages in unsubscribed folder (#1487107)
- Add support for shared folders (#1403507)
RELEASE 0.4.2
-------------
config/main.inc.php.dist
@@ -74,11 +74,17 @@
// best server supported one)
$rcmail_config['imap_auth_type'] = null;
// If you know your imap's root directory and its folder delimiter,
// you can specify them here. Otherwise they will be determined automatically.
$rcmail_config['imap_root'] = null;
// If you know your imap's folder delimiter, you can specify it here.
// Otherwise it will be determined automatically
$rcmail_config['imap_delimiter'] = null;
// If IMAP server doesn't support NAMESPACE extension, but you're
// using shared folders or personal root folder is non-empty, you'll need to
// set these options. All can be strings or arrays of strings.
$rcmail_config['imap_ns_personal'] = null;
$rcmail_config['imap_ns_other']    = null;
$rcmail_config['imap_ns_shared']   = null;
// By default IMAP capabilities are readed after connection to IMAP server
// In some cases, e.g. when using IMAP proxy, there's a need to refresh the list
// after login. Set to True if you've got this case.
installer/rcube_install.php
@@ -38,6 +38,7 @@
    'locale_string' => 'language',
    'multiple_identities' => 'identities_level',
    'addrbook_show_images' => 'show_images',
    'imap_root' => 'imap_ns_personal',
  );
  
  // these config options are required for a working system
@@ -169,16 +170,17 @@
      else if ($prop == 'smtp_pass' && !empty($_POST['_smtp_user_u'])) {
        $value = '%p';
      }
      else if ($prop == 'default_imap_folders'){
    $value = Array();
    foreach($this->config['default_imap_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;
      else if ($prop == 'default_imap_folders') {
        $value = Array();
        foreach ($this->config['default_imap_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;
        if (!in_array($_folder, $value))
          $value[] = $_folder;
        }
      }
      else if (is_bool($default)) {
program/include/rcmail.php
@@ -503,8 +503,6 @@
      'auth_method' => $this->config->get('imap_auth_type', 'check'),
      'auth_cid'    => $this->config->get('imap_auth_cid'),
      'auth_pw'     => $this->config->get('imap_auth_pw'),
      'delimiter'   => isset($_SESSION['imap_delimiter']) ? $_SESSION['imap_delimiter'] : $this->config->get('imap_delimiter'),
      'rootdir'     => isset($_SESSION['imap_root']) ? $_SESSION['imap_root'] : $this->config->get('imap_root'),
      'debug_mode'  => (bool) $this->config->get('imap_debug', 0),
      'force_caps'  => (bool) $this->config->get('imap_force_caps'),
      'timeout'     => (int) $this->config->get('imap_timeout', 0),
@@ -790,10 +788,6 @@
    if (isset($_SESSION['page'])) {
      $this->imap->set_page($_SESSION['page']);
    }
    // cache IMAP root and delimiter in session for performance reasons
    $_SESSION['imap_root'] = $this->imap->root_dir;
    $_SESSION['imap_delimiter'] = $this->imap->delimiter;
  }
program/include/rcube_imap.php
@@ -33,10 +33,8 @@
{
    public $debug_level = 1;
    public $skip_deleted = false;
    public $root_dir = '';
    public $page_size = 10;
    public $list_page = 1;
    public $delimiter = NULL;
    public $threading = false;
    public $fetch_add_headers = '';
    public $get_all_headers = false;
@@ -54,8 +52,9 @@
     * @var rcube_mdb2
     */
    private $db;
    private $root_ns = '';
    private $mailbox = 'INBOX';
    private $delimiter = NULL;
    private $namespace = NULL;
    private $sort_field = '';
    private $sort_order = 'DESC';
    private $caching_enabled = false;
@@ -156,18 +155,13 @@
        $this->port = $port;
        $this->ssl  = $use_ssl;
        // print trace messages
        if ($this->conn->connected()) {
            // print trace messages
            if ($this->conn->message && ($this->debug_level & 8)) {
                console($this->conn->message);
            }
            // get server properties
            $rootdir = $this->conn->getRootDir();
            if (!empty($rootdir))
                $this->set_rootdir($rootdir);
            if (empty($this->delimiter))
                $this->get_hierarchy_delimiter();
            // get namespace and delimiter
            $this->set_env();
            return true;
        }
@@ -243,28 +237,6 @@
    function set_options($opt)
    {
        $this->options = array_merge($this->options, (array)$opt);
    }
    /**
     * Set a root folder for the IMAP connection.
     *
     * Only folders within this root folder will be displayed
     * and all folder paths will be translated using this folder name
     *
     * @param  string   $root Root folder
     * @access public
     */
    function set_rootdir($root)
    {
        if (preg_match('/[.\/]$/', $root)) //(substr($root, -1, 1)==='/')
            $root = substr($root, 0, -1);
        $this->root_dir = $root;
        $this->options['rootdir'] = $root;
        if (empty($this->delimiter))
            $this->get_hierarchy_delimiter();
    }
@@ -482,13 +454,101 @@
     */
    function get_hierarchy_delimiter()
    {
        if ($this->conn && empty($this->delimiter))
            $this->delimiter = $this->conn->getHierarchyDelimiter();
        if (empty($this->delimiter))
            $this->delimiter = '/';
        return $this->delimiter;
    }
    /**
     * Get namespace
     *
     * @return  array  Namespace data
     * @access  public
     */
    function get_namespace()
    {
        return $this->namespace;
    }
    /**
     * Sets delimiter and namespaces
     *
     * @access private
     */
    private function set_env()
    {
        if ($this->delimiter !== null && $this->namespace !== null) {
            return;
        }
        if (isset($_SESSION['imap_namespace']) && isset($_SESSION['imap_delimiter'])) {
            $this->namespace = $_SESSION['imap_namespace'];
            $this->delimiter = $_SESSION['imap_delimiter'];
            return;
        }
        $config = rcmail::get_instance()->config;
        $imap_personal  = $config->get('imap_ns_personal');
        $imap_other     = $config->get('imap_ns_other');
        $imap_shared    = $config->get('imap_ns_shared');
        $imap_delimiter = $config->get('imap_delimiter');
        if ($imap_delimiter) {
            $this->delimiter = $imap_delimiter;
        }
        if (!$this->conn)
            return;
        $ns = $this->conn->getNamespace();
        // 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 = '/';
            $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_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);
                    }
                }
            }
        }
        $_SESSION['imap_namespace'] = $this->namespace;
        $_SESSION['imap_delimiter'] = $this->delimiter;
    }
@@ -891,7 +951,7 @@
        // flatten threads array
        // @TODO: fetch children only in expanded mode (?)
        $all_ids = array();
        foreach($msg_index as $root) {
        foreach ($msg_index as $root) {
            $all_ids[] = $root;
            if (!empty($thread_tree[$root]))
                $all_ids = array_merge($all_ids, array_keys_recursive($thread_tree[$root]));
@@ -1463,7 +1523,7 @@
        // flatten threads array
        $all_ids = array();
        foreach($msg_index as $root) {
        foreach ($msg_index as $root) {
            $all_ids[] = $root;
            if (!empty($thread_tree[$root])) {
                foreach (array_keys_recursive($thread_tree[$root]) as $val)
@@ -3073,10 +3133,11 @@
            $a_mboxes = explode(',', $mbox_name);
        if (is_array($a_mboxes)) {
            $delimiter = $this->get_hierarchy_delimiter();
            foreach ($a_mboxes as $mbox_name) {
                $mailbox = $this->mod_mailbox($mbox_name);
                $sub_mboxes = $this->conn->listMailboxes($this->mod_mailbox(''),
                    $mbox_name . $this->delimiter . '*');
                $sub_mboxes = $this->conn->listMailboxes('', $mbox_name . $delimiter . '*');
                // unsubscribe mailbox before deleting
                $this->conn->unsubscribe($mailbox);
@@ -3137,19 +3198,20 @@
            if ($mbox_name == 'INBOX')
                return true;
            $key = $subscription ? 'subscribed' : 'existing';
            if (is_array($this->icache[$key]) && in_array($mbox_name, $this->icache[$key]))
            $key  = $subscription ? 'subscribed' : 'existing';
            $mbox = $this->mod_mailbox($mbox_name)
            if (is_array($this->icache[$key]) && in_array($mbox, $this->icache[$key]))
                return true;
            if ($subscription) {
                $a_folders = $this->conn->listSubscribed($this->mod_mailbox(''), $mbox_name);
                $a_folders = $this->conn->listSubscribed('', $mbox);
            }
            else {
                $a_folders = $this->conn->listMailboxes($this->mod_mailbox(''), $mbox_name);
                $a_folders = $this->conn->listMailboxes('', $mbox);
            }
            if (is_array($a_folders) && in_array($this->mod_mailbox($mbox_name), $a_folders)) {
                $this->icache[$key][] = $mbox_name;
            if (is_array($a_folders) && in_array($mbox, $a_folders)) {
                $this->icache[$key][] = $mbox;
                return true;
            }
        }
@@ -3167,14 +3229,52 @@
     */
    function mod_mailbox($mbox_name, $mode='in')
    {
        if ($mbox_name == 'INBOX')
            return $mbox_name;
        if (empty($mbox_name))
            return '';
        if (!empty($this->root_dir)) {
            if ($mode=='in')
                $mbox_name = $this->root_dir.$this->delimiter.$mbox_name;
            else if (!empty($mbox_name)) // $mode=='out'
                $mbox_name = substr($mbox_name, strlen($this->root_dir)+1);
        if ($mode == 'in') {
            // 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 (strpos($mbox_name, $root[0]) === 0) {
                            return $mbox_name;
                        }
                    }
                }
            }
            if (is_array($this->namespace['other'])) {
                foreach ($this->namespace['other'] as $ns) {
                    foreach ((array)$ns as $root) {
                        if (strpos($mbox_name, $root[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;
                        }
                    }
                }
                // Add prefix if first personal namespace is non-empty
                if ($this->namespace['personal'][0][0]) {
                    return $this->namespace['personal'][0][0].$mbox_name;
                }
            }
        }
        else {
            // Remove prefix if folder is from first ("non-empty") personal namespace
            if (is_array($this->namespace['personal'])) {
                if ($prefix = $this->namespace['personal'][0][0]) {
                    if (strpos($mbox_name, $prefix) === 0) {
                        return substr($mbox_name, strlen($prefix));
                    }
                }
            }
        }
        return $mbox_name;
@@ -3200,7 +3300,7 @@
        if (!is_array($this->conn->data['LIST']) || !is_array($this->conn->data['LIST'][$mbox])) {
            if ($force) {
                $this->conn->listMailboxes($this->mod_mailbox(''), $mbox_name);
                $this->conn->listMailboxes('', $mbox_name);
            }
            else {
                return array();
program/include/rcube_imap_generic.php
@@ -549,53 +549,14 @@
    }
    /**
     * Gets the root directory and delimiter (of personal namespace)
     * Gets the delimiter
     *
     * @return mixed A root directory name, or false.
     */
    function getRootDir()
    {
        if (isset($this->prefs['rootdir']) && is_string($this->prefs['rootdir'])) {
            return $this->prefs['rootdir'];
        }
        if (!is_array($data = $this->getNamespace())) {
            return false;
        }
        $user_space_data = $data['personal'];
        if (!is_array($user_space_data)) {
            return false;
        }
        $first_userspace = $user_space_data[0];
        if (count($first_userspace) !=2) {
            return false;
        }
        $rootdir                  = $first_userspace[0];
        $this->prefs['delimiter'] = $first_userspace[1];
        $this->prefs['rootdir']   = $rootdir ? substr($rootdir, 0, -1) : '';
        return $this->prefs['rootdir'];
    }
    /**
     * Gets the delimiter, for example:
     * INBOX.foo -> .
     * INBOX/foo -> /
     * INBOX\foo -> \
     *
     * @return mixed A delimiter (string), or false.
     * @see connect()
     * @return string The delimiter
     */
    function getHierarchyDelimiter()
    {
        if ($this->prefs['delimiter']) {
            return $this->prefs['delimiter'];
        }
        if (!empty($this->prefs['delimiter'])) {
            return $this->prefs['delimiter'];
        }
        // try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
@@ -611,26 +572,7 @@
            }
        }
        // if that fails, try namespace extension
        // try to fetch namespace data
        if (!is_array($data = $this->getNamespace())) {
            return false;
        }
        // extract user space data (opposed to global/shared space)
        $user_space_data = $data['personal'];
        if (!is_array($user_space_data)) {
            return false;
        }
        // get first element
        $first_userspace = $user_space_data[0];
        if (!is_array($first_userspace)) {
            return false;
        }
        // extract delimiter
        return $this->prefs['delimiter'] = $first_userspace[1];
        return NULL;
    }
    /**
@@ -830,7 +772,6 @@
            if ($this->prefs['force_caps']) {
                $this->clearCapability();
            }
            $this->getRootDir();
            $this->logged = true;
            return true;
@@ -1941,10 +1882,6 @@
    {
        if (empty($mailbox)) {
            $mailbox = '*';
        }
        if (empty($ref) && $this->prefs['rootdir']) {
            $ref = $this->prefs['rootdir'];
        }
        $args = array();