1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
13: class Nag
14: {
15: 16: 17:
18: const SORT_NAME = 'name';
19:
20: 21: 22:
23: const SORT_PRIORITY = 'priority';
24:
25: 26: 27:
28: const SORT_DUE = 'due';
29:
30: 31: 32:
33: const SORT_START = 'start';
34:
35: 36: 37:
38: const SORT_COMPLETION = 'completed';
39:
40: 41: 42:
43: const SORT_CATEGORY = 'category';
44:
45: 46: 47:
48: const SORT_OWNER = 'tasklist';
49:
50: 51: 52:
53: const SORT_ESTIMATE = 'estimate';
54:
55: 56: 57:
58: const SORT_ASSIGNEE = 'assignee';
59:
60: 61: 62:
63: const SORT_ASCEND = 0;
64:
65: 66: 67:
68: const SORT_DESCEND = 1;
69:
70: 71: 72:
73: const VIEW_INCOMPLETE = 0;
74:
75: 76: 77:
78: const VIEW_ALL = 1;
79:
80: 81: 82:
83: const VIEW_COMPLETE = 2;
84:
85: 86: 87:
88: const VIEW_FUTURE = 3;
89:
90: 91: 92:
93: const VIEW_FUTURE_INCOMPLETE = 4;
94:
95: 96: 97: 98: 99: 100:
101: static public function secondsToString($seconds)
102: {
103: $hours = floor($seconds / 3600);
104: $minutes = ($seconds / 60) % 60;
105:
106: if ($hours > 1) {
107: if ($minutes == 0) {
108: return sprintf(_("%d hours"), $hours);
109: } elseif ($minutes == 1) {
110: return sprintf(_("%d hours, %d minute"), $hours, $minutes);
111: } else {
112: return sprintf(_("%d hours, %d minutes"), $hours, $minutes);
113: }
114: } elseif ($hours == 1) {
115: if ($minutes == 0) {
116: return sprintf(_("%d hour"), $hours);
117: } elseif ($minutes == 1) {
118: return sprintf(_("%d hour, %d minute"), $hours, $minutes);
119: } else {
120: return sprintf(_("%d hour, %d minutes"), $hours, $minutes);
121: }
122: } else {
123: if ($minutes == 0) {
124: return _("no time");
125: } elseif ($minutes == 1) {
126: return sprintf(_("%d minute"), $minutes);
127: } else {
128: return sprintf(_("%d minutes"), $minutes);
129: }
130: }
131: }
132:
133: 134: 135: 136: 137: 138: 139: 140: 141:
142: static public function parseDate($date, $withtime = true)
143: {
144:
145: if (!function_exists('strptime')) {
146: return new Horde_Date($date);
147: }
148:
149:
150:
151:
152: $format = Horde_Nls::getLangInfo(D_FMT);
153: if ($withtime) {
154: $format .= ' '
155: . ($GLOBALS['prefs']->getValue('twentyFour') ? '%H:%M' : '%I:%M %p');
156: }
157: $old_locale = setlocale(LC_TIME, 0);
158: setlocale(LC_TIME, 'C');
159:
160:
161: $date_arr = strptime($date, $format);
162: setlocale(LC_TIME, $old_locale);
163:
164: if (!$date_arr) {
165:
166: $date_arr = strptime($date, $format);
167: if (!$date_arr) {
168:
169: return new Horde_Date($date);
170: }
171: }
172:
173: return new Horde_Date(
174: array('year' => $date_arr['tm_year'] + 1900,
175: 'month' => $date_arr['tm_mon'] + 1,
176: 'mday' => $date_arr['tm_mday'],
177: 'hour' => $date_arr['tm_hour'],
178: 'min' => $date_arr['tm_min'],
179: 'sec' => $date_arr['tm_sec']));
180: }
181:
182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200:
201: public static function listTasks($sortby = null,
202: $sortdir = null,
203: $altsortby = null,
204: array $tasklists = null,
205: $completed = null)
206: {
207: global $prefs, $registry;
208:
209: if (is_null($sortby)) {
210: $sortby = $prefs->getValue('sortby');
211: }
212: if (is_null($sortdir)) {
213: $sortdir = $prefs->getValue('sortdir');
214: }
215: if (is_null($altsortby)) {
216: $altsortby = $prefs->getValue('altsortby');
217: }
218:
219: if (is_null($tasklists)) {
220: $tasklists = $GLOBALS['display_tasklists'];
221: }
222: if (!is_array($tasklists)) {
223: $tasklists = array($tasklists);
224: }
225: if (is_null($completed)) {
226: $completed = $prefs->getValue('show_completed');
227: }
228:
229: $tasks = new Nag_Task();
230: foreach ($tasklists as $tasklist) {
231:
232: $storage = Nag_Driver::singleton($tasklist);
233:
234:
235: $result = $storage->retrieve($completed);
236: $tasks->mergeChildren($storage->tasks->children);
237: }
238:
239:
240: $tasks->process();
241:
242:
243: $apps = @unserialize($prefs->getValue('show_external'));
244: if (is_array($apps)) {
245: foreach ($apps as $app) {
246: if ($app != 'nag' &&
247: $registry->hasMethod('getListTypes', $app)) {
248: try {
249: $types = $registry->callByPackage($app, 'getListTypes');
250: } catch (Horde_Exception $e) {
251: continue;
252: }
253: if (!empty($types['taskHash'])) {
254: try {
255: $newtasks = $registry->callByPackage($app, 'listAs', array('taskHash'));
256: foreach ($newtasks as $task) {
257: $task['tasklist_id'] = '**EXTERNAL**';
258: $task['tasklist_name'] = $registry->get('name', $app);
259: $tasks->add(new Nag_Task($task));
260: }
261: } catch (Horde_Exception $e) {
262: Horde::logMessage($newtasks, 'ERR');
263: }
264: }
265: }
266: }
267: }
268:
269:
270: $tasks->sort($sortby, $sortdir, $altsortby);
271:
272: return $tasks;
273: }
274:
275: 276: 277: 278: 279: 280: 281: 282:
283: public static function getTask($tasklist, $task)
284: {
285: $storage = Nag_Driver::singleton($tasklist);
286: $task = $storage->get($task);
287: $task->process();
288: return $task;
289: }
290:
291: 292: 293: 294: 295:
296: public static function countTasks()
297: {
298: static $count;
299: if (isset($count)) {
300: return $count;
301: }
302:
303: $tasklists = self::listTasklists(true, Horde_Perms::ALL);
304:
305: $count = 0;
306: foreach (array_keys($tasklists) as $tasklist) {
307:
308: $storage = Nag_Driver::singleton($tasklist);
309: $storage->retrieve();
310:
311:
312: $count += $storage->tasks->count();
313: }
314:
315: return $count;
316: }
317:
318: 319: 320: 321: 322: 323: 324: 325: 326: 327:
328: public static function createTasksFromText($text, $tasklist = null)
329: {
330: if ($tasklist === null) {
331: $tasklist = self::getDefaultTasklist(Horde_Perms::EDIT);
332: } elseif (!self::hasPermission($tasklist, Horde_Perms::EDIT)) {
333: return PEAR::raiseError(_("Permission Denied"));
334: }
335:
336: $storage = Nag_Driver::singleton($tasklist);
337: $dateParser = Horde_Date_Parser::factory(
338: array('locale' => $GLOBALS['prefs']->getValue('language')) );
339:
340: $quickParser = new Nag_QuickParser();
341: $tasks = $quickParser->parse($text);
342:
343: $uids = array();
344: foreach ($tasks as &$task) {
345: if (!is_array($task)) {
346: $name = $task;
347: $task = array($name);
348: }
349:
350: $r = $dateParser->parse($task[0], array('return' => 'result'));
351: if ($d = $r->guess()) {
352: $name = $r->untaggedText();
353: $due = $d->timestamp();
354: } else {
355: $name = $task[0];
356: $due = 0;
357: }
358:
359: if (isset($task['parent'])) {
360: $newTask = $storage->add($name, '', 0, $due, 3, 0.0, 0, '', 0, null, null, $tasks[$task['parent']]['id']);
361: } else {
362: $newTask = $storage->add($name, '', 0, $due, 3);
363: }
364: $uids[] = $newTask[1];
365: $task['id'] = $newTask[0];
366: }
367:
368: return $uids;
369: }
370:
371: 372: 373: 374: 375: 376: 377: 378:
379: public static function listAlarms($date, array $tasklists = null)
380: {
381: if (is_null($tasklists)) {
382: $tasklists = $GLOBALS['display_tasklists'];
383: }
384:
385: $tasks = array();
386: foreach ($tasklists as $tasklist) {
387:
388: $storage = Nag_Driver::singleton($tasklist);
389:
390:
391: $newtasks = $storage->listAlarms($date);
392:
393:
394: foreach ($newtasks as $taskID => $task) {
395: if (!empty($task->completed)) {
396: unset($newtasks[$taskID]);
397: }
398: }
399:
400: $tasks = array_merge($tasks, $newtasks);
401: }
402:
403: return $tasks;
404: }
405:
406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420:
421: public static function listTasklists($owneronly = false,
422: $permission = Horde_Perms::SHOW)
423: {
424: if ($owneronly && !$GLOBALS['registry']->getAuth()) {
425: return array();
426: }
427:
428: if ($owneronly || empty($GLOBALS['conf']['share']['hidden'])) {
429: try {
430: $tasklists = $GLOBALS['nag_shares']->listShares(
431: $GLOBALS['registry']->getAuth(),
432: array('perm' => $permission,
433: 'attributes' => $owneronly ? $GLOBALS['registry']->getAuth() : null,
434: 'sort_by' => 'name'));
435: } catch (Horde_Share_Exception $e) {
436: Horde::logMessage($e->getMessage(), 'ERR');
437: return array();
438: }
439: } else {
440: try {
441: $tasklists = $GLOBALS['nag_shares']->listShares(
442: $GLOBALS['registry']->getAuth(),
443: array('perm' => $permission,
444: 'attributes' => $GLOBALS['registry']->getAuth(),
445: 'sort_by' => 'name'));
446: } catch (Horde_Share_Exception $e) {
447: Horde::logMessage($e);
448: return array();
449: }
450: $display_tasklists = @unserialize($GLOBALS['prefs']->getValue('display_tasklists'));
451: if (is_array($display_tasklists)) {
452: foreach ($display_tasklists as $id) {
453: try {
454: $tasklist = $GLOBALS['nag_shares']->getShare($id);
455: if ($tasklist->hasPermission($GLOBALS['registry']->getAuth(), $permission)) {
456: $tasklists[$id] = $tasklist;
457: }
458: } catch (Horde_Exception_NotFound $e) {
459: } catch (Horde_Share_Exception $e) {
460: Horde::logMessage($e);
461: return array();
462: }
463: }
464: }
465: }
466:
467: return $tasklists;
468: }
469:
470: 471: 472: 473: 474: 475: 476: 477: 478:
479: public static function permissionsFilter(array $in, $permission = Horde_Perms::READ)
480: {
481:
482:
483:
484: return $in;
485:
486:
487: $out = array();
488:
489: foreach ($in as $sourceId => $source) {
490: if ($in->hasPermission($permission)) {
491: $out[$sourceId] = $source;
492: }
493: }
494:
495: return $out;
496: }
497:
498: 499: 500: 501: 502: 503: 504: 505: 506: 507:
508: static public function hasPermission($tasklist, $perm)
509: {
510: try {
511: $share = $GLOBALS['nag_shares']->getShare($tasklist);
512: if (!$share->hasPermission($GLOBALS['registry']->getAuth(), $perm)) {
513: throw new Horde_Exception_NotFound();
514: }
515: } catch (Horde_Exception_NotFound $e) {
516: return false;
517: }
518: return true;
519: }
520:
521: 522: 523: 524: 525: 526: 527: 528:
529: public static function getDefaultTasklist($permission = Horde_Perms::SHOW)
530: {
531: global $prefs;
532:
533: $default_tasklist = $prefs->getValue('default_tasklist');
534: $tasklists = self::listTasklists(false, $permission);
535:
536: if (isset($tasklists[$default_tasklist])) {
537: return $default_tasklist;
538: } elseif ($prefs->isLocked('default_tasklist')) {
539: return $GLOBALS['registry']->getAuth();
540: } elseif (count($tasklists)) {
541: reset($tasklists);
542: return key($tasklists);
543: }
544:
545: return false;
546: }
547:
548: 549: 550: 551: 552: 553: 554:
555: public static function addTasklist(array $info)
556: {
557: try {
558: $tasklist = $GLOBALS['nag_shares']->newShare($GLOBALS['registry']->getAuth(), strval(new Horde_Support_Randomid()), $info['name']);
559: $tasklist->set('color', $info['color']);
560: $tasklist->set('desc', $info['description']);
561: if (!empty($info['system'])) {
562: $tasklist->set('owner', null);
563: }
564:
565: $GLOBALS['nag_shares']->addShare($tasklist);
566: } catch (Horde_Share_Exception $e) {
567: throw new Nag_Exception($e);
568: }
569:
570: $GLOBALS['display_tasklists'][] = $tasklist->getName();
571: $GLOBALS['prefs']->setValue('display_tasklists', serialize($GLOBALS['display_tasklists']));
572:
573: return $tasklist;
574: }
575:
576: 577: 578: 579: 580: 581: 582: 583: 584:
585: public static function updateTasklist(Horde_Share_Object $tasklist, array $info)
586: {
587: if (!$GLOBALS['registry']->getAuth() ||
588: ($tasklist->get('owner') != $GLOBALS['registry']->getAuth() &&
589: (!is_null($tasklist->get('owner')) || !$GLOBALS['registry']->isAdmin()))) {
590:
591: throw new Horde_Exception_PermissionDenied(_("You are not allowed to change this task list."));
592: }
593:
594: $tasklist->set('name', $info['name']);
595: $tasklist->set('color', $info['color']);
596: $tasklist->set('desc', $info['description']);
597: $tasklist->set('owner', empty($info['system']) ? $GLOBALS['registry']->getAuth() : null);
598:
599: try {
600: $tasklist->save();
601: } catch (Horde_Share_Exception $e) {
602: throw new Nag_Exception(sprintf(_("Unable to save task list \"%s\": %s"), $info['name'], $e->getMessage()));
603: }
604: }
605:
606: 607: 608: 609: 610: 611: 612:
613: public static function deleteTasklist(Horde_Share_Object $tasklist)
614: {
615: if (!$GLOBALS['registry']->getAuth() ||
616: ($tasklist->get('owner') != $GLOBALS['registry']->getAuth() &&
617: (!is_null($tasklist->get('owner')) || !$GLOBALS['registry']->isAdmin()))) {
618: throw new Horde_Exception_PermissionDenied(_("You are not allowed to delete this task list."));
619: }
620:
621:
622: $storage = &Nag_Driver::singleton($tasklist->getName());
623: $result = $storage->deleteAll();
624:
625:
626: try {
627: return $GLOBALS['nag_shares']->removeShare($tasklist);
628: } catch (Horde_Share_Exception $e) {
629: throw new Nag_Exception($e);
630: }
631: }
632:
633: 634: 635: 636: 637: 638: 639: 640:
641: public static function buildPriorityWidget($name, $selected = -1)
642: {
643: $descs = array(1 => _("(highest)"), 5 => _("(lowest)"));
644:
645: $html = "<select id=\"$name\" name=\"$name\">";
646: for ($priority = 1; $priority <= 5; $priority++) {
647: $html .= "<option value=\"$priority\"";
648: $html .= ($priority == $selected) ? ' selected="selected">' : '>';
649: $html .= $priority . ' ' . @$descs[$priority] . '</option>';
650: }
651: $html .= "</select>\n";
652:
653: return $html;
654: }
655:
656: 657: 658: 659: 660: 661: 662: 663:
664: public static function buildCheckboxWidget($name, $checked = 0)
665: {
666: $name = htmlspecialchars($name);
667: return "<input type=\"checkbox\" id=\"$name\" name=\"$name\"" .
668: ($checked ? ' checked="checked"' : '') . ' />';
669: }
670:
671: 672: 673: 674: 675: 676: 677: 678:
679: public static function formatDate($unixdate = '', $hours = true)
680: {
681: global $prefs;
682:
683: if (empty($unixdate)) {
684: return '';
685: }
686:
687: $date = strftime($prefs->getValue('date_format'), $unixdate);
688: if (!$hours) {
689: return $date;
690: }
691:
692: return sprintf(_("%s at %s"),
693: $date,
694: strftime($prefs->getValue('twentyFour') ? '%H:%M' : '%I:%M %p', $unixdate));
695: }
696:
697: 698: 699: 700: 701: 702: 703:
704: public static function formatCompletion($completed)
705: {
706: return $completed ?
707: Horde::img('checked.png', _("Completed")) :
708: Horde::img('unchecked.png', _("Not Completed"));
709: }
710:
711: 712: 713: 714: 715: 716: 717:
718: public static function formatPriority($priority)
719: {
720: return '<span class="pri-' . (int)$priority . '">' . (int)$priority .
721: '</span>';
722: }
723:
724: 725: 726: 727: 728: 729: 730:
731: public static function formatAlarm($value)
732: {
733: if ($value) {
734: if ($value % 10080 == 0) {
735: $alarm_value = $value / 10080;
736: $alarm_unit = _("Week(s)");
737: } elseif ($value % 1440 == 0) {
738: $alarm_value = $value / 1440;
739: $alarm_unit = _("Day(s)");
740: } elseif ($value % 60 == 0) {
741: $alarm_value = $value / 60;
742: $alarm_unit = _("Hour(s)");
743: } else {
744: $alarm_value = $value;
745: $alarm_unit = _("Minute(s)");
746: }
747: $alarm_text = "$alarm_value $alarm_unit";
748: } else {
749: $alarm_text = _("None");
750: }
751: return $alarm_text;
752: }
753:
754: 755: 756: 757: 758: 759: 760: 761:
762: public static function formatAssignee($assignee, $link = false)
763: {
764: if (!strlen($assignee)) {
765: return '';
766: }
767:
768: $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($assignee);
769: $fullname = $identity->getValue('fullname');
770: if (!strlen($fullname)) {
771: $fullname = $assignee;
772: }
773: $email = $identity->getValue('from_addr');
774: if ($link && !empty($email) &&
775: $GLOBALS['registry']->hasMethod('mail/compose')) {
776: return Horde::link($GLOBALS['registry']->call(
777: 'mail/compose',
778: array(array('to' => $email))))
779: . htmlspecialchars($fullname . ' <' . $email . '>')
780: . '</a>';
781: }
782:
783: return htmlspecialchars($fullname);
784: }
785:
786: 787: 788:
789: public static function initialize()
790: {
791:
792: if (!isset($_SERVER['REQUEST_TIME'])) {
793: $_SERVER['REQUEST_TIME'] = time();
794: }
795:
796:
797:
798:
799: $GLOBALS['display_tasklists'] = @unserialize($GLOBALS['prefs']->getValue('display_tasklists'));
800: if (!$GLOBALS['display_tasklists']) {
801: $GLOBALS['display_tasklists'] = array();
802: }
803: if (($tasklistId = Horde_Util::getFormData('display_tasklist')) !== null) {
804: if (is_array($tasklistId)) {
805: $GLOBALS['display_tasklists'] = $tasklistId;
806: } else {
807: if (in_array($tasklistId, $GLOBALS['display_tasklists'])) {
808: $key = array_search($tasklistId, $GLOBALS['display_tasklists']);
809: unset($GLOBALS['display_tasklists'][$key]);
810: } else {
811: $GLOBALS['display_tasklists'][] = $tasklistId;
812: }
813: }
814: }
815:
816:
817: $_temp = $GLOBALS['display_tasklists'];
818: $GLOBALS['all_tasklists'] = self::listTasklists();
819: $GLOBALS['display_tasklists'] = array();
820: foreach ($_temp as $id) {
821: if (isset($GLOBALS['all_tasklists'][$id])) {
822: $GLOBALS['display_tasklists'][] = $id;
823: }
824: }
825:
826:
827: if (!count($GLOBALS['display_tasklists']) &&
828: !$GLOBALS['registry']->getAuth()) {
829: $GLOBALS['display_tasklists'] = array_keys($GLOBALS['all_tasklists']);
830: }
831:
832: $tasklists = $GLOBALS['injector']->getInstance('Nag_Factory_Tasklists')
833: ->create();
834: if (($new_default = $tasklists->ensureDefaultShare()) !== null) {
835: $GLOBALS['display_tasklists'][] = $new_default;
836: }
837:
838: $GLOBALS['prefs']->setValue('display_tasklists', serialize($GLOBALS['display_tasklists']));
839: }
840:
841: public static function ()
842: {
843: Horde::startBuffer();
844: include NAG_TEMPLATES . '/quick.inc';
845: return Horde::menu() . Horde::endBuffer();
846: }
847:
848: 849: 850:
851: public static function status()
852: {
853: global $notification;
854:
855: if (empty($GLOBALS['conf']['alarms']['driver'])) {
856:
857: $now = time();
858: try {
859: $alarmList = self::listAlarms($now);
860: $messages = array();
861: foreach ($alarmList as $task) {
862: $differential = $task->due - $now;
863: $key = $differential;
864: while (isset($messages[$key])) {
865: $key++;
866: }
867: if ($differential >= -60 && $differential < 60) {
868: $messages[$key] = array(sprintf(_("%s is due now."), $task->name), 'horde.alarm');
869: } elseif ($differential >= 60) {
870: $messages[$key] = array(sprintf(_("%s is due in %s"), $task->name,
871: self::secondsToString($differential)), 'horde.alarm');
872: }
873: }
874:
875: ksort($messages);
876: foreach ($messages as $message) {
877: $notification->push($message[0], $message[1]);
878: }
879: } catch (Nag_Exception $e) {
880: Horde::logMessage($e, 'ERR');
881: $notification->push($e->getMessage(), 'horde.error');
882: }
883: }
884:
885:
886:
887: if (!$GLOBALS['registry']->getAuth() && !count(self::listTasklists())) {
888: $notification->push(_("No task lists are available to guests."));
889: }
890:
891:
892: $notification->notify(array('listeners' => 'status'));
893: }
894:
895: 896: 897: 898: 899: 900: 901: 902: 903: 904: 905:
906: public static function sendNotification($action, $task, $old_task = null)
907: {
908: if (!in_array($action, array('add', 'edit', 'delete'))) {
909: throw new Nag_Exception('Unknown event action: ' . $action);
910: }
911:
912: try {
913: $share = $GLOBALS['nag_shares']->getShare($task->tasklist);
914: } catch (Horde_Share_Exception $e) {
915: Horde::logMessage($e->getMessage(), 'ERR');
916: throw new Nag_Exception($e);
917: }
918:
919: $groups = $GLOBALS['injector']->getInstance('Horde_Group');
920: $recipients = array();
921: $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create();
922: $from = $identity->getDefaultFromAddress(true);
923:
924: $owner = $share->get('owner');
925: if (strlen($owner)) {
926: $recipients[$owner] = self::_notificationPref($owner, 'owner');
927: }
928:
929: foreach ($share->listUsers(Horde_Perms::READ) as $user) {
930: if (empty($recipients[$user])) {
931: $recipients[$user] = self::_notificationPref($user, 'read', $task->tasklist);
932: }
933: }
934: foreach ($share->listGroups(Horde_Perms::READ) as $group) {
935: try {
936: $group_users = $groups->listUsers($group);
937: } catch (Horde_Group_Exception $e) {
938: Horde::logMessage($e, 'ERR');
939: continue;
940: }
941:
942: foreach ($group_users as $user) {
943: if (empty($recipients[$user])) {
944: $recipients[$user] = self::_notificationPref($user, 'read', $task->tasklist);
945: }
946: }
947: }
948:
949: $addresses = array();
950: foreach ($recipients as $user => $vals) {
951: if (!$vals) {
952: continue;
953: }
954: $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($user);
955: $email = $identity->getValue('from_addr');
956: if (strpos($email, '@') === false) {
957: continue;
958: }
959: list($mailbox, $host) = explode('@', $email);
960: if (!isset($addresses[$vals['lang']][$vals['tf']][$vals['df']])) {
961: $addresses[$vals['lang']][$vals['tf']][$vals['df']] = array();
962: }
963: $addresses[$vals['lang']][$vals['tf']][$vals['df']][] = Horde_Mime_Address::writeAddress($mailbox, $host, $identity->getValue('fullname'));
964: }
965:
966: if (!$addresses) {
967: return;
968: }
969:
970: $mail = new Horde_Mime_Mail(array(
971: 'User-Agent' => 'Nag ' . $GLOBALS['registry']->getVersion(),
972: 'Precedence' => 'bulk',
973: 'Auto-Submitted' => 'auto-generated',
974: 'From' => $from));
975:
976: foreach ($addresses as $lang => $twentyFour) {
977: $GLOBALS['registry']->setLanguageEnvironment($lang);
978:
979: $view_link = Horde_Util::addParameter(Horde::url('view.php', true),
980: array('tasklist' => $task->tasklist,
981: 'task' => $task->id),
982: null, false);
983:
984: switch ($action) {
985: case 'add':
986: $subject = _("Task added:");
987: $notification_message = _("You requested to be notified when tasks are added to your task lists.")
988: . "\n\n"
989: . ($task->due
990: ? _("The task \"%s\" has been added to task list \"%s\", with a due date of: %s.")
991: : _("The task \"%s\" has been added to task list \"%s\"."))
992: . "\n"
993: . str_replace('%', '%%', $view_link);
994: break;
995:
996: case 'edit':
997: $subject = _("Task modified:");
998: $notification_message = _("You requested to be notified when tasks are edited on your task lists.")
999: . "\n\n"
1000: . _("The task \"%s\" has been edited on task list \"%s\".")
1001: . "\n"
1002: . str_replace('%', '%%', $view_link)
1003: . "\n\n"
1004: . _("Changes made for this task:");
1005: if ($old_task->name != $task->name) {
1006: $notification_message .= "\n - "
1007: . sprintf(_("Changed name from \"%s\" to \"%s\""),
1008: $old_task->name, $task->name);
1009: }
1010: if ($old_task->tasklist != $task->tasklist) {
1011: $old_share = $GLOBALS['nag_shares']->getShare($old_task->tasklist);
1012: $notification_message .= "\n - "
1013: . sprintf(_("Changed task list from \"%s\" to \"%s\""),
1014: $old_share->get('name'), $share->get('name'));
1015: }
1016: if ($old_task->parent_id != $task->parent_id) {
1017: $old_parent = $old_task->getParent();
1018: try {
1019: $parent = $task->getParent();
1020: $notification_message .= "\n - "
1021: . sprintf(_("Changed parent task from \"%s\" to \"%s\""),
1022: $old_parent ? $old_parent->name : _("no parent"),
1023: $parent ? $parent->name : _("no parent"));
1024: } catch (Nag_Exception $e) {
1025: }
1026: }
1027: if ($old_task->category != $task->category) {
1028: $notification_message .= "\n - "
1029: . sprintf(_("Changed category from \"%s\" to \"%s\""),
1030: $old_task->category, $task->category);
1031: }
1032: if ($old_task->assignee != $task->assignee) {
1033: $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($old_task->assignee);
1034: $old_name = $identity->getValue('fullname');
1035: if (!strlen($old_name)) {
1036: $old_name = $old_task->assignee;
1037: }
1038: $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($task->assignee);
1039: $new_name = $identity->getValue('fullname');
1040: if (!strlen($new_name)) {
1041: $new_name = $new_task->assignee;
1042: }
1043: $notification_message .= "\n - "
1044: . sprintf(_("Changed assignee from \"%s\" to \"%s\""),
1045: $old_name, $new_name);
1046: }
1047: if ($old_task->private != $task->private) {
1048: $notification_message .= "\n - "
1049: . ($task->private ? _("Turned privacy on") : _("Turned privacy off"));
1050: }
1051: if ($old_task->due != $task->due) {
1052: $notification_message .= "\n - "
1053: . sprintf(_("Changed due date from %s to %s"),
1054: $old_task->due ? self::formatDate($old_task->due) : _("no due date"),
1055: $task->due ? self::formatDate($task->due) : _("no due date"));
1056: }
1057: if ($old_task->start != $task->start) {
1058: $notification_message .= "\n - "
1059: . sprintf(_("Changed start date from %s to %s"),
1060: $old_task->start ? self::formatDate($old_task->start) : _("no start date"),
1061: $task->start ? self::formatDate($task->start) : _("no start date"));
1062: }
1063: if ($old_task->alarm != $task->alarm) {
1064: $notification_message .= "\n - "
1065: . sprintf(_("Changed alarm from %s to %s"),
1066: self::formatAlarm($old_task->alarm), self::formatAlarm($task->alarm));
1067: }
1068: if ($old_task->priority != $task->priority) {
1069: $notification_message .= "\n - "
1070: . sprintf(_("Changed priority from %s to %s"),
1071: $old_task->priority, $task->priority);
1072: }
1073: if ($old_task->estimate != $task->estimate) {
1074: $notification_message .= "\n - "
1075: . sprintf(_("Changed estimate from %s to %s"),
1076: $old_task->estimate, $task->estimate);
1077: }
1078: if ($old_task->completed != $task->completed) {
1079: $notification_message .= "\n - "
1080: . sprintf(_("Changed completion from %s to %s"),
1081: $old_task->completed ? _("completed") : _("not completed"),
1082: $task->completed ? _("completed") : _("not completed"));
1083: }
1084: if ($old_task->desc != $task->desc) {
1085: $notification_message .= "\n - " . _("Changed description");
1086: }
1087: break;
1088:
1089: case 'delete':
1090: $subject = _("Task deleted:");
1091: $notification_message =
1092: _("You requested to be notified when tasks are deleted from your task lists.")
1093: . "\n\n"
1094: . _("The task \"%s\" has been deleted from task list \"%s\".");
1095: break;
1096: }
1097:
1098: $mail->addHeader('Subject', $subject . ' ' . $task->name);
1099:
1100: foreach ($twentyFour as $tf => $dateFormat) {
1101: foreach ($dateFormat as $df => $df_recipients) {
1102: $message = sprintf($notification_message,
1103: $task->name,
1104: $share->get('name'),
1105: $task->due ? strftime($df, $task->due) . ' ' . date($tf ? 'H:i' : 'h:ia', $task->due) : '');
1106: if (strlen(trim($task->desc))) {
1107: $message .= "\n\n" . _("Task description:") . "\n\n" . $task->desc;
1108: }
1109:
1110: $mail->setBody($message);
1111: $mail->clearRecipients();
1112: $mail->addRecipients($df_recipients);
1113:
1114: Horde::logMessage(sprintf('Sending event notifications for %s to %s',
1115: $task->name, implode(', ', $df_recipients)), 'INFO');
1116: $mail->send($GLOBALS['injector']->getInstance('Horde_Mail'));
1117: }
1118: }
1119: }
1120: }
1121:
1122: 1123: 1124: 1125: 1126: 1127: 1128: 1129: 1130: 1131:
1132: public static function buildMimeMessage(Horde_View $view, $template,
1133: Horde_Mime_Part $image)
1134: {
1135: $multipart = new Horde_Mime_Part();
1136: $multipart->setType('multipart/alternative');
1137: $bodyText = new Horde_Mime_Part();
1138: $bodyText->setType('text/plain');
1139: $bodyText->setCharset('UTF-8');
1140: $bodyText->setContents($view->render($template . '.plain.php'));
1141: $bodyText->setDisposition('inline');
1142: $multipart->addPart($bodyText);
1143: $bodyHtml = new Horde_Mime_Part();
1144: $bodyHtml->setType('text/html');
1145: $bodyHtml->setCharset('UTF-8');
1146: $bodyHtml->setContents($view->render($template . '.html.php'));
1147: $bodyHtml->setDisposition('inline');
1148: $related = new Horde_Mime_Part();
1149: $related->setType('multipart/related');
1150: $related->setContentTypeParameter('start', $bodyHtml->setContentId());
1151: $related->addPart($bodyHtml);
1152: $related->addPart($image);
1153: $multipart->addPart($related);
1154: return $multipart;
1155: }
1156:
1157: 1158: 1159: 1160: 1161: 1162: 1163:
1164: public static function getImagePart($file)
1165: {
1166: $background = Horde_Themes::img($file);
1167: $image = new Horde_Mime_Part();
1168: $image->setType('image/png');
1169: $image->setContents(file_get_contents($background->fs));
1170: $image->setContentId();
1171: $image->setDisposition('attachment');
1172: return $image;
1173: }
1174:
1175: 1176: 1177: 1178: 1179: 1180: 1181:
1182: public static function getUserName($uid)
1183: {
1184: static $names = array();
1185:
1186: if (!isset($names[$uid])) {
1187: $ident = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($uid);
1188: $ident->setDefault($ident->getDefault());
1189: $names[$uid] = $ident->getValue('fullname');
1190: if (empty($names[$uid])) {
1191: $names[$uid] = $uid;
1192: }
1193: }
1194:
1195: return $names[$uid];
1196: }
1197:
1198: 1199: 1200: 1201: 1202: 1203: 1204: 1205: 1206: 1207: 1208: 1209: 1210: 1211: 1212: 1213: 1214: 1215: 1216: 1217:
1218: public static function _notificationPref($user, $mode, $tasklist = null)
1219: {
1220: $prefs = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Prefs')->create('nag', array(
1221: 'cache' => false,
1222: 'user' => $user
1223: ));
1224: $vals = array('lang' => $prefs->getValue('language'),
1225: 'tf' => $prefs->getValue('twentyFour'),
1226: 'df' => $prefs->getValue('date_format'));
1227:
1228: if ($prefs->getValue('task_notification_exclude_self') &&
1229: $user == $GLOBALS['registry']->getAuth()) {
1230: return false;
1231: }
1232:
1233: $notification = $prefs->getValue('task_notification');
1234: switch ($notification) {
1235: case 'owner':
1236: return $mode == 'owner' ? $vals : false;
1237: case 'read':
1238: return $mode == 'read' ? $vals : false;
1239: case 'show':
1240: if ($mode == 'read') {
1241: $display_tasklists = unserialize($prefs->getValue('display_tasklists'));
1242: return in_array($tasklist, $display_tasklists) ? $vals : false;;
1243: }
1244: }
1245:
1246: return false;
1247: }
1248:
1249: 1250: 1251: 1252: 1253: 1254: 1255: 1256: 1257: 1258: 1259:
1260: public static function _sortByIdentity($a, $b)
1261: {
1262: return strcmp($a->id, $b->id);
1263: }
1264:
1265: 1266: 1267: 1268: 1269: 1270: 1271: 1272: 1273:
1274: public static function _sortByPriority($a, $b)
1275: {
1276: if ($a->priority == $b->priority) {
1277: return self::_sortByIdentity($a, $b);
1278: }
1279: return ($a->priority > $b->priority) ? 1 : -1;
1280: }
1281:
1282: 1283: 1284: 1285: 1286: 1287: 1288: 1289: 1290:
1291: public static function _rsortByPriority($a, $b)
1292: {
1293: return self::_sortByPriority($b, $a);
1294: }
1295:
1296: 1297: 1298: 1299: 1300: 1301: 1302: 1303: 1304:
1305: public static function _sortByName($a, $b)
1306: {
1307: return strcasecmp($a->name, $b->name);
1308: }
1309:
1310: 1311: 1312: 1313: 1314: 1315: 1316: 1317: 1318:
1319: public static function _rsortByName($a, $b)
1320: {
1321: return strcasecmp($b->name, $a->name);
1322: }
1323:
1324: 1325: 1326: 1327: 1328: 1329: 1330: 1331: 1332:
1333: public static function _sortByAssignee($a, $b)
1334: {
1335: return strcasecmp($a->assignee, $b->assignee);
1336: }
1337:
1338: 1339: 1340: 1341: 1342: 1343: 1344: 1345: 1346:
1347: public static function _rsortByAssignee($a, $b)
1348: {
1349: return strcasecmp($b->assignee, $a->assignee);
1350: }
1351:
1352: 1353: 1354: 1355: 1356: 1357: 1358: 1359: 1360:
1361: public static function _sortByEstimate($a, $b)
1362: {
1363: $a_est = $a->estimation();
1364: $b_est = $b->estimation();
1365: if ($a_est == $b_est) {
1366: return self::_sortByIdentity($a, $b);
1367: }
1368: return ($a_est > $b_est) ? 1 : -1;
1369: }
1370:
1371: 1372: 1373: 1374: 1375: 1376: 1377: 1378: 1379:
1380: public static function _rsortByEstimate($a, $b)
1381: {
1382: return self::_sortByEstimate($b, $a);
1383: }
1384:
1385: 1386: 1387: 1388: 1389: 1390: 1391: 1392: 1393:
1394: public static function _sortByCategory($a, $b)
1395: {
1396: return strcasecmp($a->category ? $a->category : _("Unfiled"),
1397: $b->category ? $b->category : _("Unfiled"));
1398: }
1399:
1400: 1401: 1402: 1403: 1404: 1405: 1406: 1407: 1408:
1409: public static function _rsortByCategory($a, $b)
1410: {
1411: return self::_sortByCategory($b, $a);
1412: }
1413:
1414: 1415: 1416: 1417: 1418: 1419: 1420: 1421: 1422:
1423: public static function _sortByDue($a, $b)
1424: {
1425: if ($a->due == $b->due) {
1426: return self::_sortByIdentity($a, $b);
1427: }
1428:
1429:
1430: if ($a->due == 0) {
1431: return 1;
1432: }
1433: if ($b->due == 0) {
1434: return -1;
1435: }
1436:
1437: return ($a->due > $b->due) ? 1 : -1;
1438: }
1439:
1440: 1441: 1442: 1443: 1444: 1445: 1446: 1447: 1448:
1449: public static function _rsortByDue($a, $b)
1450: {
1451: return self::_sortByDue($b, $a);
1452: }
1453:
1454: 1455: 1456: 1457: 1458: 1459: 1460: 1461: 1462:
1463: public static function _sortByStart($a, $b)
1464: {
1465: if ($a->start == $b->start) {
1466: return self::_sortByIdentity($a, $b);
1467: }
1468:
1469:
1470: if ($a->start == 0) {
1471: return 1;
1472: }
1473: if ($b->start == 0) {
1474: return -1;
1475: }
1476:
1477: return ($a->start > $b->start) ? 1 : -1;
1478: }
1479:
1480: 1481: 1482: 1483: 1484: 1485: 1486: 1487: 1488:
1489: public static function _rsortByStart($a, $b)
1490: {
1491: return self::_sortByStart($b, $a);
1492: }
1493:
1494: 1495: 1496: 1497: 1498: 1499: 1500: 1501: 1502:
1503: public static function _sortByCompletion($a, $b)
1504: {
1505: if ($a->completed == $b->completed) {
1506: return self::_sortByIdentity($a, $b);
1507: }
1508: return ($a->completed > $b->completed) ? -1 : 1;
1509: }
1510:
1511: 1512: 1513: 1514: 1515: 1516: 1517: 1518: 1519:
1520: public static function _rsortByCompletion($a, $b)
1521: {
1522: return self::_sortByCompletion($b, $a);
1523: }
1524:
1525: 1526: 1527: 1528: 1529: 1530: 1531: 1532: 1533:
1534: public static function _sortByOwner($a, $b)
1535: {
1536: $diff = strcasecmp(self::_getOwner($a), self::_getOwner($b));
1537: if ($diff == 0) {
1538: return self::_sortByIdentity($a, $b);
1539: } else {
1540: return $diff;
1541: }
1542: }
1543:
1544: 1545: 1546: 1547: 1548: 1549: 1550: 1551: 1552:
1553: public static function _rsortByOwner($a, $b)
1554: {
1555: return self::_sortByOwner($b, $a);
1556: }
1557:
1558: 1559: 1560: 1561: 1562: 1563: 1564:
1565: static protected function _getOwner($task)
1566: {
1567: if ($task->tasklist == '**EXTERNAL**') {
1568: return $GLOBALS['registry']->getAuth();
1569: }
1570: $share = $GLOBALS['nag_shares']->getShare($task->tasklist);
1571: $owner = $task->tasklist;
1572: if ($owner != $share->get('owner')) {
1573: $owner = $share->get('name');
1574: }
1575: return $owner;
1576: }
1577:
1578: 1579: 1580: 1581: 1582:
1583: static public function getSyncLists()
1584: {
1585: $cs = unserialize($GLOBALS['prefs']->getValue('sync_lists'));
1586: if (!empty($cs)) {
1587:
1588: $lists = self::listTasklists(false, Horde_Perms::EDIT);
1589: $cscopy = array_flip($cs);
1590: foreach ($cs as $c) {
1591: if (empty($lists[$c])) {
1592: unset($cscopy[$c]);
1593: }
1594: }
1595:
1596:
1597: if (count($cscopy)) {
1598: return array_flip($cscopy);
1599: }
1600: }
1601:
1602: if ($cs = self::getDefaultTasklist(Horde_Perms::EDIT)) {
1603: return array($cs);
1604: }
1605:
1606: return array();
1607: }
1608:
1609: }
1610: