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_Message:: class contains all functions related to handling messages
  4:  * within IMP. Actions such as moving, copying, and deleting messages are
  5:  * handled in here so that code need not be repeated between mailbox, message,
  6:  * and other pages.
  7:  *
  8:  * Copyright 2000-2001 Chris Hyde <chris@jeks.net>
  9:  * Copyright 2000-2012 Horde LLC (http://www.horde.org/)
 10:  *
 11:  * See the enclosed file COPYING for license information (GPL). If you
 12:  * did not receive this file, see http://www.horde.org/licenses/gpl.
 13:  *
 14:  * @author   Chris Hyde <chris@jeks.net>
 15:  * @author   Chuck Hagenbuch <chuck@horde.org>
 16:  * @author   Michael Slusarz <slusarz@horde.org>
 17:  * @category Horde
 18:  * @license  http://www.horde.org/licenses/gpl GPL
 19:  * @package  IMP
 20:  */
 21: class IMP_Message
 22: {
 23:     /**
 24:      * Copies or moves a list of messages to a new mailbox.
 25:      * Handles search and Trash mailboxes.
 26:      * Also handles moves to the tasklist and/or notepad applications.
 27:      *
 28:      * @param string $targetMbox    The mailbox to move/copy messages to
 29:      *                              (UTF7-IMAP).
 30:      * @param string $action        Either 'copy' or 'move'.
 31:      * @param IMP_Indices $indices  An indices object.
 32:      * @param array $opts           Additional options:
 33:      *   - create: (boolean) Should the target mailbox be created?
 34:      *             DEFAULT: false
 35:      *   - mailboxob: (IMP_Mailbox_List) Update this mailbox object.
 36:      *                DEFAULT: No update.
 37:      *
 38:      * @return boolean  True if successful, false if not.
 39:      */
 40:     public function copy($targetMbox, $action, IMP_Indices $indices,
 41:                          array $opts = array())
 42:     {
 43:         global $conf, $notification;
 44: 
 45:         if (!count($indices)) {
 46:             return false;
 47:         }
 48: 
 49:         $targetMbox = IMP_Mailbox::get($targetMbox);
 50: 
 51:         /* If the target is a tasklist, handle the move/copy specially. */
 52:         if ($conf['tasklist']['use_tasklist'] &&
 53:             (strpos($targetMbox, IMP::TASKLIST_EDIT) === 0)) {
 54:             $this->_createTasksOrNotes(str_replace(IMP::TASKLIST_EDIT, '', $targetMbox), $action, $indices, 'task');
 55:             return true;
 56:         }
 57: 
 58:         /* If the target is a notepad, handle the move/copy specially. */
 59:         if ($conf['notepad']['use_notepad'] &&
 60:             (strpos($targetMbox, IMP::NOTEPAD_EDIT) === 0)) {
 61:             $this->_createTasksOrNotes(str_replace(IMP::NOTEPAD_EDIT, '', $targetMbox), $action, $indices, 'note');
 62:             return true;
 63:         }
 64: 
 65:         if (!empty($opts['create']) && !$targetMbox->create()) {
 66:             return false;
 67:         }
 68: 
 69:         $imap_move = false;
 70:         $return_value = true;
 71: 
 72:         switch ($action) {
 73:         case 'move':
 74:             $imap_move = true;
 75:             $message = _("There was an error moving messages from \"%s\" to \"%s\". This is what the server said");
 76:             break;
 77: 
 78:         case 'copy':
 79:             $message = _("There was an error copying messages from \"%s\" to \"%s\". This is what the server said");
 80:             break;
 81:         }
 82: 
 83:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
 84: 
 85:         foreach ($indices as $ob) {
 86:             try {
 87:                 if ($targetMbox->readonly) {
 88:                     throw new IMP_Exception(_("The target directory is read-only."));
 89:                 }
 90: 
 91:                 if (($action == 'move') && $ob->mbox->readonly) {
 92:                     throw new IMP_Exception(_("The source directory is read-only."));
 93:                 }
 94: 
 95:                 $ob->mbox->uidvalid;
 96: 
 97:                 /* Attempt to copy/move messages to new mailbox. */
 98:                 $imp_imap->copy($ob->mbox, $targetMbox, array(
 99:                     'ids' => $imp_imap->getIdsOb($ob->uids),
100:                     'move' => $imap_move
101:                 ));
102: 
103:                 if (($action == 'move') &&
104:                     !empty($opts['mailboxob']) &&
105:                     $opts['mailboxob']->isBuilt()) {
106:                     $opts['mailboxob']->removeMsgs($ob->mbox->getIndicesOb($ob->uids));
107:                 }
108:             } catch (Exception $e) {
109:                 $error_msg = sprintf($message, $ob->mbox->display, $targetMbox->display) . ': ' . $e->getMessage();
110:                 if ($e instanceof IMP_Imap_Exception) {
111:                     $e->notify($error_msg);
112:                 } else {
113:                     $GLOBALS['notification']->push($error_msg, 'horde.error');
114:                 }
115:                 $return_value = false;
116:             }
117:         }
118: 
119:         return $return_value;
120:     }
121: 
122:     /**
123:      * Deletes a list of messages taking into account whether or not a
124:      * Trash folder is being used.
125:      * Handles search and Trash mailboxes.
126:      *
127:      * @param IMP_Indices $indices  An indices object.
128:      * @param array $opts           Additional options:
129:      *   - keeplog: (boolean) Should any history information of the message be
130:      *              kept?
131:      *   - mailboxob: (IMP_Mailbox_List) Update this mailbox object.
132:      *                DEFAULT: No update.
133:      *   - nuke: (boolean) Override user preferences and nuke (i.e.
134:      *           permanently delete) the messages instead?
135:      *
136:      * @return integer|boolean  The number of messages deleted if successful,
137:      *                          false if not.
138:      */
139:     public function delete(IMP_Indices $indices, array $opts = array())
140:     {
141:         global $conf, $injector, $notification, $prefs;
142: 
143:         if (!count($indices)) {
144:             return false;
145:         }
146: 
147:         $trash = IMP_Mailbox::getPref('trash_folder');
148:         $use_trash = $prefs->getValue('use_trash');
149:         if ($use_trash && !$trash) {
150:             $notification->push(_("Cannot move messages to Trash - no Trash mailbox set in preferences."), 'horde.error');
151:             return false;
152:         }
153: 
154:         $maillog_update = (empty($opts['keeplog']) && !empty($conf['maillog']['use_maillog']));
155:         $return_value = 0;
156: 
157:         $imp_imap = $injector->getInstance('IMP_Factory_Imap')->create();
158: 
159:         /* Check for Trash folder. */
160:         $no_expunge = $use_trash_folder = $use_vtrash = false;
161:         if ($use_trash &&
162:             empty($opts['nuke']) &&
163:             $imp_imap->access(IMP_Imap::ACCESS_TRASH)) {
164:             $use_vtrash = $trash->vtrash;
165:             $use_trash_folder = !$use_vtrash;
166:         }
167: 
168:         /* Check whether we are marking messages as seen.
169:          * If using virtual trash, we must mark the message as seen or else it
170:          * will appear as an 'unseen' message for purposes of new message
171:          * counts. */
172:         $mark_seen = empty($opts['nuke']) &&
173:                      ($use_vtrash || $prefs->getValue('delete_mark_seen'));
174: 
175:         if ($use_trash_folder && !$trash->create()) {
176:             /* If trash folder could not be created, just mark message as
177:              * deleted. */
178:             $no_expunge = true;
179:             $return_value = $use_trash_folder = false;
180:         }
181: 
182:         foreach ($indices as $ob) {
183:             try {
184:                 if (!$ob->mbox->access_deletemsgs) {
185:                     throw new IMP_Exception(_("This folder is read-only."));
186:                 }
187: 
188:                 $ob->mbox->uidvalid;
189:             } catch (IMP_Exception $e) {
190:                 $notification->push(sprintf(_("There was an error deleting messages from the folder \"%s\"."), $ob->mbox->display) . ' ' . $e->getMessage(), 'horde.error');
191:                 $return_value = false;
192:                 continue;
193:             }
194: 
195:             $imp_indices = $ob->mbox->getIndicesOb($ob->uids);
196:             if ($return_value !== false) {
197:                 $return_value += count($ob->uids);
198:             }
199: 
200:             $ids_ob = $imp_imap->getIdsOb($ob->uids);
201: 
202:             /* Trash is only valid for IMAP mailboxes. */
203:             if ($use_trash_folder && ($ob->mbox != $trash)) {
204:                 if ($ob->mbox->access_expunge) {
205:                     try {
206:                         if ($mark_seen) {
207:                             $imp_imap->store($ob->mbox, array(
208:                                 'add' => array(
209:                                     Horde_Imap_Client::FLAG_SEEN
210:                                 ),
211:                                 'ids' => $ids_ob
212:                             ));
213:                         }
214: 
215:                         $imp_imap->copy($ob->mbox, $trash, array(
216:                             'ids' => $ids_ob,
217:                             'move' => true
218:                         ));
219: 
220:                         if (!empty($opts['mailboxob']) &&
221:                             $opts['mailboxob']->isBuilt()) {
222:                             $opts['mailboxob']->removeMsgs($imp_indices);
223:                         }
224:                     } catch (IMP_Imap_Exception $e) {
225:                         // @todo Check for overquota error.
226:                         return false;
227:                     }
228:                 }
229:             } else {
230:                 /* Get the list of Message-IDs for the deleted messages if
231:                  * using mail logging. */
232:                 $fetch = null;
233:                 if ($maillog_update) {
234:                     $query = new Horde_Imap_Client_Fetch_Query();
235:                     $query->envelope();
236: 
237:                     try {
238:                         $fetch = $imp_imap->fetch($ob->mbox, $query, array(
239:                             'ids' => $ids_ob
240:                         ));
241:                     } catch (IMP_Imap_Exception $e) {}
242:                 }
243: 
244:                 /* Delete the messages. */
245:                 $expunge_now = false;
246:                 $del_flags = array(Horde_Imap_Client::FLAG_DELETED);
247: 
248:                 if (!$use_vtrash &&
249:                     (!$imp_imap->access(IMP_Imap::ACCESS_TRASH) ||
250:                      !empty($opts['nuke']) ||
251:                      ($use_trash && ($ob->mbox == $trash)))) {
252:                     /* Purge messages immediately. */
253:                     $expunge_now = !$no_expunge;
254:                 } elseif ($mark_seen) {
255:                     $del_flags[] = Horde_Imap_Client::FLAG_SEEN;
256:                 }
257: 
258:                 try {
259:                     $imp_imap->store($ob->mbox, array(
260:                         'add' => $del_flags,
261:                         'ids' => $ids_ob
262:                     ));
263:                     if ($expunge_now) {
264:                         $this->expungeMailbox(
265:                             $imp_indices->indices(),
266:                             array(
267:                                 'mailboxob' => empty($opts['mailboxob']) ? null : $opts['mailboxob']
268:                             )
269:                         );
270:                     } elseif (!empty($opts['mailboxob']) &&
271:                               $opts['mailboxob']->isBuilt() &&
272:                               $ob->mbox->hideDeletedMsgs()) {
273:                         $opts['mailboxob']->removeMsgs($imp_indices);
274:                     }
275:                 } catch (IMP_Imap_Exception $e) {}
276: 
277:                 /* Get the list of Message-IDs deleted, and remove the
278:                  * information from the mail log. */
279:                 if (!is_null($fetch)) {
280:                     $msg_ids = array();
281:                     reset($fetch);
282:                     while (list(,$v) = each($fetch)) {
283:                         if ($msg_id = $v->getEnvelope()->message_id) {
284:                             $msg_ids[] = $msg_id;
285:                         }
286:                     }
287: 
288:                     IMP_Maillog::deleteLog($msg_ids);
289:                 }
290:             }
291:         }
292: 
293:         return $return_value;
294:     }
295: 
296:     /**
297:      * Undeletes a list of messages.
298:      * Handles search mailboxes.
299:      * This function works with IMAP only, not POP3.
300:      *
301:      * @param IMP_Indices $indices  An indices object.
302:      *
303:      * @return boolean  True if successful, false if not.
304:      */
305:     public function undelete(IMP_Indices $indices)
306:     {
307:         return $this->flag(array(Horde_Imap_Client::FLAG_DELETED), $indices, false);
308:     }
309: 
310:     /**
311:      * Copies or moves a list of messages to a tasklist or notepad.
312:      * Handles search and Trash mailboxes.
313:      *
314:      * @param string $list          The list in which the task or note will be
315:      *                              created.
316:      * @param string $action        Either 'copy' or 'move'.
317:      * @param IMP_Indices $indices  An indices object.
318:      * @param string $type          The object type to create ('note' or
319:      *                              'task').
320:      */
321:     protected function _createTasksOrNotes($list, $action,
322:                                            IMP_Indices $indices, $type)
323:     {
324:         global $registry, $notification, $prefs;
325: 
326:         foreach ($indices as $ob) {
327:             foreach ($ob->uids as $uid) {
328:                 /* Fetch the message contents. */
329:                 $imp_contents = $GLOBALS['injector']->getInstance('IMP_Factory_Contents')->create($ob->mbox->getIndicesOb($uid));
330: 
331:                 /* Fetch the message headers. */
332:                 $imp_headers = $imp_contents->getHeader();
333:                 $subject = $imp_headers->getValue('subject');
334: 
335:                 /* Re-flow the message for prettier formatting. */
336:                 $body_part = $imp_contents->getMIMEPart($imp_contents->findBody());
337:                 $flowed = new Horde_Text_Flowed($body_part->getContents());
338:                 if ($body_part->getContentTypeParameter('delsp') == 'yes') {
339:                     $flowed->setDelSp(true);
340:                 }
341:                 $body = $flowed->toFlowed(false);
342: 
343:                 /* Convert to current charset */
344:                 /* TODO: When Horde_Icalendar supports setting of charsets
345:                  * we need to set it there instead of relying on the fact
346:                  * that both Nag and IMP use the same charset. */
347:                 $body = Horde_String::convertCharset($body, $body_part->getCharset(), 'UTF-8');
348: 
349:                 /* Create a new iCalendar. */
350:                 $vCal = new Horde_Icalendar();
351:                 $vCal->setAttribute('PRODID', '-//The Horde Project//IMP ' . $GLOBALS['registry']->getVersion() . '//EN');
352:                 $vCal->setAttribute('METHOD', 'PUBLISH');
353: 
354:                 switch ($type) {
355:                 case 'task':
356:                     /* Create a new vTodo object using this message's
357:                      * contents. */
358:                     $vTodo = Horde_Icalendar::newComponent('vtodo', $vCal);
359:                     $vTodo->setAttribute('SUMMARY', $subject);
360:                     $vTodo->setAttribute('DESCRIPTION', $body);
361:                     $vTodo->setAttribute('PRIORITY', '3');
362: 
363:                     /* Get the list of editable tasklists. */
364:                     try {
365:                         $lists = $registry->call('tasks/listTasklists', array(false, Horde_Perms::EDIT));
366:                     } catch (Horde_Exception $e) {
367:                         $lists = null;
368:                         $notification->push($e);
369:                     }
370: 
371:                     /* Attempt to add the new vTodo item to the requested
372:                      * tasklist. */
373:                     try {
374:                         $res = $registry->call('tasks/import', array($vTodo, 'text/calendar', $list));
375:                     } catch (Horde_Exception $e) {
376:                         $res = null;
377:                         $notification->push($e);
378:                     }
379:                     break;
380: 
381:                 case 'note':
382:                     /* Create a new vNote object using this message's
383:                      * contents. */
384:                     $vNote = Horde_Icalendar::newComponent('vnote', $vCal);
385:                     $vNote->setAttribute('BODY', $subject . "\n". $body);
386: 
387:                     /* Get the list of editable notepads. */
388:                     try {
389:                         $lists = $registry->call('notes/listNotepads', array(false, Horde_Perms::EDIT));
390:                     } catch (Horde_Exception $e) {
391:                         $lists = null;
392:                         $notification->push($e);
393:                     }
394: 
395:                     /* Attempt to add the new vNote item to the requested
396:                      * notepad. */
397:                     try {
398:                         $res = $registry->call('notes/import', array($vNote, 'text/x-vnote', $list));
399:                     } catch (Horde_Exception $e) {
400:                         $res = null;
401:                         $notification->push($e);
402:                     }
403:                     break;
404:                 }
405: 
406:                 if (!is_null($res)) {
407:                     if (!$res) {
408:                         switch ($type) {
409:                         case 'task':
410:                             $notification->push(_("An unknown error occured while creating the new task."), 'horde.error');
411:                             break;
412: 
413:                         case 'note':
414:                             $notification->push(_("An unknown error occured while creating the new note."), 'horde.error');
415:                             break;
416:                         }
417:                     } elseif (!is_null($lists)) {
418:                         $name = '"' . htmlspecialchars($subject) . '"';
419: 
420:                         /* Attempt to convert the object name into a
421:                          * hyperlink. */
422:                         try {
423:                             switch ($type) {
424:                             case 'task':
425:                                 $link = $registry->link('tasks/show', array('uid' => $res));
426:                                 break;
427: 
428:                             case 'note':
429:                                 $link = $registry->hasMethod('notes/show')
430:                                     ? $registry->link('notes/show', array('uid' => $res))
431:                                     : false;
432:                                 break;
433:                             }
434: 
435:                             if ($link) {
436:                                 $name = sprintf('<a href="%s">%s</a>', Horde::url($link), $name);
437:                             }
438: 
439:                             $notification->push(sprintf(_("%s was successfully added to \"%s\"."), $name, htmlspecialchars($lists[$list]->get('name'))), 'horde.success', array('content.raw'));
440:                         } catch (Horde_Exception $e) {}
441:                     }
442:                 }
443:             }
444:         }
445: 
446:         /* Delete the original messages if this is a "move" operation. */
447:         if ($action == 'move') {
448:             $this->delete($indices);
449:         }
450:     }
451: 
452:     /**
453:      * Strips one or all MIME parts out of a message.
454:      * Handles search mailboxes.
455:      *
456:      * @param IMP_Indices $indices  An indices object.
457:      * @param string $partid        The MIME ID of the part to strip. All
458:      *                              parts are stripped if null.
459:      * @param array $opts           Additional options:
460:      *   - mailboxob: (IMP_Mailbox_List) Update this mailbox object.
461:      *                DEFAULT: No update.
462:      *
463:      * @return IMP_Indices  Returns the new indices object.
464:      * @throws IMP_Exception
465:      */
466:     public function stripPart(IMP_Indices $indices, $partid = null,
467:                               array $opts = array())
468:     {
469:         list($mbox, $uid) = $indices->getSingle();
470:         if (!$uid) {
471:             return;
472:         }
473: 
474:         if ($mbox->readonly) {
475:             throw new IMP_Exception(_("Cannot strip the MIME part as the mailbox is read-only."));
476:         }
477: 
478:         $uidvalidity = $mbox->uidvalid;
479: 
480:         $contents = $GLOBALS['injector']->getInstance('IMP_Factory_Contents')->create($indices);
481:         $message = $contents->getMIMEMessage();
482:         $boundary = trim($message->getContentTypeParameter('boundary'), '"');
483: 
484:         $url_array = array(
485:             'mailbox' => $mbox,
486:             'uid' => $uid ,
487:             'uidvalidity' => $uidvalidity
488:         );
489: 
490:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
491: 
492:         /* Always add the header to output. */
493:         $parts = array(
494:             array(
495:                 't' => 'url',
496:                 'v' => $imp_imap->getUtils()->createUrl(array_merge($url_array, array('section' => 'HEADER')))
497:             )
498:         );
499: 
500:         for ($id = 1; ; ++$id) {
501:             $part = $message->getPart($id);
502:             if (!$part) {
503:                 break;
504:             }
505: 
506:             $parts[] = array(
507:                 't' => 'text',
508:                 'v' => "\r\n--" . $boundary . "\r\n"
509:             );
510: 
511:             if (($id != 1) && is_null($partid) || ($id == $partid)) {
512:                 $newPart = new Horde_Mime_Part();
513:                 $newPart->setType('text/plain');
514: 
515:                 /* Need to make sure all text is in the correct charset. */
516:                 $newPart->setCharset('UTF-8');
517:                 $newPart->setContents(sprintf(_("[Attachment stripped: Original attachment type: %s, name: %s]"), $part->getType(), $contents->getPartName($part)));
518: 
519:                 $parts[] = array(
520:                     't' => 'text',
521:                     'v' => $newPart->toString(array(
522:                         'canonical' => true,
523:                         'headers' => true,
524:                         'stream' => true
525:                     ))
526:                 );
527:             } else {
528:                 $parts[] = array(
529:                     't' => 'url',
530:                     'v' => $imp_imap->getUtils()->createUrl(array_merge($url_array, array('section' => $id . '.MIME')))
531:                 );
532:                 $parts[] = array(
533:                     't' => 'url',
534:                     'v' => $imp_imap->getUtils()->createUrl(array_merge($url_array, array('section' => $id)))
535:                 );
536:             }
537:         }
538: 
539:         $parts[] = array(
540:             't' => 'text',
541:             'v' => "\r\n--" . $boundary . "--\r\n"
542:         );
543: 
544:         /* Get the headers for the message. */
545:         $query = new Horde_Imap_Client_Fetch_Query();
546:         $query->imapDate();
547:         $query->flags();
548: 
549:         try {
550:             $res = $imp_imap->fetch($mbox, $query, array(
551:                 'ids' => $imp_imap->getIdsOb($uid)
552:             ));
553:             if (!isset($res[$uid])) {
554:                 throw new IMP_Imap_Exception();
555:             }
556:             $flags = $res[$uid]->getFlags();
557: 
558:             /* If in Virtual Inbox, we need to reset flag to unseen so that it
559:              * appears again in the mailbox list. */
560:             if ($mbox->vinbox) {
561:                 $flags = array_values(array_diff($flags, array(Horde_Imap_Client::FLAG_SEEN)));
562:             }
563: 
564:             $new_uid = $imp_imap->append($mbox, array(
565:                 array(
566:                     'data' => $parts,
567:                     'flags' => $flags,
568:                     'internaldate' => $res[$uid]->getImapDate()
569:                 )
570:             ))->ids;
571:             $new_uid = reset($new_uid);
572:         } catch (IMP_Imap_Exception $e) {
573:             throw new IMP_Exception(_("An error occured while attempting to strip the attachment."));
574:         }
575: 
576:         $this->delete($indices, array(
577:             'keeplog' => true,
578:             'mailboxob' => empty($opts['mailboxob']) ? null : $opts['mailboxob'],
579:             'nuke' => true
580:         ));
581: 
582:         $indices_ob = $mbox->getIndicesOb($new_uid);
583: 
584:         if (!empty($opts['mailboxob'])) {
585:             $opts['mailboxob']->setIndex($indices_ob);
586:         }
587: 
588:         /* We need to replace the old index in the query string with the
589:          * new index. */
590:         $_SERVER['QUERY_STRING'] = str_replace($uid, $new_uid, $_SERVER['QUERY_STRING']);
591: 
592:         return $indices_ob;
593:     }
594: 
595:     /**
596:      * Sets or clears a given flag for a list of messages.
597:      * Handles search mailboxes.
598:      * This function works with IMAP only, not POP3.
599:      *
600:      * @param array $flags          The IMAP flag(s) to set or clear.
601:      * @param IMP_Indices $indices  An indices object.
602:      * @param boolean $action       If true, set the flag(s), otherwise clear
603:      *                              the flag(s).
604:      *
605:      * @return boolean  True if successful, false if not.
606:      */
607:     public function flag($flags, IMP_Indices $indices, $action = true)
608:     {
609:         if (!count($indices)) {
610:             return false;
611:         }
612: 
613:         $action_array = $action
614:             ? array('add' => $flags)
615:             : array('remove' => $flags);
616:         $ajax_queue = $GLOBALS['injector']->getInstance('IMP_Ajax_Queue');
617:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
618:         $ret = true;
619: 
620:         foreach ($indices as $ob) {
621:             try {
622:                 if ($ob->mbox->readonly) {
623:                     throw new IMP_Exception(_("This folder is read-only."));
624:                 }
625: 
626:                 $ob->mbox->uidvalid;
627: 
628:                 /* Flag/unflag the messages now. */
629:                 $imp_imap->store($ob->mbox, array_merge($action_array, array(
630:                     'ids' => $imp_imap->getIdsOb($ob->uids)
631:                 )));
632: 
633:                 $ajax_queue->flag(reset($action_array), $action, $ob->mbox->getIndicesOb($ob->uids));
634:             } catch (Exception $e) {
635:                 $GLOBALS['notification']->push(sprintf(_("There was an error flagging messages in the folder \"%s\": %s."), $ob->mbox->display, $e->getMessage()), 'horde.error');
636:                 $ret = false;
637:             }
638:         }
639: 
640:         return $ret;
641:     }
642: 
643:     /**
644:      * Adds or removes flag(s) for all messages in a list of mailboxes.
645:      * This function works with IMAP only, not POP3.
646:      *
647:      * @param array $flags     The IMAP flag(s) to add or remove.
648:      * @param array $mboxes    The list of mailboxes to flag.
649:      * @param boolean $action  If true, add the flag(s), otherwise, remove the
650:      *                         flag(s).
651:      *
652:      * @return boolean  True if successful, false if not.
653:      */
654:     public function flagAllInMailbox($flags, $mboxes, $action = true)
655:     {
656:         if (empty($mboxes) || !is_array($mboxes)) {
657:             return false;
658:         }
659: 
660:         $action_array = $action
661:             ? array('add' => $flags)
662:             : array('remove' => $flags);
663:         $ajax_queue = $GLOBALS['injector']->getInstance('IMP_Ajax_Queue');
664:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
665: 
666:         $ajax_queue->poll($mboxes);
667: 
668:         foreach (IMP_Mailbox::get($mboxes) as $val) {
669:             try {
670:                 /* Grab list of UIDs before flagging, to make sure we
671:                  * determine the exact subset that has been flagged. */
672:                 $mailbox_list = $val->getListOb()->getIndicesOb();
673:                 $imp_imap->store($val, $action_array);
674:                 $ajax_queue->flag(reset($action_array), $action, $mailbox_list);
675:             } catch (IMP_Imap_Exception $e) {
676:                 return false;
677:             }
678:         }
679: 
680:         return true;
681:     }
682: 
683:     /**
684:      * Expunges all deleted messages from the list of mailboxes.
685:      *
686:      * @param array $mbox_list  The list of mailboxes to empty as keys; an
687:      *                          optional array of indices to delete as values.
688:      *                          If the value is not an array, all messages
689:      *                          flagged as deleted in the mailbox will be
690:      *                          deleted.
691:      * @param array $opts       Additional options:
692:      *   - list: (boolean) Return a list of messages expunged.
693:      *           DEFAULT: false
694:      *   - mailboxob: (IMP_Mailbox_List) Update this mailbox object.
695:      *                DEFAULT: No update.
696:      *
697:      * @return IMP_Indices  If 'list' option is true, an indices object
698:      *                      containing the messages that have been expunged.
699:      */
700:     public function expungeMailbox($mbox_list, array $opts = array())
701:     {
702:         $msg_list = !empty($opts['list']);
703: 
704:         if (empty($mbox_list)) {
705:             return $msg_list ? new IMP_Indices() : null;
706:         }
707: 
708:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
709:         $process_list = $update_list = array();
710: 
711:         foreach ($mbox_list as $key => $val) {
712:             $key = IMP_Mailbox::get($key);
713: 
714:             if ($key->access_expunge) {
715:                 $ids = $imp_imap->getIdsOb(is_array($val) ? $val : Horde_Imap_Client_Ids::ALL);
716: 
717:                 if ($key->search) {
718:                     foreach ($key->getSearchOb()->mboxes as $skey) {
719:                         $process_list[] = array($skey, $ids);
720:                     }
721:                 } else {
722:                     $process_list[] = array($key, $ids);
723:                 }
724:             }
725:         }
726: 
727:         // [0] = IMP_Mailbox object, [1] = Horde_Imap_Client_Ids object
728:         foreach ($process_list as $val) {
729:             /* If expunging a particular UID list, need to check
730:              * UIDVALIDITY. */
731:             if (!$val[1]->all) {
732:                 try {
733:                     $val[0]->uidvalid;
734:                 } catch (IMP_Exception $e) {
735:                     continue;
736:                 }
737:             }
738: 
739:             try {
740:                 $update_list[strval($val[0])] = $imp_imap->expunge($val[0], array(
741:                     'ids' => $val[1],
742:                     'list' => $msg_list
743:                 ));
744: 
745:                 if (!empty($opts['mailboxob']) &&
746:                     $opts['mailboxob']->isBuilt()) {
747:                     $opts['mailboxob']->removeMsgs($val[1]->all ? true : $val[0]->getIndicesOb($val[1]));
748:                 }
749:             } catch (IMP_Imap_Exception $e) {}
750:         }
751: 
752:         if ($msg_list) {
753:             return new IMP_Indices($update_list);
754:         }
755:     }
756: 
757:     /**
758:      * Empties an entire mailbox.
759:      *
760:      * @param array $mbox_list  The list of mailboxes to empty.
761:      */
762:     public function emptyMailbox($mbox_list)
763:     {
764:         global $notification, $prefs;
765: 
766:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
767:         $trash_folder = ($prefs->getValue('use_trash'))
768:             ? IMP_Mailbox::getPref('trash_folder')
769:             : null;
770: 
771:         foreach (IMP_Mailbox::get($mbox_list) as $mbox) {
772:             if (!$mbox->access_deletemsgs || !$mbox->access_expunge) {
773:                 $notification->push(sprintf(_("Could not delete messages from %s. This mailbox is read-only."), $mbox->display), 'horde.error');
774:                 continue;
775:             }
776: 
777:             if ($mbox->vtrash) {
778:                 $this->expungeMailbox(array_flip($mbox->getSearchOb()->mboxes));
779:                 $notification->push(_("Emptied all messages from Virtual Trash Folder."), 'horde.success');
780:                 continue;
781:             }
782: 
783:             /* Make sure there is at least 1 message before attempting to
784:                delete. */
785:             try {
786:                 $status = $imp_imap->status($mbox, Horde_Imap_Client::STATUS_MESSAGES);
787:                 if (empty($status['messages'])) {
788:                     $notification->push(sprintf(_("The mailbox %s is already empty."), $mbox->display), 'horde.message');
789:                     continue;
790:                 }
791: 
792:                 if (!$trash_folder || ($trash_folder == $mbox)) {
793:                     $this->flagAllInMailbox(array(Horde_Imap_Client::FLAG_DELETED), array($mbox), true);
794:                     $this->expungeMailbox(array(strval($mbox) => 1));
795:                 } else {
796:                     $ret = $imp_imap->search($mbox);
797:                     $this->delete($mbox->getIndicesOb($ret['match']));
798:                 }
799: 
800:                 $notification->push(sprintf(_("Emptied all messages from %s."), $mbox->display), 'horde.success');
801:             } catch (IMP_Imap_Exception $e) {}
802:         }
803:     }
804: 
805:     /**
806:      * Obtains the size of a mailbox.
807:      *
808:      * @param IMP_Mailbox $mbox   The mailbox to obtain the size of.
809:      * @param boolean $formatted  Whether to return a human readable value.
810:      *
811:      * @return mixed  Either the size of the mailbox (in bytes) or a formatted
812:      *                string with this information.
813:      */
814:     public function sizeMailbox(IMP_Mailbox $mbox, $formatted = true)
815:     {
816:         $query = new Horde_Imap_Client_Fetch_Query();
817:         $query->size();
818: 
819:         try {
820:             $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
821:             $res = $imp_imap->fetch($mbox, $query, array(
822:                 'ids' => $imp_imap->getIdsOb(Horde_Imap_Client_Ids::ALL, true)
823:             ));
824: 
825:             $size = 0;
826:             reset($res);
827:             while (list(,$v) = each($res)) {
828:                 $size += $v->getSize();
829:             }
830:             return ($formatted)
831:                 ? sprintf(_("%.2fMB"), $size / (1024 * 1024))
832:                 : $size;
833:         } catch (IMP_Imap_Exception $e) {
834:             return 0;
835:         }
836:     }
837: 
838: }
839: 
API documentation generated by ApiGen