Overview

Packages

  • IMP

Classes

  • IMP
  • IMP_Ajax_Addresses
  • IMP_Ajax_Application
  • IMP_Ajax_Application_Compose
  • IMP_Ajax_Application_Handler_Common
  • IMP_Ajax_Application_Handler_ComposeAttach
  • IMP_Ajax_Application_Handler_Draft
  • IMP_Ajax_Application_Handler_Dynamic
  • IMP_Ajax_Application_Handler_ImageUnblock
  • IMP_Ajax_Application_Handler_Mboxtoggle
  • IMP_Ajax_Application_Handler_Passphrase
  • IMP_Ajax_Application_Handler_Remote
  • IMP_Ajax_Application_Handler_RemotePrefs
  • IMP_Ajax_Application_Handler_Search
  • IMP_Ajax_Application_Handler_Smartmobile
  • IMP_Ajax_Application_ListMessages
  • IMP_Ajax_Application_ShowMessage
  • IMP_Ajax_Application_Viewport
  • IMP_Ajax_Application_Viewport_Error
  • IMP_Ajax_Imple_ImportEncryptKey
  • IMP_Ajax_Imple_ItipRequest
  • IMP_Ajax_Imple_PassphraseDialog
  • IMP_Ajax_Imple_VcardImport
  • IMP_Ajax_Queue
  • IMP_Api
  • IMP_Application
  • IMP_Auth
  • IMP_Basic_Base
  • IMP_Basic_Compose
  • IMP_Basic_Contacts
  • IMP_Basic_Error
  • IMP_Basic_Folders
  • IMP_Basic_Listinfo
  • IMP_Basic_Mailbox
  • IMP_Basic_Message
  • IMP_Basic_Pgp
  • IMP_Basic_Saveimage
  • IMP_Basic_Search
  • IMP_Basic_Searchbasic
  • IMP_Basic_Smime
  • IMP_Basic_Thread
  • IMP_Block_Newmail
  • IMP_Block_Summary
  • IMP_Compose
  • IMP_Compose_Attachment
  • IMP_Compose_Attachment_Linked_Metadata
  • IMP_Compose_Attachment_Metadata
  • IMP_Compose_Attachment_Storage
  • IMP_Compose_Attachment_Storage_AutoDetermine
  • IMP_Compose_Attachment_Storage_Temp
  • IMP_Compose_Attachment_Storage_VfsLinked
  • IMP_Compose_Exception
  • IMP_Compose_Exception_Address
  • IMP_Compose_HtmlSignature
  • IMP_Compose_Link
  • IMP_Compose_LinkedAttachment
  • IMP_Compose_Ui
  • IMP_Compose_View
  • IMP_Contacts
  • IMP_Contacts_Avatar_Addressbook
  • IMP_Contacts_Avatar_Gravatar
  • IMP_Contacts_Avatar_Unknown
  • IMP_Contacts_Flag_Host
  • IMP_Contacts_Image
  • IMP_Contents
  • IMP_Contents_InlineOutput
  • IMP_Contents_View
  • IMP_Crypt_Pgp
  • IMP_Crypt_Smime
  • IMP_Dynamic_AddressList
  • IMP_Dynamic_Base
  • IMP_Dynamic_Compose
  • IMP_Dynamic_Compose_Common
  • IMP_Dynamic_Helper_Base
  • IMP_Dynamic_Mailbox
  • IMP_Dynamic_Message
  • IMP_Exception
  • IMP_Factory_AuthImap
  • IMP_Factory_Compose
  • IMP_Factory_ComposeAtc
  • IMP_Factory_Contacts
  • IMP_Factory_Contents
  • IMP_Factory_Flags
  • IMP_Factory_Ftree
  • IMP_Factory_Identity
  • IMP_Factory_Imap
  • IMP_Factory_Mail
  • IMP_Factory_MailAutoconfig
  • IMP_Factory_Mailbox
  • IMP_Factory_MailboxCache
  • IMP_Factory_MailboxList
  • IMP_Factory_Maillog
  • IMP_Factory_MimeViewer
  • IMP_Factory_Pgp
  • IMP_Factory_PrefsSort
  • IMP_Factory_Quota
  • IMP_Factory_Search
  • IMP_Factory_Sentmail
  • IMP_Factory_Smime
  • IMP_Factory_Spam
  • 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_Ftree
  • IMP_Ftree_Account
  • IMP_Ftree_Account_Imap
  • IMP_Ftree_Account_Inboxonly
  • IMP_Ftree_Account_Remote
  • IMP_Ftree_Account_Vfolder
  • IMP_Ftree_Element
  • IMP_Ftree_Eltdiff
  • IMP_Ftree_Iterator
  • IMP_Ftree_Iterator_Ancestors
  • IMP_Ftree_IteratorFilter
  • IMP_Ftree_IteratorFilter_Children
  • IMP_Ftree_IteratorFilter_Containers
  • IMP_Ftree_IteratorFilter_Expanded
  • IMP_Ftree_IteratorFilter_Invisible
  • IMP_Ftree_IteratorFilter_Mailboxes
  • IMP_Ftree_IteratorFilter_Nonimap
  • IMP_Ftree_IteratorFilter_Polled
  • IMP_Ftree_IteratorFilter_Remote
  • IMP_Ftree_IteratorFilter_Special
  • IMP_Ftree_IteratorFilter_Subscribed
  • IMP_Ftree_IteratorFilter_Vfolder
  • IMP_Ftree_Prefs
  • IMP_Ftree_Prefs_Expanded
  • IMP_Ftree_Prefs_Poll
  • IMP_Ftree_Select
  • IMP_Images
  • IMP_Imap
  • IMP_Imap_Acl
  • IMP_Imap_Cache_Wrapper
  • IMP_Imap_Config
  • IMP_Imap_Exception
  • IMP_Imap_Password
  • IMP_Imap_PermanentFlags
  • IMP_Imap_Remote
  • IMP_Indices
  • IMP_Indices_Mailbox
  • 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_Pop3
  • IMP_Mailbox_List_Thread
  • IMP_Mailbox_List_Virtual
  • IMP_Mailbox_SessionCache
  • IMP_Mailbox_Ui
  • IMP_Maillog
  • IMP_Maillog_Log_Base
  • IMP_Maillog_Log_Forward
  • IMP_Maillog_Log_Mdn
  • IMP_Maillog_Log_Redirect
  • IMP_Maillog_Log_Reply
  • IMP_Maillog_Log_Replyall
  • IMP_Maillog_Log_Replylist
  • IMP_Maillog_Message
  • IMP_Maillog_Storage_Base
  • IMP_Maillog_Storage_Composite
  • IMP_Maillog_Storage_History
  • IMP_Maillog_Storage_Mdnsent
  • IMP_Maillog_Storage_Null
  • IMP_Mbox_Generate
  • IMP_Mbox_Import
  • IMP_Mbox_Size
  • IMP_Message
  • IMP_Message_Date
  • IMP_Message_Ui
  • IMP_Mime_Headers
  • IMP_Mime_Status
  • IMP_Mime_Status_RenderIssue
  • IMP_Mime_Status_RenderIssue_Display
  • 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_Minimal_Base
  • IMP_Minimal_Compose
  • IMP_Minimal_Error
  • IMP_Minimal_Folders
  • IMP_Minimal_Mailbox
  • IMP_Minimal_Message
  • IMP_Minimal_Messagepart
  • IMP_Minimal_Search
  • IMP_Notification_Event_Status
  • IMP_Notification_Handler_Decorator_ImapAlerts
  • IMP_Notification_Handler_Decorator_NewmailNotify
  • IMP_Perms
  • IMP_Prefs_AttribText
  • IMP_Prefs_Identity
  • IMP_Prefs_Sort
  • IMP_Prefs_Sort_FixedDate
  • IMP_Prefs_Sort_None
  • IMP_Prefs_Sort_Sortpref
  • IMP_Prefs_Sort_Sortpref_Locked
  • IMP_Prefs_Special_Acl
  • IMP_Prefs_Special_ComposeTemplates
  • IMP_Prefs_Special_Drafts
  • IMP_Prefs_Special_Encrypt
  • IMP_Prefs_Special_Flag
  • IMP_Prefs_Special_HtmlSignature
  • IMP_Prefs_Special_ImageReplacement
  • IMP_Prefs_Special_InitialPage
  • IMP_Prefs_Special_Mailto
  • IMP_Prefs_Special_NewmailSound
  • IMP_Prefs_Special_PgpPrivateKey
  • IMP_Prefs_Special_PgpPublicKey
  • IMP_Prefs_Special_Remote
  • IMP_Prefs_Special_Searches
  • IMP_Prefs_Special_Sentmail
  • IMP_Prefs_Special_SmimePrivateKey
  • IMP_Prefs_Special_SmimePublicKey
  • IMP_Prefs_Special_Sourceselect
  • IMP_Prefs_Special_Spam
  • IMP_Prefs_Special_SpecialMboxes
  • IMP_Prefs_Special_Trash
  • IMP_Quota
  • IMP_Quota_Hook
  • IMP_Quota_Imap
  • IMP_Quota_Null
  • IMP_Quota_Ui
  • IMP_Remote
  • IMP_Remote_Account
  • IMP_Script_Package_Autocomplete
  • IMP_Script_Package_ComposeBase
  • IMP_Script_Package_DynamicBase
  • IMP_Script_Package_Editor
  • IMP_Script_Package_Imp
  • IMP_Search
  • IMP_Search_Element
  • IMP_Search_Element_Attachment
  • IMP_Search_Element_Autogenerated
  • IMP_Search_Element_Bulk
  • IMP_Search_Element_Contacts
  • IMP_Search_Element_Daterange
  • 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_IteratorFilter
  • IMP_Search_Query
  • IMP_Search_Ui
  • IMP_Search_Vfolder
  • IMP_Search_Vfolder_Builtin
  • IMP_Search_Vfolder_Vinbox
  • IMP_Search_Vfolder_Vtrash
  • IMP_Sentmail
  • IMP_Sentmail_Mongo
  • IMP_Sentmail_Null
  • IMP_Sentmail_Sql
  • IMP_Smartmobile
  • IMP_Spam
  • IMP_Spam_Email
  • IMP_Spam_Null
  • IMP_Spam_Program
  • IMP_Test
  • IMP_Tree_Flist
  • IMP_Tree_Jquerymobile
  • IMP_Tree_Simplehtml
  • IMP_View_Subinfo

Interfaces

  • IMP_Compose_Attachment_Linked
  • IMP_Contacts_Avatar_Backend
  • IMP_Contacts_Flag_Backend
  • IMP_Spam_Base
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Copyright 2002-2014 Horde LLC (http://www.horde.org/)
  4:  *
  5:  * See the enclosed file COPYING for license information (GPL). If you
  6:  * did not receive this file, see http://www.horde.org/licenses/gpl.
  7:  *
  8:  * @category  Horde
  9:  * @copyright 2002-2014 Horde LLC
 10:  * @license   http://www.horde.org/licenses/gpl GPL
 11:  * @package   IMP
 12:  */
 13: 
 14: /**
 15:  * Object handling mailbox searching in IMP.
 16:  *
 17:  * @author    Michael Slusarz <slusarz@horde.org>
 18:  * @category  Horde
 19:  * @copyright 2002-2014 Horde LLC
 20:  * @license   http://www.horde.org/licenses/gpl GPL
 21:  * @package   IMP
 22:  */
 23: class IMP_Search implements ArrayAccess, IteratorAggregate, Serializable
 24: {
 25:     /* The mailbox search prefix. */
 26:     const MBOX_PREFIX = "impsearch\0";
 27: 
 28:     /* The special search mailbox names. */
 29:     const BASIC_SEARCH = 'impbsearch';
 30:     const DIMP_FILTERSEARCH = 'dimpfsearch';
 31:     const DIMP_QUICKSEARCH = 'dimpqsearch';
 32: 
 33:     /* Query creation types. */
 34:     const CREATE_FILTER = 1;
 35:     const CREATE_QUERY = 2;
 36:     const CREATE_VFOLDER = 3;
 37: 
 38:     /**
 39:      * Has the object data changed?
 40:      *
 41:      * @var boolean
 42:      */
 43:     public $changed = false;
 44: 
 45:     /**
 46:      * Search queries.
 47:      *
 48:      * Each subarray contains:
 49:      *   Keys: mailbox IDs.
 50:      *   Values: IMP_Search_Query objects.
 51:      *
 52:      * @var array
 53:      */
 54:     protected $_search = array(
 55:         'filters' => array(),
 56:         'query' => array(),
 57:         'vfolders' => array()
 58:     );
 59: 
 60:     /**
 61:      * Constructor.
 62:      */
 63:     public function __construct()
 64:     {
 65:         $this->init();
 66:     }
 67: 
 68:     /**
 69:      * Initialize session search data.
 70:      */
 71:     public function init()
 72:     {
 73:         $this->_getFilters();
 74:         $this->_getVFolders();
 75:     }
 76: 
 77:     /**
 78:      * Creates the IMAP search query.
 79:      *
 80:      * @param array $criteria  The search criteria array.
 81:      * @param array $opts      Additional options:
 82:      *   - id: (string) Use as the mailbox ID.
 83:      *   - label: (string) The label to use for the search results.
 84:      *   - mboxes: (array) The list of mailboxes to directly search. If this
 85:      *             contains the IMP_Search_Query::ALLSEARCH constant, all
 86:      *             mailboxes will be searched.
 87:      *   - subfolders: (array) The list of mailboxes to do subfolder searches
 88:      *                 on.
 89:      *   - type: (integer) Query type.
 90:      *
 91:      * @return IMP_Search_Query  Returns the query object.
 92:      * @throws InvalidArgumentException
 93:      */
 94:     public function createQuery($criteria, array $opts = array())
 95:     {
 96:         global $injector;
 97: 
 98:         $opts = array_merge(array(
 99:             'id' => null,
100:             'label' => null,
101:             'mboxes' => array(),
102:             'subfolders' => array(),
103:             'type' => self::CREATE_QUERY
104:         ), $opts);
105: 
106:         /* Make sure mailbox names are not IMP_Mailbox objects. */
107:         $opts['mboxes'] = array_map('strval', $opts['mboxes']);
108:         $opts['subfolders'] = array_map('strval', $opts['subfolders']);
109: 
110:         switch ($opts['type']) {
111:         case self::CREATE_FILTER:
112:             $cname = 'IMP_Search_Filter';
113:             break;
114: 
115:         case self::CREATE_QUERY:
116:             $cname = 'IMP_Search_Query';
117:             if (empty($opts['mboxes']) && empty($opts['subfolders'])) {
118:                 throw new InvalidArgumentException('Search query requires at least one mailbox.');
119:             }
120:             break;
121: 
122:         case self::CREATE_VFOLDER:
123:             $cname = 'IMP_Search_Vfolder';
124:             if (empty($opts['mboxes']) && empty($opts['subfolders'])) {
125:                 throw new InvalidArgumentException('Search query requires at least one mailbox.');
126:             }
127:             break;
128:         }
129: 
130:         $ob = new $cname(array_filter(array(
131:             'add' => $criteria,
132:             'all' => in_array(IMP_Search_Query::ALLSEARCH, $opts['mboxes']),
133:             'id' => $this->_strip($opts['id']),
134:             'label' => $opts['label'],
135:             'mboxes' => $opts['mboxes'],
136:             'subfolders' => $opts['subfolders']
137:         )));
138: 
139:         switch ($opts['type']) {
140:         case self::CREATE_FILTER:
141:             /* This will overwrite previous value, if it exists. */
142:             $this->_search['filters'][$ob->id] = $ob;
143:             $this->setFilters($this->_search['filters']);
144:             break;
145: 
146:         case self::CREATE_QUERY:
147:             $this->_search['query'][$ob->id] = $ob;
148:             $ob->mbox_ob->list_ob->rebuild(true);
149:             break;
150: 
151:         case self::CREATE_VFOLDER:
152:             /* This will overwrite previous value, if it exists. */
153:             $this->_search['vfolders'][$ob->id] = $ob;
154:             $this->setVFolders($this->_search['vfolders']);
155:             $injector->getInstance('IMP_Mailbox_SessionCache')->expire(
156:                 array(
157:                     IMP_Mailbox_SessionCache::CACHE_DISPLAY,
158:                     IMP_Mailbox_SessionCache::CACHE_LABEL
159:                 ),
160:                 $ob->mbox_ob
161:             );
162:             $ftree = $injector->getInstance('IMP_Ftree');
163:             $ftree->delete($ob);
164:             $ftree->insert($ob);
165:             break;
166:         }
167: 
168:         /* Reset the sort direction for system queries. */
169:         if ($this->isSystemQuery($ob)) {
170:             $ob->mbox_ob->setSort(null, null, true);
171:         }
172: 
173:         $this->changed = true;
174: 
175:         return $ob;
176:     }
177: 
178:     /**
179:      * Saves the list of filters for the current user.
180:      *
181:      * @param array $filters  The filter list.
182:      */
183:     public function setFilters($filters)
184:     {
185:         $GLOBALS['prefs']->setValue('filter', serialize(array_values($filters)));
186:         $this->_getFilters();
187:     }
188: 
189:     /**
190:      * Loads the list of filters for the current user.
191:      */
192:     protected function _getFilters()
193:     {
194:         $filters = array();
195: 
196:         /* Build list of default filters. */
197:         $di = new DirectoryIterator(IMP_BASE . '/lib/Search/Filter');
198:         foreach ($di as $val) {
199:             if ($val->isFile()) {
200:                 $cname = 'IMP_Search_Filter_' . $val->getBasename('.php');
201:                 if (($cname != 'IMP_Search_Filter_Builtin') &&
202:                     class_exists($cname)) {
203:                     $filter = new $cname();
204:                     $filters[$filter->id] = $filter;
205:                 }
206:             }
207:         }
208: 
209:         if ($f_list = $GLOBALS['prefs']->getValue('filter')) {
210:             $f_list = @unserialize($f_list);
211:             if (is_array($f_list)) {
212:                 foreach ($f_list as $val) {
213:                     if ($val instanceof IMP_Search_Filter) {
214:                         $filters[$val->id] = $val;
215:                     }
216:                 }
217:             }
218:         }
219: 
220:         $this->_search['filters'] = $filters;
221:         $this->changed = true;
222:     }
223: 
224:     /**
225:      * Is a mailbox a filter query?
226:      *
227:      * @param string $id         The mailbox ID.
228:      * @param boolean $editable  Is this an editable (i.e. not built-in)
229:      *                           filter query?
230:      */
231:     public function isFilter($id, $editable = false)
232:     {
233:         return (isset($this->_search['filters'][$this->_strip($id)]) &&
234:                 (!$editable || $this[$id]->canEdit));
235:     }
236: 
237:     /**
238:      * Converts a filter to a search query and stores it in the local
239:      * session.
240:      *
241:      * @param string $id     The mailbox ID of the filter.
242:      * @param array $mboxes  The list of mailboxes to apply the filter on.
243:      * @param string $mid    Use as the mailbox ID.
244:      *
245:      * @return IMP_Search_Query  The created query object.
246:      * @throws InvalidArgumentException
247:      */
248:     public function applyFilter($id, array $mboxes, $mid = null)
249:     {
250:         if (!$this->isFilter($id)) {
251:             throw new InvalidArgumentException('Invalid filter ID given.');
252:         }
253: 
254:         if (!is_null($mid)) {
255:             $mid = $this->_strip($mid);
256:         }
257: 
258:         $q_ob = $this[$id]->toQuery($mboxes, $mid);
259:         $this->_search['query'][$q_ob->id] = $q_ob;
260:         $this->changed = true;
261: 
262:         return $q_ob;
263:     }
264: 
265:     /**
266:      * Saves the list of virtual folders for the current user.
267:      *
268:      * @param array $vfolders  The virtual folder list.
269:      */
270:     public function setVFolders($vfolders)
271:     {
272:         $GLOBALS['prefs']->setValue('vfolder', serialize(array_values($vfolders)));
273:     }
274: 
275:     /**
276:      * Loads the list of virtual folders for the current user.
277:      */
278:     protected function _getVFolders()
279:     {
280:         $vf = array();
281: 
282:         /* Build list of default virtual folders. */
283:         $di = new DirectoryIterator(IMP_BASE . '/lib/Search/Vfolder');
284:         $disable = array('IMP_Search_Vfolder_Vtrash');
285: 
286:         foreach ($di as $val) {
287:             if ($val->isFile()) {
288:                 $cname = 'IMP_Search_Vfolder_' . $val->getBasename('.php');
289:                 if (($cname != 'IMP_Search_Vfolder_Builtin') &&
290:                     class_exists($cname)) {
291:                     $vfolder = new $cname(array(
292:                         'disable' => in_array($cname, $disable)
293:                     ));
294:                     $vf[$vfolder->id] = $vfolder;
295:                 }
296:             }
297:         }
298: 
299:         if ($pref_vf = $GLOBALS['prefs']->getValue('vfolder')) {
300:             $pref_vf = @unserialize($pref_vf);
301:             if (is_array($pref_vf)) {
302:                 foreach ($pref_vf as $val) {
303:                     if ($val instanceof IMP_Search_Vfolder) {
304:                         $vf[$val->id] = $val;
305:                     }
306:                 }
307:             }
308:         }
309: 
310:         $this->_search['vfolders'] = $vf;
311:         $this->changed = true;
312:     }
313: 
314:     /**
315:      * Is a mailbox a virtual folder?
316:      *
317:      * @param string $id         The mailbox ID.
318:      * @param boolean $editable  Is this an editable (i.e. not built-in)
319:      *                           virtual folder?
320:      *
321:      * @return boolean  Whether the mailbox ID is a virtual folder.
322:      */
323:     public function isVFolder($id, $editable = false)
324:     {
325:         return (isset($this->_search['vfolders'][$this->_strip($id)]) &&
326:                 (!$editable || $this[$id]->canEdit));
327:     }
328: 
329:     /**
330:      * Determines whether a mailbox ID is the Virtual Trash Folder.
331:      *
332:      * @param string $id  The mailbox id.
333:      *
334:      * @return boolean  True if the ID is the Virtual Trash folder.
335:      */
336:     public function isVTrash($id)
337:     {
338:         return (($this->isVFolder($id)) &&
339:             ($this[$id] instanceof IMP_Search_Vfolder_Vtrash));
340:     }
341: 
342:     /**
343:      * Determines whether a mailbox ID is the Virtual INBOX Folder.
344:      *
345:      * @param string $id  The mailbox id.
346:      *
347:      * @return boolean  True if the ID is the Virtual INBOX folder.
348:      */
349:     public function isVinbox($id)
350:     {
351:         return (($this->isVFolder($id)) &&
352:             ($this[$id] instanceof IMP_Search_Vfolder_Vinbox));
353:     }
354: 
355:     /**
356:      * Is a mailbox a search query?
357:      *
358:      * @param string $id         The mailbox ID.
359:      * @param boolean $editable  Is this an editable (i.e. not built-in)
360:      *                           search query?
361:      *
362:      * @return boolean  True if a search query.
363:      */
364:     public function isQuery($id, $editable = false)
365:     {
366:         return (isset($this->_search['query'][$this->_strip($id)]) &&
367:                 (!$editable || !$this->isSystemQuery($id)));
368:     }
369: 
370:     /**
371:      * Is a mailbox a system (built-in) search query?
372:      *
373:      * @param string $id  The mailbox ID.
374:      *
375:      * @return boolean  True if a system search query.
376:      */
377:     public function isSystemQuery($id)
378:     {
379:         return (isset($this->_search['query'][$this->_strip($id)]) &&
380:                 in_array($this[$id]->id, array(self::BASIC_SEARCH, self::DIMP_FILTERSEARCH, self::DIMP_QUICKSEARCH)));
381:     }
382: 
383:     /**
384:      * Returns a link to edit a given search query.
385:      *
386:      * @param string $id  The search query id.
387:      *
388:      * @return Horde_Url  The URL to the search page.
389:      */
390:     public function editUrl($id)
391:     {
392:         global $registry;
393: 
394:         $mbox = IMP_Mailbox::get($this->createSearchId($id));
395: 
396:         switch ($registry->getView()) {
397:         case $registry::VIEW_BASIC:
398:             return $mbox->url(IMP_Basic_Search::url())->add(array(
399:                 'edit_query' => 1
400:             ));
401: 
402:         case $registry::VIEW_DYNAMIC:
403:             return IMP_Dynamic_Mailbox::url()->setAnchor(
404:                 'search:' . json_encode(array(
405:                     'edit_query' => 1,
406:                     'mailbox' => $mbox->form_to
407:                 ))
408:             );
409:         }
410:     }
411: 
412:     /**
413:      * Is the given mailbox a search mailbox?
414:      *
415:      * @param string $id  The mailbox name.
416:      *
417:      * @return boolean  Whether the given mailbox name is a search mailbox.
418:      */
419:     public function isSearchMbox($id)
420:     {
421:         return (strpos($id, self::MBOX_PREFIX) === 0);
422:     }
423: 
424:     /**
425:      * Strip the identifying label from a mailbox ID.
426:      *
427:      * @param string $id  The mailbox query ID.
428:      *
429:      * @return string  The virtual folder ID, with any IMP specific
430:      *                 identifying information stripped off.
431:      */
432:     protected function _strip($id)
433:     {
434:         return $this->isSearchMbox($id)
435:             ? substr($id, strlen(self::MBOX_PREFIX))
436:             : strval($id);
437:     }
438: 
439:     /**
440:      * Create the canonical search ID for a given search query.
441:      *
442:      * @param string $id  The mailbox query ID.
443:      *
444:      * @return string  The canonical search query ID.
445:      */
446:     public function createSearchId($id)
447:     {
448:         return self::MBOX_PREFIX . $this->_strip($id);
449:     }
450: 
451:     /* ArrayAccess methods. */
452: 
453:     public function offsetExists($offset)
454:     {
455:         $id = $this->_strip($offset);
456: 
457:         foreach (array_keys($this->_search) as $key) {
458:             if (isset($this->_search[$key][$id])) {
459:                 return true;
460:             }
461:         }
462: 
463:         return false;
464:     }
465: 
466:     public function offsetGet($offset)
467:     {
468:         $id = $this->_strip($offset);
469: 
470:         foreach (array_keys($this->_search) as $key) {
471:             if (isset($this->_search[$key][$id])) {
472:                 return $this->_search[$key][$id];
473:             }
474:         }
475: 
476:         return null;
477:     }
478: 
479:     /**
480:      * Alter the current IMAP search query.
481:      *
482:      * @param string $offset           The search query id.
483:      * @param IMP_Search_Query $value  The query object.
484:      *
485:      * @throws InvalidArgumentException
486:      */
487:     public function offsetSet($offset, $value)
488:     {
489:         if (!($value instanceof IMP_Search_Query)) {
490:             throw new InvalidArgumentException('$value must be a query object.');
491:         }
492: 
493:         $id = $this->_strip($offset);
494: 
495:         foreach (array_keys($this->_search) as $key) {
496:             if (isset($this->_search[$key][$id])) {
497:                 $this->_search[$key][$id] = $value;
498:                 $this->changed = true;
499: 
500:                 if ($key == 'vfolders') {
501:                     $this->setVFolders($this->_search['vfolders']);
502: 
503:                     $ftree = $GLOBALS['injector']->getInstance('IMP_Ftree');
504:                     $ftree->delete($value);
505:                     $ftree->insert($value);
506:                 }
507:                 return;
508:             }
509:         }
510: 
511:         throw new InvalidArgumentException('Creating search queries by array index is not supported. Use createQuery() instead.');
512:     }
513: 
514:     /**
515:      * Deletes an IMAP search query.
516:      *
517:      * @param string $offset  The search query id.
518:      */
519:     public function offsetUnset($offset)
520:     {
521:         $id = $this->_strip($offset);
522: 
523:         foreach (array_keys($this->_search) as $val) {
524:             if (isset($this->_search[$val][$id])) {
525:                 $value = $this->_search[$val][$id];
526:                 unset($this->_search[$val][$id]);
527:                 $this->changed = true;
528: 
529:                 if ($val == 'vfolders') {
530:                     $this->setVFolders($this->_search['vfolders']);
531:                     $GLOBALS['injector']->getInstance('IMP_Ftree')->delete($value);
532:                 }
533:                 break;
534:             }
535:         }
536:     }
537: 
538:     /* IteratorAggregate method. */
539: 
540:     /**
541:      */
542:     public function getIterator()
543:     {
544:         $iterator = new AppendIterator();
545:         foreach ($this->_search as $val) {
546:             $iterator->append(new ArrayIterator($val));
547:         }
548:         return $iterator;
549:     }
550: 
551:     /* Serializable methods. */
552: 
553:     /**
554:      * Serialize.
555:      *
556:      * @return string  Serialized representation of this object.
557:      */
558:     public function serialize()
559:     {
560:         return $GLOBALS['injector']->getInstance('Horde_Pack')->pack(
561:             $this->_search,
562:             array(
563:                 'compression' => false,
564:                 'phpob' => true
565:             )
566:         );
567:     }
568: 
569:     /**
570:      * Unserialize.
571:      *
572:      * @param string $data  Serialized data.
573:      *
574:      * @throws Exception
575:      */
576:     public function unserialize($data)
577:     {
578:         $this->_search = $GLOBALS['injector']->getInstance('Horde_Pack')->unpack($data);
579:     }
580: 
581: }
582: 
API documentation generated by ApiGen