1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: abstract class Kronolith_Event
15: {
16: 17: 18: 19: 20: 21:
22: public $initialized = false;
23:
24: 25: 26: 27: 28:
29: public $stored = false;
30:
31: 32: 33: 34: 35:
36: protected $_id = null;
37:
38: 39: 40: 41: 42:
43: public $uid = null;
44:
45: 46: 47: 48: 49:
50: public $sequence = null;
51:
52: 53: 54: 55: 56:
57: protected $_creator = null;
58:
59: 60: 61: 62: 63: 64: 65:
66: public $title = '';
67:
68: 69: 70: 71: 72:
73: public $location = '';
74:
75: 76: 77: 78: 79:
80: public $status = Kronolith::STATUS_CONFIRMED;
81:
82: 83: 84: 85: 86:
87: public $icon = '';
88:
89: 90: 91: 92: 93:
94: public $description = '';
95:
96: 97: 98: 99: 100:
101: public $url = '';
102:
103: 104: 105: 106: 107:
108: public $private = false;
109:
110: 111: 112: 113: 114:
115: protected $_tags = null;
116:
117: 118: 119: 120: 121:
122: protected $_geoLocation;
123:
124: 125: 126: 127: 128:
129: public $first = true;
130:
131: 132: 133: 134: 135:
136: public $last = true;
137:
138: 139: 140: 141: 142: 143: 144: 145: 146: 147:
148: public $attendees = array();
149:
150: 151: 152: 153: 154: 155: 156: 157:
158: protected $_resources = array();
159:
160: 161: 162: 163: 164:
165: public $start;
166:
167: 168: 169: 170: 171:
172: public $end;
173:
174: 175: 176: 177: 178:
179: public $durMin = 0;
180:
181: 182: 183: 184: 185:
186: public $allday = false;
187:
188: 189: 190: 191: 192:
193: public $alarm = 0;
194:
195: 196: 197: 198: 199: 200: 201:
202: protected $_snooze;
203:
204: 205: 206: 207: 208:
209: public $methods;
210:
211: 212: 213: 214: 215:
216: public $calendar;
217:
218: 219: 220: 221: 222:
223: public $calendarType;
224:
225: 226: 227: 228: 229:
230: protected $_backgroundColor = '#dddddd';
231:
232: 233: 234: 235: 236:
237: protected $_foregroundColor = '#000000';
238:
239: 240: 241: 242: 243:
244: private $_varRenderer;
245:
246: 247: 248: 249: 250:
251: public $recurrence;
252:
253: 254: 255: 256: 257:
258: protected $_overlap;
259:
260: 261: 262: 263: 264:
265: protected $_indent;
266:
267: 268: 269: 270: 271:
272: protected $_span;
273:
274: 275: 276: 277: 278:
279: protected $_rowspan;
280:
281: 282: 283: 284: 285: 286:
287: public $baseid;
288:
289: 290: 291: 292: 293: 294:
295: public $exceptionoriginaldate;
296:
297: 298: 299: 300: 301: 302:
303: protected $_duration;
304:
305: 306: 307: 308: 309: 310: 311: 312:
313: public function __construct($driver, $eventObject = null)
314: {
315: $this->calendar = $driver->calendar;
316: list($this->_backgroundColor, $this->_foregroundColor) = $driver->colors();
317:
318: if (!is_null($eventObject)) {
319: $this->fromDriver($eventObject);
320: }
321: }
322:
323: 324: 325: 326: 327: 328: 329: 330:
331: public function __set($name, $value)
332: {
333: switch ($name) {
334: case 'id':
335: if (substr($value, 0, 10) == 'kronolith:') {
336: $value = substr($value, 10);
337: }
338:
339: case 'creator':
340: case 'overlap':
341: case 'indent':
342: case 'span':
343: case 'rowspan':
344: case 'geoLocation':
345: case 'tags':
346: $this->{'_' . $name} = $value;
347: return;
348: }
349: $trace = debug_backtrace();
350: trigger_error('Undefined property via __set(): ' . $name
351: . ' in ' . $trace[0]['file']
352: . ' on line ' . $trace[0]['line'],
353: E_USER_NOTICE);
354: }
355:
356: 357: 358: 359: 360: 361: 362: 363: 364:
365: public function __get($name)
366: {
367: switch ($name) {
368: case 'creator':
369: if (empty($this->_creator)) {
370: $this->_creator = $GLOBALS['registry']->getAuth();
371: }
372:
373: case 'id':
374: case 'overlap':
375: case 'indent':
376: case 'span':
377: case 'rowspan':
378: return $this->{'_' . $name};
379: case 'tags':
380: if (!isset($this->_tags)) {
381: $this->_tags = Kronolith::getTagger()->getTags($this->uid, 'event');
382: }
383: return $this->_tags;
384: case 'geoLocation':
385: if (!isset($this->_geoLocation)) {
386: try {
387: $this->_geoLocation = $GLOBALS['injector']->getInstance('Kronolith_Geo')->getLocation($this->id);
388: } catch (Kronolith_Exception $e) {}
389: }
390: return $this->_geoLocation;
391: }
392:
393: $trace = debug_backtrace();
394: trigger_error('Undefined property via __set(): ' . $name
395: . ' in ' . $trace[0]['file']
396: . ' on line ' . $trace[0]['line'],
397: E_USER_NOTICE);
398: return null;
399: }
400:
401: 402: 403: 404: 405: 406:
407: public function getDriver()
408: {
409: return Kronolith::getDriver(str_replace('Kronolith_Event_', '', get_class($this)), $this->calendar);
410: }
411:
412: 413: 414: 415: 416: 417:
418: public function getShare()
419: {
420: if (isset($GLOBALS['all_calendars'][$this->calendar])) {
421: return $GLOBALS['all_calendars'][$this->calendar]->share();
422: }
423: throw new Kronolith_Exception('Share not found');
424: }
425:
426: 427: 428: 429: 430: 431: 432: 433:
434: public function hasPermission($permission, $user = null)
435: {
436: if ($user === null) {
437: $user = $GLOBALS['registry']->getAuth();
438: }
439: try {
440: $share = $this->getShare();
441: } catch (Exception $e) {
442: return false;
443: }
444: return $share->hasPermission($user, $permission, $this->creator);
445: }
446:
447: 448: 449: 450: 451: 452:
453: public function save()
454: {
455: if (!$this->initialized) {
456: throw new Kronolith_Exception('Event not yet initialized');
457: }
458:
459:
460: $add_events = array();
461: $locks = $GLOBALS['injector']->getInstance('Horde_Lock');
462: $lock = array();
463: $failed_resources = array();
464: foreach ($this->getResources() as $id => $resourceData) {
465: 466:
467: $resource = Kronolith::getDriver('Resource')->getResource($id);
468: $rcal = $resource->get('calendar');
469: if ($rcal == $this->calendar) {
470: continue;
471: }
472:
473:
474: if ($resource->get('response_type') == Kronolith_Resource::RESPONSETYPE_AUTO) {
475: $principle = 'calendar/' . $rcal;
476: $lock[$resource->getId()] = $locks->setLock($GLOBALS['registry']->getAuth(), 'kronolith', $principle, 5, Horde_Lock::TYPE_EXCLUSIVE);
477: $haveLock = true;
478: } else {
479: $haveLock = false;
480: }
481: if ($haveLock && !$lock[$resource->getId()]) {
482:
483:
484:
485: throw new Kronolith_Exception(sprintf(_("The resource \"%s\" was locked. Please try again."), $resource->get('name')));
486: } else {
487: $response = $resource->getResponse($this);
488: }
489:
490: 491:
492: if ($response == Kronolith::RESPONSE_ACCEPTED) {
493: $add_events[] = $resource;
494: } else {
495: $locks->clearLock($lock[$resource->getId()]);
496: }
497:
498:
499: $this->addResource($resource, $response);
500: }
501:
502:
503: $result = $this->getDriver()->saveEvent($this);
504:
505: 506: 507: 508: 509: 510:
511: foreach ($add_events as $resource) {
512: $resource->addEvent($this);
513: if ($resource->get('response_type') == Kronolith_Resource::RESPONSETYPE_AUTO) {
514: $locks->clearLock($lock[$resource->getId()]);
515: }
516: }
517:
518: $hordeAlarm = $GLOBALS['injector']->getInstance('Horde_Alarm');
519: if ($alarm = $this->toAlarm(new Horde_Date($_SERVER['REQUEST_TIME']))) {
520: $alarm['start'] = new Horde_Date($alarm['start']);
521: $alarm['end'] = new Horde_Date($alarm['end']);
522: $hordeAlarm->set($alarm);
523: if ($this->_snooze) {
524: $hordeAlarm->snooze($this->uid, $GLOBALS['registry']->getAuth(), $this->_snooze);
525: }
526: } else {
527: $hordeAlarm->delete($this->uid);
528: }
529:
530: return $result;
531: }
532:
533: 534: 535: 536: 537: 538:
539: public function fromDriver($event)
540: {
541: }
542:
543: 544: 545: 546: 547: 548: 549: 550:
551: public function toiCalendar($calendar)
552: {
553: $vEvent = Horde_Icalendar::newComponent('vevent', $calendar);
554: $v1 = $calendar->getAttribute('VERSION') == '1.0';
555: $vEvents = array();
556:
557:
558: $end = clone $this->end;
559: $end->sec++;
560: if ($this->isAllDay()) {
561: $vEvent->setAttribute('DTSTART', $this->start, array('VALUE' => 'DATE'));
562: $vEvent->setAttribute('DTEND', $end, array('VALUE' => 'DATE'));
563: $vEvent->setAttribute('X-FUNAMBOL-ALLDAY', 1);
564: } else {
565: $vEvent->setAttribute('DTSTART', $this->start);
566: $vEvent->setAttribute('DTEND', $end);
567: }
568:
569: $vEvent->setAttribute('DTSTAMP', $_SERVER['REQUEST_TIME']);
570: $vEvent->setAttribute('UID', $this->uid);
571:
572:
573: $created = $modified = null;
574: try {
575: $log = $GLOBALS['injector']->getInstance('Horde_History')->getHistory('kronolith:' . $this->calendar . ':' . $this->uid);
576: foreach ($log as $entry) {
577: switch ($entry['action']) {
578: case 'add':
579: $created = $entry['ts'];
580: break;
581:
582: case 'modify':
583: $modified = $entry['ts'];
584: break;
585: }
586: }
587: } catch (Exception $e) {}
588: if (!empty($created)) {
589: $vEvent->setAttribute($v1 ? 'DCREATED' : 'CREATED', $created);
590: if (empty($modified)) {
591: $modified = $created;
592: }
593: }
594: if (!empty($modified)) {
595: $vEvent->setAttribute('LAST-MODIFIED', $modified);
596: }
597:
598: $vEvent->setAttribute('SUMMARY', $this->getTitle());
599:
600:
601: if (count($this->attendees)) {
602: $name = Kronolith::getUserName($this->creator);
603: $email = Kronolith::getUserEmail($this->creator);
604: $params = array();
605: if ($v1) {
606: if (!empty($name)) {
607: if (!empty($email)) {
608: $email = ' <' . $email . '>';
609: }
610: $email = $name . $email;
611: $email = Horde_Mime_Address::trimAddress($email);
612: }
613: } else {
614: if (!empty($name)) {
615: $params['CN'] = $name;
616: }
617: if (!empty($email)) {
618: $email = 'mailto:' . $email;
619: }
620: }
621: $vEvent->setAttribute('ORGANIZER', $email, $params);
622: }
623: if (!$this->isPrivate()) {
624: if (!empty($this->description)) {
625: $vEvent->setAttribute('DESCRIPTION', $this->description);
626: }
627:
628:
629: if ($this->tags) {
630: $tags = implode(', ', $this->tags);
631: $vEvent->setAttribute('CATEGORIES', $tags);
632: }
633:
634:
635: if (!empty($this->location)) {
636: $vEvent->setAttribute('LOCATION', $this->location);
637: }
638: if ($this->geoLocation) {
639: $vEvent->setAttribute('GEO', array('latitude' => $this->geoLocation['lat'], 'longitude' => $this->geoLocation['lon']));
640: }
641:
642:
643: if (!empty($this->url)) {
644: $vEvent->setAttribute('URL', $this->url);
645: }
646: }
647: $vEvent->setAttribute('CLASS', $this->private ? 'PRIVATE' : 'PUBLIC');
648:
649:
650: switch ($this->status) {
651: case Kronolith::STATUS_FREE:
652:
653:
654: $vEvent->setAttribute('STATUS', 'FREE');
655: $vEvent->setAttribute('TRANSP', $v1 ? 1 : 'TRANSPARENT');
656: break;
657: case Kronolith::STATUS_TENTATIVE:
658: $vEvent->setAttribute('STATUS', 'TENTATIVE');
659: $vEvent->setAttribute('TRANSP', $v1 ? 0 : 'OPAQUE');
660: break;
661: case Kronolith::STATUS_CONFIRMED:
662: $vEvent->setAttribute('STATUS', 'CONFIRMED');
663: $vEvent->setAttribute('TRANSP', $v1 ? 0 : 'OPAQUE');
664: break;
665: case Kronolith::STATUS_CANCELLED:
666: if ($v1) {
667: $vEvent->setAttribute('STATUS', 'DECLINED');
668: $vEvent->setAttribute('TRANSP', 1);
669: } else {
670: $vEvent->setAttribute('STATUS', 'CANCELLED');
671: $vEvent->setAttribute('TRANSP', 'TRANSPARENT');
672: }
673: break;
674: }
675:
676:
677: foreach ($this->attendees as $email => $status) {
678: $params = array();
679: switch ($status['attendance']) {
680: case Kronolith::PART_REQUIRED:
681: if ($v1) {
682: $params['EXPECT'] = 'REQUIRE';
683: } else {
684: $params['ROLE'] = 'REQ-PARTICIPANT';
685: }
686: break;
687:
688: case Kronolith::PART_OPTIONAL:
689: if ($v1) {
690: $params['EXPECT'] = 'REQUEST';
691: } else {
692: $params['ROLE'] = 'OPT-PARTICIPANT';
693: }
694: break;
695:
696: case Kronolith::PART_NONE:
697: if ($v1) {
698: $params['EXPECT'] = 'FYI';
699: } else {
700: $params['ROLE'] = 'NON-PARTICIPANT';
701: }
702: break;
703: }
704:
705: switch ($status['response']) {
706: case Kronolith::RESPONSE_NONE:
707: if ($v1) {
708: $params['STATUS'] = 'NEEDS ACTION';
709: $params['RSVP'] = 'YES';
710: } else {
711: $params['PARTSTAT'] = 'NEEDS-ACTION';
712: $params['RSVP'] = 'TRUE';
713: }
714: break;
715:
716: case Kronolith::RESPONSE_ACCEPTED:
717: if ($v1) {
718: $params['STATUS'] = 'ACCEPTED';
719: } else {
720: $params['PARTSTAT'] = 'ACCEPTED';
721: }
722: break;
723:
724: case Kronolith::RESPONSE_DECLINED:
725: if ($v1) {
726: $params['STATUS'] = 'DECLINED';
727: } else {
728: $params['PARTSTAT'] = 'DECLINED';
729: }
730: break;
731:
732: case Kronolith::RESPONSE_TENTATIVE:
733: if ($v1) {
734: $params['STATUS'] = 'TENTATIVE';
735: } else {
736: $params['PARTSTAT'] = 'TENTATIVE';
737: }
738: break;
739: }
740:
741: if (strpos($email, '@') === false) {
742: $email = '';
743: }
744: if ($v1) {
745: if (!empty($status['name'])) {
746: if (!empty($email)) {
747: $email = ' <' . $email . '>';
748: }
749: $email = $status['name'] . $email;
750: $email = Horde_Mime_Address::trimAddress($email);
751: }
752: } else {
753: if (!empty($status['name'])) {
754: $params['CN'] = $status['name'];
755: }
756: if (!empty($email)) {
757: $email = 'mailto:' . $email;
758: }
759: }
760:
761: $vEvent->setAttribute('ATTENDEE', $email, $params);
762: }
763:
764:
765: if (!empty($this->alarm)) {
766: if ($v1) {
767: $alarm = new Horde_Date($this->start);
768: $alarm->min -= $this->alarm;
769: $vEvent->setAttribute('AALARM', $alarm);
770: } else {
771: $vAlarm = Horde_Icalendar::newComponent('valarm', $vEvent);
772: $vAlarm->setAttribute('ACTION', 'DISPLAY');
773: $vAlarm->setAttribute('DESCRIPTION', $this->getTitle());
774: $vAlarm->setAttribute('TRIGGER;VALUE=DURATION', '-PT' . $this->alarm . 'M');
775: $vEvent->addComponent($vAlarm);
776: }
777: $hordeAlarm = $GLOBALS['injector']->getInstance('Horde_Alarm');
778: if ($hordeAlarm->exists($this->uid, $GLOBALS['registry']->getAuth()) &&
779: $hordeAlarm->isSnoozed($this->uid, $GLOBALS['registry']->getAuth())) {
780: $vEvent->setAttribute('X-MOZ-LASTACK', new Horde_Date($_SERVER['REQUEST_TIME']));
781: $alarm = $hordeAlarm->get($this->uid, $GLOBALS['registry']->getAuth());
782: if (!empty($alarm['snooze'])) {
783: $alarm['snooze']->setTimezone(date_default_timezone_get());
784: $vEvent->setAttribute('X-MOZ-SNOOZE-TIME', $alarm['snooze']);
785: }
786: }
787: }
788:
789:
790: if ($this->recurs()) {
791: if ($v1) {
792: $rrule = $this->recurrence->toRRule10($calendar);
793: } else {
794: $rrule = $this->recurrence->toRRule20($calendar);
795: }
796: if (!empty($rrule)) {
797: $vEvent->setAttribute('RRULE', $rrule);
798: }
799:
800:
801:
802:
803:
804:
805:
806: $exceptions = $this->recurrence->getExceptions();
807: $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
808: $search = new StdClass();
809: $search->baseid = $this->uid;
810: $results = $kronolith_driver->search($search);
811: $exdates = array();
812: foreach ($results as $days) {
813: foreach ($days as $exceptionEvent) {
814:
815:
816:
817: if (!$v1) {
818: $exceptionEvent->uid = $this->uid;
819: }
820: $vEventException = $exceptionEvent->toiCalendar($calendar);
821:
822:
823: if (count($vEventException) > 1) {
824: throw new Kronolith_Exception(_("Unable to parse event."));
825: }
826: $vEventException = array_pop($vEventException);
827:
828: if (!$v1) {
829: $vEventException->setAttribute('RECURRENCE-ID', $exceptionEvent->exceptionoriginaldate->timestamp());
830: } else {
831: $exdates[] = $exceptionEvent->exceptionoriginaldate;
832: }
833: $originaldate = $exceptionEvent->exceptionoriginaldate->format('Ymd');
834: $key = array_search($originaldate, $exceptions);
835: if ($key !== false) {
836: unset($exceptions[$key]);
837: }
838: $vEvents[] = $vEventException;
839: }
840: }
841:
842:
843: foreach ($exceptions as $exception) {
844: if (!empty($exception)) {
845: list($year, $month, $mday) = sscanf($exception, '%04d%02d%02d');
846: $exdates[] = new Horde_Date($year, $month, $mday);
847: }
848: }
849: if ($exdates) {
850: $vEvent->setAttribute('EXDATE', $exdates);
851: }
852: }
853: array_unshift($vEvents, $vEvent);
854:
855: return $vEvents;
856: }
857:
858: 859: 860: 861: 862: 863: 864:
865: public function fromiCalendar($vEvent)
866: {
867:
868: try {
869: $uid = $vEvent->getAttribute('UID');
870: if (!empty($uid)) {
871: $this->uid = $uid;
872: }
873: } catch (Horde_Icalendar_Exception $e) {}
874:
875:
876: try {
877: $seq = $vEvent->getAttribute('SEQUENCE');
878: if (is_int($seq)) {
879: $this->sequence = $seq;
880: }
881: } catch (Horde_Icalendar_Exception $e) {}
882:
883:
884: try {
885: $title = $vEvent->getAttribute('SUMMARY');
886: if (!is_array($title)) {
887: $this->title = $title;
888: }
889: } catch (Horde_Icalendar_Exception $e) {}
890:
891:
892: try {
893: $this->_tags = $vEvent->getAttributeValues('CATEGORIES');
894: } catch (Horde_Icalendar_Exception $e) {}
895:
896:
897: try {
898: $desc = $vEvent->getAttribute('DESCRIPTION');
899: if (!is_array($desc)) {
900: $this->description = $desc;
901: }
902: } catch (Horde_Icalendar_Exception $e) {}
903:
904:
905: try {
906: $url = $vEvent->getAttribute('URL');
907: if (!is_array($url)) {
908: $this->url = $url;
909: }
910: } catch (Horde_Icalendar_Exception $e) {}
911:
912:
913: try {
914: $location = $vEvent->getAttribute('LOCATION');
915: if (!is_array($location)) {
916: $this->location = $location;
917: }
918: } catch (Horde_Icalendar_Exception $e) {}
919:
920: try {
921: $geolocation = $vEvent->getAttribute('GEO');
922: $this->geoLocation = array(
923: 'lat' => $geolocation['latitude'],
924: 'lon' => $geolocation['longitude']
925: );
926: } catch (Horde_Icalendar_Exception $e) {}
927:
928:
929: try {
930: $class = $vEvent->getAttribute('CLASS');
931: if (!is_array($class)) {
932: $class = Horde_String::upper($class);
933: $this->private = $class == 'PRIVATE' || $class == 'CONFIDENTIAL';
934: }
935: } catch (Horde_Icalendar_Exception $e) {}
936:
937:
938: try {
939: $status = $vEvent->getAttribute('STATUS');
940: if (!is_array($status)) {
941: $status = Horde_String::upper($status);
942: if ($status == 'DECLINED') {
943: $status = 'CANCELLED';
944: }
945: if (defined('Kronolith::STATUS_' . $status)) {
946: $this->status = constant('Kronolith::STATUS_' . $status);
947: }
948: }
949: } catch (Horde_Icalendar_Exception $e) {}
950:
951:
952:
953: $this->allday = false;
954:
955:
956: try {
957: $start = $vEvent->getAttribute('DTSTART');
958: if (!is_array($start)) {
959:
960: $this->start = new Horde_Date($start);
961: } else {
962:
963: $this->start = new Horde_Date(
964: array('year' => (int)$start['year'],
965: 'month' => (int)$start['month'],
966: 'mday' => (int)$start['mday']));
967: }
968: } catch (Horde_Icalendar_Exception $e) {}
969:
970: try {
971: $end = $vEvent->getAttribute('DTEND');
972: if (!is_array($end)) {
973:
974: $this->end = new Horde_Date($end);
975:
976:
977:
978: if (is_object($this->start) && $this->start->hour == 0 &&
979: $this->start->min == 0 && $this->start->sec == 0 &&
980: $this->end->hour == 23 && $this->end->min == 59) {
981: $this->end = new Horde_Date(
982: array('year' => (int)$this->end->year,
983: 'month' => (int)$this->end->month,
984: 'mday' => (int)$this->end->mday + 1));
985: }
986: } else {
987:
988: $this->end = new Horde_Date(
989: array('year' => (int)$end['year'],
990: 'month' => (int)$end['month'],
991: 'mday' => (int)$end['mday']));
992: }
993: } catch (Horde_Icalendar_Exception $e) {
994: $end = null;
995: }
996:
997: if (is_null($end)) {
998: try {
999: $duration = $vEvent->getAttribute('DURATION');
1000: if (!is_array($duration)) {
1001: $this->end = new Horde_Date($this->start);
1002: $this->end->sec += $duration;
1003: $end = 1;
1004: }
1005: } catch (Horde_Icalendar_Exception $e) {}
1006:
1007: if (is_null($end)) {
1008:
1009: $this->end = new Horde_Date($this->start);
1010: if (is_array($start)) {
1011:
1012: $this->end->mday++;
1013: }
1014: }
1015: }
1016:
1017:
1018: try {
1019: $alarm = $vEvent->getAttribute('AALARM');
1020: if (!is_array($alarm) && intval($alarm)) {
1021: $this->alarm = intval(($this->start->timestamp() - $alarm) / 60);
1022: }
1023: } catch (Horde_Icalendar_Exception $e) {}
1024:
1025:
1026: foreach ($vEvent->getComponents() as $alarm) {
1027: if (!($alarm instanceof Horde_Icalendar_Valarm)) {
1028: continue;
1029: }
1030: try {
1031:
1032:
1033: $trigger = $alarm->getAttribute('TRIGGER');
1034: $triggerParams = $alarm->getAttribute('TRIGGER', true);
1035: } catch (Horde_Icalendar_Exception $e) {
1036: continue;
1037: }
1038: if (!is_array($triggerParams)) {
1039: $triggerParams = array($triggerParams);
1040: }
1041: foreach ($triggerParams as $tp) {
1042: if (isset($tp['VALUE']) &&
1043: $tp['VALUE'] == 'DATE-TIME') {
1044: if (isset($tp['RELATED']) &&
1045: $tp['RELATED'] == 'END') {
1046: $this->alarm = intval(($this->end->timestamp() - $trigger) / 60);
1047: } else {
1048: $this->alarm = intval(($this->start->timestamp() - $trigger) / 60);
1049: }
1050: } else {
1051: $this->alarm = -intval($trigger / 60);
1052: if (isset($tp['RELATED']) &&
1053: $tp['RELATED'] == 'END') {
1054: $this->alarm -= $this->durMin;
1055: }
1056: }
1057: }
1058: }
1059:
1060:
1061: if ($this->alarm) {
1062: try {
1063:
1064:
1065: $vEvent->getAttribute('X-MOZ-LASTACK');
1066: $hordeAlarm = $GLOBALS['injector']->getInstance('Horde_Alarm');
1067: try {
1068:
1069: $snooze = $vEvent->getAttribute('X-MOZ-SNOOZE-TIME');
1070: $this->_snooze = intval(($snooze - time()) / 60);
1071: } catch (Horde_Icalendar_Exception $e) {
1072:
1073: $this->_snooze = -1;
1074: }
1075: } catch (Horde_Icalendar_Exception $e) {
1076: }
1077: }
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086: try {
1087: $attendee = $vEvent->getAttribute('X-ATTENDEE');
1088: if (!is_array($attendee)) {
1089: $attendee = array($attendee);
1090: }
1091: $params = $vEvent->getAttribute('X-ATTENDEE', true);
1092: if (!is_array($params)) {
1093: $params = array($params);
1094: }
1095: for ($i = 0; $i < count($attendee); ++$i) {
1096: $attendee[$i] = str_replace(array('MAILTO:', 'mailto:'), '',
1097: $attendee[$i]);
1098: $email = Horde_Mime_Address::bareAddress($attendee[$i]);
1099:
1100: $attendance = Kronolith::PART_REQUIRED;
1101:
1102: if (!empty($params[$i]['ROLE'])) {
1103: switch($params[$i]['ROLE']) {
1104: case 'OPT-PARTICIPANT':
1105: $attendance = Kronolith::PART_OPTIONAL;
1106: break;
1107:
1108: case 'NON-PARTICIPANT':
1109: $attendance = Kronolith::PART_NONE;
1110: break;
1111: }
1112: }
1113:
1114: if (!empty($params[$i]['EXPECT'])) {
1115: switch($params[$i]['EXPECT']) {
1116: case 'REQUEST':
1117: $attendance = Kronolith::PART_OPTIONAL;
1118: break;
1119:
1120: case 'FYI':
1121: $attendance = Kronolith::PART_NONE;
1122: break;
1123: }
1124: }
1125: $response = Kronolith::RESPONSE_NONE;
1126: if (empty($params[$i]['PARTSTAT']) &&
1127: !empty($params[$i]['STATUS'])) {
1128: $params[$i]['PARTSTAT'] = $params[$i]['STATUS'];
1129: }
1130:
1131: if (!empty($params[$i]['PARTSTAT'])) {
1132: switch($params[$i]['PARTSTAT']) {
1133: case 'ACCEPTED':
1134: $response = Kronolith::RESPONSE_ACCEPTED;
1135: break;
1136:
1137: case 'DECLINED':
1138: $response = Kronolith::RESPONSE_DECLINED;
1139: break;
1140:
1141: case 'TENTATIVE':
1142: $response = Kronolith::RESPONSE_TENTATIVE;
1143: break;
1144: }
1145: }
1146: $name = isset($params[$i]['CN']) ? $params[$i]['CN'] : null;
1147:
1148: $this->addAttendee($email, $attendance, $response, $name);
1149: }
1150: } catch (Horde_Icalendar_Exception $e) {}
1151:
1152: $this->_handlevEventRecurrence($vEvent);
1153:
1154: $this->initialized = true;
1155: }
1156:
1157: 1158: 1159: 1160: 1161:
1162: protected function _handlevEventRecurrence($vEvent)
1163: {
1164:
1165: try {
1166: $rrule = $vEvent->getAttribute('RRULE');
1167: if (!is_array($rrule)) {
1168: $this->recurrence = new Horde_Date_Recurrence($this->start);
1169: if (strpos($rrule, '=') !== false) {
1170: $this->recurrence->fromRRule20($rrule);
1171: } else {
1172: $this->recurrence->fromRRule10($rrule);
1173: }
1174:
1175:
1176: if (!empty($this->uid)) {
1177: $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
1178: $search = new StdClass();
1179: $search->start = $this->recurrence->getRecurStart();
1180: $search->end = $this->recurrence->getRecurEnd();
1181: $search->baseid = $this->uid;
1182: $results = $kronolith_driver->search($search);
1183: foreach ($results as $days) {
1184: foreach ($days as $exception) {
1185: $kronolith_driver->deleteEvent($exception->id);
1186: }
1187: }
1188: }
1189:
1190:
1191:
1192: $exdates = $vEvent->getAttributeValues('EXDATE');
1193: if (is_array($exdates)) {
1194: foreach ($exdates as $exdate) {
1195: if (is_array($exdate)) {
1196: $this->recurrence->addException(
1197: (int)$exdate['year'],
1198: (int)$exdate['month'],
1199: (int)$exdate['mday']);
1200: }
1201: }
1202: }
1203: }
1204: } catch (Horde_Icalendar_Exception $e) {}
1205:
1206:
1207: try {
1208: $recurrenceid = $vEvent->getAttribute('RECURRENCE-ID');
1209: $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
1210: $originaldt = new Horde_Date($recurrenceid);
1211: $this->exceptionoriginaldate = $originaldt;
1212: $this->baseid = $this->uid;
1213: $this->uid = null;
1214: $originalEvent = $kronolith_driver->getByUID($this->baseid);
1215: $originalEvent->recurrence->addException($originaldt->format('Y'),
1216: $originaldt->format('m'),
1217: $originaldt->format('d'));
1218: $originalEvent->save();
1219: } catch (Horde_Icalendar_Exception $e) {}
1220: }
1221:
1222: 1223: 1224: 1225: 1226:
1227: public function fromASAppointment(Horde_ActiveSync_Message_Appointment $message)
1228: {
1229:
1230: if ($this->id === null) {
1231: $this->creator = $GLOBALS['registry']->getAuth();
1232: }
1233: if (strlen($title = $message->getSubject())) {
1234: $this->title = $title;
1235: }
1236: if (strlen($description = $message->getBody())) {
1237: $this->description = $description;
1238: }
1239: if (strlen($location = $message->getLocation())) {
1240: $this->location = $location;
1241: }
1242:
1243:
1244: $tz = $message->getTimezone();
1245: $dates = $message->getDatetime();
1246: $this->start = clone($dates['start']);
1247: $this->start->setTimezone($tz);
1248: $this->end = clone($dates['end']);
1249: $this->end->setTimezone($tz);
1250: $this->allday = $dates['allday'];
1251:
1252:
1253: $this->private = ($message->getSensitivity() == Horde_ActiveSync_Message_Appointment::SENSITIVITY_PRIVATE || $message->getSensitivity() == Horde_ActiveSync_Message_Appointment::SENSITIVITY_CONFIDENTIAL) ? true : false;
1254:
1255:
1256: $status = $message->getBusyStatus();
1257: switch ($status) {
1258: case Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY:
1259: $status = Kronolith::STATUS_CONFIRMED;
1260: break;
1261:
1262: case Horde_ActiveSync_Message_Appointment::BUSYSTATUS_FREE:
1263: $status = Kronolith::STATUS_FREE;
1264: break;
1265:
1266: case Horde_ActiveSync_Message_Appointment::BUSYSTATUS_TENTATIVE:
1267: $status = Kronolith::STATUS_TENTATIVE;
1268: break;
1269:
1270: case Horde_ActiveSync_Message_Appointment::BUSYSTATUS_OUT:
1271: $status = Kronolith::STATUS_CONFIRMED;
1272: default:
1273: $status = Kronolith::STATUS_NONE;
1274: }
1275: $this->status = $status;
1276:
1277:
1278: if ($alarm = $message->getReminder()) {
1279: $this->alarm = $alarm;
1280: }
1281:
1282:
1283: if ($rrule = $message->getRecurrence()) {
1284:
1285:
1286: 1287: 1288: 1289:
1290: $this->recurrence = $rrule;
1291: if (!empty($this->uid)) {
1292: $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
1293: $search = new StdClass();
1294: $search->start = $rrule->getRecurStart();
1295: $search->end = $rrule->getRecurEnd();
1296: $search->baseid = $this->uid;
1297: $results = $kronolith_driver->search($search);
1298: foreach ($results as $days) {
1299: foreach ($days as $exception) {
1300: $kronolith_driver->deleteEvent($exception->id);
1301: }
1302: }
1303: }
1304:
1305: $erules = $message->getExceptions();
1306: foreach ($erules as $rule){
1307:
1308: if (!$rule->deleted) {
1309: $event = $kronolith_driver->getEvent();
1310: $times = $rule->getDatetime();
1311: $original = $rule->getExceptionStartTime();
1312: $this->recurrence->addException($original->format('Y'), $original->format('m'), $original->format('d'));
1313: $event->start = $times['start'];
1314: $event->end = $times['end'];
1315: $event->allday = $times['allday'];
1316: $event->title = $rule->getSubject();
1317: $event->description = $rule->getBody();
1318: $event->baseid = $this->uid;
1319: $event->exceptionoriginaldate = $original;
1320: $event->initialized = true;
1321: $event->save();
1322: } else {
1323:
1324: $exceptiondt = $rule->getExceptionStartTime();
1325: $this->recurrence->addException($exceptiondt->format('Y'), $exceptiondt->format('m'), $exceptiondt->format('d'));
1326: }
1327: }
1328: }
1329:
1330:
1331: $attendees = $message->getAttendees();
1332: foreach ($attendees as $attendee) {
1333:
1334: $this->addAttendee($attendee->email,
1335: Kronolith::PART_NONE,
1336: Kronolith::RESPONSE_NONE,
1337: $attendee->name);
1338: }
1339:
1340:
1341: $this->_tags = $message->getCategories();
1342:
1343:
1344: $this->initialized = true;
1345: }
1346:
1347: 1348: 1349: 1350: 1351:
1352: public function toASAppointment()
1353: {
1354: $message = new Horde_ActiveSync_Message_Appointment(
1355: array('logger' => $GLOBALS['injector']->getInstance('Horde_Log_Logger')));
1356: $message->setSubject($this->getTitle());
1357: if (!$this->isPrivate()) {
1358: $message->setBody($this->description);
1359: $message->setLocation($this->location);
1360: }
1361:
1362:
1363: $message->setDatetime(array('start' => $this->start,
1364: 'end' => $this->end,
1365: 'allday' => $this->isAllDay()));
1366:
1367:
1368: $message->setTimezone($this->start);
1369:
1370:
1371: if (count($this->attendees)) {
1372: $name = Kronolith::getUserName($this->creator);
1373: $message->setOrganizer(
1374: array('name' => $name,
1375: 'email' => Kronolith::getUserEmail($this->creator))
1376: );
1377: }
1378:
1379:
1380: $message->setSensitivity($this->private ?
1381: Horde_ActiveSync_Message_Appointment::SENSITIVITY_PRIVATE :
1382: Horde_ActiveSync_Message_Appointment::SENSITIVITY_NORMAL);
1383:
1384:
1385: switch ($this->status) {
1386: case Kronolith::STATUS_CANCELLED:
1387: $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_FREE;
1388: break;
1389: case Kronolith::STATUS_CONFIRMED:
1390: $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_BUSY;
1391: break;
1392: case Kronolith::STATUS_TENTATIVE:
1393: $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_TENTATIVE;
1394: case Kronolith::STATUS_FREE:
1395: case Kronolith::STATUS_NONE:
1396: $status = Horde_ActiveSync_Message_Appointment::BUSYSTATUS_FREE;
1397: }
1398: $message->setBusyStatus($status);
1399:
1400:
1401: $message->setDTStamp($_SERVER['REQUEST_TIME']);
1402:
1403:
1404: if ($this->recurs()) {
1405: $message->setRecurrence($this->recurrence);
1406:
1407: 1408: 1409: 1410: 1411: 1412: 1413:
1414: if (!empty($this->recurrence) && $exceptions = $this->recurrence->getExceptions()) {
1415: $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
1416: $search = new StdClass();
1417: $search->start = $this->recurrence->getRecurStart();
1418: $search->end = $this->recurrence->getRecurEnd();
1419: $search->baseid = $this->uid;
1420: $results = $kronolith_driver->search($search);
1421: foreach ($results as $days) {
1422: foreach ($days as $exception) {
1423: $e = new Horde_ActiveSync_Message_Exception();
1424:
1425: $e->setDateTime(
1426: array('start' => $exception->start,
1427: 'end' => $exception->end,
1428: 'allday' => $exception->isAllDay()));
1429:
1430: $e->setExceptionStartTime($exception->exceptionoriginaldate);
1431: $originaldate = $exception->exceptionoriginaldate->format('Ymd');
1432: $key = array_search($originaldate, $exceptions);
1433: if ($key !== false) {
1434: unset($exceptions[$key]);
1435: }
1436:
1437:
1438: $e->setSubject($exception->getTitle());
1439: if (!$exception->isPrivate()) {
1440: $e->setLocation($exception->location);
1441: $e->setBody($exception->description);
1442: }
1443:
1444: $e->setSensitivity($exception->private ?
1445: Horde_ActiveSync_Message_Appointment::SENSITIVITY_PRIVATE :
1446: Horde_ActiveSync_Message_Appointment::SENSITIVITY_NORMAL);
1447:
1448: $e->setReminder($exception->alarm);
1449: $e->setDTStamp($_SERVER['REQUEST_TIME']);
1450:
1451: switch ($exception->status) {
1452: case Kronolith::STATUS_CANCELLED:
1453: $status = 'declined';
1454: break;
1455: case Kronolith::STATUS_CONFIRMED:
1456: $status = 'accepted';
1457: break;
1458: case Kronolith::STATUS_TENTATIVE:
1459: $status = 'tentative';
1460: case Kronolith::STATUS_FREE:
1461: case Kronolith::STATUS_NONE:
1462: $status = 'none';
1463: }
1464: $e->setResponseType($status);
1465:
1466:
1467: if (!$exception->isPrivate()) {
1468: foreach ($exception->tags as $tag) {
1469: $e->addCategory($tag);
1470: }
1471: }
1472: $message->addexception($e);
1473:
1474: }
1475: }
1476:
1477:
1478: foreach ($exceptions as $deleted) {
1479: $e = new Horde_ActiveSync_Message_Exception();
1480:
1481:
1482: $st = new Horde_Date($deleted);
1483: $st->hour = $this->start->hour;
1484: $st->min = $this->start->min;
1485: $e->setExceptionStartTime($st);
1486: $e->deleted = true;
1487: $message->addException($e);
1488: }
1489: }
1490: }
1491:
1492:
1493: if (!$this->isPrivate() && count($this->attendees)) {
1494: $message->setMeetingStatus(Horde_ActiveSync_Message_Appointment::MEETING_IS_MEETING);
1495: foreach ($this->attendees as $email => $properties) {
1496: $attendee = new Horde_ActiveSync_Message_Attendee();
1497: $attendee->email = $email;
1498:
1499:
1500:
1501: $message->addAttendee($attendee);
1502: }
1503: }
1504:
1505:
1506:
1507:
1508:
1509:
1510:
1511:
1512:
1513:
1514:
1515:
1516:
1517:
1518: if ($this->alarm) {
1519: $message->setReminder($this->alarm);
1520: }
1521:
1522:
1523: if (!$this->isPrivate()) {
1524: foreach ($this->tags as $tag) {
1525: $message->addCategory($tag);
1526: }
1527: }
1528:
1529: return $message;
1530: }
1531:
1532: 1533: 1534: 1535: 1536: 1537: 1538:
1539: public function fromHash($hash)
1540: {
1541:
1542: if ($this->id === null) {
1543: $this->creator = $GLOBALS['registry']->getAuth();
1544: }
1545: if (!empty($hash['title'])) {
1546: $this->title = $hash['title'];
1547: } else {
1548: throw new Kronolith_Exception(_("Events must have a title."));
1549: }
1550: if (!empty($hash['description'])) {
1551: $this->description = $hash['description'];
1552: }
1553: if (!empty($hash['location'])) {
1554: $this->location = $hash['location'];
1555: }
1556: if (!empty($hash['private'])) {
1557: $this->private = true;
1558: }
1559: if (!empty($hash['start_date'])) {
1560: $date = explode('-', $hash['start_date']);
1561: if (empty($hash['start_time'])) {
1562: $time = array(0, 0, 0);
1563: } else {
1564: $time = explode(':', $hash['start_time']);
1565: if (count($time) == 2) {
1566: $time[2] = 0;
1567: }
1568: }
1569: if (count($time) == 3 && count($date) == 3) {
1570: $this->start = new Horde_Date(array('year' => $date[0],
1571: 'month' => $date[1],
1572: 'mday' => $date[2],
1573: 'hour' => $time[0],
1574: 'min' => $time[1],
1575: 'sec' => $time[2]));
1576: }
1577: } else {
1578: throw new Kronolith_Exception(_("Events must have a start date."));
1579: }
1580: if (empty($hash['duration'])) {
1581: if (empty($hash['end_date'])) {
1582: $hash['end_date'] = $hash['start_date'];
1583: }
1584: if (empty($hash['end_time'])) {
1585: $hash['end_time'] = $hash['start_time'];
1586: }
1587: } else {
1588: $weeks = str_replace('W', '', $hash['duration'][1]);
1589: $days = str_replace('D', '', $hash['duration'][2]);
1590: $hours = str_replace('H', '', $hash['duration'][4]);
1591: $minutes = isset($hash['duration'][5]) ? str_replace('M', '', $hash['duration'][5]) : 0;
1592: $seconds = isset($hash['duration'][6]) ? str_replace('S', '', $hash['duration'][6]) : 0;
1593: $hash['duration'] = ($weeks * 60 * 60 * 24 * 7) + ($days * 60 * 60 * 24) + ($hours * 60 * 60) + ($minutes * 60) + $seconds;
1594: $this->end = new Horde_Date($this->start);
1595: $this->end->sec += $hash['duration'];
1596: }
1597: if (!empty($hash['end_date'])) {
1598: $date = explode('-', $hash['end_date']);
1599: if (empty($hash['end_time'])) {
1600: $time = array(0, 0, 0);
1601: } else {
1602: $time = explode(':', $hash['end_time']);
1603: if (count($time) == 2) {
1604: $time[2] = 0;
1605: }
1606: }
1607: if (count($time) == 3 && count($date) == 3) {
1608: $this->end = new Horde_Date(array('year' => $date[0],
1609: 'month' => $date[1],
1610: 'mday' => $date[2],
1611: 'hour' => $time[0],
1612: 'min' => $time[1],
1613: 'sec' => $time[2]));
1614: }
1615: }
1616: if (!empty($hash['alarm'])) {
1617: $this->alarm = (int)$hash['alarm'];
1618: } elseif (!empty($hash['alarm_date']) &&
1619: !empty($hash['alarm_time'])) {
1620: $date = explode('-', $hash['alarm_date']);
1621: $time = explode(':', $hash['alarm_time']);
1622: if (count($time) == 2) {
1623: $time[2] = 0;
1624: }
1625: if (count($time) == 3 && count($date) == 3) {
1626: $alarm = new Horde_Date(array('hour' => $time[0],
1627: 'min' => $time[1],
1628: 'sec' => $time[2],
1629: 'month' => $date[1],
1630: 'mday' => $date[2],
1631: 'year' => $date[0]));
1632: $this->alarm = ($this->start->timestamp() - $alarm->timestamp()) / 60;
1633: }
1634: }
1635: if (!empty($hash['recur_type'])) {
1636: $this->recurrence = new Horde_Date_Recurrence($this->start);
1637: $this->recurrence->setRecurType($hash['recur_type']);
1638: if (!empty($hash['recur_end_date'])) {
1639: $date = explode('-', $hash['recur_end_date']);
1640: $this->recurrence->setRecurEnd(new Horde_Date(array('year' => $date[0], 'month' => $date[1], 'mday' => $date[2])));
1641: }
1642: if (!empty($hash['recur_interval'])) {
1643: $this->recurrence->setRecurInterval($hash['recur_interval']);
1644: }
1645: if (!empty($hash['recur_data'])) {
1646: $this->recurrence->setRecurOnDay($hash['recur_data']);
1647: }
1648: }
1649:
1650: $this->initialized = true;
1651: }
1652:
1653: 1654: 1655: 1656: 1657: 1658: 1659: 1660: 1661:
1662: public function toAlarm($time, $user = null, $prefs = null)
1663: {
1664: if (!$this->alarm) {
1665: return;
1666: }
1667:
1668: if ($this->recurs()) {
1669: $eventDate = $this->recurrence->nextRecurrence($time);
1670: if ($eventDate && $this->recurrence->hasException($eventDate->year, $eventDate->month, $eventDate->mday)) {
1671: return;
1672: }
1673: }
1674:
1675: $serverName = $_SERVER['SERVER_NAME'];
1676: $serverConf = $GLOBALS['conf']['server']['name'];
1677: if (!empty($GLOBALS['conf']['reminder']['server_name'])) {
1678: $_SERVER['SERVER_NAME'] = $GLOBALS['conf']['server']['name'] = $GLOBALS['conf']['reminder']['server_name'];
1679: }
1680:
1681: if (empty($user)) {
1682: $user = $GLOBALS['registry']->getAuth();
1683: }
1684: if (empty($prefs)) {
1685: $prefs = $GLOBALS['prefs'];
1686: }
1687:
1688: $methods = !empty($this->methods) ? $this->methods : @unserialize($prefs->getValue('event_alarms'));
1689: $start = clone $this->start;
1690: $start->min -= $this->alarm;
1691: if (isset($methods['notify'])) {
1692: $methods['notify']['show'] = array(
1693: '__app' => $GLOBALS['registry']->getApp(),
1694: 'event' => $this->id,
1695: 'calendar' => $this->calendar);
1696: $methods['notify']['ajax'] = 'event:' . $this->calendarType . '|' . $this->calendar . ':' . $this->id . ':' . $start->dateString();
1697: if (!empty($methods['notify']['sound'])) {
1698: if ($methods['notify']['sound'] == 'on') {
1699:
1700: $methods['notify']['sound'] = (string)Horde_Themes::sound('theetone.wav');
1701: } else {
1702:
1703:
1704: $methods['notify']['sound'] = (string)Horde_Themes::sound($methods['notify']['sound']);
1705: }
1706: }
1707: if ($this->isAllDay()) {
1708: if ($this->start->compareDate($this->end) == 0) {
1709: $methods['notify']['subtitle'] = sprintf(_("On %s"), '<strong>' . $this->start->strftime($prefs->getValue('date_format')) . '</strong>');
1710: } else {
1711: $methods['notify']['subtitle'] = sprintf(_("From %s to %s"), '<strong>' . $this->start->strftime($prefs->getValue('date_format')) . '</strong>', '<strong>' . $this->end->strftime($prefs->getValue('date_format')) . '</strong>');
1712: }
1713: } else {
1714: $methods['notify']['subtitle'] = sprintf(_("From %s at %s to %s at %s"), '<strong>' . $this->start->strftime($prefs->getValue('date_format')), $this->start->format($prefs->getValue('twentyFour') ? 'H:i' : 'h:ia') . '</strong>', '<strong>' . $this->end->strftime($prefs->getValue('date_format')), $this->end->format($prefs->getValue('twentyFour') ? 'H:i' : 'h:ia') . '</strong>');
1715: }
1716: }
1717: if (isset($methods['mail'])) {
1718: $image = Kronolith::getImagePart('big_alarm.png');
1719:
1720: $view = new Horde_View(array('templatePath' => KRONOLITH_TEMPLATES . '/alarm', 'encoding' => 'UTF-8'));
1721: new Horde_View_Helper_Text($view);
1722: $view->event = $this;
1723: $view->imageId = $image->getContentId();
1724: $view->user = $user;
1725: $view->dateFormat = $prefs->getValue('date_format');
1726: $view->timeFormat = $prefs->getValue('twentyFour') ? 'H:i' : 'h:ia';
1727: if (!$prefs->isLocked('event_reminder')) {
1728: $view->prefsUrl = Horde::url(Horde::getServiceLink('prefs', 'kronolith'), true)->remove(session_name());
1729: }
1730: if (!$this->isPrivate() && $this->attendees) {
1731: $attendees = array();
1732: foreach ($this->attendees as $mail => $attendee) {
1733: $attendees[] = empty($attendee['name']) ? $mail : Horde_Mime_Address::trimAddress($attendee['name'] . (strpos($mail, '@') === false ? '' : ' <' . $mail . '>'));
1734: }
1735: $view->attendees = $attendees;
1736: }
1737:
1738: $methods['mail']['mimepart'] = Kronolith::buildMimeMessage($view, 'mail', $image);
1739: }
1740:
1741: $alarm = array(
1742: 'id' => $this->uid,
1743: 'user' => $user,
1744: 'start' => $start,
1745: 'end' => $this->end,
1746: 'methods' => array_keys($methods),
1747: 'params' => $methods,
1748: 'title' => $this->getTitle($user),
1749: 'text' => $this->description);
1750:
1751: $_SERVER['SERVER_NAME'] = $serverName;
1752: $GLOBALS['conf']['server']['name'] = $serverConf;
1753:
1754: return $alarm;
1755: }
1756:
1757: 1758: 1759: 1760: 1761: 1762: 1763: 1764: 1765: 1766: 1767: 1768: 1769: 1770: 1771: 1772: 1773: 1774: 1775: 1776: 1777: 1778: 1779: 1780: 1781: 1782: 1783: 1784: 1785: 1786: 1787: 1788: 1789: 1790: 1791: 1792: 1793: 1794: 1795: 1796: 1797: 1798: 1799: 1800: 1801:
1802: public function toJson($allDay = null, $full = false, $time_format = 'H:i')
1803: {
1804: $json = new stdClass;
1805: $json->t = $this->getTitle();
1806: $json->c = $this->calendar;
1807: $json->s = $this->start->toJson();
1808: $json->e = $this->end->toJson();
1809: $json->fi = $this->first;
1810: $json->la = $this->last;
1811: $json->x = (int)$this->status;
1812: $json->al = is_null($allDay) ? $this->isAllDay() : $allDay;
1813: $json->pe = $this->hasPermission(Horde_Perms::EDIT);
1814: $json->pd = $this->hasPermission(Horde_Perms::DELETE);
1815: $json->l = $this->getLocation();
1816: if ($this->icon) {
1817: $json->ic = $this->icon;
1818: }
1819: if ($this->alarm) {
1820: if ($this->alarm % 10080 == 0) {
1821: $alarm_value = $this->alarm / 10080;
1822: $json->a = sprintf(ngettext("%d week", "%d weeks", $alarm_value), $alarm_value);
1823: } elseif ($this->alarm % 1440 == 0) {
1824: $alarm_value = $this->alarm / 1440;
1825: $json->a = sprintf(ngettext("%d day", "%d days", $alarm_value), $alarm_value);
1826: } elseif ($this->alarm % 60 == 0) {
1827: $alarm_value = $this->alarm / 60;
1828: $json->a = sprintf(ngettext("%d hour", "%d hours", $alarm_value), $alarm_value);
1829: } else {
1830: $alarm_value = $this->alarm;
1831: $json->a = sprintf(ngettext("%d minute", "%d minutes", $alarm_value), $alarm_value);
1832: }
1833: }
1834: if ($this->recurs()) {
1835: $json->r = $this->recurrence->getRecurType();
1836: } elseif ($this->baseid) {
1837: $json->bid = $this->baseid;
1838: if ($this->exceptionoriginaldate) {
1839: $json->eod = sprintf(_("%s at %s"), $this->exceptionoriginaldate->strftime($GLOBALS['prefs']->getValue('date_format')), $this->exceptionoriginaldate->strftime(($GLOBALS['prefs']->getValue('twentyFour') ? '%H:%M' : '%I:%M %p')));
1840: }
1841: }
1842:
1843: if ($full) {
1844: $json->id = $this->id;
1845: $json->ty = $this->calendarType;
1846: $json->sd = $this->start->strftime('%x');
1847: $json->st = $this->start->format($time_format);
1848: $json->ed = $this->end->strftime('%x');
1849: $json->et = $this->end->format($time_format);
1850: $json->a = $this->alarm;
1851: $json->pv = $this->private;
1852: if ($this->recurs()) {
1853: $json->r = $this->recurrence->toJson();
1854: }
1855: if (!$this->isPrivate()) {
1856: $json->d = $this->description;
1857: $json->u = $this->url;
1858: $json->tg = array_values($this->tags);
1859: $json->gl = $this->geoLocation;
1860: if ($this->attendees) {
1861: $attendees = array();
1862: foreach ($this->attendees as $email => $info) {
1863: $attendee = array('a' => (int)$info['attendance'],
1864: 'r' => (int)$info['response'],
1865: 'l' => empty($info['name']) ? $email : Horde_Mime_Address::trimAddress($info['name'] . (strpos($email, '@') === false ? '' : ' <' . $email . '>')));
1866: if (strpos($email, '@') !== false) {
1867: $attendee['e'] = $email;
1868: }
1869: $attendees[] = $attendee;
1870: }
1871: $json->at = $attendees;
1872: }
1873: }
1874: if ($this->methods) {
1875: $json->m = $this->methods;
1876: }
1877: }
1878:
1879: return $json;
1880: }
1881:
1882: 1883: 1884: 1885: 1886: 1887: 1888:
1889: public function exists()
1890: {
1891: if (!isset($this->uid) || !isset($this->calendar)) {
1892: return false;
1893: }
1894: try {
1895: $eventID = $this->getDriver()->exists($this->uid, $this->calendar);
1896: if (!$eventID) {
1897: return false;
1898: }
1899: } catch (Exception $e) {
1900: return false;
1901: }
1902: $this->id = $eventID;
1903: return true;
1904: }
1905:
1906: public function getDuration()
1907: {
1908: if (isset($this->_duration)) {
1909: return $this->_duration;
1910: }
1911:
1912: if ($this->start && $this->end) {
1913: $dur_day_match = Date_Calc::dateDiff($this->start->mday,
1914: $this->start->month,
1915: $this->start->year,
1916: $this->end->mday,
1917: $this->end->month,
1918: $this->end->year);
1919: $dur_hour_match = $this->end->hour - $this->start->hour;
1920: $dur_min_match = $this->end->min - $this->start->min;
1921: while ($dur_min_match < 0) {
1922: $dur_min_match += 60;
1923: --$dur_hour_match;
1924: }
1925: while ($dur_hour_match < 0) {
1926: $dur_hour_match += 24;
1927: --$dur_day_match;
1928: }
1929: if ($dur_hour_match == 0 && $dur_min_match == 0 &&
1930: $this->end->mday - $this->start->mday == 1) {
1931: $dur_day_match = 1;
1932: $dur_hour_match = 0;
1933: $dur_min_match = 0;
1934: $whole_day_match = true;
1935: } else {
1936: $whole_day_match = false;
1937: }
1938: } else {
1939: $dur_day_match = 0;
1940: $dur_hour_match = 1;
1941: $dur_min_match = 0;
1942: $whole_day_match = false;
1943: }
1944:
1945: $this->_duration = new stdClass;
1946: $this->_duration->day = $dur_day_match;
1947: $this->_duration->hour = $dur_hour_match;
1948: $this->_duration->min = $dur_min_match;
1949: $this->_duration->wholeDay = $whole_day_match;
1950:
1951: return $this->_duration;
1952: }
1953:
1954: 1955: 1956: 1957: 1958:
1959: public function recurs()
1960: {
1961: return isset($this->recurrence) &&
1962: !$this->recurrence->hasRecurType(Horde_Date_Recurrence::RECUR_NONE) &&
1963: empty($this->baseid);
1964: }
1965:
1966: 1967: 1968: 1969: 1970:
1971: public function getRecurName()
1972: {
1973: if (empty($this->baseid)) {
1974: return $this->recurs()
1975: ? $this->recurrence->getRecurName()
1976: : _("No recurrence");
1977: } else {
1978: return _("Exception");
1979: }
1980: }
1981:
1982: 1983: 1984: 1985: 1986: 1987: 1988: 1989:
1990: public function exceptionLink($date)
1991: {
1992: if (!preg_match('/(\d{4})(\d{2})(\d{2})/', $date, $match)) {
1993: return '';
1994: }
1995: $horde_date = new Horde_Date(array('year' => $match[1],
1996: 'month' => $match[2],
1997: 'mday' => $match[3]));
1998: $formatted = $horde_date->strftime($GLOBALS['prefs']->getValue('date_format'));
1999: return $formatted
2000: . Horde::url('edit.php')
2001: ->add(array('calendar' => $this->calendarType . '_' .$this->calendar,
2002: 'eventID' => $this->id,
2003: 'del_exception' => $date,
2004: 'url' => Horde_Util::getFormData('url')))
2005: ->link(array('title' => sprintf(_("Delete exception on %s"), $formatted)))
2006: . Horde::img('delete-small.png', _("Delete"))
2007: . '</a>';
2008: }
2009:
2010: 2011: 2012: 2013: 2014: 2015:
2016: public function exceptionsList()
2017: {
2018: $exceptions = $this->recurrence->getExceptions();
2019: asort($exceptions);
2020: return implode(', ', array_map(array($this, 'exceptionLink'), $exceptions));
2021: }
2022:
2023: 2024: 2025: 2026: 2027: 2028: 2029: 2030: 2031: 2032: 2033: 2034:
2035: public function isPrivate($user = null)
2036: {
2037: if ($user === null) {
2038: $user = $GLOBALS['registry']->getAuth();
2039: }
2040:
2041: if (!(Horde_Cli::runningFromCLI() && $GLOBALS['registry']->isAdmin()) &&
2042: $this->private && $this->creator != $user) {
2043: return true;
2044: }
2045: if ($GLOBALS['registry']->isAdmin() ||
2046: $this->hasPermission(Horde_Perms::READ, $user)) {
2047: return false;
2048: }
2049: return true;
2050: }
2051:
2052: 2053: 2054: 2055: 2056: 2057: 2058:
2059: public function getTitle($user = null)
2060: {
2061: if (!$this->initialized) {
2062: return '';
2063: }
2064:
2065: return $this->isPrivate($user)
2066: ? _("busy")
2067: : (strlen($this->title) ? $this->title : _("[Unnamed event]"));
2068: }
2069:
2070: 2071: 2072: 2073: 2074: 2075: 2076:
2077: public function getLocation($user = null)
2078: {
2079: return $this->isPrivate($user) ? '' : $this->location;
2080: }
2081:
2082: 2083: 2084: 2085: 2086: 2087: 2088: 2089: 2090:
2091: public function hasAttendee($email)
2092: {
2093: return isset($this->attendees[Horde_String::lower($email)]);
2094: }
2095:
2096: 2097: 2098: 2099: 2100: 2101: 2102: 2103: 2104: 2105: 2106:
2107: public function addAttendee($email, $attendance, $response, $name = null)
2108: {
2109: $email = Horde_String::lower($email);
2110: if ($attendance == Kronolith::PART_IGNORE) {
2111: if (isset($this->attendees[$email])) {
2112: $attendance = $this->attendees[$email]['attendance'];
2113: } else {
2114: $attendance = Kronolith::PART_REQUIRED;
2115: }
2116: }
2117: if (empty($name) && isset($this->attendees[$email]) &&
2118: !empty($this->attendees[$email]['name'])) {
2119: $name = $this->attendees[$email]['name'];
2120: }
2121:
2122: $this->attendees[$email] = array(
2123: 'attendance' => $attendance,
2124: 'response' => $response,
2125: 'name' => $name
2126: );
2127: }
2128:
2129: 2130: 2131: 2132: 2133: 2134: 2135: 2136:
2137: public function addResource($resource, $response)
2138: {
2139: $this->_resources[$resource->getId()] = array(
2140: 'attendance' => Kronolith::PART_REQUIRED,
2141: 'response' => $response,
2142: 'name' => $resource->get('name')
2143: );
2144: }
2145:
2146: 2147: 2148: 2149: 2150:
2151: public function removeResource($resource)
2152: {
2153: if (isset($this->_resources[$resource->getId()])) {
2154: unset($this->_resources[$resource->getId()]);
2155: }
2156: }
2157:
2158: 2159: 2160: 2161: 2162:
2163: public function getResources()
2164: {
2165: return $this->_resources;
2166: }
2167:
2168: public function isAllDay()
2169: {
2170: return $this->allday ||
2171: ($this->start->hour == 0 && $this->start->min == 0 && $this->start->sec == 0 &&
2172: (($this->end->hour == 23 && $this->end->min == 59) ||
2173: ($this->end->hour == 0 && $this->end->min == 0 && $this->end->sec == 0 &&
2174: ($this->end->mday > $this->start->mday ||
2175: $this->end->month > $this->start->month ||
2176: $this->end->year > $this->start->year))));
2177: }
2178:
2179: public function readForm()
2180: {
2181: global $prefs, $cManager, $session;
2182:
2183:
2184: $targetcalendar = Horde_Util::getFormData('targetcalendar');
2185: if (strpos($targetcalendar, '\\')) {
2186: list(, $this->creator) = explode('\\', $targetcalendar, 2);
2187: } elseif (!isset($this->_id)) {
2188: $this->creator = $GLOBALS['registry']->getAuth();
2189: }
2190:
2191:
2192: $this->title = Horde_Util::getFormData('title', $this->title);
2193: $this->description = Horde_Util::getFormData('description', $this->description);
2194: $this->location = Horde_Util::getFormData('location', $this->location);
2195: $this->private = (bool)Horde_Util::getFormData('private');
2196:
2197:
2198: $url = Horde_Util::getFormData('eventurl', $this->url);
2199: if (strlen($url)) {
2200:
2201: $url = @parse_url($url);
2202: if ($url) {
2203: if (function_exists('http_build_url')) {
2204: if (empty($url['path'])) {
2205: $url['path'] = '/';
2206: }
2207: $url = http_build_url($url);
2208: } else {
2209: $new_url = '';
2210: if (isset($url['scheme'])) {
2211: $new_url .= $url['scheme'] . '://';
2212: }
2213: if (isset($url['user'])) {
2214: $new_url .= $url['user'];
2215: if (isset($url['pass'])) {
2216: $new_url .= ':' . $url['pass'];
2217: }
2218: $new_url .= '@';
2219: }
2220: if (isset($url['host'])) {
2221:
2222: if (function_exists('idn_to_ascii')) {
2223: $url['host'] = @idn_to_ascii($url['host']);
2224: } elseif (Horde_Mime::is8bit($url['host'])) {
2225:
2226: $url['host'] = '';
2227: }
2228: $new_url .= $url['host'];
2229: }
2230: if (isset($url['path'])) {
2231: $new_url .= $url['path'];
2232: }
2233: if (isset($url['query'])) {
2234: $new_url .= '?' . $url['query'];
2235: }
2236: if (isset($url['fragment'])) {
2237: $new_url .= '#' . $url['fragment'];
2238: }
2239: $url = $new_url;
2240: }
2241: }
2242: }
2243: $this->url = $url;
2244:
2245:
2246: $this->status = Horde_Util::getFormData('status', $this->status);
2247:
2248:
2249: $attendees = $session->get('kronolith', 'attendees', Horde_Session::TYPE_ARRAY);
2250: if (!is_null($newattendees = Horde_Util::getFormData('attendees'))) {
2251: $newattendees = Kronolith::parseAttendees(trim($newattendees));
2252: foreach ($newattendees as $email => $attendee) {
2253: if (!isset($attendees[$email])) {
2254: $attendees[$email] = $attendee;
2255: }
2256: }
2257: foreach (array_keys($attendees) as $email) {
2258: if (!isset($newattendees[$email])) {
2259: unset($attendees[$email]);
2260: }
2261: }
2262: }
2263: $this->attendees = $attendees;
2264:
2265:
2266: $this->_resources = $session->get('kronolith', 'resources', Horde_Session::TYPE_ARRAY);
2267:
2268:
2269: $allDay = Horde_Util::getFormData('whole_day');
2270: if ($start_date = Horde_Util::getFormData('start_date')) {
2271:
2272: $this->start = Kronolith::parseDate($start_date . ' ' . Horde_Util::getFormData('start_time'));
2273: if ($allDay) {
2274: $this->start->hour = $this->start->min = $this->start->sec = 0;
2275: }
2276: } else {
2277:
2278: $start = Horde_Util::getFormData('start');
2279: $start_year = $start['year'];
2280: $start_month = $start['month'];
2281: $start_day = $start['day'];
2282: $start_hour = Horde_Util::getFormData('start_hour');
2283: $start_min = Horde_Util::getFormData('start_min');
2284: $am_pm = Horde_Util::getFormData('am_pm');
2285:
2286: if (!$prefs->getValue('twentyFour')) {
2287: if ($am_pm == 'PM') {
2288: if ($start_hour != 12) {
2289: $start_hour += 12;
2290: }
2291: } elseif ($start_hour == 12) {
2292: $start_hour = 0;
2293: }
2294: }
2295:
2296: if (Horde_Util::getFormData('end_or_dur') == 1) {
2297: if ($allDay) {
2298: $start_hour = 0;
2299: $start_min = 0;
2300: $dur_day = 0;
2301: $dur_hour = 24;
2302: $dur_min = 0;
2303: } else {
2304: $dur_day = (int)Horde_Util::getFormData('dur_day');
2305: $dur_hour = (int)Horde_Util::getFormData('dur_hour');
2306: $dur_min = (int)Horde_Util::getFormData('dur_min');
2307: }
2308: }
2309:
2310: $this->start = new Horde_Date(array('hour' => $start_hour,
2311: 'min' => $start_min,
2312: 'month' => $start_month,
2313: 'mday' => $start_day,
2314: 'year' => $start_year));
2315: }
2316:
2317:
2318: if ($end_date = Horde_Util::getFormData('end_date')) {
2319:
2320: $this->end = Kronolith::parseDate($end_date . ' ' . Horde_Util::getFormData('end_time'));
2321: if ($allDay) {
2322: $this->end->hour = 23;
2323: $this->end->min = $this->end->sec = 59;
2324: }
2325: } elseif (Horde_Util::getFormData('end_or_dur') == 1) {
2326:
2327: $this->end = new Horde_Date(array('hour' => $start_hour + $dur_hour,
2328: 'min' => $start_min + $dur_min,
2329: 'month' => $start_month,
2330: 'mday' => $start_day + $dur_day,
2331: 'year' => $start_year));
2332: } else {
2333:
2334: $end = Horde_Util::getFormData('end');
2335: $end_year = $end['year'];
2336: $end_month = $end['month'];
2337: $end_day = $end['day'];
2338: $end_hour = Horde_Util::getFormData('end_hour');
2339: $end_min = Horde_Util::getFormData('end_min');
2340: $end_am_pm = Horde_Util::getFormData('end_am_pm');
2341:
2342: if (!$prefs->getValue('twentyFour')) {
2343: if ($end_am_pm == 'PM') {
2344: if ($end_hour != 12) {
2345: $end_hour += 12;
2346: }
2347: } elseif ($end_hour == 12) {
2348: $end_hour = 0;
2349: }
2350: }
2351:
2352: $this->end = new Horde_Date(array('hour' => $end_hour,
2353: 'min' => $end_min,
2354: 'month' => $end_month,
2355: 'mday' => $end_day,
2356: 'year' => $end_year));
2357: if ($this->end->compareDateTime($this->start) < 0) {
2358: $this->end = new Horde_Date($this->start);
2359: }
2360: }
2361:
2362: $this->allday = false;
2363:
2364:
2365: if (!is_null($alarm = Horde_Util::getFormData('alarm'))) {
2366: if ($alarm) {
2367: $value = Horde_Util::getFormData('alarm_value');
2368: $unit = Horde_Util::getFormData('alarm_unit');
2369: if ($value == 0) {
2370: $value = $unit = 1;
2371: }
2372: $this->alarm = $value * $unit;
2373:
2374: if (Horde_Util::getFormData('alarm_change_method')) {
2375: $types = Horde_Util::getFormData('event_alarms');
2376: if (!empty($types)) {
2377: $methods = array();
2378: foreach ($types as $type) {
2379: $methods[$type] = array();
2380: switch ($type){
2381: case 'notify':
2382: $methods[$type]['sound'] = Horde_Util::getFormData('event_alarms_sound');
2383: break;
2384: case 'mail':
2385: $methods[$type]['email'] = Horde_Util::getFormData('event_alarms_email');
2386: break;
2387: case 'popup':
2388: break;
2389: }
2390: }
2391: $this->methods = $methods;
2392: }
2393: } else {
2394: $this->methods = array();
2395: }
2396: } else {
2397: $this->alarm = 0;
2398: $this->methods = array();
2399: }
2400: }
2401:
2402:
2403: $recur = Horde_Util::getFormData('recur');
2404: if ($recur !== null && $recur !== '') {
2405: if (!isset($this->recurrence)) {
2406: $this->recurrence = new Horde_Date_Recurrence($this->start);
2407: } else {
2408: $this->recurrence->setRecurStart($this->start);
2409: }
2410: if (Horde_Util::getFormData('recur_end_type') == 'date') {
2411: if ($end_date = Horde_Util::getFormData('recur_end_date')) {
2412:
2413: $date_ob = Kronolith::parseDate($end_date, false);
2414: $recur_enddate = array('year' => $date_ob->year,
2415: 'month' => $date_ob->month,
2416: 'day' => $date_ob->mday);
2417: } else {
2418:
2419: $recur_enddate = Horde_Util::getFormData('recur_end');
2420: }
2421: if ($this->recurrence->hasRecurEnd()) {
2422: $recurEnd = $this->recurrence->recurEnd;
2423: $recurEnd->month = $recur_enddate['month'];
2424: $recurEnd->mday = $recur_enddate['day'];
2425: $recurEnd->year = $recur_enddate['year'];
2426: } else {
2427: $recurEnd = new Horde_Date(
2428: array('hour' => 23,
2429: 'min' => 59,
2430: 'sec' => 59,
2431: 'month' => $recur_enddate['month'],
2432: 'mday' => $recur_enddate['day'],
2433: 'year' => $recur_enddate['year']));
2434: }
2435: $this->recurrence->setRecurEnd($recurEnd);
2436: } elseif (Horde_Util::getFormData('recur_end_type') == 'count') {
2437: $this->recurrence->setRecurCount(Horde_Util::getFormData('recur_count'));
2438: } elseif (Horde_Util::getFormData('recur_end_type') == 'none') {
2439: $this->recurrence->setRecurCount(0);
2440: $this->recurrence->setRecurEnd(null);
2441: }
2442:
2443: $this->recurrence->setRecurType($recur);
2444: switch ($recur) {
2445: case Horde_Date_Recurrence::RECUR_DAILY:
2446: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_daily_interval', 1));
2447: break;
2448:
2449: case Horde_Date_Recurrence::RECUR_WEEKLY:
2450: $weekly = Horde_Util::getFormData('weekly');
2451: $weekdays = 0;
2452: if (is_array($weekly)) {
2453: foreach ($weekly as $day) {
2454: $weekdays |= $day;
2455: }
2456: }
2457:
2458: if ($weekdays == 0) {
2459:
2460: switch ($this->start->dayOfWeek()) {
2461: case 0: $weekdays |= Horde_Date::MASK_SUNDAY; break;
2462: case 1: $weekdays |= Horde_Date::MASK_MONDAY; break;
2463: case 2: $weekdays |= Horde_Date::MASK_TUESDAY; break;
2464: case 3: $weekdays |= Horde_Date::MASK_WEDNESDAY; break;
2465: case 4: $weekdays |= Horde_Date::MASK_THURSDAY; break;
2466: case 5: $weekdays |= Horde_Date::MASK_FRIDAY; break;
2467: case 6: $weekdays |= Horde_Date::MASK_SATURDAY; break;
2468: }
2469: }
2470:
2471: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_weekly_interval', 1));
2472: $this->recurrence->setRecurOnDay($weekdays);
2473: break;
2474:
2475: case Horde_Date_Recurrence::RECUR_MONTHLY_DATE:
2476: switch (Horde_Util::getFormData('recur_monthly_scheme')) {
2477: case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY:
2478: $this->recurrence->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY);
2479: case Horde_Date_Recurrence::RECUR_MONTHLY_DATE:
2480: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_monthly') ? 1 : Horde_Util::getFormData('recur_monthly_interval', 1));
2481: break;
2482: default:
2483: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_day_of_month_interval', 1));
2484: break;
2485: }
2486: break;
2487:
2488: case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY:
2489: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_week_of_month_interval', 1));
2490: break;
2491:
2492: case Horde_Date_Recurrence::RECUR_YEARLY_DATE:
2493: switch (Horde_Util::getFormData('recur_yearly_scheme')) {
2494: case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY:
2495: case Horde_Date_Recurrence::RECUR_YEARLY_DAY:
2496: $this->recurrence->setRecurType(Horde_Util::getFormData('recur_yearly_scheme'));
2497: case Horde_Date_Recurrence::RECUR_YEARLY_DATE:
2498: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly') ? 1 : Horde_Util::getFormData('recur_yearly_interval', 1));
2499: break;
2500: default:
2501: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_interval', 1));
2502: break;
2503: }
2504: break;
2505:
2506: case Horde_Date_Recurrence::RECUR_YEARLY_DAY:
2507: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_day_interval', $yearly_interval));
2508: break;
2509:
2510: case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY:
2511: $this->recurrence->setRecurInterval(Horde_Util::getFormData('recur_yearly_weekday_interval', $yearly_interval));
2512: break;
2513: }
2514:
2515: if ($exceptions = Horde_Util::getFormData('exceptions')) {
2516: foreach ($exceptions as $exception) {
2517: $this->recurrence->addException((int)substr($exception, 0, 4),
2518: (int)substr($exception, 4, 2),
2519: (int)substr($exception, 6, 2));
2520: }
2521: }
2522: }
2523:
2524:
2525: $this->tags = Horde_Util::getFormData('tags', $this->tags);
2526:
2527:
2528: if (Horde_Util::getFormData('lat') && Horde_Util::getFormData('lon')) {
2529: $this->geoLocation = array('lat' => Horde_Util::getFormData('lat'),
2530: 'lon' => Horde_Util::getFormData('lon'),
2531: 'zoom' => Horde_Util::getFormData('zoom'));
2532: }
2533:
2534: $this->initialized = true;
2535: }
2536:
2537: public function html($property)
2538: {
2539: global $prefs;
2540:
2541: $options = array();
2542: $attributes = '';
2543: $sel = false;
2544: $label = '';
2545:
2546: switch ($property) {
2547: case 'start[year]':
2548: return '<label for="' . $this->_formIDEncode($property) . '" class="hidden">' . _("Start Year") . '</label>' .
2549: '<input name="' . $property . '" value="' . $this->start->year .
2550: '" type="text"' .
2551: ' id="' . $this->_formIDEncode($property) . '" size="4" maxlength="4" />';
2552:
2553: case 'start[month]':
2554: $sel = $this->start->month;
2555: for ($i = 1; $i < 13; ++$i) {
2556: $options[$i] = strftime('%b', mktime(1, 1, 1, $i, 1));
2557: }
2558: $label = _("Start Month");
2559: break;
2560:
2561: case 'start[day]':
2562: $sel = $this->start->mday;
2563: for ($i = 1; $i < 32; ++$i) {
2564: $options[$i] = $i;
2565: }
2566: $label = _("Start Day");
2567: break;
2568:
2569: case 'start_hour':
2570: $sel = $this->start->format($prefs->getValue('twentyFour') ? 'G' : 'g');
2571: $hour_min = $prefs->getValue('twentyFour') ? 0 : 1;
2572: $hour_max = $prefs->getValue('twentyFour') ? 24 : 13;
2573: for ($i = $hour_min; $i < $hour_max; ++$i) {
2574: $options[$i] = $i;
2575: }
2576: $label = _("Start Hour");
2577: break;
2578:
2579: case 'start_min':
2580: $sel = sprintf('%02d', $this->start->min);
2581: for ($i = 0; $i < 12; ++$i) {
2582: $min = sprintf('%02d', $i * 5);
2583: $options[$min] = $min;
2584: }
2585: $label = _("Start Minute");
2586: break;
2587:
2588: case 'end[year]':
2589: return '<label for="' . $this->_formIDEncode($property) . '" class="hidden">' . _("End Year") . '</label>' .
2590: '<input name="' . $property . '" value="' . $this->end->year .
2591: '" type="text"' .
2592: ' id="' . $this->_formIDEncode($property) . '" size="4" maxlength="4" />';
2593:
2594: case 'end[month]':
2595: $sel = $this->end ? $this->end->month : $this->start->month;
2596: for ($i = 1; $i < 13; ++$i) {
2597: $options[$i] = strftime('%b', mktime(1, 1, 1, $i, 1));
2598: }
2599: $label = _("End Month");
2600: break;
2601:
2602: case 'end[day]':
2603: $sel = $this->end ? $this->end->mday : $this->start->mday;
2604: for ($i = 1; $i < 32; ++$i) {
2605: $options[$i] = $i;
2606: }
2607: $label = _("End Day");
2608: break;
2609:
2610: case 'end_hour':
2611: $sel = $this->end
2612: ? $this->end->format($prefs->getValue('twentyFour') ? 'G' : 'g')
2613: : $this->start->format($prefs->getValue('twentyFour') ? 'G' : 'g') + 1;
2614: $hour_min = $prefs->getValue('twentyFour') ? 0 : 1;
2615: $hour_max = $prefs->getValue('twentyFour') ? 24 : 13;
2616: for ($i = $hour_min; $i < $hour_max; ++$i) {
2617: $options[$i] = $i;
2618: }
2619: $label = _("End Hour");
2620: break;
2621:
2622: case 'end_min':
2623: $sel = $this->end ? $this->end->min : $this->start->min;
2624: $sel = sprintf('%02d', $sel);
2625: for ($i = 0; $i < 12; ++$i) {
2626: $min = sprintf('%02d', $i * 5);
2627: $options[$min] = $min;
2628: }
2629: $label = _("End Minute");
2630: break;
2631:
2632: case 'dur_day':
2633: $dur = $this->getDuration();
2634: return '<label for="' . $property . '" class="hidden">' . _("Duration Day") . '</label>' .
2635: '<input name="' . $property . '" value="' . $dur->day .
2636: '" type="text"' .
2637: ' id="' . $property . '" size="4" maxlength="4" />';
2638:
2639: case 'dur_hour':
2640: $dur = $this->getDuration();
2641: $sel = $dur->hour;
2642: for ($i = 0; $i < 24; ++$i) {
2643: $options[$i] = $i;
2644: }
2645: $label = _("Duration Hour");
2646: break;
2647:
2648: case 'dur_min':
2649: $dur = $this->getDuration();
2650: $sel = $dur->min;
2651: for ($i = 0; $i < 13; ++$i) {
2652: $min = sprintf('%02d', $i * 5);
2653: $options[$min] = $min;
2654: }
2655: $label = _("Duration Minute");
2656: break;
2657:
2658: case 'recur_end[year]':
2659: if ($this->end) {
2660: $end = ($this->recurs() && $this->recurrence->hasRecurEnd())
2661: ? $this->recurrence->recurEnd->year
2662: : $this->end->year;
2663: } else {
2664: $end = $this->start->year;
2665: }
2666: return '<label for="' . $this->_formIDEncode($property) . '" class="hidden">' . _("Recurrence End Year") . '</label>' .
2667: '<input name="' . $property . '" value="' . $end .
2668: '" type="text"' .
2669: ' id="' . $this->_formIDEncode($property) . '" size="4" maxlength="4" />';
2670:
2671: case 'recur_end[month]':
2672: if ($this->end) {
2673: $sel = ($this->recurs() && $this->recurrence->hasRecurEnd())
2674: ? $this->recurrence->recurEnd->month
2675: : $this->end->month;
2676: } else {
2677: $sel = $this->start->month;
2678: }
2679: for ($i = 1; $i < 13; ++$i) {
2680: $options[$i] = strftime('%b', mktime(1, 1, 1, $i, 1));
2681: }
2682: $label = _("Recurrence End Month");
2683: break;
2684:
2685: case 'recur_end[day]':
2686: if ($this->end) {
2687: $sel = ($this->recurs() && $this->recurrence->hasRecurEnd())
2688: ? $this->recurrence->recurEnd->mday
2689: : $this->end->mday;
2690: } else {
2691: $sel = $this->start->mday;
2692: }
2693: for ($i = 1; $i < 32; ++$i) {
2694: $options[$i] = $i;
2695: }
2696: $label = _("Recurrence End Day");
2697: break;
2698: }
2699:
2700: if (!$this->_varRenderer) {
2701: $this->_varRenderer = Horde_Core_Ui_VarRenderer::factory('Html');
2702: }
2703:
2704: return '<label for="' . $this->_formIDEncode($property) . '" class="hidden">' . $label . '</label>' .
2705: '<select name="' . $property . '"' . $attributes . ' id="' . $this->_formIDEncode($property) . '">' .
2706: $this->_varRenderer->selectOptions($options, $sel) .
2707: '</select>';
2708: }
2709:
2710: 2711: 2712: 2713: 2714:
2715: public function getViewUrl($params = array(), $full = false, $encoded = true)
2716: {
2717: $params['eventID'] = $this->id;
2718: $params['calendar'] = $this->calendar;
2719: $params['type'] = $this->calendarType;
2720:
2721: return Horde::url('event.php', $full)->setRaw(!$encoded)->add($params);
2722: }
2723:
2724: 2725: 2726: 2727: 2728:
2729: public function getEditUrl($params = array(), $full = false)
2730: {
2731: $params['view'] = 'EditEvent';
2732: $params['eventID'] = $this->id;
2733: $params['calendar'] = $this->calendar;
2734: $params['type'] = $this->calendarType;
2735:
2736: return Horde::url('event.php', $full)->add($params);
2737: }
2738:
2739: 2740: 2741: 2742: 2743:
2744: public function getDeleteUrl($params = array(), $full = false)
2745: {
2746: $params['view'] = 'DeleteEvent';
2747: $params['eventID'] = $this->id;
2748: $params['calendar'] = $this->calendar;
2749: $params['type'] = $this->calendarType;
2750:
2751: return Horde::url('event.php', $full)->add($params);
2752: }
2753:
2754: 2755: 2756: 2757: 2758:
2759: public function getExportUrl($params = array(), $full = false)
2760: {
2761: $params['view'] = 'ExportEvent';
2762: $params['eventID'] = $this->id;
2763: $params['calendar'] = $this->calendar;
2764: $params['type'] = $this->calendarType;
2765:
2766: return Horde::url('event.php', $full)->add($params);
2767: }
2768:
2769: public function getLink($datetime = null, $icons = true, $from_url = null,
2770: $full = false, $encoded = true)
2771: {
2772: global $prefs, $registry;
2773:
2774: if (is_null($datetime)) {
2775: $datetime = $this->start;
2776: }
2777: if (is_null($from_url)) {
2778: $from_url = Horde::selfUrl(true, false, true);
2779: }
2780:
2781: $event_title = $this->getTitle();
2782: $view_url = $this->getViewUrl(array('datetime' => $datetime->strftime('%Y%m%d%H%M%S'), 'url' => $from_url), $full, $encoded);
2783: $read_permission = $this->hasPermission(Horde_Perms::READ);
2784:
2785: $link = '<span' . $this->getCSSColors() . '>';
2786: if ($read_permission && $view_url) {
2787: $link .= Horde::linkTooltip($view_url,
2788: $event_title,
2789: $this->getStatusClass(),
2790: '',
2791: '',
2792: $this->getTooltip(),
2793: '',
2794: array('style' => $this->getCSSColors(false)));
2795: }
2796: $link .= htmlspecialchars($event_title);
2797: if ($read_permission && $view_url) {
2798: $link .= '</a>';
2799: }
2800:
2801: if ($icons && $prefs->getValue('show_icons')) {
2802: $icon_color = $this->_foregroundColor == '#000' ? '000' : 'fff';
2803: $status = '';
2804: if ($this->alarm) {
2805: if ($this->alarm % 10080 == 0) {
2806: $alarm_value = $this->alarm / 10080;
2807: $title = sprintf(ngettext("Alarm %d week before", "Alarm %d weeks before", $alarm_value), $alarm_value);
2808: } elseif ($this->alarm % 1440 == 0) {
2809: $alarm_value = $this->alarm / 1440;
2810: $title = sprintf(ngettext("Alarm %d day before", "Alarm %d days before", $alarm_value), $alarm_value);
2811: } elseif ($this->alarm % 60 == 0) {
2812: $alarm_value = $this->alarm / 60;
2813: $title = sprintf(ngettext("Alarm %d hour before", "Alarm %d hours before", $alarm_value), $alarm_value);
2814: } else {
2815: $alarm_value = $this->alarm;
2816: $title = sprintf(ngettext("Alarm %d minute before", "Alarm %d minutes before", $alarm_value), $alarm_value);
2817: }
2818: $status .= Horde::fullSrcImg('alarm-' . $icon_color . '.png', array('attr' => array('alt' => $title, 'title' => $title, 'class' => 'iconAlarm')));
2819: }
2820:
2821: if ($this->recurs()) {
2822: $title = Kronolith::recurToString($this->recurrence->getRecurType());
2823: $status .= Horde::fullSrcImg('recur-' . $icon_color . '.png', array('attr' => array('alt' => $title, 'title' => $title, 'class' => 'iconRecur')));
2824: } elseif ($this->baseid) {
2825: $title = _("Exception");
2826: $status .= Horde::fullSrcImg('exception-' . $icon_color . '.png', array('attr' => array('alt' => $title, 'title' => $title, 'class' => 'iconRecur')));
2827: }
2828:
2829: if ($this->private) {
2830: $title = _("Private event");
2831: $status .= Horde::fullSrcImg('private-' . $icon_color . '.png', array('attr' => array('alt' => $title, 'title' => $title, 'class' => 'iconPrivate')));
2832: }
2833:
2834: if (!empty($this->attendees)) {
2835: $status .= Horde::fullSrcImg('attendees-' . $icon_color . '.png', array('attr' => array('alt' => _("Meeting"), 'title' => _("Meeting"), 'class' => 'iconPeople')));
2836: }
2837:
2838: if (!empty($this->icon)) {
2839: $link = $status . '<img src="' . $this->icon . '" /> ' . $link;
2840: } elseif (!empty($status)) {
2841: $link .= ' ' . $status;
2842: }
2843:
2844: if ((!$this->private ||
2845: $this->creator == $GLOBALS['registry']->getAuth()) &&
2846: Kronolith::getDefaultCalendar(Horde_Perms::EDIT)) {
2847: $url = $this->getEditUrl(
2848: array('datetime' => $datetime->strftime('%Y%m%d%H%M%S'),
2849: 'url' => $from_url),
2850: $full);
2851: if ($url) {
2852: $link .= $url->link(array('title' => sprintf(_("Edit %s"), $event_title),
2853: 'class' => 'iconEdit'))
2854: . Horde::fullSrcImg('edit-' . $icon_color . '.png',
2855: array('attr' => array('alt' => _("Edit"))))
2856: . '</a>';
2857: }
2858: }
2859: if ($this->hasPermission(Horde_Perms::DELETE)) {
2860: $url = $this->getDeleteUrl(
2861: array('datetime' => $datetime->strftime('%Y%m%d%H%M%S'),
2862: 'url' => $from_url),
2863: $full);
2864: if ($url) {
2865: $link .= $url->link(array('title' => sprintf(_("Delete %s"), $event_title),
2866: 'class' => 'iconDelete'))
2867: . Horde::fullSrcImg('delete-' . $icon_color . '.png',
2868: array('attr' => array('alt' => _("Delete"))))
2869: . '</a>';
2870: }
2871: }
2872: }
2873:
2874: return $link . '</span>';
2875: }
2876:
2877: 2878: 2879: 2880: 2881: 2882: 2883: 2884:
2885: public function getCSSColors($with_attribute = true)
2886: {
2887: $css = 'background-color:' . $this->_backgroundColor . ';color:' . $this->_foregroundColor;
2888: if ($with_attribute) {
2889: $css = ' style="' . $css . '"';
2890: }
2891: return $css;
2892: }
2893:
2894: 2895: 2896:
2897: public function getTooltip()
2898: {
2899: $tooltip = $this->getTimeRange()
2900: . "\n" . sprintf(_("Owner: %s"), ($this->creator == $GLOBALS['registry']->getAuth() ?
2901: _("Me") : Kronolith::getUserName($this->creator)));
2902:
2903: if (!$this->isPrivate()) {
2904: if ($this->location) {
2905: $tooltip .= "\n" . _("Location") . ': ' . $this->location;
2906: }
2907:
2908: if ($this->description) {
2909: $tooltip .= "\n\n" . Horde_String::wrap($this->description);
2910: }
2911: }
2912:
2913: return $tooltip;
2914: }
2915:
2916: 2917: 2918: 2919:
2920: public function getTimeRange()
2921: {
2922: if ($this->isAllDay()) {
2923: return _("All day");
2924: } elseif (($cmp = $this->start->compareDate($this->end)) > 0) {
2925: $df = $GLOBALS['prefs']->getValue('date_format');
2926: if ($cmp > 0) {
2927: return $this->end->strftime($df) . '-'
2928: . $this->start->strftime($df);
2929: } else {
2930: return $this->start->strftime($df) . '-'
2931: . $this->end->strftime($df);
2932: }
2933: } else {
2934: $twentyFour = $GLOBALS['prefs']->getValue('twentyFour');
2935: return $this->start->format($twentyFour ? 'G:i' : 'g:ia')
2936: . '-'
2937: . $this->end->format($twentyFour ? 'G:i' : 'g:ia');
2938: }
2939: }
2940:
2941: 2942: 2943:
2944: public function getStatusClass()
2945: {
2946: switch ($this->status) {
2947: case Kronolith::STATUS_CANCELLED:
2948: return 'kronolithEventCancelled';
2949:
2950: case Kronolith::STATUS_TENTATIVE:
2951: case Kronolith::STATUS_FREE:
2952: return 'kronolithEventTentative';
2953: }
2954:
2955: return 'kronolithEvent';
2956: }
2957:
2958: private function _formIDEncode($id)
2959: {
2960: return str_replace(array('[', ']'),
2961: array('_', ''),
2962: $id);
2963: }
2964:
2965: }
2966: