⚝
One Hat Cyber Team
⚝
Your IP:
216.73.217.4
Server IP:
41.128.143.86
Server:
Linux host.raqmix.cloud 6.8.0-1025-azure #30~22.04.1-Ubuntu SMP Wed Mar 12 15:28:20 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
8.3.23
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
proc
/
self
/
root
/
usr
/
share
/
psa-horde
/
imp
/
lib
/
View File Name :
Mailbox.php
* @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: *
* - subfolders: (boolean) If true, applies actions to all subfolders. *
* * @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); } } }