add Horde_Imap_Client_Utils to replace static utility functions
authorChuck Hagenbuch <chuck@horde.org>
Thu, 15 Jan 2009 05:50:17 +0000 (00:50 -0500)
committerChuck Hagenbuch <chuck@horde.org>
Thu, 15 Jan 2009 05:55:07 +0000 (00:55 -0500)
Fix constant names since _Base doesn't extend H_I_C now.

framework/Imap_Client/lib/Horde/Imap/Client.php
framework/Imap_Client/lib/Horde/Imap/Client/Base.php
framework/Imap_Client/lib/Horde/Imap/Client/Cclient.php
framework/Imap_Client/lib/Horde/Imap/Client/Cclient/Pop3.php
framework/Imap_Client/lib/Horde/Imap/Client/Search/Query.php
framework/Imap_Client/lib/Horde/Imap/Client/Socket.php
framework/Imap_Client/lib/Horde/Imap/Client/Utils.php [new file with mode: 0644]
framework/Imap_Client/package.xml
framework/Imap_Client/test/Horde/Imap/test_client.php

index 6de60e6..09d2c60 100644 (file)
  *
  * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
  *
- * getBaseSubject() code adapted from imap-base-subject.c (Dovecot 1.2)
- *   Original code released under the LGPL v2.1
- *   Copyright (c) 2002-2008 Timo Sirainen <tss@iki.fi>
- *
  * See the enclosed file COPYING for license information (LGPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  *
index 9ea27db..41fe0e5 100644 (file)
@@ -62,9 +62,16 @@ abstract class Horde_Imap_Client_Base
     );
 
     /**
+     * The Horde_Imap_Client_Utils object
+     *
+     * @var Horde_Imap_Client_Utils
+     */
+    protected $_utils = null;
+
+    /**
      * The Horde_Imap_Client_Cache object.
      *
-     * @var Horde_Cache
+     * @var Horde_Imap_Client_Cache
      */
     protected $_cacheOb = null;
 
@@ -76,350 +83,6 @@ abstract class Horde_Imap_Client_Base
     protected $_debug = null;
 
     /**
-     * Create an IMAP message sequence string from a list of indices.
-     * Format: range_start:range_end,uid,uid2,range2_start:range2_end,...
-     *
-     * @param array $in  An array of indices.
-     * @param array $options  Additional options:
-     * <pre>
-     * 'nosort' - (boolean) Do not numerically sort the IDs before creating
-     *            the range?
-     *            DEFAULT: IDs are sorted
-     * </pre>
-     *
-     * @return string  The IMAP message sequence string.
-     */
-    static public function toSequenceString($ids, $options = array())
-    {
-        if (empty($ids)) {
-            return '';
-        }
-
-        // Make sure IDs are unique
-        $ids = array_keys(array_flip($ids));
-
-        if (empty($options['nosort'])) {
-            sort($ids, SORT_NUMERIC);
-        }
-
-        $first = $last = array_shift($ids);
-        $out = array();
-
-        foreach ($ids as $val) {
-            if ($last + 1 == $val) {
-                $last = $val;
-            } else {
-                $out[] = $first . ($last == $first ? '' : (':' . $last));
-                $first = $last = $val;
-            }
-        }
-        $out[] = $first . ($last == $first ? '' : (':' . $last));
-
-        return implode(',', $out);
-    }
-
-    /**
-     * Parse an IMAP message sequence string into a list of indices.
-     * Format: range_start:range_end,uid,uid2,range2_start:range2_end,...
-     *
-     * @param string $str  The IMAP message sequence string.
-     *
-     * @return array  An array of indices.
-     */
-    static public function fromSequenceString($str)
-    {
-        $ids = array();
-        $str = trim($str);
-
-        $idarray = explode(',', $str);
-        if (empty($idarray)) {
-            $idarray = array($str);
-        }
-
-        foreach ($idarray as $val) {
-            $range = array_map('intval', explode(':', $val));
-            if (count($range) == 1) {
-                $ids[] = $val;
-            } else {
-                list($low, $high) = ($range[0] < $range[1]) ? $range : array_reverse($range);
-                $ids = array_merge($ids, range($low, $high));
-            }
-        }
-
-        return $ids;
-    }
-
-    /**
-     * Remove "bare newlines" from a string.
-     *
-     * @param string $str  The original string.
-     *
-     * @return string  The string with all bare newlines removed.
-     */
-    static public function removeBareNewlines($str)
-    {
-        return str_replace(array("\r\n", "\n"), array("\n", "\r\n"), $str);
-    }
-
-    /**
-     * Escape IMAP output via a quoted string (see RFC 3501 [4.3]).
-     *
-     * @param string $str  The unescaped string.
-     *
-     * @return string  The escaped string.
-     */
-    static public function escape($str)
-    {
-        return '"' . addcslashes($str, '"\\') . '"';
-    }
-
-    /**
-     * Return the "base subject" defined in RFC 5256 [2.1].
-     *
-     * @param string $str     The original subject string.
-     * @param array $options  Additional options:
-     * <pre>
-     * 'keepblob' - (boolean) Don't remove any "blob" information (i.e. text
-     *              leading text between square brackets) from string.
-     * </pre>
-     *
-     * @return string  The cleaned up subject string.
-     */
-    static public function getBaseSubject($str, $options = array())
-    {
-        // Rule 1a: MIME decode to UTF-8 (if possible).
-        $str = Horde_Mime::decode($str, 'UTF-8');
-
-        // Rule 1b: Remove superfluous whitespace.
-        $str = preg_replace("/\s{2,}/", '', $str);
-
-        if (!$str) {
-            return '';
-        }
-
-        do {
-            /* (2) Remove all trailing text of the subject that matches the
-             * the subj-trailer ABNF, repeat until no more matches are
-             * possible. */
-            $str = preg_replace("/(?:\s*\(fwd\)\s*)+$/i", '', $str);
-
-            do {
-                /* (3) Remove all prefix text of the subject that matches the
-                 * subj-leader ABNF. */
-                $found = self::_removeSubjLeader($str, !empty($options['keepblob']));
-
-                /* (4) If there is prefix text of the subject that matches
-                 * the subj-blob ABNF, and removing that prefix leaves a
-                 * non-empty subj-base, then remove the prefix text. */
-                $found = (empty($options['keepblob']) && self::_removeBlobWhenNonempty($str)) || $found;
-
-                /* (5) Repeat (3) and (4) until no matches remain. */
-            } while ($found);
-
-            /* (6) If the resulting text begins with the subj-fwd-hdr ABNF and
-             * ends with the subj-fwd-trl ABNF, remove the subj-fwd-hdr and
-             * subj-fwd-trl and repeat from step (2). */
-        } while (self::_removeSubjFwdHdr($str));
-
-        return $str;
-    }
-
-    /**
-     * Parse an IMAP URL (RFC 5092).
-     *
-     * @param string $url  A IMAP URL string.
-     *
-     * @return mixed  False if the URL is invalid.  If valid, a URL with the
-     *                following fields:
-     * <pre>
-     * 'auth' - (string) The authentication method to use.
-     * 'port' - (integer) The remote port
-     * 'hostspec' - (string) The remote server
-     * 'username' - (string) The username to use on the remote server.
-     * </pre>
-     */
-    static public function parseImapUrl($url)
-    {
-        $url = trim($url);
-        if (stripos($url, 'imap://') !== 0) {
-            return false;
-        }
-        $url = substr($url, 7);
-
-        /* At present, only support imap://<iserver>[/] style URLs. */
-        if (($pos = strpos($url, '/')) !== false) {
-            $url = substr($url, 0, $pos);
-        }
-
-        $ret_array = array();
-
-        /* Check for username/auth information. */
-        if (($pos = strpos($url, '@')) !== false) {
-            if ((($apos = stripos($url, ';AUTH=')) !== false) &&
-                ($apos < $pos)) {
-                $auth = substr($url, $apos + 6, $pos - $apos - 6);
-                if ($auth != '*') {
-                    $ret_array['auth'] = $auth;
-                }
-                if ($apos) {
-                    $ret_array['username'] = substr($url, 0, $apos);
-                }
-            }
-            $url = substr($url, $pos + 1);
-        }
-
-        /* Check for port information. */
-        if (($pos = strpos($url, ':')) !== false) {
-            $ret_array['port'] = substr($url, $pos + 1);
-            $url = substr($url, 0, $pos);
-        }
-
-        $ret_array['hostspec'] = $url;
-
-        return $ret_array;
-    }
-
-    /**
-     * Remove all prefix text of the subject that matches the subj-leader
-     * ABNF.
-     *
-     * @param string &$str       The subject string.
-     * @param boolean $keepblob  Remove blob information?
-     *
-     * @return boolean  True if string was altered.
-     */
-    static protected function _removeSubjLeader(&$str, $keepblob = false)
-    {
-        $ret = false;
-
-        if (!$str) {
-            return $ret;
-        }
-
-        if ($str[0] == ' ') {
-            $str = substr($str, 1);
-            $ret = true;
-        }
-
-        $i = 0;
-
-        if (!$keepblob) {
-            while ($str[$i] == '[') {
-                if (($i = self::_removeBlob($str, $i)) === false) {
-                    return $ret;
-                }
-            }
-        }
-
-        $cmp_str = substr($str, $i);
-        if (stripos($cmp_str, 're') === 0) {
-            $i += 2;
-        } elseif (stripos($cmp_str, 'fwd') === 0) {
-            $i += 3;
-        } elseif (stripos($cmp_str, 'fw') === 0) {
-            $i += 2;
-        } else {
-            return $ret;
-        }
-
-        if ($str[$i] == ' ') {
-            ++$i;
-        }
-
-        if (!$keepblob) {
-            while ($str[$i] == '[') {
-                if (($i = self::_removeBlob($str, $i)) === false) {
-                    return $ret;
-                }
-            }
-        }
-
-        if ($str[$i] != ':') {
-            return $ret;
-        }
-
-        $str = substr($str, ++$i);
-
-        return true;
-    }
-
-    /**
-     * Remove "[...]" text.
-     *
-     * @param string &$str  The subject string.
-     *
-     * @return boolean  True if string was altered.
-     */
-    static protected function _removeBlob($str, $i)
-    {
-        if ($str[$i] != '[') {
-            return false;
-        }
-
-        ++$i;
-
-        for ($cnt = strlen($str); $i < $cnt; ++$i) {
-            if ($str[$i] == ']') {
-                break;
-            }
-
-            if ($str[$i] == '[') {
-                return false;
-            }
-        }
-
-        if ($i == ($cnt - 1)) {
-            return false;
-        }
-
-        ++$i;
-
-        if ($str[$i] == ' ') {
-            ++$i;
-        }
-
-        return $i;
-    }
-
-    /**
-     * Remove "[...]" text if it doesn't result in the subject becoming
-     * empty.
-     *
-     * @param string &$str  The subject string.
-     *
-     * @return boolean  True if string was altered.
-     */
-    static protected function _removeBlobWhenNonempty(&$str)
-    {
-        if ($str &&
-            ($str[0] == '[') &&
-            (($i = self::_removeBlob($str, 0)) !== false) &&
-            ($i != strlen($str))) {
-            $str = substr($str, $i);
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Remove a "[fwd: ... ]" string.
-     *
-     * @param string &$str  The subject string.
-     *
-     * @return boolean  True if string was altered.
-     */
-    static protected function _removeSubjFwdHdr(&$str)
-    {
-        if ((stripos($str, '[fwd:') !== 0) || (substr($str, -1) != ']')) {
-            return false;
-        }
-
-        $str = substr($str, 5, -1);
-        return true;
-    }
-
-    /**
      * Constructs a new Horde_Imap_Client object.
      * Throws a Horde_Imap_Client_Exception on error.
      *
@@ -448,11 +111,11 @@ abstract class Horde_Imap_Client_Base
             $params['cache'] = array('fields' => array());
         } elseif (empty($params['cache']['fields'])) {
             $params['cache']['fields'] = array(
-                self::FETCH_STRUCTURE => 1,
-                self::FETCH_ENVELOPE => 1,
-                self::FETCH_FLAGS => 1,
-                self::FETCH_DATE => 1,
-                self::FETCH_SIZE => 1
+                Horde_Imap_Client::FETCH_STRUCTURE => 1,
+                Horde_Imap_Client::FETCH_ENVELOPE => 1,
+                Horde_Imap_Client::FETCH_FLAGS => 1,
+                Horde_Imap_Client::FETCH_DATE => 1,
+                Horde_Imap_Client::FETCH_SIZE => 1
             );
         } else {
             $params['cache']['fields'] = array_flip($params['cache']['fields']);
@@ -460,6 +123,8 @@ abstract class Horde_Imap_Client_Base
 
         $this->_params = $params;
 
+        $this->_utils = new Horde_Imap_Client_Utils();
+
         // This will initialize debugging, if needed.
         $this->__wakeup();
     }
@@ -674,7 +339,7 @@ abstract class Horde_Imap_Client_Base
                 continue;
             }
 
-            $mbox = $this->listMailboxes($val, self::MBOX_ALL, array('delimiter' => true));
+            $mbox = $this->listMailboxes($val, Horde_Imap_Client::MBOX_ALL, array('delimiter' => true));
             $first = reset($mbox);
 
             if ($first && ($first['mailbox'] == $val)) {
@@ -691,7 +356,7 @@ abstract class Horde_Imap_Client_Base
             /* This accurately determines the namespace information of the
              * base namespace if the NAMESPACE command is not supported.
              * See: RFC 3501 [6.3.8] */
-            $mbox = $this->listMailboxes('', self::MBOX_ALL, array('delimiter' => true));
+            $mbox = $this->listMailboxes('', Horde_Imap_Client::MBOX_ALL, array('delimiter' => true));
             $first = reset($mbox);
             $ns[''] = array(
                 'name' => '',
@@ -766,9 +431,9 @@ abstract class Horde_Imap_Client_Base
             }
 
             /* Check for ability to cache flags here. */
-            if (isset($this->_params['cache']['fields'][self::FETCH_FLAGS]) &&
+            if (isset($this->_params['cache']['fields'][Horde_Imap_Client::FETCH_FLAGS]) &&
                 !isset($this->_init['enabled']['CONDSTORE'])) {
-                unset($this->_params['cache']['fields'][self::FETCH_FLAGS]);
+                unset($this->_params['cache']['fields'][Horde_Imap_Client::FETCH_FLAGS]);
             }
         }
 
@@ -927,15 +592,15 @@ abstract class Horde_Imap_Client_Base
      *                         Horde_Imap_Client::OPEN_READWRITE, or
      *                         Horde_Imap_Client::OPEN_AUTO.
      */
-    public function openMailbox($mailbox, $mode = self::OPEN_AUTO)
+    public function openMailbox($mailbox, $mode = Horde_Imap_Client::OPEN_AUTO)
     {
         $change = false;
 
         $mailbox = Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($mailbox);
 
-        if ($mode == self::OPEN_AUTO) {
+        if ($mode == Horde_Imap_Client::OPEN_AUTO) {
             if (is_null($this->_selected) || ($this->_selected != $mailbox)) {
-                $mode = self::OPEN_READONLY;
+                $mode = Horde_Imap_Client::OPEN_READONLY;
                 $change = true;
             }
         } elseif (is_null($this->_selected) ||
@@ -1052,7 +717,7 @@ abstract class Horde_Imap_Client_Base
         $new = Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($new);
 
         /* Check if old mailbox was subscribed to. */
-        $subscribed = $this->listMailboxes($old, self::MBOX_SUBSCRIBED, array('flat' => true));
+        $subscribed = $this->listMailboxes($old, Horde_Imap_Client::MBOX_SUBSCRIBED, array('flat' => true));
 
         $this->_renameMailbox($old, $new);
 
@@ -1143,7 +808,7 @@ abstract class Horde_Imap_Client_Base
      *                if 'attributes' option is true), and 'delimiter' (only
      *                if 'delimiter' option is true).
      */
-    public function listMailboxes($pattern, $mode = self::MBOX_ALL,
+    public function listMailboxes($pattern, $mode = Horde_Imap_Client::MBOX_ALL,
                                   $options = array())
     {
         $ret = $this->_listMailboxes(Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($pattern), $mode, $options);
@@ -1236,15 +901,15 @@ abstract class Horde_Imap_Client_Base
      *
      * @return array  An array with the requested keys (see above).
      */
-    public function status($mailbox, $flags = self::STATUS_ALL)
+    public function status($mailbox, $flags = Horde_Imap_Client::STATUS_ALL)
     {
-        if ($flags & self::STATUS_ALL) {
-            $flags |= self::STATUS_MESSAGES | self::STATUS_RECENT | self::STATUS_UNSEEN | self::STATUS_UIDNEXT | self::STATUS_UIDVALIDITY;
+        if ($flags & Horde_Imap_Client::STATUS_ALL) {
+            $flags |= Horde_Imap_Client::STATUS_MESSAGES | Horde_Imap_Client::STATUS_RECENT | Horde_Imap_Client::STATUS_UNSEEN | Horde_Imap_Client::STATUS_UIDNEXT | Horde_Imap_Client::STATUS_UIDVALIDITY;
         }
 
         /* STATUS_PERMFLAGS requires a read/write mailbox. */
-        if ($flags & self::STATUS_PERMFLAGS) {
-            $this->openMailbox($mailbox, self::OPEN_READWRITE);
+        if ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) {
+            $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_READWRITE);
         }
 
         return $this->_status(Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($mailbox), $flags);
@@ -1258,7 +923,7 @@ abstract class Horde_Imap_Client_Base
      * @param string $flags    A bitmask of information requested from the
      *                         server.
      *
-     * @return array  See Horde_Imap_Client_Base::status().
+     * @return array  See self::status().
      */
     abstract protected function _status($mailbox, $flags);
 
@@ -1425,7 +1090,7 @@ abstract class Horde_Imap_Client_Base
      */
     public function expunge($mailbox, $options = array())
     {
-        $this->openMailbox($mailbox, self::OPEN_READWRITE);
+        $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_READWRITE);
         $this->_expunge($options);
     }
 
@@ -1517,12 +1182,12 @@ abstract class Horde_Imap_Client_Base
      */
     public function search($mailbox, $query = null, $options = array())
     {
-        $this->openMailbox($mailbox, self::OPEN_AUTO);
+        $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_AUTO);
 
         if (empty($options['results'])) {
             $options['results'] = array(
-                self::SORT_RESULTS_MATCH,
-                self::SORT_RESULTS_COUNT
+                Horde_Imap_Client::SORT_RESULTS_MATCH,
+                Horde_Imap_Client::SORT_RESULTS_COUNT
             );
         }
 
@@ -1538,14 +1203,14 @@ abstract class Horde_Imap_Client_Base
          * optimize with unseen queries because we may cause an infinite loop
          * between here and the status() call. */
         if ((count($options['results']) == 1) &&
-            (reset($options['results']) == self::SORT_RESULTS_COUNT)) {
+            (reset($options['results']) == Horde_Imap_Client::SORT_RESULTS_COUNT)) {
             switch ($options['_query']['query']) {
             case 'ALL':
-                $ret = $this->status($this->_selected, self::STATUS_MESSAGES);
+                $ret = $this->status($this->_selected, Horde_Imap_Client::STATUS_MESSAGES);
                 return array('count' => $ret['messages']);
 
             case 'RECENT':
-                $ret = $this->status($this->_selected, self::STATUS_RECENT);
+                $ret = $this->status($this->_selected, Horde_Imap_Client::STATUS_RECENT);
                 return array('count' => $ret['recent']);
             }
         }
@@ -1662,7 +1327,7 @@ abstract class Horde_Imap_Client_Base
      */
     public function thread($mailbox, $options = array())
     {
-        $this->openMailbox($mailbox, self::OPEN_AUTO);
+        $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_AUTO);
 
         $ret = $this->_thread($options);
         return new Horde_Imap_Client_Thread($ret, empty($options['sequence']) ? 'uid' : 'sequence');
@@ -2052,13 +1717,13 @@ abstract class Horde_Imap_Client_Base
 
         /* If using cache, we store by UID so we need to return UIDs. */
         if ($seq && !empty($cf)) {
-            $criteria[self::FETCH_UID] = true;
+            $criteria[Horde_Imap_Client::FETCH_UID] = true;
         }
 
-        $this->openMailbox($mailbox, self::OPEN_AUTO);
+        $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_AUTO);
 
         /* We need the UIDVALIDITY for the current mailbox. */
-        $status_res = $this->status($this->_selected, self::STATUS_HIGHESTMODSEQ | self::STATUS_UIDVALIDITY);
+        $status_res = $this->status($this->_selected, Horde_Imap_Client::STATUS_HIGHESTMODSEQ | Horde_Imap_Client::STATUS_UIDVALIDITY);
 
         /* Determine if caching is available and if anything in $criteria is
          * cacheable. Do some sanity checking on criteria also. */
@@ -2066,7 +1731,7 @@ abstract class Horde_Imap_Client_Base
             $cache_field = null;
 
             switch ($k) {
-            case self::FETCH_STRUCTURE:
+            case Horde_Imap_Client::FETCH_STRUCTURE:
                 /* Don't cache if 'noext' is present. It will probably be a
                  * rare event anyway. */
                 if (empty($v['noext']) && isset($cf[$k])) {
@@ -2077,20 +1742,20 @@ abstract class Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_BODYPARTSIZE:
+            case Horde_Imap_Client::FETCH_BODYPARTSIZE:
                 if (!$this->queryCapability('BINARY')) {
                     unset($criteria[$k]);
                 }
                 break;
 
-            case self::FETCH_ENVELOPE:
+            case Horde_Imap_Client::FETCH_ENVELOPE:
                 if (isset($cf[$k])) {
                     $cache_field = 'HICenv';
                     $fetch_field = 'envelope';
                 }
                 break;
 
-            case self::FETCH_FLAGS:
+            case Horde_Imap_Client::FETCH_FLAGS:
                 if (isset($cf[$k])) {
                     /* QRESYNC would have already done syncing on mailbox
                      * open, so no need to do again. */
@@ -2102,7 +1767,7 @@ abstract class Horde_Imap_Client_Base
                             ($metadata['HICmodseq'] != $status_res['highestmodseq'])) {
                             $uids = $this->_cacheOb->get($this->_selected, array(), array(), $status_res['uidvalidity']);
                             if (!empty($uids)) {
-                                $this->_fetch(array(self::FETCH_FLAGS => true), array('changedsince' => $metadata['HICmodseq'], 'ids' => $uids));
+                                $this->_fetch(array(Horde_Imap_Client::FETCH_FLAGS => true), array('changedsince' => $metadata['HICmodseq'], 'ids' => $uids));
                             }
                             $this->_cacheOb->setMetaData($mailbox, array('HICmodseq' => $status_res['highestmodseq']));
                         }
@@ -2113,21 +1778,21 @@ abstract class Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_DATE:
+            case Horde_Imap_Client::FETCH_DATE:
                 if (isset($cf[$k])) {
                     $cache_field = 'HICdate';
                     $fetch_field = 'date';
                 }
                 break;
 
-            case self::FETCH_SIZE:
+            case Horde_Imap_Client::FETCH_SIZE:
                 if (isset($cf[$k])) {
                     $cache_field = 'HICsize';
                     $fetch_field = 'size';
                 }
                 break;
 
-            case self::FETCH_MODSEQ:
+            case Horde_Imap_Client::FETCH_MODSEQ:
                 if (!isset($this->_init['enabled']['CONDSTORE'])) {
                     unset($criteria[$k]);
                 }
@@ -2183,7 +1848,7 @@ abstract class Horde_Imap_Client_Base
             }
 
             if (!$seq) {
-                unset($crit[self::FETCH_UID]);
+                unset($crit[Horde_Imap_Client::FETCH_UID]);
             }
 
             if (!empty($crit)) {
@@ -2260,7 +1925,7 @@ abstract class Horde_Imap_Client_Base
      */
     public function store($mailbox, $options = array())
     {
-        $this->openMailbox($mailbox, self::OPEN_READWRITE);
+        $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_READWRITE);
 
         if (!empty($options['unchangedsince']) &&
             !isset($this->_init['enabled']['CONDSTORE'])) {
@@ -2276,7 +1941,7 @@ abstract class Horde_Imap_Client_Base
      *
      * @param array $options  Additional options.
      *
-     * @return array  See Horde_Imap_Client::store().
+     * @return array  See self::store().
      */
     abstract protected function _store($options);
 
@@ -2306,7 +1971,7 @@ abstract class Horde_Imap_Client_Base
      */
     public function copy($source, $dest, $options = array())
     {
-        $this->openMailbox($source, empty($options['move']) ? self::OPEN_AUTO : self::OPEN_READWRITE);
+        $this->openMailbox($source, empty($options['move']) ? Horde_Imap_Client::OPEN_AUTO : Horde_Imap_Client::OPEN_READWRITE);
         return $this->_copy(Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($dest), $options);
     }
 
@@ -2570,7 +2235,7 @@ abstract class Horde_Imap_Client_Base
     {
         $search = new Horde_Imap_Client_Search_Query();
         $search->sequence($ids, $seq);
-        $res = $this->search($this->_selected, $search, array('sort' => array(self::SORT_ARRIVAL)));
+        $res = $this->search($this->_selected, $search, array('sort' => array(Horde_Imap_Client::SORT_ARRIVAL)));
         $ret = array('uids' => $res['sort']);
         if ($seq) {
             if (empty($ids)) {
@@ -2615,7 +2280,7 @@ abstract class Horde_Imap_Client_Base
         $mailbox = empty($options['mailbox']) ? $this->_selected : $options['mailbox'];
 
         if (empty($options['uidvalid'])) {
-            $status_res = $this->status($mailbox, self::STATUS_HIGHESTMODSEQ | self::STATUS_UIDVALIDITY);
+            $status_res = $this->status($mailbox, Horde_Imap_Client::STATUS_HIGHESTMODSEQ | Horde_Imap_Client::STATUS_UIDVALIDITY);
             $uidvalid = $status_res['uidvalidity'];
             if (isset($status_res['highestmodseq'])) {
                 $highestmodseq[] = $status_res['highestmodseq'];
@@ -2633,19 +2298,19 @@ abstract class Horde_Imap_Client_Base
             while (list($label, $val) = each($v)) {
                 switch ($label) {
                 case 'structure':
-                    if (isset($cf[self::FETCH_STRUCTURE])) {
+                    if (isset($cf[Horde_Imap_Client::FETCH_STRUCTURE])) {
                         $tmp[is_array($val) ? 'HICstructa' : 'HICstructm'] = $val;
                     }
                     break;
 
                 case 'envelope':
-                    if (isset($cf[self::FETCH_ENVELOPE])) {
+                    if (isset($cf[Horde_Imap_Client::FETCH_ENVELOPE])) {
                         $tmp['HICenv'] = $val;
                     }
                     break;
 
                 case 'flags':
-                    if (isset($cf[self::FETCH_FLAGS])) {
+                    if (isset($cf[Horde_Imap_Client::FETCH_FLAGS])) {
                         /* A FLAGS FETCH can only occur if we are in the
                          * mailbox. So either HIGHESTMODSEQ has already been
                          * updated or the flag FETCHs will provide the new
@@ -2664,13 +2329,13 @@ abstract class Horde_Imap_Client_Base
                     break;
 
                 case 'date':
-                    if (isset($cf[self::FETCH_DATE])) {
+                    if (isset($cf[Horde_Imap_Client::FETCH_DATE])) {
                         $tmp['HICdate'] = $val;
                     }
                     break;
 
                 case 'size':
-                    if (isset($cf[self::FETCH_SIZE])) {
+                    if (isset($cf[Horde_Imap_Client::FETCH_SIZE])) {
                         $tmp['HICsize'] = $val;
                     }
                     break;
index cf6c4f8..b9c071e 100644 (file)
@@ -314,7 +314,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
     protected function _openMailbox($mailbox, $mode)
     {
         $this->login();
-        $flag = ($mode == self::OPEN_READONLY) ? OP_READONLY : 0;
+        $flag = ($mode == Horde_Imap_Client::OPEN_READONLY) ? OP_READONLY : 0;
 
         $old_error = error_reporting(0);
         if (version_compare(PHP_VERSION, '5.2.1') != -1) {
@@ -432,7 +432,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
         $this->login();
 
         switch ($mode) {
-        case self::MBOX_ALL:
+        case Horde_Imap_Client::MBOX_ALL:
             if (!empty($options['flat'])) {
                 $mboxes = $this->_getMailboxList($pattern, $mode);
                 return (empty($options['utf8'])) ? $mboxes : array_map(array('Horde_Imap_Client_Utf7imap', 'Utf7ImapToUtf8'), $mboxes);
@@ -440,18 +440,18 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
             $check = false;
             break;
 
-        case self::MBOX_SUBSCRIBED:
-        case self::MBOX_UNSUBSCRIBED:
-            $sub = $this->_getMailboxList($pattern, self::MBOX_SUBSCRIBED);
+        case Horde_Imap_Client::MBOX_SUBSCRIBED:
+        case Horde_Imap_Client::MBOX_UNSUBSCRIBED:
+            $sub = $this->_getMailboxList($pattern, Horde_Imap_Client::MBOX_SUBSCRIBED);
             if (!empty($options['flat'])) {
                 if (!empty($options['utf8'])) {
                     $sub = array_map(array('Horde_Imap_Client_Utf7imap', 'Utf7ImapToUtf8'), $sub);
                 }
-                if ($mode == self::MBOX_SUBSCRIBED) {
+                if ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) {
                     return $sub;
                 }
 
-                $mboxes = $this->_getMailboxList($pattern, self::MBOX_ALL);
+                $mboxes = $this->_getMailboxList($pattern, Horde_Imap_Client::MBOX_ALL);
                 if (!empty($options['utf8'])) {
                     $sub = array_map(array('Horde_Imap_Client_Utf7imap', 'Utf7ImapToUtf8'), $sub);
                 }
@@ -480,9 +480,9 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
             $mbox = substr($val->name, strpos($val->name, '}') + 1);
 
             if ($check &&
-                ((($mode == self::MBOX_UNSUBSCRIBED) &&
+                ((($mode == Horde_Imap_Client::MBOX_UNSUBSCRIBED) &&
                   isset($sub[$mbox])) ||
-                 (($mode == self::MBOX_SUBSCRIBED) &&
+                 (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) &&
                   !isset($sub[$mbox])))) {
                 continue;
             }
@@ -524,7 +524,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
         $mboxes = array();
 
         $old_error = error_reporting(0);
-        if ($mode != self::MBOX_ALL) {
+        if ($mode != Horde_Imap_Client::MBOX_ALL) {
             $res = imap_list($this->_stream, $this->_connString(), $pattern);
         } else {
             $res = imap_lsub($this->_stream, $this->_connString(), $pattern);
@@ -556,19 +556,19 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
 
         /* If FLAGS/PERMFLAGS/HIGHESTMODSEQ/UIDNOTSTICKY are needed, we must
          * use the Socket driver. */
-        if (($flags & self::STATUS_FLAGS) ||
-            ($flags & self::STATUS_PERMFLAGS) ||
-            ($flags & self::STATUS_HIGHESTMODSEQ) ||
-            ($flags & self::STATUS_UIDNOTSTICKY)) {
+        if (($flags & Horde_Imap_Client::STATUS_FLAGS) ||
+            ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) ||
+            ($flags & Horde_Imap_Client::STATUS_HIGHESTMODSEQ) ||
+            ($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY)) {
             return $this->_getSocket()->status($mailbox, $flags);
         }
 
         $items = array(
-            self::STATUS_MESSAGES => SA_MESSAGES,
-            self::STATUS_RECENT => SA_RECENT,
-            self::STATUS_UIDNEXT => SA_UIDNEXT,
-            self::STATUS_UIDVALIDITY => SA_UIDVALIDITY,
-            self::STATUS_UNSEEN => SA_UNSEEN
+            Horde_Imap_Client::STATUS_MESSAGES => SA_MESSAGES,
+            Horde_Imap_Client::STATUS_RECENT => SA_RECENT,
+            Horde_Imap_Client::STATUS_UIDNEXT => SA_UIDNEXT,
+            Horde_Imap_Client::STATUS_UIDVALIDITY => SA_UIDVALIDITY,
+            Horde_Imap_Client::STATUS_UNSEEN => SA_UNSEEN
         );
 
         $c_flag = 0;
@@ -587,10 +587,10 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
             }
         }
 
-        if ($flags & self::STATUS_FIRSTUNSEEN) {
+        if ($flags & Horde_Imap_Client::STATUS_FIRSTUNSEEN) {
             $search_query = new Horde_Imap_Client_Search_Query();
             $search_query->flag('\\unseen', false);
-            $search = $this->search($mailbox, $search_query, array('results' => array(self::SORT_RESULTS_MIN), 'sequence' => true));
+            $search = $this->search($mailbox, $search_query, array('results' => array(Horde_Imap_Client::SORT_RESULTS_MIN), 'sequence' => true));
 
             if (is_null($res)) {
                 return array('firstunseen' => $search['min']);
@@ -635,7 +635,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
         while (list(,$val) = each($data)) {
             $old_error = error_reporting(0);
             $text = is_resource($val['data']) ? stream_get_contents($val['data']) : $val['data'];
-            $res = imap_append($this->_stream, $this->_connString($mailbox), $this->removeBareNewlines($text), empty($val['flags']) ? null : implode(' ', $val['flags']));
+            $res = imap_append($this->_stream, $this->_connString($mailbox), $this->_utils->removeBareNewlines($text), empty($val['flags']) ? null : implode(' ', $val['flags']));
             error_reporting($old_error);
 
             if ($res === false) {
@@ -680,7 +680,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
         if (!empty($options['expunge'])) {
             $this->expunge($this->_selected);
         }
-        $this->openMailbox($this->_selected, self::OPEN_READONLY);
+        $this->openMailbox($this->_selected, Horde_Imap_Client::OPEN_READONLY);
     }
 
     /**
@@ -759,7 +759,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
         if ($options['_query']['imap4'] ||
             (!empty($options['sort']) &&
              ((count($options['sort']) > 1) ||
-             in_array(self::SORT_REVERSE, $options['sort'])))) {
+             in_array(Horde_Imap_Client::SORT_REVERSE, $options['sort'])))) {
             return $this->_getSocket()->search($this->_selected, $query, $options);
         }
 
@@ -768,13 +768,13 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
             $res = imap_search($this->_stream, $options['_query']['query'], empty($options['sequence']) ? SE_UID : 0, $options['_query']['charset']);
         } else {
             $sort_criteria = array(
-                self::SORT_ARRIVAL => SORTARRIVAL,
-                self::SORT_CC => SORTCC,
-                self::SORT_DATE => SORTDATE,
-                self::SORT_FROM => SORTFROM,
-                self::SORT_SIZE => SORTSIZE,
-                self::SORT_SUBJECT => SORTSUBJECT,
-                self::SORT_TO => SORTTO
+                Horde_Imap_Client::SORT_ARRIVAL => SORTARRIVAL,
+                Horde_Imap_Client::SORT_CC => SORTCC,
+                Horde_Imap_Client::SORT_DATE => SORTDATE,
+                Horde_Imap_Client::SORT_FROM => SORTFROM,
+                Horde_Imap_Client::SORT_SIZE => SORTSIZE,
+                Horde_Imap_Client::SORT_SUBJECT => SORTSUBJECT,
+                Horde_Imap_Client::SORT_TO => SORTTO
             );
 
             $res = imap_sort($this->_stream, $sort_criteria[reset($options['sort'])], 0, empty($options['sequence']) ? SE_UID : 0, $options['_query']['query'], $options['_query']['charset']);
@@ -785,19 +785,19 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
         $ret = array();
         foreach ($options['results'] as $val) {
             switch ($val) {
-            case self::SORT_RESULTS_COUNT:
+            case Horde_Imap_Client::SORT_RESULTS_COUNT:
                 $ret['count'] = count($res);
                 break;
 
-            case self::SORT_RESULTS_MATCH:
+            case Horde_Imap_Client::SORT_RESULTS_MATCH:
                 $ret[empty($options['sort']) ? 'match' : 'sort'] = $res;
                 break;
 
-            case self::SORT_RESULTS_MAX:
+            case Horde_Imap_Client::SORT_RESULTS_MAX:
                 $ret['max'] = empty($res) ? null : max($res);
                 break;
 
-            case self::SORT_RESULTS_MIN:
+            case Horde_Imap_Client::SORT_RESULTS_MIN:
                 $ret['min'] = empty($res) ? null : min($res);
                 break;
             }
@@ -848,7 +848,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
          * and does not support defining search criteria. */
         if (!empty($options['search']) ||
             (!empty($options['criteria']) &&
-             $options['criteria'] != self::THREAD_REFERENCES)) {
+             $options['criteria'] != Horde_Imap_Client::THREAD_REFERENCES)) {
             return $this->_getSocket()->thread($this->_selected, $options);
         }
 
@@ -944,7 +944,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
 
         // These options are not supported by this driver.
         if (!empty($options['changedsince']) ||
-            (reset($options['ids']) == self::USE_SEARCHRES)) {
+            (reset($options['ids']) == Horde_Imap_Client::USE_SEARCHRES)) {
             return $this->_getSocket()->fetch($this->_selected, $criteria, $options);
         }
 
@@ -952,7 +952,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
             $seq = '1:*';
             $options['ids'] = range(1, imap_num_msg($this->_stream));
         } else {
-            $seq = $this->toSequenceString($options['ids']);
+            $seq = $this->_utils->toSequenceString($options['ids']);
         }
 
         $ret = array_combine($options['ids'], array_fill(0, count($options['ids']), array()));
@@ -963,7 +963,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
             }
 
             switch ($type) {
-            case self::FETCH_STRUCTURE:
+            case Horde_Imap_Client::FETCH_STRUCTURE:
                 // 'noext' has no effect in this driver
                 foreach ($options['ids'] as $id) {
                     $structure = imap_fetchstructure($this->_stream, $id, empty($options['sequence']) ? FT_UID : 0);
@@ -976,7 +976,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_FULLMSG:
+            case Horde_Imap_Client::FETCH_FULLMSG:
                 foreach ($options['ids'] as $id) {
                     $tmp = imap_fetchheader($this->_stream, $id, (empty($options['sequence']) ? FT_UID : 0) | FT_PREFETCHTEXT) .
                            imap_body($this->_stream, $id, (empty($options['sequence']) ? FT_UID : 0) | (empty($c_val['peek']) ? 0 : FT_PEEK));
@@ -988,10 +988,10 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_HEADERTEXT:
-            case self::FETCH_BODYPART:
+            case Horde_Imap_Client::FETCH_HEADERTEXT:
+            case Horde_Imap_Client::FETCH_BODYPART:
                 foreach ($c_val as $val) {
-                    if ($type == self::FETCH_HEADERTEXT) {
+                    if ($type == Horde_Imap_Client::FETCH_HEADERTEXT) {
                         $label = 'headertext';
                         /* imap_fetchbody() can return header parts for a
                          * given MIME part by appending '.0' (or 0 for the
@@ -1029,7 +1029,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_BODYTEXT:
+            case Horde_Imap_Client::FETCH_BODYTEXT:
                 foreach ($c_val as $val) {
                     // This is the base body.  This is easily obtained via
                     // imap_body().
@@ -1064,9 +1064,9 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_MIMEHEADER:
-            case self::FETCH_HEADERS:
-            case self::FETCH_MODSEQ:
+            case Horde_Imap_Client::FETCH_MIMEHEADER:
+            case Horde_Imap_Client::FETCH_HEADERS:
+            case Horde_Imap_Client::FETCH_MODSEQ:
                 // Can't do it. Nope. Nada. Without heavy duty parsing of the
                 // full imap_body() object, it is impossible to retrieve the
                 // MIME headers for each individual part. Ship it off to
@@ -1074,15 +1074,15 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 // This goes for header field searches also.
                 // MODSEQ isn't available in c-client either.
                 switch ($type) {
-                case self::FETCH_MIMEHEADER:
+                case Horde_Imap_Client::FETCH_MIMEHEADER:
                     $label = 'mimeheader';
                     break;
 
-                case self::FETCH_HEADERS:
+                case Horde_Imap_Client::FETCH_HEADERS:
                     $label = 'headers';
                     break;
 
-                case self::FETCH_MODSEQ:
+                case Horde_Imap_Client::FETCH_MODSEQ:
                     $label = 'modseq';
                     break;
                 }
@@ -1095,7 +1095,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_ENVELOPE:
+            case Horde_Imap_Client::FETCH_ENVELOPE:
                 if (is_null($hdrinfo)) {
                     $hdrinfo = array();
                     foreach ($options['ids'] as $id) {
@@ -1136,7 +1136,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_FLAGS:
+            case Horde_Imap_Client::FETCH_FLAGS:
                 if (is_null($overview)) {
                     $overview = imap_fetch_overview($this->_stream, $seq, empty($options['sequence']) ? FT_UID : 0);
                     if (!$overview) {
@@ -1156,7 +1156,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_DATE:
+            case Horde_Imap_Client::FETCH_DATE:
                 if (is_null($hdrinfo)) {
                     $hdrinfo = array();
                     foreach ($options['ids'] as $id) {
@@ -1173,7 +1173,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_SIZE:
+            case Horde_Imap_Client::FETCH_SIZE:
                 if (!is_null($hdrinfo)) {
                     foreach ($options['ids'] as $id) {
                         $ret[$id]['size'] = $hdrinfo[$id]->Size;
@@ -1192,7 +1192,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_UID:
+            case Horde_Imap_Client::FETCH_UID:
                 if (empty($options['sequence'])) {
                     foreach ($options['ids'] as $id) {
                         $ret[$id]['uid'] = $id;
@@ -1211,7 +1211,7 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_SEQ:
+            case Horde_Imap_Client::FETCH_SEQ:
                 if (!empty($options['sequence'])) {
                     foreach ($options['ids'] as $id) {
                         $ret[$id]['seq'] = $id;
@@ -1328,14 +1328,14 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
         // options, nor does it support using stored searches.
         if (!empty($options['unchangedsince']) ||
             !empty($options['replace']) ||
-            (reset($options['ids']) == self::USE_SEARCHRES)) {
+            (reset($options['ids']) == Horde_Imap_Client::USE_SEARCHRES)) {
             // Requires Socket driver.
             return $this->_getSocket()->store($this->_selected, $options);
         }
 
         $seq = empty($options['ids'])
             ? '1:*'
-            : $this->toSequenceString($options['ids']);
+            : $this->_utils->toSequenceString($options['ids']);
 
         $old_error = error_reporting(0);
 
@@ -1378,14 +1378,14 @@ class Horde_Imap_Client_Cclient extends Horde_Imap_Client_Base
             $opts |= CP_MOVE;
         }
 
-        if (reset($options['ids']) == self::USE_SEARCHRES) {
+        if (reset($options['ids']) == Horde_Imap_Client::USE_SEARCHRES) {
             // Requires Socket driver.
             return $this->_getSocket()->copy($this->_selected, $options);
         }
 
         $seq = empty($options['ids'])
             ? '1:*'
-            : $this->toSequenceString($options['ids']);
+            : $this->_utils->toSequenceString($options['ids']);
 
         $old_error = error_reporting(0);
         $res = imap_mail_copy($this->_stream, $seq, $this->_connString($dest), $opts);
index a688405..329b328 100644 (file)
@@ -238,7 +238,7 @@ class Horde_Imap_Client_Cclient_Pop3 extends Horde_Imap_Client_Cclient
         if ($search_query['imap4'] ||
             (!empty($options['sort']) &&
              ((count($options['sort']) > 1) ||
-             in_array(self::SORT_REVERSE, $options['sort'])))) {
+             in_array(Horde_Imap_Client::SORT_REVERSE, $options['sort'])))) {
             throw new Horde_Imap_Client_Exception('Unsupported search criteria on POP3 server.', Horde_Imap_Client_Exception::POP3_NOTSUPPORTED);
         }
 
@@ -282,7 +282,7 @@ class Horde_Imap_Client_Cclient_Pop3 extends Horde_Imap_Client_Cclient
          * and does not support defining search criteria. */
         if (!empty($options['search']) ||
             (!empty($options['criteria']) &&
-             $options['criteria'] != self::THREAD_REFERENCES)) {
+             $options['criteria'] != Horde_Imap_Client::THREAD_REFERENCES)) {
             throw new Horde_Imap_Client_Exception('Unsupported threading criteria on POP3 server.', Horde_Imap_Client_Exception::POP3_NOTSUPPORTED);
         }
 
@@ -315,7 +315,7 @@ class Horde_Imap_Client_Cclient_Pop3 extends Horde_Imap_Client_Cclient
     protected function _fetch($criteria, $options)
     {
         // No support for FETCH_MIMEHEADER or FETCH_HEADERS
-        $nosupport = array(self::FETCH_MIMEHEADER, self::FETCH_HEADERS);
+        $nosupport = array(Horde_Imap_Client::FETCH_MIMEHEADER, Horde_Imap_Client::FETCH_HEADERS);
 
         reset($criteria);
         while (list($val,) = each($criteria)) {
index 392e283..242e5f4 100644 (file)
@@ -66,6 +66,21 @@ class Horde_Imap_Client_Search_Query
     protected $_exts = array();
 
     /**
+     * The Horde_Imap_Client_Utils object
+     *
+     * @var Horde_Imap_Client_Utils
+     */
+    protected $_utils = null;
+
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        $this->_utils = new Horde_Imap_Client_Utils();
+    }
+
+    /**
      * Sets the charset of the search text.
      *
      * @param string $charset  The charset to use for the search.
@@ -140,7 +155,7 @@ class Horde_Imap_Client_Search_Query
                     $tmp .= 'HEADER ';
                     $imap4 = true;
                 }
-                $cmds[] = $tmp . $val['header'] . ' ' . Horde_Imap_Client::escape($val['text']);
+                $cmds[] = $tmp . $val['header'] . ' ' . $this->_utils->escape($val['text']);
             }
         }
 
@@ -152,7 +167,7 @@ class Horde_Imap_Client_Search_Query
                     // NOT searches were not in IMAP2
                     $imap4 = true;
                 }
-                $cmds[] = $tmp . $val['type'] . ' ' . Horde_Imap_Client::escape($val['text']);
+                $cmds[] = $tmp . $val['type'] . ' ' . $this->_utils->escape($val['text']);
             }
         }
 
@@ -205,7 +220,7 @@ class Horde_Imap_Client_Search_Query
                 'MODSEQ ' .
                 (is_null($ptr['modseq']['name'])
                     ? ''
-                    : Horde_Imap_Client::escape($ptr['modseq']['name']) . ' ' . $ptr['modseq']['type'] . ' ') .
+                    : $this->_utils->escape($ptr['modseq']['name']) . ' ' . $ptr['modseq']['type'] . ' ') .
                 $ptr['modseq']['value'];
         }
 
@@ -372,7 +387,7 @@ class Horde_Imap_Client_Search_Query
         if (empty($ids)) {
             $ids = '1:*';
         } else {
-            $ids = Horde_Imap_Client::toSequenceString($ids);
+            $ids = $this->_utils->toSequenceString($ids);
         }
         $this->_search['sequence'] = array(
             'ids' => $ids,
index 6536d2a..9a40038 100644 (file)
@@ -522,7 +522,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             break;
 
         case 'LOGIN':
-            $this->_sendLine('LOGIN ' . $this->escape($this->_params['username']) . ' ' . $this->escape($this->_params['password']), array('debug' => '[LOGIN Command]'));
+            $this->_sendLine('LOGIN ' . $this->_utils->escape($this->_params['username']) . ' ' . $this->_utils->escape($this->_params['password']), array('debug' => '[LOGIN Command]'));
             break;
 
         case 'PLAIN':
@@ -616,7 +616,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         } else {
             $cmd = '(';
             foreach ($info as $key => $val) {
-                $cmd .= $this->escape(strtolower($key)) . ' ' . $this->escape($val);
+                $cmd .= $this->_utils->escape(strtolower($key)) . ' ' . $this->_utils->escape($val);
             }
             $cmd .= ')';
         }
@@ -670,7 +670,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
     {
         $cmd = array();
         foreach ($langs as $val) {
-            $cmd[] = $this->escape($val);
+            $cmd[] = $this->_utils->escape($val);
         }
 
         try {
@@ -776,7 +776,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             $this->_temp['qresyncmbox'] = $mailbox;
         }
 
-        $cmd = (($mode == self::OPEN_READONLY) ? 'EXAMINE' : 'SELECT') . ' ' . $this->escape($mailbox);
+        $cmd = (($mode == Horde_Imap_Client::OPEN_READONLY) ? 'EXAMINE' : 'SELECT') . ' ' . $this->_utils->escape($mailbox);
 
         /* If QRESYNC is available, synchronize the mailbox. */
         if ($qresync) {
@@ -795,7 +795,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                      * response handlers.
                      * TODO: Use 4th parameter (useful if we keep a sequence
                      * number->UID lookup in the future). */
-                    $cmd .= ' (QRESYNC (' . $metadata['uidvalid'] . ' ' . $metadata['HICmodseq'] . ' ' . $this->toSequenceString($uids) . '))';
+                    $cmd .= ' (QRESYNC (' . $metadata['uidvalid'] . ' ' . $metadata['HICmodseq'] . ' ' . $this->_utils->toSequenceString($uids) . '))';
                 }
             }
         } elseif (!isset($this->_init['enabled']['CONDSTORE']) &&
@@ -843,7 +843,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $this->login();
 
         // CREATE returns no untagged information (RFC 3501 [6.3.3])
-        $this->_sendLine('CREATE ' . $this->escape($mailbox));
+        $this->_sendLine('CREATE ' . $this->_utils->escape($mailbox));
     }
 
     /**
@@ -864,7 +864,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
 
         try {
             // DELETE returns no untagged information (RFC 3501 [6.3.4])
-            $this->_sendLine('DELETE ' . $this->escape($mailbox));
+            $this->_sendLine('DELETE ' . $this->_utils->escape($mailbox));
         } catch (Horde_Imap_Client_Exception $e) {
             // Some IMAP servers won't allow a mailbox delete unless all
             // messages in that mailbox are deleted.
@@ -895,7 +895,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $this->login();
 
         // RENAME returns no untagged information (RFC 3501 [6.3.5])
-        $this->_sendLine('RENAME ' . $this->escape($old) . ' ' . $this->escape($new));
+        $this->_sendLine('RENAME ' . $this->_utils->escape($old) . ' ' . $this->_utils->escape($new));
     }
 
     /**
@@ -911,7 +911,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
 
         // SUBSCRIBE/UNSUBSCRIBE returns no untagged information (RFC 3501
         // [6.3.6 & 6.3.7])
-        $this->_sendLine(($subscribe ? '' : 'UN') . 'SUBSCRIBE ' . $this->escape($mailbox));
+        $this->_sendLine(($subscribe ? '' : 'UN') . 'SUBSCRIBE ' . $this->_utils->escape($mailbox));
     }
 
     /**
@@ -931,11 +931,11 @@ 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 != self::MBOX_ALL) {
-            $subscribed = $this->_getMailboxList($pattern, self::MBOX_SUBSCRIBED, array('flat' => true));
+        if ($mode != Horde_Imap_Client::MBOX_ALL) {
+            $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 == self::MBOX_SUBSCRIBED) && !empty($options['flat'])) {
+            if (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) && !empty($options['flat'])) {
                 return $subscribed;
             }
         } else {
@@ -959,7 +959,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
     protected function _getMailboxList($pattern, $mode, $options,
                                        $subscribed = null)
     {
-        $check = (($mode != self::MBOX_ALL) && !is_null($subscribed));
+        $check = (($mode != Horde_Imap_Client::MBOX_ALL) && !is_null($subscribed));
 
         // Setup cache entry for use in _parseList()
         $t = &$this->_temp;
@@ -970,7 +970,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         );
         $t['listresponse'] = array();
 
-        $this->_sendLine((($mode == self::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST') . ' "" ' . $this->escape($pattern));
+        $this->_sendLine((($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST') . ' "" ' . $this->_utils->escape($pattern));
 
         return (empty($options['flat'])) ? $t['listresponse'] : array_values($t['listresponse']);
     }
@@ -1033,31 +1033,31 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $search = null;
 
         $items = array(
-            self::STATUS_MESSAGES => 'messages',
-            self::STATUS_RECENT => 'recent',
-            self::STATUS_UIDNEXT => 'uidnext',
-            self::STATUS_UIDVALIDITY => 'uidvalidity',
-            self::STATUS_UNSEEN => 'unseen',
-            self::STATUS_FIRSTUNSEEN => 'firstunseen',
-            self::STATUS_FLAGS => 'flags',
-            self::STATUS_PERMFLAGS => 'permflags',
-            self::STATUS_UIDNOTSTICKY => 'uidnotsticky',
+            Horde_Imap_Client::STATUS_MESSAGES => 'messages',
+            Horde_Imap_Client::STATUS_RECENT => 'recent',
+            Horde_Imap_Client::STATUS_UIDNEXT => 'uidnext',
+            Horde_Imap_Client::STATUS_UIDVALIDITY => 'uidvalidity',
+            Horde_Imap_Client::STATUS_UNSEEN => 'unseen',
+            Horde_Imap_Client::STATUS_FIRSTUNSEEN => 'firstunseen',
+            Horde_Imap_Client::STATUS_FLAGS => 'flags',
+            Horde_Imap_Client::STATUS_PERMFLAGS => 'permflags',
+            Horde_Imap_Client::STATUS_UIDNOTSTICKY => 'uidnotsticky',
         );
 
         /* Don't include 'highestmodseq' return if server does not support it.
          * OK to use queryCapability('CONDSTORE') here because we may not have
          * yet sent an enabling command. */
         if ($this->queryCapability('CONDSTORE')) {
-            $items[self::STATUS_HIGHESTMODSEQ] = 'highestmodseq';
+            $items[Horde_Imap_Client::STATUS_HIGHESTMODSEQ] = 'highestmodseq';
         }
 
         /* If FLAGS/PERMFLAGS/UIDNOTSTICKY/FIRSTUNSEEN are needed, we must do
          * a SELECT/EXAMINE to get this information (data will be caught in
          * the code below). */
-        if (($flags & self::STATUS_FIRSTUNSEEN) ||
-            ($flags & self::STATUS_FLAGS) ||
-            ($flags & self::STATUS_PERMFLAGS) ||
-            ($flags & self::STATUS_UIDNOTSTICKY)) {
+        if (($flags & Horde_Imap_Client::STATUS_FIRSTUNSEEN) ||
+            ($flags & Horde_Imap_Client::STATUS_FLAGS) ||
+            ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) ||
+            ($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY)) {
             $this->openMailbox($mailbox);
         } else {
             $this->login();
@@ -1069,17 +1069,17 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                     if (isset($this->_temp['mailbox'][$val])) {
                         $data[$val] = $this->_temp['mailbox'][$val];
                     } else {
-                        if ($key == self::STATUS_UIDNOTSTICKY) {
+                        if ($key == Horde_Imap_Client::STATUS_UIDNOTSTICKY) {
                             /* In the absence of uidnotsticky information, or
                              * if UIDPLUS is not supported, we assume the UIDs
                              * are sticky. */
                             $data[$val] = false;
-                        } elseif (in_array($key, array(self::STATUS_FIRSTUNSEEN, self::STATUS_UNSEEN))) {
+                        } elseif (in_array($key, array(Horde_Imap_Client::STATUS_FIRSTUNSEEN, Horde_Imap_Client::STATUS_UNSEEN))) {
                             /* If we already know there are no messages in the
                              * current mailbox, we know there is no
                              * firstunseen and unseen info also. */
                             if (empty($this->_temp['mailbox']['messages'])) {
-                                $data[$val] = ($key == self::STATUS_FIRSTUNSEEN) ? null : 0;
+                                $data[$val] = ($key == Horde_Imap_Client::STATUS_FIRSTUNSEEN) ? null : 0;
                             } else {
                                 /* RFC 3501 [6.3.1] - FIRSTUNSEEN information
                                  * is not mandatory. If missing EXAMINE/SELECT
@@ -1088,10 +1088,10 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                                 if (is_null($search)) {
                                     $search_query = new Horde_Imap_Client_Search_Query();
                                     $search_query->flag('\\seen', false);
-                                    $search = $this->search($mailbox, $search_query, array('results' => array(($key == self::STATUS_FIRSTUNSEEN) ? self::SORT_RESULTS_MIN : self::SORT_RESULTS_COUNT), 'sequence' => true));
+                                    $search = $this->search($mailbox, $search_query, array('results' => array(($key == Horde_Imap_Client::STATUS_FIRSTUNSEEN) ? Horde_Imap_Client::SORT_RESULTS_MIN : Horde_Imap_Client::SORT_RESULTS_COUNT), 'sequence' => true));
                                 }
 
-                                $data[$val] = $search[($key == self::STATUS_FIRSTUNSEEN) ? 'min' : 'count'];
+                                $data[$val] = $search[($key == Horde_Imap_Client::STATUS_FIRSTUNSEEN) ? 'min' : 'count'];
                             }
                         }
                     }
@@ -1106,7 +1106,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         }
 
         $this->_temp['status'] = array();
-        $this->_sendLine('STATUS ' . $this->escape($mailbox) . ' (' . implode(' ', array_map('strtoupper', $query)) . ')');
+        $this->_sendLine('STATUS ' . $this->_utils->escape($mailbox) . ' (' . implode(' ', array_map('strtoupper', $query)) . ')');
 
         return $this->_temp['status'];
     }
@@ -1166,7 +1166,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         reset($data);
         while (list(,$m_data) = each($data)) {
             if (!$i++ || !$multiappend) {
-                $cmd = 'APPEND ' . $this->escape($mailbox);
+                $cmd = 'APPEND ' . $this->_utils->escape($mailbox);
             } else {
                 $cmd = '';
                 $notag = true;
@@ -1177,7 +1177,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             }
 
             if (!empty($m_data['internaldate'])) {
-                $cmd .= ' ' . $this->escape($m_data['internaldate']->format('j-M-Y H:i:s O'));
+                $cmd .= ' ' . $this->_utils->escape($m_data['internaldate']->format('j-M-Y H:i:s O'));
             }
 
             /* @todo There is no way I am aware of to determine the length of
@@ -1187,7 +1187,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
              * for now, simply grab the contents of the stream and do a
              * strlen() call to determine the literal size to send to the
              * IMAP server. */
-            $text = $this->removeBareNewlines(is_resource($m_data['data']) ? stream_get_contents($m_data['data']) : $m_data['data']);
+            $text = $this->_utils->removeBareNewlines(is_resource($m_data['data']) ? stream_get_contents($m_data['data']) : $m_data['data']);
             $datalength = strlen($text);
 
             /* RFC 3516/4466 says we should be able to append binary data
@@ -1300,19 +1300,19 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             $uid_string = '1:*';
         } elseif ($uidplus) {
             /* UID EXPUNGE command needs UIDs. */
-            if (reset($options['ids']) === self::USE_SEARCHRES) {
+            if (reset($options['ids']) === Horde_Imap_Client::USE_SEARCHRES) {
                 $uid_string = '$';
             } elseif ($seq) {
-                $results = array(self::SORT_RESULTS_MATCH);
+                $results = array(Horde_Imap_Client::SORT_RESULTS_MATCH);
                 if ($this->queryCapability('SEARCHRES')) {
-                    $results[] = self::SORT_RESULTS_SAVE;
+                    $results[] = Horde_Imap_Client::SORT_RESULTS_SAVE;
                 }
                 $s_res = $this->search($mailbox, null, array('results' => $results));
-                $uid_string = (in_array(self::SORT_RESULTS_SAVE, $results) && !empty($s_res['save']))
+                $uid_string = (in_array(Horde_Imap_Client::SORT_RESULTS_SAVE, $results) && !empty($s_res['save']))
                     ? '$'
-                    : $this->toSequenceString($s_res['match']);
+                    : $this->_utils->toSequenceString($s_res['match']);
             } else {
-                $uid_string = $this->toSequenceString($options['ids']);
+                $uid_string = $this->_utils->toSequenceString($options['ids']);
             }
         } else {
             /* Without UIDPLUS, need to temporarily unflag all messages marked
@@ -1320,7 +1320,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
              * searches to accomplish this goal. */
             $search_query = new Horde_Imap_Client_Search_Query();
             $search_query->flag('\\deleted', true);
-            if (reset($options['ids']) === self::USE_SEARCHRES) {
+            if (reset($options['ids']) === Horde_Imap_Client::USE_SEARCHRES) {
                 $search_query->previousSearch(true);
             } else {
                 $search_query->sequence($options['ids'], $seq, true);
@@ -1338,7 +1338,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
          * we will get VANISHED responses, so we need to do this. */
         if ($use_cache && is_null($s_res)) {
             /* Keys in $s_res['sort'] start at 0, not 1. */
-            $s_res = $this->search($mailbox, null, array('sort' => array(self::SORT_ARRIVAL)));
+            $s_res = $this->search($mailbox, null, array('sort' => array(Horde_Imap_Client::SORT_ARRIVAL)));
         }
 
         $tmp = &$this->_temp;
@@ -1412,13 +1412,13 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
          * the tagged response. */
         if (is_array($data[0])) {
             if (strtoupper(reset($data[0])) == 'EARLIER') {
-                $this->_cacheOb->deleteMsgs($this->_temp['mailbox']['name'], $this->fromSequenceString($data[1]));
+                $this->_cacheOb->deleteMsgs($this->_temp['mailbox']['name'], $this->_utils->fromSequenceString($data[1]));
             }
         } else {
             /* The second form is just VANISHED. This is returned from an
              * EXPUNGE command and will be processed in _expunge() (since
              * we need to adjust message counts in the current mailbox). */
-            $this->_temp['vanished'] = $this->fromSequenceString($data[0]);
+            $this->_temp['vanished'] = $this->_utils->fromSequenceString($data[0]);
         }
     }
 
@@ -1458,22 +1458,22 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         }
 
         $sort_criteria = array(
-            self::SORT_ARRIVAL => 'ARRIVAL',
-            self::SORT_CC => 'CC',
-            self::SORT_DATE => 'DATE',
-            self::SORT_FROM => 'FROM',
-            self::SORT_REVERSE => 'REVERSE',
-            self::SORT_SIZE => 'SIZE',
-            self::SORT_SUBJECT => 'SUBJECT',
-            self::SORT_TO => 'TO'
+            Horde_Imap_Client::SORT_ARRIVAL => 'ARRIVAL',
+            Horde_Imap_Client::SORT_CC => 'CC',
+            Horde_Imap_Client::SORT_DATE => 'DATE',
+            Horde_Imap_Client::SORT_FROM => 'FROM',
+            Horde_Imap_Client::SORT_REVERSE => 'REVERSE',
+            Horde_Imap_Client::SORT_SIZE => 'SIZE',
+            Horde_Imap_Client::SORT_SUBJECT => 'SUBJECT',
+            Horde_Imap_Client::SORT_TO => 'TO'
         );
 
         $results_criteria = array(
-            self::SORT_RESULTS_COUNT => 'COUNT',
-            self::SORT_RESULTS_MATCH => 'ALL',
-            self::SORT_RESULTS_MAX => 'MAX',
-            self::SORT_RESULTS_MIN => 'MIN',
-            self::SORT_RESULTS_SAVE => 'SAVE'
+            Horde_Imap_Client::SORT_RESULTS_COUNT => 'COUNT',
+            Horde_Imap_Client::SORT_RESULTS_MATCH => 'ALL',
+            Horde_Imap_Client::SORT_RESULTS_MAX => 'MAX',
+            Horde_Imap_Client::SORT_RESULTS_MIN => 'MIN',
+            Horde_Imap_Client::SORT_RESULTS_SAVE => 'SAVE'
         );
 
         // Check if the server supports server-side sorting (RFC 5256).
@@ -1485,7 +1485,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             /* Make sure sort options are correct. If not, default to ARRIVAL
              * sort. */
             if (count(array_intersect($options['sort'], array_keys($sort_criteria))) === 0) {
-                $options['sort'] = array(self::SORT_ARRIVAL);
+                $options['sort'] = array(Horde_Imap_Client::SORT_ARRIVAL);
             }
         }
 
@@ -1495,7 +1495,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                 $results = array();
                 foreach ($options['results'] as $val) {
                     if (isset($results_criteria[$val]) &&
-                        ($val != self::SORT_RESULTS_SAVE)) {
+                        ($val != Horde_Imap_Client::SORT_RESULTS_SAVE)) {
                         $results[] = $results_criteria[$val];
                     }
                 }
@@ -1545,23 +1545,23 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $ret = array();
         foreach ($options['results'] as $val) {
             switch ($val) {
-            case self::SORT_RESULTS_COUNT:
+            case Horde_Imap_Client::SORT_RESULTS_COUNT:
                 $ret['count'] = $esearch ? $er['count'] : count($sr);
                 break;
 
-            case self::SORT_RESULTS_MATCH:
+            case Horde_Imap_Client::SORT_RESULTS_MATCH:
                 $ret[$return_sort ? 'sort' : 'match'] = $sr;
                 break;
 
-            case self::SORT_RESULTS_MAX:
+            case Horde_Imap_Client::SORT_RESULTS_MAX:
                 $ret['max'] = $esearch ? (isset($er['max']) ? $er['max'] : null) : (empty($sr) ? null : max($sr));
                 break;
 
-            case self::SORT_RESULTS_MIN:
+            case Horde_Imap_Client::SORT_RESULTS_MIN:
                 $ret['min'] = $esearch ? (isset($er['min']) ? $er['min'] : null) : (empty($sr) ? null : min($sr));
                 break;
 
-            case self::SORT_RESULTS_SAVE:
+            case Horde_Imap_Client::SORT_RESULTS_SAVE:
                 $ret['save'] = $esearch ? empty($this->_temp['searchnotsaved']) : false;
             }
         }
@@ -1622,7 +1622,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             $tag = strtoupper($data[$i]);
             switch ($tag) {
             case 'ALL':
-                $this->_temp['searchresp'] = $this->fromSequenceString($val);
+                $this->_temp['searchresp'] = $this->_utils->fromSequenceString($val);
                 break;
 
             case 'COUNT':
@@ -1655,19 +1655,19 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $criteria = array();
         foreach ($opts['sort'] as $val) {
             switch ($val) {
-            case self::SORT_DATE:
-                $criteria[self::FETCH_DATE] = true;
+            case Horde_Imap_Client::SORT_DATE:
+                $criteria[Horde_Imap_Client::FETCH_DATE] = true;
                 // Fall through
 
-            case self::SORT_CC:
-            case self::SORT_FROM:
-            case self::SORT_SUBJECT:
-            case self::SORT_TO:
-                $criteria[self::FETCH_ENVELOPE] = true;
+            case Horde_Imap_Client::SORT_CC:
+            case Horde_Imap_Client::SORT_FROM:
+            case Horde_Imap_Client::SORT_SUBJECT:
+            case Horde_Imap_Client::SORT_TO:
+                $criteria[Horde_Imap_Client::FETCH_ENVELOPE] = true;
                 break;
 
-            case self::SORT_SIZE:
-                $criteria[self::FETCH_SIZE] = true;
+            case Horde_Imap_Client::SORT_SIZE:
+                $criteria[Horde_Imap_Client::FETCH_SIZE] = true;
                 break;
             }
         }
@@ -1682,7 +1682,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
 
         $reverse = false;
         foreach ($opts['sort'] as $val) {
-            if ($val == self::SORT_REVERSE) {
+            if ($val == Horde_Imap_Client::SORT_REVERSE) {
                 $reverse = true;
                 continue;
             }
@@ -1698,7 +1698,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                 }
 
                 switch ($val) {
-                case self::SORT_ARRIVAL:
+                case Horde_Imap_Client::SORT_ARRIVAL:
                     /* There is no requirement that IDs be returned in
                      * sequence order (see RFC 4549 [4.3.1]). So we must sort
                      * ourselves. */
@@ -1706,19 +1706,19 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                     sort($sorted, SORT_NUMERIC);
                     break;
 
-                case self::SORT_SIZE:
+                case Horde_Imap_Client::SORT_SIZE:
                     foreach ($slice as $num) {
                         $sorted[$num] = $fetch_res[$num]['size'];
                     }
                     asort($sorted, SORT_NUMERIC);
                     break;
 
-                case self::SORT_CC:
-                case self::SORT_FROM:
-                case self::SORT_TO:
-                    if ($val == self::SORT_CC) {
+                case Horde_Imap_Client::SORT_CC:
+                case Horde_Imap_Client::SORT_FROM:
+                case Horde_Imap_Client::SORT_TO:
+                    if ($val == Horde_Imap_Client::SORT_CC) {
                         $field = 'cc';
-                    } elseif ($val = self::SORT_FROM) {
+                    } elseif ($val = Horde_Imap_Client::SORT_FROM) {
                         $field = 'from';
                     } else {
                         $field = 'to';
@@ -1732,18 +1732,18 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                     asort($sorted, SORT_LOCALE_STRING);
                     break;
 
-                case self::SORT_DATE:
+                case Horde_Imap_Client::SORT_DATE:
                     // Date sorting rules in RFC 5256 [2.2]
                     $sorted = $this->_getSentDates($fetch_res, $slice);
                     asort($sorted, SORT_NUMERIC);
                     break;
 
-                case self::SORT_SUBJECT:
+                case Horde_Imap_Client::SORT_SUBJECT:
                     // Subject sorting rules in RFC 5256 [2.1]
                     foreach ($slice as $num) {
                         $sorted[$num] = empty($fetch_res[$num]['envelope']['subject'])
                             ? ''
-                            : $this->getBaseSubject($fetch_res[$num]['envelope']['subject']);
+                            : $this->_utils->getBaseSubject($fetch_res[$num]['envelope']['subject']);
                     }
                     asort($sorted, SORT_LOCALE_STRING);
                     break;
@@ -1829,7 +1829,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
 
         $cmd = array();
         foreach (explode(' ', $comparator) as $val) {
-            $cmd[] = $this->escape($val);
+            $cmd[] = $this->_utils->escape($val);
         }
 
         $this->_sendLine('COMPARATOR ' . implode(' ', $cmd));
@@ -1872,8 +1872,8 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
     protected function _thread($options)
     {
         $thread_criteria = array(
-            self::THREAD_ORDEREDSUBJECT => 'ORDEREDSUBJECT',
-            self::THREAD_REFERENCES => 'REFERENCES'
+            Horde_Imap_Client::THREAD_ORDEREDSUBJECT => 'ORDEREDSUBJECT',
+            Horde_Imap_Client::THREAD_REFERENCES => 'REFERENCES'
         );
 
         $tsort = (isset($options['criteria']))
@@ -1891,7 +1891,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                 }
 
                 /* Do client-side ORDEREDSUBJECT threading. */
-                $fetch_res = $this->fetch($this->_selected, array(self::FETCH_ENVELOPE => true, self::FETCH_DATE => true), array('ids' => $ids, 'sequence' => !empty($options['sequence'])));
+                $fetch_res = $this->fetch($this->_selected, array(Horde_Imap_Client::FETCH_ENVELOPE => true, Horde_Imap_Client::FETCH_DATE => true), array('ids' => $ids, 'sequence' => !empty($options['sequence'])));
                 return $this->_clientThreadOrderedsubject($fetch_res);
             } else {
                 throw new Horde_Imap_Client_Exception('Server does not support REFERENCES thread sort.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT);
@@ -1967,7 +1967,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         while(list($k, $v) = each($data)) {
             $subject = empty($v['envelope']['subject'])
                 ? ''
-                : $this->getBaseSubject($v['envelope']['subject']);
+                : $this->_utils->getBaseSubject($v['envelope']['subject']);
             if (!isset($sorted[$subject])) {
                 $sorted[$subject] = array();
             }
@@ -2052,14 +2052,14 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             }
 
             switch ($type) {
-            case self::FETCH_STRUCTURE:
+            case Horde_Imap_Client::FETCH_STRUCTURE:
                 $fp['parsestructure'] = !empty($c_val['parse']);
                 $fetch[] = !empty($c_val['noext']) ? 'BODY' : 'BODYSTRUCTURE';
                 break;
 
-            case self::FETCH_FULLMSG:
+            case Horde_Imap_Client::FETCH_FULLMSG:
                 if (empty($c_val['peek'])) {
-                    $this->openMailbox($this->_selected, self::OPEN_READWRITE);
+                    $this->openMailbox($this->_selected, Horde_Imap_Client::OPEN_READWRITE);
                 }
                 $fetch[] = 'BODY' .
                     (!empty($c_val['peek']) ? '.PEEK' : '') .
@@ -2067,11 +2067,11 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                     (isset($c_val['start']) && !empty($c_val['length']) ? ('<' . $c_val['start'] . '.' . $c_val['length'] . '>') : '');
                 break;
 
-            case self::FETCH_HEADERTEXT:
-            case self::FETCH_BODYTEXT:
-            case self::FETCH_MIMEHEADER:
-            case self::FETCH_BODYPART:
-            case self::FETCH_HEADERS:
+            case Horde_Imap_Client::FETCH_HEADERTEXT:
+            case Horde_Imap_Client::FETCH_BODYTEXT:
+            case Horde_Imap_Client::FETCH_MIMEHEADER:
+            case Horde_Imap_Client::FETCH_BODYPART:
+            case Horde_Imap_Client::FETCH_HEADERS:
                 foreach ($c_val as $val) {
                     $main_cmd = 'BODY';
 
@@ -2082,23 +2082,23 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                     }
 
                     switch ($type) {
-                    case self::FETCH_HEADERTEXT:
+                    case Horde_Imap_Client::FETCH_HEADERTEXT:
                         $fp['parseheadertext'] = !empty($val['parse']);
                         $cmd .= 'HEADER';
                         break;
 
-                    case self::FETCH_BODYTEXT:
+                    case Horde_Imap_Client::FETCH_BODYTEXT:
                         $cmd .= 'TEXT';
                         break;
 
-                    case self::FETCH_MIMEHEADER:
+                    case Horde_Imap_Client::FETCH_MIMEHEADER:
                         if (empty($val['id'])) {
                             throw new Horde_Imap_Client_Exception('Need a MIME ID when retrieving a MIME header.');
                         }
                         $cmd .= 'MIME';
                         break;
 
-                    case self::FETCH_BODYPART:
+                    case Horde_Imap_Client::FETCH_BODYPART:
                         if (empty($val['id'])) {
                             throw new Horde_Imap_Client_Exception('Need a MIME ID when retrieving a MIME body part.');
                         }
@@ -2111,7 +2111,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                         }
                         break;
 
-                    case self::FETCH_HEADERS:
+                    case Horde_Imap_Client::FETCH_HEADERS:
                         if (empty($val['label'])) {
                             throw new Horde_Imap_Client_Exception('Need a unique label when doing a headers field search.');
                         }
@@ -2135,7 +2135,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                     }
 
                     if (empty($val['peek'])) {
-                        $this->openMailbox($this->_selected, self::OPEN_READWRITE);
+                        $this->openMailbox($this->_selected, Horde_Imap_Client::OPEN_READWRITE);
                     }
 
                     $fetch[] = $main_cmd .
@@ -2145,7 +2145,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_BODYPARTSIZE:
+            case Horde_Imap_Client::FETCH_BODYPARTSIZE:
                 foreach ($c_val as $val) {
                     if (empty($val['id'])) {
                         throw new Horde_Imap_Client_Exception('Need a MIME ID when retrieving unencoded MIME body part size.');
@@ -2154,31 +2154,31 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
                 }
                 break;
 
-            case self::FETCH_ENVELOPE:
+            case Horde_Imap_Client::FETCH_ENVELOPE:
                 $fetch[] = 'ENVELOPE';
                 break;
 
-            case self::FETCH_FLAGS:
+            case Horde_Imap_Client::FETCH_FLAGS:
                 $fetch[] = 'FLAGS';
                 break;
 
-            case self::FETCH_DATE:
+            case Horde_Imap_Client::FETCH_DATE:
                 $fetch[] = 'INTERNALDATE';
                 break;
 
-            case self::FETCH_SIZE:
+            case Horde_Imap_Client::FETCH_SIZE:
                 $fetch[] = 'RFC822.SIZE';
                 break;
 
-            case self::FETCH_UID:
+            case Horde_Imap_Client::FETCH_UID:
                 $fetch[] = 'UID';
                 break;
 
-            case self::FETCH_SEQ:
+            case Horde_Imap_Client::FETCH_SEQ:
                 // Nothing we need to add to fetch criteria.
                 break;
 
-            case self::FETCH_MODSEQ:
+            case Horde_Imap_Client::FETCH_MODSEQ:
                 /* RFC 4551 [3.1] - trying to do a FETCH of MODSEQ on a
                  * mailbox that doesn't support it will return BAD. Catch that
                  * here and throw an exception. */
@@ -2192,9 +2192,9 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
 
         $seq = empty($options['ids'])
             ? '1:*'
-            : ((reset($options['ids']) === self::USE_SEARCHRES)
+            : ((reset($options['ids']) === Horde_Imap_Client::USE_SEARCHRES)
                  ? '$'
-                 : $this->toSequenceString($options['ids']));
+                 : $this->_utils->toSequenceString($options['ids']));
         $use_seq = !empty($options['sequence']);
 
         $cmd = ($use_seq ? '' : 'UID ') . 'FETCH ' . $seq . ' (' . implode(' ', $fetch) . ')';
@@ -2580,9 +2580,9 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
     {
         $seq = empty($options['ids'])
             ? '1:*'
-            : ((reset($options['ids']) === self::USE_SEARCHRES)
+            : ((reset($options['ids']) === Horde_Imap_Client::USE_SEARCHRES)
                  ? '$'
-                 : $this->toSequenceString($options['ids']));
+                 : $this->_utils->toSequenceString($options['ids']));
 
         $cmd_prefix = (empty($options['sequence']) ? 'UID ' : '') .
                       'STORE ' . $seq . ' ';
@@ -2676,13 +2676,13 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
 
         $seq = empty($options['ids'])
             ? '1:*'
-            : ((reset($options['ids']) === self::USE_SEARCHRES)
+            : ((reset($options['ids']) === Horde_Imap_Client::USE_SEARCHRES)
                  ? '$'
-                 : $this->toSequenceString($options['ids']));
+                 : $this->_utils->toSequenceString($options['ids']));
 
         // COPY returns no untagged information (RFC 3501 [6.4.7])
         try {
-            $this->_sendLine((empty($options['sequence']) ? 'UID ' : '') . 'COPY ' . $seq . ' ' . $this->escape($dest));
+            $this->_sendLine((empty($options['sequence']) ? 'UID ' : '') . 'COPY ' . $seq . ' ' . $this->_utils->escape($dest));
         } catch (Horde_Imap_Client_Exception $e) {
             if (!empty($options['create']) && $this->_temp['trycreate']) {
                 $this->createMailbox($dest);
@@ -2728,7 +2728,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             $limits[] = 'STORAGE ' . $options['storage'];
         }
 
-        $this->_sendLine('SETQUOTA ' . $this->escape($root) . ' (' . implode(' ', $limits) . ')');
+        $this->_sendLine('SETQUOTA ' . $this->_utils->escape($root) . ' (' . implode(' ', $limits) . ')');
     }
 
     /**
@@ -2746,7 +2746,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $this->login();
 
         $this->_temp['quotaresp'] = array();
-        $this->_sendLine('GETQUOTA ' . $this->escape($root));
+        $this->_sendLine('GETQUOTA ' . $this->_utils->escape($root));
         return reset($this->_temp['quotaresp']);
     }
 
@@ -2786,7 +2786,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $this->login();
 
         $this->_temp['quotaresp'] = array();
-        $this->_sendLine('GETQUOTAROOT ' . $this->escape($mailbox));
+        $this->_sendLine('GETQUOTAROOT ' . $this->_utils->escape($mailbox));
         return $this->_temp['quotaresp'];
     }
 
@@ -2805,9 +2805,9 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         // SETACL/DELETEACL returns no untagged information (RFC 4314 [3.1 &
         // 3.2]).
         if (empty($options['rights']) && !empty($options['remove'])) {
-            $this->_sendLine('DELETEACL ' . $this->escape($mailbox) . ' ' . $identifier);
+            $this->_sendLine('DELETEACL ' . $this->_utils->escape($mailbox) . ' ' . $identifier);
         } else {
-            $this->_sendLine('SETACL ' . $this->escape($mailbox) . ' ' . $identifier . ' ' . $options['rights']);
+            $this->_sendLine('SETACL ' . $this->_utils->escape($mailbox) . ' ' . $identifier . ' ' . $options['rights']);
         }
     }
 
@@ -2825,7 +2825,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $this->login();
 
         $this->_temp['getacl'] = array();
-        $this->_sendLine('GETACL ' . $this->escape($mailbox));
+        $this->_sendLine('GETACL ' . $this->_utils->escape($mailbox));
         return $this->_temp['getacl'];
     }
 
@@ -2858,7 +2858,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $this->login();
 
         $this->_temp['listaclrights'] = array();
-        $this->_sendLine('LISTRIGHTS ' . $this->escape($mailbox) . ' ' . $identifier);
+        $this->_sendLine('LISTRIGHTS ' . $this->_utils->escape($mailbox) . ' ' . $identifier);
         return $this->_temp['listaclrights'];
     }
 
@@ -2889,7 +2889,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
         $this->login();
 
         $this->_temp['myrights'] = array();
-        $this->_sendLine('MYRIGHTS ' . $this->escape($mailbox));
+        $this->_sendLine('MYRIGHTS ' . $this->_utils->escape($mailbox));
         return $this->_temp['myrights'];
     }
 
@@ -3474,7 +3474,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
 
         case 'REFERRAL':
             // Defined by RFC 2221
-            $this->_temp['referral'] = $this->parseImapUrl($data);
+            $this->_temp['referral'] = $this->_utils->parseImapUrl($data);
             break;
 
         case 'UNKNOWN-CTE':
@@ -3502,9 +3502,9 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
             $this->_updateCache(array(), array('mailbox' => $this->_temp['uidplusmbox'], 'uidvalid' => $parts[0]));
 
             if ($code == 'APPENDUID') {
-                $this->_temp['appenduid'] = array_merge($this->_temp['appenduid'], $this->fromSequenceString($parts[1]));
+                $this->_temp['appenduid'] = array_merge($this->_temp['appenduid'], $this->_utils->fromSequenceString($parts[1]));
             } else {
-                $this->_temp['copyuid'] = array_combine($this->fromSequenceString($parts[1]), $this->fromSequenceString($parts[2]));
+                $this->_temp['copyuid'] = array_combine($this->_utils->fromSequenceString($parts[1]), $this->_utils->fromSequenceString($parts[2]));
             }
             break;
 
@@ -3521,7 +3521,7 @@ class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base
 
         case 'MODIFIED':
             // Defined by RFC 4551 [3.2]
-            $this->_temp['modified'] = $this->fromSequenceString($data);
+            $this->_temp['modified'] = $this->_utils->fromSequenceString($data);
             break;
 
         case 'CLOSED':
diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Utils.php b/framework/Imap_Client/lib/Horde/Imap/Client/Utils.php
new file mode 100644 (file)
index 0000000..621a01a
--- /dev/null
@@ -0,0 +1,364 @@
+<?php
+/**
+ * Horde_Imap_Client_Utils provides utility functions for the Horde IMAP client.
+ *
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * getBaseSubject() code adapted from imap-base-subject.c (Dovecot 1.2)
+ *   Original code released under the LGPL v2.1
+ *   Copyright (c) 2002-2008 Timo Sirainen <tss@iki.fi>
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author   Michael Slusarz <slusarz@curecanti.org>
+ * @category Horde
+ * @package  Horde_Imap_Client
+ */
+class Horde_Imap_Client_Utils
+{
+    /**
+     * Create an IMAP message sequence string from a list of indices.
+     * Format: range_start:range_end,uid,uid2,range2_start:range2_end,...
+     *
+     * @param array $in  An array of indices.
+     * @param array $options  Additional options:
+     * <pre>
+     * 'nosort' - (boolean) Do not numerically sort the IDs before creating
+     *            the range?
+     *            DEFAULT: IDs are sorted
+     * </pre>
+     *
+     * @return string  The IMAP message sequence string.
+     */
+    public function toSequenceString($ids, $options = array())
+    {
+        if (empty($ids)) {
+            return '';
+        }
+
+        // Make sure IDs are unique
+        $ids = array_keys(array_flip($ids));
+
+        if (empty($options['nosort'])) {
+            sort($ids, SORT_NUMERIC);
+        }
+
+        $first = $last = array_shift($ids);
+        $out = array();
+
+        foreach ($ids as $val) {
+            if ($last + 1 == $val) {
+                $last = $val;
+            } else {
+                $out[] = $first . ($last == $first ? '' : (':' . $last));
+                $first = $last = $val;
+            }
+        }
+        $out[] = $first . ($last == $first ? '' : (':' . $last));
+
+        return implode(',', $out);
+    }
+
+    /**
+     * Parse an IMAP message sequence string into a list of indices.
+     * Format: range_start:range_end,uid,uid2,range2_start:range2_end,...
+     *
+     * @param string $str  The IMAP message sequence string.
+     *
+     * @return array  An array of indices.
+     */
+    public function fromSequenceString($str)
+    {
+        $ids = array();
+        $str = trim($str);
+
+        $idarray = explode(',', $str);
+        if (empty($idarray)) {
+            $idarray = array($str);
+        }
+
+        foreach ($idarray as $val) {
+            $range = array_map('intval', explode(':', $val));
+            if (count($range) == 1) {
+                $ids[] = $val;
+            } else {
+                list($low, $high) = ($range[0] < $range[1]) ? $range : array_reverse($range);
+                $ids = array_merge($ids, range($low, $high));
+            }
+        }
+
+        return $ids;
+    }
+
+    /**
+     * Remove "bare newlines" from a string.
+     *
+     * @param string $str  The original string.
+     *
+     * @return string  The string with all bare newlines removed.
+     */
+    public function removeBareNewlines($str)
+    {
+        return str_replace(array("\r\n", "\n"), array("\n", "\r\n"), $str);
+    }
+
+    /**
+     * Escape IMAP output via a quoted string (see RFC 3501 [4.3]).
+     *
+     * @param string $str  The unescaped string.
+     *
+     * @return string  The escaped string.
+     */
+    public function escape($str)
+    {
+        return '"' . addcslashes($str, '"\\') . '"';
+    }
+
+    /**
+     * Return the "base subject" defined in RFC 5256 [2.1].
+     *
+     * @param string $str     The original subject string.
+     * @param array $options  Additional options:
+     * <pre>
+     * 'keepblob' - (boolean) Don't remove any "blob" information (i.e. text
+     *              leading text between square brackets) from string.
+     * </pre>
+     *
+     * @return string  The cleaned up subject string.
+     */
+    public function getBaseSubject($str, $options = array())
+    {
+        // Rule 1a: MIME decode to UTF-8 (if possible).
+        $str = Horde_Mime::decode($str, 'UTF-8');
+
+        // Rule 1b: Remove superfluous whitespace.
+        $str = preg_replace("/\s{2,}/", '', $str);
+
+        if (!$str) {
+            return '';
+        }
+
+        do {
+            /* (2) Remove all trailing text of the subject that matches the
+             * the subj-trailer ABNF, repeat until no more matches are
+             * possible. */
+            $str = preg_replace("/(?:\s*\(fwd\)\s*)+$/i", '', $str);
+
+            do {
+                /* (3) Remove all prefix text of the subject that matches the
+                 * subj-leader ABNF. */
+                $found = $this->_removeSubjLeader($str, !empty($options['keepblob']));
+
+                /* (4) If there is prefix text of the subject that matches
+                 * the subj-blob ABNF, and removing that prefix leaves a
+                 * non-empty subj-base, then remove the prefix text. */
+                $found = (empty($options['keepblob']) && $this->_removeBlobWhenNonempty($str)) || $found;
+
+                /* (5) Repeat (3) and (4) until no matches remain. */
+            } while ($found);
+
+            /* (6) If the resulting text begins with the subj-fwd-hdr ABNF and
+             * ends with the subj-fwd-trl ABNF, remove the subj-fwd-hdr and
+             * subj-fwd-trl and repeat from step (2). */
+        } while ($this->_removeSubjFwdHdr($str));
+
+        return $str;
+    }
+
+    /**
+     * Parse an IMAP URL (RFC 5092).
+     *
+     * @param string $url  A IMAP URL string.
+     *
+     * @return mixed  False if the URL is invalid.  If valid, a URL with the
+     *                following fields:
+     * <pre>
+     * 'auth' - (string) The authentication method to use.
+     * 'port' - (integer) The remote port
+     * 'hostspec' - (string) The remote server
+     * 'username' - (string) The username to use on the remote server.
+     * </pre>
+     */
+    public function parseImapUrl($url)
+    {
+        $url = trim($url);
+        if (stripos($url, 'imap://') !== 0) {
+            return false;
+        }
+        $url = substr($url, 7);
+
+        /* At present, only support imap://<iserver>[/] style URLs. */
+        if (($pos = strpos($url, '/')) !== false) {
+            $url = substr($url, 0, $pos);
+        }
+
+        $ret_array = array();
+
+        /* Check for username/auth information. */
+        if (($pos = strpos($url, '@')) !== false) {
+            if ((($apos = stripos($url, ';AUTH=')) !== false) &&
+                ($apos < $pos)) {
+                $auth = substr($url, $apos + 6, $pos - $apos - 6);
+                if ($auth != '*') {
+                    $ret_array['auth'] = $auth;
+                }
+                if ($apos) {
+                    $ret_array['username'] = substr($url, 0, $apos);
+                }
+            }
+            $url = substr($url, $pos + 1);
+        }
+
+        /* Check for port information. */
+        if (($pos = strpos($url, ':')) !== false) {
+            $ret_array['port'] = substr($url, $pos + 1);
+            $url = substr($url, 0, $pos);
+        }
+
+        $ret_array['hostspec'] = $url;
+
+        return $ret_array;
+    }
+
+    /**
+     * Remove all prefix text of the subject that matches the subj-leader
+     * ABNF.
+     *
+     * @param string &$str       The subject string.
+     * @param boolean $keepblob  Remove blob information?
+     *
+     * @return boolean  True if string was altered.
+     */
+    protected function _removeSubjLeader(&$str, $keepblob = false)
+    {
+        $ret = false;
+
+        if (!$str) {
+            return $ret;
+        }
+
+        if ($str[0] == ' ') {
+            $str = substr($str, 1);
+            $ret = true;
+        }
+
+        $i = 0;
+
+        if (!$keepblob) {
+            while ($str[$i] == '[') {
+                if (($i = $this->_removeBlob($str, $i)) === false) {
+                    return $ret;
+                }
+            }
+        }
+
+        $cmp_str = substr($str, $i);
+        if (stripos($cmp_str, 're') === 0) {
+            $i += 2;
+        } elseif (stripos($cmp_str, 'fwd') === 0) {
+            $i += 3;
+        } elseif (stripos($cmp_str, 'fw') === 0) {
+            $i += 2;
+        } else {
+            return $ret;
+        }
+
+        if ($str[$i] == ' ') {
+            ++$i;
+        }
+
+        if (!$keepblob) {
+            while ($str[$i] == '[') {
+                if (($i = $this->_removeBlob($str, $i)) === false) {
+                    return $ret;
+                }
+            }
+        }
+
+        if ($str[$i] != ':') {
+            return $ret;
+        }
+
+        $str = substr($str, ++$i);
+
+        return true;
+    }
+
+    /**
+     * Remove "[...]" text.
+     *
+     * @param string &$str  The subject string.
+     *
+     * @return boolean  True if string was altered.
+     */
+    protected function _removeBlob($str, $i)
+    {
+        if ($str[$i] != '[') {
+            return false;
+        }
+
+        ++$i;
+
+        for ($cnt = strlen($str); $i < $cnt; ++$i) {
+            if ($str[$i] == ']') {
+                break;
+            }
+
+            if ($str[$i] == '[') {
+                return false;
+            }
+        }
+
+        if ($i == ($cnt - 1)) {
+            return false;
+        }
+
+        ++$i;
+
+        if ($str[$i] == ' ') {
+            ++$i;
+        }
+
+        return $i;
+    }
+
+    /**
+     * Remove "[...]" text if it doesn't result in the subject becoming
+     * empty.
+     *
+     * @param string &$str  The subject string.
+     *
+     * @return boolean  True if string was altered.
+     */
+    protected function _removeBlobWhenNonempty(&$str)
+    {
+        if ($str &&
+            ($str[0] == '[') &&
+            (($i = $this->_removeBlob($str, 0)) !== false) &&
+            ($i != strlen($str))) {
+            $str = substr($str, $i);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Remove a "[fwd: ... ]" string.
+     *
+     * @param string &$str  The subject string.
+     *
+     * @return boolean  True if string was altered.
+     */
+    protected function _removeSubjFwdHdr(&$str)
+    {
+        if ((stripos($str, '[fwd:') !== 0) || (substr($str, -1) != ']')) {
+            return false;
+        }
+
+        $str = substr($str, 5, -1);
+        return true;
+    }
+
+}
index 8c578bb..b301642 100644 (file)
@@ -54,6 +54,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
        <file name="Sort.php" role="php" />
        <file name="Thread.php" role="php" />
        <file name="Utf7imap.php" role="php" />
+       <file name="Utils.php" role="php" />
       </dir> <!-- /lib/Horde/Imap/Client -->
       <file name="Client.php" role="php" />
      </dir> <!-- /lib/Horde/Imap -->
@@ -111,6 +112,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
    <install name="lib/Horde/Imap/Client/Sort.php" as="Horde/Imap/Client/Sort.php" />
    <install name="lib/Horde/Imap/Client/Thread.php" as="Horde/Imap/Client/Thread.php" />
    <install name="lib/Horde/Imap/Client/Utf7imap.php" as="Horde/Imap/Client/Utf7imap.php" />
+   <install name="lib/Horde/Imap/Client/Utils.php" as="Horde/Imap/Client/Utils.php" />
    <install name="lib/Horde/Imap/Client.php" as="Horde/Imap/Client.php" />
   </filelist>
  </phprelease>
index 25acc9c..161be14 100644 (file)
@@ -74,7 +74,7 @@ if (empty($argv[2])) {
 }
 
 if (!empty($argv[3])) {
-    $params = array_merge($params, Horde_Imap_Client::parseImapUrl($argv[3]));
+    $params = array_merge($params, $imap_utils->parseImapUrl($argv[3]));
 }
 
 function exception_handler($exception) {
@@ -92,6 +92,7 @@ if (@include_once 'Benchmark/Timer.php') {
 // Add an ID field to send to server (ID extension)
 $params['id'] = array('name' => 'Horde_Imap_Client test program');
 
+$imap_utils = new Horde_Imap_Client_Utils();
 $imap_client = Horde_Imap_Client::getInstance($driver, $params);
 if ($driver == 'Cclient_Pop3') {
     $test_mbox = $test_mbox_utf8 = 'INBOX';
@@ -536,7 +537,7 @@ try {
 print "\nSort 1st 5 messages in " . $test_mbox . " by thread - references algorithm (UIDs).\n";
 try {
     $ten_query = new Horde_Imap_Client_Search_Query();
-    $ten_query->sequence(Horde_Imap_Client::fromSequenceString('1:5'), true);
+    $ten_query->sequence($imap_utils->fromSequenceString('1:5'), true);
     print_r($imap_client->thread($test_mbox, array('search' => $ten_query, 'criteria' => Horde_Imap_Client::THREAD_REFERENCES)));
     print "Thread search: OK\n";
 } catch (Horde_Imap_Client_Exception $e) {
@@ -854,7 +855,7 @@ $subject_lines = array(
 print "\nBase subject parsing:\n";
 foreach ($subject_lines as $val) {
     print "  ORIGINAL: \"" . $val . "\"\n";
-    print "  BASE: \"" . Horde_Imap_Client::getBaseSubject($val) . "\"\n\n";
+    print "  BASE: \"" . $imap_utils->getBaseSubject($val) . "\"\n\n";
 }
 
 $imap_urls = array(
@@ -874,7 +875,7 @@ print "\nRFC 5092 URL parsing:\n";
 foreach ($imap_urls as $val) {
     print "URL: " . $val . "\n";
     print "PARSED:\n";
-    print_r(Horde_Imap_Client::parseImapUrl($val));
+    print_r($imap_utils->parseImapUrl($val));
     print "\n";
 }