Files
server/usr/share/psa-horde/imp/lib/Mailbox.php
2026-01-07 20:52:11 +01:00

1746 lines
60 KiB
PHP

<?php
/**
* Copyright 2011-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (GPL). If you
* did not receive this file, see http://www.horde.org/licenses/gpl.
*
* @category Horde
* @copyright 2011-2017 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package IMP
*/
/**
* This object is a clearinghouse for actions related to an IMP mailbox.
*
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @copyright 2011-2017 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package IMP
*
* @property-read string $abbrev_label Abbreviated version of $label -
* displays only the bare mailbox name
* (no parents).
* @property-read boolean $access_creatembox Can sub mailboxes be created?
* @property-read boolean $access_deletembox Can this mailbox be deleted?
* @property-read boolean $access_deletembox_acl Can this mailbox be deleted
* according to ACL rules?
* @property-read boolean $access_deletemsgs Can messages be deleted in this
* mailbox?
* @property-read boolean $access_empty Can this mailbox be emptied?
* @property-read boolean $access_expunge Can messages be expunged in this
* mailbox?
* @property-read boolean $access_filters Is filtering available?
* @property-read boolean $access_flags Are flags available?
* @property-read boolean $access_search Is searching available?
* @property-read boolean $access_sort Is sorting available?
* @property-read boolean $access_sortthread Is thread sort available?
* @property-read mixed $acl Either an ACL object for the mailbox, or null if
* no ACL found for the mailbox.
* @property-read string $basename The basename of the mailbox (UTF-8).
* @property-read string $cacheid Cache ID for the mailbox.
* @property-read string $cacheid_date Cache ID for the mailbox, with added
* data information.
* @property-read boolean $children Does the element have children?
* @property-read boolean $container Is this a container element?
* @property string $display Display version of mailbox. Special mailboxes
* are replaced with localized strings and
* namespace information is removed.
* @property-read string $display_html $display that has been HTML encoded.
* @property-read boolean $drafts Is this a Drafts mailbox?
* @property-read boolean $editquery Can this search query be edited?
* @property-read boolean $editvfolder Can this virtual folder be edited?
* @property-read boolean $exists Does this mailbox exist on the IMAP server?
* @property-read string $form_to Converts this mailbox to a form
* representation.
* @property-read object $icon Icon information for the mailbox. Properties:
* - alt: (string) The alt text for the icon.
* - class: (string) The CSS class name.
* - icon: (Horde_Themes_Image) The icon graphic to use.
* - iconopen: (Horde_Themes_Image) The openicon to use.
* - user_icon: (boolean) Use a user defined icon?
* @property-read IMP_Imap $imp_imap The IMP_Imap object for this mailbox.
* @property-read string $imap_mbox The actual name of the underlying IMAP
* mailbox.
* @property-read Horde_Imap_Client_Mailbox $imap_mbox_ob Convert this object
* tp an
* Imap_Client mailbox
* object.
* @property-read boolean $inbox Is this the INBOX?
* @property-read boolean $innocent_show Show the innocent action in this
* mailbox?
* @property-read boolean $invisible Is this mailbox invisible?
* @property-read boolean $is_imap Is this an IMAP mailbox?
* @property-read boolean $is_open Is this level expanded?
* @property-read string $label The mailbox label. Essentially is $display
* that can be modified by user hook.
* @property-read integer $level The child level of this element.
* @property-read IMP_Mailbox_List $list_ob Returns the List object for the
* mailbox.
* @property-read string $namespace Is this a namespace element?
* @property-read IMP_Mailbox $namespace_append The mailbox with necessary
* namespace information appended.
* @property-read string $namespace_delimiter The delimiter for this
* namespace.
* @property-read Horde_Imap_Client_Data_Namespace $namespace_info Namespace
* info.
* @property-read boolean $nonimap Is this a non-IMAP element?
* @property-read IMP_Mailbox $parent The parent element. Returns null if no
* parent. (Base of tree is returned as
* a special element).
* @property-read string $parent_imap The IMAP parent name.
* @property-read IMP_Imap_PermanentFlags $permflags Return the list of
* permanent flags
* available to set in the
* mailbox.
* @property-read boolean $polled Show polled information?
* @property-read object $poll_info Poll information for the mailbox.
* Properties:
* - msgs: (integer) The number of total messages in the element, if polled.
* - recent: (integer) The number of new messages in the element, if polled.
* - unseen: (integer) The number of unseen messages in the element, if
* polled.
* @property-read string $pref_from Convert mailbox name from preference
* storage.
* @property-read string $pref_to Convert mailbox name to preference storage.
* @property-read boolean $query Is this a search query?
* @property-read boolean $readonly Is this mailbox read-only?
* @property-read boolean $remote Is this a remote element?
* @property-read IMP_Remote_Account $remote_account Return the account
* object for this element
* (null if not a remote
* element).
* @property-read boolean $remote_container Is this mailbox a remote special
* element?
* @property-read boolean $remote_mbox Is this mailbox on a remote server?
* @property-read boolean $search Is this a search mailbox?
* @property-read string $size Human readable size of the mailbox.
* @property-read integer $size_raw Size of mailbox in bytes. @since 6.2.14
* @property-read IMP_Prefs_Sort $sortob Sort ob for use with this mailbox.
* @property-read boolean $spam Is this a Spam mailbox?
* @property-read boolean $spam_show Show the spam action in this mailbox?
* @property-read boolean $special Is this is a "special" element?
* @property-read boolean $special_outgoing Is this a "special" element
* dealing with outgoing messages?
* @property-read boolean $specialvfolder Is this a "special" virtual folder?
* @property-read boolean $sub Is this mailbox subscribed to?
* @property-read array $subfolders Returns the list of subfolders as mailbox
* objects (including the current mailbox).
* @property-read array $subfolders_only Returns the list of subfolders as
* mailbox objects (NOT including the
* current mailbox).
* @property-read boolean $systemquery Is this a system (built-in) search
* query?
* @property-read boolean $templates Is this a Templates mailbox?
* @property-read boolean $trash Is this a Trash mailbox?
* @property-read IMP_Ftree_Element $tree_elt The tree element (null if it
* doesn't exist in the tree).
* @property-read string $uidvalid Returns the UIDVALIDITY string. Throws an
* IMP_Exception on error.
* @property-read string $utf7imap The UTF7-IMAP representation of this
* object.
* @property-read string $value The value of this element (IMAP mailbox name;
* UTF-8).
* @property-read boolean $vfolder Is this a virtual folder?
* @property-read boolean $vfolder_container Is this the virtual folder
* container?
* @property-read boolean $vinbox Is this the virtual inbox?
* @property-read boolean $vtrash Is this the virtual trash?
*/
class IMP_Mailbox
{
/* Special mailbox prefs. */
const MBOX_DRAFTS = 'drafts_folder';
const MBOX_SENT = 'sent_mail_folder';
const MBOX_SPAM = 'spam_folder';
const MBOX_TEMPLATES = 'composetemplates_mbox';
const MBOX_TRASH = 'trash_folder';
// This is just a placeholder - this pref doesn't exist.
const MBOX_USERSPECIAL = 'user_special';
/* Special mailbox identifiers. */
const SPECIAL_COMPOSETEMPLATES = 'composetemplates';
const SPECIAL_DRAFTS = 'drafts';
const SPECIAL_SENT = 'sent';
const SPECIAL_SPAM = 'spam';
const SPECIAL_TRASH = 'trash';
const SPECIAL_USER = 'userspecial';
/**
* The IMAP mailbox name (UTF-8).
*
* @var string
*/
protected $_mbox;
/**
* Shortcut to obtaining mailbox object(s).
*
* @param mixed $mbox The full IMAP mailbox name(s).
*
* @return mixed The IMP_Mailbox object(s).
*/
static public function get($mbox)
{
if (is_array($mbox)) {
return array_filter(array_map(array(__CLASS__, 'get'), $mbox));
}
if ($mbox instanceof IMP_Mailbox) {
return $mbox;
}
try {
return $GLOBALS['injector']
->getInstance('IMP_Factory_Mailbox')
->create(strval($mbox));
} catch (IMP_Exception $e) {
return null;
}
}
/**
* Shortcut to obtaining Horde_Imap_Client_Mailbox object(s).
*
* @param mixed $mbox The full IMAP mailbox name(s).
*
* @return mixed The Horde_Imap_Client_Mailbox object(s).
*/
static public function getImapMboxOb($mbox)
{
if (is_array($mbox)) {
return array_filter(array_map(array(__CLASS__, 'getImapMboxOb'), $mbox));
}
if ($mbox instanceof Horde_Imap_Client_Mailbox) {
return $mbox;
}
// Mailbox names are always UTF-8 within IMP.
$mbox_ob = new self($mbox);
return Horde_Imap_Client_Mailbox::get($mbox_ob->imap_mbox);
}
/**
* Shortcut to obtaining a mailbox object from a preference name.
*
* @var string $pref The preference name.
*
* @return IMP_Mailbox The IMP_Mailbox object.
*/
static public function getPref($pref)
{
return self::get(self::prefFrom($GLOBALS['prefs']->getValue($pref)));
}
/**
* Constructor.
*
* @var string $mbox The full IMAP mailbox name.
*
* @throws IMP_Exception
*/
public function __construct($mbox)
{
if (strlen($mbox) === 0) {
throw new IMP_Exception('Mailbox name must not be empty.');
}
$this->_mbox = $mbox;
}
/**
*/
public function __toString()
{
return strval(
($this->_mbox == IMP_Ftree::BASE_ELT) ? '' : $this->_mbox
);
}
/**
*/
public function __get($key)
{
global $injector;
switch ($key) {
case 'abbrev_label':
$label = $this->label;
return ($this->nonimap || ($pos = strrpos($label, $this->namespace_delimiter)) === false)
? $label
: substr($label, $pos + 1);
case 'access_creatembox':
return (!($acl = $this->acl) ||
($acl[Horde_Imap_Client::ACL_CREATEMBOX]));
case 'access_deletembox':
return ($this->access_deletembox_acl);
case 'access_deletembox_acl':
return (!($acl = $this->acl) ||
($acl[Horde_Imap_Client::ACL_DELETEMBOX]));
case 'access_deletemsgs':
return (!($acl = $this->acl) ||
($acl[Horde_Imap_Client::ACL_DELETEMSGS]));
case 'access_empty':
if ($this->access_deletemsgs && $this->access_expunge) {
$special = $this->getSpecialMailboxes();
return empty($special[self::SPECIAL_TRASH]) ||
!$special[self::SPECIAL_TRASH]->vtrash ||
($special[self::SPECIAL_TRASH] == $this);
}
return false;
case 'access_expunge':
return (!($acl = $this->acl) ||
($acl[Horde_Imap_Client::ACL_EXPUNGE]));
case 'access_filters':
return !$this->search && $this->is_imap;
case 'access_flags':
return $this->is_imap;
case 'access_search':
return $this->is_imap;
case 'access_sort':
/* Although possible to abstract other sorting methods, all other
* non-sequence methods require a download of ALL messages, which
* is too much overhead.*/
return $this->is_imap;
case 'access_sortthread':
/* Thread sort is always available for IMAP servers, since
* Horde_Imap_Client_Socket has a built-in ORDEREDSUBJECT
* implementation. We will always prefer REFERENCES, but will
* fallback to ORDEREDSUBJECT if the server doesn't support THREAD
* sorting. */
return $this->is_imap;
case 'acl':
$cache = $injector->getInstance('IMP_Mailbox_SessionCache');
if (($acl = $cache->getAcl($this->_mbox)) !== false) {
return $acl;
}
if ($this->nonimap) {
$acl = null;
} else {
$acl = $injector->getInstance('IMP_Imap_Acl')->getACL($this, true);
$hooks = $injector->getInstance('Horde_Core_Hooks');
if ($hooks->hookExists('mbox_acl', 'imp')) {
$hooks->callHook('mbox_acl', 'imp', array($this, $acl));
}
}
$cache->setAcl($this->_mbox, $acl);
return $acl;
case 'basename':
if ($this->nonimap) {
return $this->label;
}
$mbox = $this->remote_mbox
? $this->label
: $this->_mbox;
return (($pos = strrpos($mbox, $this->namespace_delimiter)) === false)
? strval($mbox)
: substr($mbox, $pos + 1);
case 'cacheid':
case 'cacheid_date':
return $this->_getCacheID($key == 'cacheid_date');
case 'children':
return (($elt = $this->tree_elt) && $elt->children);
case 'container':
return (($elt = $this->tree_elt) && $elt->container);
case 'display':
return $this->nonimap
? $this->label
: $this->_getDisplay();
case 'display_html':
return htmlspecialchars($this->display);
case 'display_notranslate':
return $this->nonimap
? $this->label
: $this->_getDisplay(true);
case 'drafts':
$special = $this->getSpecialMailboxes();
return ($this->_mbox == $special[self::SPECIAL_DRAFTS]);
case 'editquery':
return $injector->getInstance('IMP_Search')->isQuery($this->_mbox, true);
case 'editvfolder':
return $injector->getInstance('IMP_Search')->isVFolder($this->_mbox, true);
case 'exists':
return $injector->getInstance('IMP_Mailbox_SessionCache')->exists($this);
case 'form_to':
return $this->formTo($this->_mbox);
case 'icon':
return $this->_getIcon();
case 'imp_imap':
return $injector->getInstance('IMP_Factory_Imap')->create(strval($this));
case 'imap_mbox':
return strval(
$injector->getInstance('IMP_Remote')->getMailboxById($this->_mbox) ?: $this->_mbox
);
case 'imap_mbox_ob':
return self::getImapMboxOb($this->_mbox);
case 'inbox':
return (strcasecmp($this->_mbox, 'INBOX') === 0);
case 'innocent_show':
$p = $this->imp_imap->config->innocent_params;
return (!empty($p) &&
((isset($p['display']) && empty($p['display'])) || $this->spam));
case 'invisible':
return (($elt = $this->tree_elt) && $elt->invisible);
case 'is_imap':
return $this->imp_imap->isImap();
case 'is_open':
return (($elt = $this->tree_elt) && $elt->open);
case 'label':
$cache = $injector->getInstance('IMP_Mailbox_SessionCache');
if (($label = $cache->getLabel($this->_mbox)) !== false) {
return $label;
}
/* Returns the plain text label that is displayed for the
* current mailbox, replacing virtual search mailboxes with an
* appropriate description, removing namespace and mailbox
* prefix information from what is shown to the user, and
* passing the label through a user-defined hook. */
$imp_search = $injector->getInstance('IMP_Search');
$label = ($ob = $imp_search[$this->_mbox])
? $ob->label
: $this->_getDisplay();
$hooks = $injector->getInstance('Horde_Core_Hooks');
if ($hooks->hookExists('mbox_label' ,'imp')) {
$label = $hooks->callHook(
'mbox_label',
'imp',
array($this->_mbox, $label)
);
}
$cache->setLabel($this->_mbox, $label);
return $label;
case 'level':
return ($elt = $this->tree_elt) ? $elt->level : 0;
case 'list_ob':
return $injector->getInstance('IMP_Factory_MailboxList')->create($this);
case 'namespace':
return (($elt = $this->tree_elt) && $elt->namespace);
case 'namespace_append':
$imp_imap = $this->imp_imap;
$def_ns = $imp_imap->getNamespace($imp_imap::NS_DEFAULT);
if (is_null($def_ns)) {
return $this;
}
$empty_ns = $imp_imap->getNamespace('');
/* If default namespace is empty, or there is no empty namespace,
* then we can auto-detect namespace from input.
* If a non-default namespace is empty, then we must always use
* default namespace. */
if (!is_null($empty_ns) &&
($def_ns->name == $empty_ns->name)) {
return $this;
}
$ns_info = $this->namespace_info;
if (is_null($ns_info) || !is_null($empty_ns)) {
return self::get($def_ns->name . $this->_mbox);
}
return $this;
case 'namespace_delimiter':
$ns_info = $this->namespace_info;
return is_null($ns_info)
? ''
: $ns_info->delimiter;
case 'namespace_info':
return $this->imp_imap->getNamespace(strlen($this) ? $this->_mbox : IMP_Imap::NS_DEFAULT);
case 'nonimap':
return ($this->search ||
(($elt = $this->tree_elt) && $elt->nonimap));
case 'parent':
return ($elt = $this->tree_elt) ? $elt->parent->mbox_ob : null;
case 'parent_imap':
return (is_null($p = $this->parent) || !strlen($p))
? null
: $p;
case 'permflags':
if ($this->access_flags) {
$imp_imap = $this->imp_imap;
try {
/* Make sure we are in R/W mailbox mode (SELECT). No flags
* are allowed in EXAMINE mode. */
$imp_imap->openMailbox($this, Horde_Imap_Client::OPEN_READWRITE);
$status = $imp_imap->status($this->_mbox, Horde_Imap_Client::STATUS_FLAGS | Horde_Imap_Client::STATUS_PERMFLAGS);
return new IMP_Imap_PermanentFlags($status['permflags'], $status['flags']);
} catch (Exception $e) {}
}
return new IMP_Imap_PermanentFlags();
case 'poll_info':
$info = new stdClass;
$info->msgs = 0;
$info->recent = 0;
$info->unseen = 0;
try {
if ($msgs_info = $this->imp_imap->status($this->_mbox, Horde_Imap_Client::STATUS_RECENT_TOTAL | Horde_Imap_Client::STATUS_UNSEEN | Horde_Imap_Client::STATUS_MESSAGES)) {
if (!empty($msgs_info['recent_total'])) {
$info->recent = intval($msgs_info['recent_total']);
}
$info->msgs = intval($msgs_info['messages']);
$info->unseen = intval($msgs_info['unseen']);
}
} catch (IMP_Imap_Exception $e) {}
return $info;
case 'polled':
return (!$this->search &&
(($elt = $this->tree_elt) && $elt->polled));
case 'pref_from':
return $this->prefFrom($this->_mbox);
case 'pref_to':
return $this->prefTo($this->_mbox);
case 'query':
return $injector->getInstance('IMP_Search')->isQuery($this->_mbox);
case 'readonly':
return (($acl = $this->acl) &&
!$acl[Horde_Imap_Client::ACL_DELETEMBOX] &&
!$acl[Horde_Imap_Client::ACL_DELETEMSGS] &&
!$acl[Horde_Imap_Client::ACL_EXPUNGE] &&
!$acl[Horde_Imap_Client::ACL_INSERT] &&
!$acl[Horde_Imap_Client::ACL_SEEN] &&
!$acl[Horde_Imap_Client::ACL_WRITE]);
case 'remote':
return $injector->getInstance('IMP_Remote')->isRemoteMbox($this->_mbox);
case 'remote_account':
$remote = $injector->getInstance('IMP_Remote');
$account = ($this->remote_container)
? $remote[$this->_mbox]
: $remote->getRemoteById($this->_mbox);
return $account ?: null;
case 'remote_container':
return (($elt = $this->tree_elt) && $elt->remote);
case 'remote_mbox':
return (($elt = $this->tree_elt) && $elt->remote_mbox);
case 'search':
return $injector->getInstance('IMP_Search')->isSearchMbox($this->_mbox);
case 'size':
return $injector->getInstance('IMP_Mbox_Size')->getSize($this);
case 'size_raw':
return $injector->getInstance('IMP_Mbox_Size')->getSize($this, false);
case 'sortob':
return $this->imp_imap->access(IMP_Imap::ACCESS_SORT)
? $injector->getInstance('IMP_Prefs_Sort')
: $injector->getInstance('IMP_Prefs_Sort_None');
case 'spam':
$special = $this->getSpecialMailboxes();
return ($this->_mbox == $special[self::SPECIAL_SPAM]);
case 'spam_show':
$p = $this->imp_imap->config->spam_params;
return (!empty($p) && (!empty($p['display']) || !$this->spam));
case 'special':
$special = $this->getSpecialMailboxes();
switch ($this->_mbox) {
case $special[self::SPECIAL_COMPOSETEMPLATES]:
case $special[self::SPECIAL_DRAFTS]:
case $special[self::SPECIAL_SPAM]:
case $special[self::SPECIAL_TRASH]:
return true;
}
return in_array($this->_mbox, array_merge(
$special[self::SPECIAL_SENT],
$special[self::SPECIAL_USER]
));
case 'special_outgoing':
$special = $this->getSpecialMailboxes();
return in_array($this->_mbox, array_merge(
array(
$special[self::SPECIAL_COMPOSETEMPLATES],
$special[self::SPECIAL_DRAFTS]
),
$special[self::SPECIAL_SENT]
));
case 'specialvfolder':
return !$this->editvfolder;
case 'sub':
return (($elt = $this->tree_elt) && $elt->subscribed);
case 'subfolders':
return $this->get(array_merge(array($this->_mbox), $this->subfolders_only));
case 'subfolders_only':
return $this->get($this->imp_imap->listMailboxes($this->imap_mbox_ob->list_escape . $this->namespace_delimiter . '*', null, array('flat' => true)));
case 'systemquery':
return $injector->getInstance('IMP_Search')->isSystemQuery($this->_mbox);
case 'templates':
$special = $this->getSpecialMailboxes();
return ($this->_mbox == $special[self::SPECIAL_COMPOSETEMPLATES]);
case 'trash':
$special = $this->getSpecialMailboxes();
return ($this->_mbox == $special[self::SPECIAL_TRASH]);
case 'tree_elt':
$ftree = $injector->getInstance('IMP_Ftree');
return $ftree[$this->_mbox];
case 'uidvalid':
$cache = $injector->getInstance('IMP_Mailbox_SessionCache');
$uidvalid = $cache->getUidvalidity($this->_mbox);
if ($uidvalid === 0) {
return;
}
// POP3 and non-IMAP mailboxes do not support UIDVALIDITY.
if (!$this->is_imap || $this->nonimap) {
$cache->setUidvalidity($this->_mbox, 0);
return false;
}
$status = $this->imp_imap->status($this->_mbox, Horde_Imap_Client::STATUS_UIDVALIDITY);
if (($first = ($uidvalid === false)) ||
($status['uidvalidity'] != $uidvalid)) {
$uidvalid = $status['uidvalidity'];
$cache->setUidvalidity($this->_mbox, $uidvalid);
if (!$first) {
throw new IMP_Exception(_("Mailbox structure on server has changed."));
}
}
return $uidvalid;
case 'utf7imap':
return Horde_String::convertCharset($this->_mbox, 'UTF-8', 'UTF7-IMAP');
case 'value':
return $this->_mbox;
case 'vfolder':
return $injector->getInstance('IMP_Search')->isVFolder($this->_mbox);
case 'vfolder_container':
return ($this->_mbox == IMP_Ftree_Account_Vfolder::VFOLDER_KEY);
case 'vinbox':
return $injector->getInstance('IMP_Search')->isVinbox($this->_mbox);
case 'vtrash':
return $injector->getInstance('IMP_Search')->isVTrash($this->_mbox);
}
return false;
}
/**
*/
public function __set($key, $value)
{
global $injector;
switch ($key) {
case 'display':
$injector->getInstance('IMP_Mailbox_SessionCache')->setDisplay($this->_mbox, $value);
break;
}
}
/**
* Create this mailbox on the server.
*
* @param array $opts Additional options:
* - special_use: (array) An array of special-use attributes to attempt
* to add to the mailbox.
* DEFAULT: NONE
* - subscribe: (boolean) Override preference value of subscribe.
*
* @return boolean True on success.
* @throws Horde_Exception
*/
public function create(array $opts = array())
{
global $injector, $notification, $prefs;
if ($this->exists) {
return true;
}
$imp_imap = $this->imp_imap;
/* Check permissions. */
if (!$imp_imap->access(IMP_Imap::ACCESS_CREATEMBOX)) {
Horde::permissionDeniedError(
'imp',
'create_mboxes',
_("You are not allowed to create mailboxes.")
);
return false;
}
if (!$imp_imap->access(IMP_Imap::ACCESS_CREATEMBOX_MAX)) {
Horde::permissionDeniedError(
'imp',
'max_create_mboxes',
sprintf(_("You are not allowed to create more than %d mailboxes."), $imp_imap->max_create_mboxes)
);
return false;
}
/* Special use flags. */
$special_use = isset($opts['special_use'])
? $opts['special_use']
: array();
/* Attempt to create the mailbox. */
try {
$imp_imap->createMailbox($this->_mbox, array('special_use' => $special_use));
} catch (IMP_Imap_Exception $e) {
if ($e->getCode() == $e::USEATTR) {
unset($opts['special_use']);
return $this->create($opts);
}
$e->notify(sprintf(_("The mailbox \"%s\" was not created. This is what the server said"), $this->display) . ': ' . $e->getMessage());
return false;
}
$notification->push(sprintf(_("The mailbox \"%s\" was successfully created."), $this->display), 'horde.success');
/* Subscribe, if requested. */
if ((!isset($opts['subscribe']) && $prefs->getValue('subscribe')) ||
!empty($opts['subscribe'])) {
try {
$imp_imap->subscribeMailbox($this->_mbox, true);
} catch (IMP_Imap_Exception $e) {}
}
/* Update the mailbox tree. */
$injector->getInstance('IMP_Ftree')->insert($this->_mbox);
return true;
}
/**
* Deletes mailbox.
*
* @param array $opts Addtional options:
* - subfolders: (boolean) Delete all subfolders?
* DEFAULT: false
* - subfolders_only: (boolean) If deleting subfolders, delete only
* subfolders (not current mailbox)?
* DEFAULT: false
*
* @return boolean True on success.
*/
public function delete(array $opts = array())
{
global $injector, $notification;
if ($this->vfolder) {
if ($this->editvfolder) {
$imp_search = $injector->getInstance('IMP_Search');
$label = $imp_search[$this->_mbox]->label;
unset($imp_search[$this->_mbox]);
$notification->push(sprintf(_("Deleted Virtual Folder \"%s\"."), $label), 'horde.success');
return true;
}
$notification->push(sprintf(_("Could not delete Virtual Folder \"%s\"."), $this->label), 'horde.error');
return false;
}
$deleted = array();
$imp_imap = $this->imp_imap;
if (empty($opts['subfolders'])) {
$to_delete = array($this);
} else {
$to_delete = empty($opts['subfolders_only'])
? $this->subfolders
: $this->subfolders_only;
}
foreach ($to_delete as $val) {
if (!$val->access_deletembox_acl) {
$notification->push(sprintf(_("The mailbox \"%s\" may not be deleted."), $val->display), 'horde.error');
continue;
}
try {
$imp_imap->deleteMailbox($val->value);
$notification->push(sprintf(_("The mailbox \"%s\" was successfully deleted."), $val->display), 'horde.success');
$deleted[] = $val;
} catch (IMP_Imap_Exception $e) {
$e->notify(sprintf(_("The mailbox \"%s\" was not deleted. This is what the server said"), $val->display) . ': ' . $e->getMessage());
}
}
if (!empty($deleted)) {
$injector->getInstance('IMP_Ftree')->delete($deleted);
$this->_onDelete($deleted);
}
return (count($deleted) == count($to_delete));
}
/**
* Rename this mailbox on the server. The subscription status remains the
* same. All subfolders will also be renamed.
*
* @param string $new_name The new mailbox name (UTF-8).
*
* @return boolean True on success
*/
public function rename($new_name)
{
global $injector, $notification;
/* Don't try to rename to an empty string. */
if (!strlen($new_name)) {
return false;
}
if (!$this->access_deletembox_acl) {
$notification->push(sprintf(_("The mailbox \"%s\" may not be renamed."), $this->display), 'horde.error');
return false;
}
$new_mbox = $this->get($new_name);
$old_list = $this->subfolders;
try {
$this->imp_imap->renameMailbox($this->_mbox, $new_mbox);
} catch (IMP_Imap_Exception $e) {
$e->notify(sprintf(_("Renaming \"%s\" to \"%s\" failed. This is what the server said"), $this->display, $new_mbox->display) . ': ' . $e->getMessage());
return false;
}
$notification->push(sprintf(_("The mailbox \"%s\" was successfully renamed to \"%s\"."), $this->display, $new_mbox->display), 'horde.success');
$injector->getInstance('IMP_Ftree')->rename($this->_mbox, $new_mbox);
$this->_onDelete($old_list);
return true;
}
/**
* Subscribe/unsubscribe to an IMAP mailbox.
*
* @param boolean $sub True to subscribe, false to unsubscribe.
* @param array $opts Additional options:
* <pre>
* - subfolders: (boolean) If true, applies actions to all subfolders.
* </pre>
*
* @return boolean True on success.
*/
public function subscribe($sub, array $opts = array())
{
global $injector, $notification, $prefs;
/* Skip non-IMAP/container mailboxes. */
if (!$prefs->getValue('subscribe') ||
$this->nonimap ||
$this->container) {
return false;
}
if (!$sub && $this->inbox) {
$notification->push(sprintf(_("You cannot unsubscribe from \"%s\"."), $this->display), 'horde.error');
return false;
}
$imp_imap = $this->imp_imap;
try {
$imp_imap->subscribeMailbox($this->_mbox, $sub);
} catch (IMP_Imap_Exception $e) {
if ($sub) {
$e->notify(sprintf(_("You were not subscribed to \"%s\". Here is what the server said"), $this->display) . ': ' . $e->getMessage());
} else {
$e->notify(sprintf(_("You were not unsubscribed from \"%s\". Here is what the server said"), $this->display) . ': ' . $e->getMessage());
}
return false;
}
$imap_tree = $injector->getInstance('IMP_Ftree');
if ($sub) {
$imap_tree->subscribe($this->_mbox);
} else {
$imap_tree->unsubscribe($this->_mbox);
}
if (empty($opts['subfolders'])) {
$notify = $sub
? sprintf(_("You were successfully subscribed to \"%s\"."), $this->display)
: sprintf(_("You were successfully unsubscribed from \"%s\"."), $this->display);
} else {
$action = false;
foreach ($this->subfolders_only as $val) {
try {
$imp_imap->subscribeMailbox($val, $sub);
if ($sub) {
$imap_tree->subscribe($val);
} else {
$imap_tree->unsubscribe($val);
}
$action = true;
} catch (IMP_Imap_Exception $e) {
// Ignore errors for sub-mailboxes.
}
}
if ($action) {
$notify = $sub
? sprintf(_("You were successfully subscribed to \"%s\" and all subfolders."), $this->display)
: sprintf(_("You were successfully unsubscribed from \"%s\" and all subfolders."), $this->display);
}
}
$notification->push($notify, 'horde.success');
return true;
}
/**
* Runs filters on this mailbox.
*/
public function filter()
{
if (!$this->search) {
$GLOBALS['injector']->getInstance('IMP_Filter')->filter($this);
}
}
/**
* Filters this mailbox if it is the INBOX and the filter on display pref
* is active.
*
* @return boolean True if filter() was called.
*/
public function filterOnDisplay()
{
if ($this->inbox &&
$GLOBALS['prefs']->getValue('filter_on_display')) {
$this->filter();
return true;
}
return false;
}
/**
* Return the search query object for this mailbox.
*
* @return IMP_Search_Query The search query object.
*/
public function getSearchOb()
{
$imp_search = $GLOBALS['injector']->getInstance('IMP_Search');
return $imp_search[$this->_mbox];
}
/**
* Return an indices object for this mailbox.
*
* @param mixed $in Either a single UID, array of UIDs, or a
* Horde_Imap_Client_Ids object.
*
* @return IMP_Indices An indices object.
*/
public function getIndicesOb($in)
{
return new IMP_Indices($this, $in);
}
/**
* Return the sorting preference for this mailbox.
*
* @param boolean $convert Convert 'by' to a Horde_Imap_Client constant?
*
* @return IMP_Prefs_Sort_Sortpref Sortpref object.
*/
public function getSort($convert = false)
{
global $prefs;
$mbox = $this->search
? $this
: self::get($this->pref_from);
$ob = $this->sortob[strval($mbox)];
$ob->convertSortby();
if ($convert && ($ob->sortby == IMP::IMAP_SORT_DATE)) {
$ob->sortby = $prefs->getValue('sortdate');
}
return $ob;
}
/**
* Set the sorting preference for this mailbox.
*
* @param integer $by The sort type.
* @param integer $dir The sort direction.
* @param boolean $delete Delete the entry?
*/
public function setSort($by = null, $dir = null, $delete = false)
{
$mbox = $this->search
? $this
: self::get($this->pref_from);
if ($delete) {
unset($this->sortob[strval($mbox)]);
} else {
$change = array();
if (!is_null($by)) {
$change['by'] = $by;
}
if (!is_null($dir)) {
$change['dir'] = $dir;
}
$this->sortob[strval($mbox)] = $change;
}
}
/**
* Are deleted messages hidden in this mailbox?
*
* @param boolean $deleted Return value is what should be done with
* deleted messages in general, as opposed to any
* deleted message in the mailbox.
*
* @return boolean True if deleted messages should be hidden.
*/
public function hideDeletedMsgs($deleted = false)
{
global $prefs;
if (!$this->access_flags) {
return true;
}
if ($prefs->getValue('use_trash')) {
/* If using Virtual Trash, only show deleted messages in
* the Virtual Trash mailbox. */
return $this->get($prefs->getValue(self::MBOX_TRASH))->vtrash
? !$this->vtrash
: ($prefs->getValue('delhide_trash') ? true : $deleted);
}
return $prefs->getValue('delhide');
}
/**
* Sets the 'delhide' preference and clears necessary cached data.
*
* @param boolean $value The value to set 'delhide' to.
*/
public function setHideDeletedMsgs($value)
{
$GLOBALS['prefs']->setValue('delhide', $value);
$GLOBALS['injector']->getInstance('IMP_Factory_MailboxList')->expireAll();
}
/**
* Run a search query on this mailbox that is not stored in the current
* session. Allows custom queries with custom sorts to be used without
* affecting cached mailboxes.
*
* @param Horde_Imap_Client_Search_Query $query The search query object.
* @param integer $sortby The sort criteria.
* @param integer $sortdir The sort directory.
*
* @return IMP_Indices An indices object.
*/
public function runSearchQuery(Horde_Imap_Client_Search_Query $query,
$sortby = null, $sortdir = null)
{
try {
$results = $this->imp_imap->search($this, $query, array(
'sort' => is_null($sortby) ? null : array($sortby)
));
if ($sortdir) {
$results['match']->reverse();
}
return $this->getIndicesOb($results['match']);
} catch (IMP_Imap_Exception $e) {
return new IMP_Indices();
}
}
/**
* Generate a URL using the current mailbox.
*
* @param string|Horde_Url $page Page name to link to.
* @param string $buid The BUID to use on the linked page.
* @param boolean $encode Encode the argument separator?
*
* @return Horde_Url URL to $page with any necessary mailbox information
* added to the parameter list of the URL.
*/
public function url($page, $buid = null, $encode = true)
{
if ($page instanceof Horde_Url) {
return $page->add($this->urlParams($buid))->setRaw(!$encode);
}
switch ($GLOBALS['registry']->getView()) {
case Horde_Registry::VIEW_BASIC:
switch ($page) {
case 'message':
return IMP_Basic_Message::url(array(
'buid' => $buid,
'mailbox' => $this->_mbox
))->setRaw(!$encode);
case 'mailbox':
return IMP_Basic_Mailbox::url(array(
'mailbox' => $this->_mbox
))->setRaw(!$encode);
}
break;
case Horde_Registry::VIEW_DYNAMIC:
$anchor = is_null($buid)
? ('mbox:' . $this->form_to)
: ('msg:' . $this->form_to . ';' . $buid);
return Horde::url('index.php')->setAnchor($anchor);
case Horde_Registry::VIEW_MINIMAL:
switch ($page) {
case 'message':
return IMP_Minimal_Message::url(array(
'buid' => $buid,
'mailbox' => $this->_mbox
))->setRaw(!$encode);
case 'mailbox':
return IMP_Minimal_Mailbox::url(array(
'mailbox' => $this->_mbox
))->setRaw(!$encode);
}
break;
case Horde_Registry::VIEW_SMARTMOBILE:
$url = Horde::url('smartmobile.php');
$anchor = is_null($buid)
? ('mbox=' . $this->form_to)
: ('msg=' . $this->form_to . ';' . $buid);
$url->setAnchor('mailbox?' . $anchor);
return $url;
}
return Horde::url($page . '.php')->add($this->urlParams($buid))->setRaw(!$encode);
}
/**
* Returns list of URL parameters necessary to indicate current mailbox
* status.
*
* @param string $buid The BUID to use on the linked page.
*
* @return array The list of parameters needed to indicate the current
* mailbox status.
*/
public function urlParams($buid = null)
{
$params = array('mailbox' => $this->form_to);
if (!is_null($buid)) {
$params['buid'] = $buid;
}
return $params;
}
/**
* Determines if this mailbox is equal to the given mailbox.
* Needed because directly comparing two mailbox objects may fail (the
* member variables may be different).
*
* @param mixed $mbox The mailbox to compare to.
*
* @return boolean True if the mailboxes are the same.
*/
public function equals($mbox)
{
return ($mbox == $this->_mbox);
}
/**
* Create an indices object from a list of browser-UIDs.
*
* @param IMP_Indices|array $buids Browser-UIDs.
*
* @return IMP_Indices An indices object.
*/
public function fromBuids($buids)
{
if (is_array($buids)) {
$buids = new IMP_Indices($this->_mbox, $buids);
}
$buid_list = $buids->getSingle(true);
$out = new IMP_Indices();
if ($buid_list[1]) {
$list_ob = $this->list_ob;
foreach ($buid_list[1] as $buid) {
if ($resolve = $list_ob->resolveBuid($buid)) {
$out->add($resolve['m'], $resolve['u']);
}
}
}
return $out;
}
/**
* Create a BUID indices object from a list of UIDs.
*
* @param IMP_Indices $uids UIDs.
*
* @return IMP_Indices An indices object.
*/
public function toBuids(IMP_Indices $uids)
{
$list_ob = $this->list_ob;
$out = new IMP_Indices();
foreach ($uids as $val) {
foreach ($val->uids as $val2) {
$out->add($this->_mbox, $list_ob->getBuid($val->mbox, $val2));
}
}
return $out;
}
/**
* Return the mailbox name to create given a submailbox name.
*
* @param string $new The submailbox name (UTF-8).
*
* @return IMP_Mailbox The mailbox to create.
*/
public function createMailboxName($new)
{
if ($this->remote_container) {
$new = $this->remote_account->mailbox($new);
} else {
$ns_info = $this->namespace_info;
$new = strlen($this)
? ($this->_mbox . $ns_info->delimiter . $new)
: $ns_info->name . $new;
}
return self::get($new);
}
/* Static methods. */
/**
* Converts a mailbox string from a form representation.
* Needed because null characters (used for various internal non-IMAP
* mailbox representations) will not work in form elements.
*
* @param mixed $mbox The mailbox name(s).
*
* @return mixed The mailbox object(s).
*/
static public function formFrom($mbox)
{
return is_array($mbox)
? array_filter(array_map(array(__CLASS__, 'formFrom'), $mbox))
// Base64url (RFC 4648 [5]) encoding
: self::get(base64_decode(strtr($mbox, '-_', '+/')));
}
/**
* Converts a mailbox string to a form representation.
* Needed because null characters (used for various internal non-IMAP
* mailbox representations) will not work in form elements.
*
* @param mixed $mbox The mailbox name(s).
*
* @return mixed The converted mailbox string(s).
*/
static public function formTo($mbox)
{
return is_array($mbox)
? array_filter(array_map(array(__CLASS__, 'formTo'), $mbox))
// Base64url (RFC 4648 [5]) encoding
: strtr(rtrim(base64_encode($mbox), '='), '+/', '-_');
}
/**
* Return the list of special mailboxes.
*
* @return array A list of mailboxes, with the self::SPECIAL_* constants
* as keys and values containing the IMP_Mailbox objects or
* null if the mailbox doesn't exist (self::SPECIAL_SENT
* contains an array of objects).
*/
static public function getSpecialMailboxes()
{
global $injector;
return $injector->getInstance('IMP_Mailbox_SessionCache')->getSpecialMailboxes();
}
/**
* Return the list of sorted special mailboxes.
*
* @return array The list of sorted special mailboxes (IMP_Mailbox
* objects).
*/
static public function getSpecialMailboxesSort()
{
$out = array();
foreach (array_filter(self::getSpecialMailboxes()) as $val) {
if (is_array($val)) {
$out = array_merge($out, $val);
} else {
$out[] = $val;
}
}
$tmp = array();
foreach ($out as $val) {
$tmp[strval($val)] = $val->abbrev_label;
}
asort($tmp, SORT_LOCALE_STRING);
return self::get(array_keys($tmp));
}
/**
* Converts a mailbox name from a value stored in the preferences.
*
* @param string $mbox The mailbox name as stored in a preference.
*
* @return string The full IMAP mailbox name (UTF-8).
*/
static public function prefFrom($mbox)
{
$imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
if ($imp_imap->isImap()) {
$empty_ns = $imp_imap->getNamespace('');
if (!is_null($empty_ns) &&
(strpos($mbox, $empty_ns->delimiter) === 0)) {
/* Prefixed with delimiter => from empty namespace. */
return substr($mbox, strlen($empty_ns->delimiter));
} elseif ($imp_imap->getNamespace($mbox, true) === null) {
/* No namespace prefix => from personal namespace. */
$def_ns = $imp_imap->getNamespace($imp_imap::NS_DEFAULT);
return $def_ns->name . $mbox;
}
}
return $mbox;
}
/**
* Converts a mailbox name to a value to be stored in a preference.
*
* @param string $mbox The full IMAP mailbox name (UTF-8).
*
* @return string The value to store in a preference.
*/
static public function prefTo($mbox)
{
global $injector;
$cache = $injector->getInstance('IMP_Mailbox_SessionCache');
$mbox_str = $ret = strval($mbox);
if (($pref_to = $cache->getPrefTo($mbox_str)) !== false) {
return $pref_to;
}
if (($ns = self::get($mbox)->namespace_info) !== null) {
$imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
$def_ns = $imp_imap->getNamespace($imp_imap::NS_DEFAULT);
if ($ns->name == $def_ns->name) {
/* From personal namespace => strip namespace. */
$ret = substr($mbox_str, strlen($def_ns->name));
} else {
$empty_ns = $imp_imap->getNamespace('');
if ($ns->name == $empty_ns->name) {
/* From empty namespace => prefix with delimiter. */
$ret = $empty_ns->delimiter . $mbox_str;
}
}
}
$cache->setPrefTo($mbox_str, $ret);
return $ret;
}
/* Internal methods. */
/**
* Returns a unique identifier for this mailbox's status.
*
* This cache ID is guaranteed to change if messages are added/deleted
* from the mailbox. Additionally, if CONDSTORE is available on the remote
* IMAP server, this ID will change if flag information changes.
*
* For search mailboxes, this value never changes (search mailboxes must
* be forcibly refreshed).
*
* @param boolean $date If true, adds date information to ID.
*
* @return string The cache ID string, which will change when the
* composition of this mailbox changes.
*/
protected function _getCacheID($date = false)
{
global $prefs;
$date = $date
? 'D' . date('z')
: '';
if ($this->search) {
return '1' . ($date ? '|' . $date : '');
}
$sortpref = $this->getSort(true);
$addl = array(
$sortpref->sortby,
$sortpref->sortdir,
intval($prefs->getValue('delhide'))
);
if ($date) {
$addl[] = $date;
}
try {
return $this->imp_imap->getCacheId($this->_mbox, $addl);
} catch (IMP_Imap_Exception $e) {
/* Assume an error means that a mailbox can not be trusted. */
return strval(new Horde_Support_Randomid());
}
}
/**
* 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. Additionally, translate prefix text if this
* is a special mailbox.
*
* @param boolean $notranslate Don't translate the mailbox prefix?
*
* @return string The mailbox, with any prefix gone/translated.
*/
protected function _getDisplay($notranslate = false)
{
global $injector;
$cache = $injector->getInstance('IMP_Mailbox_SessionCache');
if (!$notranslate &&
(($display = $cache->getDisplay($this->_mbox)) !== false)) {
return $display;
}
/* Handle special container mailboxes. */
if (($elt = $this->tree_elt) && $elt->nonimap && $elt->container) {
if ($elt->remote) {
return _("Remote Accounts");
} elseif ($elt->vfolder) {
return _("Virtual Folders");
} elseif ($elt->namespace_other) {
return _("Other Users");
} elseif ($elt->namespace_shared) {
return _("Shared");
}
}
/* Handle remote mailboxes. */
if ($this->remote) {
return $injector->getInstance('IMP_Remote')->label($this->_mbox);
}
$ns_info = $this->namespace_info;
$out = $this->_mbox;
if (!is_null($ns_info)) {
/* Return translated namespace information. */
if (strlen($ns_info->translation) && $this->namespace) {
$cache->setDisplay($this->_mbox, $ns_info->translation);
return $ns_info->translation;
}
/* Strip personal namespace information. */
if ($ns_info->type === $ns_info::NS_PERSONAL) {
$out = $ns_info->stripNamespace($this->_mbox);
}
}
if ($notranslate) {
return $out;
}
/* Bug #9971: Special mailboxes can be empty IMP_Mailbox objects -
* catch this with the strlen check below. */
foreach ($this->getSpecialMailboxes() as $key => $val) {
switch ($key) {
case self::SPECIAL_COMPOSETEMPLATES:
if (strval($val) == $this->_mbox) {
$out = _("Templates");
}
break;
case self::SPECIAL_DRAFTS:
if (strval($val) == $this->_mbox) {
$out = _("Drafts");
}
break;
case self::SPECIAL_SENT:
if (in_array($this->_mbox, $val)) {
$out = _("Sent");
}
break;
case self::SPECIAL_SPAM:
if (strval($val) == $this->_mbox) {
$out = _("Spam");
}
break;
case self::SPECIAL_TRASH:
if (strval($val) == $this->_mbox) {
$out = _("Trash");
}
break;
}
}
if ($this->inbox) {
$out = _("Inbox");
} elseif (($this->_mbox == $out) &&
!is_null($ns_info) &&
(strpos($out, 'INBOX' . $ns_info->delimiter) === 0)) {
$out = substr_replace($out, _("Inbox"), 0, 5);
}
$cache->setDisplay($this->_mbox, $out);
return $out;
}
/**
* Return icon information.
*
* @return object Object with the following properties:
* - alt
* - class
* - icon
* - iconopen
* - user_icon
*/
protected function _getIcon()
{
global $injector;
$info = new stdClass;
$info->iconopen = null;
$info->user_icon = false;
if ($this->container) {
/* We are dealing with folders here. */
if ($this->is_open) {
$info->alt = _("Opened Folder");
$info->class = 'folderopenImg';
$info->icon = 'folders/open.png';
} else {
$info->alt = _("Folder");
$info->class = 'folderImg';
$info->icon = 'folders/folder.png';
$info->iconopen = Horde_Themes::img('folders/open.png');
}
} elseif ($this->remote_container) {
$info->alt = _("Remote Account");
$info->class = 'remoteImg';
$info->icon = 'shared.png';
} else {
$special = $this->getSpecialMailboxes();
switch ($this->_mbox) {
case 'INBOX':
$info->alt = _("Inbox");
$info->class = 'inboxImg';
$info->icon = 'folders/inbox.png';
break;
case $special[self::SPECIAL_COMPOSETEMPLATES]:
$info->alt = ("Templates");
$info->class = 'composetemplatesImg';
$info->icon = 'folders/drafts.png';
break;
case $special[self::SPECIAL_DRAFTS]:
$info->alt = _("Drafts");
$info->class = 'draftsImg';
$info->icon = 'folders/drafts.png';
break;
case $special[self::SPECIAL_SPAM]:
$info->alt = _("Spam");
$info->class = 'spamImg';
$info->icon = 'folders/spam.png';
break;
case $special[self::SPECIAL_TRASH]:
$info->alt = _("Trash");
$info->class = 'trashImg';
$info->icon = 'folders/trash.png';
break;
default:
if (in_array($this->_mbox, $special[self::SPECIAL_SENT])) {
$info->alt = _("Sent");
$info->class = 'sentImg';
$info->icon = 'folders/sent.png';
} else {
$info->alt = in_array($this->_mbox, $special[self::SPECIAL_USER])
? $this->display
: _("Mailbox");
if ($this->is_open) {
$info->class = 'folderopenImg';
$info->icon = 'folders/open.png';
} else {
$info->class = 'folderImg';
$info->icon = 'folders/folder.png';
}
}
break;
}
/* Virtual folders. */
if ($this->vfolder) {
$imp_search = $injector->getInstance('IMP_Search');
if ($imp_search->isVTrash($this->_mbox)) {
$info->alt = $imp_search[$this->_mbox]->label;
$info->class = 'trashImg';
$info->icon = 'folders/trash.png';
} elseif ($imp_search->isVinbox($this->_mbox)) {
$info->alt = $imp_search[$this->_mbox]->label;
$info->class = 'inboxImg';
$info->icon = 'folders/inbox.png';
}
}
}
/* Overwrite the icon information now. */
$mi = $injector->getInstance('IMP_Mailbox_SessionCache')->getIcons($this->_mbox);
if (!empty($mi)) {
if (isset($mi['alt'])) {
$info->alt = $mi['alt'];
}
$info->icon = strval($mi['icon']);
$info->user_icon = true;
} elseif ($info->icon) {
$info->icon = Horde_Themes::img($info->icon);
}
return $info;
}
/**
* Do the necessary cleanup/cache updates when deleting mailboxes.
*
* @param array $deleted The list of deleted mailboxes.
*/
protected function _onDelete($deleted)
{
/* Clear the mailboxes from the sort prefs. */
foreach ($this->get($deleted) as $val) {
$val->setSort(null, null, true);
}
}
}