Overview

Packages

  • Kronolith
  • None

Classes

  • Kronolith
  • Kronolith_Ajax_Application
  • Kronolith_Ajax_Imple_ContactAutoCompleter
  • Kronolith_Ajax_Imple_Embed
  • Kronolith_Ajax_Imple_TagActions
  • Kronolith_Ajax_Imple_TagAutoCompleter
  • Kronolith_Api
  • Kronolith_Calendar
  • Kronolith_Calendar_External
  • Kronolith_Calendar_External_Tasks
  • Kronolith_Calendar_Holiday
  • Kronolith_Calendar_Internal
  • Kronolith_Calendar_Remote
  • Kronolith_Calendar_Resource
  • Kronolith_Calendars_Base
  • Kronolith_Calendars_Default
  • Kronolith_Calendars_Kolab
  • Kronolith_Day
  • Kronolith_Driver
  • Kronolith_Driver_Holidays
  • Kronolith_Driver_Horde
  • Kronolith_Driver_Ical
  • Kronolith_Driver_Kolab
  • Kronolith_Driver_Mock
  • Kronolith_Driver_Resource
  • Kronolith_Driver_Sql
  • Kronolith_Event
  • Kronolith_Event_Holidays
  • Kronolith_Event_Horde
  • Kronolith_Event_Ical
  • Kronolith_Event_Kolab
  • Kronolith_Event_Resource
  • Kronolith_Event_Sql
  • Kronolith_Exception
  • Kronolith_Factory_Calendars
  • Kronolith_Factory_Geo
  • Kronolith_Form_CreateCalendar
  • Kronolith_Form_CreateResource
  • Kronolith_Form_CreateResourceGroup
  • Kronolith_Form_DeleteCalendar
  • Kronolith_Form_DeleteResource
  • Kronolith_Form_DeleteResourceGroup
  • Kronolith_Form_EditCalendar
  • Kronolith_Form_EditRemoteCalendar
  • Kronolith_Form_EditResource
  • Kronolith_Form_EditResourceGroup
  • Kronolith_Form_SubscribeRemoteCalendar
  • Kronolith_Form_UnsubscribeRemoteCalendar
  • Kronolith_FreeBusy
  • Kronolith_FreeBusy_View
  • Kronolith_FreeBusy_View_Day
  • Kronolith_FreeBusy_View_Month
  • Kronolith_FreeBusy_View_Week
  • Kronolith_FreeBusy_View_Workweek
  • Kronolith_Geo_Base
  • Kronolith_Geo_Mysql
  • Kronolith_Geo_Sql
  • Kronolith_LoginTasks_SystemTask_Upgrade
  • Kronolith_LoginTasks_Task_PurgeEvents
  • Kronolith_Notification_Listener_AjaxStatus
  • Kronolith_Resource
  • Kronolith_Resource_Base
  • Kronolith_Resource_Group
  • Kronolith_Resource_Single
  • Kronolith_Storage
  • Kronolith_Storage_Kolab
  • Kronolith_Storage_Sql
  • Kronolith_Tagger
  • Kronolith_Test
  • Kronolith_View_Day
  • Kronolith_View_DeleteEvent
  • Kronolith_View_EditEvent
  • Kronolith_View_Event
  • Kronolith_View_ExportEvent
  • Kronolith_View_Month
  • Kronolith_View_Week
  • Kronolith_View_WorkWeek
  • Kronolith_View_Year
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Horde Kronolith driver for the Kolab IMAP Server.
  4:  *
  5:  * Copyright 2004-2012 Horde LLC (http://www.horde.org/)
  6:  *
  7:  * See the enclosed file COPYING for license information (GPL). If you
  8:  * did not receive this file, see http://www.horde.org/licenses/gpl.
  9:  *
 10:  * @author  Thomas Jarosch <thomas.jarosch@intra2net.com>
 11:  * @author  Gunnar Wrobel <wrobel@pardus.de>
 12:  * @author  Stuart Binge <omicron@mighty.co.za>
 13:  * @package Kronolith
 14:  */
 15: class Kronolith_Driver_Kolab extends Kronolith_Driver
 16: {
 17:     /**
 18:      * The session handler.
 19:      *
 20:      * @var Horde_Kolab_Session
 21:      */
 22:     private $_session;
 23: 
 24:     /**
 25:      * Our Kolab server connection.
 26:      *
 27:      * @var Kolab
 28:      */
 29:     private $_kolab = null;
 30: 
 31:     /**
 32:      * Internal cache of Kronolith_Event_Kolab. eventID/UID is key
 33:      *
 34:      * @var array
 35:      */
 36:     private $_events_cache;
 37: 
 38:     /**
 39:      * Indicates if we have synchronized this folder
 40:      *
 41:      * @var boolean
 42:      */
 43:     private $_synchronized;
 44: 
 45:     /**
 46:      * The current calendar.
 47:      *
 48:      * @var Horde_Kolab_Storage_Data
 49:      */
 50:     private $_data;
 51: 
 52:     /**
 53:      * Attempts to open a Kolab Groupware folder.
 54:      */
 55:     public function initialize()
 56:     {
 57:         if (empty($this->_params['storage'])) {
 58:             throw new InvalidArgumentException('Missing required Horde_Kolab_Storage instance');
 59:         }
 60:         $this->_kolab = $this->_params['storage'];
 61:         $this->reset();
 62:     }
 63: 
 64:     /**
 65:      * Selects a calendar as the currently opened calendar.
 66:      *
 67:      * @param string $calendar  A calendar identifier.
 68:      */
 69:     public function open($calendar)
 70:     {
 71:         if ($this->calendar == $calendar) {
 72:             return;
 73:         }
 74:         $this->calendar = $calendar;
 75:         $this->reset();
 76:     }
 77: 
 78:     /**
 79:      * Returns the background color of the current calendar.
 80:      *
 81:      * @return string  The calendar color.
 82:      */
 83:     public function backgroundColor()
 84:     {
 85:         if (isset($GLOBALS['all_calendars'][$this->calendar])) {
 86:             return $GLOBALS['all_calendars'][$this->calendar]->background();
 87:         }
 88:         return '#dddddd';
 89:     }
 90: 
 91:     /**
 92:      * Reset internal variable on share change
 93:      */
 94:     public function reset()
 95:     {
 96:         $this->_events_cache = array();
 97:         $this->_synchronized = false;
 98:     }
 99: 
100:     // We delay initial synchronization to the first use
101:     // so multiple calendars don't add to the total latency.
102:     // This function must be called before all internal driver functions
103:     public function synchronize($force = false)
104:     {
105:         if ($this->_synchronized && !$force) {
106:             return;
107:         }
108: 
109:         // Connect to the Kolab backend
110:         $this->_data = $this->_kolab->getData(
111:             $GLOBALS['all_calendars'][$this->calendar]->share()->get('folder'),
112:             'event'
113:         );
114: 
115: 
116:         // build internal event cache
117:         $this->_events_cache = array();
118:         $events = $this->_data->getObjects();
119:         foreach ($events as $event) {
120:             $this->_events_cache[$event['uid']] = new Kronolith_Event_Kolab($this, $event);
121:         }
122: 
123:         $this->_synchronized = true;
124:     }
125: 
126:     /**
127:      * @throws Kronolith_Exception
128:      */
129:     public function listAlarms($date, $fullevent = false)
130:     {
131:         $allevents = $this->listEvents($date, null, false, true);
132:         $events = array();
133: 
134:         foreach ($allevents as $eventId => $data) {
135:             $event = $this->getEvent($eventId);
136:             if (!$event->recurs()) {
137:                 $start = new Horde_Date($event->start);
138:                 $start->min -= $event->alarm;
139:                 if ($start->compareDateTime($date) <= 0 &&
140:                     $date->compareDateTime($event->end) <= -1) {
141:                     $events[] = $fullevent ? $event : $eventId;
142:                 }
143:             } else {
144:                 if ($next = $event->recurrence->nextRecurrence($date)) {
145:                     if ($event->recurrence->hasException($next->year, $next->month, $next->mday)) {
146:                         continue;
147:                     }
148:                     $start = new Horde_Date($next);
149:                     $start->min -= $event->alarm;
150:                     $end = new Horde_Date(array('year' => $next->year,
151:                                                 'month' => $next->month,
152:                                                 'mday' => $next->mday,
153:                                                 'hour' => $event->end->hour,
154:                                                 'min' => $event->end->min,
155:                                                 'sec' => $event->end->sec));
156:                     if ($start->compareDateTime($date) <= 0 &&
157:                         $date->compareDateTime($end) <= -1) {
158:                         if ($fullevent) {
159:                             $event->start = $start;
160:                             $event->end = $end;
161:                             $events[] = $event;
162:                         } else {
163:                             $events[] = $eventId;
164:                         }
165:                     }
166:                 }
167:             }
168:         }
169: 
170:         return is_array($events) ? $events : array();
171:     }
172: 
173:     /**
174:      * Checks if the event's UID already exists and returns all event
175:      * ids with that UID.
176:      *
177:      * @param string $uid          The event's uid.
178:      * @param string $calendar_id  Calendar to search in.
179:      *
180:      * @return string|boolean  Returns a string with event_id or false if
181:      *                         not found.
182:      * @throws Kronolith_Exception
183:      */
184:     public function exists($uid, $calendar_id = null)
185:     {
186:         // Log error if someone uses this function in an unsupported way
187:         if ($calendar_id != $this->calendar) {
188:             Horde::logMessage(sprintf("Kolab::exists called for calendar %s. Currently active is %s.", $calendar_id, $this->calendar), 'ERR');
189:             throw new Kronolith_Exception(sprintf("Kolab::exists called for calendar %s. Currently active is %s.", $calendar_id, $this->calendar));
190:         }
191: 
192:         $result = $this->synchronize();
193: 
194:         if ($this->_data->objectIdExists($uid)) {
195:             return $uid;
196:         }
197: 
198:         return false;
199:     }
200: 
201:     /**
202:      * Lists all events in the time range, optionally restricting results to
203:      * only events with alarms.
204:      *
205:      * @param Horde_Date $startInterval  Start of range date object.
206:      * @param Horde_Date $endInterval    End of range data object.
207:      * @param boolean $showRecurrence    Return every instance of a recurring
208:      *                                   event? If false, will only return
209:      *                                   recurring events once inside the
210:      *                                   $startDate - $endDate range.
211:      * @param boolean $hasAlarm          Only return events with alarms?
212:      * @param boolean $json              Store the results of the events'
213:      *                                   toJson() method?
214:      * @param boolean $coverDates        Whether to add the events to all days
215:      *                                   that they cover.
216:      *
217:      * @return array  Events in the given time range.
218:      */
219:     public function listEvents($startDate = null, $endDate = null,
220:                                $showRecurrence = false, $hasAlarm = false,
221:                                $json = false, $coverDates = true,
222:                                $fetchTags = false)
223:     {
224:         $result = $this->synchronize();
225: 
226:         if (empty($startDate)) {
227:             $startDate = new Horde_Date(array('mday' => 1,
228:                                               'month' => 1,
229:                                               'year' => 0000));
230:         }
231:         if (empty($endDate)) {
232:             $endDate = new Horde_Date(array('mday' => 31,
233:                                             'month' => 12,
234:                                             'year' => 9999));
235:         }
236:         if (!($startDate instanceOf Horde_Date)) {
237:             $startDate = new Horde_Date($startDate);
238:         }
239:         if (!($endDate instanceOf Horde_Date)) {
240:             $endDate = new Horde_Date($endDate);
241:         }
242: 
243:         $startDate = clone $startDate;
244:         $startDate->hour = $startDate->min = $startDate->sec = 0;
245:         $endDate = clone $endDate;
246:         $endDate->hour = 23;
247:         $endDate->min = $endDate->sec = 59;
248: 
249:         $events = array();
250:         foreach($this->_events_cache as $event) {
251:             if ($hasAlarm && !$event->alarm) {
252:                 continue;
253:             }
254: 
255:             /* Ignore events out of the period. */
256:             if (
257:                 /* Starts after the period. */
258:                 $event->start->compareDateTime($endDate) > 0 ||
259:                 /* End before the period and doesn't recur. */
260:                 (!$event->recurs() &&
261:                  $event->end->compareDateTime($startDate) < 0) ||
262:                 /* Recurs and ... */
263:                 ($event->recurs() &&
264:                   /* ... has a recurrence end before the period. */
265:                   ($event->recurrence->hasRecurEnd() &&
266:                    $event->recurrence->recurEnd->compareDateTime($startDate) < 0))) {
267:                 continue;
268:             }
269: 
270:             Kronolith::addEvents($events, $event, $startDate, $endDate,
271:                                  $showRecurrence, $json, $coverDates);
272:         }
273: 
274:         return $events;
275:     }
276: 
277:     /**
278:      * @throws Kronolith_Exception
279:      * @throws Horde_Exception_NotFound
280:      */
281:     public function getEvent($eventId = null)
282:     {
283:         if (!strlen($eventId)) {
284:             return new Kronolith_Event_Kolab($this);
285:         }
286: 
287:         $result = $this->synchronize();
288: 
289:         if (array_key_exists($eventId, $this->_events_cache)) {
290:             return $this->_events_cache[$eventId];
291:         }
292: 
293:         throw new Horde_Exception_NotFound(sprintf(_("Event not found: %s"), $eventId));
294:     }
295: 
296:     /**
297:      * Get an event or events with the given UID value.
298:      *
299:      * @param string $uid The UID to match
300:      * @param array $calendars A restricted array of calendar ids to search
301:      * @param boolean $getAll Return all matching events? If this is false,
302:      * an error will be returned if more than one event is found.
303:      *
304:      * @return Kronolith_Event
305:      * @throws Kronolith_Exception
306:      * @throws Horde_Exception_NotFound
307:      */
308:     public function getByUID($uid, $calendars = null, $getAll = false)
309:     {
310:         if (!is_array($calendars)) {
311:             $calendars = array_keys(Kronolith::listInternalCalendars(true, Horde_Perms::READ));
312:         }
313: 
314:         foreach ($calendars as $calendar) {
315:             $this->open($calendar);
316:             $this->synchronize();
317: 
318:             if (!array_key_exists($uid, $this->_events_cache)) {
319:                 continue;
320:             }
321: 
322:             // Ok, found event
323:             $event = $this->_events_cache[$uid];
324: 
325:             if ($getAll) {
326:                 $events = array();
327:                 $events[] = $event;
328:                 return $events;
329:             } else {
330:                 return $event;
331:             }
332:         }
333: 
334:         throw new Horde_Exception_NotFound(sprintf(_("Event not found: %s"), $uid));
335:     }
336: 
337:     /**
338:      * Updates an existing event in the backend.
339:      *
340:      * @param Kronolith_Event $event  The event to save.
341:      *
342:      * @return string  The event id.
343:      * @throws Horde_Mime_Exception
344:      */
345:     protected function _updateEvent(Kronolith_Event $event)
346:     {
347:         return $this->_saveEvent($event, true);
348:     }
349: 
350:     /**
351:      * Adds an event to the backend.
352:      *
353:      * @param Kronolith_Event $event  The event to save.
354:      *
355:      * @return string  The event id.
356:      * @throws Horde_Mime_Exception
357:      */
358:     protected function _addEvent(Kronolith_Event $event)
359:     {
360:         return $this->_saveEvent($event, false);
361:     }
362: 
363:     /**
364:      * Saves an event in the backend.
365:      *
366:      * @param Kronolith_Event $event  The event to save.
367:      *
368:      * @return string  The event id.
369:      * @throws Horde_Mime_Exception
370:      */
371:     protected function _saveEvent($event, $edit)
372:     {
373:         $this->synchronize();
374: 
375:         $action = $edit
376:             ? array('action' => 'modify')
377:             : array('action' => 'add');
378: 
379:         if (!$event->uid) {
380:             $event->uid = $this->_data->generateUID();
381:         }
382:         if (!$edit) {
383:             $object = $event->toKolab();
384:             $this->_data->create($object);
385:         } else {
386:             $object = $event->toKolab();
387:             $this->_data->modify($object);
388:         }
389: 
390:         /* Deal with tags */
391:         if ($edit) {
392:             Kronolith::getTagger()->replaceTags($event->uid, $event->tags, $event->creator, 'event');
393:         } else {
394:             Kronolith::getTagger()->tag($event->uid, $event->tags, $event->creator, 'event');
395:         }
396: 
397:         $cal = $GLOBALS['kronolith_shares']->getShare($event->calendar);
398: 
399:         /* Notify about the changed event. */
400:         Kronolith::sendNotification($event, $edit ? 'edit' : 'add');
401: 
402:         /* Log the creation/modification of this item in the history log. */
403:         try {
404:             $GLOBALS['injector']->getInstance('Horde_History')->log('kronolith:' . $event->calendar . ':' . $event->uid, $action, true);
405:         } catch (Exception $e) {
406:             Horde::logMessage($e, 'ERR');
407:         }
408: 
409:         // refresh IMAP cache
410:         $this->synchronize(true);
411: 
412:         if (is_callable('Kolab', 'triggerFreeBusyUpdate')) {
413:             //Kolab::triggerFreeBusyUpdate($this->_data->parseFolder($event->calendar));
414:         }
415: 
416:         return $event->uid;
417:     }
418: 
419:     /**
420:      * Moves an event to a new calendar.
421:      *
422:      * @param string $eventId      The event to move.
423:      * @param string $newCalendar  The new calendar.
424:      *
425:      * @return Kronolith_Event  The old event.
426:      * @throws Kronolith_Exception
427:      * @throws Horde_Exception_NotFound
428:      */
429:     protected function _move($eventId, $newCalendar)
430:     {
431:         $event = $this->getEvent($eventId);
432:         $result = $this->synchronize();
433: 
434:         global $kronolith_shares;
435:         $target = $kronolith_shares->getShare($newCalendar);
436:         $folder = $target->getId();
437: 
438:         $result = $this->_data->move($eventId, $folder);
439:         if ($result) {
440:             unset($this->_events_cache[$eventId]);
441:         }
442: 
443:         if (is_callable('Kolab', 'triggerFreeBusyUpdate')) {
444:             //Kolab::triggerFreeBusyUpdate($this->_data->parseFolder($this->calendar));
445:             //Kolab::triggerFreeBusyUpdate($this->_data->parseFolder($newCalendar));
446:         }
447: 
448:         return $event;
449:     }
450: 
451:     /**
452:      * Delete a calendar and all its events.
453:      *
454:      * @param string $calendar  The name of the calendar to delete.
455:      *
456:      * @throws Kronolith_Exception
457:      */
458:     public function delete($calendar)
459:     {
460:         $this->open($calendar);
461:         $result = $this->synchronize();
462: 
463:         $result = $this->_data->deleteAll($calendar);
464:         if (is_callable('Kolab', 'triggerFreeBusyUpdate')) {
465:             //Kolab::triggerFreeBusyUpdate($this->_data->parseFolder($calendar));
466:         }
467:     }
468: 
469:     /**
470:      * Delete an event.
471:      *
472:      * @param string $eventId  The ID of the event to delete.
473:      *
474:      * @throws Kronolith_Exception
475:      * @throws Horde_Exception_NotFound
476:      * @throws Horde_Mime_Exception
477:      */
478:     public function deleteEvent($eventId, $silent = false)
479:     {
480:         $result = $this->synchronize();
481: 
482:         if (!$this->_data->objectIdExists($eventId)) {
483:             throw new Kronolith_Exception(sprintf(_("Event not found: %s"), $eventId));
484:         }
485: 
486:         $event = $this->getEvent($eventId);
487:         $this->_data->delete($eventId);
488: 
489:         // Notify about the deleted event.
490:         if (!$silent) {
491:             Kronolith::sendNotification($event, 'delete');
492:         }
493: 
494:         /* Log the deletion of this item in the history log. */
495:         try {
496:             $GLOBALS['injector']->getInstance('Horde_History')->log('kronolith:' . $event->calendar . ':' . $event->uid, array('action' => 'delete'), true);
497:         } catch (Exception $e) {
498:             Horde::logMessage($e, 'ERR');
499:         }
500: 
501:         unset($this->_events_cache[$eventId]);
502:     }
503: 
504: }
505: 
API documentation generated by ApiGen