From: Michael M Slusarz Date: Tue, 24 Nov 2009 03:14:09 +0000 (-0700) Subject: Add support for RFC 5258 (LIST-EXTENDED) X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=6b07c0946c0090f19d0e05ed38582bf9c88b74e9;p=horde.git Add support for RFC 5258 (LIST-EXTENDED) --- diff --git a/framework/Imap_Client/lib/Horde/Imap/Client.php b/framework/Imap_Client/lib/Horde/Imap/Client.php index e2f8ba239..5ed7910f7 100644 --- a/framework/Imap_Client/lib/Horde/Imap/Client.php +++ b/framework/Imap_Client/lib/Horde/Imap/Client.php @@ -80,8 +80,9 @@ class Horde_Imap_Client /* Constants for listMailboxes() */ const MBOX_SUBSCRIBED = 1; - const MBOX_UNSUBSCRIBED = 2; - const MBOX_ALL = 3; + const MBOX_SUBSCRIBED_EXISTS = 2; + const MBOX_UNSUBSCRIBED = 3; + const MBOX_ALL = 4; /* Constants for status() */ const STATUS_MESSAGES = 1; diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Base.php b/framework/Imap_Client/lib/Horde/Imap/Client/Base.php index f314c051c..e6af0c781 100644 --- a/framework/Imap_Client/lib/Horde/Imap/Client/Base.php +++ b/framework/Imap_Client/lib/Horde/Imap/Client/Base.php @@ -811,13 +811,13 @@ abstract class Horde_Imap_Client_Base /** * Obtain a list of mailboxes matching a pattern. * - * @todo RFC 5258 extensions - * - * @param string $pattern The mailbox search pattern (see RFC 3501 - * [6.3.8] for the format). Either in UTF7-IMAP or + * @param mixed $pattern The mailbox search pattern(s) (see RFC 3501 + * [6.3.8] for the format). Either a string or an + * array of strings. Either in UTF7-IMAP or * UTF-8. * @param integer $mode Which mailboxes to return. Either * Horde_Imap_Client::MBOX_SUBSCRIBED, + * Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS, * Horde_Imap_Client::MBOX_UNSUBSCRIBED, or * Horde_Imap_Client::MBOX_ALL. * @param array $options Additional options: @@ -826,26 +826,43 @@ abstract class Horde_Imap_Client_Base * the 'attributes' key. The attributes will be returned * in an array with each attribute in lowercase. * DEFAULT: Do not return this information. - * 'utf8' - (boolean) True to return mailbox names in UTF-8. - * DEFAULT: Names are returned in UTF7-IMAP. + * 'children' - (boolean) Tell server to return children attribute + * information. Requires the LIST-EXTENDED extension. Server + * MAY return this autribute without this option, but it + * is not guaranteed. + * DEFAULT: false * 'delimiter' - (boolean) If true, return delimiter information under * the 'delimiter' key. * DEFAULT: Do not return this information. * 'flat' - (boolean) If true, return a flat list of mailbox names only. * Overrides both the 'attributes' and 'delimiter' options. * DEFAULT: Do not return flat list. + * 'recursivematch' - (boolean) Force the server to return information + * about parent mailboxes that don't match other + * selection options, but have some submailboxes that + * do. Information about children is returned in the + * CHILDINFO extended data item ('extended'). Requires + * the LIST-EXTENDED extension. + * DEFAULT: false + * 'remote' - (boolean) Tell server to return mailboxes that reside on + * another server. Requires the LIST-EXTENDED extension. + * DEFAULT: false * 'sort' - (boolean) If true, return a sorted list of mailboxes? * DEFAULT: Do not sort the list. * 'sort_delimiter' - (string) If 'sort' is true, this is the delimiter * used to sort the mailboxes. * DEFAULT: '.' + * 'utf8' - (boolean) True to return mailbox names in UTF-8. + * DEFAULT: Names are returned in UTF7-IMAP. * * * @return array If 'flat' option is true, the array values are the list * of mailboxes. Otherwise, the array values are arrays * with the following keys: 'mailbox', 'attributes' (only - * if 'attributes' option is true), and 'delimiter' (only - * if 'delimiter' option is true). + * if 'attributes' option is true), 'delimiter' (only + * if 'delimiter' option is true), and 'extended' (only + * if 'recursivematch' option is true and LIST-EXTENDED + * extension is supported on the server). * @throws Horde_Imap_Client_Exception */ public function listMailboxes($pattern, $mode = Horde_Imap_Client::MBOX_ALL, @@ -863,9 +880,9 @@ abstract class Horde_Imap_Client_Base /** * Obtain a list of mailboxes matching a pattern. * - * @param string $pattern The mailbox search pattern (UTF7-IMAP). - * @param integer $mode Which mailboxes to return. - * @param array $options Additional options. + * @param mixed $pattern The mailbox search pattern(s) (UTF7-IMAP). + * @param integer $mode Which mailboxes to return. + * @param array $options Additional options. * * @return array See self::listMailboxes(). * @throws Horde_Imap_Client_Exception diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Cclient.php b/framework/Imap_Client/lib/Horde/Imap/Client/Cclient.php index e89ecb892..1356ee6a4 100644 --- a/framework/Imap_Client/lib/Horde/Imap/Client/Cclient.php +++ b/framework/Imap_Client/lib/Horde/Imap/Client/Cclient.php @@ -421,9 +421,9 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base /** * Obtain a list of mailboxes matching a pattern. * - * @param string $pattern The mailbox search pattern. - * @param integer $mode Which mailboxes to return. - * @param array $options Additional options. + * @param mixed $pattern The mailbox search pattern(s). + * @param integer $mode Which mailboxes to return. + * @param array $options Additional options. *
      * For the 'attributes' option, this driver will return only these
      * attributes:
@@ -449,23 +449,33 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
 
         case Horde_Imap_Client::MBOX_SUBSCRIBED:
         case Horde_Imap_Client::MBOX_UNSUBSCRIBED:
+        case Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS:
             $sub = $this->_getMailboxList($pattern, Horde_Imap_Client::MBOX_SUBSCRIBED);
+            if ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS) {
+                $mboxes = $this->_getMailboxList($pattern, Horde_Imap_Client::MBOX_ALL);
+                $sub = array_intersect($sub, $mboxes);
+            }
+
             if (!empty($options['flat'])) {
                 if (!empty($options['utf8'])) {
                     $sub = array_map(array('Horde_Imap_Client_Utf7imap', 'Utf7ImapToUtf8'), $sub);
                 }
-                if ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) {
-                    return $sub;
+
+                if (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ||
+                    ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS)) {
+                    return array_values($sub);
                 }
 
                 $mboxes = $this->_getMailboxList($pattern, Horde_Imap_Client::MBOX_ALL);
+
                 if (!empty($options['utf8'])) {
-                    $sub = array_map(array('Horde_Imap_Client_Utf7imap', 'Utf7ImapToUtf8'), $sub);
+                    $mboxes = array_map(array('Horde_Imap_Client_Utf7imap', 'Utf7ImapToUtf8'), $mboxes);
                 }
                 return array_values(array_diff($mboxes, $sub));
             }
             $sub = array_flip($sub);
             $check = true;
+            break;
         }
 
         $attr = array(
@@ -519,15 +529,25 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
     /**
      * Obtain a list of mailboxes matching a pattern.
      *
-     * @param string $pattern  The mailbox search pattern.
-     * @param integer $mode    Which mailboxes to return.  Either
-     *                         Horde_Imap_Client::MBOX_SUBSCRIBED or
-     *                         Horde_Imap_Client::MBOX_ALL.
+     * @param mixed $pattern  The mailbox search patterns.
+     * @param integer $mode   Which mailboxes to return.  Either
+     *                        Horde_Imap_Client::MBOX_SUBSCRIBED or
+     *                        Horde_Imap_Client::MBOX_ALL.
      *
      * @return array  A list of mailboxes in UTF7-IMAP format.
      */
     protected function _getMailboxList($pattern, $mode)
     {
+        if (is_array($pattern)) {
+            $res = array();
+            foreach ($pattern as $val) {
+                if (strlen($val)) {
+                    $res = array_merge($res, $this->_getMailboxList($val, $mode);
+                }
+            }
+            return array_unique($res);
+        }
+
         $mboxes = array();
 
         $old_error = error_reporting(0);
diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php b/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php
index 724f779f1..f78c225f2 100644
--- a/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php
+++ b/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php
@@ -31,6 +31,7 @@
  *   RFC 5182 - SEARCHRES
  *   RFC 5255 - LANGUAGE/I18NLEVEL
  *   RFC 5256 - THREAD/SORT
+ *   RFC 5258 - LIST-EXTENDED
  *   RFC 5267 - ESORT
  *   RFC 5464 - METADATA
  *
@@ -49,7 +50,6 @@
  *   RFC 4469/5550 - CATENATE
  *   RFC 4978 - COMPRESS=DEFLATE
  *              See: http://bugs.php.net/bug.php?id=48725
- *   RFC 3348/5258 - LIST-EXTENDED
  *   RFC 5257 - ANNOTATE
  *   RFC 5259 - CONVERT
  *   RFC 5267 - CONTEXT
@@ -933,9 +933,9 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
     /**
      * Obtain a list of mailboxes matching a pattern.
      *
-     * @param string $pattern  The mailbox search pattern.
-     * @param integer $mode    Which mailboxes to return.
-     * @param array $options   Additional options.
+     * @param mixed $pattern  The mailbox search pattern(s).
+     * @param integer $mode   Which mailboxes to return.
+     * @param array $options  Additional options.
      *
      * @return array  See self::listMailboxes().
      * @throws Horde_Imap_Client_Exception
@@ -947,8 +947,12 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         // Get the list of subscribed/unsubscribed mailboxes. Since LSUB is
         // not guaranteed to have correct attributes, we must use LIST to
         // ensure we receive the correct information.
-        if ($mode != Horde_Imap_Client::MBOX_ALL) {
+        // TODO: Use LSUB for MBOX_SUBSCRIBED if no other options are
+        // set (RFC 5258 3.1)
+        if (($mode != Horde_Imap_Client::MBOX_ALL) &&
+            !$this->queryCapability('LIST-EXTENDED')) {
             $subscribed = $this->_getMailboxList($pattern, Horde_Imap_Client::MBOX_SUBSCRIBED, array('flat' => true));
+
             // If mode is subscribed, and 'flat' option is true, we can
             // return now.
             if (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) && !empty($options['flat'])) {
@@ -962,9 +966,9 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
     }
 
     /**
-     * Obtain a list of mailboxes matching a pattern.
+     * Obtain a list of mailboxes.
      *
-     * @param string $pattern    The mailbox search pattern.
+     * @param mixed $pattern     The mailbox search pattern(s).
      * @param integer $mode      Which mailboxes to return.
      * @param array $options     Additional options.
      * @param array $subscribed  A list of subscribed mailboxes.
@@ -981,14 +985,63 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $t = &$this->_temp;
         $t['mailboxlist'] = array(
             'check' => $check,
-            'subscribed' => $check ? array_flip($subscribed) : null,
-            'options' => $options
+            'options' => $options,
+            'subexist' => ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS),
+            'subscribed' => ($check ? array_flip($subscribed) : null)
         );
         $t['listresponse'] = array();
 
-        $this->_sendLine((($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST') . ' "" ' . $this->utils->escape($pattern));
+        if ($this->queryCapability('LIST-EXTENDED')) {
+            $cmd = 'LIST';
+
+            $return_opts = $select_opts = array();
+
+            if (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ||
+                ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS)) {
+                $select_opts[] = 'SUBSCRIBED';
+                $return_opts[] = 'SUBSCRIBED';
+            }
+
+            if (!empty($options['remote'])) {
+                $select_opts[] = 'REMOTE';
+            }
+
+            if (!empty($options['recursivematch'])) {
+                $select_opts[] = 'RECURSIVEMATCH';
+            }
+
+            if (!empty($select_opts)) {
+                $cmd .= ' (' . implode(' ', $select_opts) . ')';
+            }
+
+            $cmd .= ' "" ';
+
+            if (is_array($pattern)) {
+                $cmd .= '(';
+                foreach ($pattern as $val) {
+                    $cmd .= $this->utils->escape($pattern) . ' ';
+                }
+                $cmd = rtrim($cmd) . ')';
+            } else {
+                $cmd .= $this->utils->escape($pattern);
+            }
+
+            if (!empty($options['children'])) {
+                $return_opts[] = 'CHILDREN';
+            }
 
-        return (empty($options['flat'])) ? $t['listresponse'] : array_values($t['listresponse']);
+            if (!empty($return_opts)) {
+                $cmd .= ' RETURN (' . implode(' ', $return_opts) . ')';
+            }
+        } else {
+           $cmd = (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST') . ' "" ' . $this->utils->escape($pattern);
+        }
+
+        $this->_sendLine($cmd);
+
+        return empty($options['flat'])
+            ? $t['listresponse']
+            : array_values($t['listresponse']);
     }
 
     /**
@@ -1020,14 +1073,25 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             $mbox = Horde_Imap_Client_Utf7imap::Utf7ImapToUtf8($mbox);
         }
 
+        if ($ml['subexist'] ||
+            (empty($mlo['flat']) && !empty($mlo['attributes']))) {
+            $attr = array_map('strtolower', $data[1]);
+            if ($ml['subexist'] && in_array('\\nonexistent', $attr)) {
+                return;
+            }
+        }
+
         if (empty($mlo['flat'])) {
             $tmp = array('mailbox' => $mbox);
             if (!empty($mlo['attributes'])) {
-                $tmp['attributes'] = array_map('strtolower', $data[1]);
+                $tmp['attributes'] = $attr;
             }
             if (!empty($mlo['delimiter'])) {
                 $tmp['delimiter'] = $data[2];
             }
+            if (isset($data[4])) {
+                $tmp['extended'] = $data[4];
+            }
             $lr[$mbox] = $tmp;
         } else {
             $lr[] = $mbox;
diff --git a/framework/Imap_Client/package.xml b/framework/Imap_Client/package.xml
index 843a350a5..9d1164fc5 100644
--- a/framework/Imap_Client/package.xml
+++ b/framework/Imap_Client/package.xml
@@ -31,7 +31,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
   alpha
  
  LGPL
- * Add Horde_Imap_Client_Utils::createUrl().
+ * Add support for RFC 5258 (LIST-EXTENDED).
+ * Add Horde_Imap_Client_Utils::createUrl().
  * Support SORT=DISPLAY extension.
  * Added search and thread (message list) caching.
  * Added PHP socket based POP3 driver.