/**
  * (non-PHPdoc)
  * @see Sabre\DAV\Collection::getChild()
  */
 public function getChild($_name)
 {
     $eventId = $_name instanceof Tinebase_Record_Interface ? $_name->getId() : $this->_getIdFromName($_name);
     // check if child exists in calendarQuery cache
     if ($this->_calendarQueryCache && isset($this->_calendarQueryCache[$eventId])) {
         $child = $this->_calendarQueryCache[$eventId];
         // remove entries from cache / they will not be used anymore
         unset($this->_calendarQueryCache[$eventId]);
         if (empty($this->_calendarQueryCache)) {
             $this->_calendarQueryCache = null;
         }
         return $child;
     }
     $modelName = $this->_application->name . '_Model_' . $this->_model;
     if ($_name instanceof $modelName) {
         $object = $_name;
     } else {
         $filterClass = $this->_application->name . '_Model_' . $this->_model . 'Filter';
         $filter = new $filterClass(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_container->getId()), array('condition' => 'OR', 'filters' => array(array('field' => 'id', 'operator' => 'equals', 'value' => $eventId), array('field' => 'uid', 'operator' => 'equals', 'value' => $eventId)))));
         $object = $this->_getController()->search($filter, null, false, false, 'sync')->getFirstRecord();
         if ($object == null) {
             throw new Sabre\DAV\Exception\NotFound('Object not found');
         }
     }
     $httpRequest = new Sabre\HTTP\Request();
     // lie about existence of event of request is a PUT request from an ATTENDEE for an already existing event
     // to prevent ugly (and not helpful) error messages on the client
     if (isset($_SERVER['REQUEST_METHOD']) && $httpRequest->getMethod() == 'PUT' && $httpRequest->getHeader('If-None-Match') === '*') {
         if ($object->organizer != Tinebase_Core::getUser()->contact_id && Calendar_Model_Attender::getOwnAttender($object->attendee) !== null) {
             throw new Sabre\DAV\Exception\NotFound('Object not found');
         }
     }
     $objectClass = $this->_application->name . '_Frontend_WebDAV_' . $this->_model;
     return new $objectClass($this->_container, $object);
 }
 /**
  * @return void
  */
 public function testEmailsToAttendeeWithGroups()
 {
     if (Tinebase_User::getConfiguredBackend() === Tinebase_User::LDAP || Tinebase_User::getConfiguredBackend() === Tinebase_User::ACTIVEDIRECTORY) {
         $this->markTestSkipped('FIXME: Does not work with LDAP/AD backend');
     }
     $event = $this->_getEvent();
     $persistentEvent = Calendar_Controller_Event::getInstance()->create($event);
     $primaryGroup = Tinebase_Group::getInstance()->getGroupById(Tinebase_Core::getUser()->accountPrimaryGroup);
     $newAttendees = array(array('userType' => Calendar_Model_Attender::USERTYPE_USER, 'firstName' => $this->_originalTestUser->accountFirstName, 'lastName' => $this->_originalTestUser->accountLastName, 'partStat' => Calendar_Model_Attender::STATUS_TENTATIVE, 'role' => Calendar_Model_Attender::ROLE_REQUIRED, 'email' => $this->_originalTestUser->accountEmailAddress), array('userType' => Calendar_Model_Attender::USERTYPE_GROUP, 'displayName' => $primaryGroup->name, 'partStat' => Calendar_Model_Attender::STATUS_NEEDSACTION, 'role' => Calendar_Model_Attender::ROLE_REQUIRED, 'email' => '*****@*****.**'));
     Calendar_Model_Attender::emailsToAttendee($persistentEvent, $newAttendees, TRUE);
     $persistentEvent = Calendar_Controller_Event::getInstance()->update($persistentEvent);
     $attendees = clone $persistentEvent->attendee;
     Calendar_Model_Attender::resolveAttendee($attendees);
     $newAttendees = array();
     foreach ($attendees as $attendee) {
         $newAttendees[] = array('userType' => $attendee->user_type == 'group' ? Calendar_Model_Attender::USERTYPE_GROUP : Calendar_Model_Attender::USERTYPE_USER, 'partStat' => Calendar_Model_Attender::STATUS_TENTATIVE, 'role' => Calendar_Model_Attender::ROLE_REQUIRED, 'email' => $attendee->user_type == 'group' ? $attendee->user_id->getId() : $attendee->user_id->email, 'displayName' => $attendee->user_type == 'group' ? $attendee->user_id->name : $attendee->user_id->n_fileas);
     }
     Calendar_Model_Attender::emailsToAttendee($persistentEvent, $newAttendees, TRUE);
     $persistentEvent = Calendar_Controller_Event::getInstance()->update($persistentEvent);
     //         print_r($persistentEvent->attendee->toArray());
     // there must be more than 2 attendees the user, the group + the groupmembers
     $this->assertGreaterThan(2, count($persistentEvent->attendee));
     // current account must not be a groupmember
     $this->assertFalse(!!Calendar_Model_Attender::getAttendee($persistentEvent->attendee, new Calendar_Model_Attender(array('user_type' => Calendar_Model_Attender::USERTYPE_GROUPMEMBER, 'user_id' => $this->_originalTestUser->contact_id))), 'found user as groupmember');
     $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, Calendar_Model_Attender::getOwnAttender($persistentEvent->attendee)->status);
 }
 /**
  * (non-PHPdoc)
  * @see Sabre\DAV\Collection::getChild()
  */
 public function getChild($_name)
 {
     try {
         $event = $_name instanceof Calendar_Model_Event ? $_name : $this->_getController()->get($this->_getIdFromName($_name));
     } catch (Tinebase_Exception_NotFound $tenf) {
         throw new \Sabre\DAV\Exception\NotFound('Object not found');
     }
     $ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee);
     $displayContainer = $ownAttendee->displaycontainer_id instanceof Tinebase_Model_Container ? $ownAttendee->displaycontainer_id : Tinebase_Container::getInstance()->get($ownAttendee->displaycontainer_id);
     return new Calendar_Frontend_WebDAV_Event($displayContainer, $event);
 }
 /**
  * (non-PHPdoc)
  * @see Sabre_DAV_Collection::getChild()
  */
 public function getChild($_name)
 {
     $modelName = $this->_application->name . '_Model_' . $this->_model;
     if ($_name instanceof $modelName) {
         $object = $_name;
     } else {
         $filterClass = $this->_application->name . '_Model_' . $this->_model . 'Filter';
         $filter = new $filterClass(array(array('field' => 'container_id', 'operator' => 'equals', 'value' => $this->_container->getId()), array('condition' => 'OR', 'filters' => array(array('field' => 'id', 'operator' => 'equals', 'value' => $this->_getIdFromName($_name)), array('field' => 'uid', 'operator' => 'equals', 'value' => $this->_getIdFromName($_name))))));
         $object = $this->_getController()->search($filter, null, false, false, 'sync')->getFirstRecord();
         if ($object == null) {
             throw new Sabre_DAV_Exception_FileNotFound('Object not found');
         }
     }
     $httpRequest = new Sabre_HTTP_Request();
     // lie about existance of event of request is a PUT request from an ATTENDEE for an already existing event
     // to prevent ugly (and not helpful) error messages on the client
     if (isset($_SERVER['REQUEST_METHOD']) && $httpRequest->getMethod() == 'PUT' && $httpRequest->getHeader('If-None-Match') === '*') {
         if ($object->organizer != Tinebase_Core::getUser()->contact_id && Calendar_Model_Attender::getOwnAttender($object->attendee) !== null) {
             throw new Sabre_DAV_Exception_FileNotFound('Object not found');
         }
     }
     $objectClass = $this->_application->name . '_Frontend_WebDAV_' . $this->_model;
     return new $objectClass($this->_container, $object);
 }
 /**
  * process request
  * 
  * @param  Calendar_Model_iMIP   $_iMIP
  * @param  string                $_status
  */
 protected function _processRequest($_iMIP, $_status)
 {
     $existingEvent = $this->getExistingEvent($_iMIP);
     $ownAttender = Calendar_Model_Attender::getOwnAttender($existingEvent ? $existingEvent->attendee : $_iMIP->getEvent()->attendee);
     $organizer = $existingEvent ? $existingEvent->resolveOrganizer() : $_iMIP->getEvent()->resolveOrganizer();
     // internal organizer:
     //  - event is up to date
     //  - status change could also be done by calendar method
     //  - normal notifications
     if ($organizer->account_id) {
         if (!$existingEvent) {
             // organizer has an account but no event exists, it seems that event was created from a non-caldav client
             // do not send notifications in this case + create event in context of organizer
             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Organizer has an account but no event exists!');
             }
             return;
             // not clear how to create in the organizers context...
             $sendNotifications = Calendar_Controller_Event::getInstance()->sendNotifications(FALSE);
             $existingEvent = Calendar_Controller_MSEventFacade::getInstance()->create($_iMIP->getEvent());
             Calendar_Controller_Event::getInstance()->sendNotifications($sendNotifications);
         }
         if ($_status && $_status != $ownAttender->status) {
             $ownAttender->status = $_status;
             Calendar_Controller_Event::getInstance()->attenderStatusUpdate($existingEvent, $ownAttender, $ownAttender->status_authkey);
         }
     } else {
         $sendNotifications = Calendar_Controller_Event::getInstance()->sendNotifications(false);
         $event = $_iMIP->getEvent();
         if (!$existingEvent) {
             if (!$event->container_id) {
                 $event->container_id = Tinebase_Core::getPreference('Calendar')->{Calendar_Preference::DEFAULTCALENDAR};
             }
             $event = $_iMIP->event = Calendar_Controller_MSEventFacade::getInstance()->create($event);
         } else {
             if ($event->external_seq > $existingEvent->external_seq && !$_status) {
                 // no buttons pressed (just reading/updating)
                 // updates event with .ics
                 $event->id = $existingEvent->id;
                 $event = $_iMIP->event = Calendar_Controller_MSEventFacade::getInstance()->update($event);
             } else {
                 $event = $_iMIP->event = Calendar_Controller_MSEventFacade::getInstance()->update($existingEvent);
             }
         }
         Calendar_Controller_Event::getInstance()->sendNotifications($sendNotifications);
         $ownAttender = Calendar_Model_Attender::getOwnAttender($event->attendee);
         // NOTE: we do the status update in a separate call to trigger the right notifications
         if ($ownAttender && $_status) {
             $ownAttender->status = $_status;
             $a = Calendar_Controller_Event::getInstance()->attenderStatusUpdate($event, $ownAttender, $ownAttender->status_authkey);
         }
     }
 }
 /**
  * add status_authkey for own attender
  * 
  * @param Calendar_Model_Event $event
  */
 protected function _addStatusAuthkeyForOwnAttender($event)
 {
     if (!$event->attendee instanceof Tinebase_Record_RecordSet) {
         return;
     }
     $ownAttender = Calendar_Model_Attender::getOwnAttender($event->attendee);
     if ($ownAttender) {
         $currentEvent = $this->_eventController->get($event->id);
         $currentAttender = Calendar_Model_Attender::getAttendee($currentEvent->attendee, $ownAttender);
         if ($currentAttender) {
             $ownAttender->status_authkey = $currentAttender->status_authkey;
         } else {
             if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
                 Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' currentAttender not found in currentEvent: ' . print_r($currentEvent->toArray(), true));
             }
         }
     }
 }
 /**
  * set status of own attender depending on BusyStatus
  * 
  * @param SimpleXMLElement $xmlData
  * @param Calendar_Model_Event $event
  * 
  * @todo move detection of special handling / device type to device library
  */
 protected function _handleBusyStatus($data, $event)
 {
     if (!isset($data->busyStatus)) {
         return;
     }
     $ownAttender = Calendar_Model_Attender::getOwnAttender($event->attendee);
     if ($ownAttender === NULL) {
         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' No own attender found.');
         }
         return;
     }
     $busyStatus = $data->busyStatus;
     if (in_array(strtolower($this->_device->devicetype), $this->_devicesWithWrongBusyStatusDefault)) {
         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Device uses a bad default setting. BUSY and FREE are mapped to ACCEPTED.');
         }
         $busyStatusMapping = array(Syncroton_Model_Event::BUSY_STATUS_BUSY => Calendar_Model_Attender::STATUS_ACCEPTED, Syncroton_Model_Event::BUSY_STATUS_TENATTIVE => Calendar_Model_Attender::STATUS_TENTATIVE, Syncroton_Model_Event::BUSY_STATUS_FREE => Calendar_Model_Attender::STATUS_ACCEPTED);
     } else {
         $busyStatusMapping = $this->_busyStatusMapping;
     }
     if (isset($busyStatusMapping[$busyStatus])) {
         $ownAttender->status = $busyStatusMapping[$busyStatus];
     } else {
         $ownAttender->status = Calendar_Model_Attender::STATUS_NEEDSACTION;
     }
 }
 /**
  * NOTE: As noted in {@see testMoveOriginPersonalToShared} we can't delete/decline for organizer in his
  *       personal cal because a move personal->shared would delete/decline the event.
  *       
  *       To support intensional delete/declines we allow the delte/decline only if ther is some
  *       time between this and the last update
  */
 public function testDeleteImplicitDeclineOrganizer()
 {
     $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.21) Gecko/20110831 Lightning/1.0b2 Thunderbird/3.1.13';
     $vcalendar = self::getVCalendar(dirname(__FILE__) . '/../../Import/files/lightning.ics');
     $vcalendar = preg_replace('#DTSTART;TZID=Europe/Berlin:20111004T100000#', 'DTSTART;TZID=Europe/Berlin:' . Tinebase_DateTime::now()->format('Ymd\\THis'), $vcalendar);
     $vcalendar = preg_replace('#DTEND;TZID=Europe/Berlin:20111004T120000#', 'DTEND;TZID=Europe/Berlin:' . Tinebase_DateTime::now()->addHour(1)->format('Ymd\\THis'), $vcalendar);
     $id = Tinebase_Record_Abstract::generateUID();
     $event = Calendar_Frontend_WebDAV_Event::create($this->objects['initialContainer'], "{$id}.ics", $vcalendar);
     // move event origin to shared (origin and display where the same)
     Calendar_Frontend_WebDAV_Event::create($this->objects['sharedContainer'], "{$id}.ics", stream_get_contents($event->get()));
     //         $oldEvent = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], "$id.ics");
     //         $oldEvent->delete();
     // wait some time
     $cbs = new Calendar_Backend_Sql();
     $cbs->updateMultiple(array($id), array('creation_time' => Tinebase_DateTime::now()->subMinute(5), 'last_modified_time' => Tinebase_DateTime::now()->subMinute(3)));
     $personalEvent = new Calendar_Frontend_WebDAV_Event($this->objects['initialContainer'], "{$id}.ics");
     $personalEvent->delete();
     $loadedEvent = new Calendar_Frontend_WebDAV_Event($this->objects['sharedContainer'], "{$id}.ics");
     $ownAttendee = Calendar_Model_Attender::getOwnAttender($loadedEvent->getRecord()->attendee);
     $this->assertEquals(Calendar_Model_Attender::STATUS_DECLINED, $ownAttendee->status, 'event must be declined');
 }
 public function testAlarm()
 {
     Tinebase_Alarm::getInstance()->sendPendingAlarms("Tinebase_Event_Async_Minutely");
     $event = $this->_getEvent();
     $event->dtstart = Tinebase_DateTime::now()->addMinute(15);
     $event->dtend = clone $event->dtstart;
     $event->dtend->addMinute(30);
     $event->attendee = $this->_getAttendee();
     $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(new Tinebase_Model_Alarm(array('minutes_before' => 30), TRUE)));
     $persistentEvent = $this->_eventController->create($event);
     Calendar_Model_Attender::getOwnAttender($persistentEvent->attendee)->status = Calendar_Model_Attender::STATUS_DECLINED;
     // hack to get declined attendee
     $this->_eventController->sendNotifications(FALSE);
     $updatedEvent = $this->_eventController->update($persistentEvent);
     $this->_eventController->sendNotifications(TRUE);
     self::flushMailer();
     Tinebase_Alarm::getInstance()->sendPendingAlarms("Tinebase_Event_Async_Minutely");
     $this->_assertMail('sclever', 'Alarm');
     $this->assertEquals(1, count(self::getMessages()));
 }
 /**
  * testInternalInvitationRequestProcess
  */
 public function testInternalInvitationRequestProcess()
 {
     $iMIP = $this->_getiMIP('REQUEST');
     $result = $this->_iMIPFrontendMock->process($iMIP, Calendar_Model_Attender::STATUS_TENTATIVE);
     $event = $this->_iMIPFrontend->getExistingEvent($iMIP, true);
     $attender = Calendar_Model_Attender::getOwnAttender($event->attendee);
     $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, $attender->status);
 }
Exemple #11
0
 /**
  * Updates the VCard-formatted object
  *
  * @param string $cardData
  * @return void
  */
 public function put($cardData)
 {
     if (get_class($this->_converter) == 'Calendar_Convert_Event_VCalendar_Generic') {
         if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) {
             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " update by generic client not allowed. See Calendat_Convert_Event_VCalendar_Factory for supported clients.");
         }
         throw new Sabre_DAV_Exception_Forbidden('Update denied for unknow client');
     }
     if (is_resource($cardData)) {
         $cardData = stream_get_contents($cardData);
     }
     // Converting to UTF-8, if needed
     $cardData = Sabre_DAV_StringUtil::ensureUTF8($cardData);
     Sabre_CalDAV_ICalendarUtil::validateICalendarObject($cardData, array('VEVENT', 'VFREEBUSY'));
     $vobject = Calendar_Convert_Event_VCalendar_Abstract::getVcal($cardData);
     foreach ($vobject->children() as $component) {
         if (isset($component->{'X-TINE20-CONTAINER'})) {
             $xContainerId = $component->{'X-TINE20-CONTAINER'};
             break;
         }
     }
     // keep old record for reference
     $recordBeforeUpdate = clone $this->getRecord();
     $event = $this->_converter->toTine20Model($vobject, $this->getRecord());
     // iCal does sends back an old value, because it does not refresh the vcalendar after
     // update. Therefor we must reapply the value of last_modified_time after the convert
     $event->last_modified_time = $recordBeforeUpdate->last_modified_time;
     $currentContainer = Tinebase_Container::getInstance()->getContainerById($this->getRecord()->container_id);
     $ownAttendee = Calendar_Model_Attender::getOwnAttender($this->getRecord()->attendee);
     // event 'belongs' current user -> allow container move
     if ($currentContainer->isPersonalOf(Tinebase_Core::getUser())) {
         $event->container_id = $this->_container->getId();
     } else {
         if (isset($xContainerId)) {
             if ($xContainerId == $currentContainer->getId()) {
                 $event->container_id = $this->_container->getId();
             } else {
                 // @TODO allow organizer to move original cal when he edits the displaycal event?
                 if ($ownAttendee && $this->_container->type == Tinebase_Model_Container::TYPE_PERSONAL) {
                     $ownAttendee->displaycontainer_id = $this->_container->getId();
                 }
             }
         } else {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " X-TINE20-CONTAINER not present -> restrict container moves");
             }
             if ($ownAttendee && $this->_container->type == Tinebase_Model_Container::TYPE_PERSONAL) {
                 if ($ownAttendee->displaycontainer_id == $currentContainer->getId()) {
                     $event->container_id = $this->_container->getId();
                 }
                 $ownAttendee->displaycontainer_id = $this->_container->getId();
             }
         }
     }
     self::enforceEventParameters($event);
     // don't allow update of alarms for non organizer if oganizer is Tine 2.0 user
     if ($event->organizer !== Tinebase_Core::getUser()->contact_id) {
         $organizerContact = Addressbook_Controller_Contact::getInstance()->get($event->organizer);
         // reset alarms if organizer is Tine 2.0 user
         if (!empty($organizerContact->account_id)) {
             $this->_resetAlarms($event, $recordBeforeUpdate);
         }
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " " . print_r($event->toArray(), true));
     }
     try {
         $this->_event = Calendar_Controller_MSEventFacade::getInstance()->update($event);
     } catch (Tinebase_Timemachine_Exception_ConcurrencyConflict $ttecc) {
         throw new Sabre_DAV_Exception_PreconditionFailed('An If-Match header was specified, but none of the specified the ETags matched.', 'If-Match');
     }
     // avoid sending headers during unit tests
     if (php_sapi_name() != 'cli') {
         // @todo this belong to DAV_Server, but it currently not supported
         header('ETag: ' . $this->getETag());
     }
 }
 /**
  * checks event for given grant
  * 
  * @param  string $_grant
  * @return bool
  */
 public function hasGrant($_grant)
 {
     $hasGrant = (isset($this->_properties[$_grant]) || array_key_exists($_grant, $this->_properties)) && (bool) $this->{$_grant};
     if ($this->class !== Calendar_Model_Event::CLASS_PUBLIC) {
         $hasGrant &= $this->{Tinebase_Model_Grants::GRANT_PRIVATE} || Tinebase_Core::getUser()->contact_id == ($this->organizer instanceof Addressbook_Model_Contact ? $this->organizer->getId() : $this->organizer) || Calendar_Model_Attender::getOwnAttender($this->attendee);
     }
     return $hasGrant;
 }
 public function testRepairAttendee()
 {
     $event = $this->_getEvent(true);
     $event->attendee = null;
     $persistentEvent = $this->_controller->create($event);
     $result = $this->_controller->repairAttendee($persistentEvent->container_id, Tinebase_DateTime::now()->subDay(1), Tinebase_DateTime::now());
     $this->assertEquals(1, $result, 'should repair 1 event');
     $repairedEvent = $this->_controller->get($persistentEvent->getId());
     $this->assertEquals(1, count($repairedEvent->attendee));
     $ownAttender = Calendar_Model_Attender::getOwnAttender($repairedEvent->attendee);
     $this->assertTrue($ownAttender !== null);
 }
 /**
  * parse VEVENT part of VCALENDAR
  * 
  * @param  Sabre_VObject_Component  $_vevent  the VEVENT to parse
  * @param  Calendar_Model_Event     $_event   the Tine 2.0 event to update
  */
 protected function _convertVevent(Sabre_VObject_Component $_vevent, Calendar_Model_Event $_event)
 {
     $event = $_event;
     $newAttendees = array();
     // unset supported fields
     foreach ($this->_supportedFields as $field) {
         if ($field == 'alarms') {
             $event->{$field} = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm');
         } else {
             $event->{$field} = null;
         }
     }
     foreach ($_vevent->children() as $property) {
         switch ($property->name) {
             case 'CREATED':
             case 'DTSTAMP':
                 // do nothing
                 break;
             case 'LAST-MODIFIED':
                 $event->last_modified_time = new Tinebase_DateTime($property->value);
                 break;
             case 'ATTENDEE':
                 $newAttendees[] = $this->_getAttendee($property);
                 break;
             case 'CLASS':
                 if (in_array($property->value, array(Calendar_Model_Event::CLASS_PRIVATE, Calendar_Model_Event::CLASS_PUBLIC))) {
                     $event->class = $property->value;
                 } else {
                     $event->class = Calendar_Model_Event::CLASS_PUBLIC;
                 }
                 break;
             case 'DTEND':
                 if (isset($property['VALUE']) && strtoupper($property['VALUE']) == 'DATE') {
                     // all day event
                     $event->is_all_day_event = true;
                     $dtend = $this->_convertToTinebaseDateTime($property, TRUE);
                     // whole day events ends at 23:59:59 in Tine 2.0 but 00:00 the next day in vcalendar
                     $dtend->subSecond(1);
                 } else {
                     $event->is_all_day_event = false;
                     $dtend = $this->_convertToTinebaseDateTime($property);
                 }
                 $event->dtend = $dtend;
                 break;
             case 'DTSTART':
                 if (isset($property['VALUE']) && strtoupper($property['VALUE']) == 'DATE') {
                     // all day event
                     $event->is_all_day_event = true;
                     $dtstart = $this->_convertToTinebaseDateTime($property, TRUE);
                 } else {
                     $event->is_all_day_event = false;
                     $dtstart = $this->_convertToTinebaseDateTime($property);
                 }
                 $event->originator_tz = $dtstart->getTimezone()->getName();
                 $event->dtstart = $dtstart;
                 break;
             case 'SEQUENCE':
                 $event->seq = $property->value;
                 break;
             case 'DESCRIPTION':
             case 'LOCATION':
             case 'UID':
             case 'SUMMARY':
                 $key = strtolower($property->name);
                 $event->{$key} = $property->value;
                 break;
             case 'ORGANIZER':
                 if (preg_match('/mailto:(?P<email>.*)/i', $property->value, $matches)) {
                     // it's not possible to change the organizer by spec
                     if (empty($event->organizer)) {
                         $name = isset($property['CN']) ? $property['CN']->value : $matches['email'];
                         $contact = Calendar_Model_Attender::resolveEmailToContact(array('email' => $matches['email'], 'lastName' => $name));
                         $event->organizer = $contact->getId();
                     }
                     // Lightning attaches organizer ATTENDEE properties to ORGANIZER property and does not add an ATTENDEE for the organizer
                     if (isset($property['PARTSTAT'])) {
                         $newAttendees[] = $this->_getAttendee($property);
                     }
                 }
                 break;
             case 'RECURRENCE-ID':
                 // original start of the event
                 $event->recurid = $this->_convertToTinebaseDateTime($property);
                 // convert recurrence id to utc
                 $event->recurid->setTimezone('UTC');
                 break;
             case 'RRULE':
                 $event->rrule = $property->value;
                 // convert date format
                 $event->rrule = preg_replace_callback('/UNTIL=([\\dTZ]+)(?=;?)/', function ($matches) {
                     if (strlen($matches[1]) < 10) {
                         $dtUntil = date_create($matches[1], new DateTimeZone((string) Tinebase_Core::get(Tinebase_Core::USERTIMEZONE)));
                         $dtUntil->setTimezone(new DateTimeZone('UTC'));
                     } else {
                         $dtUntil = date_create($matches[1]);
                     }
                     return 'UNTIL=' . $dtUntil->format(Tinebase_Record_Abstract::ISO8601LONG);
                 }, $event->rrule);
                 // remove additional days from BYMONTHDAY property
                 $event->rrule = preg_replace('/(BYMONTHDAY=)([\\d]+)([,\\d]+)/', '$1$2', $event->rrule);
                 // process exceptions
                 if (isset($_vevent->EXDATE)) {
                     $exdates = new Tinebase_Record_RecordSet('Calendar_Model_Event');
                     foreach ($_vevent->EXDATE as $exdate) {
                         foreach ($exdate->getDateTimes() as $exception) {
                             if (isset($exdate['VALUE']) && strtoupper($exdate['VALUE']) == 'DATE') {
                                 $recurid = new Tinebase_DateTime($exception->format(Tinebase_Record_Abstract::ISO8601LONG), (string) Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
                             } else {
                                 $recurid = new Tinebase_DateTime($exception->format(Tinebase_Record_Abstract::ISO8601LONG), $exception->getTimezone());
                             }
                             $recurid->setTimezone(new DateTimeZone('UTC'));
                             $eventException = new Calendar_Model_Event(array('recurid' => $recurid, 'is_deleted' => true));
                             $exdates->addRecord($eventException);
                         }
                     }
                     $event->exdate = $exdates;
                 }
                 break;
             case 'TRANSP':
                 if (in_array($property->value, array(Calendar_Model_Event::TRANSP_OPAQUE, Calendar_Model_Event::TRANSP_TRANSP))) {
                     $event->transp = $property->value;
                 } else {
                     $event->transp = Calendar_Model_Event::TRANSP_TRANSP;
                 }
                 break;
             case 'UID':
                 // it's not possible to change the uid by spec
                 if (!empty($event->uid)) {
                     continue;
                 }
                 $event->uid = $property->value;
                 break;
             case 'VALARM':
                 foreach ($property as $valarm) {
                     switch (strtoupper($valarm->TRIGGER['VALUE']->value)) {
                         # TRIGGER;VALUE=DATE-TIME:20111031T130000Z
                         case 'DATE-TIME':
                             //@TODO fixme
                             $alarmTime = new Tinebase_DateTime($valarm->TRIGGER->value);
                             $alarmTime->setTimezone('UTC');
                             $alarm = new Tinebase_Model_Alarm(array('alarm_time' => $alarmTime, 'minutes_before' => 'custom', 'model' => 'Calendar_Model_Event'));
                             $event->alarms->addRecord($alarm);
                             break;
                             # TRIGGER;VALUE=DURATION:-PT1H15M
                         # TRIGGER;VALUE=DURATION:-PT1H15M
                         case 'DURATION':
                         default:
                             $alarmTime = $this->_convertToTinebaseDateTime($_vevent->DTSTART);
                             $alarmTime->setTimezone('UTC');
                             preg_match('/(?P<invert>[+-]?)(?P<spec>P.*)/', $valarm->TRIGGER->value, $matches);
                             $duration = new DateInterval($matches['spec']);
                             $duration->invert = !!($matches['invert'] === '-');
                             $alarm = new Tinebase_Model_Alarm(array('alarm_time' => $alarmTime->add($duration), 'minutes_before' => $duration->format('%d') * 60 * 24 + $duration->format('%h') * 60 + $duration->format('%i'), 'model' => 'Calendar_Model_Event'));
                             $event->alarms->addRecord($alarm);
                             break;
                     }
                 }
                 break;
             case 'CATEGORIES':
                 // @todo handle categories
                 break;
             case 'X-MOZ-LASTACK':
                 $lastAck = $this->_convertToTinebaseDateTime($property);
                 break;
             case 'X-MOZ-SNOOZE-TIME':
                 $snoozeTime = $this->_convertToTinebaseDateTime($property);
                 break;
             default:
                 break;
         }
     }
     // merge old and new attendees
     Calendar_Model_Attender::emailsToAttendee($event, $newAttendees);
     if (($ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee)) !== null) {
         if (isset($lastAck)) {
             $ownAttendee->alarm_ack_time = $lastAck;
         }
         if (isset($snoozeTime)) {
             $ownAttendee->alarm_snooze_time = $snoozeTime;
         }
     }
     if (empty($event->seq)) {
         $event->seq = 0;
     }
     if (empty($event->class)) {
         $event->class = Calendar_Model_Event::CLASS_PUBLIC;
     }
     // convert all datetime fields to UTC
     $event->setTimezone('UTC');
 }
 /**
  * add calendar owner as attendee if not already set
  * 
  * @param string $calendarId
  * @param Tinebase_DateTime $from
  * @param Tinebase_DateTime $until
  * @param boolean $dry run
  * 
  * @return number of updated events
  */
 public function repairAttendee($calendarId, $from, $until, $dry = false)
 {
     $container = Tinebase_Container::getInstance()->getContainerById($calendarId);
     if ($container->type !== Tinebase_Model_Container::TYPE_PERSONAL) {
         throw new Calendar_Exception('Only allowed for personal containers!');
     }
     if ($container->owner_id !== Tinebase_Core::getUser()->getId()) {
         throw new Calendar_Exception('Only allowed for own containers!');
     }
     $updateCount = 0;
     while ($from->isEarlier($until)) {
         $endWeek = $from->getClone()->addWeek(1);
         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Repairing period ' . $from . ' - ' . $endWeek);
         }
         // TODO we need to detect events with DECLINED/DELETED attendee
         $events = $this->_getEventsForPeriodAndCalendar($calendarId, $from, $endWeek);
         $from->addWeek(1);
         if (count($events) == 0) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' No events found');
             }
             continue;
         }
         foreach ($events as $event) {
             // add attendee if not already set
             if ($event->isRecurInstance()) {
                 // TODO get base event
                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Skip recur instance ' . $event->toShortString());
                 }
                 continue;
             }
             $ownAttender = Calendar_Model_Attender::getOwnAttender($event->attendee);
             if (!$ownAttender) {
                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Add missing attender to event ' . $event->toShortString());
                 }
                 $attender = new Calendar_Model_Attender(array('user_type' => Calendar_Model_Attender::USERTYPE_USER, 'user_id' => Tinebase_Core::getUser()->contact_id, 'status' => Calendar_Model_Attender::STATUS_ACCEPTED));
                 $event->attendee->addRecord($attender);
                 if (!$dry) {
                     $this->update($event);
                 }
                 $updateCount++;
             }
         }
     }
     return $updateCount;
 }
 /**
  * convert contact from xml to Calendar_Model_Event
  *
  * @todo handle BusyStatus
  * @param SimpleXMLElement $_data
  * @return Calendar_Model_Event
  */
 public function toTineModel(SimpleXMLElement $_data, $_entry = null)
 {
     if ($_entry instanceof Calendar_Model_Event) {
         $event = $_entry;
     } else {
         $event = new Calendar_Model_Event(array(), true);
     }
     $xmlData = $_data->children('uri:Calendar');
     $airSyncBase = $_data->children('uri:AirSyncBase');
     foreach ($this->_mapping as $fieldName => $value) {
         switch ($value) {
             case 'dtend':
             case 'dtstart':
                 if (isset($xmlData->{$fieldName})) {
                     $event->{$value} = new Tinebase_DateTime((string) $xmlData->{$fieldName});
                 } else {
                     $event->{$value} = null;
                 }
                 break;
             default:
                 if (isset($xmlData->{$fieldName})) {
                     $event->{$value} = (string) $xmlData->{$fieldName};
                 } else {
                     $event->{$value} = null;
                 }
                 break;
         }
     }
     // get body
     if (version_compare($this->_device->acsversion, '12.0', '>=') === true) {
         $event->description = isset($airSyncBase->Body) ? (string) $airSyncBase->Body->Data : null;
     } else {
         $event->description = isset($xmlData->Body) ? (string) $xmlData->Body : null;
     }
     // whole day events ends at 23:59:59 in Tine 2.0 but 00:00 the next day in AS
     if (isset($xmlData->AllDayEvent) && $xmlData->AllDayEvent == 1) {
         $event->dtend->subSecond(1);
     }
     if (isset($xmlData->Reminder)) {
         $alarm = clone $event->dtstart;
         $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array(array('alarm_time' => $alarm->subMinute((int) $xmlData->Reminder), 'minutes_before' => (int) $xmlData->Reminder, 'model' => 'Calendar_Model_Event')));
     }
     // decode timezone data
     if (isset($xmlData->Timezone)) {
         $timeZoneConverter = ActiveSync_TimezoneConverter::getInstance(Tinebase_Core::getLogger(), Tinebase_Core::get(Tinebase_Core::CACHE));
         try {
             $timezone = $timeZoneConverter->getTimezone((string) $xmlData->Timezone, Tinebase_Core::get(Tinebase_Core::USERTIMEZONE));
             $event->originator_tz = $timezone;
         } catch (ActiveSync_TimezoneNotFoundException $e) {
             Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . " timezone data not found " . (string) $xmlData->Timezone);
             $event->originator_tz = Tinebase_Core::get(Tinebase_Core::USERTIMEZONE);
         }
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " timezone data " . $event->originator_tz);
         }
     }
     if (!$event->attendee instanceof Tinebase_Record_RecordSet) {
         $event->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender');
     }
     if (isset($xmlData->Attendees)) {
         $newAttendees = array();
         foreach ($xmlData->Attendees->Attendee as $attendee) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " attendee email " . $attendee->Email);
             }
             if (isset($attendee->AttendeeType) && array_key_exists((int) $attendee->AttendeeType, $this->_attendeeTypeMapping)) {
                 $role = $this->_attendeeTypeMapping[(int) $attendee->AttendeeType];
             } else {
                 $role = Calendar_Model_Attender::ROLE_REQUIRED;
             }
             // AttendeeStatus send only on repsonse
             if (preg_match('/(?P<firstName>\\S*) (?P<lastNameName>\\S*)/', (string) $attendee->Name, $matches)) {
                 $firstName = $matches['firstName'];
                 $lastName = $matches['lastNameName'];
             } else {
                 $firstName = null;
                 $lastName = $attendee->Name;
             }
             // @todo handle resources
             $newAttendees[] = array('userType' => Calendar_Model_Attender::USERTYPE_USER, 'firstName' => $firstName, 'lastName' => $lastName, 'role' => $role, 'email' => (string) $attendee->Email);
         }
         Calendar_Model_Attender::emailsToAttendee($event, $newAttendees);
     }
     // new event, add current user as participant
     if ($event->getId() == null) {
         $selfContactId = Tinebase_Core::getUser()->contact_id;
         $selfAttender = $event->attendee->filter('user_type', Calendar_Model_Attender::USERTYPE_USER)->filter('user_id', $selfContactId);
         if (count($selfAttender) == 0) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " added current user as attender for new event ");
             }
             $newAttender = new Calendar_Model_Attender(array('user_id' => $selfContactId, 'user_type' => Calendar_Model_Attender::USERTYPE_USER, 'status' => Calendar_Model_Attender::STATUS_ACCEPTED, 'role' => Calendar_Model_Attender::ROLE_REQUIRED));
             $event->attendee->addRecord($newAttender);
         }
     }
     if (isset($xmlData->BusyStatus) && ($ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee)) !== null) {
         if (isset($this->_busyStatusMapping[(string) $xmlData->BusyStatus])) {
             $ownAttendee->status = $this->_busyStatusMapping[(string) $xmlData->BusyStatus];
         } else {
             $ownAttendee->status = Calendar_Model_Attender::STATUS_NEEDSACTION;
         }
     }
     // handle recurrence
     if (isset($xmlData->Recurrence) && isset($xmlData->Recurrence->Type)) {
         $rrule = new Calendar_Model_Rrule();
         switch ((int) $xmlData->Recurrence->Type) {
             case self::RECUR_TYPE_DAILY:
                 $rrule->freq = Calendar_Model_Rrule::FREQ_DAILY;
                 break;
             case self::RECUR_TYPE_WEEKLY:
                 $rrule->freq = Calendar_Model_Rrule::FREQ_WEEKLY;
                 $rrule->byday = $this->_convertBitMaskToDay((int) $xmlData->Recurrence->DayOfWeek);
                 break;
             case self::RECUR_TYPE_MONTHLY:
                 $rrule->freq = Calendar_Model_Rrule::FREQ_MONTHLY;
                 $rrule->bymonthday = (int) $xmlData->Recurrence->DayOfMonth;
                 break;
             case self::RECUR_TYPE_MONTHLY_DAYN:
                 $rrule->freq = Calendar_Model_Rrule::FREQ_MONTHLY;
                 $week = (int) $xmlData->Recurrence->WeekOfMonth;
                 $day = (int) $xmlData->Recurrence->DayOfWeek;
                 $byDay = $week == 5 ? -1 : $week;
                 $byDay .= $this->_convertBitMaskToDay($day);
                 $rrule->byday = $byDay;
                 break;
             case self::RECUR_TYPE_YEARLY:
                 $rrule->freq = Calendar_Model_Rrule::FREQ_YEARLY;
                 $rrule->bymonth = (int) $xmlData->Recurrence->MonthOfYear;
                 $rrule->bymonthday = (int) $xmlData->Recurrence->DayOfMonth;
                 break;
             case self::RECUR_TYPE_YEARLY_DAYN:
                 $rrule->freq = Calendar_Model_Rrule::FREQ_YEARLY;
                 $rrule->bymonth = (int) $xmlData->Recurrence->MonthOfYear;
                 $week = (int) $xmlData->Recurrence->WeekOfMonth;
                 $day = (int) $xmlData->Recurrence->DayOfWeek;
                 $byDay = $week == 5 ? -1 : $week;
                 $byDay .= $this->_convertBitMaskToDay($day);
                 $rrule->byday = $byDay;
                 break;
         }
         $rrule->interval = isset($xmlData->Recurrence->Interval) ? (int) $xmlData->Recurrence->Interval : 1;
         if (isset($xmlData->Recurrence->Until)) {
             $rrule->until = new Tinebase_DateTime((string) $xmlData->Recurrence->Until);
             // until ends at 23:59:59 in Tine 2.0 but at 00:00:00 in Windows CE (local user time)
             if ($rrule->until->format('s') == '00') {
                 $rrule->until->addHour(23)->addMinute(59)->addSecond(59);
             }
         } else {
             $rrule->until = null;
         }
         $event->rrule = $rrule;
         // handle exceptions from recurrence
         if (isset($xmlData->Exceptions)) {
             $exdates = new Tinebase_Record_RecordSet('Calendar_Model_Event');
             foreach ($xmlData->Exceptions->Exception as $exception) {
                 $eventException = new Calendar_Model_Event(array('recurid' => new Tinebase_DateTime((string) $exception->ExceptionStartTime)));
                 if ((int) $exception->Deleted === 0) {
                     $eventException->is_deleted = false;
                     $this->toTineModel($exception, $eventException);
                 } else {
                     $eventException->is_deleted = true;
                 }
                 $exdates->addRecord($eventException);
             }
             $event->exdate = $exdates;
         }
     } else {
         $event->rrule = null;
         $event->exdate = null;
     }
     if (empty($event->organizer)) {
         $event->organizer = Tinebase_Core::getUser()->contact_id;
     }
     // event should be valid now
     $event->isValid();
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " eventData " . print_r($event->toArray(), true));
     }
     return $event;
 }
 /**
  * convert calendar event to Sabre\VObject\Component
  * 
  * @param  \Sabre\VObject\Component\VCalendar $vcalendar
  * @param  Calendar_Model_Event               $_event
  * @param  Calendar_Model_Event               $_mainEvent
  */
 protected function _convertCalendarModelEvent(\Sabre\VObject\Component\VCalendar $vcalendar, Calendar_Model_Event $_event, Calendar_Model_Event $_mainEvent = null)
 {
     // clone the event and change the timezone
     $event = clone $_event;
     $event->setTimezone($event->originator_tz);
     $lastModifiedDateTime = $_event->last_modified_time ? $_event->last_modified_time : $_event->creation_time;
     if (!$event->creation_time instanceof Tinebase_DateTime) {
         throw new Tinebase_Exception_Record_Validation('creation_time needed for conversion to Sabre\\VObject\\Component');
     }
     $vevent = $vcalendar->create('VEVENT', array('CREATED' => $_event->creation_time->getClone()->setTimezone('UTC'), 'LAST-MODIFIED' => $lastModifiedDateTime->getClone()->setTimezone('UTC'), 'DTSTAMP' => Tinebase_DateTime::now(), 'UID' => $event->uid));
     $vevent->add('SEQUENCE', $event->hasExternalOrganizer() ? $event->external_seq : $event->seq);
     if ($event->isRecurException()) {
         $originalDtStart = $_event->getOriginalDtStart()->setTimezone($_event->originator_tz);
         $recurrenceId = $vevent->add('RECURRENCE-ID', $originalDtStart);
         if ($_mainEvent && $_mainEvent->is_all_day_event == true) {
             $recurrenceId['VALUE'] = 'DATE';
         }
     }
     // dtstart and dtend
     $dtstart = $vevent->add('DTSTART', $_event->dtstart->getClone()->setTimezone($event->originator_tz));
     if ($event->is_all_day_event == true) {
         $dtstart['VALUE'] = 'DATE';
         // whole day events ends at 23:59:(00|59) in Tine 2.0 but 00:00 the next day in vcalendar
         $event->dtend->addSecond($event->dtend->get('s') == 59 ? 1 : 0);
         $event->dtend->addMinute($event->dtend->get('i') == 59 ? 1 : 0);
         $dtend = $vevent->add('DTEND', $event->dtend);
         $dtend['VALUE'] = 'DATE';
     } else {
         $dtend = $vevent->add('DTEND', $event->dtend);
     }
     // auto status for deleted events
     if ($event->is_deleted) {
         $event->status = Calendar_Model_Event::STATUS_CANCELED;
     }
     // event organizer
     if (!empty($event->organizer)) {
         $organizerContact = $event->resolveOrganizer();
         if ($organizerContact instanceof Addressbook_Model_Contact && !empty($organizerContact->email)) {
             $organizer = $vevent->add('ORGANIZER', 'mailto:' . $organizerContact->email, array('CN' => $organizerContact->n_fileas, 'EMAIL' => $organizerContact->email));
         }
     }
     $this->_addEventAttendee($vevent, $event);
     $optionalProperties = array('class', 'status', 'description', 'geo', 'location', 'priority', 'summary', 'transp', 'url');
     foreach ($optionalProperties as $property) {
         if (!empty($event->{$property})) {
             $vevent->add(strtoupper($property), $event->{$property});
         }
     }
     $class = $event->class == Calendar_Model_Event::CLASS_PUBLIC ? 'PUBLIC' : 'CONFIDENTIAL';
     $vcalendar->add('X-CALENDARSERVER-ACCESS', $class);
     $vevent->add('X-CALENDARSERVER-ACCESS', $class);
     // categories
     if (!isset($event->tags)) {
         $event->tags = Tinebase_Tags::getInstance()->getTagsOfRecord($event);
     }
     if (isset($event->tags) && count($event->tags) > 0) {
         $vevent->add('CATEGORIES', (array) $event->tags->name);
     }
     // repeating event properties
     if ($event->rrule) {
         if ($event->is_all_day_event == true) {
             $vevent->add('RRULE', preg_replace_callback('/UNTIL=([\\d :-]{19})(?=;?)/', function ($matches) {
                 $dtUntil = new Tinebase_DateTime($matches[1]);
                 $dtUntil->setTimezone((string) Tinebase_Core::getUserTimezone());
                 return 'UNTIL=' . $dtUntil->format('Ymd');
             }, $event->rrule));
         } else {
             $vevent->add('RRULE', preg_replace('/(UNTIL=)(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})/', '$1$2$3$4T$5$6$7Z', $event->rrule));
         }
         if ($event->exdate instanceof Tinebase_Record_RecordSet) {
             $event->exdate->addIndices(array('is_deleted'));
             $deletedEvents = $event->exdate->filter('is_deleted', true);
             foreach ($deletedEvents as $deletedEvent) {
                 $dateTime = $deletedEvent->getOriginalDtStart();
                 $exdate = $vevent->add('EXDATE');
                 if ($event->is_all_day_event == true) {
                     $dateTime->setTimezone($event->originator_tz);
                     $exdate['VALUE'] = 'DATE';
                 }
                 $exdate->setValue($dateTime);
             }
         }
     }
     $ownAttendee = Calendar_Model_Attender::getOwnAttender($event->attendee);
     if ($event->alarms instanceof Tinebase_Record_RecordSet) {
         $mozLastAck = NULL;
         $mozSnooze = NULL;
         foreach ($event->alarms as $alarm) {
             $valarm = $vcalendar->create('VALARM');
             $valarm->add('ACTION', 'DISPLAY');
             $valarm->add('DESCRIPTION', $event->summary);
             if ($dtack = Calendar_Controller_Alarm::getAcknowledgeTime($alarm)) {
                 $valarm->add('ACKNOWLEDGED', $dtack->getClone()->setTimezone('UTC')->format('Ymd\\THis\\Z'));
                 $mozLastAck = $dtack > $mozLastAck ? $dtack : $mozLastAck;
             }
             if ($dtsnooze = Calendar_Controller_Alarm::getSnoozeTime($alarm)) {
                 $mozSnooze = $dtsnooze > $mozSnooze ? $dtsnooze : $mozSnooze;
             }
             if (is_numeric($alarm->minutes_before)) {
                 if ($event->dtstart == $alarm->alarm_time) {
                     $periodString = 'PT0S';
                 } else {
                     $interval = $event->dtstart->diff($alarm->alarm_time);
                     $periodString = sprintf('%sP%s%s%s%s', $interval->format('%r'), $interval->format('%d') > 0 ? $interval->format('%dD') : null, $interval->format('%h') > 0 || $interval->format('%i') > 0 ? 'T' : null, $interval->format('%h') > 0 ? $interval->format('%hH') : null, $interval->format('%i') > 0 ? $interval->format('%iM') : null);
                 }
                 # TRIGGER;VALUE=DURATION:-PT1H15M
                 $trigger = $valarm->add('TRIGGER', $periodString);
                 $trigger['VALUE'] = "DURATION";
             } else {
                 # TRIGGER;VALUE=DATE-TIME:...
                 $trigger = $valarm->add('TRIGGER', $alarm->alarm_time->getClone()->setTimezone('UTC')->format('Ymd\\THis\\Z'));
                 $trigger['VALUE'] = "DATE-TIME";
             }
             $vevent->add($valarm);
         }
         if ($mozLastAck instanceof DateTime) {
             $vevent->add('X-MOZ-LASTACK', $mozLastAck->getClone()->setTimezone('UTC'), array('VALUE' => 'DATE-TIME'));
         }
         if ($mozSnooze instanceof DateTime) {
             $vevent->add('X-MOZ-SNOOZE-TIME', $mozSnooze->getClone()->setTimezone('UTC'), array('VALUE' => 'DATE-TIME'));
         }
     }
     $baseUrl = Tinebase_Core::getHostname() . "/webdav/Calendar/records/Calendar_Model_Event/{$event->getId()}/";
     if ($event->attachments instanceof Tinebase_Record_RecordSet) {
         foreach ($event->attachments as $attachment) {
             $filename = rawurlencode($attachment->name);
             $attach = $vcalendar->createProperty('ATTACH', "{$baseUrl}{$filename}", array('MANAGED-ID' => $attachment->hash, 'FMTTYPE' => $attachment->contenttype, 'SIZE' => $attachment->size, 'FILENAME' => $filename), 'TEXT');
             $vevent->add($attach);
         }
     }
     $vcalendar->add($vevent);
 }
Exemple #18
0
 /**
  * inspect before create/update
  * 
  * @TODO move stuff from other places here
  * @param   Calendar_Model_Event $_record      the record to inspect
  */
 protected function _inspectEvent($_record)
 {
     $_record->uid = $_record->uid ? $_record->uid : Tinebase_Record_Abstract::generateUID();
     $_record->originator_tz = $_record->originator_tz ? $_record->originator_tz : Tinebase_Core::get(Tinebase_Core::USERTIMEZONE);
     $_record->organizer = $_record->organizer ? $_record->organizer : Tinebase_Core::getUser()->contact_id;
     // external organizer (iTIP)
     if (!$_record->resolveOrganizer()->account_id && count($_record->attendee) > 1) {
         $ownAttendee = Calendar_Model_Attender::getOwnAttender($_record->attendee);
         $_record->attendee = new Tinebase_Record_RecordSet('Calendar_Model_Attender', $ownAttendee ? array($ownAttendee) : array());
     }
     $_record->setRruleUntil();
 }
 public function testMeetingResponseWithNewInstanceId()
 {
     $syncrotonFolder = $this->testCreateFolder();
     list($serverId, $event) = $this->testCreateEntry($syncrotonFolder);
     $controller = Syncroton_Data_Factory::factory($this->_class, $this->_getDevice(Syncroton_Model_Device::TYPE_IPHONE), new Tinebase_DateTime(null, null, 'de_DE'));
     $XMLMeetingResponse = $this->_testXMLMeetingResponse;
     $thisYear = Tinebase_DateTime::now()->format('Y');
     $XMLMeetingResponse = str_replace('2012', $thisYear, $XMLMeetingResponse);
     $XMLMeetingResponse = str_replace('<CollectionId>17</CollectionId>', '<CollectionId>' . $syncrotonFolder->serverId . '</CollectionId>', $XMLMeetingResponse);
     $XMLMeetingResponse = str_replace('<RequestId>f0c79775b6b44be446f91187e24566aa1c5d06ab</RequestId>', '<RequestId>' . $serverId . '</RequestId>', $XMLMeetingResponse);
     $XMLMeetingResponse = str_replace('<InstanceId>20121125T130000Z</InstanceId>', '<InstanceId>20121126T130000Z</InstanceId>', $XMLMeetingResponse);
     $xml = new SimpleXMLElement($XMLMeetingResponse);
     $meetingResponse = new Syncroton_Model_MeetingResponse($xml->Request[0]);
     $eventId = $controller->setAttendeeStatus($meetingResponse);
     $event = Calendar_Controller_MSEventFacade::getInstance()->get($serverId);
     $event->exdate->sort('dtstart', 'DESC');
     $instance = $event->exdate->filter('is_deleted', 0)->getFirstRecord();
     $ownAttendee = Calendar_Model_Attender::getOwnAttender($instance->attendee);
     $this->assertEquals(Calendar_Model_Attender::STATUS_TENTATIVE, $ownAttendee->status);
 }
Exemple #20
0
 /**
  * process request
  * 
  * @param  Calendar_Model_iMIP   $_iMIP
  * @param  string                $_status
  * @throws Tinebase_Exception_NotImplemented
  * 
  * @todo handle external organizers
  * @todo create event in the organizers context
  */
 protected function _processRequest($_iMIP, $_status)
 {
     $existingEvent = $_iMIP->getExistingEvent();
     $ownAttender = Calendar_Model_Attender::getOwnAttender($existingEvent ? $existingEvent->attendee : $_iMIP->getEvent()->attendee);
     $organizer = $existingEvent ? $existingEvent->resolveOrganizer() : $_iMIP->getEvent()->resolveOrganizer();
     // internal organizer:
     //  - event is up to date
     //  - status change could also be done by calendar method
     //  - normal notifications
     if ($organizer->account_id) {
         if (!$existingEvent) {
             // organizer has an account but no event exists, it seems that event was created from a non-caldav client
             // do not send notifications in this case + create event in context of organizer
             return;
             // not clear how to create in the organizers context...
             $sendNotifications = Calendar_Controller_Event::getInstance()->sendNotifications(FALSE);
             $existingEvent = Calendar_Controller_MSEventFacade::getInstance()->create($_iMIP->getEvent());
             Calendar_Controller_Event::getInstance()->sendNotifications($sendNotifications);
         }
         if ($_status && $_status != $ownAttender->status) {
             $ownAttender->status = $_status;
             Calendar_Controller_Event::getInstance()->attenderStatusUpdate($existingEvent, $ownAttender, $ownAttender->status_authkey);
         }
     } else {
         if ($ownAttender && $_status) {
             $ownAttender->status = $_status;
         }
         if (!$existingEvent) {
             $event = $_iMIP->getEvent();
             if (!$event->container_id) {
                 $event->container_id = Tinebase_Core::getPreference('Calendar')->{Calendar_Preference::DEFAULTCALENDAR};
             }
             $_iMIP->event = Calendar_Controller_MSEventFacade::getInstance()->create($event);
         } else {
             $_iMIP->event = Calendar_Controller_MSEventFacade::getInstance()->update($existingEvent);
         }
         //  - send reply to organizer
     }
 }