steffen: server/kolab-horde-framework/kolab-horde-framework/IMAP/IMAP ACL.php, NONE, 1.1 Admin.php, NONE, 1.1 Cache.php, NONE, 1.1 Search.php, NONE, 1.1 Sort.php, NONE, 1.1 Tree.php, NONE, 1.1

cvs at intevation.de cvs at intevation.de
Fri Oct 14 16:33:07 CEST 2005


Author: steffen

Update of /kolabrepository/server/kolab-horde-framework/kolab-horde-framework/IMAP/IMAP
In directory doto:/tmp/cvs-serv28903/kolab-horde-framework/kolab-horde-framework/IMAP/IMAP

Added Files:
	ACL.php Admin.php Cache.php Search.php Sort.php Tree.php 
Log Message:
Separated Horde Framework from kolab-resource-handlers

--- NEW FILE: ACL.php ---
<?php
/**
 * Contains functions related to managing
 * Access Control Lists.
 *
 * $Horde: framework/IMAP/IMAP/ACL.php,v 1.2 2004/02/19 00:11:20 jan Exp $
 *
 * Copyright 2003-2004 Chris Hastie <imp at oak-wood.co.uk>
 *
 * 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  Chris Hastie <imp at oak-wood.co.uk>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 * @package Horde_IMAP
 */
class IMAP_ACL {

    /**
     * Hash containing connection parameters.
     *
     * @var array $_params
     */
    var $_params = array();

    /**
     * Boolean indicating if the driver is supported by the server
     *
     * @var boolean $_supported
     */
    var $_supported = false;

    /**
     * Any PEAR_Error that occured but couldn't be returned directly.
     *
     * @var object PEAR_Error $_error
     */
    var $_error = null;

    /**
     * Hash containing the list of possible rights and a human
     * readable description of each
     * 
     * Array (
     *     right-id => right-description   
     * )
     *
     * @var array $_rightsList
     */
    var $_rightsList = array();

    /**
     * Array containing user names that can not have their access
     * rights changed.
     *
     * @var boolean $_protected
     */
    var $_protected;

    /**
     * Constructor.
     *
     * @access public
     *
     * @param optional array $params  Hash containing connection parameters.
     */
    function IMAP_ACL($params = array())
    {
        $this->_params = $params;
    }    

    /**
     * Attempts to retrieve the existing ACL for a folder from 
     * the current IMAP server. If protocol is imap/ssl, will
     * only attempt ssl connection with PHP >= 4.3
     *
     * @access public
     *
     * @param string folder  The folder to get the ACL for
     *
     * @return array  A hash containing information on the ACL
     *                Array (
     *                    user => Array (
     *                                right => 1
     *                            )
     *                )
     */
    function getACL($folder)
    {
        return false;
    }

    /**
     * Sets the ACL on an IMAP server
     *
     * @access public
     *
     * @param string $folder  The folder on which to edit the ACL
     *                           
     * @param string $share_user  The user to grant rights to
     *
     * @param array $acl  An array, the keys of which are the 
     *                    rights to be granted (see RFC 2086)
     *
     * @return mixed  True on success, false on failure unless
     *                server doesn't support ACLs, returns 'no_support'
     */
    function createACL($folder, $share_user, $acl)
    {
        return false;
    }

    /**
     * Edits an ACL on an IMAP server
     *
     * @access public
     *
     * @param string $folder  The folder on which to edit the ACL
     *                           
     * @param string $share_user  The user to grant rights to
     *
     * @param array $acl  An array, the keys of which are the 
     *                    rights to be granted (see RFC 2086)
     *
     * @return mixed  True on success, false on failure unless
     *                server doesn't support ACLs, returns 'no_support'
     */
    function editACL($folder, $share_user, $acl)
    {
        return false;
    }    

    /**
     * Can a user edit the ACL for this folder? Returns true if $user   
     * permission to edit the ACL on $folder
     *
     * @param string $folder  The folder name
     *
     * @param string $user  A user name
     *
     * @returns boolean  True if $user has 'a' right
     */
    function canEdit($folder, $user)
    {
        return true;
    }

    function getRights()
    {
        return $this->_rightsList;
    }

    function getProtected()
    {
        return $this->_protected;
    }

    function isSupported()
    {
        return $this->_supported;
    }

    function getError()
    {
        $error = $this->_error;
        $this->_error = null;
        return $error;
    }

    /**
     * Attempts to return an ACL instance based on $driver.
     *
     * @access public
     *
     * @param string $driver          The type of concrete ACL subclass
     *                                to return.  The is based on the acl
     *                                source ($driver).  The code is
     *                                dynamically included.
     *
     * @param optional array $params  A hash containing any additional
     *                                configuration or connection parameters
     *                                a subclass might need.
     *
     * @return mixed  The newly created concrete ACL instance, or false
     *                on error.
     */
    function &factory($driver, $params = array())
    {
        $driver = basename($driver);
        require_once dirname(__FILE__) . '/ACL/' . $driver . '.php';
        $class = 'IMAP_ACL_' . $driver;
        if (class_exists($class)) {
            return $ret = &new $class($params);
        } else {
            return false;
        }
    }

    /**
     * Attempts to return a reference to a concrete ACL instance
     * based on $driver.  It will only create a new instance if no
     * ACL instance with the same parameters currently exists.
     *
     * This method must be invoked as: $var = &IMAP_ACL::singleton()
     *
     * @access public
     *
     * @param string $driver          The type of concrete ACL subclass
     *                                to return.  The is based on the acl
     *                                source ($driver).  The code is
     *                                dynamically included.
     *
     * @param optional array $params  A hash containing any additional
     *                                configuration or connection parameters
     *                                a subclass might need.
     *
     * @return mixed  The created concrete ACL instance, or false on error.
     */
    function &singleton($driver, $params = array())
    {
        static $instances;

        if (!isset($instances)) {
            $instances = array();
        }

        $signature = serialize(array($driver, $params));
        if (!isset($instances[$signature])) {
            $instances[$signature] = &IMAP_ACL::factory($driver, $params);
        }

        return $instances[$signature];
    }

}

--- NEW FILE: Admin.php ---
<?php
/**
 * The IMAP_Admin:: class allow managing of mailboxes on IMAP servers.
 *
 * <pre>
 * Required parameters:
 * ====================
 *  'admin_user'      --  The name of a user with admin privileges.
 *  'admin_password'  --  The password of the adminstrator.
 *
 * Optional parameters:
 * ====================
 *  'hostspec'       --  The hostname or IP address of the server.
 *                       DEFAULT: 'localhost'
 *  'port'           --  The server port to which we will connect.
 *                       IMAP is generally 143, while IMAP-SSL is generally 993.
 *                       DEFAULT: 143
 *  'protocol'       --  The connection protocol (e.g. 'imap', 'pop3', 'nntp').
 *                       Protocol is one of 'imap/notls' (or only 'imap' if you
 *                       have a c-client version 2000c or older), 'imap/ssl',
 *                       or 'imap/ssl/novalidate-cert' (for a self-signed
 *                       certificate).
 *                       DEFAULT: 'imap'
 *  'userhierarchy'  --  The hierarchy where user mailboxes are stored.
 *                       DEFAULT: 'user.'
 *  'dsn'            --  The full IMAP connection string.
 *                       If not present, this is built from 'hostspec', 'port'
 *                       and 'protocol' parameters.
 * </pre>
 *
 * $Horde: framework/IMAP/IMAP/Admin.php,v 1.3 2004/04/17 14:24:13 jan Exp $
 *
 * Copyright 2004 Jan Schneider <jan at horde.org>
 *
 * 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  Jan Schneider <jan at horde.org>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 * @package Horde_IMAP
 */
class IMAP_Admin {

    /**
     * Parameter hash.
     *
     * @var array $_params
     */
    var $_params;

    /**
     * IMAP resource.
     *
     * @var resource $_imap
     */
    var $_imap;

    /**
     * Constructor.
     *
     * @param array $params  A hash with all necessary parameters
     */
    function IMAP_Admin($params)
    {
        $default_params = array(
            'hostspec' => 'localhost',
            'port' => '143',
            'protocol' => 'imap',
            'userhierarchy' => 'user.'
        );
        $this->_params = array_merge($default_params, $params);

        /* Create DSN string. */
        if (!isset($this->_params['dsn'])) {
            $this->_params['dsn'] = sprintf('{%s:%d/%s}',
                                            $this->_params['hostspec'],
                                            $this->_params['port'],
                                            $this->_params['protocol']);
            $this->_ref = $this->_params['dsn'];
            if (!empty($this->_params['folder'])) {
                $this->_params['dsn'] .= $this->_params['folder'];
            }
        } else {
            $this->_ref = substr($this->_params['dsn'], 0, strpos($this->_params['dsn'], '}') + 1);
        }
    }

    /**
     * Connects to the IMAP server with the parameters passed to the
     * constructor.
     *
     * @return resource|object  An IMAP resource or a PEAR_Error on failure
     */
    function _connect()
    {
        if (!isset($this->_imap)) {
            $this->_imap = @imap_open($this->_ref,
                                      $this->_params['admin_user'],
                                      $this->_params['admin_password'],
                                      OP_HALFOPEN);
            if (!$this->_imap) {
                $this->_imap = PEAR::raiseError(imap_last_error(), 'horde.error');
            }
        }
        return $this->_imap;
    }

    /**
     * Adds a mailbox.
     *
     * @param string $mailbox      The mailbox name to add.
     *
     * @return mixed  True on success or a PEAR_Error object on failure.
     */
    function addMailbox($mailbox)
    {
        require_once dirname(__FILE__) . '/ACL.php';

        if (is_a($imap = $this->_connect(), 'PEAR_Error')) {
            return $imap;
        }
        if (!@imap_createmailbox($imap, $this->_ref . $this->_params['userhierarchy'] . $mailbox)) {
            return PEAR::raiseError(imap_last_error(), 'horde.warning');
        }

        $params = array('username' => $this->_params['admin_user'],
                        'password' => $this->_params['admin_password'],
                        'hostspec' => $this->_params['hostspec'],
                        'port' => $this->_params['port'],
                        'protocol' => $this->_params['protocol']);
        $acl = &IMAP_ACL::factory('rfc2086', $params);
        $result = $acl->createACL($this->_params['userhierarchy'] . $mailbox,
                                  $this->_params['admin_user'],
                                  array('l' => true,
                                        'r' => true,
                                        's' => true,
                                        'w' => true,
                                        'i' => true,
                                        'p' => true,
                                        'c' => true,
                                        'd' => true,
                                        'a' => true));
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }
        return true;
    }

    /**
     * Deletes a mailbox.
     *
     * @param string $mailbox  The mailbox to delete.
     *
     * @return mixed  True on success or a PEAR_Error object on failure.
     */
    function removeMailbox($mailbox)
    {
        if (is_a($imap = $this->_connect(), 'PEAR_Error')) {
            return $imap;
        }
        if (!@imap_deletemailbox($imap, $this->_ref . $this->_params['userhierarchy'] . $mailbox)) {
            return PEAR::raiseError(imap_last_error(), 'horde.warning');
        }
        return true;
    }

    /**
     * List all mailboxes.
     *
     * @return mixed  The array of mailboxes, or a PEAR_Error object on failure.
     */
    function listMailboxes()
    {
        if (is_a($imap = $this->_connect(), 'PEAR_Error')) {
            return $imap;
        }
        $list = @imap_list($imap, $this->_ref, $this->_params['userhierarchy'] . '%');
        if (!$list) {
            return array();
        }
        $list = preg_replace('/.*' . $this->_params['userhierarchy'] . '(.*)/', '\\1', $list);
        return $list;
    }
}

--- NEW FILE: Cache.php ---
<?php
/**
 * The IMAP_Cache:: class facilitates in caching output from the PHP imap
 * extension in the current session.
 *
 * $Horde: framework/IMAP/IMAP/Cache.php,v 1.4 2004/01/01 15:14:17 jan Exp $
 *
 * Copyright 2003-2004 Michael Slusarz <slusarz at bigworm.colorado.edu>
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * @author  Michael Slusarz <slusarz at bigworm.colorado.edu>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 * @package Horde_IMAP
 */
class IMAP_Cache {

    /**
     * Pointer to the session cache.
     *
     * @var array $_cache
     */
    var $_cache;

    /**
     * Returns a reference to the global IMAP_Cache object, only creating
     * it if it doesn't already exist.
     *
     * This method must be invoked as:
     *   $imap_cache = &IMAP_Cache::singleton();
     *
     * @access public
     *
     * @param optional array $params  Any parameters the constructor may need.
     *
     * @return object IMAP_Cache  The IMAP_Cache instance.
     */
    function &singleton($params = array())
    {
        static $object;

        if (!isset($object)) {
            $object = &new IMAP_Cache($params);
        }

        return $object;
    }

    /**
     * Constructor
     *
     * @access public
     *
     * @param optional array $params  Not used.
     */
    function IMAP_Cache($params = array())
    {
        if (!isset($_SESSION['imap_cache'])) {
            $_SESSION['imap_cache'] = array();
        }
        $this->_cache = &$_SESSION['imap_cache'];
    }

    /**
     * Get data from the cache.
     *
     * @access public
     *
     * @param resource &$imap          The IMAP resource stream.
     * @param string $mailbox          The full ({hostname}mailbox) mailbox
     *                                 name.
     * @param optional string $key     The name of a specific entry to return.
     * @param optional boolean $check  Check for updated mailbox?
     *
     * @return mixed  The data requested, or false if not available.
     */
    function getCache(&$imap, $mailbox, $key = null, $check = true)
    {
        if (isset($this->_cache[$mailbox])) {
            if (!$check || $this->checkCache($imap, $mailbox)) {
                $ptr = &$this->_cache[$mailbox];
                if (!is_null($key)) {
                    if (isset($ptr['d'][$key])) {
                        return $ptr['d'][$key];
                    }
                } else {
                    return $ptr['d'];
                }
            }
        }
        return false;
    }

    /**
     * Is the cache information up-to-date?
     *
     * @access public
     *
     * @param resource &$imap           The IMAP resource stream.
     * @param string $mailbox           The full ({hostname}mailbox) mailbox
     *                                  name.
     * @param optional boolean $update  Should the cache ID string be updated?
     *
     * @return boolean  True if cache information up-to-date, false if not. 
     */
    function checkCache(&$imap, $mailbox, $update = false)
    {
        if (isset($this->_cache[$mailbox])) {
            $id = $this->_getCacheID($imap, $mailbox);
            if ($this->_cache[$mailbox]['k'] == $id) {
                return true;
            } elseif ($update) {
                $this->storeCache($imap, $mailbox);
            }
        } elseif ($update) {
            $this->storeCache($imap, $mailbox);
        }
        return false;
    }

    /**
     * Store data in the cache.
     *
     * @access public
     *
     * @param resource &$imap         The IMAP resource stream.
     * @param string $mailbox         The full ({hostname}mailbox) mailbox
     *                                name.
     * @param optional array $values  The data to add to the cache.
     */
    function storeCache(&$imap, $mailbox, $values = array())
    {
        $id = $this->_getCacheID($imap, $mailbox);
        if (!isset($this->_cache[$mailbox])) {
            $this->_cache[$mailbox] = array('k' => $id, 'd' => $values);
        } else {
            $ptr = &$this->_cache[$mailbox];
            $ptr['k'] = $id;
            $ptr['d'] = array_merge($values, $ptr['d']);
        }
    }

    /**
     * Generate the unique ID string for the mailbox.
     *
     * @access private
     *
     * @param resource &$imap  The IMAP resource stream.
     * @param string $mailbox  The full ({hostname}mailbox) mailbox name.
     *
     * @return string  A unique string for the current state of the mailbox.
     */
    function _getCacheID(&$imap, $mailbox)
    {
        $ob = @imap_status($imap, $mailbox, SA_MESSAGES | SA_RECENT | SA_UNSEEN | SA_UIDNEXT);
        return implode('|', array($ob->messages, $ob->recent, $ob->unseen, $ob->uidnext));
    }

}

--- NEW FILE: Search.php ---
<?php
/**
 * The IMAP_Search:: class performs complex searching of an IMAP mailbox.
 *
 * Classes to help with complex searching of an IMAP mailbox.
 * The built-in PHP search() function only allows IMAPv2 search queries
 * (see RFC 1176).  This library allows more complex searches to be
 * created (e.g. OR searches, searching specific headers).
 *
 * $Horde: framework/IMAP/IMAP/Search.php,v 1.26 2004/04/07 14:43:09 chuck Exp $
 *
 * Copyright 2003-2004 Michael Slusarz <slusarz at bigworm.colorado.edu>
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * @author  Michael Slusarz <slusarz at bigworm.colorado.edu>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 * @package Horde_IMAP
 */
class IMAP_Search {

    /**
     * The headers cache.
     *
     * @var array $_headers
     */
    var $_headers = array();

    /**
     * The results cache.
     *
     * @var array $_result
     */
    var $_result = array();

    /**
     * Are we dealing with a POP3 connection?
     *
     * @var boolean $_pop3
     */
    var $_pop3 = false;

    /**
     * Internal flag used by searchMailbox().
     *
     * @var integer $_searchflag
     */
    var $_searchflag = 0;

    /**
     * Returns a reference to the global IMAP_Search object,
     * only creating it if it doesn't already exist.
     *
     * This method must be invoked as:
     *   $imap_search = &IMAP_Search::singleton();
     *
     * @access public
     *
     * @param optional array $params  Any parameters the constructor may need.
     *
     * @return object IMAP_Search  The IMAP_Search instance.
     */
    function &singleton($params = array())
    {
        static $object;

        if (!isset($object)) {
            $object = new IMAP_Search($params);
        }

        return $object;
    }

    /**
     * Constructor
     *
     * @access public
     *
     * @param optional array $params  A hash containing the following entries:
     *                                'pop3' => boolean (using POP3
     *                                                   connection?)
     */
    function IMAP_Search($params = array())
    {
        if (isset($params['pop3'])) {
            $this->_pop3 = $params['pop3'];
        }
    }

    /**
     * Searches messages by ALL headers (rather than the limited set
     * provided by imap_search()).
     *
     * @access public
     *
     * @param object IMAP_Search_Query $query  The search query.
     * @param resource &$imap                  An IMAP resource stream.
     * @param string $mbox                     The name of the mailbox to
     *                                         search. For POP3, this should
     *                                         be empty.
     *
     * @return array  The list of indices that match the search rules in the
     *                current mailbox.
     *                Returns PEAR_Error on error.
     */
    function searchMailbox($query, &$imap, $mbox)
    {
        /* Check for IMAP extension. */
        if (!Util::extensionExists('imap')) {
            Horde::fatal(PEAR::raiseError("This function requires 'imap' to be built into PHP."), __FILE__, __LINE__, false);
        }

        /* Open to the correct mailbox. */
        if (!$this->_pop3) {
            @imap_reopen($imap, $mbox);
        }

        /* Clear the search flag. */
        $this->_searchflag = 0;

        return $this->_searchMailbox($query, $imap, $mbox);
    }

    /**
     * Search the mailbox and sort the results.
     *
     * @access public
     *
     * @param object IMAP_Search_Query $query  The search query.
     * @param resource &$imap                  An IMAP resource stream.
     * @param string $mbox                     The name of the mailbox to
     *                                         search.
     * @param integer $criteria                The criteria to sort by
     *                                         (see imap_sort()).
     * @param optional integer $dir            1 for reverse sorting.
     *
     * @return array  The list of indices that match the search rules in the
     *                current mailbox and sorted.
     *                Returns PEAR_Error on error.
     */
    function searchSortMailbox($query, &$imap, $mbox, $criteria, $dir = 0)
    {
        $indices = $this->searchMailbox($query, $imap, $mbox);
        if (is_a($indices, 'PEAR_Error')) {
            return $indices;
        } else {
            $indices_sort = @imap_sort($imap, $sortby, $sortdir, SE_UID);
            return array_values(array_intersect($indices_sort, $indices));
        }
    }

    /**
     * Internal function to search the mailbox.
     *
     * @access private
     */
    function _searchMailbox($query, &$imap, $mbox)
    {
        $indices = array();

        /* Do the simple searches that imap_search() can handle. */
        if (($ob = $query->build())) {
            if ($ob->not) {
                if (!($indices1 = @imap_search($imap, $ob->flags, SE_UID))) {
                    $indices1 = array();
                }
                if (!($indices2 = @imap_search($imap, $ob->query, SE_UID))) {
                    $indices2 = array();
                }
                $indices = array_diff($indices1, $indices2);
            } else {
                if (!($indices = @imap_search($imap, $ob->fullquery, SE_UID))) {
                    $indices = array();
                }
            }

            /* Set the search flag. */
            if ($this->_searchflag == 0) {
                $this->_searchflag = 1;
            }
        }

        /* Process extended searches. */
        if (($extended = $query->extendedSearch())) {
            $result = $this->_searchPHP($extended, $query->flags(), $imap, $mbox);
            /* Set the search flag. */
            if ($this->_searchflag == 0) {
                $indices = $result;
                $this->_searchflag = 1;
            } else {
                $indices = array_values(array_intersect($indices, $result));
            }
        }

        /* Process size searches. */
        if (($sizeOb = $query->sizeSearch())) {
            $overview = @imap_fetch_overview($imap, implode(',', $indices), FT_UID);
            $func = create_function('$a', 'return ($a ' . $sizeOb->sizeop . ' ' . $sizeOb->size . ');');
            $result = array();
            foreach ($overview as $val) {
                if ($func($val->size)) {
                    $result[] = $val->uid;
                }
            }
            $indices = array_values(array_intersect($indices, $result));
        }

        /* Process AND searches now. */
        $indices = $this->_doAndOrSearch($query->andSearch(), $imap, $mbox, 'and', $indices);

        /* Process OR searches now. */
        $indices = $this->_doAndOrSearch($query->orSearch(), $imap, $mbox, 'or', $indices);

        return $indices;
    }

    /**
     * Internal function to search the mailbox.
     *
     * @access private
     */
    function _doAndOrSearch($query, &$imap, $mbox, $mode, $indices,
                            $base = false)
    {
        if (empty($query)) {
            return $indices;
        }

        foreach ($query as $val) {
            if (is_a($val, 'IMAP_Search_Query')) {
                $result = $this->_searchMailbox($val, $imap, $mbox);
                if ($mode == 'and') {
                    /* If the result is empty in an AND search, we know that
                       the entire AND search will be empty so return
                       immediately. */
                    if (empty($result)) {
                        return array();
                    }

                    /* If we have reached this point, and have not performed
                       a search yet, we must use the results as the indices
                       list. Without this check, the indices list will always
                       be empty if an AND search is the first search. */
                    if (empty($indices) && ($this->_searchflag == 1)) {
                        $indices = $result;
                        $this->_searchflag = 2;
                    } else {
                        $indices = array_values(array_intersect($indices, $result));
                    }
                } elseif (!empty($result)) {
                    $indices = array_unique(array_merge($indices, $result));
                }
            } else {
                $indices = $this->_doAndOrSearch($val, $imap, $mbox, $mode, $indices);
            }
        }

        return $indices;
    }

    /**
     * Use a PHP based functions to perform the search.
     *
     * @access private
     *
     * @param array $imap_query  The search query.
     * @param string $flags      Any additional flags.
     * @param resource &$imap    An IMAP resource stream.
     * @param string $mbox       The name of the search mailbox.
     *
     * @return array  The list of indices that match.
     */
    function _searchPHP($imap_query, $flags, &$imap, $mbox)
    {
        $indices = array();

        if (empty($flags)) {
            $flags = 'ALL';
        }

        if ($this->_pop3) {
            $mbox = 'POP3';
        }

        $cache_key = $mbox . '|' . $flags;

        /* We have to use parseMIMEHeaders() to get each header and see if
           any field matches. Use imap_search() to get the list of message
           indices or return empty list if no search results. */
        if (!isset($this->_result[$cache_key])) {
            $this->_result[$cache_key] = @imap_search($imap, $flags, SE_UID);
        }

        /* If empty message list, return now. */
        if (empty($this->_result[$cache_key])) {
            return array();
        }

        include_once 'Horde/MIME/Structure.php';

        if (!isset($this->_headers[$mbox])) {
            $this->_headers[$mbox] = array();
        }

        /* Get the header/query to search for. */
        $query = reset($imap_query);
        $key = strtolower(key($imap_query));

        foreach ($this->_result[$cache_key] as $index) {
            if (!isset($this->_headers[$mbox][$index])) {
                $this->_headers[$mbox][$index] = MIME_Structure::parseMIMEHeaders(@imap_fetchheader($imap, $index, FT_UID), null, true);
            }
            $h = &$this->_headers[$mbox][$index];

            /* We need to do a case insensitive search on text because,
               for example, e-mail addresses may not be caught correctly
               (filtering for example at example.com will not catch
                exAmple at example.com). */
            if (isset($h[$key]) &&
                (stristr($h[$key], strval($query)) !== false)) {
                $indices[] = $index;
            }
        }

        return $indices;
    }

}

/**
 * The IMAP_Search_Object:: class is used to formulate queries to be used
 * with the IMAP_Search:: class.
 *
 * @author  Michael Slusarz <slusarz at bigworm.colorado.edu>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 * @package Horde_IMAP
 */
class IMAP_Search_Query {

    var $_and = array();
    var $_extendedSearch = array();
    var $_flags = array();
    var $_not = false;
    var $_or = array();
    var $_query = null;
    var $_size = null;
    var $_sizeop = null;

    function IMAP_Search_Query()
    {
    }

    /**
     * Return any extended searches.
     */
    function extendedSearch()
    {
        return $this->_extendedSearch;
    }

    /**
     * Return the parameters for a size search.
     */
    function sizeSearch()
    {
        if (is_null($this->_size)) {
            return null;
        }
        $ob = &new stdClass;
        $ob->size = $this->_size;
        $ob->sizeop = $this->_sizeop;

        return $ob;
    }

    /**
     * Return any AND searches.
     */
    function andSearch()
    {
        return $this->_and;
    }

    /**
     * Return any OR searches.
     */
    function orSearch()
    {
        return $this->_or;
    }

    /**
     * Return the flags.
     */
    function flags()
    {
        return ((empty($this->_flags)) ? '' : implode(' ', $this->_flags));
    }

    /**
     * Build the IMAP search query.
     */
    function build()
    {
        $search = &new stdClass;

        $search->not = $this->_not;
        $search->flags = $this->flags();

        if (empty($this->_query)) {
            if (empty($search->flags)) {
                return '';
            }
            $search->query = 'ALL';
            $search->not = false;
        } else {
            if ($search->not && empty($search->flags)) {
                $search->flags = 'ALL';
            }
            $search->query = $this->_query;
        }
        $search->fullquery = $search->flags . ' ' . $search->query;

        return $search;
    }

    /* IMAP search modifiers. */
    function _modifiers($ob, $cmd)
    {
        if (is_a($ob, 'IMAP_Search_Query')) {
            $ob = array($ob);
        }
        array_push($this->$cmd, $ob);
    }

    function imapAnd($ob)
    {
        $this->_modifiers($ob, '_and');
    }

    function imapOr($ob)
    {
        $this->_modifiers($ob, '_or');
    }

    /* IMAP Search Flags. */
    /* There is no need to support the KEYWORD/UNKEYWORD query since the
       individual keywords have identical functionality. */
    function _imapFlags($flag, $cmd) {
        $cmd = ($flag) ? $cmd : 'UN' . $cmd;
        $this->_flags[] = $cmd;
    }

    function answered($flag)
    {
        $this->_imapFlags($flag, 'ANSWERED');
    }

    function deleted($flag)
    {
        $this->_imapFlags($flag, 'DELETED');
    }

    function flagged($flag)
    {
        $this->_imapFlags($flag, 'FLAGGED');
    }

    function seen($flag)
    {
        $this->_imapFlags($flag, 'SEEN');
    }

    function recent($flag)
    {
        $this->_imapFlags(true, (($flag) ? 'RECENT' : 'OLD'));
    }

    function imapNew()
    {
        $this->_imapFlags(true, 'NEW');
    }

    /* IMAP Header Search. */
    function header($header, $query, $not = false) {
        $header = ucfirst(rtrim($header, ':'));
        $stdHdrs = array('To', 'Cc', 'From', 'Subject');
        if ($query != '') {
            if (in_array($header, $stdHdrs)) {
                $this->_query = String::upper($header) . ' "' . addslashes($query) . '"';
            } else {
                $this->_extendedSearch[$header] = $query;
            }
            $this->_not = $not;
        }
    }

    /* IMAP Date Search. */
    function _imapDate($day, $month, $year, $cmd)
    {
        $this->_query = $cmd . ' ' . date("d-M-y", mktime(0, 0, 0, $month, $day, $year));
    }

    function before($day, $month, $year)
    {
        $this->_imapDate($day, $month, $year, 'BEFORE');
    }

    function since($day, $month, $year)
    {
        $this->_imapDate($day, $month, $year, 'SINCE');
    }

    function on($day, $month, $year)
    {
        $this->_imapDate($day, $month, $year, 'ON');
    }

    /* IMAP Text searches. */
    function body($query, $not = false)
    {
        $this->_query = 'BODY "' . $query . '"';
        $this->_not = $not;
    }

    function text($query, $not = false)
    {
        $this->_query = 'TEXT "' . $query . '"';
        $this->_not = $not;
    }

    /* IMAP Size searches. */
    function size($size, $operator)
    {
        $this->_size = $size;
        $this->_sizeop = $operator;
    }

}

--- NEW FILE: Sort.php ---
<?php
/**
 * IMAP_Sort provides functions for sorting lists of IMAP mailboxes/folders.
 *
 * $Horde: framework/IMAP/IMAP/Sort.php,v 1.2 2004/05/27 14:41:59 jan Exp $
 *
 * Copyright 2004 Michael Slusarz <slusarz at bigworm.colorado.edu>
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * @author  Michael Slusarz <slusarz at bigworm.colorado.edu>
 * @version $Revision: 1.1 $
 * @since   Horde 3.0
 * @package Horde_IMAP
 */
class IMAP_Sort {

    /**
     * The delimiter character to use.
     *
     * @var string $_delimiter
     */
    var $_delimiter = '/';

    /**
     * Should we sort with 'INBOX' at the front of the list?
     *
     * @var boolean $_sortinbox
     */
    var $_sortinbox;

    /**
     * Constructor.
     *
     * @access public
     *
     * @param string $delimiter  The delimiter used to separate mailboxes.
     */
    function IMAP_Sort($delimiter)
    {
        $this->_delimiter = $delimiter;
    }

    /**
     * Sort a list of mailboxes (by value).
     *
     * @access public
     *
     * @param array &$mbox             The list of mailboxes to sort.
     * @param optional boolean $inbox  When sorting, always put 'INBOX' at
     *                                 the head of the list?
     */
    function sortMailboxes(&$mbox, $inbox = true)
    {
        $this->_sortinbox = $inbox;
        usort($mbox, array($this, '_mbox_cmp'));
    }

    /**
     * Sort a list of mailboxes (by key).
     *
     * @access public
     *
     * @param array &$mbox             The list of mailboxes to sort, with
     *                                 the keys being the mailbox names.
     * @param optional boolean $inbox  When sorting, always put 'INBOX' at
     *                                 the head of the list?
     */
    function sortMailboxesByKey(&$mbox, $inbox = true)
    {
        $this->_sortinbox = $inbox;
        uksort($mbox, array($this, '_mbox_cmp'));
    }

    /**
     * Hierarchical folder sorting function (used with usort()).
     *
     * @access private
     *
     * @param string $a  Comparison item #1.
     * @param string $b  Comparison item #2.
     *
     * @return integer  See usort().
     */
    function _mbox_cmp($a, $b)
    {
        /* Always return INBOX as "smaller". */
        if ($this->_sortinbox) {
            if (String::upper($a) == 'INBOX') {
                return -1;
            } elseif (String::upper($b) == 'INBOX') {
                return 1;
            }
        }

        $a_parts = explode($this->_delimiter, $a);
        $b_parts = explode($this->_delimiter, $b);

        $iMax = min(count($a_parts), count($b_parts));
        for ($i = 0; $i < $iMax; $i++) {
            if ($a_parts[$i] != $b_parts[$i]) {
                return strnatcasecmp($a_parts[$i], $b_parts[$i]);
            }
        }

        return count($a_parts) - count($b_parts);
    }

}

--- NEW FILE: Tree.php ---
<?php
/* Constants for mailboxElt attributes.
 * All versions of c-client (c-client/mail.h) define these constants:
 *   LATT_NOINFERIORS (long) 0x1 = 1
 *   LATT_NOSELECT (long) 0x2 = 2
 *   LATT_MARKED (long) 0x4 = 4
 *   LATT_UNMARKED (long) 0x8 = 8
 *
 * Newer versions of c-client (imap-2002 and greater) define these constants:
 *   LATT_REFERRAL (long) 0x10 = 16
 *   LATT_HASCHILDREN (long) 0x20 = 32
 *   LATT_HASNOCHILDREN (long) 0x40 = 64
 * ...but these constant names do not appear in PHP until PHP 4.3.5 and 5.0.
 */
if (!defined('LATT_HASCHILDREN')) {
    @define('LATT_REFERRAL', 16);
    @define('LATT_HASCHILDREN', 32);
    @define('LATT_HASNOCHILDREN', 64);
}
[...1594 lines suppressed...]
     *
     * @param array &$mbox           The list of mailboxes to sort.
     * @param optional boolean $key  Are the list of mailbox names in the key
     *                               field of $mbox?
     */
    function _sortList(&$mbox, $key = false)
    {
        if (is_null($this->_imap_sort)) {
            require_once 'Horde/IMAP/Sort.php';
            $this->_imap_sort = &new IMAP_Sort($this->_delimiter);
        }

        if ($key) {
            $this->_imap_sort->sortMailboxesByKey($mbox, ($this->_mode == IMAPTREE_MODE_MAIL));
        } else {
            $this->_imap_sort->sortMailboxes($mbox, ($this->_mode == IMAPTREE_MODE_MAIL));
        }
    }

}





More information about the commits mailing list