<?php
// Compose encryption options
/** @const IMP_ENCRYPT_NONE Send Message w/no encryption.        */ define('IMP_ENCRYPT_NONE', 1);
/** @const IMP_PGP_ENCRYPT Send Message - PGP Encrypt            */ define('IMP_PGP_ENCRYPT', 2);
/** @const IMP_PGP_SIGN Send Message - PGP Sign                  */ define('IMP_PGP_SIGN', 3);
/** @const IMP_PGP_SIGNENC Send Message - PGP Sign/Encrypt       */ define('IMP_PGP_SIGNENC', 4);
/** @const IMP_SMIME_ENCRYPT Send Message - S/MIME Encrypt       */ define('IMP_SMIME_ENCRYPT', 5);
/** @const IMP_SMIME_SIGN Send Message - S/MIME Sign             */ define('IMP_SMIME_SIGN', 6);
/** @const IMP_SMIME_SIGNENC Send Message - S/MIME Sign/Encrypt. */ define('IMP_SMIME_SIGNENC', 7);

// IMAP Flags
/** @const IMP_ALL Match all IMAP flags.      */ define('IMP_ALL', 0);
/** @const IMP_UNSEEN \\UNSEEN flag.          */ define('IMP_UNSEEN', 1);
/** @const IMP_DELETED \\DELETED flag.        */ define('IMP_DELETED', 2);
/** @const IMP_ANSWERED \\ANSWERED flag.      */ define('IMP_ANSWERED', 4);
/** @const IMP_FLAGGED \\FLAGGED flag.        */ define('IMP_FLAGGED', 8);
/** @const IMP_DRAFT \\DRAFT flag.            */ define('IMP_DRAFT', 16);
/** @const IMP_PERSONAL An email is personal. */ define('IMP_PERSONAL', 32);

// IMAP Sorting Constant
/** @const SORTTHREAD Sort By Thread. */ define('SORTTHREAD', 161);

// IMP Mailbox view constants
/** @const IMP_MAILBOXSTART_UNSEEN Start on the page with the first unseen message. */ define('IMP_MAILBOXSTART_FIRSTUNSEEN', 1);
/** @const IMP_MAILBOXSTART_LASTUNSEEN Start on the page with the last unseen message. */ define('IMP_MAILBOXSTART_LASTUNSEEN', 2);
/** @const IMP_MAILBOXSTART_FIRSTPAGE Start on the first page. */ define('IMP_MAILBOXSTART_FIRSTPAGE', 3);
/** @const IMP_MAILBOXSTART_LASTPAGE Start on the last page. */ define('IMP_MAILBOXSTART_LASTPAGE', 4);

// IMP mailbox labels
/** @const IMP_SEARCH_MBOX The mailbox name to use for search results. */ define('IMP_SEARCH_MBOX', '**search');

// IMP internal indexing strings
define('IMP_MSG_SEP', "\0");
define('IMP_IDX_SEP', "\1");

/**
 * IMP Base Class.
 *
 * $Horde: imp/lib/IMP.php,v 1.396 2003/08/19 17:16:06 slusarz Exp $
 *
 * Copyright 1999-2003 Chuck Hagenbuch <chuck@horde.org>
 * Copyright 1999-2003 Jon Parise <jon@horde.org>
 * Copyright 2002-2003 Michael Slusarz <slusarz@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  Chuck Hagenbuch <chuck@horde.org>
 * @author  Jon Parise <jon@horde.org>
 * @author  Michael Slusarz <slusarz@bigworm.colorado.edu>
 * @version $Revision: 1.396 $
 * @since   IMP 2.3.5
 * @package imp
 */
class IMP {

    /**
     * Make sure the user has been authenticated to view the page.
     *
     * @access public
     *
     * @param optional mixed $flags     Any flags to pass to imap_open().
     *                                  See Auth_imp::authenticate(). However,
     *                                  if this is the string 'horde', we just
     *                                  check for Horde auth and don't bother
     *                                  the IMAP server.
     * @param optional boolean $return  If this is true, return false instead
     *                                  of exiting/redirecting if
     *                                  authentication fails.
     *
     * @return boolean  True on success, false on error.
     */
    function checkAuthentication($flags = 0, $return = false)
    {
        if ($flags === 'horde') {
            $reason = Auth::isAuthenticated();
        } else {
            $auth_imp = &Auth::singleton(array('imp', 'imp'));
            $auth_imp->authenticateOptions(array('flags' => $flags));
            $reason = $auth_imp->authenticate();
        }

        if ($reason !== true) {
            if ($return) {
                return false;
            }

            if (Horde::getFormData('popup')) {
                Horde::closeWindowJS();
            } else {
                $url = Horde::applicationUrl(IMP::logoutUrl('login.php', $reason), true);
                $url = Horde::addParameter($url, 'url', Horde::selfUrl(true));
                $url = Horde::addParameter($url, 'reason', $reason);
                header('Location: ' . $url);
            }
            exit;
        }

        return true;
    }

    /**
     * Determines if the given mail server is the "preferred" mail server for
     * this web server.  This decision is based on the global 'SERVER_NAME'
     * and 'HTTP_HOST' server variables and the contents of the 'preferred'
     * either field in the server's definition.  The 'preferred' field may
     * take a single value or an array of multiple values.
     *
     * @param string $server      A complete server entry from the $servers
     *                            hash.
     * @param optional TODO $key  TODO
     *
     * @return boolean  True if this entry is "preferred".
     */
    function isPreferredServer($server, $key = null)
    {
        static $urlServer;

        if (!isset($urlServer)) {
            $urlServer = Horde::getFormData('server');
        }

        if (!empty($urlServer)) {
            return $key == $urlServer;
        }

        if (!empty($server['preferred'])) {
            if (is_array($server['preferred'])) {
                if (in_array($_SERVER['SERVER_NAME'], $server['preferred']) ||
                    in_array($_SERVER['HTTP_HOST'], $server['preferred'])) {
                    return true;
                }
            } elseif (($server['preferred'] == $_SERVER['SERVER_NAME']) ||
                      ($server['preferred'] == $_SERVER['HTTP_HOST'])) {
                return true;
            }
        }

        return false;
    }

    /**
     * Tack on any prefixes that need to be put at the beginning of
     * the folder path.
     *
     * @return string  The prefix, if any.
     */
    function preambleString()
    {
        return $_SESSION['imp']['folders'] . $_SESSION['imp']['namespace'];
    }

    /**
     * Tack on any prefixes that need to be put at the beginning of
     * the folder path, but don't add it to INBOX, and return the full
     * mailbox name.
     *
     * @param string $mailbox   The folder path that needs the prefixes to be
     *                          prepended.
     *
     * @return string  The full folder path with prefixes if needed.
     */
    function addPreambleString($mailbox)
    {
        if (empty($mailbox) || ($mailbox == 'INBOX')) {
            return $mailbox;
        }
        return IMP::preambleString() . $mailbox;
    }

    /**
     * Remove any prefixes from a full folder path.
     *
     * @param string $mailbox  The folder path to strip the prefix from
     *
     * @return string  The folder path without prefixes.
     */
    function stripPreambleString($mailbox)
    {
        $preamble = IMP::preambleString();
        if (substr($mailbox, 0, strlen($preamble)) == $preamble) {
            $mailbox = substr($mailbox, strlen($preamble));
        }
        return $mailbox;
    }

    /**
     * Generate a full c-client server specification string.
     *
     * @access public
     *
     * @param optional string $mbox      The mailbox to append to end of the
     *                                   server string.
     * @param optional string $protocol  Override the protocol currently
     *                                   being used.
     *
     * @return string  The full spec string.
     */
    function serverString($mbox = null, $protocol = null)
    {
        $srvstr = '{' . $_SESSION['imp']['server'];

        /* If port is not specified, don't include it in the string. */
        if (!empty($_SESSION['imp']['port'])) {
            $srvstr .= ':' . $_SESSION['imp']['port'];
        }

        if (is_null($protocol)) {
            $protocol = $_SESSION['imp']['protocol'];
        }

        /* If protocol is not specified, don't include it in the string. */
        if (!empty($protocol)) {
            $srvstr .= '/' . $protocol;
        }

        return $srvstr . '}' . $mbox;
    }

    /**
     * Get the plain text label that is displayed for the current
     * mailbox, replacing IMP_SEARCH_MBOX with an appropriate string and
     * removing namespace and folder prefix information from what is
     * shown to the user.
     *
     * @access public
     *
     * @return string  The plain text label.
     */
    function getLabel()
    {
        global $imp;

        $label = '';

        if ($imp['mailbox'] == IMP_SEARCH_MBOX) {
            $label = _("Search Results");
        } else {
            $label = String::convertCharset($imp['mailbox'], 'UTF7-IMAP');
            if (strcmp($imp['folders'], String::substr($label, 0, String::length($imp['folders']))) == 0) {
                $label = String::substr($label, String::length($imp['folders']));
            }
            if (strcmp($imp['namespace'], String::substr($label, 0, String::length($imp['namespace']))) == 0) {
                $label = String::substr($label, String::length($imp['namespace']));
            }
        }

        return $label;
    }

    /**
     * Returns the bare address.
     *
     * @access public
     *
     * @param string $address             The address string.
     * @param optional boolean $multiple  Should we return multiple results?
     *
     * @return mixed  See MIME::bareAddress().
     */
    function bareAddress($address, $multiple = false)
    {
        global $imp;

        require_once HORDE_BASE . '/lib/MIME.php';
        return MIME::bareAddress($address, $imp['maildomain'], $multiple);
    }

    /**
     * Use the Registry to expand names and returning error information for
     * any address that is either not valid or fails to expand.
     *
     * @param string $addrString  The name(s) or address(es) to expand.
     * @param bool $full          If true generate a full, rfc822-valid
     *                            address list.
     *
     * @return mixed   Either a string containing all expanded addresses or
     *                 an array containing all matching address or an error
     *                 object.
     */
    function expandAddresses($addrString, $full = false)
    {
        if (!preg_match('|[^\s]|', $addrString)) {
            return '';
        }

        global $prefs, $registry;

        require_once 'Mail/RFC822.php';
        require_once HORDE_BASE . '/lib/MIME.php';

        $addrString = preg_replace('/,\s+/', ',', $addrString);
        $parser = &new Mail_RFC822(null, '@INVALID');
        $search_fields = array();

        $src = explode("\t", $prefs->getValue('search_sources'));
        if ((count($src) == 1) && empty($src[0])) {
            $src = array();
        }

        if (($val = $prefs->getValue('search_fields'))) {
            $field_arr = explode("\n", $val);
            foreach ($field_arr as $field) {
                $field = trim($field);
                if (!empty($field)) {
                    $tmp = explode("\t", $field);
                    if (count($tmp) > 1) {
                        $source = array_splice($tmp, 0, 1);
                        $search_fields[$source[0]] = $tmp;
                    }
                }
            }
        }

        $arr = MIME::rfc822Explode($addrString, ',');
        $results = $registry->call('contacts/search', array($arr, $src, $search_fields));
        if (is_a($results, 'PEAR_Error')) {
            return $results;
        }

        $ambiguous = false;
        $error = false;
        $i = 0;
        $missing = array();

        foreach ($results as $res) {
            $tmp = $arr[$i];
            if ($parser->validateMailbox(MIME::encodeAddress($tmp, null, ''))) {
                // noop
            } elseif (count($res) == 1) {
                if ($full) {
                    if (strpos($res[0]['email'], ',') !== false) {
                        $arr[$i] = $res[0]['name'] . ': ' . $res[0]['email'] . ';';
                    } else {
                        list($mbox, $host) = explode('@', $res[0]['email']);
                        $arr[$i] = MIME::rfc822WriteAddress($mbox, $host, $res[0]['name']);
                    }
                } else {
                    $arr[$i] = $res[0]['name'];
                }
            } elseif (count($res) > 1) {
                /* Handle the multiple case - we return an array with all found
                   addresses. */
                $arr[$i] = array($arr[$i]);
                foreach ($res as $one_res) {
                    if ($full) {
                        if (strpos($one_res['email'], ',') !== false) {
                            $arr[$i][] = $one_res['name'] . ': ' . $one_res['email'] . ';';
                        } else {
                            $mbox_host = explode('@', $one_res['email']);
                            if (isset($mbox_host[1])) {
                                $arr[$i][] = MIME::rfc822WriteAddress($mbox_host[0], $mbox_host[1], $one_res['name']);
                            }
                        }
                    } else {
                        $arr[$i][] = $one_res['name'];
                    }
                }
                $ambiguous = true;
            } else {
                /* Handle the missing/invalid case - we should return error info
                   on each address that couldn't be expanded/validated. */
                $error = true;
                if (!$ambiguous) {
                    $arr[$i] = PEAR::raiseError(null, null, null, null, $arr[$i]);
                    $missing[$i] = $arr[$i];
                }
            }
            $i++;
        }

        if ($ambiguous) {
            foreach ($missing as $i => $addr) {
                $arr[$i] = $addr->getUserInfo();
            }
            return $arr;
        } elseif ($error) {
            return PEAR::raiseError(_("Please resolve ambiguous or invalid addresses."), null, null, null, $res);
        } else {
            return implode(', ', $arr);
        }
    }

    /**
     * Wrapper around IMP_Folder::flist() which generates the body of a
     * &lt;select&gt; form input from the generated folder list. The
     * &lt;select&gt; and &lt;/select&gt; tags are NOT included in the
     * output of this function.
     *
     * @access public
     *
     * @param optional string $heading   An optional string to use as the label
     *                                   for an empty-value option at the top
     *                                   of the list. Defaults to none.
     *
     * @param optional string $heading   An optional string to use as the label
     *                                   for an empty-value option at the top
     *                                   of the list. Defaults to none.
     * @param optional boolean $abbrev   If true, abbreviate long mailbox names
     *                                   by replacing the middle of the name
     *                                   with '...'. Defaults to true.
     * @param optional array $filter     An array of mailboxes to ignore.
     * @param optional string $selected  The mailbox to have selected by
     *                                   default. Defaults to the first option
     *                                   in the list.
     *
     * @return string  A string containg <option> elements for each mailbox in
     *                 the list.
     */
    function flistSelect($heading = '', $abbrev = true, $filter = array(),
                         $selected = null, $new_folder_header = false)
    {
        global $conf, $imp;
        static $cache;

        $signature = serialize(array($heading, $abbrev, $filter, $selected, $new_folder_header));

        /* Use the cached value, if possible. */
        if ($conf['server']['cache_folders']) {
            require_once HORDE_BASE . '/lib/SessionObjects.php';
            $sessionOb = &Horde_SessionObjects::singleton();
            if (!isset($imp['cache']['flistselect'])) {
                $imp['cache']['flistselect'] = array();
            }
            $flist_cache = &$imp['cache']['flistselect'];
            if (isset($imp['cache']['folder_cache']) &&
                isset($flist_cache['_md5']) &&
                isset($flist_cache[$signature])) {
                $md5sum = md5(serialize($imp['cache']['folder_cache']));
                /* Determine if the folder cache has changed since we last
                   generated the select list. */
                if ($md5sum == $flist_cache['_md5']) {
                    $cachedata = $sessionOb->query($flist_cache[$signature]);
                    if ($cachedata) {
                        return $cachedata;
                    }
                } else {
                    unset($flist_cache['_md5']);
                    foreach ($flist_cache as $key => $val) {
                        $sessionOb->setPruneFlag($val, true);
                    }
                    $flist_cache = array();
                }
            }
        } elseif (isset($cache)) {
            if (isset($cache[$signature])) {
                return $cache[$signature];
            }
        } else {
            $cache = array();
        }
            
        require_once HORDE_BASE . '/lib/Text.php';
        require_once IMP_BASE . '/lib/Folder.php';

        $imp_folder = &IMP_Folder::singleton();
        $mailboxes = $imp_folder->flist_IMP($filter);
        $text = '';

        if (strlen($heading) > 0) {
            $text .= '<option value="">' . $heading . "</option>\n";
        }

        if ($new_folder_header) {
            $text .= '<option value="">----</option>' . "\n";
            $text .= '<option value="*new*">' . _("New Folder") . "</option>\n";
            $text .= '<option value="">----</option>' . "\n";
        }

        foreach ($mailboxes as $mbox) {
            $sel = ($mbox['val'] && $mbox['val'] === $selected) ? ' selected="selected"' : '';
            $val = htmlspecialchars($mbox['val']);
            if ($abbrev) {
                $label = $mbox['abbrev'];
            } else {
                $label = $mbox['label'];
            }
            $text .= sprintf('<option value="%s"%s>%s</option>%s', $val, $sel, Text::htmlSpaces($label), "\n");
        }

        /* Cache results. */
        if ($conf['server']['cache_folders']) {
            if (!isset($md5sum)) {
                $md5sum = md5(serialize($imp['cache']['folder_cache']));
            }
            $flist_cache['_md5'] = $md5sum;
            $flist_cache[$signature] = $sessionOb->storeOid($text, false);
        } else {
            $cache[$signature] = $text;
        }

        return $text;
    }

    /**
     * Returns the current mailbox.
     *
     * @access public
     *
     * @param optional integer $array_index  The array index of the current
     *                                       message.
     *
     * @return string  The current mailbox name.
     */
    function getThisMailbox($array_index = null)
    {
        global $imp;

        if (!is_null($array_index) && ($imp['mailbox'] == IMP_SEARCH_MBOX)) {
            $msgs = explode(IMP_MSG_SEP, $imp['msgl']);
            if (array_key_exists($array_index, $msgs)) {
                return substr($msgs[$array_index], strpos($msgs[$array_index], IMP_IDX_SEP) + 1);
            }
        }

        return $imp['thismailbox'];
    }

    /**
     * Check for To:, Subject:, Cc:, and other compose window
     * arguments and pass back either a URI fragment or an associative
     * array with any of them which are present.
     *
     * @access public

     * @param string $format  Either 'uri' or 'array'.
     *
     * @return string  A URI fragment or an associative array with any compose
     *                 arguments present.
     */
    function getComposeArgs($format = 'uri')
    {
        $args = array();
        $fields = array('to', 'cc', 'bcc', 'msg', 'subject');

        foreach ($fields as $val) {
            if (($$val = Horde::getFormData($val))) {
                $args[$val] = $$val;
            }
        }

        /* Decode mailto: URLs. */
        if (array_key_exists('to', $args) &&
            (strpos($args['to'], 'mailto:') === 0)) {
            $mailto = @parse_url($args['to']);
            if (is_array($mailto)) {
                $args['to'] = $mailto['path'];
                if (!empty($mailto['query'])) {
                    parse_str($mailto['query'], $vals);
                    foreach ($fields as $val) {
                        if (array_key_exists($val, $vals)) {
                            $args[$val] = $vals[$val];
                        }
                    }
                }
            }
        }

        if (stristr($format, 'array')) {
            return $args;
        } else {
            $url = '';
            foreach ($args as $key => $val) {
                $url = Horde::addParameter($url, $key, $val);
            }
            return $url;
        }
    }

    /**
     * Get the initial URL.
     *
     * @access public
     *
     * @param optional string $actionID  The action ID to perform on the
     *                                   initial page.
     *
     * @return string  The initial URL.
     */
    function getInitialUrl($actionID = null)
    {
        global $prefs;

        $init_url = $prefs->getValue('initial_page');
        if ($init_url == 'folders.php') {
            $url = Horde::applicationUrl($init_url, true);
        } else {
            $url = Horde::applicationUrl('mailbox.php', true);
            $url = Horde::addParameter($url, 'mailbox', IMP::addPreambleString($init_url));
            foreach (IMP::getComposeArgs('array') as $arg => $value) {
                $url = Horde::addParameter($url, $arg, $value);
            }
        }

        if (!empty($actionID)) {
            $url = Horde::addParameter($url, 'actionID', $actionID);
        }

        return $url;
    }

    /**
     * Returns the appropriate link to call the message composition
     * screen.
     *
     * @access public
     *
     * @param optional mixed $args   List of arguments to pass to compose.php.
     *                               If this is passed in as a string, it will
     *                               be parsed as a
     *                               toaddress?subject=foo&cc=ccaddress
     *                               (mailto-style) string.
     * @param optional array $extra  Hash of extra, non-standard arguments to
     *                               pass to compose.php.
     *
     * @return string  The link to the message composition screen.
     */
    function composeLink($args = array(), $extra = array())
    {
        global $browser, $prefs;

        /* Make sure the compose window always knows which mailbox
           it's in, for replying, forwarding, marking as answered,
           etc. */
        if (!array_key_exists('thismailbox', $extra)) {
            if (array_key_exists('array_index', $extra)) {
                $extra['thismailbox'] = IMP::getThisMailbox($extra['array_index']);
            } else {
                $extra['thismailbox'] = IMP::getThisMailbox();
            }
        }

        if (is_string($args)) {
            $string = $args;
            $args = array();
            if (($pos = strpos($string, '?')) !== false) {
                parse_str(substr($string, $pos + 1), $args);
                $args['to'] = substr($string, 0, $pos);
            } else {
                $args['to'] = $string;
            }
        }

        /* Merge the two argument arrays. */
        $args = array_merge($args, $extra);

        /* Convert the $args hash into proper URL parameters. */
        $url = '';
        foreach ($args as $key => $val) {
            if (!empty($val) || is_int($val)) {
                $url = Horde::addParameter($url, $key, $val);
            }
        }

        if ($prefs->getValue('compose_popup') &&
            $browser->hasFeature('javascript')) {
            Horde::addScriptFile('open_compose_win.js');
            return 'javascript:open_compose_win(\'' . $browser->escapeJSCode(substr($url, 1)) . '\');';
        } else {
            return Horde::applicationUrl('compose.php' . $url);
        }
    }

    /**
     * Generate an URL to the logout screen that includes any known
     * information, such as username, server, etc., that can be filled
     * in on the login form.
     *
     * @param string $uri              The page that will process the logout.
     * @param optional string $reason  The reason for the logout.
     *
     * @return string  $uri with parameters added.
     */
    function logoutUrl($uri, $reason = null)
    {
        $params = array(
            'imapuser' => isset($_SESSION['imp']['user']) ? $_SESSION['imp']['user'] :
                                                            Horde::getFormData('imapuser'),
            'server'   => isset($_SESSION['imp']['server']) ? $_SESSION['imp']['server'] :
                                                              Horde::getFormData('server'),
            'port'     => isset($_SESSION['imp']['port']) ? $_SESSION['imp']['port'] :
                                                            Horde::getFormData('port'),
            'protocol' => isset($_SESSION['imp']['protocol']) ? $_SESSION['imp']['protocol'] :
                                                                Horde::getFormData('protocol'),
            'folders'  => isset($_SESSION['imp']['folders']) ? $_SESSION['imp']['folders'] :
                                                               Horde::getFormData('folders'),
            'language' => isset($_SESSION['imp']['language']) ? $_SESSION['imp']['language'] :
                                                                Horde::getFormData('language'),
            'reason'   => $reason
        );

        foreach ($params as $key => $val) {
            if (!empty($val)) {
                $uri = Horde::addParameter($uri, $key, $val);
            }
        }

        return $uri;
    }

    /**
     * If there is information available to tell us about a prefix in
     * front of mailbox names that shouldn't be displayed to the user,
     * then use it to strip that prefix out.
     *
     * @param string $folder            The folder name to display.
     * @param optional boolean $decode  Whether or not the folder needs to be
     *                                  decoded from UTF7-IMAP.
     *
     * @return string  The folder, with any prefix gone.
     */
    function displayFolder($folder, $decode = true)
    {
        $prefix = IMP::preambleString();
        if (substr($folder, 0, ($prefixLen = strlen($prefix))) == $prefix) {
            $folder = substr($folder, $prefixLen);
        }

        return $decode ? String::convertCharset($folder, 'UTF7-IMAP') : $folder;
    }

    /**
     * Filter a string, if requested.
     *
     * @access public
     *
     * @param string $text  The text to filter.
     *
     * @return string  The filtered text (if requested).
     */
    function filterText($text)
    {
        global $conf, $prefs;

        if ($prefs->getValue('filtering')) {
            require_once HORDE_BASE . '/lib/Text.php';
            $text = Text::filter($text, $conf['msg']['filtering']['words'],
                                 $conf['msg']['filtering']['replacement']);
        }

        return $text;
    }

    /**
     * Output IMP's menubar.
     *
     * @access public
     */
    function menu()
    {
        global $conf, $registry, $imp, $prefs;
        require_once HORDE_BASE . '/lib/Menu.php';

        /* Get the folder listing for the <select> widget. */
        if ($conf['user']['allow_folders']) {
            $menu_folders = IMP::flistSelect('', true, array(), $imp['mailbox']);
        }

        require IMP_TEMPLATES . '/menu/menu.inc';

        /* Include the JavaScript for the help system. */
        Help::javascript();
    }

    /**
     * Output IMP's status/notification bar.
     *
     * @access public
     */
    function status()
    {
        global $imp, $notification;

        if (isset($imp['stream'])) {
            $alerts = imap_alerts();
            if (is_array($alerts)) {
                foreach ($alerts as $alert) {
                    $notification->push($alert, 'horde.message');
                }
            }
        }

        $notification->notify();
    }

}
