1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
17: class IMP
18: {
19:
20: const ENCRYPT_NONE = 'encrypt_none';
21:
22:
23: const MAILBOX_START_FIRSTUNSEEN = 1;
24: const MAILBOX_START_LASTUNSEEN = 2;
25: const MAILBOX_START_FIRSTPAGE = 3;
26: const MAILBOX_START_LASTPAGE = 4;
27:
28:
29: const NOTEPAD_EDIT = "notepad\0";
30: const TASKLIST_EDIT = "tasklist\0";
31:
32:
33: const INITIAL_FOLDERS = "initial\0folders";
34:
35:
36: const IMAP_SORT_DATE = 100;
37:
38: 39: 40: 41: 42:
43: static public $newUrl = null;
44:
45: 46: 47: 48: 49:
50: static public $mailbox;
51:
52: 53: 54: 55: 56:
57: static public $thismailbox;
58:
59: 60: 61: 62: 63:
64: static public $uid = '';
65:
66: 67: 68: 69: 70:
71: static public function getViewMode()
72: {
73: return ($view = $GLOBALS['session']->get('imp', 'view'))
74: ? $view
75: : 'imp';
76: }
77:
78: 79: 80: 81: 82: 83:
84: static public function showAjaxView()
85: {
86: global $prefs, $session;
87:
88: $mode = $session->get('horde', 'mode');
89: return ($mode == 'dynamic' || ($prefs->getValue('dynamic_view') && $mode == 'auto')) && Horde::ajaxAvailable();
90: }
91:
92: 93: 94: 95: 96: 97: 98: 99: 100:
101: static public function addAddress($newAddress, $newName)
102: {
103: global $registry, $prefs;
104:
105: if (empty($newName)) {
106: $newName = $newAddress;
107: }
108:
109: $result = $registry->call('contacts/import', array(array('name' => $newName, 'email' => $newAddress), 'array', $prefs->getValue('add_source')));
110:
111: $escapeName = @htmlspecialchars($newName, ENT_COMPAT, 'UTF-8');
112:
113: try {
114: if ($contact_link = $registry->link('contacts/show', array('uid' => $result, 'source' => $prefs->getValue('add_source')))) {
115: return Horde::link(Horde::url($contact_link), sprintf(_("Go to address book entry of \"%s\""), $newName)) . $escapeName . '</a>';
116: }
117: } catch (Horde_Exception $e) {}
118:
119: return $escapeName;
120: }
121:
122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150:
151: static public function flistSelect(array $options = array())
152: {
153: $imaptree = $GLOBALS['injector']->getInstance('IMP_Imap_Tree');
154: $imaptree->setIteratorFilter();
155: $tree = $imaptree->createTree(strval(new Horde_Support_Randomid()), array(
156: 'basename' => !empty($options['basename']),
157: 'render_type' => 'IMP_Tree_Flist'
158: ));
159: if (!empty($options['selected'])) {
160: $tree->addNodeParams(IMP_Mailbox::formTo($options['selected']), array('selected' => true));
161: }
162: $tree->setOption($options);
163:
164: return $tree->getTree();
165: }
166:
167: 168: 169: 170: 171: 172:
173: static public function getComposeArgs()
174: {
175: $args = array();
176: $fields = array('to', 'cc', 'bcc', 'message', 'body', 'subject');
177:
178: foreach ($fields as $val) {
179: if (($$val = Horde_Util::getFormData($val))) {
180: $args[$val] = $$val;
181: }
182: }
183:
184: return self::_decodeMailto($args);
185: }
186:
187: 188: 189: 190: 191: 192: 193:
194: static protected function _decodeMailto($args)
195: {
196: $fields = array('to', 'cc', 'bcc', 'message', 'body', 'subject');
197:
198: if (isset($args['to']) && (strpos($args['to'], 'mailto:') === 0)) {
199: $mailto = @parse_url($args['to']);
200: if (is_array($mailto)) {
201: $args['to'] = isset($mailto['path']) ? $mailto['path'] : '';
202: if (!empty($mailto['query'])) {
203: parse_str($mailto['query'], $vals);
204: foreach ($fields as $val) {
205: if (isset($vals[$val])) {
206: $args[$val] = $vals[$val];
207: }
208: }
209: }
210: }
211: }
212:
213: return $args;
214: }
215:
216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229:
230: static public function composeLink($args = array(), $extra = array(),
231: $simplejs = false)
232: {
233: if (is_string($args)) {
234: $string = $args;
235: $args = array();
236: if (($pos = strpos($string, '?')) !== false) {
237: parse_str(substr($string, $pos + 1), $args);
238: $args['to'] = substr($string, 0, $pos);
239: } else {
240: $args['to'] = $string;
241: }
242: }
243:
244: $args = array_merge(self::_decodeMailto($args), $extra);
245: $callback = $raw = false;
246: $uid = isset($args['uid'])
247: ? $args['uid']
248: : null;
249: $view = self::getViewMode();
250:
251: if ($simplejs || ($view == 'dimp')) {
252: $args['popup'] = 1;
253:
254: $url = ($view == 'dimp')
255: ? 'compose-dimp.php'
256: : 'compose.php';
257: $raw = true;
258: $callback = array(__CLASS__, 'composeLinkSimpleCallback');
259: } elseif (($view != 'mimp') &&
260: $GLOBALS['prefs']->getValue('compose_popup') &&
261: $GLOBALS['browser']->hasFeature('javascript')) {
262: $url = 'compose.php';
263: $callback = array(__CLASS__, 'composeLinkJsCallback');
264: } else {
265: $url = ($view == 'mimp')
266: ? 'compose-mimp.php'
267: : 'compose.php';
268: }
269:
270: if (isset($args['thismailbox'])) {
271: $url = IMP_Mailbox::get($args['thismailbox'])->url($url, $uid);
272: } elseif (isset($args['mailbox'])) {
273: $url = IMP_Mailbox::get($args['mailbox'])->url($url, $uid);
274: } else {
275: $url = Horde::url($url);
276: }
277:
278: unset($args['mailbox'], $args['thismailbox'], $args['uid']);
279:
280: $url->setRaw($raw)->add($args);
281: if ($callback) {
282: $url->toStringCallback = $callback;
283: }
284:
285: return $url;
286: }
287:
288: 289: 290: 291: 292: 293: 294: 295:
296: static public function composeLinkSimpleCallback($url)
297: {
298: return "javascript:void(window.open('" . strval($url) . "','','width=820,height=610,status=1,scrollbars=yes,resizable=yes'));";
299: }
300:
301: 302: 303: 304: 305: 306: 307:
308: static public function composeLinkJsCallback($url)
309: {
310: return 'javascript:' . Horde::popupJs(strval($url), array('urlencode' => true));
311: }
312:
313: 314: 315: 316: 317: 318: 319:
320: static public function filterText($text)
321: {
322: if ($GLOBALS['prefs']->getValue('filtering') && strlen($text)) {
323: return $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($text, 'words', array(
324: 'replacement' => $GLOBALS['conf']['msgsettings']['filtering']['replacement'],
325: 'words_file' => $GLOBALS['conf']['msgsettings']['filtering']['words']
326: ));
327: }
328:
329: return $text;
330: }
331:
332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342:
343: public function hasPermission($permission, $opts = array())
344: {
345: $allowed = $GLOBALS['injector']->getInstance('Horde_Core_Perms')
346: ->hasAppPermission($permission);
347:
348: switch ($permission) {
349: case 'create_folders':
350:
351: break;
352:
353: case 'max_folders':
354: return ($allowed >= count($GLOBALS['injector']->getInstance('IMP_Imap_Tree')));
355: break;
356:
357: case 'max_recipients':
358: if (isset($opts['value'])) {
359: return ($allowed >= $opts['value']);
360: }
361: break;
362:
363: case 'max_timelimit':
364: if (isset($opts['value'])) {
365: $sentmail = $GLOBALS['injector']->getInstance('IMP_Sentmail');
366: if (!($sentmail instanceof IMP_Sentmail_Base)) {
367: Horde::logMessage('The permission for the maximum number of recipients per time period has been enabled, but no backend for the sent-mail logging has been configured for IMP.', 'ERR');
368: return true;
369: }
370:
371: try {
372: $opts['value'] += $sentmail->numberOfRecipients($GLOBALS['conf']['sentmail']['params']['limit_period'], true);
373: } catch (IMP_Exception $e) {}
374:
375: return ($allowed >= $opts['value']);
376: }
377: break;
378: }
379:
380: return (bool)$allowed;
381: }
382:
383: 384: 385: 386: 387:
388: static public function ()
389: {
390: $t = $GLOBALS['injector']->createInstance('Horde_Template');
391: $t->set('form_url', Horde::url('mailbox.php'));
392: $t->set('forminput', Horde_Util::formInput());
393: $t->set('use_folders', $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->access(IMP_Imap::ACCESS_FOLDERS), true);
394: if ($t->get('use_folders')) {
395: Horde::addScriptFile('imp.js', 'imp');
396: $menu_view = $GLOBALS['prefs']->getValue('menu_view');
397: $ak = $GLOBALS['prefs']->getValue('widget_accesskey')
398: ? Horde::getAccessKey(_("Open Fo_lder"))
399: : '';
400:
401: $t->set('ak', $ak);
402: $t->set('flist', self::flistSelect(array(
403: 'inc_vfolder' => true,
404: 'selected' => self::$mailbox
405: )));
406: $t->set('flink', sprintf('%s%s<br />%s</a>', Horde::link('#'), ($menu_view != 'text') ? '<span class="iconImg folderImg" title="' . htmlspecialchars(_("Open Folder")) . '"></span>' : '', ($menu_view != 'icon') ? Horde::highlightAccessKey(_("Open Fo_lder"), $ak) : ''));
407: }
408: $t->set('menu_string', Horde::menu(array('app' => 'imp', 'menu_ob' => true))->render());
409:
410: $menu = $t->fetch(IMP_TEMPLATES . '/imp/menu/menu.html');
411:
412: 413:
414: Horde::startBuffer();
415: require HORDE_BASE . '/services/sidebar.php';
416: return $menu . Horde::endBuffer();
417: }
418:
419: 420: 421:
422: static public function status()
423: {
424: $GLOBALS['notification']->notify(array('listeners' => array('status', 'audio')));
425: }
426:
427: 428: 429:
430: static public function quota()
431: {
432: $quotadata = self::quotaData(true);
433: if (!empty($quotadata)) {
434: $t = $GLOBALS['injector']->createInstance('Horde_Template');
435: $t->set('class', $quotadata['class']);
436: $t->set('message', $quotadata['message']);
437: echo $t->fetch(IMP_TEMPLATES . '/quota/quota.html');
438: }
439: }
440:
441: 442: 443: 444: 445: 446: 447:
448: static public function quotaData($long = true)
449: {
450: if (!$GLOBALS['session']->get('imp', 'imap_quota')) {
451: return false;
452: }
453:
454: try {
455: $quotaDriver = $GLOBALS['injector']->getInstance('IMP_Quota');
456: $quota = $quotaDriver->getQuota();
457: } catch (IMP_Exception $e) {
458: Horde::logMessage($e, 'ERR');
459: return false;
460: }
461:
462: if (empty($quota)) {
463: return false;
464: }
465:
466: $strings = $quotaDriver->getMessages();
467: list($calc, $unit) = $quotaDriver->getUnit();
468: $ret = array('percent' => 0);
469:
470: if ($quota['limit'] != 0) {
471: $quota['usage'] = $quota['usage'] / $calc;
472: $quota['limit'] = $quota['limit'] / $calc;
473: $ret['percent'] = ($quota['usage'] * 100) / $quota['limit'];
474: if ($ret['percent'] >= 90) {
475: $ret['class'] = 'quotaalert';
476: } elseif ($ret['percent'] >= 75) {
477: $ret['class'] = 'quotawarn';
478: } else {
479: $ret['class'] = 'control';
480: }
481:
482: $ret['message'] = $long
483: ? sprintf($strings['long'], $quota['usage'], $unit, $quota['limit'], $unit, $ret['percent'])
484: : sprintf($strings['short'], $ret['percent'], $quota['limit'], $unit);
485: $ret['percent'] = sprintf("%.2f", $ret['percent']);
486: } else {
487: $ret['class'] = 'control';
488: if ($quota['usage'] != 0) {
489: $quota['usage'] = $quota['usage'] / $calc;
490:
491: $ret['message'] = $long
492: ? sprintf($strings['nolimit_long'], $quota['usage'], $unit)
493: : sprintf($strings['nolimit_short'], $quota['usage'], $unit);
494: } else {
495: $ret['message'] = $long
496: ? sprintf(_("Quota status: NO LIMIT"))
497: : _("No limit");
498: }
499: }
500:
501: return $ret;
502: }
503:
504: 505: 506: 507: 508: 509: 510: 511: 512: 513:
514: static public function encryptList($default = null, $returnList = false)
515: {
516: if (is_null($default)) {
517: $default = $GLOBALS['prefs']->getValue('default_encrypt');
518: }
519:
520: $enc_opts = array();
521: $output = '';
522:
523: if (!empty($GLOBALS['conf']['gnupg']['path']) &&
524: $GLOBALS['prefs']->getValue('use_pgp')) {
525: $enc_opts += $GLOBALS['injector']->getInstance('IMP_Crypt_Pgp')->encryptList();
526: }
527:
528: if ($GLOBALS['prefs']->getValue('use_smime')) {
529: $enc_opts += $GLOBALS['injector']->getInstance('IMP_Crypt_Smime')->encryptList();
530: }
531:
532: if (!empty($enc_opts)) {
533: $enc_opts = array_merge(
534: array(self::ENCRYPT_NONE => _("None")),
535: $enc_opts
536: );
537: }
538:
539: if ($returnList) {
540: return $enc_opts;
541: }
542:
543: foreach ($enc_opts as $key => $val) {
544: $output .= '<option value="' . $key . '"' . (($default == $key) ? ' selected="selected"' : '') . '>' . $val . "</option>\n";
545: }
546:
547: return $output;
548: }
549:
550: 551: 552: 553: 554: 555:
556: static public function setCurrentMailboxInfo($mbox = null)
557: {
558: if (is_null($mbox)) {
559: $mbox = Horde_Util::getFormData('mailbox');
560: self::$mailbox = is_null($mbox)
561: ? IMP_Mailbox::get('INBOX')
562: : IMP_Mailbox::formFrom($mbox);
563:
564: $mbox = Horde_Util::getFormData('thismailbox');
565: self::$thismailbox = is_null($mbox)
566: ? self::$mailbox
567: : IMP_Mailbox::formFrom($mbox);
568:
569: self::$uid = Horde_Util::getFormData('uid');
570: } else {
571: self::$mailbox = self::$thismailbox = IMP_Mailbox::get($mbox);
572: self::$uid = null;
573: }
574: }
575:
576: 577: 578: 579: 580: 581: 582:
583: static public function selfUrl()
584: {
585: return self::$newUrl
586: ? self::$newUrl->copy()
587: : Horde::selfUrl(true);
588: }
589:
590: 591: 592: 593: 594: 595:
596: static public function canCompose()
597: {
598: try {
599: return !Horde::callHook('disable_compose', array(), 'imp');
600: } catch (Horde_Exception_HookNotSet $e) {
601: return true;
602: }
603: }
604:
605: 606: 607: 608: 609:
610: static public function getAddressbookSearchParams()
611: {
612: $src = json_decode($GLOBALS['prefs']->getValue('search_sources'));
613: if (empty($src)) {
614: $src = array();
615: }
616:
617: $fields = json_decode($GLOBALS['prefs']->getValue('search_fields'), true);
618: if (empty($fields)) {
619: $fields = array();
620: }
621:
622: return array(
623: 'fields' => $fields,
624: 'sources' => $src
625: );
626: }
627:
628: 629: 630: 631: 632: 633: 634:
635: static public function base64urlEncode($in)
636: {
637: return strtr(rtrim(base64_encode($in), '='), '+/', '-_');
638: }
639:
640: 641: 642: 643: 644: 645: 646:
647: static public function base64urlDecode($in)
648: {
649: return base64_decode(strtr($in, '-_', '+/'));
650: }
651:
652: 653: 654: 655: 656: 657: 658: 659:
660: static public function numberFormat($number, $decimals)
661: {
662: $localeinfo = Horde_Nls::getLocaleInfo();
663:
664: return str_replace(
665: array('X', 'Y'),
666: array($localeinfo['decimal_point'], $localeinfo['thousands_sep']),
667: number_format($number, $decimals, 'X', 'Y')
668: );
669: }
670:
671: }
672: