1: <?php
2: 3: 4: 5: 6: 7: 8: 9:
10:
11: 12: 13: 14: 15: 16:
17: class Kronolith
18: {
19:
20: const STATUS_NONE = 0;
21: const STATUS_TENTATIVE = 1;
22: const STATUS_CONFIRMED = 2;
23: const STATUS_CANCELLED = 3;
24: const STATUS_FREE = 4;
25:
26:
27: const RESPONSE_NONE = 1;
28: const RESPONSE_ACCEPTED = 2;
29: const RESPONSE_DECLINED = 3;
30: const RESPONSE_TENTATIVE = 4;
31:
32:
33: const PART_REQUIRED = 1;
34: const PART_OPTIONAL = 2;
35: const PART_NONE = 3;
36: const PART_IGNORE = 4;
37:
38:
39: const ITIP_REQUEST = 1;
40: const ITIP_CANCEL = 2;
41:
42:
43: const PERMS_DELEGATE = 1024;
44:
45: 46: 47: 48: 49:
50: static private $_instances = array();
51:
52: 53: 54:
55: static private $_tagger;
56:
57: 58: 59: 60:
61: static public function header()
62: {
63:
64: $datejs = str_replace('_', '-', $GLOBALS['language']) . '.js';
65: if (!file_exists($GLOBALS['registry']->get('jsfs', 'horde') . '/date/' . $datejs)) {
66: $datejs = 'en-US.js';
67: }
68: Horde::addScriptFile('effects.js', 'horde');
69: Horde::addScriptFile('sound.js', 'horde');
70: Horde::addScriptFile('horde.js', 'horde');
71: Horde::addScriptFile('dragdrop2.js', 'kronolith');
72: Horde::addScriptFile('growler.js', 'horde');
73: Horde::addScriptFile('redbox.js', 'horde');
74: Horde::addScriptFile('tooltips.js', 'horde');
75: Horde::addScriptFile('colorpicker.js', 'horde');
76: Horde::addScriptFile('date/' . $datejs, 'horde');
77: Horde::addScriptFile('date/date.js', 'horde');
78: Horde::addScriptFile('kronolith.js', 'kronolith');
79: Horde_Core_Ui_JsCalendar::init(array('short_weekdays' => true));
80:
81: if (isset($GLOBALS['language'])) {
82: header('Content-type: text/html; charset=UTF-8');
83: header('Vary: Accept-Language');
84: }
85:
86: echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">' . "\n" .
87: (!empty($GLOBALS['language']) ? '<html lang="' . strtr($GLOBALS['language'], '_', '-') . '"' : '<html') . ">\n".
88: "<head>\n" .
89: '<title>' . htmlspecialchars($GLOBALS['registry']->get('name')) . "</title>\n";
90:
91: Horde::includeFavicon();
92: echo Horde::wrapInlineScript(self::includeJSVars());
93: Horde::includeStylesheetFiles();
94:
95: echo "</head>\n";
96:
97:
98:
99:
100: echo Horde::endBuffer();
101: flush();
102: }
103:
104: 105: 106: 107: 108: 109: 110: 111:
112: static public function includeJSVars()
113: {
114: global $prefs, $registry;
115:
116: $kronolith_webroot = $registry->get('webroot');
117: $horde_webroot = $registry->get('webroot', 'horde');
118: $has_tasks = self::hasApiPermission('tasks');
119: $app_urls = array();
120: if (isset($GLOBALS['conf']['menu']['apps']) &&
121: is_array($GLOBALS['conf']['menu']['apps'])) {
122: foreach ($GLOBALS['conf']['menu']['apps'] as $app) {
123: $app_urls[$app] = (string)Horde::url($registry->getInitialPage($app), true)->add('ajaxui', 1);
124: }
125: }
126:
127:
128: $code['conf'] = array(
129: 'URI_AJAX' => (string)Horde::getServiceLink('ajax', 'kronolith'),
130: 'URI_SNOOZE' => (string)Horde::url($registry->get('webroot', 'horde') . '/services/snooze.php', true, -1),
131: 'URI_CALENDAR_EXPORT' => (string)Horde::url('data.php', true)->add(array('actionID' => 'export', 'all_events' => 1, 'exportID' => Horde_Data::EXPORT_ICALENDAR, 'exportCal' => 'internal_')),
132: 'URI_EVENT_EXPORT' => str_replace(array('%23', '%7B', '%7D'), array('#', '{', '}'), Horde::url('event.php', true)->add(array('view' => 'ExportEvent', 'eventID' => '#{id}', 'calendar' => '#{calendar}', 'type' => '#{type}'))),
133: 'SESSION_ID' => defined('SID') ? SID : '',
134: 'images' => array(
135: 'attendees' => (string)Horde_Themes::img('attendees-fff.png'),
136: 'alarm' => (string)Horde_Themes::img('alarm-fff.png'),
137: 'recur' => (string)Horde_Themes::img('recur-fff.png'),
138: 'exception' => (string)Horde_Themes::img('exception-fff.png'),
139: ),
140: 'user' => $GLOBALS['registry']->convertUsername($GLOBALS['registry']->getAuth(), false),
141: 'prefs_url' => (string)Horde::getServiceLink('prefs', 'kronolith')->setRaw(true)->add('ajaxui', 1),
142: 'app_urls' => $app_urls,
143: 'use_iframe' => !empty($GLOBALS['conf']['menu']['apps_iframe']),
144: 'name' => $registry->get('name'),
145: 'has_tasks' => (bool)$has_tasks,
146: 'is_ie6' => ($GLOBALS['browser']->isBrowser('msie') && ($GLOBALS['browser']->getMajor() < 7)),
147: 'login_view' => $prefs->getValue('defaultview') == 'workweek' ? 'week' : $prefs->getValue('defaultview'),
148: 'default_calendar' => 'internal|' . self::getDefaultCalendar(Horde_Perms::EDIT),
149: 'week_start' => (int)$prefs->getValue('week_start_monday'),
150: 'max_events' => (int)$prefs->getValue('max_events'),
151: 'date_format' => str_replace(array('%e', '%d', '%a', '%A', '%m', '%h', '%b', '%B', '%y', '%Y'),
152: array('d', 'dd', 'ddd', 'dddd', 'MM', 'MMM', 'MMM', 'MMMM', 'yy', 'yyyy'),
153: Horde_Nls::getLangInfo(D_FMT)),
154: 'time_format' => $prefs->getValue('twentyFour') ? 'HH:mm' : 'hh:mm tt',
155: 'show_time' => self::viewShowTime(),
156: 'default_alarm' => (int)$prefs->getValue('default_alarm'),
157: 'status' => array('tentative' => self::STATUS_TENTATIVE,
158: 'confirmed' => self::STATUS_CONFIRMED,
159: 'cancelled' => self::STATUS_CANCELLED,
160: 'free' => self::STATUS_FREE),
161: 'recur' => array(Horde_Date_Recurrence::RECUR_NONE => 'None',
162: Horde_Date_Recurrence::RECUR_DAILY => 'Daily',
163: Horde_Date_Recurrence::RECUR_WEEKLY => 'Weekly',
164: Horde_Date_Recurrence::RECUR_MONTHLY_DATE => 'Monthly',
165: Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY => 'Monthly',
166: Horde_Date_Recurrence::RECUR_YEARLY_DATE => 'Yearly',
167: Horde_Date_Recurrence::RECUR_YEARLY_DAY => 'Yearly',
168: Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY => 'Yearly'),
169: 'perms' => array('all' => Horde_Perms::ALL,
170: 'show' => Horde_Perms::SHOW,
171: 'read' => Horde_Perms::READ,
172: 'edit' => Horde_Perms::EDIT,
173: 'delete' => Horde_Perms::DELETE,
174: 'delegate' => self::PERMS_DELEGATE),
175: 'snooze' => array('0' => _("select..."),
176: '5' => _("5 minutes"),
177: '15' => _("15 minutes"),
178: '60' => _("1 hour"),
179: '360' => _("6 hours"),
180: '1440' => _("1 day")),
181: );
182: if (!empty($GLOBALS['conf']['logo']['link'])) {
183: $code['conf']['URI_HOME'] = $GLOBALS['conf']['logo']['link'];
184: }
185:
186: if ($has_tasks) {
187: $code['conf']['tasks'] = $registry->tasks->ajaxDefaults();
188: }
189:
190:
191:
192: foreach (array(true, false) as $my) {
193: foreach ($GLOBALS['all_calendars'] as $id => $calendar) {
194: $owner = $GLOBALS['registry']->getAuth() &&
195: $calendar->owner() == $GLOBALS['registry']->getAuth();
196: if (($my && $owner) || (!$my && !$owner)) {
197: $code['conf']['calendars']['internal'][$id] = $calendar->toHash();
198: }
199: }
200:
201:
202: if (!$has_tasks) {
203: continue;
204: }
205: foreach ($registry->tasks->listTasklists($my, Horde_Perms::SHOW) as $id => $tasklist) {
206: if (!isset($GLOBALS['all_external_calendars']['tasks/' . $id])) {
207: continue;
208: }
209: $owner = $GLOBALS['registry']->getAuth() &&
210: $tasklist->get('owner') == $GLOBALS['registry']->getAuth();
211: if (($my && $owner) || (!$my && !$owner)) {
212: $code['conf']['calendars']['tasklists']['tasks/' . $id] = $GLOBALS['all_external_calendars']['tasks/' . $id]->toHash();
213: }
214: }
215: }
216:
217:
218: foreach ($GLOBALS['all_external_calendars'] as $id => $calendar) {
219: if ($calendar->api() == 'tasks') {
220: continue;
221: }
222: if (!empty($GLOBALS['conf']['share']['hidden']) &&
223: !in_array($id, $GLOBALS['display_external_calendars'])) {
224: continue;
225: }
226: $code['conf']['calendars']['external'][$id] = $calendar->toHash();
227: }
228:
229:
230: foreach ($GLOBALS['all_remote_calendars'] as $url => $calendar) {
231: $code['conf']['calendars']['remote'][$url] = $calendar->toHash();
232: }
233:
234:
235: foreach ($GLOBALS['all_holidays'] as $id => $calendar) {
236: $code['conf']['calendars']['holiday'][$id] = $calendar->toHash();
237: }
238:
239:
240: $code['text'] = array(
241: 'ajax_error' => _("Error when communicating with the server."),
242: 'ajax_timeout' => _("There has been no contact with the server for several minutes. The server may be temporarily unavailable or network problems may be interrupting your session. You will not see any updates until the connection is restored."),
243: 'ajax_recover' => _("The connection to the server has been restored."),
244: 'alarm' => _("Alarm:"),
245: 'snooze' => sprintf(_("You can snooze it for %s or %s dismiss %s it entirely"), '#{time}', '#{dismiss_start}', '#{dismiss_end}'),
246: 'noalerts' => _("No Notifications"),
247: 'alerts' => sprintf(_("%s notifications"), '#{count}'),
248: 'hidelog' => _("Hide Notifications"),
249: 'growlerinfo' => _("This is the notification backlog"),
250: 'agenda' => _("Agenda"),
251: 'tasks' => _("Tasks"),
252: 'searching' => sprintf(_("Events matching \"%s\""), '#{term}'),
253: 'allday' => _("All day"),
254: 'more' => _("more..."),
255: 'prefs' => _("Preferences"),
256: 'shared' => _("Shared"),
257: 'external_category' => _("Other events"),
258: 'no_url' => _("You must specify a URL."),
259: 'no_calendar_title' => _("The calendar title must not be empty."),
260: 'no_tasklist_title' => _("The task list title must not be empty."),
261: 'delete_calendar' => _("Are you sure you want to delete this calendar and all the events in it?"),
262: 'delete_tasklist' => _("Are you sure you want to delete this task list and all the tasks in it?"),
263: 'wrong_auth' => _("The authentication information you specified wasn't accepted."),
264: 'geocode_error' => _("Unable to locate requested address"),
265: 'wrong_date_format' => sprintf(_("You used an unknown date format \"%s\". Please try something like \"%s\"."), '#{wrong}', '#{right}'),
266: 'wrong_time_format' => sprintf(_("You used an unknown time format \"%s\". Please try something like \"%s\"."), '#{wrong}', '#{right}'),
267: 'fix_form_values' => _("Please enter correct values in the form first."),
268: );
269: for ($i = 1; $i <= 12; ++$i) {
270: $code['text']['month'][$i - 1] = Horde_Nls::getLangInfo(constant('MON_' . $i));
271: }
272: for ($i = 1; $i <= 7; ++$i) {
273: $code['text']['weekday'][$i] = Horde_Nls::getLangInfo(constant('DAY_' . $i));
274: }
275: foreach (array(Horde_Date_Recurrence::RECUR_DAILY,
276: Horde_Date_Recurrence::RECUR_WEEKLY,
277: Horde_Date_Recurrence::RECUR_MONTHLY_DATE,
278: Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY,
279: Horde_Date_Recurrence::RECUR_YEARLY_DATE,
280: Horde_Date_Recurrence::RECUR_YEARLY_DAY,
281: Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY) as $recurType) {
282: $code['text']['recur'][$recurType] = self::recurToString($recurType);
283: }
284:
285: $code['text']['recur']['exception'] = _("Exception");
286:
287:
288: $code['conf']['maps'] = $GLOBALS['conf']['maps'];
289:
290: return Horde::addInlineJsVars(array(
291: 'var Kronolith' => $code
292: ), array('ret_vars' => true));
293: }
294:
295: 296: 297: 298: 299: 300: 301: 302: 303: 304:
305: static public function permissionToJson(Horde_Perms_Permission $perm)
306: {
307: $json = $perm->data;
308: if (isset($json['users'])) {
309: $users = array();
310: foreach ($json['users'] as $user => $value) {
311: if ($user == $GLOBALS['registry']->getAuth()) {
312: continue;
313: }
314: $user = $GLOBALS['registry']->convertUsername($user, false);
315: $users[$user] = $value;
316: }
317: if ($users) {
318: $json['users'] = $users;
319: } else {
320: unset($json['users']);
321: }
322: }
323: return $json;
324: }
325:
326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337:
338: static public function listAlarms($date, $calendars, $fullevent = false)
339: {
340: $kronolith_driver = self::getDriver();
341:
342: $alarms = array();
343: foreach ($calendars as $cal) {
344: $kronolith_driver->open($cal);
345: $alarms[$cal] = $kronolith_driver->listAlarms($date, $fullevent);
346: }
347:
348: return $alarms;
349: }
350:
351: 352: 353: 354: 355: 356: 357: 358: 359: 360:
361: static public function search($query, $calendar = null)
362: {
363: if ($calendar) {
364: $driver = explode('|', $calendar, 2);
365: $calendars = array($driver[0] => array($driver[1]));
366: } elseif (!empty($query->calendars)) {
367: $calendars = $query->calendars;
368: } else {
369: $calendars = array(
370: Horde_String::ucfirst($GLOBALS['conf']['calendar']['driver']) => $GLOBALS['display_calendars'],
371: 'Horde' => $GLOBALS['display_external_calendars'],
372: 'Ical' => $GLOBALS['display_remote_calendars'],
373: 'Holidays' => $GLOBALS['display_holidays']);
374: }
375:
376: $events = array();
377: foreach ($calendars as $type => $list) {
378: $kronolith_driver = self::getDriver($type);
379: foreach ($list as $cal) {
380: $kronolith_driver->open($cal);
381: $retevents = $kronolith_driver->search($query);
382: self::mergeEvents($events, $retevents);
383: }
384: }
385:
386: return $events;
387: }
388:
389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412:
413: static public function listEvents($startDate, $endDate, $calendars = null,
414: $showRecurrence = true,
415: $alarmsOnly = false, $showRemote = true,
416: $hideExceptions = false,
417: $coverDates = true, $fetchTags = false)
418: {
419: $results = array();
420:
421:
422: if (!isset($calendars)) {
423: $calendars = $GLOBALS['display_calendars'];
424: }
425: $driver = self::getDriver();
426: foreach ($calendars as $calendar) {
427: try {
428: $driver->open($calendar);
429: $events = $driver->listEvents($startDate, $endDate,
430: $showRecurrence, $alarmsOnly,
431: false, $coverDates,
432: $hideExceptions, $fetchTags);
433: self::mergeEvents($results, $events);
434: } catch (Kronolith_Exception $e) {
435: $GLOBALS['notification']->push($e);
436: }
437: }
438:
439: 440: 441: 442: 443: 444: 445:
446: if (!empty($GLOBALS['display_resource_calendars'])) {
447: $driver = self::getDriver('Resource');
448: foreach ($GLOBALS['display_resource_calendars'] as $calendar) {
449: try {
450: $driver->open($calendar);
451: $events = $driver->listEvents($startDate, $endDate, $showRecurrence);
452: self::mergeEvents($results, $events);
453: } catch (Kronolith_Exception $e) {
454: $GLOBALS['notification']->push($e);
455: }
456: }
457: }
458:
459: if ($showRemote) {
460:
461: if (count($GLOBALS['display_external_calendars'])) {
462: $driver = self::getDriver('Horde');
463: foreach ($GLOBALS['display_external_calendars'] as $external_cal) {
464: try {
465: $driver->open($external_cal);
466: $events = $driver->listEvents($startDate, $endDate, $showRecurrence);
467: self::mergeEvents($results, $events);
468: } catch (Kronolith_Exception $e) {
469: $GLOBALS['notification']->push($e);
470: }
471: }
472: }
473:
474:
475: foreach ($GLOBALS['display_remote_calendars'] as $url) {
476: try {
477: $driver = self::getDriver('Ical', $url);
478: $events = $driver->listEvents($startDate, $endDate, $showRecurrence);
479: self::mergeEvents($results, $events);
480: } catch (Kronolith_Exception $e) {
481: $GLOBALS['notification']->push($e);
482: }
483: }
484:
485:
486: if (count($GLOBALS['display_holidays']) && !empty($GLOBALS['conf']['holidays']['enable'])) {
487: $driver = self::getDriver('Holidays');
488: foreach ($GLOBALS['display_holidays'] as $holiday) {
489: try {
490: $driver->open($holiday);
491: $events = $driver->listEvents($startDate, $endDate, $showRecurrence);
492: self::mergeEvents($results, $events);
493: } catch (Kronolith_Exception $e) {
494: $GLOBALS['notification']->push($e);
495: }
496: }
497: }
498: }
499:
500:
501: $results = Kronolith::sortEvents($results);
502:
503: return $results;
504: }
505:
506: 507: 508: 509: 510: 511:
512: static public function mergeEvents(&$results, $events)
513: {
514: foreach ($events as $day => $day_events) {
515: if (isset($results[$day])) {
516: $results[$day] = array_merge($results[$day], $day_events);
517: } else {
518: $results[$day] = $day_events;
519: }
520: }
521: ksort($results);
522: }
523:
524: 525: 526:
527: static public function addEvents(&$results, &$event, $startDate, $endDate,
528: $showRecurrence, $json, $coverDates = true)
529: {
530: if ($event->recurs() && $showRecurrence) {
531:
532:
533: 534: 535:
536: if ($event->end->hour == 0 &&
537: $event->end->min == 0 &&
538: $event->end->sec == 0 &&
539: $event->start->compareDateTime($event->end) != 0) {
540: $event->end = new Horde_Date(
541: array('hour' => 23,
542: 'min' => 59,
543: 'sec' => 59,
544: 'month' => $event->end->month,
545: 'mday' => $event->end->mday - 1,
546: 'year' => $event->end->year));
547: }
548:
549: 550:
551: $diff = array($event->end->year - $event->start->year,
552: $event->end->month - $event->start->month,
553: $event->end->mday - $event->start->mday,
554: $event->end->hour - $event->start->hour,
555: $event->end->min - $event->start->min);
556:
557: if ($event->start->compareDateTime($startDate) < 0) {
558: 559: 560:
561: $next = array('year' => $startDate->year,
562: 'month' => $startDate->month,
563: 'mday' => $startDate->mday);
564: } else {
565: 566:
567: if (!$event->recurrence->hasException($event->start->year,
568: $event->start->month,
569: $event->start->mday)) {
570: if ($coverDates) {
571: self::addCoverDates($results, $event, $event->start, $event->end, $json);
572: } else {
573: $results[$event->start->dateString()][$event->id] = $json ? $event->toJson() : $event;
574: }
575: }
576:
577: 578:
579: $next = clone $event->start;
580: ++$next->mday;
581: }
582:
583:
584: $next = $event->recurrence->nextRecurrence($next);
585: while ($next !== false && $next->compareDate($endDate) <= 0) {
586: if (!$event->recurrence->hasException($next->year, $next->month, $next->mday)) {
587:
588: $nextEnd = clone $next;
589: $nextEnd->year += $diff[0];
590: $nextEnd->month += $diff[1];
591: $nextEnd->mday += $diff[2];
592: $nextEnd->hour += $diff[3];
593: $nextEnd->min += $diff[4];
594: if ($coverDates) {
595: self::addCoverDates($results, $event, $next, $nextEnd, $json);
596: } else {
597: $addEvent = clone $event;
598: $addEvent->start = $next;
599: $addEvent->end = $nextEnd;
600: $results[$addEvent->start->dateString()][$addEvent->id] = $json ? $addEvent->toJson() : $addEvent;
601:
602: }
603: }
604: $next = $event->recurrence->nextRecurrence(
605: array('year' => $next->year,
606: 'month' => $next->month,
607: 'mday' => $next->mday + 1,
608: 'hour' => $next->hour,
609: 'min' => $next->min,
610: 'sec' => $next->sec));
611: }
612: } else {
613:
614: if (!$coverDates) {
615: $results[$event->start->dateString()][$event->id] = $json ? $event->toJson() : $event;
616: } else {
617: $allDay = $event->isAllDay();
618:
619:
620: if ($startDate &&
621: $event->start->compareDateTime($startDate) < 0) {
622:
623: if ($event->recurs()) {
624: $eventStart = $event->recurrence->nextRecurrence($startDate);
625: } else {
626: $eventStart = clone $startDate;
627: }
628: } else {
629: $eventStart = clone $event->start;
630: }
631:
632:
633: if ($endDate &&
634: $event->end->compareDateTime($endDate) > 0) {
635:
636: if (is_object($endDate)) {
637: $eventEnd = clone $endDate;
638: } else {
639: $eventEnd = $endDate;
640: }
641: } else {
642: 643: 644:
645: if ($event->recurs()) {
646:
647: $diff = array($event->end->year - $event->start->year,
648: $event->end->month - $event->start->month,
649: $event->end->mday - $event->start->mday,
650: $event->end->hour - $event->start->hour,
651: $event->end->min - $event->start->min);
652:
653: $theEnd = $event->recurrence->nextRecurrence($eventStart);
654: $theEnd->year += $diff[0];
655: $theEnd->month += $diff[1];
656: $theEnd->mday += $diff[2];
657: $theEnd->hour += $diff[3];
658: $theEnd->min += $diff[4];
659: } else {
660: $theEnd = clone $event->end;
661: }
662:
663: 664: 665: 666:
667: if ($theEnd->hour != 0 ||
668: $theEnd->min != 0 ||
669: $theEnd->sec != 0 ||
670: $event->start->compareDateTime($theEnd) == 0 ||
671: $allDay) {
672: $eventEnd = clone $theEnd;
673: } else {
674: $eventEnd = new Horde_Date(
675: array('hour' => 23,
676: 'min' => 59,
677: 'sec' => 59,
678: 'month' => $theEnd->month,
679: 'mday' => $theEnd->mday - 1,
680: 'year' => $theEnd->year));
681: }
682: }
683:
684: 685: 686: 687: 688:
689: $i = $eventStart->mday;
690: $loopDate = new Horde_Date(array('month' => $eventStart->month,
691: 'mday' => $i,
692: 'year' => $eventStart->year));
693: while ($loopDate->compareDateTime($eventEnd) <= 0) {
694: if (!$allDay ||
695: $loopDate->compareDateTime($eventEnd) != 0) {
696: $addEvent = clone $event;
697:
698: 699: 700:
701: if ($loopDate->compareDate($eventStart) == 0) {
702: $addEvent->start = $eventStart;
703: } else {
704: $addEvent->start = clone $loopDate;
705: $addEvent->start->hour = $addEvent->start->min = $addEvent->start->sec = 0;
706: $addEvent->first = false;
707: }
708:
709: 710:
711: if ($loopDate->compareDate($eventEnd) == 0) {
712: $addEvent->end = $eventEnd;
713: } else {
714: $addEvent->end = clone $loopDate;
715: $addEvent->end->hour = 23;
716: $addEvent->end->min = $addEvent->end->sec = 59;
717: $addEvent->last = false;
718: }
719:
720: $results[$loopDate->dateString()][$addEvent->id] = $json ? $addEvent->toJson($allDay) : $addEvent;
721: }
722:
723: $loopDate = new Horde_Date(
724: array('month' => $eventStart->month,
725: 'mday' => ++$i,
726: 'year' => $eventStart->year));
727: }
728: }
729: }
730: ksort($results);
731: }
732:
733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743:
744: static public function addCoverDates(&$results, $event, $eventStart,
745: $eventEnd, $json)
746: {
747: $loopDate = new Horde_Date($eventStart->year, $eventStart->month, $eventStart->mday);
748: $allDay = $event->isAllDay();
749: $first = true;
750: while ($loopDate->compareDateTime($eventEnd) <= 0) {
751: if (!$allDay ||
752: $loopDate->compareDateTime($eventEnd) != 0) {
753: $addEvent = clone $event;
754: $addEvent->start = $eventStart;
755: $addEvent->end = $eventEnd;
756: if ($loopDate->compareDate($eventStart) != 0) {
757: $addEvent->first = false;
758: }
759: if ($loopDate->compareDate($eventEnd) != 0) {
760: $addEvent->last = false;
761: }
762: $results[$loopDate->dateString()][$addEvent->id] = $json ? $addEvent->toJson($allDay) : $addEvent;
763: }
764: $loopDate->mday++;
765: }
766: }
767:
768: 769: 770: 771: 772: 773: 774: 775: 776: 777:
778: static public function addSearchEvents(&$events, $event, $query, $json)
779: {
780: static $now;
781: if (!isset($now)) {
782: $now = new Horde_Date($_SERVER['REQUEST_TIME']);
783: }
784: $showRecurrence = true;
785: if ($event->recurs()) {
786: if (empty($query->start) && empty($query->end)) {
787: $eventStart = $event->start;
788: $eventEnd = $event->end;
789: } else {
790: if (empty($query->end)) {
791: $eventEnd = $event->recurrence->nextRecurrence($now);
792: if (!$eventEnd) {
793: return;
794: }
795: } else {
796: $eventEnd = $query->end;
797: }
798: if (empty($query->start)) {
799: $eventStart = $event->start;
800: $showRecurrence = false;
801: } else {
802: $eventStart = $query->start;
803: }
804: }
805: } else {
806: $eventStart = $event->start;
807: $eventEnd = $event->end;
808: }
809: self::addEvents($events, $event, $eventStart, $eventEnd, $showRecurrence, $json, false);
810: }
811:
812: 813: 814: 815: 816:
817: static public function countEvents()
818: {
819: static $count;
820: if (isset($count)) {
821: return $count;
822: }
823:
824: $kronolith_driver = self::getDriver();
825: $calendars = self::listInternalCalendars(true, Horde_Perms::ALL);
826: $current_calendar = $kronolith_driver->calendar;
827:
828: $count = 0;
829: foreach (array_keys($calendars) as $calendar) {
830: $kronolith_driver->open($calendar);
831: try {
832: $count += $kronolith_driver->countEvents();
833: } catch (Exception $e) {
834: }
835: }
836:
837:
838: $kronolith_driver->open($current_calendar);
839:
840: return $count;
841: }
842:
843: 844: 845: 846: 847: 848: 849: 850: 851: 852: 853:
854: public function quickAdd($text, $calendar = null)
855: {
856: $text = trim($text);
857: if (strpos($text, "\n") !== false) {
858: list($title, $description) = explode($text, "\n", 2);
859: } else {
860: $title = $text;
861: $description = '';
862: }
863: $title = trim($title);
864: $description = trim($description);
865:
866: $dateParser = Horde_Date_Parser::factory(array('locale' => $GLOBALS['language']));
867: $r = $dateParser->parse($title, array('return' => 'result'));
868: if (!($d = $r->guess())) {
869: throw new Horde_Exception(sprintf(_("Cannot parse event description \"%s\""), Horde_String::truncate($text)));
870: }
871:
872: $title = $r->untaggedText();
873: $start = $d->timestamp();
874:
875: $kronolith_driver = self::getDriver(null, $calendar);
876: $event = $kronolith_driver->getEvent();
877: $event->initialized = true;
878: $event->title = $title;
879: $event->description = $description;
880: $event->start = $d;
881: $event->end = $d->add(array('hour' => 1));
882: $event->save();
883:
884: return $event;
885: }
886:
887: 888: 889:
890: static public function initialize()
891: {
892:
893: if (!isset($_SERVER['REQUEST_TIME'])) {
894: $_SERVER['REQUEST_TIME'] = time();
895: }
896:
897:
898: $GLOBALS['display_calendars'] = @unserialize($GLOBALS['prefs']->getValue('display_cals'));
899: $GLOBALS['display_remote_calendars'] = @unserialize($GLOBALS['prefs']->getValue('display_remote_cals'));
900: $GLOBALS['display_external_calendars'] = @unserialize($GLOBALS['prefs']->getValue('display_external_cals'));
901: $GLOBALS['display_holidays'] = @unserialize($GLOBALS['prefs']->getValue('holiday_drivers'));
902:
903: if (!is_array($GLOBALS['display_calendars'])) {
904: $GLOBALS['display_calendars'] = array();
905: }
906: if (!is_array($GLOBALS['display_remote_calendars'])) {
907: $GLOBALS['display_remote_calendars'] = array();
908: }
909: if (!is_array($GLOBALS['display_external_calendars'])) {
910: $GLOBALS['display_external_calendars'] = array();
911: }
912: if (!is_array($GLOBALS['display_holidays']) ||
913: empty($GLOBALS['conf']['holidays']['enable'])) {
914: $GLOBALS['display_holidays'] = array();
915: }
916:
917: 918: 919: 920:
921: if (($calendarId = Horde_Util::getFormData('display_cal')) !== null) {
922: $GLOBALS['session']->set('kronolith', 'display_cal', $calendarId);
923: }
924:
925: if (strlen($GLOBALS['session']->get('kronolith', 'display_cal'))) {
926: 927: 928: 929:
930: $GLOBALS['display_calendars'] = array();
931: $GLOBALS['display_remote_calendars'] = array();
932: $GLOBALS['display_external_calendars'] = array();
933: $GLOBALS['display_resource_calendars'] = array();
934: $GLOBALS['display_holidays'] = array();
935: $calendars = $GLOBALS['session']->get('kronolith', 'display_cal');
936: if (!is_array($calendars)) {
937: $calendars = array($calendars);
938: }
939: foreach ($calendars as $calendarId) {
940: if (strncmp($calendarId, 'remote_', 7) === 0) {
941: $calendarId = substr($calendarId, 7);
942: if (!in_array($calendarId, $GLOBALS['display_remote_calendars'])) {
943: $GLOBALS['display_remote_calendars'][] = $calendarId;
944: }
945: } elseif (strncmp($calendarId, 'external_', 9) === 0) {
946: $calendarId = substr($calendarId, 9);
947: if (!in_array($calendarId, $GLOBALS['display_external_calendars'])) {
948: $GLOBALS['display_external_calendars'][] = $calendarId;
949: }
950: } elseif (strncmp($calendarId, 'resource_', 9) === 0) {
951: $calendarId = substr($calendarId, 9);
952: if (!in_array($calendarId, $GLOBALS['display_resource_calendars'])) {
953: $GLOBALS['display_resource_calendars'][] = $calendarId;
954: }
955: } elseif (strncmp($calendarId, 'holidays_', 9) === 0) {
956: $calendarId = substr($calendarId, 9);
957: if (!in_array($calendarId, $GLOBALS['display_holidays'])) {
958: $GLOBALS['display_holidays'][] = $calendarId;
959: }
960: } else {
961: if (strncmp($calendarId, 'internal_', 9) === 0) {
962: $calendarId = substr($calendarId, 9);
963: }
964: if (!in_array($calendarId, $GLOBALS['display_calendars'])) {
965: $GLOBALS['display_calendars'][] = $calendarId;
966: }
967: }
968: }
969: }
970:
971:
972: if (($calendarId = Horde_Util::getFormData('toggle_calendar')) !== null) {
973: if (strncmp($calendarId, 'remote_', 7) === 0) {
974: $calendarId = substr($calendarId, 7);
975: if (in_array($calendarId, $GLOBALS['display_remote_calendars'])) {
976: $key = array_search($calendarId, $GLOBALS['display_remote_calendars']);
977: unset($GLOBALS['display_remote_calendars'][$key]);
978: } else {
979: $GLOBALS['display_remote_calendars'][] = $calendarId;
980: }
981: } elseif ((strncmp($calendarId, 'external_', 9) === 0 &&
982: $calendarId = substr($calendarId, 9)) ||
983: (strncmp($calendarId, 'tasklists_', 10) === 0 &&
984: $calendarId = substr($calendarId, 10))) {
985: if (in_array($calendarId, $GLOBALS['display_external_calendars'])) {
986: $key = array_search($calendarId, $GLOBALS['display_external_calendars']);
987: unset($GLOBALS['display_external_calendars'][$key]);
988: } else {
989: $GLOBALS['display_external_calendars'][] = $calendarId;
990: }
991: if (strpos($calendarId, 'tasks/') === 0) {
992: $tasklists = array();
993: foreach ($GLOBALS['display_external_calendars'] as $id) {
994: if (strpos($id, 'tasks/') === 0) {
995: $tasklists[] = substr($id, 6);
996: }
997: }
998: try {
999: $GLOBALS['registry']->tasks->setDisplayedTasklists($tasklists);
1000: } catch (Horde_Exception $e) {
1001: }
1002: }
1003: } elseif (strncmp($calendarId, 'holiday_', 8) === 0) {
1004: $calendarId = substr($calendarId, 8);
1005: if (in_array($calendarId, $GLOBALS['display_holidays'])) {
1006: $key = array_search($calendarId, $GLOBALS['display_holidays']);
1007: unset($GLOBALS['display_holidays'][$key]);
1008: } else {
1009: $GLOBALS['display_holidays'][] = $calendarId;
1010: }
1011: } else {
1012: if (in_array($calendarId, $GLOBALS['display_calendars'])) {
1013: $key = array_search($calendarId, $GLOBALS['display_calendars']);
1014: unset($GLOBALS['display_calendars'][$key]);
1015: } else {
1016: $GLOBALS['display_calendars'][] = $calendarId;
1017: }
1018: }
1019:
1020: $GLOBALS['prefs']->setValue('display_cals', serialize($GLOBALS['display_calendars']));
1021: }
1022:
1023:
1024: $GLOBALS['all_calendars'] = array();
1025: foreach (self::listInternalCalendars() as $id => $calendar) {
1026: $GLOBALS['all_calendars'][$id] = new Kronolith_Calendar_Internal(array('share' => $calendar));
1027: }
1028: $calendar_keys = array_values($GLOBALS['display_calendars']);
1029: $GLOBALS['display_calendars'] = array();
1030: foreach ($calendar_keys as $id) {
1031: if (isset($GLOBALS['all_calendars'][$id])) {
1032: $GLOBALS['display_calendars'][] = $id;
1033: }
1034: }
1035:
1036:
1037: $_temp = $GLOBALS['display_remote_calendars'];
1038: $GLOBALS['display_remote_calendars'] = array();
1039: $GLOBALS['all_remote_calendars'] = array();
1040: $calendars = @unserialize($GLOBALS['prefs']->getValue('remote_cals'));
1041: if (!is_array($calendars)) {
1042: $calendars = array();
1043: }
1044: foreach ($calendars as $calendar) {
1045: $GLOBALS['all_remote_calendars'][$calendar['url']] = new Kronolith_Calendar_Remote($calendar);
1046: if (in_array($calendar['url'], $_temp)) {
1047: $GLOBALS['display_remote_calendars'][] = $calendar['url'];
1048: }
1049: }
1050: $GLOBALS['prefs']->setValue('display_remote_cals', serialize($GLOBALS['display_remote_calendars']));
1051:
1052:
1053: $GLOBALS['all_holidays'] = array();
1054: if (!empty($GLOBALS['conf']['holidays']['enable'])) {
1055: if (class_exists('Date_Holidays')) {
1056: foreach (Date_Holidays::getInstalledDrivers() as $driver) {
1057: if ($driver['id'] == 'Composite') {
1058: continue;
1059: }
1060: $GLOBALS['all_holidays'][$driver['id']] = new Kronolith_Calendar_Holiday(array('driver' => $driver));
1061: ksort($GLOBALS['all_holidays']);
1062: }
1063: }
1064: }
1065: $_temp = $GLOBALS['display_holidays'];
1066: $GLOBALS['display_holidays'] = array();
1067: foreach (array_keys($GLOBALS['all_holidays']) as $id) {
1068: if (in_array($id, $_temp)) {
1069: $GLOBALS['display_holidays'][] = $id;
1070: }
1071: }
1072: $GLOBALS['prefs']->setValue('holiday_drivers', serialize($GLOBALS['display_holidays']));
1073:
1074:
1075: $GLOBALS['all_external_calendars'] = array();
1076:
1077:
1078: if (self::hasApiPermission('tasks') &&
1079: $GLOBALS['registry']->hasMethod('tasks/listTimeObjects')) {
1080: try {
1081: $tasklists = $GLOBALS['registry']->tasks->listTasklists();
1082: $categories = $GLOBALS['registry']->call('tasks/listTimeObjectCategories');
1083: foreach ($categories as $name => $description) {
1084: if (!isset($tasklists[$name])) {
1085: continue;
1086: }
1087: $GLOBALS['all_external_calendars']['tasks/' . $name] = new Kronolith_Calendar_External_Tasks(array('api' => 'tasks', 'name' => $description, 'share' => $tasklists[$name]));
1088: }
1089: } catch (Horde_Exception $e) {
1090: Horde::logMessage($e, 'DEBUG');
1091: }
1092: }
1093:
1094: if ($GLOBALS['session']->exists('kronolith', 'all_external_calendars')) {
1095: foreach ($GLOBALS['session']->get('kronolith', 'all_external_calendars') as $calendar) {
1096: if (!self::hasApiPermission($calendar['a']) ||
1097: $calendar['a'] == 'tasks') {
1098: continue;
1099: }
1100: $GLOBALS['all_external_calendars'][$calendar['a'] . '/' . $calendar['n']] = new Kronolith_Calendar_External(array('api' => $calendar['a'], 'name' => $calendar['d'], 'id' => $calendar['n']));
1101: }
1102: } else {
1103: $apis = array_unique($GLOBALS['registry']->listAPIs());
1104: $ext_cals = array();
1105:
1106: foreach ($apis as $api) {
1107: if ($api == 'tasks' ||
1108: !self::hasApiPermission($api) ||
1109: !$GLOBALS['registry']->hasMethod($api . '/listTimeObjects')) {
1110: continue;
1111: }
1112: try {
1113: $categories = $GLOBALS['registry']->call($api . '/listTimeObjectCategories');
1114: } catch (Horde_Exception $e) {
1115: Horde::logMessage($e, 'DEBUG');
1116: continue;
1117: }
1118:
1119: foreach ($categories as $name => $description) {
1120: $GLOBALS['all_external_calendars'][$api . '/' . $name] = new Kronolith_Calendar_External(array('api' => $api, 'name' => $description, 'id' => $name));
1121: $ext_cals[] = array(
1122: 'a' => $api,
1123: 'n' => $name,
1124: 'd' => $description
1125: );
1126: }
1127: }
1128:
1129: $GLOBALS['session']->set('kronolith', 'all_external_calendars', $ext_cals);
1130: }
1131:
1132:
1133: $_tasklists = $_temp = $GLOBALS['display_external_calendars'];
1134: if (self::hasApiPermission('tasks')) {
1135: try {
1136: $_tasklists = $GLOBALS['registry']->tasks->getDisplayedTasklists();
1137: } catch (Horde_Exception $e) {
1138: }
1139: }
1140: $GLOBALS['display_external_calendars'] = array();
1141: foreach ($GLOBALS['all_external_calendars'] as $id => $calendar) {
1142: if ((substr($id, 0, 6) == 'tasks/' &&
1143: in_array(substr($id, 6), $_tasklists)) ||
1144: in_array($id, $_temp)) {
1145: $GLOBALS['display_external_calendars'][] = $id;
1146: } else {
1147: 1148:
1149: list(,$oldid,) = explode('/', $id);
1150: if (in_array($calendar->api() . '/' . $oldid, $_temp)) {
1151: $GLOBALS['display_external_calendars'][] = $calendarId;
1152: }
1153: }
1154: }
1155: $GLOBALS['prefs']->setValue('display_external_cals', serialize($GLOBALS['display_external_calendars']));
1156:
1157:
1158: if (!empty($GLOBALS['conf']['share']['auto_create']) &&
1159: $GLOBALS['registry']->getAuth() &&
1160: !count(self::listInternalCalendars(true))) {
1161: $calendars = $GLOBALS['injector']->getInstance('Kronolith_Factory_Calendars')
1162: ->create();
1163:
1164: $share = $calendars->createDefaultShare();
1165: $GLOBALS['all_calendars'][$share->getName()] = new Kronolith_Calendar_Internal(array('share' => $share));
1166: $GLOBALS['display_calendars'][] = $share->getName();
1167:
1168:
1169: if ($GLOBALS['conf']['autoshare']['shareperms'] != 'none') {
1170: $perm_value = 0;
1171: switch ($GLOBALS['conf']['autoshare']['shareperms']) {
1172: case 'read':
1173: $perm_value = Horde_Perms::READ | Horde_Perms::SHOW;
1174: break;
1175: case 'edit':
1176: $perm_value = Horde_Perms::READ | Horde_Perms::SHOW | Horde_Perms::EDIT;
1177: break;
1178: case 'full':
1179: $perm_value = Horde_Perms::READ | Horde_Perms::SHOW | Horde_Perms::EDIT | Horde_Perms::DELETE;
1180: break;
1181: }
1182:
1183: try {
1184: $group_list = $GLOBALS['injector']
1185: ->getInstance('Horde_Group')
1186: ->listGroups($GLOBALS['registry']->getAuth());
1187: if (count($group_list)) {
1188: $perm = $share->getPermission();
1189:
1190: foreach ($group_list as $group_id => $group_name) {
1191: $perm->addGroupPermission($group_id, $perm_value, false);
1192: }
1193: $share->setPermission($perm);
1194: $GLOBALS['notification']->push(sprintf(_("New calendar created and automatically shared with the following group(s): %s."), implode(', ', $group_list)), 'horde.success');
1195: }
1196: } catch (Horde_Group_Exception $e) {}
1197: }
1198:
1199: $GLOBALS['prefs']->setValue('display_cals', serialize($GLOBALS['display_calendars']));
1200: }
1201: }
1202:
1203: 1204: 1205: 1206: 1207: 1208: 1209:
1210: static public function initEventMap($params)
1211: {
1212:
1213: if (!empty($params['providers'])) {
1214: 1215:
1216:
1217:
1218: $language = str_replace('_', '-', $GLOBALS['language']);
1219: if (!file_exists($GLOBALS['registry']->get('jsfs', 'horde') . '/map/lang/' . $language . '.js')) {
1220: $language = 'en-US';
1221: }
1222: $params['conf'] = array(
1223: 'markerImage' => (string)Horde_Themes::img('map/marker.png'),
1224: 'markerBackground' => (string)Horde_Themes::img('map/marker-shadow.png'),
1225: 'useMarkerLayer' => true,
1226: 'language' => $language,
1227: );
1228:
1229: foreach ($params['providers'] as $layer) {
1230: switch ($layer) {
1231: case 'Google':
1232: $params['conf']['apikeys']['google'] = $GLOBALS['conf']['api']['googlemaps'];
1233: break;
1234: case 'Yahoo':
1235: $params['conf']['apikeys']['yahoo'] = $GLOBALS['conf']['api']['yahoomaps'];
1236: break;
1237: case 'Cloudmade':
1238: $params['conf']['apikeys']['cloudmade'] = $GLOBALS['conf']['api']['cloudmade'];
1239: break;
1240: }
1241: }
1242: }
1243:
1244: if (!empty($params['geocoder'])) {
1245: switch ($params['geocoder']) {
1246: case 'Google':
1247: $params['conf']['apikeys']['google'] = $GLOBALS['conf']['api']['googlemaps'];
1248: break;
1249: case 'Yahoo':
1250: $params['conf']['apikeys']['yahoo'] = $GLOBALS['conf']['api']['yahoomaps'];
1251: break;
1252: case 'Cloudmade':
1253: $params['conf']['apikeys']['cloudmade'] = $GLOBALS['conf']['api']['cloudmade'];
1254: break;
1255: }
1256: }
1257: $params['jsuri'] = $GLOBALS['registry']->get('jsuri', 'horde') . '/map/';
1258: $params['ssl'] = $GLOBALS['browser']->usingSSLConnection();
1259: Horde::addScriptFile('map/map.js', 'horde');
1260: $js = 'HordeMap.initialize(' . Horde_Serialize::serialize($params, HORDE_SERIALIZE::JSON) . ');';
1261: Horde::addinlineScript($js);
1262: }
1263:
1264: 1265: 1266:
1267: static public function getUserName($uid)
1268: {
1269: static $names = array();
1270:
1271: if (!isset($names[$uid])) {
1272: $ident = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($uid);
1273: $ident->setDefault($ident->getDefault());
1274: $names[$uid] = $ident->getValue('fullname');
1275: if (empty($names[$uid])) {
1276: $names[$uid] = $uid;
1277: }
1278: }
1279:
1280: return $names[$uid];
1281: }
1282:
1283: 1284: 1285:
1286: static public function getUserEmail($uid)
1287: {
1288: static $emails = array();
1289:
1290: if (!isset($emails[$uid])) {
1291: $ident = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($uid);
1292: $emails[$uid] = $ident->getValue('from_addr');
1293: if (empty($emails[$uid])) {
1294: $emails[$uid] = $uid;
1295: }
1296: }
1297:
1298: return $emails[$uid];
1299: }
1300:
1301: 1302: 1303:
1304: static public function isUserEmail($uid, $email)
1305: {
1306: static $emails = array();
1307:
1308: if (!isset($emails[$uid])) {
1309: $ident = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($uid);
1310:
1311: $addrs = $ident->getAll('from_addr');
1312: $addrs[] = $uid;
1313:
1314: $emails[$uid] = $addrs;
1315: }
1316:
1317: return in_array($email, $emails[$uid]);
1318: }
1319:
1320: 1321: 1322: 1323: 1324: 1325: 1326: 1327: 1328:
1329: static public function recurToString($type)
1330: {
1331: switch ($type) {
1332: case Horde_Date_Recurrence::RECUR_NONE:
1333: return _("Does not recur");
1334:
1335: case Horde_Date_Recurrence::RECUR_DAILY:
1336: return _("Recurs daily");
1337:
1338: case Horde_Date_Recurrence::RECUR_WEEKLY:
1339: return _("Recurs weekly");
1340:
1341: case Horde_Date_Recurrence::RECUR_MONTHLY_DATE:
1342: case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY:
1343: return _("Recurs monthly");
1344:
1345: case Horde_Date_Recurrence::RECUR_YEARLY_DATE:
1346: case Horde_Date_Recurrence::RECUR_YEARLY_DAY:
1347: case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY:
1348: return _("Recurs yearly");
1349: }
1350: }
1351:
1352: 1353: 1354: 1355: 1356: 1357: 1358: 1359: 1360:
1361: static public function statusToString($status)
1362: {
1363: switch ($status) {
1364: case self::STATUS_CONFIRMED:
1365: return _("Confirmed");
1366:
1367: case self::STATUS_CANCELLED:
1368: return _("Cancelled");
1369:
1370: case self::STATUS_FREE:
1371: return _("Free");
1372:
1373: case self::STATUS_TENTATIVE:
1374: default:
1375: return _("Tentative");
1376: }
1377: }
1378:
1379: 1380: 1381: 1382: 1383: 1384: 1385: 1386: 1387:
1388: static public function responseToString($response)
1389: {
1390: switch ($response) {
1391: case self::RESPONSE_ACCEPTED:
1392: return _("Accepted");
1393:
1394: case self::RESPONSE_DECLINED:
1395: return _("Declined");
1396:
1397: case self::RESPONSE_TENTATIVE:
1398: return _("Tentative");
1399:
1400: case self::RESPONSE_NONE:
1401: default:
1402: return _("None");
1403: }
1404: }
1405:
1406: 1407: 1408: 1409: 1410: 1411: 1412: 1413: 1414: 1415:
1416: static public function partToString($part)
1417: {
1418: switch ($part) {
1419: case self::PART_OPTIONAL:
1420: return _("Optional");
1421:
1422: case self::PART_NONE:
1423: return _("None");
1424:
1425: case self::PART_REQUIRED:
1426: default:
1427: return _("Required");
1428: }
1429: }
1430:
1431: 1432: 1433: 1434: 1435: 1436: 1437: 1438:
1439: static public function responseFromICal($response)
1440: {
1441: switch (Horde_String::upper($response)) {
1442: case 'ACCEPTED':
1443: return self::RESPONSE_ACCEPTED;
1444:
1445: case 'DECLINED':
1446: return self::RESPONSE_DECLINED;
1447:
1448: case 'TENTATIVE':
1449: return self::RESPONSE_TENTATIVE;
1450:
1451: case 'NEEDS-ACTION':
1452: default:
1453: return self::RESPONSE_NONE;
1454: }
1455: }
1456:
1457: 1458: 1459: 1460: 1461: 1462: 1463: 1464: 1465:
1466: static public function buildStatusWidget($name,
1467: $current = self::STATUS_CONFIRMED,
1468: $any = false)
1469: {
1470: $html = "<select id=\"$name\" name=\"$name\">";
1471:
1472: $statii = array(
1473: self::STATUS_FREE,
1474: self::STATUS_TENTATIVE,
1475: self::STATUS_CONFIRMED,
1476: self::STATUS_CANCELLED
1477: );
1478:
1479: if (!isset($current)) {
1480: $current = self::STATUS_NONE;
1481: }
1482:
1483: if ($any) {
1484: $html .= "<option value=\"" . self::STATUS_NONE . "\"";
1485: $html .= ($current == self::STATUS_NONE) ? ' selected="selected">' : '>';
1486: $html .= _("Any") . "</option>";
1487: }
1488:
1489: foreach ($statii as $status) {
1490: $html .= "<option value=\"$status\"";
1491: $html .= ($status == $current) ? ' selected="selected">' : '>';
1492: $html .= self::statusToString($status) . "</option>";
1493: }
1494: $html .= '</select>';
1495:
1496: return $html;
1497: }
1498:
1499: 1500: 1501: 1502: 1503: 1504: 1505: 1506: 1507: 1508: 1509: 1510: 1511: 1512: 1513: 1514:
1515: static public function listInternalCalendars($owneronly = false, $permission = Horde_Perms::SHOW)
1516: {
1517: if ($owneronly && !$GLOBALS['registry']->getAuth()) {
1518: return array();
1519: }
1520:
1521: if ($owneronly || empty($GLOBALS['conf']['share']['hidden'])) {
1522: try {
1523: $calendars = $GLOBALS['kronolith_shares']->listShares(
1524: $GLOBALS['registry']->getAuth(),
1525: array('perm' => $permission,
1526: 'attributes' => $owneronly ? $GLOBALS['registry']->getAuth() : null,
1527: 'sort_by' => 'name'));
1528: } catch (Horde_Share_Exception $e) {
1529: Horde::logMessage($e);
1530: return array();
1531: }
1532: } else {
1533: try {
1534: $calendars = $GLOBALS['kronolith_shares']->listShares(
1535: $GLOBALS['registry']->getAuth(),
1536: array('perm' => $permission,
1537: 'attributes' => $GLOBALS['registry']->getAuth(),
1538: 'sort_by' => 'name'));
1539: } catch (Horde_Share_Exception $e) {
1540: Horde::logMessage($e);
1541: return array();
1542: }
1543: $display_calendars = @unserialize($GLOBALS['prefs']->getValue('display_cals'));
1544: if (is_array($display_calendars)) {
1545: foreach ($display_calendars as $id) {
1546: try {
1547: $calendar = $GLOBALS['kronolith_shares']->getShare($id);
1548: if ($calendar->hasPermission($GLOBALS['registry']->getAuth(), $permission)) {
1549: $calendars[$id] = $calendar;
1550: }
1551: } catch (Horde_Exception_NotFound $e) {
1552: } catch (Horde_Share_Exception $e) {
1553: Horde::logMessage($e);
1554: return array();
1555: }
1556: }
1557: }
1558: }
1559:
1560: $default_share = $GLOBALS['prefs']->getValue('default_share');
1561: if (isset($calendars[$default_share])) {
1562: $calendar = $calendars[$default_share];
1563: unset($calendars[$default_share]);
1564: $calendars = array($default_share => $calendar) + $calendars;
1565: }
1566:
1567: return $calendars;
1568: }
1569:
1570: 1571: 1572: 1573: 1574: 1575: 1576: 1577: 1578: 1579: 1580: 1581: 1582:
1583: static public function listCalendars($permission = Horde_Perms::SHOW,
1584: $display = false,
1585: $flat = true)
1586: {
1587: $calendars = array();
1588: foreach ($GLOBALS['all_calendars'] as $id => $calendar) {
1589: if ($calendar->hasPermission($permission) &&
1590: (!$display || $calendar->display())) {
1591: if ($flat) {
1592: $calendars['internal_' . $id] = $calendar;
1593: }
1594: }
1595: }
1596:
1597: foreach ($GLOBALS['all_remote_calendars'] as $id => $calendar) {
1598: try {
1599: if ($calendar->hasPermission($permission) &&
1600: (!$display || $calendar->display())) {
1601: if ($flat) {
1602: $calendars['remote_' . $id] = $calendar;
1603: }
1604: }
1605: } catch (Kronolith_Exception $e) {
1606: $GLOBALS['notification']->push(sprintf(_("The calendar %s returned the error: %s"), $calendar->name(), $e->getMessage()), 'horde.error');
1607: }
1608: }
1609:
1610: foreach ($GLOBALS['all_external_calendars'] as $id => $calendar) {
1611: if ($calendar->hasPermission($permission) &&
1612: (!$display || $calendar->display())) {
1613: if ($flat) {
1614: $calendars['external_' . $id] = $calendar;
1615: }
1616: }
1617: }
1618:
1619: foreach ($GLOBALS['all_holidays'] as $id => $calendar) {
1620: if ($calendar->hasPermission($permission) &&
1621: (!$display || $calendar->display())) {
1622: if ($flat) {
1623: $calendars['holiday_' . $id] = $calendar;
1624: }
1625: }
1626: }
1627:
1628: return $calendars;
1629: }
1630:
1631: 1632: 1633: 1634: 1635: 1636: 1637: 1638: 1639:
1640: static public function getDefaultCalendar($permission = Horde_Perms::SHOW, $owner_only = false)
1641: {
1642: global $prefs;
1643:
1644: $default_share = $prefs->getValue('default_share');
1645: $calendars = self::listInternalCalendars($owner_only, $permission);
1646:
1647: if (isset($calendars[$default_share]) ||
1648: $prefs->isLocked('default_share')) {
1649: return $default_share;
1650: } elseif (isset($GLOBALS['all_calendars'][$GLOBALS['registry']->getAuth()]) &&
1651: $GLOBALS['all_calendars'][$GLOBALS['registry']->getAuth()]->hasPermission($permission)) {
1652:
1653:
1654: return $GLOBALS['registry']->getAuth();
1655: } elseif (count($calendars)) {
1656: return key($calendars);
1657: }
1658:
1659: return false;
1660: }
1661:
1662: 1663: 1664: 1665: 1666: 1667: 1668: 1669: 1670: 1671:
1672: static public function getSyncCalendars($prune = false)
1673: {
1674: $haveRemoved = false;
1675: $cs = unserialize($GLOBALS['prefs']->getValue('sync_calendars'));
1676: if (!empty($cs)) {
1677: if ($prune) {
1678: $calendars = self::listInternalCalendars(true, Horde_Perms::EDIT);
1679: $cscopy = array_flip($cs);
1680: foreach ($cs as $c) {
1681: if (empty($calendars[$c])) {
1682: unset($cscopy[$c]);
1683: $haveRemoved = true;
1684: }
1685: }
1686: if ($haveRemoved) {
1687: $GLOBALS['prefs']->setValue('sync_calendars', serialize(array_flip($cscopy)));
1688: }
1689: }
1690: return $cs;
1691: }
1692:
1693: if ($cs = self::getDefaultCalendar(Horde_Perms::EDIT, true)) {
1694: return array($cs);
1695: }
1696:
1697: return array();
1698: }
1699:
1700: 1701: 1702: 1703: 1704: 1705: 1706: 1707: 1708: 1709:
1710: static public function hasPermission($calendar, $perm)
1711: {
1712: try {
1713: $share = $GLOBALS['kronolith_shares']->getShare($calendar);
1714: if (!$share->hasPermission($GLOBALS['registry']->getAuth(), $perm)) {
1715: throw new Horde_Exception_NotFound();
1716: }
1717: } catch (Horde_Exception_NotFound $e) {
1718: return false;
1719: }
1720: return true;
1721: }
1722:
1723: 1724: 1725: 1726: 1727: 1728: 1729: 1730:
1731: static public function addShare($info)
1732: {
1733: try {
1734: $calendar = $GLOBALS['kronolith_shares']->newShare($GLOBALS['registry']->getAuth(), strval(new Horde_Support_Randomid()), $info['name']);
1735: } catch (Horde_Share_Exception $e) {
1736: throw new Kronolith_Exception($e);
1737: }
1738:
1739: $calendar->set('color', $info['color']);
1740: $calendar->set('desc', $info['description']);
1741: if (!empty($info['system'])) {
1742: $calendar->set('owner', null);
1743: }
1744: $tagger = self::getTagger();
1745: $tagger->tag($calendar->getName(), $info['tags'], $calendar->get('owner'), 'calendar');
1746:
1747: try {
1748: $GLOBALS['kronolith_shares']->addShare($calendar);
1749: } catch (Horde_Share_Exception $e) {
1750: throw new Kronolith_Exception($e);
1751: }
1752:
1753: $GLOBALS['display_calendars'][] = $calendar->getName();
1754: $GLOBALS['prefs']->setValue('display_cals', serialize($GLOBALS['display_calendars']));
1755:
1756: return $calendar;
1757: }
1758:
1759: 1760: 1761: 1762: 1763: 1764: 1765: 1766:
1767: static public function updateShare(&$calendar, $info)
1768: {
1769: if (!$GLOBALS['registry']->getAuth() ||
1770: ($calendar->get('owner') != $GLOBALS['registry']->getAuth() &&
1771: (!is_null($calendar->get('owner')) || !$GLOBALS['registry']->isAdmin()))) {
1772: throw new Kronolith_Exception(_("You are not allowed to change this calendar."));
1773: }
1774:
1775: $original_name = $calendar->get('name');
1776: $calendar->set('name', $info['name']);
1777: $calendar->set('color', $info['color']);
1778: $calendar->set('desc', $info['description']);
1779: $calendar->set('owner', empty($info['system']) ? $GLOBALS['registry']->getAuth() : null);
1780:
1781: try {
1782: $result = $calendar->save();
1783: } catch (Horde_Share_Exception $e) {
1784: throw new Kronolith_Exception(sprintf(_("Unable to save calendar \"%s\": %s"), $info['name'], $e->getMessage()));
1785: }
1786:
1787: $tagger = self::getTagger();
1788: $tagger->replaceTags($calendar->getName(), $info['tags'], $calendar->get('owner'), 'calendar');
1789: }
1790:
1791: 1792: 1793: 1794: 1795: 1796: 1797:
1798: static public function deleteShare($calendar)
1799: {
1800: if (!$GLOBALS['registry']->getAuth() ||
1801: ($calendar->get('owner') != $GLOBALS['registry']->getAuth() &&
1802: (!is_null($calendar->get('owner')) || !$GLOBALS['registry']->isAdmin()))) {
1803: throw new Kronolith_Exception(_("You are not allowed to delete this calendar."));
1804: }
1805:
1806:
1807: try {
1808: self::getDriver()->delete($calendar->getName());
1809: } catch (Exception $e) {
1810: throw new Kronolith_Exception(sprintf(_("Unable to delete \"%s\": %s"), $calendar->get('name'), $e->getMessage()));
1811: }
1812:
1813:
1814: try {
1815: $result = $GLOBALS['kronolith_shares']->removeShare($calendar);
1816: } catch (Horde_Share_Exception $e) {
1817: throw new Kronolith_Exception($e);
1818: }
1819: }
1820:
1821: 1822: 1823: 1824: 1825: 1826: 1827: 1828:
1829: static public function readPermsForm($share)
1830: {
1831: $auth = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Auth')->create();
1832: $perm = $share->getPermission();
1833: $errors = array();
1834:
1835: if ($GLOBALS['conf']['share']['notify']) {
1836: $identity = $GLOBALS['injector']
1837: ->getInstance('Horde_Core_Factory_Identity')
1838: ->create();
1839: $mail = new Horde_Mime_Mail(array(
1840: 'From' => $identity->getDefaultFromAddress(true),
1841: 'User-Agent' => 'Kronolith ' . $GLOBALS['registry']->getVersion()));
1842: $image = self::getImagePart('big_share.png');
1843: $view = new Horde_View(array('templatePath' => KRONOLITH_TEMPLATES . '/share'));
1844: new Horde_View_Helper_Text($view);
1845: $view->identity = $identity;
1846: $view->calendar = $share->get('name');
1847: $view->imageId = $image->getContentId();
1848: }
1849:
1850:
1851: $old_owner = $share->get('owner');
1852: $new_owner_backend = Horde_Util::getFormData('owner_select', Horde_Util::getFormData('owner_input', $old_owner));
1853: $new_owner = $GLOBALS['registry']->convertUsername($new_owner_backend, true);
1854: if ($old_owner !== $new_owner && !empty($new_owner)) {
1855: if ($old_owner != $GLOBALS['registry']->getAuth() && !$GLOBALS['registry']->isAdmin()) {
1856: $errors[] = _("Only the owner or system administrator may change ownership or owner permissions for a share");
1857: } elseif ($auth->hasCapability('list') && !$auth->exists($new_owner_backend)) {
1858: $errors[] = sprintf(_("The user \"%s\" does not exist."), $new_owner_backend);
1859: } else {
1860: $share->set('owner', $new_owner);
1861: $share->save();
1862: if ($GLOBALS['conf']['share']['notify']) {
1863: $view->ownerChange = true;
1864: $multipart = self::buildMimeMessage($view, 'notification', $image);
1865: $to = $GLOBALS['injector']
1866: ->getInstance('Horde_Core_Factory_Identity')
1867: ->create($new_owner)
1868: ->getDefaultFromAddress(true);
1869: $mail->addHeader('Subject', _("Ownership assignment"));
1870: $mail->addHeader('To', $to);
1871: $mail->setBasePart($multipart);
1872: $mail->send($GLOBALS['injector']->getInstance('Horde_Mail'));
1873: $view->ownerChange = false;
1874: }
1875: }
1876: }
1877:
1878: if ($GLOBALS['conf']['share']['notify']) {
1879: if ($GLOBALS['conf']['share']['hidden']) {
1880: $view->subscribe = Horde::url('calendars/subscribe.php', true)->add('calendar', $share->getName());
1881: }
1882: $multipart = self::buildMimeMessage($view, 'notification', $image);
1883: }
1884:
1885: if ($GLOBALS['registry']->isAdmin() ||
1886: !empty($GLOBALS['conf']['share']['world'])) {
1887:
1888: if (Horde_Util::getFormData('default_show')) {
1889: $perm->addDefaultPermission(Horde_Perms::SHOW, false);
1890: } else {
1891: $perm->removeDefaultPermission(Horde_Perms::SHOW, false);
1892: }
1893: if (Horde_Util::getFormData('default_read')) {
1894: $perm->addDefaultPermission(Horde_Perms::READ, false);
1895: } else {
1896: $perm->removeDefaultPermission(Horde_Perms::READ, false);
1897: }
1898: if (Horde_Util::getFormData('default_edit')) {
1899: $perm->addDefaultPermission(Horde_Perms::EDIT, false);
1900: } else {
1901: $perm->removeDefaultPermission(Horde_Perms::EDIT, false);
1902: }
1903: if (Horde_Util::getFormData('default_delete')) {
1904: $perm->addDefaultPermission(Horde_Perms::DELETE, false);
1905: } else {
1906: $perm->removeDefaultPermission(Horde_Perms::DELETE, false);
1907: }
1908: if (Horde_Util::getFormData('default_delegate')) {
1909: $perm->addDefaultPermission(self::PERMS_DELEGATE, false);
1910: } else {
1911: $perm->removeDefaultPermission(self::PERMS_DELEGATE, false);
1912: }
1913:
1914:
1915: if (Horde_Util::getFormData('guest_show')) {
1916: $perm->addGuestPermission(Horde_Perms::SHOW, false);
1917: } else {
1918: $perm->removeGuestPermission(Horde_Perms::SHOW, false);
1919: }
1920: if (Horde_Util::getFormData('guest_read')) {
1921: $perm->addGuestPermission(Horde_Perms::READ, false);
1922: } else {
1923: $perm->removeGuestPermission(Horde_Perms::READ, false);
1924: }
1925: if (Horde_Util::getFormData('guest_edit')) {
1926: $perm->addGuestPermission(Horde_Perms::EDIT, false);
1927: } else {
1928: $perm->removeGuestPermission(Horde_Perms::EDIT, false);
1929: }
1930: if (Horde_Util::getFormData('guest_delete')) {
1931: $perm->addGuestPermission(Horde_Perms::DELETE, false);
1932: } else {
1933: $perm->removeGuestPermission(Horde_Perms::DELETE, false);
1934: }
1935: if (Horde_Util::getFormData('guest_delegate')) {
1936: $perm->addGuestPermission(self::PERMS_DELEGATE, false);
1937: } else {
1938: $perm->removeGuestPermission(self::PERMS_DELEGATE, false);
1939: }
1940: }
1941:
1942:
1943: if (Horde_Util::getFormData('creator_show')) {
1944: $perm->addCreatorPermission(Horde_Perms::SHOW, false);
1945: } else {
1946: $perm->removeCreatorPermission(Horde_Perms::SHOW, false);
1947: }
1948: if (Horde_Util::getFormData('creator_read')) {
1949: $perm->addCreatorPermission(Horde_Perms::READ, false);
1950: } else {
1951: $perm->removeCreatorPermission(Horde_Perms::READ, false);
1952: }
1953: if (Horde_Util::getFormData('creator_edit')) {
1954: $perm->addCreatorPermission(Horde_Perms::EDIT, false);
1955: } else {
1956: $perm->removeCreatorPermission(Horde_Perms::EDIT, false);
1957: }
1958: if (Horde_Util::getFormData('creator_delete')) {
1959: $perm->addCreatorPermission(Horde_Perms::DELETE, false);
1960: } else {
1961: $perm->removeCreatorPermission(Horde_Perms::DELETE, false);
1962: }
1963: if (Horde_Util::getFormData('creator_delegate')) {
1964: $perm->addCreatorPermission(self::PERMS_DELEGATE, false);
1965: } else {
1966: $perm->removeCreatorPermission(self::PERMS_DELEGATE, false);
1967: }
1968:
1969:
1970: $u_names = Horde_Util::getFormData('u_names');
1971: $u_show = Horde_Util::getFormData('u_show');
1972: $u_read = Horde_Util::getFormData('u_read');
1973: $u_edit = Horde_Util::getFormData('u_edit');
1974: $u_delete = Horde_Util::getFormData('u_delete');
1975: $u_delegate = Horde_Util::getFormData('u_delegate');
1976:
1977: $current = $perm->getUserPermissions();
1978: if ($GLOBALS['conf']['share']['notify']) {
1979: $mail->addHeader('Subject', _("Access permissions"));
1980: }
1981:
1982: $perm->removeUserPermission(null, null, false);
1983: foreach ($u_names as $key => $user_backend) {
1984:
1985: $user = $GLOBALS['registry']->convertUsername($user_backend, true);
1986:
1987:
1988: if (empty($user) || $user == $new_owner) {
1989: continue;
1990: }
1991: if ($auth->hasCapability('list') && !$auth->exists($user_backend)) {
1992: $errors[] = sprintf(_("The user \"%s\" does not exist."), $user_backend);
1993: continue;
1994: }
1995:
1996: $has_perms = false;
1997: if (!empty($u_show[$key])) {
1998: $perm->addUserPermission($user, Horde_Perms::SHOW, false);
1999: $has_perms = true;
2000: }
2001: if (!empty($u_read[$key])) {
2002: $perm->addUserPermission($user, Horde_Perms::READ, false);
2003: $has_perms = true;
2004: }
2005: if (!empty($u_edit[$key])) {
2006: $perm->addUserPermission($user, Horde_Perms::EDIT, false);
2007: $has_perms = true;
2008: }
2009: if (!empty($u_delete[$key])) {
2010: $perm->addUserPermission($user, Horde_Perms::DELETE, false);
2011: $has_perms = true;
2012: }
2013: if (!empty($u_delegate[$key])) {
2014: $perm->addUserPermission($user, self::PERMS_DELEGATE, false);
2015: $has_perms = true;
2016: }
2017:
2018:
2019: if ($GLOBALS['conf']['share']['notify'] &&
2020: !isset($current[$user]) && $has_perms) {
2021: $to = $GLOBALS['injector']
2022: ->getInstance('Horde_Core_Factory_Identity')
2023: ->create($user)
2024: ->getDefaultFromAddress(true);
2025: $mail->addHeader('To', $to);
2026: $mail->setBasePart($multipart);
2027: $mail->send($GLOBALS['injector']->getInstance('Horde_Mail'));
2028: }
2029: }
2030:
2031:
2032: $g_names = Horde_Util::getFormData('g_names');
2033: $g_show = Horde_Util::getFormData('g_show');
2034: $g_read = Horde_Util::getFormData('g_read');
2035: $g_edit = Horde_Util::getFormData('g_edit');
2036: $g_delete = Horde_Util::getFormData('g_delete');
2037: $g_delegate = Horde_Util::getFormData('g_delegate');
2038:
2039: $current = $perm->getGroupPermissions();
2040: $perm->removeGroupPermission(null, null, false);
2041: foreach ($g_names as $key => $group) {
2042: if (empty($group)) {
2043: continue;
2044: }
2045:
2046: $has_perms = false;
2047: if (!empty($g_show[$key])) {
2048: $perm->addGroupPermission($group, Horde_Perms::SHOW, false);
2049: $has_perms = true;
2050: }
2051: if (!empty($g_read[$key])) {
2052: $perm->addGroupPermission($group, Horde_Perms::READ, false);
2053: $has_perms = true;
2054: }
2055: if (!empty($g_edit[$key])) {
2056: $perm->addGroupPermission($group, Horde_Perms::EDIT, false);
2057: $has_perms = true;
2058: }
2059: if (!empty($g_delete[$key])) {
2060: $perm->addGroupPermission($group, Horde_Perms::DELETE, false);
2061: $has_perms = true;
2062: }
2063: if (!empty($g_delegate[$key])) {
2064: $perm->addGroupPermission($group, self::PERMS_DELEGATE, false);
2065: $has_perms = true;
2066: }
2067:
2068:
2069: if ($GLOBALS['conf']['share']['notify'] &&
2070: !isset($current[$group]) && $has_perms) {
2071: $groupOb = $GLOBALS['injector']
2072: ->getInstance('Horde_Group')
2073: ->getData($group);
2074: if (!empty($groupOb['email'])) {
2075: $mail->addHeader('To', $groupOb['name'] . ' <' . $groupOb['email'] . '>');
2076: $mail->setBasePart($multipart);
2077: $mail->send($GLOBALS['injector']->getInstance('Horde_Mail'));
2078: }
2079: }
2080: }
2081: try {
2082: $share->setPermission($perm);
2083: } catch (Horde_Share_Exception $e) {
2084: throw new Kronolith_Exception($e);
2085: }
2086:
2087: return $errors;
2088: }
2089:
2090: 2091: 2092: 2093: 2094: 2095: 2096: 2097: 2098:
2099: static public function subscribeRemoteCalendar(&$info, $update = false)
2100: {
2101: if (!(strlen($info['name']) && strlen($info['url']))) {
2102: throw new Kronolith_Exception(_("You must specify a name and a URL."));
2103: }
2104:
2105: if (!empty($info['user']) || !empty($info['password'])) {
2106: $key = $GLOBALS['registry']->getAuthCredential('password');
2107: if ($key) {
2108: $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
2109: $info['user'] = base64_encode($secret->write($key, $info['user']));
2110: $info['password'] = base64_encode($secret->write($key, $info['password']));
2111: }
2112: }
2113:
2114: $remote_calendars = unserialize($GLOBALS['prefs']->getValue('remote_cals'));
2115: if ($update) {
2116: foreach ($remote_calendars as $key => $calendar) {
2117: if ($calendar['url'] == $update) {
2118: $remote_calendars[$key] = $info;
2119: break;
2120: }
2121: }
2122: } else {
2123: $remote_calendars[] = $info;
2124: $GLOBALS['display_remote_calendars'][] = $info['url'];
2125: $GLOBALS['prefs']->setValue('display_remote_cals', serialize($GLOBALS['display_remote_calendars']));
2126: }
2127:
2128: $GLOBALS['prefs']->setValue('remote_cals', serialize($remote_calendars));
2129: }
2130:
2131: 2132: 2133: 2134: 2135: 2136: 2137: 2138:
2139: static public function unsubscribeRemoteCalendar($url)
2140: {
2141: $url = trim($url);
2142: if (!strlen($url)) {
2143: return false;
2144: }
2145:
2146: $remote_calendars = unserialize($GLOBALS['prefs']->getValue('remote_cals'));
2147: $remote_calendar = null;
2148: foreach ($remote_calendars as $key => $calendar) {
2149: if ($calendar['url'] == $url) {
2150: $remote_calendar = $calendar;
2151: unset($remote_calendars[$key]);
2152: break;
2153: }
2154: }
2155: if (!$remote_calendar) {
2156: throw new Kronolith_Exception(_("The remote calendar was not found."));
2157: }
2158:
2159: $GLOBALS['prefs']->setValue('remote_cals', serialize($remote_calendars));
2160:
2161: return $remote_calendar;
2162: }
2163:
2164: 2165: 2166: 2167: 2168: 2169: 2170:
2171: static public function feedUrl($calendar)
2172: {
2173: if (isset($GLOBALS['conf']['urls']['pretty']) &&
2174: $GLOBALS['conf']['urls']['pretty'] == 'rewrite') {
2175: return Horde::url('feed/' . $calendar, true, -1);
2176: }
2177: return Horde::url('feed/index.php', true, -1)
2178: ->add('c', $calendar);
2179: }
2180:
2181: 2182: 2183: 2184: 2185: 2186: 2187: 2188:
2189: static public function embedCode($calendar)
2190: {
2191:
2192: $imple = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Imple')->create(array('kronolith', 'Embed'), array(
2193: 'calendar' => 'internal_' . $calendar,
2194: 'container' => 'kronolithCal',
2195: 'view' => 'month'
2196: ), true);
2197:
2198: $html = '<div id="kronolithCal"></div><script src="' . $imple->getUrl()
2199: . '" type="text/javascript"></script>';
2200:
2201: return $html;
2202: }
2203:
2204: 2205: 2206: 2207: 2208: 2209: 2210: 2211: 2212:
2213: static public function parseAttendees($newAttendees)
2214: {
2215: global $notification;
2216:
2217: if (empty($newAttendees)) {
2218: return array();
2219: }
2220:
2221: $parser = new Horde_Mail_Rfc822();
2222: $attendees = array();
2223:
2224: foreach (Horde_Mime_Address::explode($newAttendees) as $newAttendee) {
2225:
2226:
2227:
2228:
2229: try {
2230: $newAttendeeParsed = $parser->parseAddressList($newAttendee, array(
2231: 'default_domain' => null,
2232: 'nest_groups' => false,
2233: 'validate' => false
2234: ));
2235: $error = (!isset($newAttendeeParsed[0]) || !isset($newAttendeeParsed[0]->mailbox));
2236: } catch (Horde_Mail_Exception $e) {
2237: $error = true;
2238: }
2239:
2240:
2241:
2242: if ($error) {
2243: $notification->push(
2244: sprintf(_("Unable to recognize \"%s\" as an email address."), $newAttendee),
2245: 'horde.error');
2246: continue;
2247: }
2248:
2249:
2250: foreach ($newAttendeeParsed as $newAttendeeParsedPart) {
2251:
2252:
2253: if (empty($newAttendeeParsedPart->host)) {
2254: $attendees[] = array(
2255: 'attendance' => self::PART_REQUIRED,
2256: 'response' => self::RESPONSE_NONE,
2257: 'name' => $newAttendee,
2258: );
2259: continue;
2260: }
2261:
2262:
2263: $name = empty($newAttendeeParsedPart->personal)
2264: ? ''
2265: : $newAttendeeParsedPart->personal;
2266:
2267: try {
2268: $newAttendeeParsedPartNew = Horde_Mime::encodeAddress(Horde_Mime_Address::writeAddress($newAttendeeParsedPart->mailbox, $newAttendeeParsedPart->host, $name), 'UTF-8');
2269: $newAttendeeParsedPartValidated = $parser->parseAddressList($newAttendeeParsedPartNew, array(
2270: 'default_domain' => null
2271: ));
2272:
2273: $email = $newAttendeeParsedPart->mailbox . '@'
2274: . $newAttendeeParsedPart->host;
2275:
2276:
2277: $attendees[Horde_String::lower($email)] = array(
2278: 'attendance' => self::PART_REQUIRED,
2279: 'response' => self::RESPONSE_NONE,
2280: 'name' => $name);
2281: } catch (Horde_Mime_Exception $e) {
2282: $notification->push($e, 'horde.error');
2283: }
2284: }
2285: }
2286:
2287: return $attendees;
2288: }
2289:
2290: 2291: 2292: 2293: 2294:
2295: static public function attendeeList()
2296: {
2297:
2298: $attendees = array();
2299: foreach ($GLOBALS['session']->get('kronolith', 'attendees', Horde_Session::TYPE_ARRAY) as $email => $attendee) {
2300: $attendees[] = empty($attendee['name']) ? $email : Horde_Mime_Address::trimAddress($attendee['name'] . (strpos($email, '@') === false ? '' : ' <' . $email . '>'));
2301: }
2302:
2303:
2304: foreach ($GLOBALS['session']->get('kronolith', 'resources', Horde_Session::TYPE_ARRAY) as $resource) {
2305: $attendees[] = $resource['name'];
2306: }
2307:
2308: return implode(', ', $attendees);
2309: }
2310:
2311: 2312: 2313: 2314: 2315: 2316: 2317: 2318: 2319: 2320: 2321: 2322: 2323: 2324: 2325: 2326: 2327: 2328:
2329: static public function sendITipNotifications($event, $notification,
2330: $action, $instance = null)
2331: {
2332: global $conf, $registry;
2333:
2334: if (!$event->attendees) {
2335: return;
2336: }
2337:
2338: $ident = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($event->creator);
2339: if (!$ident->getValue('from_addr')) {
2340: $notification->push(sprintf(_("You do not have an email address configured in your Personal Information Preferences. You must set one %shere%s before event notifications can be sent."), Horde::getServiceLink('prefs', 'kronolith')->add(array('app' => 'horde', 'group' => 'identities'))->link(), '</a>'), 'horde.error', array('content.raw'));
2341: return;
2342: }
2343:
2344:
2345:
2346: $image = self::getImagePart('big_invitation.png');
2347:
2348: $share = $GLOBALS['kronolith_shares']->getShare($event->calendar);
2349: $view = new Horde_View(array('templatePath' => KRONOLITH_TEMPLATES . '/itip'));
2350: new Horde_View_Helper_Text($view);
2351: $view->identity = $ident;
2352: $view->event = $event;
2353: $view->imageId = $image->getContentId();
2354:
2355: foreach ($event->attendees as $email => $status) {
2356: 2357: 2358:
2359: if (strpos($email, '@') === false ||
2360: $status['attendance'] == self::PART_NONE ||
2361: $status['response'] == self::RESPONSE_DECLINED) {
2362: continue;
2363: }
2364:
2365:
2366: switch ($action) {
2367: case self::ITIP_CANCEL:
2368:
2369: $method = 'CANCEL';
2370: $filename = 'event-cancellation.ics';
2371: $view->subject = sprintf(_("Cancelled: %s"), $event->getTitle());
2372: if (empty($instance)) {
2373: $view->header = sprintf(_("%s has cancelled \"%s\"."), $ident->getName(), $event->getTitle());
2374: } else {
2375: $view->header = sprintf(_("%s has cancelled an instance of the recurring \"%s\"."), $ident->getName(), $event->getTitle());
2376: }
2377: break;
2378:
2379: case self::ITIP_REQUEST:
2380: default:
2381: $method = 'REQUEST';
2382: if ($status['response'] == self::RESPONSE_NONE) {
2383:
2384: $filename = 'event-invitation.ics';
2385: $view->subject = $event->getTitle();
2386: $view->header = sprintf(_("%s wishes to make you aware of \"%s\"."), $ident->getName(), $event->getTitle());
2387: } else {
2388:
2389: $filename = 'event-update.ics';
2390: $view->subject = sprintf(_("Updated: %s."), $event->getTitle());
2391: $view->header = sprintf(_("%s wants to notify you about changes of \"%s\"."), $ident->getName(), $event->getTitle());
2392: }
2393: break;
2394: }
2395:
2396: if ($event->attendees) {
2397: $attendees = array();
2398: foreach ($event->attendees as $mail => $attendee) {
2399: $attendees[] = empty($attendee['name']) ? $mail : Horde_Mime_Address::trimAddress($attendee['name'] . (strpos($mail, '@') === false ? '' : ' <' . $mail . '>'));
2400: }
2401: $view->organizer = $GLOBALS['registry']->convertUserName($event->creator, false);
2402: $view->attendees = $attendees;
2403: }
2404:
2405: if ($action == self::ITIP_REQUEST) {
2406: $attend_link = Horde::url('attend.php', true, -1)
2407: ->add(array('c' => $event->calendar,
2408: 'e' => $event->id,
2409: 'u' => $email));
2410: $view->linkAccept = (string)$attend_link->add('a', 'accept');
2411: $view->linkTentative = (string)$attend_link->add('a', 'tentative');
2412: $view->linkDecline = (string)$attend_link->add('a', 'decline');
2413: }
2414:
2415:
2416: $iCal = new Horde_Icalendar();
2417: $iCal->setAttribute('METHOD', $method);
2418: $iCal->setAttribute('X-WR-CALNAME', $share->get('name'));
2419: $vevent = $event->toiCalendar($iCal);
2420: if ($action == self::ITIP_CANCEL && !empty($instance)) {
2421:
2422:
2423: $vevent = array_pop($vevent);
2424: $vevent->setAttribute('RECURRENCE-ID', $instance, array('VALUE' => 'DATE'));
2425: $vevent->removeAttribute('EXDATE');
2426: }
2427: $iCal->addComponent($vevent);
2428:
2429:
2430: $ics = new Horde_Mime_Part();
2431: $ics->setType('text/calendar');
2432: $ics->setContents($iCal->exportvCalendar());
2433: $ics->setName($filename);
2434: $ics->setContentTypeParameter('METHOD', $method);
2435: $ics->setCharset('UTF-8');
2436: $ics->setEOL("\r\n");
2437:
2438: $multipart = self::buildMimeMessage($view, 'notification', $image);
2439: $multipart->addPart($ics);
2440: $recipient = empty($status['name']) ? $email : Horde_Mime_Address::trimAddress($status['name'] . ' <' . $email . '>');
2441: $mail = new Horde_Mime_Mail(
2442: array('Subject' => $view->subject,
2443: 'To' => $recipient,
2444: 'From' => $ident->getDefaultFromAddress(true),
2445: 'User-Agent' => 'Kronolith ' . $GLOBALS['registry']->getVersion()));
2446: $mail->setBasePart($multipart);
2447:
2448: try {
2449: $mail->send($GLOBALS['injector']->getInstance('Horde_Mail'));
2450: $notification->push(
2451: sprintf(_("The event notification to %s was successfully sent."), $recipient),
2452: 'horde.success'
2453: );
2454: } catch (Horde_Mime_Exception $e) {
2455: $notification->push(
2456: sprintf(_("There was an error sending an event notification to %s: %s"), $recipient, $e->getMessage(), $e->getCode()),
2457: 'horde.error'
2458: );
2459: }
2460: }
2461: }
2462:
2463: 2464: 2465: 2466: 2467: 2468: 2469: 2470: 2471: 2472: 2473:
2474: static public function sendNotification($event, $action)
2475: {
2476: global $conf;
2477:
2478: if (!in_array($action, array('add', 'edit', 'delete'))) {
2479: throw new Kronolith_Exception('Unknown event action: ' . $action);
2480: }
2481:
2482: $groups = $GLOBALS['injector']->getInstance('Horde_Group');
2483: $calendar = $event->calendar;
2484: $recipients = array();
2485: try {
2486: $share = $GLOBALS['kronolith_shares']->getShare($calendar);
2487: } catch (Horde_Share_Exception $e) {
2488: throw new Kronolith_Exception($e);
2489: }
2490:
2491: $senderIdentity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create();
2492:
2493: $owner = $share->get('owner');
2494: if ($owner) {
2495: $recipients[$owner] = self::_notificationPref($owner, 'owner');
2496: }
2497:
2498: foreach ($share->listUsers(Horde_Perms::READ) as $user) {
2499: if (!isset($recipients[$user])) {
2500: $recipients[$user] = self::_notificationPref($user, 'read', $calendar);
2501: }
2502: }
2503:
2504: foreach ($share->listGroups(Horde_Perms::READ) as $group) {
2505: try {
2506: $group_users = $groups->listUsers($group);
2507: } catch (Horde_Group_Exception $e) {
2508: Horde::logMessage($e, 'ERR');
2509: continue;
2510: }
2511:
2512: foreach ($group_users as $user) {
2513: if (!isset($recipients[$user])) {
2514: $recipients[$user] = self::_notificationPref($user, 'read', $calendar);
2515: }
2516: }
2517: }
2518:
2519: $addresses = array();
2520: foreach ($recipients as $user => $vals) {
2521: if (!$vals) {
2522: continue;
2523: }
2524: $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($user);
2525: $email = $identity->getValue('from_addr');
2526: if (strpos($email, '@') === false) {
2527: continue;
2528: }
2529: list($mailbox, $host) = explode('@', $email);
2530: if (!isset($addresses[$vals['lang']][$vals['tf']][$vals['df']])) {
2531: $addresses[$vals['lang']][$vals['tf']][$vals['df']] = array();
2532: }
2533: $addresses[$vals['lang']][$vals['tf']][$vals['df']][] = Horde_Mime_Address::writeAddress($mailbox, $host, $identity->getValue('fullname'));
2534: }
2535:
2536: if (!$addresses) {
2537: return;
2538: }
2539:
2540: foreach ($addresses as $lang => $twentyFour) {
2541: $GLOBALS['registry']->setLanguageEnvironment($lang);
2542:
2543: switch ($action) {
2544: case 'add':
2545: $subject = _("Event added:");
2546: $notification_message = _("You requested to be notified when events are added to your calendars.") . "\n\n" . _("The event \"%s\" has been added to \"%s\" calendar, which is on %s at %s.");
2547: break;
2548:
2549: case 'edit':
2550: $subject = _("Event edited:");
2551: $notification_message = _("You requested to be notified when events are edited in your calendars.") . "\n\n" . _("The event \"%s\" has been edited on \"%s\" calendar, which is on %s at %s.");
2552: break;
2553:
2554: case 'delete':
2555: $subject = _("Event deleted:");
2556: $notification_message = _("You requested to be notified when events are deleted from your calendars.") . "\n\n" . _("The event \"%s\" has been deleted from \"%s\" calendar, which was on %s at %s.");
2557: break;
2558: }
2559:
2560: foreach ($twentyFour as $tf => $dateFormat) {
2561: foreach ($dateFormat as $df => $df_recipients) {
2562: $message = "\n"
2563: . sprintf($notification_message,
2564: $event->title,
2565: $share->get('name'),
2566: $event->start->strftime($df),
2567: $event->start->strftime($tf ? '%R' : '%I:%M%p'))
2568: . "\n\n" . $event->description;
2569:
2570: $mime_mail = new Horde_Mime_Mail(array(
2571: 'Subject' => $subject . ' ' . $event->title,
2572: 'To' => implode(',', $df_recipients),
2573: 'From' => $senderIdentity->getDefaultFromAddress(true),
2574: 'User-Agent' => 'Kronolith ' . $GLOBALS['registry']->getVersion(),
2575: 'body' => $message));
2576: Horde::logMessage(sprintf('Sending event notifications for %s to %s', $event->title, implode(', ', $df_recipients)), 'DEBUG');
2577: $mime_mail->send($GLOBALS['injector']->getInstance('Horde_Mail'));
2578: }
2579: }
2580: }
2581: }
2582:
2583: 2584: 2585: 2586: 2587: 2588: 2589:
2590: static public function notifyOfResourceRejection($event)
2591: {
2592: $declined = array();
2593: $accepted = array();
2594: foreach ($event->getResources() as $id => $resource) {
2595: if ($resource['response'] == self::RESPONSE_DECLINED) {
2596: $r = self::getDriver('Resource')->getResource($id);
2597: $declined[] = $r->get('name');
2598: } elseif ($resource['response'] == self::RESPONSE_ACCEPTED) {
2599: $r = self::getDriver('Resource')->getResource($id);
2600: $accepted[] = $r->get('name');
2601: }
2602:
2603:
2604: }
2605: if (count($declined)) {
2606: $GLOBALS['notification']->push(sprintf(ngettext("The following resource has declined your request: %s",
2607: "The following resources have declined your request: %s",
2608: count($declined)),
2609: implode(", ", $declined)),
2610: 'horde.error');
2611: }
2612: if (count($accepted)) {
2613: $GLOBALS['notification']->push(sprintf(ngettext("The following resource has accepted your request: %s",
2614: "The following resources have accepted your request: %s",
2615: count($accepted)),
2616: implode(", ", $accepted)),
2617: 'horde.success');
2618: }
2619: }
2620:
2621: 2622: 2623: 2624: 2625: 2626: 2627: 2628: 2629: 2630: 2631: 2632: 2633: 2634: 2635: 2636: 2637: 2638: 2639: 2640: 2641:
2642: static public function _notificationPref($user, $mode, $calendar = null)
2643: {
2644: $prefs = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Prefs')->create('kronolith', array(
2645: 'cache' => false,
2646: 'user' => $user
2647: ));
2648: $vals = array('lang' => $prefs->getValue('language'),
2649: 'tf' => $prefs->getValue('twentyFour'),
2650: 'df' => $prefs->getValue('date_format'));
2651:
2652: if ($prefs->getValue('event_notification_exclude_self') &&
2653: $user == $GLOBALS['registry']->getAuth()) {
2654: return false;
2655: }
2656:
2657: switch ($prefs->getValue('event_notification')) {
2658: case 'owner':
2659: return $mode == 'owner' ? $vals : false;
2660:
2661: case 'read':
2662: return $mode == 'read' ? $vals : false;
2663:
2664: case 'show':
2665: if ($mode == 'read') {
2666: $display_calendars = unserialize($prefs->getValue('display_cals'));
2667: return in_array($calendar, $display_calendars) ? $vals : false;
2668: }
2669: }
2670:
2671: return false;
2672: }
2673:
2674: 2675: 2676: 2677: 2678: 2679: 2680: 2681: 2682: 2683:
2684: static public function buildMimeMessage(Horde_View $view, $template,
2685: Horde_Mime_Part $image)
2686: {
2687: $multipart = new Horde_Mime_Part();
2688: $multipart->setType('multipart/alternative');
2689: $bodyText = new Horde_Mime_Part();
2690: $bodyText->setType('text/plain');
2691: $bodyText->setCharset('UTF-8');
2692: $bodyText->setContents($view->render($template . '.plain.php'));
2693: $bodyText->setDisposition('inline');
2694: $multipart->addPart($bodyText);
2695: $bodyHtml = new Horde_Mime_Part();
2696: $bodyHtml->setType('text/html');
2697: $bodyHtml->setCharset('UTF-8');
2698: $bodyHtml->setContents($view->render($template . '.html.php'));
2699: $bodyHtml->setDisposition('inline');
2700: $related = new Horde_Mime_Part();
2701: $related->setType('multipart/related');
2702: $related->setContentTypeParameter('start', $bodyHtml->setContentId());
2703: $related->addPart($bodyHtml);
2704: $related->addPart($image);
2705: $multipart->addPart($related);
2706: return $multipart;
2707: }
2708:
2709: 2710: 2711: 2712: 2713: 2714: 2715:
2716: static public function getImagePart($file)
2717: {
2718: $background = Horde_Themes::img($file);
2719: $image = new Horde_Mime_Part();
2720: $image->setType('image/png');
2721: $image->setContents(file_get_contents($background->fs));
2722: $image->setContentId();
2723: $image->setDisposition('attachment');
2724: return $image;
2725: }
2726:
2727: 2728: 2729:
2730: static public function currentDate()
2731: {
2732: if ($date = Horde_Util::getFormData('date')) {
2733: return new Horde_Date($date . '000000');
2734: }
2735: if ($date = Horde_Util::getFormData('datetime')) {
2736: return new Horde_Date($date);
2737: }
2738:
2739: return new Horde_Date($_SERVER['REQUEST_TIME']);
2740: }
2741:
2742: 2743: 2744: 2745: 2746: 2747: 2748: 2749: 2750:
2751: static public function parseDate($date, $withtime = true)
2752: {
2753:
2754: if (!function_exists('strptime')) {
2755: return new Horde_Date($date);
2756: }
2757:
2758:
2759:
2760:
2761: $format = Horde_Nls::getLangInfo(D_FMT);
2762: if ($withtime) {
2763: $format .= ' '
2764: . ($GLOBALS['prefs']->getValue('twentyFour') ? '%H:%M' : '%I:%M %p');
2765: }
2766: $old_locale = setlocale(LC_TIME, 0);
2767: setlocale(LC_TIME, 'C');
2768:
2769:
2770: $date_arr = strptime($date, $format);
2771: setlocale(LC_TIME, $old_locale);
2772:
2773: if (!$date_arr) {
2774:
2775: $date_arr = strptime($date, $format);
2776: if (!$date_arr) {
2777:
2778: return new Horde_Date($date);
2779: }
2780: }
2781:
2782: return new Horde_Date(
2783: array('year' => $date_arr['tm_year'] + 1900,
2784: 'month' => $date_arr['tm_mon'] + 1,
2785: 'mday' => $date_arr['tm_mday'],
2786: 'hour' => $date_arr['tm_hour'],
2787: 'min' => $date_arr['tm_min'],
2788: 'sec' => $date_arr['tm_sec']));
2789: }
2790:
2791: 2792: 2793:
2794: static public function tabs($tabname = null)
2795: {
2796: $date = self::currentDate();
2797: $date_stamp = $date->dateString();
2798:
2799: $tabs = new Horde_Core_Ui_Tabs('view', Horde_Variables::getDefaultVariables());
2800: $tabs->preserve('date', $date_stamp);
2801:
2802: $tabs->addTab(_("Day"), Horde::url('day.php'),
2803: array('tabname' => 'day', 'id' => 'tabday', 'onclick' => 'return ShowView(\'Day\', \'' . $date_stamp . '\');'));
2804: $tabs->addTab(_("Work Week"), Horde::url('workweek.php'),
2805: array('tabname' => 'workweek', 'id' => 'tabworkweek', 'onclick' => 'return ShowView(\'WorkWeek\', \'' . $date_stamp . '\');'));
2806: $tabs->addTab(_("Week"), Horde::url('week.php'),
2807: array('tabname' => 'week', 'id' => 'tabweek', 'onclick' => 'return ShowView(\'Week\', \'' . $date_stamp . '\');'));
2808: $tabs->addTab(_("Month"), Horde::url('month.php'),
2809: array('tabname' => 'month', 'id' => 'tabmonth', 'onclick' => 'return ShowView(\'Month\', \'' . $date_stamp . '\');'));
2810: $tabs->addTab(_("Year"), Horde::url('year.php'),
2811: array('tabname' => 'year', 'id' => 'tabyear', 'onclick' => 'return ShowView(\'Year\', \'' . $date_stamp . '\');'));
2812:
2813: if ($tabname === null) {
2814: $tabname = basename($_SERVER['PHP_SELF']) == 'index.php' ? $GLOBALS['prefs']->getValue('defaultview') : str_replace('.php', '', basename($_SERVER['PHP_SELF']));
2815: }
2816: echo $tabs->render($tabname);
2817: }
2818:
2819: 2820: 2821: 2822:
2823: static public function eventTabs($tabname, $event)
2824: {
2825: if (!$event->initialized) {
2826: return;
2827: }
2828:
2829: $tabs = new Horde_Core_Ui_Tabs('event', Horde_Variables::getDefaultVariables());
2830:
2831: $date = self::currentDate();
2832: $tabs->preserve('datetime', $date->dateString());
2833:
2834: $tabs->addTab(
2835: htmlspecialchars($event->getTitle()),
2836: $event->getViewUrl(),
2837: array('tabname' => 'Event',
2838: 'id' => 'tabEvent',
2839: 'onclick' => 'return ShowTab(\'Event\');'));
2840: 2841:
2842: if ((!$event->private ||
2843: $event->creator == $GLOBALS['registry']->getAuth()) &&
2844: $event->hasPermission(Horde_Perms::READ) &&
2845: self::getDefaultCalendar(Horde_Perms::EDIT)) {
2846: $tabs->addTab(
2847: $event->hasPermission(Horde_Perms::EDIT) ? _("_Edit") : _("Save As New"),
2848: $event->getEditUrl(),
2849: array('tabname' => 'EditEvent',
2850: 'id' => 'tabEditEvent',
2851: 'onclick' => 'return ShowTab(\'EditEvent\');'));
2852: }
2853: if ($event->hasPermission(Horde_Perms::DELETE)) {
2854: $tabs->addTab(
2855: _("De_lete"),
2856: $event->getDeleteUrl(array('confirm' => 1)),
2857: array('tabname' => 'DeleteEvent',
2858: 'id' => 'tabDeleteEvent',
2859: 'onclick' => 'return ShowTab(\'DeleteEvent\');'));
2860: }
2861: $tabs->addTab(
2862: _("Export"),
2863: $event->getExportUrl(),
2864: array('tabname' => 'ExportEvent',
2865: 'id' => 'tabExportEvent'));
2866:
2867: echo $tabs->render($tabname);
2868: }
2869:
2870: 2871: 2872: 2873: 2874: 2875: 2876: 2877: 2878: 2879: 2880: 2881: 2882: 2883: 2884: 2885:
2886: static public function getDriver($driver = null, $calendar = null)
2887: {
2888: switch ($driver) {
2889: case 'internal':
2890: $driver = '';
2891: break;
2892: case 'external':
2893: case 'tasklists':
2894: $driver = 'Horde';
2895: break;
2896: case 'remote':
2897: $driver = 'Ical';
2898: break;
2899: case 'holiday':
2900: $driver = 'Holidays';
2901: break;
2902: case 'resource':
2903: $driver = 'Resource';
2904: break;
2905: }
2906:
2907: if (empty($driver)) {
2908: $driver = Horde_String::ucfirst($GLOBALS['conf']['calendar']['driver']);
2909: }
2910:
2911: if (!isset(self::$_instances[$driver])) {
2912: switch ($driver) {
2913: case 'Sql':
2914: case 'Resource':
2915: $params = Horde::getDriverConfig('calendar', 'sql');
2916: if ($params['driverconfig'] != 'Horde') {
2917: $customParams = $params;
2918: unset($customParams['driverconfig'], $customParams['table'], $customParams['utc']);
2919: $params['db'] = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Db')->create('kronolith', $customParams);
2920: } else {
2921: $params['db'] = $GLOBALS['injector']->getInstance('Horde_Db_Adapter');
2922: }
2923: break;
2924:
2925: case 'Kolab':
2926: $params['storage'] = $GLOBALS['injector']->getInstance('Horde_Kolab_Storage');
2927: break;
2928:
2929: case 'Ical':
2930: case 'Mock':
2931: $params = array();
2932: break;
2933:
2934: case 'Horde':
2935: $params['registry'] = $GLOBALS['registry'];
2936: break;
2937:
2938: case 'Holidays':
2939: if (empty($GLOBALS['conf']['holidays']['enable'])) {
2940: throw new Kronolith_Exception(_("Holidays are disabled"));
2941: }
2942: $params['language'] = $GLOBALS['language'];
2943: break;
2944:
2945: default:
2946: throw new Kronolith_Exception('No calendar driver specified');
2947: break;
2948: }
2949:
2950: self::$_instances[$driver] = $GLOBALS['injector']->getInstance('Kronolith_Factory_Driver')->create($driver, $params);
2951: }
2952:
2953: if (!is_null($calendar)) {
2954: self::$_instances[$driver]->open($calendar);
2955:
2956: if ($driver == 'Ical') {
2957: self::$_instances[$driver]->setParams(self::getRemoteParams($calendar));
2958: }
2959: }
2960:
2961: return self::$_instances[$driver];
2962: }
2963:
2964: 2965: 2966:
2967: static public function getRemoteParams($calendar)
2968: {
2969: if (empty($calendar)) {
2970: return array();
2971: }
2972:
2973: $cals = unserialize($GLOBALS['prefs']->getValue('remote_cals'));
2974: foreach ($cals as $cal) {
2975: if ($cal['url'] == $calendar) {
2976: $user = isset($cal['user']) ? $cal['user'] : '';
2977: $password = isset($cal['password']) ? $cal['password'] : '';
2978: $key = $GLOBALS['registry']->getAuthCredential('password');
2979: if ($key && $password) {
2980: $secret = $GLOBALS['injector']->getInstance('Horde_Secret');
2981: $user = $secret->read($key, base64_decode($user));
2982: $password = $secret->read($key, base64_decode($password));
2983: }
2984: if (!empty($user)) {
2985: return array('user' => $user, 'password' => $password);
2986: }
2987: return array();
2988: }
2989: }
2990:
2991: return array();
2992: }
2993:
2994: 2995: 2996: 2997: 2998: 2999:
3000: static public function getView($view)
3001: {
3002: switch ($view) {
3003: case 'Day':
3004: case 'Month':
3005: case 'Week':
3006: case 'WorkWeek':
3007: case 'Year':
3008: $class = 'Kronolith_View_' . $view;
3009: return new $class(self::currentDate());
3010:
3011: case 'Event':
3012: case 'EditEvent':
3013: case 'DeleteEvent':
3014: case 'ExportEvent':
3015: try {
3016: if ($uid = Horde_Util::getFormData('uid')) {
3017: $event = self::getDriver()->getByUID($uid);
3018: } else {
3019: $event = self::getDriver(Horde_Util::getFormData('type'),
3020: Horde_Util::getFormData('calendar'))
3021: ->getEvent(Horde_Util::getFormData('eventID'),
3022: Horde_Util::getFormData('datetime'));
3023: }
3024: } catch (Horde_Exception $e) {
3025: $event = $e->getMessage();
3026: }
3027: switch ($view) {
3028: case 'Event':
3029: if (!is_string($event) &&
3030: !$event->hasPermission(Horde_Perms::READ)) {
3031: $event = _("Permission Denied");
3032: }
3033: return new Kronolith_View_Event($event);
3034: case 'EditEvent':
3035: 3036:
3037: if (!is_string($event) &&
3038: !$event->hasPermission(Horde_Perms::READ)) {
3039: $event = _("Permission Denied");
3040: }
3041: return new Kronolith_View_EditEvent($event);
3042: case 'DeleteEvent':
3043: if (!is_string($event) &&
3044: !$event->hasPermission(Horde_Perms::DELETE)) {
3045: $event = _("Permission Denied");
3046: }
3047: return new Kronolith_View_DeleteEvent($event);
3048: case 'ExportEvent':
3049: if (!is_string($event) &&
3050: !$event->hasPermission(Horde_Perms::READ)) {
3051: $event = _("Permission Denied");
3052: }
3053: return new Kronolith_View_ExportEvent($event);
3054: }
3055: }
3056: }
3057:
3058: 3059: 3060:
3061: static public function viewShowLocation()
3062: {
3063: $show = @unserialize($GLOBALS['prefs']->getValue('show_location'));
3064: return @in_array('screen', $show);
3065: }
3066:
3067: 3068: 3069:
3070: static public function viewShowTime()
3071: {
3072: $show = @unserialize($GLOBALS['prefs']->getValue('show_time'));
3073: return @in_array('screen', $show);
3074: }
3075:
3076: 3077: 3078: 3079: 3080: 3081: 3082: 3083: 3084:
3085: static public function backgroundColor($calendar)
3086: {
3087: $color = '';
3088: if (!is_array($calendar)) {
3089: $color = $calendar->get('color');
3090: } elseif (isset($calendar['color'])) {
3091: $color = $calendar['color'];
3092: }
3093: return empty($color) ? '#dddddd' : $color;
3094: }
3095:
3096: 3097: 3098: 3099: 3100: 3101: 3102: 3103: 3104: 3105:
3106: static public function foregroundColor($calendar)
3107: {
3108: return Horde_Image::brightness(is_string($calendar) ? $calendar : self::backgroundColor($calendar)) < 128 ? '#fff' : '#000';
3109: }
3110:
3111: 3112: 3113: 3114: 3115: 3116: 3117: 3118: 3119: 3120: 3121:
3122: static public function getCSSColors($calendar, $with_attribute = true)
3123: {
3124: $css = 'background-color:' . self::backgroundColor($calendar) . ';color:' . self::foregroundColor($calendar);
3125: if ($with_attribute) {
3126: $css = ' style="' . $css . '"';
3127: }
3128: return $css;
3129: }
3130:
3131: 3132: 3133: 3134: 3135:
3136: static public function showAjaxView()
3137: {
3138: global $prefs, $session;
3139:
3140: $mode = $session->get('horde', 'mode');
3141: return ($mode == 'dynamic' || ($prefs->getValue('dynamic_view') && $mode == 'auto')) && Horde::ajaxAvailable();
3142: }
3143:
3144: 3145: 3146: 3147: 3148: 3149: 3150: 3151: 3152:
3153: static public function sortEvents($days)
3154: {
3155: foreach ($days as $day => $devents) {
3156: if (count($devents)) {
3157: uasort($devents, array('Kronolith', '_sortEventStartTime'));
3158: $days[$day] = $devents;
3159: }
3160: }
3161: return $days;
3162: }
3163:
3164: 3165: 3166:
3167: static protected function _sortEventStartTime($a, $b)
3168: {
3169: $diff = $a->start->compareDateTime($b->start);
3170: if ($diff == 0) {
3171: return strcoll($a->title, $b->title);
3172: } else {
3173: return $diff;
3174: }
3175: }
3176:
3177: 3178: 3179: 3180: 3181:
3182: static public function getTagger()
3183: {
3184: if (empty(self::$_tagger)) {
3185: self::$_tagger = new Kronolith_Tagger();
3186: }
3187: return self::$_tagger;
3188: }
3189:
3190: 3191: 3192: 3193: 3194: 3195: 3196: 3197: 3198:
3199: static public function getInternalCalendar($target)
3200: {
3201: if (Kronolith::getDriver('Resource')->isResourceCalendar($target)) {
3202: $driver = self::getDriver('Resource');
3203: $id = $driver->getResourceIdByCalendar($target);
3204: return $driver->getResource($id);
3205: } else {
3206: return $GLOBALS['kronolith_shares']->getShare($target);
3207: }
3208: }
3209:
3210: 3211: 3212: 3213: 3214:
3215: static public function getAddressbookSearchParams()
3216: {
3217: $src = json_decode($GLOBALS['prefs']->getValue('search_sources'));
3218: if (empty($src)) {
3219: $src = array();
3220: }
3221:
3222: $fields = json_decode($GLOBALS['prefs']->getValue('search_fields'), true);
3223: if (empty($fields)) {
3224: $fields = array();
3225: }
3226:
3227: return array(
3228: 'fields' => $fields,
3229: 'sources' => $src
3230: );
3231: }
3232:
3233: 3234: 3235: 3236: 3237: 3238: 3239: 3240: 3241:
3242: static public function hasApiPermission($api, $perm = Horde_Perms::READ)
3243: {
3244: $app = $GLOBALS['registry']->hasInterface($api);
3245: return ($app && $GLOBALS['registry']->hasPermission($app, $perm));
3246: }
3247:
3248: 3249: 3250: 3251: 3252: 3253: 3254: 3255: 3256: 3257: 3258:
3259: static public function removeUserEvents($user)
3260: {
3261: if (!$GLOBALS['registry']->isAdmin()) {
3262: throw new Horde_Exception_PermissionDenied();
3263: }
3264:
3265: try {
3266: $shares = $GLOBALS['kronolith_shares']->listShares(
3267: $user, array('perm' => Horde_Perms::EDIT));
3268: } catch (Horde_Share_Exception $e) {
3269: Horde::logMessage($shares, 'ERR');
3270: throw new Kronolith_Exception($shares);
3271: }
3272:
3273: foreach (array_keys($shares) as $calendar) {
3274: $driver = Kronolith::getDriver(null, $calendar);
3275: $events = $driver->listEvents(null, null, false, false, false);
3276: $uids = array();
3277: foreach ($events as $dayevents) {
3278: foreach ($dayevents as $event) {
3279: $uids[] = $event->uid;
3280: }
3281: }
3282: foreach ($uids as $uid) {
3283: $event = $driver->getByUID($uid, array($calendar));
3284: $driver->deleteEvent($event->id);
3285: }
3286: }
3287: }
3288:
3289: }
3290: