Overview

Packages

  • IMP
  • None

Classes

  • IMP
  • IMP_Ajax_Application
  • IMP_Ajax_Imple_ContactAutoCompleter
  • IMP_Ajax_Imple_PassphraseDialog
  • IMP_Ajax_Queue
  • IMP_Api
  • IMP_Auth
  • IMP_Block_Newmail
  • IMP_Block_Summary
  • IMP_Compose
  • IMP_Compose_Exception
  • IMP_Compose_Stationery
  • IMP_Contents
  • IMP_Crypt_Pgp
  • IMP_Crypt_Smime
  • IMP_Dimp
  • IMP_Exception
  • IMP_Factory_AuthImap
  • IMP_Factory_Compose
  • IMP_Factory_Contents
  • IMP_Factory_Flags
  • IMP_Factory_Identity
  • IMP_Factory_Imap
  • IMP_Factory_Imaptree
  • IMP_Factory_Mail
  • IMP_Factory_Mailbox
  • IMP_Factory_MailboxList
  • IMP_Factory_MimeViewer
  • IMP_Factory_Pgp
  • IMP_Factory_Quota
  • IMP_Factory_Search
  • IMP_Factory_Sentmail
  • IMP_Factory_Smime
  • IMP_Filter
  • IMP_Flag_Base
  • IMP_Flag_Imap
  • IMP_Flag_Imap_Answered
  • IMP_Flag_Imap_Deleted
  • IMP_Flag_Imap_Draft
  • IMP_Flag_Imap_Flagged
  • IMP_Flag_Imap_Forwarded
  • IMP_Flag_Imap_Junk
  • IMP_Flag_Imap_NotJunk
  • IMP_Flag_Imap_Seen
  • IMP_Flag_System_Attachment
  • IMP_Flag_System_Encrypted
  • IMP_Flag_System_HighPriority
  • IMP_Flag_System_List
  • IMP_Flag_System_LowPriority
  • IMP_Flag_System_Match_Address
  • IMP_Flag_System_Match_Flag
  • IMP_Flag_System_Match_Header
  • IMP_Flag_System_Personal
  • IMP_Flag_System_Signed
  • IMP_Flag_System_Unseen
  • IMP_Flag_User
  • IMP_Flags
  • IMP_Imap
  • IMP_Imap_Acl
  • IMP_Imap_Exception
  • IMP_Imap_PermanentFlags
  • IMP_Imap_Thread
  • IMP_Imap_Tree
  • IMP_Indices
  • IMP_Indices_Form
  • IMP_LoginTasks_SystemTask_GarbageCollection
  • IMP_LoginTasks_SystemTask_Upgrade
  • IMP_LoginTasks_SystemTask_UpgradeAuth
  • IMP_LoginTasks_Task_Autocreate
  • IMP_LoginTasks_Task_DeleteAttachmentsMonthly
  • IMP_LoginTasks_Task_DeleteSentmailMonthly
  • IMP_LoginTasks_Task_FilterOnLogin
  • IMP_LoginTasks_Task_PurgeSentmail
  • IMP_LoginTasks_Task_PurgeSpam
  • IMP_LoginTasks_Task_PurgeTrash
  • IMP_LoginTasks_Task_RecoverDraft
  • IMP_LoginTasks_Task_RenameSentmailMonthly
  • IMP_Mailbox
  • IMP_Mailbox_List
  • IMP_Mailbox_List_Track
  • IMP_Maillog
  • IMP_Menu_Dimp
  • IMP_Message
  • IMP_Mime_Status
  • IMP_Mime_Viewer_Alternative
  • IMP_Mime_Viewer_Appledouble
  • IMP_Mime_Viewer_Audio
  • IMP_Mime_Viewer_Enriched
  • IMP_Mime_Viewer_Externalbody
  • IMP_Mime_Viewer_Html
  • IMP_Mime_Viewer_Images
  • IMP_Mime_Viewer_Itip
  • IMP_Mime_Viewer_Mdn
  • IMP_Mime_Viewer_Partial
  • IMP_Mime_Viewer_Pdf
  • IMP_Mime_Viewer_Pgp
  • IMP_Mime_Viewer_Plain
  • IMP_Mime_Viewer_Related
  • IMP_Mime_Viewer_Rfc822
  • IMP_Mime_Viewer_Smil
  • IMP_Mime_Viewer_Smime
  • IMP_Mime_Viewer_Status
  • IMP_Mime_Viewer_Vcard
  • IMP_Mime_Viewer_Video
  • IMP_Mime_Viewer_Zip
  • IMP_Notification_Event_Status
  • IMP_Notification_Handler_Decorator_ImapAlerts
  • IMP_Notification_Handler_Decorator_NewmailNotify
  • IMP_Notification_Listener_AjaxStatus
  • Imp_Prefs_Identity
  • IMP_Prefs_Ui
  • IMP_Quota
  • IMP_Quota_Base
  • IMP_Quota_Command
  • IMP_Quota_Hook
  • IMP_Quota_Imap
  • IMP_Quota_Maildir
  • IMP_Quota_Mdaemon
  • IMP_Quota_Mercury32
  • IMP_Quota_Null
  • IMP_Quota_Sql
  • IMP_Search
  • IMP_Search_Element
  • IMP_Search_Element_Attachment
  • IMP_Search_Element_Autogenerated
  • IMP_Search_Element_Bulk
  • IMP_Search_Element_Contacts
  • IMP_Search_Element_Date
  • IMP_Search_Element_Flag
  • IMP_Search_Element_Header
  • IMP_Search_Element_Mailinglist
  • IMP_Search_Element_Or
  • IMP_Search_Element_Personal
  • IMP_Search_Element_Recipient
  • IMP_Search_Element_Size
  • IMP_Search_Element_Text
  • IMP_Search_Element_Within
  • IMP_Search_Filter
  • IMP_Search_Filter_Attachment
  • IMP_Search_Filter_Autogenerated
  • IMP_Search_Filter_Builtin
  • IMP_Search_Filter_Bulk
  • IMP_Search_Filter_Contacts
  • IMP_Search_Filter_Mailinglist
  • IMP_Search_Filter_Personal
  • IMP_Search_Query
  • IMP_Search_Vfolder
  • IMP_Search_Vfolder_Builtin
  • IMP_Search_Vfolder_Vinbox
  • IMP_Search_Vfolder_Vtrash
  • IMP_Sentmail
  • IMP_Sentmail_Base
  • IMP_Sentmail_Null
  • IMP_Sentmail_Sql
  • IMP_Spam
  • IMP_Test
  • IMP_Tree_Flist
  • IMP_Tree_Jquerymobile
  • IMP_Tree_Simplehtml
  • IMP_Ui_Compose
  • IMP_Ui_Editor
  • IMP_Ui_Folder
  • IMP_Ui_Headers
  • IMP_Ui_Imageview
  • IMP_Ui_Mailbox
  • IMP_Ui_Message
  • IMP_Ui_Mimp
  • IMP_Ui_Search
  • IMP_Views_Compose
  • IMP_Views_ListMessages
  • IMP_Views_ShowMessage
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: /**
   3:  * The IMP_Mailbox class acts as a clearinghouse for actions related to a
   4:  * mailbox.
   5:  *
   6:  * Copyright 2011-2012 Horde LLC (http://www.horde.org/)
   7:  *
   8:  * See the enclosed file COPYING for license information (GPL). If you
   9:  * did not receive this file, see http://www.horde.org/licenses/gpl.
  10:  *
  11:  * @author   Michael Slusarz <slusarz@horde.org>
  12:  * @category Horde
  13:  * @license  http://www.horde.org/licenses/gpl GPL
  14:  * @package  IMP
  15:  *
  16:  * @property string $abbrev_label  Abbreviated version of $label - displays
  17:  *                                 only the bare mailbox name (no parents).
  18:  * @property boolean $access_creatembox  Can sub mailboxes be created?
  19:  * @property boolean $access_deletembox  Can this mailbox be deleted?
  20:  * @property boolean $access_deletemsgs  Can messages be deleted in this
  21:  *                                       mailbox?
  22:  * @property boolean $access_expunge  Can messages be expunged in this
  23:  *                                    mailbox?
  24:  * @property boolean $access_filters  Is filtering available?
  25:  * @property boolean $access_sort  Is sorting available?
  26:  * @property boolean $access_sortthread  Is thread sort available?
  27:  * @property mixed $acl  Either an ACL object for the mailbox, or null if
  28:  *                       no ACL found for the mailbox.
  29:  * @property string $basename  The basename of the mailbox (UTF-8).
  30:  * @property string $cacheid  Cache ID for the mailbox.
  31:  * @property string $cacheid_date  Cache ID for the mailbox, with added date
  32:  *                                 information.
  33:  * @property boolean $children  Does the element have children?
  34:  * @property boolean $container  Is this a container element?
  35:  * @property string $display  Display version of mailbox. Special mailboxes
  36:  *                            are replaced with localized strings and
  37:  *                            namespace information is removed.
  38:  * @property string $display_html  $display that has been HTML encoded.
  39:  * @property boolean $drafts  Is this a Drafts mailbox?
  40:  * @property boolean $editquery  Can this search query be edited?
  41:  * @property boolean $editvfolder  Can this virtual folder be edited?
  42:  * @property boolean $exists  Does this mailbox exist on the IMAP server?
  43:  * @property boolean $fixed  Is this mailbox fixed (i.e. unchangable)?
  44:  * @property string $form_to  Converts this mailbox to a form representation.
  45:  * @property boolean $is_open  Is this level expanded?
  46:  * @property boolean $is_trash  Is this a trash folder?
  47:  * @property object $icon  Icon information for the mailbox. Properties:
  48:  *   - alt: (string) The alt text for the icon.
  49:  *   - class: (string) The CSS class name.
  50:  *   - icon: (Horde_Themes_Image) The icon graphic to use.
  51:  *   - iconopen: (Horde_Themes_Image) The openicon to use.
  52:  *   - user_icon: (boolean) Use a user defined icon?
  53:  * @property boolean $inbox)  Is this the INBOX?
  54:  * @property boolean $invisible  Is this mailbox invisible?
  55:  * @property string $label  The mailbox label. Essentially is $display that
  56:  *                          can be modified by user hook.
  57:  * @property integer $level  The child level of this element.
  58:  * @property string $namespace  Is this a namespace element?
  59:  * @property IMP_Mailbox $namespace_append  The mailbox with necessary
  60:  *                                          namespace information appended.
  61:  * @property string $namespace_delimiter  The delimiter for this namespace.
  62:  * @property array $namespace_info  See IMP_Imap::getNamespace().
  63:  * @property boolean $nonimap  Is this a non-IMAP element?
  64:  * @property IMP_Mailbox $parent  The parent element. Returns null if no
  65:  *                                parent.
  66:  * @property IMP_Imap_PermanentFlags $permflags  Return the list of permanent
  67:  *                                               flags available to set in the
  68:  *                                               mailbox.
  69:  * @property boolean $polled  Show polled information?
  70:  * @property object $poll_info  Poll information for the mailbox. Properties:
  71:  *   - msgs: (integer) The number of total messages in the element, if polled.
  72:  *   - recent: (integer) The number of new messages in the element, if polled.
  73:  *   - unseen: (integer) The number of unseen messages in the element, if
  74:  *             polled.
  75:  * @property string $pref_from  Convert mailbox name from preference storage.
  76:  * @property string $pref_to  Convert mailbox name to preference storage.
  77:  * @property boolean $query  Is this a search query?
  78:  * @property boolean $readonly  Is this mailbox read-only?
  79:  * @property boolean $search  Is this a search mailbox?
  80:  * @property boolean $special  Is this is a "special" element?
  81:  * @property boolean $special_outgoing  Is this a "special" element dealing
  82:  *                                      with outgoing messages?
  83:  * @property boolean $specialvfolder  Is this a "special" virtual folder?
  84:  * @property boolean $sub  Is this mailbox subscribed to?
  85:  * @property array $subfolders  Returns the list of subfolders as mailbox
  86:  *                              objects (including the current mailbox).
  87:  * @property array $subfolders_only  Returns the list of subfolders as mailbox
  88:  *                                   objects (NOT including the current
  89:  *                                   mailbox).
  90:  * @property string $uidvalid  Returns the UIDVALIDITY string. Throws an
  91:  *                             IMP_Exception on error.
  92:  * @property string $value  The value of this element (i.e. IMAP mailbox
  93:  *                          name). In UTF7-IMAP.
  94:  * @property boolean $vfolder  Is this a virtual folder?
  95:  * @property boolean $vfolder_container  Is this the virtual folder container?
  96:  * @property boolean $vinbox  Is this the virtual inbox?
  97:  * @property boolean $vtrash  Is this the virtual trash?
  98:  */
  99: class IMP_Mailbox implements Serializable
 100: {
 101:     /* Changed constants. */
 102:     const CHANGED_NO = 0;
 103:     const CHANGED_YES = 1;
 104:     const CHANGED_DELETE = 2;
 105: 
 106:     /* Special mailbox identifiers. */
 107:     const SPECIAL_DRAFTS = 'drafts';
 108:     const SPECIAL_SENT = 'sent';
 109:     const SPECIAL_SPAM = 'spam';
 110:     const SPECIAL_TRASH = 'trash';
 111: 
 112:     /* Cache identifiers. */
 113:     // (array) ACL rights
 114:     const CACHE_ACL = 'a';
 115:     // (string) Display string
 116:     const CACHE_DISPLAY = 'd';
 117:     // (array) Icons array
 118:     const CACHE_ICONS = 'i';
 119:     // (array) Namespace information
 120:     const CACHE_NAMESPACE = 'n';
 121:     // (boolean) Read-only?
 122:     const CACHE_READONLY = 'ro';
 123:     // (integer) UIDVALIDITY
 124:     const CACHE_UIDVALIDITY = 'v';
 125: 
 126:     /* Cache identifiers - temporary data. */
 127:     const CACHE_HASICONHOOK = 'ih';
 128:     const CACHE_ICONHOOK = 'ic';
 129:     const CACHE_HASLABELHOOK = 'lh';
 130:     const CACHE_HIDEDELETED = 'hd';
 131:     const CACHE_READONLYHOOK = 'roh';
 132:     const CACHE_SPECIALMBOXES = 's';
 133: 
 134:     /**
 135:      * Cached data.
 136:      *
 137:      * @var array
 138:      */
 139:     public $cache = array();
 140: 
 141:     /**
 142:      * Has this object changed?
 143:      *
 144:      * @var integer
 145:      */
 146:     public $changed = self::CHANGED_NO;
 147: 
 148:     /**
 149:      * Temporary data from importMbox().
 150:      *
 151:      * @var array
 152:      */
 153:     protected $_import;
 154: 
 155:     /**
 156:      * Temporary cached data.  Used among all instances.
 157:      *
 158:      * @var array
 159:      */
 160:     static protected $_temp = array();
 161: 
 162:     /**
 163:      * The full IMAP mailbox name.
 164:      *
 165:      * @var string
 166:      */
 167:     protected $_mbox;
 168: 
 169:     /**
 170:      * Shortcut to obtaining mailbox object(s).
 171:      *
 172:      * @param mixed $mbox  The full IMAP mailbox name(s).
 173:      *
 174:      * @return mixed  The IMP_Mailbox object(s).
 175:      */
 176:     static public function get($mbox)
 177:     {
 178:         if (is_array($mbox)) {
 179:             return array_filter(array_map(array(__CLASS__, 'get'), $mbox));
 180:         }
 181: 
 182:         try {
 183:             return $GLOBALS['injector']
 184:                 ->getInstance('IMP_Factory_Mailbox')
 185:                 ->create(strval($mbox));
 186:         } catch (IMP_Exception $e) {
 187:             return null;
 188:         }
 189:     }
 190: 
 191:     /**
 192:      * Shortcut to obtaining a mailbox object from a preference name.
 193:      *
 194:      * @var string $pref  The preference name.
 195:      *
 196:      * @return IMP_Mailbox  The IMP_Mailbox object.
 197:      */
 198:     static public function getPref($pref)
 199:     {
 200:         return self::get(self::prefFrom($GLOBALS['prefs']->getValue($pref)));
 201:     }
 202: 
 203:     /**
 204:      * Constructor.
 205:      *
 206:      * @var string $mbox  The full IMAP mailbox name.
 207:      *
 208:      * @throws IMP_Exception
 209:      */
 210:     public function __construct($mbox)
 211:     {
 212:         if (strlen($mbox) == 0) {
 213:             throw new IMP_Exception('Mailbox name must not be empty.');
 214:         }
 215: 
 216:         $this->_mbox = $mbox;
 217: 
 218:         if (!isset(self::$_temp[self::CACHE_HASICONHOOK])) {
 219:             self::$_temp[self::CACHE_HASICONHOOK] = Horde::hookExists('mbox_icons', 'imp');
 220:             self::$_temp[self::CACHE_HASLABELHOOK] = Horde::hookExists('mbox_label', 'imp');
 221:         }
 222:     }
 223: 
 224:     /**
 225:      */
 226:     public function __toString()
 227:     {
 228:         return strval($this->_mbox);
 229:     }
 230: 
 231:     /**
 232:      */
 233:     public function __get($key)
 234:     {
 235:         global $injector;
 236: 
 237:         switch ($key) {
 238:         case 'abbrev_label':
 239:             $label = $this->label;
 240:             return (($pos = strrpos($label, $this->namespace_delimiter)) === false)
 241:                 ? $label
 242:                 : substr($label, $pos + 1);
 243: 
 244:         case 'access_creatembox':
 245:             return (!($acl = $this->acl) ||
 246:                     ($acl[Horde_Imap_Client::ACL_CREATEMBOX]));
 247: 
 248:         case 'access_deletembox':
 249:             return (!($acl = $this->acl) ||
 250:                     ($acl[Horde_Imap_Client::ACL_DELETEMBOX]));
 251: 
 252:         case 'access_deletemsgs':
 253:             return (!$this->readonly &&
 254:                     (!($acl = $this->acl) ||
 255:                     ($acl[Horde_Imap_Client::ACL_DELETEMSGS])));
 256: 
 257:         case 'access_expunge':
 258:             return (!$this->readonly &&
 259:                     (!($acl = $this->acl) ||
 260:                     ($acl[Horde_Imap_Client::ACL_EXPUNGE])));
 261: 
 262:         case 'access_filters':
 263:             return !$this->search &&
 264:                    !$injector->getInstance('IMP_Factory_Imap')->create()->pop3;
 265: 
 266:         case 'access_sort':
 267:             /* Although possible to abstract other sorting methods, all other
 268:              * non-sequence methods require a download of ALL messages, which
 269:              * is too much overhead.*/
 270:             return !$injector->getInstance('IMP_Factory_Imap')->create()->pop3;
 271: 
 272:         case 'access_sortthread':
 273:             /* Thread sort is always available for IMAP servers, since
 274:              * Horde_Imap_Client_Socket has a built-in ORDEREDSUBJECT
 275:              * implementation. We will always prefer REFERENCES, but will
 276:              * fallback to ORDEREDSUBJECT if the server doesn't support THREAD
 277:              * sorting. */
 278:             return ($injector->getInstance('IMP_Factory_Imap')->create()->imap &&
 279:                     !$this->search);
 280: 
 281:         case 'acl':
 282:             if (isset($this->cache[self::CACHE_ACL])) {
 283:                 return is_null($this->cache[self::CACHE_ACL])
 284:                     ? null
 285:                     : new Horde_Imap_Client_Data_Acl($this->cache[self::CACHE_ACL]);
 286:             }
 287: 
 288:             $acl = $this->cache[self::CACHE_ACL] = null;
 289:             $this->changed = self::CHANGED_YES;
 290: 
 291:             if (!$this->nonimap) {
 292:                 try {
 293:                     $acl = $injector->getInstance('IMP_Imap_Acl')->getACL($this, true);
 294:                     /* Store string representation of ACL for a more compact
 295:                      * serialized format. */
 296:                     $this->cache[self::CACHE_ACL] = strval($acl);
 297:                 } catch (IMP_Exception $e) {}
 298:             }
 299: 
 300:             return $acl;
 301: 
 302:         case 'basename':
 303:             if ($this->nonimap) {
 304:                 return $this->label;
 305:             }
 306: 
 307:             $basename = (($pos = strrpos($this->_mbox, $this->namespace_delimiter)) === false)
 308:                 ? $this->_mbox
 309:                 : substr($this->_mbox, $pos + 1);
 310: 
 311:             return Horde_String::convertCharset($basename, 'UTF7-IMAP', 'UTF-8');
 312: 
 313:         case 'cacheid':
 314:         case 'cacheid_date':
 315:             return $this->_getCacheID($key == 'cacheid_date');
 316: 
 317:         case 'children':
 318:             return $injector->getInstance('IMP_Imap_Tree')->hasChildren($this->_mbox);
 319: 
 320:         case 'container':
 321:             return $injector->getInstance('IMP_Imap_Tree')->isContainer($this->_mbox);
 322: 
 323:         case 'display':
 324:             return $this->nonimap
 325:                 ? $this->label
 326:                 : $this->_getDisplay();
 327: 
 328:         case 'display_html':
 329:             return htmlspecialchars($this->display);
 330: 
 331:         case 'display_notranslate':
 332:             return $this->nonimap
 333:                 ? $this->label
 334:                 : $this->_getDisplay(true);
 335: 
 336:         case 'drafts':
 337:             $special = $this->getSpecialMailboxes();
 338:             return ($this->_mbox == $special[self::SPECIAL_DRAFTS]);
 339: 
 340:         case 'editquery':
 341:             return $injector->getInstance('IMP_Search')->isQuery($this->_mbox, true);
 342: 
 343:         case 'editvfolder':
 344:             return $injector->getInstance('IMP_Search')->isVFolder($this->_mbox, true);
 345: 
 346:         case 'exists':
 347:             if ($ob = $this->getSearchOb()) {
 348:                 return $ob->enabled;
 349:             }
 350: 
 351:             $imaptree = $injector->getInstance('IMP_Imap_Tree');
 352:             if (isset($imaptree[$this->_mbox])) {
 353:                 return !$imaptree[$this->_mbox]->container;
 354:             }
 355: 
 356:             try {
 357:                 return (bool)$injector->getInstance('IMP_Factory_Imap')->create()->listMailboxes($this->_mbox, array('flat' => true));
 358:             } catch (IMP_Imap_Exception $e) {
 359:                 return false;
 360:             }
 361: 
 362:         case 'fixed':
 363:             return (!empty($GLOBALS['conf']['server']['fixed_folders']) &&
 364:                     in_array($this->pref_to, $GLOBALS['conf']['server']['fixed_folders']));
 365: 
 366:         case 'form_to':
 367:             return $this->formTo($this->_mbox);
 368: 
 369:         case 'is_open':
 370:             return $injector->getInstance('IMP_Imap_Tree')->isOpen($this->_mbox);
 371: 
 372:         case 'is_trash':
 373:             return (self::getPref('trash_folder') == $this) || $this->vtrash;
 374: 
 375:         case 'icon':
 376:             return $this->_getIcon();
 377: 
 378:         case 'inbox':
 379:             return (strcasecmp($this->_mbox, 'INBOX') === 0);
 380: 
 381:         case 'invisible':
 382:             return $injector->getInstance('IMP_Imap_Tree')->isInvisible($this->_mbox);
 383: 
 384:         case 'label':
 385:             /* Returns the plain text label that is displayed for the current
 386:              * mailbox, replacing virtual search mailboxes with an appropriate
 387:              * description, removing namespace and mailbox prefix information
 388:              * from what is shown to the user, and passing the label through a
 389:              * user-defined hook. */
 390:             $imp_search = $injector->getInstance('IMP_Search');
 391:             $label = ($ob = $imp_search[$this->_mbox])
 392:                 ? $ob->label
 393:                 : $this->_getDisplay();
 394: 
 395:             return self::$_temp[self::CACHE_HASLABELHOOK]
 396:                 ? Horde::callHook('mbox_label', array($this->_mbox, $label), 'imp')
 397:                 : $label;
 398: 
 399:         case 'level':
 400:             $elt = $injector->getInstance('IMP_Imap_Tree')->getElement($this->_mbox);
 401:             return $elt
 402:                 ? $elt['c']
 403:                 : 0;
 404: 
 405:         case 'namespace':
 406:             return $injector->getInstance('IMP_Imap_Tree')->isNamespace($this->_mbox);
 407: 
 408:         case 'namespace_append':
 409:             $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
 410:             $def_ns = $imp_imap->defaultNamespace();
 411:             if (is_null($def_ns)) {
 412:                 return $this;
 413:             }
 414:             $empty_ns = $imp_imap->getNamespace('');
 415: 
 416: 
 417:             /* If default namespace is empty, or there is no empty namespace,
 418:              * then we can auto-detect namespace from input.
 419:              * If a non-default namespace is empty, then we must always use
 420:              * default namespace. */
 421:             if (!is_null($empty_ns) &&
 422:                 ($def_ns['name'] == $empty_ns['name'])) {
 423:                 return $this;
 424:             }
 425: 
 426:             $ns_info = $this->namespace_info;
 427: 
 428:             if (is_null($ns_info) || !is_null($empty_ns)) {
 429:                 return self::get($def_ns['name'] . $this->_mbox);
 430:             }
 431: 
 432:             return $this;
 433: 
 434:         case 'namespace_delimiter':
 435:             $ns_info = $this->namespace_info;
 436:             return is_null($ns_info)
 437:                 ? ''
 438:                 : $ns_info['delimiter'];
 439: 
 440:         case 'namespace_info':
 441:             $keys = array('delimiter', 'hidden', 'name', 'translation', 'type');
 442: 
 443:             if (isset($this->cache[self::CACHE_NAMESPACE])) {
 444:                 $ns = $this->cache[self::CACHE_NAMESPACE];
 445: 
 446:                 if (is_null($ns)) {
 447:                     return null;
 448:                 }
 449: 
 450:                 $ret = array();
 451:                 foreach ($keys as $key => $val) {
 452:                     $ret[$val] = isset($ns[$key])
 453:                         ? $ns[$key]
 454:                         : '';
 455:                 }
 456: 
 457:                 return $ret;
 458:             }
 459: 
 460:             $ns_info = $injector->getInstance('IMP_Factory_Imap')->create()->getNamespace($this->_mbox);
 461:             if (is_null($ns_info)) {
 462:                 $this->cache[self::CACHE_NAMESPACE] = null;
 463:             } else {
 464:                 /* Store data compressed in the cache array. */
 465:                 $this->cache[self::CACHE_NAMESPACE] = array();
 466:                 foreach ($keys as $id => $key) {
 467:                     if ($ns_info[$key]) {
 468:                         $this->cache[self::CACHE_NAMESPACE][$id] = $ns_info[$key];
 469:                     }
 470:                 }
 471:             }
 472: 
 473:             $this->changed = self::CHANGED_YES;
 474: 
 475:             return $ns_info;
 476: 
 477:         case 'nonimap':
 478:             return ($this->search ||
 479:                     $injector->getInstance('IMP_Imap_Tree')->isNonImapElt($this->_mbox));
 480: 
 481:         case 'parent':
 482:             $elt = $injector->getInstance('IMP_Imap_Tree')->getElement($this->_mbox);
 483:             return $elt
 484:                 ? self::get($elt['p'])
 485:                 : null;
 486: 
 487:         case 'permflags':
 488:             $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
 489: 
 490:             if ($imp_imap->access(IMP_Imap::ACCESS_FLAGS)) {
 491:                 try {
 492:                     /* Make sure we are in R/W mailbox mode (SELECT). No flags
 493:                      * are allowed in EXAMINE mode. */
 494:                     $imp_imap->openMailbox($this->_mbox, Horde_Imap_Client::OPEN_READWRITE);
 495:                     $status = $imp_imap->status($this->_mbox, Horde_Imap_Client::STATUS_FLAGS | Horde_Imap_Client::STATUS_PERMFLAGS);
 496:                     return new IMP_Imap_PermanentFlags($status['permflags'], $status['flags']);
 497:                 } catch (Exception $e) {}
 498:             }
 499: 
 500:             return new IMP_Imap_PermanentFlags();
 501: 
 502:         case 'poll_info':
 503:             $info = new stdClass;
 504:             $info->msgs = 0;
 505:             $info->recent = 0;
 506:             $info->unseen = 0;
 507: 
 508:             try {
 509:                 if ($msgs_info = $injector->getInstance('IMP_Factory_Imap')->create()->status($this->_mbox, Horde_Imap_Client::STATUS_RECENT | Horde_Imap_Client::STATUS_UNSEEN | Horde_Imap_Client::STATUS_MESSAGES)) {
 510:                     if (!empty($msgs_info['recent'])) {
 511:                         $info->recent = intval($msgs_info['recent']);
 512:                     }
 513:                     $info->msgs = intval($msgs_info['messages']);
 514:                     $info->unseen = intval($msgs_info['unseen']);
 515:                 }
 516:             } catch (IMP_Imap_Exception $e) {}
 517: 
 518:             return $info;
 519: 
 520:         case 'polled':
 521:             return !$this->search &&
 522:                    $injector->getInstance('IMP_Imap_Tree')->isPolled($this->_mbox);
 523: 
 524:         case 'pref_from':
 525:             return $this->prefFrom($this->_mbox);
 526: 
 527:         case 'pref_to':
 528:             return $this->prefTo($this->_mbox);
 529: 
 530:         case 'query':
 531:             return $injector->getInstance('IMP_Search')->isQuery($this->_mbox);
 532: 
 533:         case 'readonly':
 534:             if (isset($this->cache[self::CACHE_READONLY])) {
 535:                 return $this->cache[self::CACHE_READONLY];
 536:             }
 537: 
 538:             $this->cache[self::CACHE_READONLY] = false;
 539:             $this->changed = self::CHANGED_YES;
 540: 
 541:             /* This check works for regular and search mailboxes. */
 542:             if (empty(self::$_temp[self::CACHE_READONLYHOOK])) {
 543:                 try {
 544:                     if (Horde::callHook('mbox_readonly', array($this->_mbox), 'imp')) {
 545:                         $this->cache[self::CACHE_READONLY] = true;
 546:                     }
 547:                 } catch (Horde_Exception_HookNotSet $e) {
 548:                     self::$_temp[self::CACHE_READONLYHOOK] = true;
 549:                 }
 550:             }
 551: 
 552:             /* The UIDNOTSTICKY check would go here. */
 553: 
 554:             return $this->cache[self::CACHE_READONLY];
 555: 
 556:         case 'search':
 557:             return $injector->getInstance('IMP_Search')->isSearchMbox($this->_mbox);
 558: 
 559:         case 'special':
 560:             $special = $this->getSpecialMailboxes();
 561: 
 562:             switch ($this->_mbox) {
 563:             case 'INBOX':
 564:             case $special[self::SPECIAL_DRAFTS]:
 565:             case $special[self::SPECIAL_SPAM]:
 566:             case $special[self::SPECIAL_TRASH]:
 567:                 return true;
 568:             }
 569: 
 570:             return in_array($this->_mbox, $special[self::SPECIAL_SENT]);
 571: 
 572:         case 'special_outgoing':
 573:             $special = $this->getSpecialMailboxes();
 574: 
 575:             return in_array($this->_mbox, array_merge(
 576:                 array(
 577:                     $special[self::SPECIAL_DRAFTS]
 578:                 ),
 579:                 $special[self::SPECIAL_SENT]
 580:             ));
 581: 
 582:         case 'specialvfolder':
 583:             return !$this->editvfolder;
 584: 
 585:         case 'sub':
 586:             return $injector->getInstance('IMP_Imap_Tree')->isSubscribed($this->_mbox);
 587: 
 588:         case 'subfolders':
 589:             return $this->get(array_merge(array($this->_mbox), $this->subfolders_only));
 590: 
 591:         case 'subfolders_only':
 592:             return $this->get($injector->getInstance('IMP_Factory_Imap')->create()->listMailboxes($this->_mbox . $this->namespace_delimiter . '*', null, array('flat' => true)));
 593: 
 594:         case 'uidvalid':
 595:             $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
 596: 
 597:             // POP3 and non-IMAP mailboxes does not support UIDVALIDITY.
 598:             if ($imp_imap->pop3 || $this->nonimap) {
 599:                 return;
 600:             }
 601: 
 602:             $status = $imp_imap->status($this->_mbox, Horde_Imap_Client::STATUS_UIDVALIDITY);
 603:             if (($first = !isset($this->cache[self::CACHE_UIDVALIDITY])) ||
 604:                 ($status['uidvalidity'] != $this->cache[self::CACHE_UIDVALIDITY])) {
 605:                 $this->cache[self::CACHE_UIDVALIDITY] = $status['uidvalidity'];
 606:                 $this->changed = self::CHANGED_YES;
 607: 
 608:                 if (!$first) {
 609:                     throw new IMP_Exception(_("Mailbox structure on server has changed."));
 610:                 }
 611:             }
 612: 
 613:             return $this->cache[self::CACHE_UIDVALIDITY];
 614: 
 615:         case 'value':
 616:             return $this->_mbox;
 617: 
 618:         case 'vfolder':
 619:             return $injector->getInstance('IMP_Search')->isVFolder($this->_mbox);
 620: 
 621:         case 'vfolder_container':
 622:             return ($this->_mbox == IMP_Imap_Tree::VFOLDER_KEY);
 623: 
 624:         case 'vinbox':
 625:             return $injector->getInstance('IMP_Search')->isVinbox($this->_mbox);
 626: 
 627:         case 'vtrash':
 628:             return $injector->getInstance('IMP_Search')->isVtrash($this->_mbox);
 629:         }
 630: 
 631:         return false;
 632:     }
 633: 
 634:     /**
 635:      * Create this mailbox on the server.
 636:      *
 637:      * @param array $opts  Additional options:
 638:      *   - special_use: (array) An array of special-use attributes to attempt
 639:      *                  to add to the mailbox.
 640:      *                  DEFAULT: NONE
 641:      *   - subscribe: (boolean) Override preference value of subscribe.
 642:      *
 643:      * @return boolean  True on success.
 644:      * @throws Horde_Exception
 645:      */
 646:     public function create(array $opts = array())
 647:     {
 648:         global $injector, $notification, $prefs, $registry;
 649: 
 650:         if ($this->exists) {
 651:             return true;
 652:         }
 653: 
 654:         /* Check permissions. */
 655:         if (!IMP::hasPermission('create_folders')) {
 656:             Horde::permissionDeniedError(
 657:                 'imp',
 658:                 'create_folders',
 659:                 _("You are not allowed to create folders.")
 660:             );
 661:             return false;
 662:         }
 663:         if (!IMP::hasPermission('max_folders')) {
 664:             Horde::permissionDeniedError(
 665:                 'imp',
 666:                 'max_folders',
 667:                 sprintf(_("You are not allowed to create more than %d folders."), $injector->getInstance('Horde_Core_Perms')->hasAppPermission('max_folders'))
 668:             );
 669:             return false;
 670:         }
 671: 
 672:         /* Special use flags. */
 673:         $special_use = isset($opts['special_use'])
 674:             ? $opts['special_use']
 675:             : array();
 676: 
 677:         /* Attempt to create the mailbox. */
 678:         try {
 679:             $injector->getInstance('IMP_Factory_Imap')->create()->createMailbox($this->_mbox, array('special_use' => $special_use));
 680:         } catch (IMP_Imap_Exception $e) {
 681:             if ($e->getCode() == Horde_Imap_Client_Exception::USEATTR) {
 682:                 unset($opts['special_use']);
 683:                 return $this->create($opts);
 684:             }
 685: 
 686:             $e->notify(sprintf(_("The mailbox \"%s\" was not created. This is what the server said"), $this->display) . ': ' . $e->getMessage());
 687:             return false;
 688:         }
 689: 
 690:         $notification->push(sprintf(_("The mailbox \"%s\" was successfully created."), $this->display), 'horde.success');
 691: 
 692:         /* Subscribe, if requested. */
 693:         if ((!isset($opts['subscribe']) && $prefs->getValue('subscribe')) ||
 694:             !empty($opts['subscribe'])) {
 695:             $this->subscribe(true);
 696:         }
 697: 
 698:         /* Update the mailbox tree. */
 699:         $injector->getInstance('IMP_Imap_Tree')->insert($this->_mbox);
 700: 
 701:         return true;
 702:     }
 703: 
 704:     /**
 705:      * Deletes mailbox.
 706:      *
 707:      * @param boolean $force  Delete even if fixed?
 708:      *
 709:      * @return boolean  True on success.
 710:      */
 711:     public function delete($force = false)
 712:     {
 713:         global $conf, $injector, $notification;
 714: 
 715:         if ($this->vfolder) {
 716:             if ($this->editvfolder) {
 717:                 $imp_search = $injector->getInstance('IMP_Search');
 718:                 $label = $imp_search[$this->_mbox]->label;
 719:                 unset($imp_search[$this->_mbox]);
 720:                 $notification->push(sprintf(_("Deleted Virtual Folder \"%s\"."), $label), 'horde.success');
 721:                 return true;
 722:             }
 723: 
 724:             $notification->push(sprintf(_("Could not delete Virtual Folder \"%s\"."), $this->label), 'horde.error');
 725:             return false;
 726:         }
 727: 
 728:         if ((!$force && $this->fixed) || !$this->access_deletembox)  {
 729:             $notification->push(sprintf(_("The mailbox \"%s\" may not be deleted."), $this->display), 'horde.error');
 730:             return false;
 731:         }
 732: 
 733:         try {
 734:             $injector->getInstance('IMP_Factory_Imap')->create()->deleteMailbox($this->_mbox);
 735:             $notification->push(sprintf(_("The mailbox \"%s\" was successfully deleted."), $this->display), 'horde.success');
 736:         } catch (IMP_Imap_Exception $e) {
 737:             $e->notify(sprintf(_("The mailbox \"%s\" was not deleted. This is what the server said"), $this->display) . ': ' . $e->getMessage());
 738:             return false;
 739:         }
 740: 
 741:         $injector->getInstance('IMP_Imap_Tree')->delete($this->_mbox);
 742:         $this->_onDelete(array($this->_mbox));
 743: 
 744:         return true;
 745:     }
 746: 
 747:     /**
 748:      * Rename this mailbox on the server. The subscription status remains the
 749:      * same.  All subfolders will also be renamed.
 750:      *
 751:      * @param string $new     The new mailbox name (UTF7-IMAP).
 752:      * @param boolean $force  Rename mailbox even if it is fixed?
 753:      *
 754:      * @return boolean  True on success
 755:      */
 756:     public function rename($new_name, $force = false)
 757:     {
 758:         global $injector, $notification;
 759: 
 760:         /* Don't try to rename to an empty string. */
 761:         if (!strlen($new_name)) {
 762:             return false;
 763:         }
 764: 
 765:         if ((!$force && $this->fixed) || !$this->access_deletembox) {
 766:             $notification->push(sprintf(_("The mailbox \"%s\" may not be renamed."), $this->display), 'horde.error');
 767:             return false;
 768:         }
 769: 
 770:         $new_mbox = $this->get($new_name);
 771:         $old_list = $this->subfolders;
 772: 
 773:         try {
 774:             $injector->getInstance('IMP_Factory_Imap')->create()->renameMailbox($this->_mbox, strval($new_mbox));
 775:         } catch (IMP_Imap_Exception $e) {
 776:             $e->notify(sprintf(_("Renaming \"%s\" to \"%s\" failed. This is what the server said"), $this->display, $new_mbox->display) . ': ' . $e->getMessage());
 777:             return false;
 778:         }
 779: 
 780:         $notification->push(sprintf(_("The mailbox \"%s\" was successfully renamed to \"%s\"."), $this->display, $new_mbox->display), 'horde.success');
 781: 
 782:         $injector->getInstance('IMP_Imap_Tree')->rename($this->_mbox, strval($new_mbox));
 783:         $this->_onDelete($old_list);
 784: 
 785:         return true;
 786:     }
 787: 
 788:     /**
 789:      * Subscribe/unsubscribe to an IMAP mailbox.
 790:      *
 791:      * @param boolean $sub  True to subscribe, false to unsubscribe.
 792: 
 793:      * @return boolean  True on success.
 794:      */
 795:     public function subscribe($sub)
 796:     {
 797:         global $injector, $notification;
 798: 
 799:         if (!$sub && $this->inbox) {
 800:             $notification->push(sprintf(_("You cannot unsubscribe from \"%s\"."), $this->display), 'horde.error');
 801:             return false;
 802:         }
 803: 
 804:         try {
 805:             $injector->getInstance('IMP_Factory_Imap')->create()->subscribeMailbox($this->_mbox, $sub);
 806:         } catch (IMP_Imap_Exception $e) {
 807:             if ($sub) {
 808:                 $e->notify(sprintf(_("You were not subscribed to \"%s\". Here is what the server said"), $this->display) . ': ' . $e->getMessage());
 809:             } else {
 810:                 $e->notify(sprintf(_("You were not unsubscribed from \"%s\". Here is what the server said"), $this->display) . ': ' . $e->getMessage());
 811:             }
 812:             return false;
 813:         }
 814: 
 815:         if ($sub) {
 816:             $notification->push(sprintf(_("You were successfully subscribed to \"%s\"."), $this->display), 'horde.success');
 817:             $injector->getInstance('IMP_Imap_Tree')->subscribe($this->_mbox);
 818:         } else {
 819:             $notification->push(sprintf(_("You were successfully unsubscribed from \"%s\"."), $this->display), 'horde.success');
 820:             $injector->getInstance('IMP_Imap_Tree')->unsubscribe($this->_mbox);
 821:         }
 822: 
 823:         return true;
 824:     }
 825: 
 826:     /**
 827:      * Runs filters on this mailbox.
 828:      */
 829:     public function filter()
 830:     {
 831:         if (!$this->search) {
 832:             $GLOBALS['injector']->getInstance('IMP_Filter')->filter($this);
 833:         }
 834:     }
 835: 
 836:     /**
 837:      * Filters this mailbox if it is the INBOX and the filter on display pref
 838:      * is active.
 839:      *
 840:      * @return boolean  True if filter() was called.
 841:      */
 842:     public function filterOnDisplay()
 843:     {
 844:         if ($this->inbox &&
 845:             $GLOBALS['prefs']->getValue('filter_on_display')) {
 846:             $this->filter();
 847:             return true;
 848:         }
 849: 
 850:         return false;
 851:     }
 852: 
 853:     /**
 854:      * Return the mailbox list object.
 855:      *
 856:      * @param IMP_Indices $indices  See IMP_Factory_MailboxList::__construct().
 857:      *
 858:      * @return IMP_Mailbox_List  See IMP_Factory_MailboxList::__construct().
 859:      */
 860:     public function getListOb($indices = null)
 861:     {
 862:         return $GLOBALS['injector']->getInstance('IMP_Factory_MailboxList')->create($this, $indices);
 863:     }
 864: 
 865:     /**
 866:      * Return the search query object for this mailbox.
 867:      *
 868:      * @return IMP_Search_Query  The search query object.
 869:      */
 870:     public function getSearchOb()
 871:     {
 872:         $imp_search = $GLOBALS['injector']->getInstance('IMP_Search');
 873:         return $imp_search[$this->_mbox];
 874:     }
 875: 
 876:     /**
 877:      * Return an indices object for this mailbox.
 878:      *
 879:      * @param mixed $in  Either a single UID, array of UIDs, or a
 880:      *                   Horde_Imap_Client_Ids object.
 881:      *
 882:      * @return IMP_Indices  An indices object.
 883:      */
 884:     public function getIndicesOb($in)
 885:     {
 886:         return new IMP_Indices($this, $in);
 887:     }
 888: 
 889:     /**
 890:      * Return the sorting preference for this mailbox.
 891:      *
 892:      * @param boolean $convert  Convert 'by' to a Horde_Imap_Client constant?
 893:      *
 894:      * @return array  An array with the following keys:
 895:      *   - by: (integer) Sort type.
 896:      *   - dir:(integer) Sort direction.
 897:      *   - locked: (boolean) Is sort locked for the mailbox?
 898:      */
 899:     public function getSort($convert = false)
 900:     {
 901:         global $prefs;
 902: 
 903:         $prefmbox = $this->search
 904:             ? $this->_mbox
 905:             : $this->pref_from;
 906: 
 907:         $sortpref = @unserialize($prefs->getValue('sortpref'));
 908:         $entry = isset($sortpref[$prefmbox])
 909:             ? $sortpref[$prefmbox]
 910:             : array();
 911: 
 912:         if (!isset($entry['b'])) {
 913:             $sortby = $prefs->getValue('sortby');
 914:         }
 915: 
 916:         $ob = array(
 917:             'by' => isset($entry['b']) ? $entry['b'] : $sortby,
 918:             'dir' => isset($entry['d']) ? $entry['d'] : $prefs->getValue('sortdir'),
 919:             'locked' => $prefs->isLocked('sortpref')
 920:         );
 921: 
 922:         /* Restrict to sequence sorting only. */
 923:         if (!$this->access_sort) {
 924:             $ob['by'] = Horde_Imap_Client::SORT_SEQUENCE;
 925:             return $ob;
 926:         }
 927: 
 928:         switch ($ob['by']) {
 929:         case Horde_Imap_Client::SORT_THREAD:
 930:             /* Can't do threaded searches in search mailboxes. */
 931:             if (!$this->access_sortthread) {
 932:                 $ob['by'] = IMP::IMAP_SORT_DATE;
 933:             }
 934:             break;
 935: 
 936:         case Horde_Imap_Client::SORT_FROM:
 937:             /* If the preference is to sort by From Address, when we are
 938:              * in the Drafts or Sent folders, sort by To Address. */
 939:             if ($this->special_outgoing) {
 940:                 $ob['by'] = Horde_Imap_Client::SORT_TO;
 941:             }
 942:             break;
 943: 
 944:         case Horde_Imap_Client::SORT_TO:
 945:             if (!$this->special_outgoing) {
 946:                 $ob['by'] = Horde_Imap_Client::SORT_FROM;
 947:             }
 948:             break;
 949:         }
 950: 
 951:         if ($convert && ($ob['by'] == IMP::IMAP_SORT_DATE)) {
 952:             $ob['by'] = $prefs->getValue('sortdate');
 953:         }
 954: 
 955:         /* Sanity check: make sure we have some sort of sort value. */
 956:         if (!$ob['by']) {
 957:             $ob['by'] = Horde_Imap_Client::SORT_ARRIVAL;
 958:         }
 959: 
 960:         return $ob;
 961:     }
 962: 
 963:     /**
 964:      * Set the sorting preference for this mailbox.
 965:      *
 966:      * @param integer $by      The sort type.
 967:      * @param integer $dir     The sort direction.
 968:      * @param boolean $delete  Delete the entry?
 969:      */
 970:     public function setSort($by = null, $dir = null, $delete = false)
 971:     {
 972:         global $injector, $prefs;
 973: 
 974:         $entry = array();
 975:         $sortpref = @unserialize($prefs->getValue('sortpref'));
 976: 
 977:         $prefmbox = $this->search
 978:             ? $this->_mbox
 979:             : $this->pref_from;
 980: 
 981:         if ($delete) {
 982:             unset($sortpref[$prefmbox]);
 983:         } else {
 984:             if (!is_null($by)) {
 985:                 $entry['b'] = $by;
 986:             }
 987:             if (!is_null($dir)) {
 988:                 $entry['d'] = $dir;
 989:             }
 990: 
 991:             if (!empty($entry)) {
 992:                 // TODO: convert using pref_to?
 993:                 $sortpref[$prefmbox] = isset($sortpref[$prefmbox])
 994:                     ? array_merge($sortpref[$prefmbox], $entry)
 995:                     : $entry;
 996:             }
 997:         }
 998: 
 999:         if ($delete || !empty($entry)) {
1000:             $prefs->setValue('sortpref', serialize($sortpref));
1001:         }
1002:     }
1003: 
1004:     /**
1005:      * Are deleted messages hidden in this mailbox?
1006:      *
1007:      * @param boolean $deleted  Return value is what should be done with
1008:      *                          deleted messages in general, as opposed to any
1009:      *                          deleted message in the mailbox.
1010:      *
1011:      * @return boolean  True if deleted messages should be hidden.
1012:      */
1013:     public function hideDeletedMsgs($deleted = false)
1014:     {
1015:         global $injector, $prefs;
1016: 
1017:         $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
1018:         if (!$imp_imap->access(IMP_Imap::ACCESS_FLAGS)) {
1019:             return $imp_imap->imap;
1020:         }
1021: 
1022:         $delhide = isset(self::$_temp[self::CACHE_HIDEDELETED])
1023:             ? self::$_temp[self::CACHE_HIDEDELETED]
1024:             : null;
1025: 
1026:         if (is_null($delhide)) {
1027:             if ($prefs->getValue('use_trash')) {
1028:                 /* If using Virtual Trash, only show deleted messages in
1029:                  * the Virtual Trash mailbox. */
1030:                 $delhide = $this->get($prefs->getValue('trash_folder'))->vtrash
1031:                     ? !$this->vtrash
1032:                     : $prefs->getValue('delhide_trash') ? true : $deleted;
1033:             } else {
1034:                 $delhide = $prefs->getValue('delhide');
1035:             }
1036: 
1037:             /* Even if delhide is true, need to not hide if we are doing
1038:              * thread sort. */
1039:             if ($delhide) {
1040:                 $sortpref = $this->getSort();
1041:                 $delhide = ($sortpref['by'] != Horde_Imap_Client::SORT_THREAD);
1042:             }
1043:         }
1044: 
1045:         if (!$deleted) {
1046:             self::$_temp[self::CACHE_HIDEDELETED] = $delhide;
1047:         }
1048: 
1049:         return $delhide;
1050:     }
1051: 
1052:     /**
1053:      * Sets the 'delhide' preference and clears necessary cached data.
1054:      *
1055:      * @param boolean $value  The value to set 'delhide' to.
1056:      */
1057:     public function setHideDeletedMsgs($value)
1058:     {
1059:         $GLOBALS['prefs']->setValue('delhide', $value);
1060:         $this->expire(IMP_Mailbox::CACHE_HIDEDELETED);
1061:         $GLOBALS['injector']->getInstance('IMP_Factory_MailboxList')->expireAll();
1062:     }
1063: 
1064:     /**
1065:      * Run a search query on this mailbox that is not stored in the current
1066:      * session. Allows custom queries with custom sorts to be used without
1067:      * affecting cached mailboxes.
1068:      *
1069:      * @param Horde_Imap_Client_Search_Query $query  The search query object.
1070:      * @param integer $sortby                        The sort criteria.
1071:      * @param integer $sortdir                       The sort directory.
1072:      *
1073:      * @return IMP_Indices  An indices object.
1074:      */
1075:     public function runSearchQuery(Horde_Imap_Client_Search_Query $query,
1076:                                    $sortby = null, $sortdir = null)
1077:     {
1078:         try {
1079:             $results = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->search($this, $query, array(
1080:                 'sort' => is_null($sortby) ? null : array($sortby)
1081:             ));
1082:             if ($sortdir) {
1083:                 $results['match']->reverse();
1084:             }
1085:             return $this->getIndicesOb($results['match']);
1086:         } catch (IMP_Imap_Exception $e) {
1087:             return new IMP_Indices();
1088:         }
1089:     }
1090: 
1091:     /**
1092:      * Expire cache entries.
1093:      *
1094:      * @param mixed $entries  A CACHE_* constant (or array of constants). If
1095:      *                        null, clears the entire cache.
1096:      */
1097:     public function expire($entries = null)
1098:     {
1099:         if (is_null($entries)) {
1100:             $changed = true;
1101:             $this->cache = array();
1102:         } else {
1103:             $changed = false;
1104: 
1105:             if (!is_array($entries)) {
1106:                 $entries = array($entries);
1107:             }
1108: 
1109:             foreach ($entries as $val) {
1110:                 $changed = isset($this->cache[$val]);
1111:                 unset($this->cache[$val], self::$_temp[$val]);
1112:             }
1113:         }
1114: 
1115:         if ($changed) {
1116:             $this->changed = empty($this->cache)
1117:                 ? self::CHANGED_DELETE
1118:                 : self::CHANGED_YES;
1119:         }
1120:     }
1121: 
1122:     /**
1123:      * Generate a URL using the current mailbox.
1124:      *
1125:      * @param string|Horde_Url $page  Page name to link to.
1126:      * @param string $uid             The UID to use on the linked page.
1127:      * @param string $tmailbox        The mailbox associated with $uid.
1128:      * @param boolean $encode         Encode the argument separator?
1129:      *
1130:      * @return Horde_Url  URL to $page with any necessary mailbox information
1131:      *                    added to the parameter list of the URL.
1132:      */
1133:     public function url($page, $uid = null, $tmailbox = null, $encode = true)
1134:     {
1135:         if ($page instanceof Horde_Url) {
1136:             $url = clone $page;
1137:         } else {
1138:             if (($page != 'search.php') && (IMP::getViewMode() == 'dimp')) {
1139:                 $anchor = is_null($uid)
1140:                     ? ('mbox:' . $this->form_to)
1141:                     : ('msg:' . $this->getIndicesOb($uid)->formTo());
1142:                 return Horde::url('index.php')->setAnchor($anchor);
1143:             }
1144: 
1145:             $url = Horde::url($page);
1146:         }
1147: 
1148:         return $url->add($this->urlParams($uid, $tmailbox))->setRaw(!$encode);
1149:     }
1150: 
1151:     /**
1152:      * Returns list of URL parameters necessary to indicate current mailbox
1153:      * status.
1154:      *
1155:      * @param string $uid       The UID to use on the linked page.
1156:      * @param string $tmailbox  The mailbox associated with $uid to use on
1157:      *                          the linked page.
1158:      *
1159:      * @return array  The list of parameters needed to indicate the current
1160:      *                mailbox status.
1161:      */
1162:     public function urlParams($uid = null, $tmailbox = null)
1163:     {
1164:         $params = array('mailbox' => $this->form_to);
1165:         if (!is_null($uid)) {
1166:             $params['uid'] = $uid;
1167:             if (!is_null($tmailbox) && ($this->_mbox != $tmailbox)) {
1168:                 $params['thismailbox'] = IMP_Mailbox::get($tmailbox)->form_to;
1169:             }
1170:         }
1171:         return $params;
1172:     }
1173: 
1174:     /**
1175:      * Determines if this mailbox is equal to the given mailbox.
1176:      * Needed because directly comparing two mailbox objects may fail (the
1177:      * member variables may be different).
1178:      *
1179:      * @param mixed $mbox  The mailbox to compare to.
1180:      *
1181:      * @return boolean  True if the mailboxes are the same.
1182:      */
1183:     public function equals($mbox)
1184:     {
1185:         return ($mbox == $this->_mbox);
1186:     }
1187: 
1188:     /**
1189:      * Imports messages from a mbox (see RFC 4155) -or- a message source
1190:      * (eml) file.
1191:      *
1192:      * @param string $fname  Filename containing the message data.
1193:      * @param string $type   The MIME type of the message data.
1194:      *
1195:      * @return mixed  False (boolean) on fail or the number of messages
1196:      *                imported (integer) on success.
1197:      * @throws IMP_Exception
1198:      */
1199:     public function importMbox($fname, $type)
1200:     {
1201:         $fd = $format = $msg = null;
1202: 
1203:         if (!file_exists($fname)) {
1204:             return false;
1205:         }
1206: 
1207:         switch ($type) {
1208:         case 'application/gzip':
1209:         case 'application/x-gzip':
1210:         case 'application/x-gzip-compressed':
1211:             // No need to default to Horde_Compress because it uses zlib
1212:             // also.
1213:             if (in_array('compress.zlib', stream_get_wrappers())) {
1214:                 $fname = 'compress.zlib://' . $fname;
1215:             }
1216:             break;
1217: 
1218:         case 'application/x-bzip2':
1219:         case 'application/x-bzip':
1220:             if (in_array('compress.bzip2', stream_get_wrappers())) {
1221:                 $fname = 'compress.bzip2://' . $fname;
1222:             }
1223:             break;
1224: 
1225:         case 'application/zip':
1226:         case 'application/x-compressed':
1227:         case 'application/x-zip-compressed':
1228:             if (in_array('zip', stream_get_wrappers())) {
1229:                 $fname = 'zip://' . $fname;
1230:             } else {
1231:                 try {
1232:                     $zip = Horde_Compress::factory('Zip');
1233:                     if ($zip->canDecompress) {
1234:                         $file_data = file_get_contents($fname);
1235: 
1236:                         $zip_info = $zip->decompress($file_data, array(
1237:                             'action' => Horde_Compress_Zip::ZIP_LIST
1238:                         ));
1239: 
1240:                         if (!empty($zip_info)) {
1241:                             $fd = fopen('php://temp', 'r+');
1242: 
1243:                             foreach (array_keys($zip_info) as $key) {
1244:                                 fwrite($fd, $zip->decompress($file_data, array(
1245:                                     'action' => Horde_Compress_Zip::ZIP_DATA,
1246:                                     'info' => $zip_info,
1247:                                     'key' => $key
1248:                                 )));
1249:                             }
1250: 
1251:                             rewind($fd);
1252:                         }
1253:                     }
1254:                 } catch (Horde_Compress_Exception $e) {
1255:                     if ($fd) {
1256:                         fclose($fd);
1257:                         $fd = null;
1258:                     }
1259:                 }
1260: 
1261:                 $fname = null;
1262:             }
1263:             break;
1264:         }
1265: 
1266:         if (!is_null($fname)) {
1267:             $fd = fopen($fname, 'r');
1268:         }
1269: 
1270:         if (!$fd) {
1271:             throw new IMP_Exception(_("The uploaded file cannot be opened"));
1272:         }
1273: 
1274:         $this->_import = array(
1275:             'data' => array(),
1276:             'msgs' => 0,
1277:             'size' => 0
1278:         );
1279: 
1280:         while (!feof($fd)) {
1281:             $line = fgets($fd);
1282: 
1283:             /* RFC 4155 - mbox format. */
1284:             // TODO: Better preg for matching From line
1285:             // See(?) http://code.iamcal.com/php/rfc822/
1286:             if ((!$format || ($format == 'mbox')) &&
1287:                 preg_match('/^From (.+@.+|- )/', $line)) {
1288:                 $format = 'mbox';
1289: 
1290:                 if ($msg) {
1291:                     /* Send in chunks to take advantage of MULTIAPPEND (if
1292:                      * available). */
1293:                     $this->_importMbox($msg, true);
1294:                 }
1295: 
1296:                 $msg = fopen('php://temp', 'r+');
1297:             } elseif ($msg) {
1298:                 fwrite($msg, $line);
1299:             } elseif (!$format && trim($line)) {
1300:                 /* Allow blank space at beginning of file. Anything else is
1301:                  * treated as message input. */
1302:                 $format = 'eml';
1303:                 $msg = fopen('php://temp', 'r+');
1304:                 fwrite($msg, $line);
1305:             }
1306:         }
1307:         fclose($fd);
1308: 
1309:         if ($msg) {
1310:             $this->_importMbox($msg);
1311:         }
1312: 
1313:         return $this->_import['msgs']
1314:             ? $this->_import['msgs']
1315:             : false;
1316:     }
1317: 
1318:     /**
1319:      * Helper for importMbox().
1320:      *
1321:      * @param resource $msg    Stream containing message data.
1322:      * @param integer $buffer  Buffer messages before sending?
1323:      */
1324:     protected function _importMbox($msg, $buffer = false)
1325:     {
1326:         $this->_import['data'][] = array('data' => $msg);
1327:         $this->_import['size'] += intval(ftell($msg));
1328: 
1329:         /* Buffer 5 MB of messages before sending. */
1330:         if ($buffer && ($this->_import['size'] < 5242880)) {
1331:             return;
1332:         }
1333: 
1334:         try {
1335:             $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->append($this->_mbox, $this->_import['data']);
1336:             $this->_import['msgs'] += count($this->_import['data']);
1337:         } catch (IMP_Imap_Exception $e) {}
1338: 
1339:         foreach ($this->_import['data'] as $val) {
1340:             fclose($val['data']);
1341:         }
1342: 
1343:         $this->_import['data'] = array();
1344:         $this->_import['size'] = 0;
1345:     }
1346: 
1347:     /* Static methods. */
1348: 
1349:     /**
1350:      * Converts a mailbox string from a form representation.
1351:      * Needed because null characters (used for various internal non-IMAP
1352:      * mailbox representations) will not work in form elements.
1353:      *
1354:      * @param mixed $mbox  The mailbox name(s).
1355:      *
1356:      * @return mixed  The mailbox object(s).
1357:      */
1358:     static public function formFrom($mbox)
1359:     {
1360:         return is_array($mbox)
1361:             ? array_filter(array_map(array(__CLASS__, 'formFrom'), $mbox))
1362:             : self::get(IMP::base64urlDecode($mbox));
1363:     }
1364: 
1365:     /**
1366:      * Converts a mailbox string to a form representation.
1367:      * Needed because null characters (used for various internal non-IMAP
1368:      * mailbox representations) will not work in form elements.
1369:      *
1370:      * @param mixed $mbox  The mailbox name(s).
1371:      *
1372:      * @return mixed  The converted mailbox string(s).
1373:      */
1374:     static public function formTo($mbox)
1375:     {
1376:         return is_array($mbox)
1377:             ? array_filter(array_map(array(__CLASS__, 'formTo'), $mbox))
1378:             : IMP::base64urlEncode($mbox);
1379:     }
1380: 
1381:     /**
1382:      * Return the list of special mailboxes.
1383:      *
1384:      * @return array  A list of folders, with the self::SPECIAL_* constants as
1385:      *                keys and values containing the IMP_Mailbox objects or
1386:      *                null if the mailbox doesn't exist (self::SPECIAL_SENT
1387:      *                contains an array of objects). These mailboxes are
1388:      *                sorted in a logical order (see Ticket #10683).
1389:      */
1390:     static public function getSpecialMailboxes()
1391:     {
1392:         if (!isset(self::$_temp[self::CACHE_SPECIALMBOXES])) {
1393:             self::$_temp[self::CACHE_SPECIALMBOXES] = array(
1394:                 self::SPECIAL_DRAFTS => self::getPref('drafts_folder'),
1395:                 self::SPECIAL_SENT => $GLOBALS['injector']->getInstance('IMP_Identity')->getAllSentmailFolders(),
1396:                 self::SPECIAL_SPAM => self::getPref('spam_folder'),
1397:                 self::SPECIAL_TRASH => $GLOBALS['prefs']->getValue('use_trash') ? self::getPref('trash_folder') : null
1398:             );
1399:         }
1400: 
1401:         return self::$_temp[self::CACHE_SPECIALMBOXES];
1402:     }
1403: 
1404:     /**
1405:      * Converts a mailbox name from a value stored in the preferences.
1406:      *
1407:      * @param string $mbox  The mailbox name as stored in a preference.
1408:      *
1409:      * @return string  The full IMAP mailbox name (UTF7-IMAP).
1410:      */
1411:     static public function prefFrom($mbox)
1412:     {
1413:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
1414:         $def_ns = $imp_imap->defaultNamespace();
1415:         $empty_ns = $imp_imap->getNamespace('');
1416: 
1417:         if (!is_null($empty_ns) &&
1418:             strpos($mbox, $empty_ns['delimiter']) === 0) {
1419:             /* Prefixed with delimiter => from empty namespace. */
1420:             return substr($mbox, strlen($empty_ns['delimiter']));
1421:         } elseif (($ns = $imp_imap->getNamespace($mbox, true)) == null) {
1422:             /* No namespace prefix => from personal namespace. */
1423:             return $def_ns['name'] . $mbox;
1424:         }
1425: 
1426:         return $mbox;
1427:     }
1428: 
1429:     /**
1430:      * Converts a mailbox name to a value to be stored in a preference.
1431:      *
1432:      * @param string $mbox  The full IMAP mailbox name (UTF7-IMAP).
1433:      *
1434:      * @return string  The value to store in a preference.
1435:      */
1436:     static public function prefTo($mbox)
1437:     {
1438:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
1439:         $def_ns = $imp_imap->defaultNamespace();
1440:         $empty_ns = $imp_imap->getNamespace('');
1441: 
1442:         if (($ns = self::get($mbox)->namespace_info) !== null) {
1443:              if ($ns['name'] == $def_ns['name']) {
1444:                  /* From personal namespace => strip namespace. */
1445:                  return substr($mbox, strlen($def_ns['name']));
1446:              } elseif ($ns['name'] == $empty_ns['name']) {
1447:                  /* From empty namespace => prefix with delimiter. */
1448:                  return $empty_ns['delimiter'] . $mbox;
1449:              }
1450:          }
1451: 
1452:         return strval($mbox);
1453:     }
1454: 
1455:     /* Internal methods. */
1456: 
1457:     /**
1458:      * Returns a unique identifier for this mailbox's status.
1459:      *
1460:      * This cache ID is guaranteed to change if messages are added/deleted
1461:      * from the mailbox. Additionally, if CONDSTORE is available on the remote
1462:      * IMAP server, this ID will change if flag information changes.
1463:      *
1464:      * For search mailboxes, this value never changes (search mailboxes must
1465:      * be forcibly refreshed).
1466:      *
1467:      * @param boolean $date  If true, adds date information to ID.
1468:      *
1469:      * @return string  The cache ID string, which will change when the
1470:      *                 composition of this mailbox changes.
1471:      */
1472:     protected function _getCacheID($date = false)
1473:     {
1474:         $date = $date
1475:             ? 'D' . date('mdy')
1476:             : '';
1477: 
1478:         if ($this->search) {
1479:             return '1' . ($date ? '|' . $date : '');
1480:         }
1481: 
1482:         $sortpref = $this->getSort(true);
1483:         $addl = array($sortpref['by'], $sortpref['dir']);
1484:         if ($date) {
1485:             $addl[] = $date;
1486:         }
1487: 
1488:         try {
1489:             return $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->getCacheId($this->_mbox, $addl);
1490:         } catch (IMP_Imap_Exception $e) {
1491:             /* Assume an error means that a mailbox can not be trusted. */
1492:             return strval(new Horde_Support_Randomid());
1493:         }
1494:     }
1495: 
1496:     /**
1497:      * If there is information available to tell us about a prefix in front of
1498:      * mailbox names that shouldn't be displayed to the user, then use it to
1499:      * strip that prefix out. Additionally, translate prefix text if this
1500:      * is a special mailbox.
1501:      *
1502:      * @param boolean $notranslate  Don't translate the mailbox prefix?
1503:      *
1504:      * @return string  The mailbox, with any prefix gone/translated.
1505:      */
1506:     protected function _getDisplay($notranslate = false)
1507:     {
1508:         if (!$notranslate && isset($this->cache[self::CACHE_DISPLAY])) {
1509:             return is_bool($this->cache[self::CACHE_DISPLAY])
1510:                 ? Horde_String::convertCharset($this->_mbox, 'UTF7-IMAP', 'UTF-8')
1511:                 : $this->cache[self::CACHE_DISPLAY];
1512:         }
1513: 
1514:         /* Handle special container mailboxes. */
1515:         switch ($this->_mbox) {
1516:         case IMP_Imap_Tree::OTHER_KEY:
1517:             return _("Other Users");
1518: 
1519:         case IMP_Imap_Tree::SHARED_KEY:
1520:             return _("Shared");
1521: 
1522:         case IMP_Imap_Tree::VFOLDER_KEY:
1523:             return _("Virtual Folders");
1524:         }
1525: 
1526:         $ns_info = $this->namespace_info;
1527:         $out = $this->_mbox;
1528: 
1529:         if (!is_null($ns_info)) {
1530:             /* Return translated namespace information. */
1531:             if (!empty($ns_info['translate']) && $this->namespace) {
1532:                 $d = Horde_String::convertCharset($ns_info['translate'], 'UTF7-IMAP', 'UTF-8');
1533:                 $this->_cache[self::CACHE_DISPLAY] = ($ns_info['translate'] == $this->_mbox)
1534:                     ? true
1535:                     : $d;
1536:                 $this->changed = self::CHANGED_YES;
1537:                 return $d;
1538:             }
1539: 
1540:             /* Strip namespace information. */
1541:             if (!empty($ns_info['name']) &&
1542:                 ($ns_info['type'] == Horde_Imap_Client::NS_PERSONAL) &&
1543:                 (substr($this->_mbox, 0, strlen($ns_info['name'])) == $ns_info['name'])) {
1544:                 $out = substr($this->_mbox, strlen($ns_info['name']));
1545:             }
1546:         }
1547: 
1548:         if ($notranslate) {
1549:             return $out;
1550:         }
1551: 
1552:         /* Substitute any translated prefix text. */
1553:         $sub = array(
1554:             'INBOX' => _("Inbox")
1555:         );
1556: 
1557:         /* Bug #9971: Special mailboxes can be empty IMP_Mailbox objects -
1558:          * catch this with the strlen check below. */
1559:         foreach ($this->getSpecialMailboxes() as $key => $val) {
1560:             switch ($key) {
1561:             case self::SPECIAL_DRAFTS:
1562:                 $sub[strval($val)] = _("Drafts");
1563:                 break;
1564: 
1565:             case self::SPECIAL_SENT:
1566:                 if (count($val) == 1) {
1567:                     $sub[strval(reset($val))] = _("Sent");
1568:                 } else {
1569:                     $sent = self::getPref('sent_mail_folder');
1570:                     foreach ($val as $mbox) {
1571:                         if ($mbox == $sent) {
1572:                             $sub[strval($mbox)] = _("Sent");
1573:                             break;
1574:                         }
1575:                     }
1576:                 }
1577:                 break;
1578: 
1579:             case self::SPECIAL_SPAM:
1580:                 $sub[strval($val)] = _("Spam");
1581:                 break;
1582: 
1583:             case self::SPECIAL_TRASH:
1584:                 $sub[strval($val)] = _("Trash");
1585:                 break;
1586:             }
1587:         }
1588: 
1589:         foreach ($sub as $key => $val) {
1590:             if (strlen($key) &&
1591:                 (($key != 'INBOX') || ($this->_mbox == $out)) &&
1592:                 strpos($this->_mbox, $key) === 0) {
1593:                 $len = strlen($key);
1594:                 if ((strlen($this->_mbox) == $len) || ($this->_mbox[$len] == (is_null($ns_info) ? '' : $ns_info['delimiter']))) {
1595:                     $out = substr_replace($this->_mbox, Horde_String::convertCharset($val, 'UTF-8', 'UTF7-IMAP'), 0, $len);
1596:                     break;
1597:                 }
1598:             }
1599:         }
1600: 
1601:         $d = Horde_String::convertCharset($out, 'UTF7-IMAP', 'UTF-8');
1602:         $this->cache[self::CACHE_DISPLAY] = ($out == $this->_mbox)
1603:             ? true
1604:             : $d;
1605:         $this->changed = self::CHANGED_YES;
1606: 
1607:         return $d;
1608:     }
1609: 
1610:     /**
1611:      * Return icon information.
1612:      *
1613:      * @return object  Object with the following properties:
1614:      * <pre>
1615:      * 'alt'
1616:      * 'class'
1617:      * 'icon'
1618:      * 'iconopen'
1619:      * 'user_icon'
1620:      * </pre>
1621:      */
1622:     protected function _getIcon()
1623:     {
1624:         $info = new stdClass;
1625:         $info->iconopen = null;
1626:         $info->user_icon = false;
1627: 
1628:         if ($this->container) {
1629:             /* We are dealing with folders here. */
1630:             if ($this->is_open) {
1631:                 $info->alt = _("Opened Folder");
1632:                 $info->class = 'folderopenImg';
1633:                 $info->icon = 'folders/open.png';
1634:             } else {
1635:                 $info->alt = _("Folder");
1636:                 $info->class = 'folderImg';
1637:                 $info->icon = 'folders/folder.png';
1638:                 $info->iconopen = Horde_Themes::img('folders/open.png');
1639:             }
1640:         } else {
1641:             $special = $this->getSpecialMailboxes();
1642: 
1643:             switch ($this->_mbox) {
1644:             case 'INBOX':
1645:                 $info->alt = _("Inbox");
1646:                 $info->class = 'inboxImg';
1647:                 $info->icon = 'folders/inbox.png';
1648:                 break;
1649: 
1650:             case $special[self::SPECIAL_DRAFTS]:
1651:                 $info->alt = _("Drafts");
1652:                 $info->class = 'draftsImg';
1653:                 $info->icon = 'folders/drafts.png';
1654:                 break;
1655: 
1656:             case $special[self::SPECIAL_SPAM]:
1657:                 $info->alt = _("Spam");
1658:                 $info->class = 'spamImg';
1659:                 $info->icon = 'folders/spam.png';
1660:                 break;
1661: 
1662:             case $special[self::SPECIAL_TRASH]:
1663:                 $info->alt = _("Trash");
1664:                 $info->class = 'trashImg';
1665:                 $info->icon = 'folders/trash.png';
1666:                 break;
1667: 
1668:             default:
1669:                 if (in_array($this->_mbox, $special[self::SPECIAL_SENT])) {
1670:                     $info->alt = _("Sent");
1671:                     $info->class = 'sentImg';
1672:                     $info->icon = 'folders/sent.png';
1673:                 } else {
1674:                     $info->alt = _("Mailbox");
1675:                     if ($this->is_open) {
1676:                         $info->class = 'folderopenImg';
1677:                         $info->icon = 'folders/open.png';
1678:                     } else {
1679:                         $info->class = 'folderImg';
1680:                         $info->icon = 'folders/folder.png';
1681:                     }
1682:                 }
1683:                 break;
1684:             }
1685: 
1686:             /* Virtual folders. */
1687:             if ($this->vfolder) {
1688:                 $imp_search = $GLOBALS['injector']->getInstance('IMP_Search');
1689:                 if ($imp_search->isVTrash($this->_mbox)) {
1690:                     $info->alt = $imp_search[$this->_mbox]->label;
1691:                     $info->class = 'trashImg';
1692:                     $info->icon = 'folders/trash.png';
1693:                 } elseif ($imp_search->isVinbox($this->_mbox)) {
1694:                     $info->alt = $imp_search[$this->_mbox]->label;
1695:                     $info->class = 'inboxImg';
1696:                     $info->icon = 'folders/inbox.png';
1697:                 }
1698:             }
1699:         }
1700: 
1701:         /* Overwrite the icon information now. */
1702:         if (empty($this->cache[self::CACHE_ICONS]) &&
1703:             self::$_temp[self::CACHE_HASICONHOOK]) {
1704:             if (!isset(self::$_temp[self::CACHE_ICONHOOK])) {
1705:                 self::$_temp[self::CACHE_ICONHOOK] = Horde::callHook('mbox_icons', array(), 'imp');
1706:             }
1707: 
1708:             if (isset(self::$_temp[self::CACHE_ICONHOOK][$this->_mbox])) {
1709:                 $this->cache[self::CACHE_ICONS] = self::$_temp[self::CACHE_ICONHOOK][$this->_mbox];
1710:                 $this->changed = self::CHANGED_YES;
1711:             }
1712:         }
1713: 
1714:         if (!empty($this->cache[self::CACHE_ICONS])) {
1715:             $mi = $this->cache[self::CACHE_ICONS];
1716: 
1717:             if (isset($mi['alt'])) {
1718:                 $info->alt = $mi['alt'];
1719:             }
1720:             $info->icon = strval($mi['icon']);
1721:             $info->user_icon = true;
1722:         } elseif ($info->icon) {
1723:             $info->icon = Horde_Themes::img($info->icon);
1724:         }
1725: 
1726:         return $info;
1727:     }
1728: 
1729:     /**
1730:      * Do the necessary cleanup/cache updates when deleting mailboxes.
1731:      *
1732:      * @param array $deleted  The list of deleted mailboxes.
1733:      */
1734:     protected function _onDelete($deleted)
1735:     {
1736:         /* Clear the mailbox from the sort prefs. */
1737:         foreach ($this->get($deleted) as $val) {
1738:             $val->setSort(null, null, true);
1739:         }
1740:     }
1741: 
1742:     /* Serializable methods. */
1743: 
1744:     /**
1745:      */
1746:     public function serialize()
1747:     {
1748:         return json_encode(array(
1749:             $this->_mbox,
1750:             $this->cache
1751:         ));
1752:     }
1753: 
1754:     /**
1755:      */
1756:     public function unserialize($data)
1757:     {
1758:         list(
1759:             $this->_mbox,
1760:             $this->cache
1761:         ) = json_decode($data, true);
1762:     }
1763: 
1764: }
1765: 
API documentation generated by ApiGen