1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
21: class IMP_Message
22: {
23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 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:
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:
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:
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: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 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:
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: 169: 170: 171:
172: $mark_seen = empty($opts['nuke']) &&
173: ($use_vtrash || $prefs->getValue('delete_mark_seen'));
174:
175: if ($use_trash_folder && !$trash->create()) {
176: 177:
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:
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:
226: return false;
227: }
228: }
229: } else {
230: 231:
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:
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:
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: 278:
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: 298: 299: 300: 301: 302: 303: 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: 312: 313: 314: 315: 316: 317: 318: 319: 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:
329: $imp_contents = $GLOBALS['injector']->getInstance('IMP_Factory_Contents')->create($ob->mbox->getIndicesOb($uid));
330:
331:
332: $imp_headers = $imp_contents->getHeader();
333: $subject = $imp_headers->getValue('subject');
334:
335:
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:
344: 345: 346:
347: $body = Horde_String::convertCharset($body, $body_part->getCharset(), 'UTF-8');
348:
349:
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: 357:
358: $vTodo = Horde_Icalendar::newComponent('vtodo', $vCal);
359: $vTodo->setAttribute('SUMMARY', $subject);
360: $vTodo->setAttribute('DESCRIPTION', $body);
361: $vTodo->setAttribute('PRIORITY', '3');
362:
363:
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: 372:
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: 383:
384: $vNote = Horde_Icalendar::newComponent('vnote', $vCal);
385: $vNote->setAttribute('BODY', $subject . "\n". $body);
386:
387:
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: 396:
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: 421:
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:
447: if ($action == 'move') {
448: $this->delete($indices);
449: }
450: }
451:
452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 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:
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:
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:
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: 559:
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: 589:
590: $_SERVER['QUERY_STRING'] = str_replace($uid, $new_uid, $_SERVER['QUERY_STRING']);
591:
592: return $indices_ob;
593: }
594:
595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 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:
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: 645: 646: 647: 648: 649: 650: 651: 652: 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: 671:
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: 685: 686: 687: 688: 689: 690: 691: 692: 693: 694: 695: 696: 697: 698: 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:
728: foreach ($process_list as $val) {
729: 730:
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: 759: 760: 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: 784:
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: 807: 808: 809: 810: 811: 812: 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: