1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13:
14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
24: class IMP_Contents
25: {
26:
27: const SUMMARY_BYTES = 1;
28: const SUMMARY_SIZE = 2;
29: const SUMMARY_ICON = 4;
30: const SUMMARY_ICON_RAW = 16384;
31: const SUMMARY_DESCRIP = 8;
32: const SUMMARY_DESCRIP_LINK = 16;
33: const SUMMARY_DOWNLOAD = 32;
34: const SUMMARY_DOWNLOAD_ZIP = 64;
35: const SUMMARY_IMAGE_SAVE = 128;
36: const SUMMARY_PRINT = 256;
37: const SUMMARY_PRINT_STUB = 512;
38: const SUMMARY_STRIP = 1024;
39:
40:
41: const RENDER_FULL = 1;
42: const RENDER_INLINE = 2;
43: const RENDER_INLINE_DISP_NO = 4;
44: const RENDER_INFO = 8;
45: const RENDER_INLINE_AUTO = 16;
46: const RENDER_RAW = 32;
47: const RENDER_RAW_FALLBACK = 64;
48:
49:
50: const = 1;
51: const = 2;
52: const = 3;
53:
54: 55: 56: 57: 58:
59: protected $_build = false;
60:
61: 62: 63: 64: 65:
66: protected $_embedded = array();
67:
68: 69: 70: 71: 72:
73: protected ;
74:
75: 76: 77: 78: 79:
80: protected $_indices;
81:
82: 83: 84: 85: 86:
87: protected $_message;
88:
89: 90: 91: 92: 93:
94: protected $_viewcache;
95:
96: 97: 98: 99: 100: 101: 102:
103: public function __construct($in)
104: {
105: if ($in instanceof Horde_Mime_Part) {
106: $this->_message = $in;
107: } else {
108: $this->_indices = $in;
109:
110:
111: $query = new Horde_Imap_Client_Fetch_Query();
112: $query->structure();
113:
114: if (!($ret = $this->_fetchData($query))) {
115: $e = new IMP_Exception(_("Error displaying message: message does not exist on server."));
116: $e->setLogLevel('NOTICE');
117: throw $e;
118: }
119:
120: $this->_message = $ret->getStructure();
121: }
122: }
123:
124: 125: 126: 127: 128:
129: public function __toString()
130: {
131: return strval($this->getIndicesOb());
132: }
133:
134: 135: 136: 137: 138:
139: public function getUid()
140: {
141: list(,$uid) = $this->_indices->getSingle();
142: return $uid;
143: }
144:
145: 146: 147: 148: 149:
150: public function getMailbox()
151: {
152: list($mbox,) = $this->_indices->getSingle();
153: return $mbox;
154: }
155:
156: 157: 158: 159: 160:
161: public function getIndicesOb()
162: {
163: return $this->_indices;
164: }
165:
166: 167: 168: 169: 170: 171: 172: 173: 174: 175:
176: public function getBody($options = array())
177: {
178: if (!$this->_indices) {
179: return $this->_message->toString(array(
180: 'headers' => true,
181: 'stream' => !empty($options['stream'])
182: ));
183: }
184:
185: $query = new Horde_Imap_Client_Fetch_Query();
186: $query->bodytext(array(
187: 'peek' => true
188: ));
189:
190: return ($res = $this->_fetchData($query))
191: ? $res->getBodyText(0, !empty($options['stream']))
192: : '';
193: }
194:
195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216:
217: public function getBodyPart($id, $options = array())
218: {
219: $ret = new stdClass;
220: $ret->data = '';
221: $ret->decode = null;
222:
223: if (empty($id)) {
224: return $ret;
225: }
226:
227: if (!$this->_indices || $this->isEmbedded($id)) {
228: if (empty($options['mimeheaders']) ||
229: in_array($id, $this->_embedded)) {
230: $ob = $this->getMIMEPart($id, array('nocontents' => true));
231:
232: if (empty($options['stream'])) {
233: if (!is_null($ob)) {
234: $ret->data = $ob->getContents();
235: }
236: } else {
237: $ret->data = is_null($ob)
238: ? fopen('php://temp', 'r+')
239: : $ob->getContents(array('stream' => true));
240: }
241:
242: return $ret;
243: }
244:
245: $base_id = new Horde_Mime_Id($id);
246: while (!in_array($base_id->id, $this->_embedded, true)) {
247: $base_id->id = $base_id->idArithmetic($base_id::ID_UP);
248: if (is_null($base_id->id)) {
249: return $ret;
250: }
251: }
252:
253: $part = $this->getMIMEPart($base_id->id, array('nocontents' => true));
254: $txt = $part->addMimeHeaders()->toString() .
255: "\n" .
256: $part->getContents();
257:
258: try {
259: $body = Horde_Mime_Part::getRawPartText($txt, 'header', '1') .
260: "\n\n" .
261: Horde_Mime_Part::getRawPartText($txt, 'body', '1');
262: } catch (Horde_Mime_Exception $e) {
263: $body = '';
264: }
265:
266: if (empty($options['stream'])) {
267: $ret->data = $body;
268: return $ret;
269: }
270:
271: $ret->data = fopen('php://temp', 'r+');
272: if (strlen($body)) {
273: fwrite($ret->data, $body);
274: fseek($ret->data, 0);
275: }
276: return $ret;
277: }
278:
279: $query = new Horde_Imap_Client_Fetch_Query();
280: if (substr($id, -2) === '.0') {
281: $rfc822 = true;
282: $id = substr($id, 0, -2);
283: } else {
284: $rfc822 = false;
285: }
286:
287: if (!isset($options['length']) || !empty($options['length'])) {
288: $bodypart_params = array(
289: 'decode' => !empty($options['decode']),
290: 'peek' => true
291: );
292:
293: if (isset($options['length'])) {
294: $bodypart_params['start'] = 0;
295: $bodypart_params['length'] = $options['length'];
296: }
297:
298: if ($rfc822) {
299: $bodypart_params['id'] = $id;
300: $query->bodyText($bodypart_params);
301: } else {
302: $query->bodyPart($id, $bodypart_params);
303: }
304: }
305:
306: if (!empty($options['mimeheaders'])) {
307: if ($rfc822) {
308: $query->headerText(array(
309: 'id' => $id,
310: 'peek' => true
311: ));
312: } else {
313: $query->mimeHeader($id, array(
314: 'peek' => true
315: ));
316: }
317: }
318:
319: if ($res = $this->_fetchData($query)) {
320: try {
321: if (empty($options['mimeheaders'])) {
322: $ret->decode = $res->getBodyPartDecode($id);
323: $ret->data = $rfc822
324: ? $res->getBodyText($id, !empty($options['stream']))
325: : $res->getBodyPart($id, !empty($options['stream']));
326: return $ret;
327: } elseif (empty($options['stream'])) {
328: $ret->data = $rfc822
329: ? ($res->getHeaderText($id) . $res->getBodyText($id))
330: : ($res->getMimeHeader($id) . $res->getBodyPart($id));
331: return $ret;
332: }
333:
334: if ($rfc822) {
335: $data = array(
336: $res->getHeaderText($id, Horde_Imap_Client_Data_Fetch::HEADER_STREAM),
337: $res->getBodyText($id, true)
338: );
339: } else {
340: $data = array(
341: $res->getMimeHeader($id, Horde_Imap_Client_Data_Fetch::HEADER_STREAM),
342: $res->getBodyPart($id, true)
343: );
344: }
345:
346: $ret->data = Horde_Stream_Wrapper_Combine::getStream($data);
347: return $ret;
348: } catch (Horde_Exception $e) {}
349: }
350:
351: if (!empty($options['stream'])) {
352: $ret->data = fopen('php://temp', 'r+');
353: }
354:
355: return $ret;
356: }
357:
358: 359: 360: 361: 362: 363: 364: 365: 366: 367:
368: public function fullMessageText($options = array())
369: {
370: if (!$this->_indices) {
371: return $this->_message->toString();
372: }
373:
374: $query = new Horde_Imap_Client_Fetch_Query();
375: $query->bodyText(array(
376: 'peek' => true
377: ));
378:
379: if ($res = $this->_fetchData($query)) {
380: try {
381: if (empty($options['stream'])) {
382: return $this->getHeader(self::HEADER_TEXT) . $res->getBodyText(0);
383: }
384:
385: return Horde_Stream_Wrapper_Combine::getStream(array(
386: $this->getHeader(self::HEADER_STREAM),
387: $res->getBodyText(0, true)
388: ));
389: } catch (Horde_Exception $e) {}
390: }
391:
392: return empty($options['stream'])
393: ? ''
394: : fopen('php://temp', 'r+');
395: }
396:
397: 398: 399: 400: 401: 402: 403: 404:
405: public function ($type = self::HEADER_OB)
406: {
407: return $this->_getHeader($type, false);
408: }
409:
410: 411: 412: 413: 414: 415: 416:
417: public function getHeaderAndMarkAsSeen($type = self::HEADER_OB)
418: {
419: $mbox = $this->getMailbox();
420:
421: if ($mbox->readonly) {
422: $seen = false;
423: } else {
424: $seen = true;
425:
426: if (isset($this->_header)) {
427: try {
428: $imp_imap = $mbox->imp_imap;
429: $imp_imap->store($mbox, array(
430: 'add' => array(
431: Horde_Imap_Client::FLAG_SEEN
432: ),
433: 'ids' => $imp_imap->getIdsOb($this->getUid())
434: ));
435: } catch (Exception $e) {}
436: }
437: }
438:
439: return $this->_getHeader($type, $seen);
440: }
441:
442: 443: 444: 445: 446: 447: 448: 449:
450: protected function ($type, $seen)
451: {
452: if (!isset($this->_header)) {
453: if (!$this->_indices) {
454: $this->_header = $this->_message->addMimeHeaders();
455: } else {
456: $query = new Horde_Imap_Client_Fetch_Query();
457: $query->headerText(array(
458: 'peek' => !$seen
459: ));
460:
461: $this->_header = ($res = $this->_fetchData($query))
462: ? $res
463: : new Horde_Imap_Client_Data_Fetch();
464: }
465: }
466:
467: switch ($type) {
468: case self::HEADER_OB:
469: return $this->_indices
470: ? $this->_header->getHeaderText(0, Horde_Imap_Client_Data_Fetch::HEADER_PARSE)
471: : $this->_header;
472:
473: case self::HEADER_TEXT:
474: return $this->_indices
475: ? $this->_header->getHeaderText()
476: : $this->_header->toString();
477:
478: case self::HEADER_STREAM:
479: if ($this->_indices) {
480: return $this->_header->getHeaderText(0, Horde_Imap_Client_Data_Fetch::HEADER_STREAM);
481: }
482:
483: $stream = new Horde_Support_StringStream($this->_header->toString());
484: $stream->fopen();
485: return $stream;
486: }
487: }
488:
489: 490: 491: 492: 493:
494: public function getMIMEMessage()
495: {
496: return $this->_message;
497: }
498:
499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511:
512: public function getMIMEPart($id, $options = array())
513: {
514: $this->_buildMessage();
515:
516: $part = $this->_message->getPart($id);
517:
518: 519: 520: 521:
522: if ($part &&
523: (strcasecmp($part->getCharset(), 'ISO-8859-1') === 0)) {
524: $part->setCharset('windows-1252');
525: }
526:
527: 528: 529:
530: if (!empty($id) &&
531: !is_null($part) &&
532: (substr($id, -2) != '.0') &&
533: empty($options['nocontents']) &&
534: $this->_indices &&
535: !$part->getContents(array('stream' => true))) {
536: $body = $this->getBodyPart($id, array(
537: 'decode' => true,
538: 'length' => empty($options['length']) ? null : $options['length'],
539: 'stream' => true
540: ));
541: $part->setContents($body->data, array(
542: 'encoding' => $body->decode,
543: 'usestream' => true
544: ));
545: }
546:
547: return $part;
548: }
549:
550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570:
571: public function renderMIMEPart($mime_id, $mode, array $options = array())
572: {
573: $this->_buildMessage();
574:
575: $mime_part = empty($options['mime_part'])
576: ? $this->getMIMEPart($mime_id)
577: : $options['mime_part'];
578: if (!$mime_part) {
579: return array($mime_id => null);
580: }
581:
582: if (!empty($options['autodetect']) &&
583: ($tempfile = Horde::getTempFile()) &&
584: ($fp = fopen($tempfile, 'w')) &&
585: !is_null($contents = $mime_part->getContents(array('stream' => true)))) {
586: rewind($contents);
587: while (!feof($contents)) {
588: fwrite($fp, fread($contents, 8192));
589: }
590: fclose($fp);
591:
592: $options['type'] = Horde_Mime_Magic::analyzeFile($tempfile, empty($GLOBALS['conf']['mime']['magic_db']) ? null : $GLOBALS['conf']['mime']['magic_db']);
593: }
594:
595: $type = empty($options['type'])
596: ? null
597: : $options['type'];
598:
599: $viewer = $GLOBALS['injector']->getInstance('IMP_Factory_MimeViewer')->create($mime_part, array('contents' => $this, 'type' => $type));
600:
601: switch ($mode) {
602: case self::RENDER_INLINE:
603: case self::RENDER_INLINE_AUTO:
604: case self::RENDER_INLINE_DISP_NO:
605: $textmode = 'inline';
606: $limit = $viewer->getConfigParam('limit_inline_size');
607:
608: if ($limit && ($mime_part->getBytes() > $limit)) {
609: $data = '';
610: $status = new IMP_Mime_Status(array(
611: _("This message part cannot be viewed because it is too large."),
612: sprintf(_("Click %s to download the data."), $this->linkView($mime_part, 'download_attach', _("HERE")))
613: ));
614: $status->icon('alerts/warning.png', _("Warning"));
615:
616: if (method_exists($viewer, 'overLimitText')) {
617: $data = $viewer->overLimitText();
618: $status->addText(_("The initial portion of this text part is displayed below."));
619: }
620:
621: return array(
622: $mime_id => array(
623: 'data' => $data,
624: 'name' => '',
625: 'status' => $status,
626: 'type' => 'text/html; charset=' . 'UTF-8'
627: )
628: );
629: }
630: break;
631:
632: case self::RENDER_INFO:
633: $textmode = 'info';
634: break;
635:
636: case self::RENDER_RAW:
637: $textmode = 'raw';
638: break;
639:
640: case self::RENDER_RAW_FALLBACK:
641: $textmode = $viewer->canRender('raw')
642: ? 'raw'
643: : 'full';
644: break;
645:
646: case self::RENDER_FULL:
647: default:
648: $textmode = 'full';
649: break;
650: }
651:
652: $ret = $viewer->render($textmode);
653:
654: if (empty($ret)) {
655: return ($mode == self::RENDER_INLINE_AUTO)
656: ? $this->renderMIMEPart($mime_id, self::RENDER_INFO, $options)
657: : array();
658: }
659:
660: if (!empty($ret[$mime_id]) && !isset($ret[$mime_id]['name'])) {
661: $ret[$mime_id]['name'] = $mime_part->getName(true);
662: }
663:
664:
665: if (($textmode == 'inline') &&
666: !is_null($ret[$mime_id]['data']) &&
667: !strlen($ret[$mime_id]['data']) &&
668: !isset($ret[$mime_id]['status'])) {
669: $ret[$mime_id] = null;
670: }
671:
672: return $ret;
673: }
674:
675: 676: 677: 678: 679: 680: 681: 682:
683: public function findBody($subtype = null)
684: {
685: $this->_buildMessage();
686: return $this->_message->findBody($subtype);
687: }
688:
689: 690: 691: 692: 693: 694: 695:
696: public function generatePreview()
697: {
698:
699:
700:
701: $oldbuild = $this->_build;
702: $this->_build = true;
703: $mimeid = $this->findBody();
704:
705: if (is_null($mimeid)) {
706: $this->_build = $oldbuild;
707: return array('cut' => false, 'text' => '');
708: }
709:
710: $maxlen = empty($GLOBALS['conf']['msgcache']['preview_size'])
711: ? $GLOBALS['prefs']->getValue('preview_maxlen')
712: : $GLOBALS['conf']['msgcache']['preview_size'];
713:
714:
715:
716: $pmime = $this->getMIMEPart($mimeid, array('length' => $maxlen * 3));
717:
718: $ptext = Horde_String::convertCharset($pmime->getContents(), $pmime->getCharset(), 'UTF-8');
719:
720: if ($pmime->getType() == 'text/html') {
721: $ptext = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($ptext, 'Html2text');
722: }
723:
724: $this->_build = $oldbuild;
725:
726: if (Horde_String::length($ptext) > $maxlen) {
727: return array(
728: 'cut' => true,
729: 'text' => Horde_String::truncate($ptext, $maxlen)
730: );
731: }
732:
733: return array(
734: 'cut' => false,
735: 'text' => $ptext
736: );
737: }
738:
739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: 752: 753: 754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: 782:
783: public function getSummary($id, $mask = 0)
784: {
785: $autodetect_link = false;
786: $download_zip = (($mask & self::SUMMARY_DOWNLOAD_ZIP) && Horde_Util::extensionExists('zlib'));
787: $param_array = array();
788:
789: $this->_buildMessage();
790:
791: $part = array(
792: 'bytes' => null,
793: 'download' => null,
794: 'download_url' => null,
795: 'download_zip' => null,
796: 'id' => $id,
797: 'img_save' => null,
798: 'size' => null,
799: 'strip' => null
800: );
801:
802: $mime_part = $this->getMIMEPart($id, array('nocontents' => true));
803: $mime_type = $mime_part->getType();
804:
805: 806:
807: if (in_array($mime_type, array('application/octet-stream', 'application/base64'))) {
808: $mime_type = Horde_Mime_Magic::filenameToMIME($mime_part->getName());
809: if ($mime_type == $mime_part->getType()) {
810: $autodetect_link = true;
811: } else {
812: $mime_part = clone $mime_part;
813: $mime_part->setType($mime_type);
814: $param_array['ctype'] = $mime_type;
815: }
816: }
817: $part['type'] = $mime_type;
818:
819:
820: $is_atc = $this->isAttachment($mime_type);
821:
822:
823: if (($mask & self::SUMMARY_BYTES) ||
824: $download_zip ||
825: ($mask & self::SUMMARY_SIZE)) {
826: $part['bytes'] = $size = $mime_part->getBytes();
827: $part['size'] = ($size > 1048576)
828: ? sprintf(_("%s MB"), IMP::numberFormat($size / 1048576, 1))
829: : sprintf(_("%s KB"), max(round($size / 1024), 1));
830: }
831:
832:
833: if (($mask & self::SUMMARY_ICON) ||
834: ($mask & self::SUMMARY_ICON_RAW)) {
835: $part['icon'] = $GLOBALS['injector']->getInstance('IMP_Factory_MimeViewer')->getIcon($mime_type);
836: if ($mask & self::SUMMARY_ICON) {
837: $part['icon'] = Horde_Themes_Image::tag($part['icon'], array(
838: 'attr' => array(
839: 'title' => $mime_type
840: )
841: ));
842: }
843: } else {
844: $part['icon'] = null;
845: }
846:
847:
848: $description = $this->getPartName($mime_part, true);
849:
850: if ($mask & self::SUMMARY_DESCRIP_LINK) {
851: if (($can_d = $this->canDisplay($mime_part, self::RENDER_FULL)) ||
852: $autodetect_link) {
853: $part['description'] = $this->linkViewJS($mime_part, 'view_attach', htmlspecialchars($description), array('jstext' => sprintf(_("View %s"), $description), 'params' => array_filter(array_merge($param_array, array(
854: 'autodetect' => !$can_d
855: )))));
856: } else {
857: $part['description'] = htmlspecialchars($description);
858: }
859: }
860: if ($mask & self::SUMMARY_DESCRIP) {
861: $part['description_raw'] = $description;
862: }
863:
864:
865: if (($mask & self::SUMMARY_DOWNLOAD) &&
866: $is_atc &&
867: (is_null($part['bytes']) || $part['bytes'])) {
868: $part['download'] = $this->linkView($mime_part, 'download_attach', '', array('class' => 'iconImg downloadAtc', 'jstext' => _("Download")));
869: $part['download_url'] = $this->urlView($mime_part, 'download_attach');
870: }
871:
872: 873:
874: if ($is_atc &&
875: $download_zip &&
876: ($part['bytes'] > 204800)) {
877: $viewer = $GLOBALS['injector']->getInstance('IMP_Factory_MimeViewer')->create($mime_part, array('contents' => $this, 'type' => $mime_type));
878: if (!$viewer->getMetadata('compressed')) {
879: $part['download_zip'] = $this->linkView($mime_part, 'download_attach', null, array('class' => 'iconImg downloadZipAtc', 'jstext' => sprintf(_("Download %s in .zip Format"), $description), 'params' => array('zip' => 1)));
880: }
881: }
882:
883: 884:
885: if (($mask & self::SUMMARY_IMAGE_SAVE) &&
886: $GLOBALS['registry']->hasMethod('images/selectGalleries') &&
887: ($mime_part->getPrimaryType() == 'image')) {
888: $part['img_save'] = Horde::link('#', _("Save Image in Gallery"), 'iconImg saveImgAtc', null, Horde::popupJs(IMP_Basic_Saveimage::url(), array('params' => array('muid' => strval($this->getIndicesOb()), 'id' => $id), 'height' => 200, 'width' => 450, 'urlencode' => true)) . 'return false;') . '</a>';
889: }
890:
891:
892: if ((($mask & self::SUMMARY_PRINT) ||
893: ($mask & self::SUMMARY_PRINT_STUB)) &&
894: $this->canDisplay($id, self::RENDER_FULL)) {
895: $part['print'] = ($mask & self::SUMMARY_PRINT)
896: ? $this->linkViewJS($mime_part, 'print_attach', '', array('css' => 'iconImg printAtc', 'jstext' => _("Print"), 'onload' => 'IMP_JS.printWindow', 'params' => $param_array))
897: : Horde::link('#', _("Print"), 'iconImg printAtc', null, null, null, null, array('mimeid' => $id)) . '</a>';
898: }
899:
900: 901:
902: if (($mask & self::SUMMARY_STRIP) &&
903: ($id != 0) &&
904: (intval($id) != 1) &&
905: (strpos($id, '.') === false)) {
906: $part['strip'] = Horde::link(
907: Horde::selfUrlParams()->add(array(
908: 'actionID' => 'strip_attachment',
909: 'imapid' => $id,
910: 'muid' => strval($this->getIndicesOb()),
911: 'token' => $GLOBALS['session']->getToken()
912: )),
913: _("Strip Attachment"),
914: 'iconImg deleteImg stripAtc',
915: null,
916: null,
917: null,
918: null,
919: array('mimeid' => $id)
920: ) . '</a>';
921: }
922:
923: return $part;
924: }
925:
926: 927: 928: 929: 930: 931: 932: 933: 934: 935: 936:
937: public function urlView($mime_part = null, $actionID = 'view_attach',
938: array $options = array())
939: {
940: $params = $this->_urlViewParams($mime_part, $actionID, isset($options['params']) ? $options['params'] : array());
941:
942: return (strpos($actionID, 'download_') === 0)
943: ? IMP_Contents_View::downloadUrl($mime_part->getName(true), $params)
944: : Horde::url('view.php', true)->add($params);
945: }
946:
947: 948: 949: 950: 951: 952: 953: 954: 955:
956: protected function _urlViewParams($mime_part, $actionID, $params)
957: {
958:
959: $params = array_merge($params, array(
960: 'actionID' => $actionID,
961: 'id' => isset($params['id']) ? $params['id'] : $mime_part->getMIMEId()
962: ));
963:
964: if ($this->_indices) {
965: $params['muid'] = strval($this->getIndicesOb());
966: }
967:
968: return IMP_Contents_View::addToken($params);
969: }
970:
971: 972: 973: 974: 975: 976: 977: 978: 979: 980: 981: 982: 983: 984:
985: public function linkView($mime_part, $actionID, $text, $options = array())
986: {
987: $options = array_merge(array(
988: 'class' => null,
989: 'jstext' => $text,
990: 'params' => array()
991: ), $options);
992:
993: return Horde::link(
994: $this->urlView($mime_part, $actionID, $options),
995: $options['jstext'],
996: $options['class'],
997: ($actionID == 'download_attach') ? null : strval(new Horde_Support_Randomid())
998: ) . $text . '</a>';
999: }
1000:
1001: 1002: 1003: 1004: 1005: 1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016: 1017: 1018:
1019: public function linkViewJS($mime_part, $actionID, $text,
1020: $options = array())
1021: {
1022: if (empty($options['params'])) {
1023: $options['params'] = array();
1024: }
1025:
1026: if (empty($options['jstext'])) {
1027: $options['jstext'] = sprintf(_("View %s"), $mime_part->getDescription(true));
1028: }
1029:
1030: $url = Horde::popupJs(Horde::url('view.php'), array(
1031: 'menu' => true,
1032: 'onload' => empty($options['onload']) ? 'IMP_JS.resizePopup' : $options['onload'],
1033: 'params' => $this->_urlViewParams($mime_part, $actionID, isset($options['params']) ? $options['params'] : array()),
1034: 'urlencode' => true
1035: ));
1036:
1037: return empty($options['widget'])
1038: ? Horde::link('#', $options['jstext'], empty($options['css']) ? null : $options['css'], null, $url) . $text . '</a>'
1039: : Horde::widget(array('url' => '#', 'class' => empty($options['css']) ? null : $options['css'], 'onclick' => $url, 'title' => $text));
1040: }
1041:
1042: 1043: 1044: 1045: 1046: 1047: 1048: 1049: 1050: 1051:
1052: public function isAttachment($mime_type)
1053: {
1054: switch ($mime_type) {
1055: case 'application/ms-tnef':
1056: return false;
1057: }
1058:
1059: list($ptype,) = explode('/', $mime_type, 2);
1060:
1061: switch ($ptype) {
1062: case 'message':
1063: return in_array($mime_type, array('message/rfc822', 'message/disposition-notification'));
1064:
1065: case 'multipart':
1066: return false;
1067:
1068: default:
1069: return true;
1070: }
1071: }
1072:
1073: 1074: 1075: 1076: 1077: 1078:
1079: protected function _buildMessage($parts = null)
1080: {
1081: global $injector;
1082:
1083: if (is_null($parts)) {
1084: if ($this->_build) {
1085: return;
1086: }
1087: $this->_build = true;
1088: $parts = array_keys($this->_message->contentTypeMap());
1089: $first_id = reset($parts);
1090: } else {
1091: $first_id = null;
1092: }
1093:
1094: $last_id = null;
1095: $to_process = array();
1096:
1097: $mv_factory = $injector->getInstance('IMP_Factory_MimeViewer');
1098:
1099: foreach ($parts as $id) {
1100: if (!is_null($last_id) &&
1101: (strpos($id, $last_id) === 0)) {
1102: continue;
1103: }
1104:
1105: $last_id = null;
1106:
1107: $mime_part = $this->getMIMEPart($id, array('nocontents' => true));
1108: $viewer = $mv_factory->create($mime_part, array('contents' => $this));
1109: if ($viewer->embeddedMimeParts()) {
1110: $mime_part = $this->getMIMEPart($id);
1111: $viewer->setMIMEPart($mime_part);
1112: $new_part = $viewer->getEmbeddedMimeParts();
1113: if (!is_null($new_part)) {
1114: $mime_part->addPart($new_part);
1115: $mime_part->buildMimeIds($id);
1116: $this->_embedded[] = $new_part->getMimeId();
1117: $to_process = array_merge($to_process, array_keys($new_part->contentTypeMap()));
1118: $last_id = $id;
1119: }
1120: }
1121: }
1122:
1123: if (!empty($to_process)) {
1124: $this->_buildMessage($to_process);
1125: }
1126: }
1127:
1128: 1129: 1130: 1131: 1132: 1133: 1134: 1135: 1136: 1137:
1138: public function canDisplay($part, $mask, $type = null)
1139: {
1140: if (!is_object($part)) {
1141: $part = $this->getMIMEPart($part, array('nocontents' => true));
1142: }
1143: $viewer = $GLOBALS['injector']->getInstance('IMP_Factory_MimeViewer')->create($part, array('contents' => $this, 'type' => $type));
1144:
1145: if ($mask & self::RENDER_INLINE_AUTO) {
1146: $mask |= self::RENDER_INLINE | self::RENDER_INFO;
1147: }
1148:
1149: if (($mask & self::RENDER_RAW) && $viewer->canRender('raw')) {
1150: return self::RENDER_RAW;
1151: }
1152:
1153: if (($mask & self::RENDER_FULL) && $viewer->canRender('full')) {
1154: return self::RENDER_FULL;
1155: }
1156:
1157: if ($mask & self::RENDER_INLINE) {
1158: if ($viewer->canRender('inline')) {
1159: return self::RENDER_INLINE;
1160: }
1161: } elseif (($mask & self::RENDER_INLINE_DISP_NO) &&
1162: $viewer->canRender('inline')) {
1163: return self::RENDER_INLINE_DISP_NO;
1164: }
1165:
1166: if (($mask & self::RENDER_INFO) && $viewer->canRender('info')) {
1167: return self::RENDER_INFO;
1168: }
1169:
1170: return 0;
1171: }
1172:
1173: 1174: 1175: 1176: 1177: 1178:
1179: public function getContentTypeMap()
1180: {
1181: $this->_buildMessage();
1182: return $this->_message->contentTypeMap();
1183: }
1184:
1185: 1186: 1187: 1188: 1189: 1190: 1191: 1192: 1193:
1194: public function getTree($renderer = 'Horde_Core_Tree_Renderer_Html')
1195: {
1196: $tree = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Tree')->create('mime-' . $this->getUid(), $renderer, array(
1197: 'nosession' => true
1198: ));
1199: $this->_addTreeNodes($tree, $this->_message);
1200: return $tree;
1201: }
1202:
1203: 1204: 1205: 1206: 1207: 1208: 1209: 1210:
1211: protected function _addTreeNodes($tree, $part, $parent = null)
1212: {
1213: $mimeid = $part->getMimeId();
1214:
1215: $summary_mask = self::SUMMARY_ICON_RAW | self::SUMMARY_DESCRIP_LINK | self::SUMMARY_SIZE | self::SUMMARY_DOWNLOAD;
1216: if ($GLOBALS['prefs']->getValue('strip_attachments')) {
1217: $summary_mask += self::SUMMARY_STRIP;
1218: }
1219:
1220: $summary = $this->getSummary($mimeid, $summary_mask);
1221:
1222: $tree->addNode(array(
1223: 'id' => $mimeid,
1224: 'parent' => $parent,
1225: 'label' => sprintf(
1226: '%s (%s) %s %s',
1227: $summary['description'],
1228: $summary['size'],
1229: $summary['download'],
1230: $summary['strip']
1231: ),
1232: 'params' => array(
1233: 'class' => 'partsTreeDiv',
1234: 'icon' => $summary['icon']
1235: )
1236: ));
1237:
1238: foreach ($part->getParts() as $part) {
1239: $this->_addTreeNodes($tree, $part, $mimeid);
1240: }
1241: }
1242:
1243: 1244: 1245: 1246: 1247:
1248: public function downloadAllList()
1249: {
1250: $ret = array();
1251:
1252: foreach ($this->getContentTypeMap() as $key => $val) {
1253: if ($this->isAttachment($val)) {
1254: $ret[] = $key;
1255: }
1256: }
1257:
1258: return $ret;
1259: }
1260:
1261: 1262: 1263: 1264: 1265: 1266: 1267:
1268: public function buildMessageContents($ignore = array())
1269: {
1270: $message = $this->_message;
1271: $curr_ignore = null;
1272:
1273: foreach ($message->contentTypeMap() as $key => $val) {
1274: if (is_null($curr_ignore) && in_array($key, $ignore)) {
1275: $curr_ignore = $key . '.';
1276: } elseif (is_null($curr_ignore) ||
1277: (strpos($key, $curr_ignore) === false)) {
1278: $curr_ignore = null;
1279: if (($key != 0) &&
1280: ($val != 'message/rfc822') &&
1281: (strpos($val, 'multipart/') === false)) {
1282: $part = $this->getMIMEPart($key);
1283: $message->alterPart($key, $part);
1284: }
1285: }
1286: }
1287:
1288: return $message;
1289: }
1290:
1291: 1292: 1293: 1294: 1295: 1296: 1297:
1298: public function isEmbedded($mime_id)
1299: {
1300: foreach ($this->_embedded as $val) {
1301: if (($mime_id == $val) ||
1302: (($id_ob = new Horde_Mime_Id($val)) &&
1303: $id_ob->isChild($mime_id))) {
1304: return true;
1305: }
1306: }
1307:
1308: return false;
1309: }
1310:
1311: 1312: 1313: 1314: 1315: 1316: 1317: 1318:
1319: public function findMimeType($id, $type)
1320: {
1321: $id_ob = new Horde_Mime_Id($id);
1322:
1323: while (($id_ob->id = $id_ob->idArithmetic($id_ob::ID_UP)) !== null) {
1324: if (($part = $this->getMIMEPart($id_ob->id, array('nocontents' => true))) &&
1325: ($part->getType() == $type)) {
1326: return $part;
1327: }
1328: }
1329:
1330: return null;
1331: }
1332:
1333: 1334: 1335: 1336: 1337: 1338: 1339: 1340:
1341: public function getPartName(Horde_Mime_Part $part, $use_descrip = false)
1342: {
1343: $name = $use_descrip
1344: ? $part->getDescription(true)
1345: : $part->getName(true);
1346:
1347: if ($name) {
1348: return $name;
1349: }
1350:
1351: switch ($ptype = $part->getPrimaryType()) {
1352: case 'multipart':
1353: if (($part->getSubType() == 'related') &&
1354: ($view_id = $part->getMetaData('viewable_part')) &&
1355: ($viewable = $this->getMIMEPart($view_id, array('nocontents' => true)))) {
1356: return $this->getPartName($viewable, $use_descrip);
1357: }
1358:
1359:
1360: case 'application':
1361: case 'model':
1362: $ptype = $part->getSubType();
1363: break;
1364: }
1365:
1366: switch ($ptype) {
1367: case 'audio':
1368: return _("Audio");
1369:
1370: case 'image':
1371: return _("Image");
1372:
1373: case 'message':
1374: case '':
1375: case Horde_Mime_Part::UNKNOWN:
1376: return _("Message");
1377:
1378: case 'multipart':
1379: return _("Multipart");
1380:
1381: case 'text':
1382: return _("Text");
1383:
1384: case 'video':
1385: return _("Video");
1386:
1387: default:
1388:
1389:
1390: return _(Horde_String::ucfirst($ptype));
1391: }
1392: }
1393:
1394: 1395: 1396: 1397: 1398: 1399: 1400:
1401: protected function _fetchData(Horde_Imap_Client_Fetch_Query $query)
1402: {
1403: try {
1404: $mbox = $this->getMailbox();
1405: $imp_imap = $mbox->imp_imap;
1406: return $imp_imap->fetch($mbox, $query, array(
1407: 'ids' => $imp_imap->getIdsOb($this->getUid())
1408: ))->first();
1409: } catch (Horde_Imap_Client_Exception $e) {
1410: return new Horde_Imap_Client_Data_Fetch();
1411: }
1412: }
1413:
1414: 1415: 1416: 1417: 1418:
1419: public function getViewCache()
1420: {
1421: if (!isset($this->_viewcache)) {
1422: $this->_viewcache = new stdClass;
1423: }
1424:
1425: return $this->_viewcache;
1426: }
1427:
1428: }
1429: