/** * parse valarm properties * * @param Tinebase_Record_Abstract $record * @param iteratable $valarms * @param \Sabre\VObject\Component $vcalendar */ protected function _parseAlarm(Tinebase_Record_Abstract $record, $valarms, \Sabre\VObject\Component $vcomponent) { foreach ($valarms as $valarm) { if ($valarm->ACTION == 'NONE') { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' We can\'t cope with action NONE: iCal 6.0 sends default alarms in the year 1976 with action NONE. Skipping alarm.'); } continue; } if (!is_object($valarm->TRIGGER)) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Alarm has no TRIGGER value. Skipping it.'); } continue; } # TRIGGER:-PT15M if (is_string($valarm->TRIGGER->getValue()) && $valarm->TRIGGER instanceof Sabre\VObject\Property\ICalendar\Duration) { if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Adding DURATION trigger value for ' . $valarm->TRIGGER->getValue()); } $valarm->TRIGGER->add('VALUE', 'DURATION'); } $trigger = is_object($valarm->TRIGGER['VALUE']) ? $valarm->TRIGGER['VALUE'] : (is_object($valarm->TRIGGER['RELATED']) ? $valarm->TRIGGER['RELATED'] : NULL); if ($trigger === NULL) { // added Trigger/Related for eM Client alarms // 2014-01-03 - Bullshit, why don't we have testdata for emclient alarms? // this alarm handling should be refactored, the logic is scrambled // @see 0006110: handle iMIP messages from outlook // @todo fix 0007446: handle broken alarm in outlook invitation message if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Alarm has no TRIGGER value. Skipping it.'); } continue; } switch (strtoupper($trigger->getValue())) { # TRIGGER;VALUE=DATE-TIME:20111031T130000Z case 'DATE-TIME': $alarmTime = new Tinebase_DateTime($valarm->TRIGGER->getValue()); $alarmTime->setTimezone('UTC'); $alarm = new Tinebase_Model_Alarm(array('alarm_time' => $alarmTime, 'minutes_before' => 'custom', 'model' => $this->_modelName)); break; # TRIGGER;VALUE=DURATION:-PT1H15M # TRIGGER;VALUE=DURATION:-PT1H15M case 'DURATION': default: $durationBaseTime = isset($vcomponent->DTSTART) ? $vcomponent->DTSTART : $vcomponent->DUE; $alarmTime = $this->_convertToTinebaseDateTime($durationBaseTime); $alarmTime->setTimezone('UTC'); preg_match('/(?P<invert>[+-]?)(?P<spec>P.*)/', $valarm->TRIGGER->getValue(), $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' => $this->_modelName)); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' Adding DURATION alarm ' . print_r($alarm->toArray(), true)); } } if ($valarm->ACKNOWLEDGED) { $dtack = $valarm->ACKNOWLEDGED->getDateTime(); Calendar_Controller_Alarm::setAcknowledgeTime($alarm, $dtack); } $record->alarms->addRecord($alarm); } }
/** * send an alarm (to responsible person and if it does not exist, to creator) * * @param Tinebase_Model_Alarm $_alarm * @return void */ public function sendAlarm(Tinebase_Model_Alarm $_alarm) { // save and disable container checks to be able to get all required tasks $oldCheckValue = $this->_doContainerACLChecks; $this->_doContainerACLChecks = FALSE; if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " About to send alarm " . print_r($_alarm->toArray(), TRUE)); } try { $task = $this->get($_alarm->record_id); if ($task->organizer) { $organizerContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId($task->organizer, TRUE); } else { // use creator as organizer $organizerContact = Addressbook_Controller_Contact::getInstance()->getContactByUserId($task->created_by, TRUE); } // create message $translate = Tinebase_Translation::getTranslation($this->_applicationName); $messageSubject = $translate->_('Notification for Task ' . $task->summary); $messageBody = $task->getNotificationMessage(); $notificationsBackend = Tinebase_Notification_Factory::getBackend(Tinebase_Notification_Factory::SMTP); // send message if ($organizerContact->email && !empty($organizerContact->email)) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Trying to send alarm email to ' . $organizerContact->email); } $notificationsBackend->send(NULL, $organizerContact, $messageSubject, $messageBody); } else { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Organizer / creator has no email address.'); } } } catch (Exception $e) { $this->_doContainerACLChecks = $oldCheckValue; throw $e; } }
/** * inspect alarm and set time * * @param Tinebase_Record_Abstract $_record * @param Tinebase_Model_Alarm $_alarm * @return void * @throws Tinebase_Exception_InvalidArgument */ protected function _inspectAlarmSet(Tinebase_Record_Abstract $_record, Tinebase_Model_Alarm $_alarm) { if (!$_record->{$this->_recordAlarmField} instanceof DateTime) { throw new Tinebase_Exception_InvalidArgument('alarm reference time is not set'); } $_alarm->setTime($_record->{$this->_recordAlarmField}); }
/** * converts egw alarms into tine alarms * * @param array $_egwEventData * @return Tinebase_Record_RecordSet of Tinebase_Model_Alarm */ protected function _convertAlarms($_egwEventData) { $alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm'); $select = $this->_egwDb->select()->from(array('alarms' => 'egw_async'))->where($this->_egwDb->quoteInto($this->_egwDb->quoteIdentifier('async_id') . ' LIKE ?', "cal:{$_egwEventData['cal_id']}:%")); $egwAlarms = $this->_egwDb->fetchAll($select, NULL, Zend_Db::FETCH_ASSOC); if (count($egwAlarms) == 0) { return $alarms; } foreach ($egwAlarms as $egwAlarm) { $egwAlarmData = unserialize($egwAlarm['async_data']); $tineAlarm = new Tinebase_Model_Alarm(array('model' => 'Calendar_Model_Event', 'alarm_time' => $this->convertDate($egwAlarmData['time']), 'minutes_before' => $egwAlarmData['offset'] / 60), TRUE); $tineAlarm->sent_status = $tineAlarm->alarm_time->isEarlier($this->_migrationStartTime) ? Tinebase_Model_Alarm::STATUS_SUCCESS : Tinebase_Model_Alarm::STATUS_PENDING; $tineAlarm->setOption('minutes_before', $tineAlarm->minutes_before); $tineAlarm->setOption('custom', false); if (isset($_egwEventData['rrule'])) { $dtstart = $this->convertDate($egwAlarmData['time'] + $egwAlarmData['offset']); $dtstart = $dtstart ? $dtstart : Tinebase_DateTime::now(); $recurId = $_egwEventData['cal_uid'] . '-' . $dtstart->get(Tinebase_Record_Abstract::ISO8601LONG); } $tineAlarm->setOption('recurid', isset($_egwEventData['rrule']) ? $recurId : NULL); $alarms->addRecord($tineAlarm); } return $alarms; }
/** * sets snoozed time in alarm * * @param Tinebase_Model_Alarm $alarm * @param DateTime $time * @param Tinebase_Model_User $user */ public static function setSnoozeTime($alarm, $time, $user = null) { $user = $user instanceof Tinebase_Model_User ?: Tinebase_Core::getUser(); $alarm->setOption("snoozed-{$user->contact_id}", $time->format(Tinebase_Record_Abstract::ISO8601LONG)); }
/** * send an alarm * * @param Tinebase_Model_Alarm $_alarm * @return void * * NOTE: the given alarm is raw and has not passed _inspectAlarmGet * * @todo throw exception on error */ public function sendAlarm(Tinebase_Model_Alarm $_alarm) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " About to send alarm " . print_r($_alarm->toArray(), TRUE)); } $doContainerACLChecks = $this->doContainerACLChecks(FALSE); try { $event = $this->get($_alarm->record_id); $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array($_alarm)); $this->_inspectAlarmGet($event); } catch (Exception $e) { $this->doContainerACLChecks($doContainerACLChecks); throw $e; } $this->doContainerACLChecks($doContainerACLChecks); if ($event->rrule) { $recurid = $_alarm->getOption('recurid'); // adopts the (referenced) alarm and sets alarm time to next occurance parent::_inspectAlarmSet($event, $_alarm); $this->adoptAlarmTime($event, $_alarm, 'instance'); // sent_status might have changed in adoptAlarmTime() if ($_alarm->sent_status !== Tinebase_Model_Alarm::STATUS_PENDING) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Not sending alarm for event at ' . $event->dtstart->toString() . ' with status ' . $_alarm->sent_status); } return; } if ($recurid) { // NOTE: In case of recuring events $event is always the baseEvent, // so we might need to adopt event time to recur instance. $diff = $event->dtstart->diff($event->dtend); $event->dtstart = new Tinebase_DateTime(substr($recurid, -19)); $event->dtend = clone $event->dtstart; $event->dtend->add($diff); } if ($event->exdate && in_array($event->dtstart, $event->exdate)) { if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Not sending alarm because instance at " . $event->dtstart->toString() . ' is an exception.'); } return; } } Calendar_Controller_EventNotifications::getInstance()->doSendNotifications($event, Tinebase_Core::getUser(), 'alarm', NULL, $_alarm); }
/** * checks if given alarm should be send to given attendee * * @param Calendar_Model_Attender $_attendee * @param Tinebase_Model_Alarm $_alarm * @return bool */ public static function isAlarmForAttendee($_attendee, $_alarm, $_event = NULL) { // attendee: array with one user_type/id if alarm is for one attendee only $attendeeOption = $_alarm->getOption('attendee'); // skip: array of array of user_type/id with attendees this alarm is to skip for $skipOption = $_alarm->getOption('skip'); if ($attendeeOption) { return (bool) self::getAttendee(new Tinebase_Record_RecordSet('Calendar_Model_Attender', array($_attendee)), new Calendar_Model_Attender($attendeeOption)); } if (is_array($skipOption)) { $skipAttendees = new Tinebase_Record_RecordSet('Calendar_Model_Attender', $skipOption); if (self::getAttendee($skipAttendees, $_attendee)) { return false; } } $isOrganizerCondition = $_event ? $_event->isOrganizer($_attendee) : TRUE; $isAttendeeCondition = $_event && $_event->attendee instanceof Tinebase_Record_RecordSet ? self::getAttendee($_event->attendee, $_attendee) : TRUE; return ($isAttendeeCondition || $isOrganizerCondition) && $_attendee->status != Calendar_Model_Attender::STATUS_DECLINED; }
/** * send an alarm * * @param Tinebase_Model_Alarm $_alarm * @return void * * NOTE: the given alarm is raw and has not passed _inspectAlarmGet * * @todo make this working with recuring events * @todo throw exception on error */ public function sendAlarm(Tinebase_Model_Alarm $_alarm) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " About to send alarm " . print_r($_alarm->toArray(), TRUE)); } $doContainerACLChecks = $this->doContainerACLChecks(FALSE); $event = $this->get($_alarm->record_id); $event->alarms = new Tinebase_Record_RecordSet('Tinebase_Model_Alarm', array($_alarm)); $this->_inspectAlarmGet($event); if ($event->rrule) { $recurid = $_alarm->getOption('recurid'); // adopts the (referenced) alarm and sets alarm time to next occurance parent::_inspectAlarmSet($event, $_alarm); $this->adoptAlarmTime($event, $_alarm, 'instance'); if ($recurid) { // NOTE: In case of recuring events $event is always the baseEvent, // so we might need to adopt event time to recur instance. $diff = $event->dtstart->diff($event->dtend); $event->dtstart = new Tinebase_DateTime(substr($recurid, -19)); $event->dtend = clone $event->dtstart; $event->dtend->add($diff); } } $this->doContainerACLChecks($doContainerACLChecks); $this->doSendNotifications($event, $this->_currentAccount, 'alarm'); }