/** * Sends one or more iTip messages through email. * * @param string $originator * @param array $recipients * @param Sabre_VObject_Component $vObject * @return void */ public function sendMessage($originator, array $recipients, Sabre_VObject_Component $vObject) { foreach ($recipients as $recipient) { $to = $recipient; $replyTo = $originator; $subject = 'SabreDAV iTIP message'; switch (strtoupper($vObject->METHOD)) { case 'REPLY': $subject = 'Response for: ' . $vObject->VEVENT->SUMMARY; break; case 'REQUEST': $subject = 'Invitation for: ' . $vObject->VEVENT->SUMMARY; break; case 'CANCEL': $subject = 'Cancelled event: ' . $vObject->VEVENT->SUMMARY; break; } $headers = array(); $headers[] = 'Reply-To: ' . $replyTo; $headers[] = 'From: ' . $this->senderEmail; $headers[] = 'Content-Type: text/calendar; method=' . (string) $vObject->method . '; charset=utf-8'; $headers[] = 'X-Sabre-Version: ' . Sabre_DAV_Version::VERSION . '-' . Sabre_DAV_Version::STABILITY; $vcalBody = $vObject->serialize(); $this->mail($to, $subject, $vcalBody, $headers); } }
function testStuff() { $vcard = new Sabre_VObject_Component('VCARD'); $vcard->VERSION = '3.0'; $vcard->UID = 'foo-bar'; $vcard->PHOTO = base64_encode('random_stuff'); $vcard->PHOTO->add('BASE64', null); $result = $vcard->serialize(); $expected = array("BEGIN:VCARD", "VERSION:3.0", "PHOTO;BASE64:" . base64_encode('random_stuff'), "UID:foo-bar", "END:VCARD", ""); $this->assertEquals(implode("\r\n", $expected), $result); }
/** * Reads and parses a single line. * * This method receives the full array of lines. The array pointer is used * to traverse. * * @param array $lines * @return Sabre_VObject_Element */ private static function readLine(&$lines) { $line = current($lines); $lineNr = key($lines); next($lines); // Components if (stripos($line, "BEGIN:") === 0) { // This is a component $obj = new Sabre_VObject_Component(strtoupper(substr($line, 6))); $nextLine = current($lines); while (stripos($nextLine, "END:") !== 0) { $obj->add(self::readLine($lines)); $nextLine = current($lines); if ($nextLine === false) { throw new Sabre_VObject_ParseException('Invalid VObject. Document ended prematurely.'); } } // Checking component name of the 'END:' line. if (substr($nextLine, 4) !== $obj->name) { throw new Sabre_VObject_ParseException('Invalid VObject, expected: "END:' . $obj->name . '" got: "' . $nextLine . '"'); } next($lines); return $obj; } // Properties //$result = preg_match('/(?P<name>[A-Z0-9-]+)(?:;(?P<parameters>^(?<!:):))(.*)$/',$line,$matches); $token = '[A-Z0-9-\\.]+'; $parameters = "(?:;(?P<parameters>([^:^\"]|\"([^\"]*)\")*))?"; $regex = "/^(?P<name>{$token}){$parameters}:(?P<value>.*)\$/i"; $result = preg_match($regex, $line, $matches); if (!$result) { throw new Sabre_VObject_ParseException('Invalid VObject, line ' . ($lineNr + 1) . ' did not follow the icalendar/vcard format'); } $propertyName = strtoupper($matches['name']); if (strpos($propertyName, '.') !== false) { list(, $mapName) = explode('.', $propertyName); } else { $mapName = $propertyName; } if (isset(self::$elementMap[$mapName])) { $className = self::$elementMap[$mapName]; } else { $className = 'Sabre_VObject_Property'; } $propertyValue = $className::stripSlashes($matches['value']); $obj = new $className($propertyName, $propertyValue); if ($matches['parameters']) { foreach (self::readParameters($matches['parameters']) as $param) { $obj->add($param); } } return $obj; }
/** * Different bug, also likely an infinite loop. */ function testYearlyByMonthLoop() { $ev = Sabre_VObject_Component::create('VEVENT'); $ev->UID = 'uuid'; $ev->DTSTART = '20120101T154500'; $ev->DTSTART['TZID'] = 'Europe/Berlin'; $ev->RRULE = 'FREQ=YEARLY;INTERVAL=1;UNTIL=20120203T225959Z;BYMONTH=2;BYSETPOS=1;BYDAY=SU,MO,TU,WE,TH,FR,SA'; $ev->DTEND = '20120101T164500'; $ev->DTEND['TZID'] = 'Europe/Berlin'; // This recurrence rule by itself is a yearly rule that should happen // every february. // // The BYDAY part expands this to every day of the month, but the // BYSETPOS limits this to only the 1st day of the month. Very crazy // way to specify this, and could have certainly been a lot easier. $cal = Sabre_VObject_Component::create('VCALENDAR'); $cal->add($ev); $it = new Sabre_VObject_RecurrenceIterator($cal, 'uuid'); $it->fastForward(new DateTime('2012-01-29 23:00:00', new DateTimeZone('UTC'))); $collect = array(); while ($it->valid()) { $collect[] = $it->getDTSTART(); if ($it->getDTSTART() > new DateTime('2013-02-05 22:59:59', new DateTimeZone('UTC'))) { break; } $it->next(); } $this->assertEquals(array(new DateTime('2012-02-01 15:45:00', new DateTimeZone('Europe/Berlin'))), $collect); }
function testAlarmWayBefore() { $vevent = Sabre_VObject_Component::create('VEVENT'); $vevent->DTSTART = '20120101T120000Z'; $vevent->UID = 'bla'; $valarm = Sabre_VObject_Component::create('VALARM'); $valarm->TRIGGER = '-P2W1D'; $vevent->add($valarm); $vcalendar = Sabre_VObject_Component::create('VCALENDAR'); $vcalendar->add($vevent); $filter = array('name' => 'VCALENDAR', 'is-not-defined' => false, 'time-range' => null, 'prop-filters' => array(), 'comp-filters' => array(array('name' => 'VEVENT', 'is-not-defined' => false, 'time-range' => null, 'prop-filters' => array(), 'comp-filters' => array(array('name' => 'VALARM', 'is-not-defined' => false, 'prop-filters' => array(), 'comp-filters' => array(), 'time-range' => array('start' => new DateTime('2011-12-10'), 'end' => new DateTime('2011-12-20'))))))); $validator = new Sabre_CalDAV_CalendarQueryValidator(); $this->assertTrue($validator->validate($vcalendar, $filter)); }
/** * Reads and parses a single line. * * This method receives the full array of lines. The array pointer is used * to traverse. * * @param array $lines * @return Sabre_VObject_Element */ private static function readLine(&$lines) { $line = current($lines); $lineNr = key($lines); next($lines); // Components if (stripos($line, "BEGIN:") === 0) { $componentName = strtoupper(substr($line, 6)); $obj = Sabre_VObject_Component::create($componentName); $nextLine = current($lines); while (stripos($nextLine, "END:") !== 0) { $obj->add(self::readLine($lines)); $nextLine = current($lines); if ($nextLine === false) { throw new Sabre_VObject_ParseException('Invalid VObject. Document ended prematurely.'); } } // Checking component name of the 'END:' line. if (substr($nextLine, 4) !== $obj->name) { throw new Sabre_VObject_ParseException('Invalid VObject, expected: "END:' . $obj->name . '" got: "' . $nextLine . '"'); } next($lines); return $obj; } // Properties //$result = preg_match('/(?P<name>[A-Z0-9-]+)(?:;(?P<parameters>^(?<!:):))(.*)$/',$line,$matches); $token = '[A-Z0-9-\\.]+'; $parameters = "(?:;(?P<parameters>([^:^\"]|\"([^\"]*)\")*))?"; $regex = "/^(?P<name>{$token}){$parameters}:(?P<value>.*)\$/i"; $result = preg_match($regex, $line, $matches); if (!$result) { throw new Sabre_VObject_ParseException('Invalid VObject, line ' . ($lineNr + 1) . ' did not follow the icalendar/vcard format'); } $propertyName = strtoupper($matches['name']); $propertyValue = preg_replace_callback('#(\\\\(\\\\|N|n|;|,))#', function ($matches) { if ($matches[2] === 'n' || $matches[2] === 'N') { return "\n"; } else { return $matches[2]; } }, $matches['value']); $obj = Sabre_VObject_Property::create($propertyName, $propertyValue); if ($matches['parameters']) { foreach (self::readParameters($matches['parameters']) as $param) { $obj->add($param); } } return $obj; }
/** * Merges all calendar objects, and builds one big ics export * * @param array $nodes * @return string */ public function generateICS(array $nodes) { $calendar = new Sabre_VObject_Component('vcalendar'); $calendar->version = '2.0'; if (Sabre_DAV_Server::$exposeVersion) { $calendar->prodid = '-//SabreDAV//SabreDAV ' . Sabre_DAV_Version::VERSION . '//EN'; } else { $calendar->prodid = '-//SabreDAV//SabreDAV//EN'; } $calendar->calscale = 'GREGORIAN'; $collectedTimezones = array(); $timezones = array(); $objects = array(); foreach ($nodes as $node) { if (!isset($node[200]['{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data'])) { continue; } $nodeData = $node[200]['{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data']; $nodeComp = Sabre_VObject_Reader::read($nodeData); foreach ($nodeComp->children() as $child) { switch ($child->name) { case 'VEVENT': case 'VTODO': case 'VJOURNAL': $objects[] = $child; break; // VTIMEZONE is special, because we need to filter out the duplicates // VTIMEZONE is special, because we need to filter out the duplicates case 'VTIMEZONE': // Naively just checking tzid. if (in_array((string) $child->TZID, $collectedTimezones)) { continue; } $timezones[] = $child; $collectedTimezones[] = $child->TZID; break; } } } foreach ($timezones as $tz) { $calendar->add($tz); } foreach ($objects as $obj) { $calendar->add($obj); } return $calendar->serialize(); }
public function timeRangeTestData() { $tests = array(); $vjournal = Sabre_VObject_Component::create('VJOURNAL'); $vjournal->DTSTART = '20111223T120000Z'; $tests[] = array($vjournal, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vjournal, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vjournal2 = Sabre_VObject_Component::create('VJOURNAL'); $vjournal2->DTSTART = '20111223'; $vjournal2->DTSTART['VALUE'] = 'DATE'; $tests[] = array($vjournal2, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vjournal2, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vjournal3 = Sabre_VObject_Component::create('VJOURNAL'); $tests[] = array($vjournal3, new DateTime('2011-01-01'), new DateTime('2012-01-01'), false); $tests[] = array($vjournal3, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); return $tests; }
public function timeRangeTestData() { $tests = array(); $vtodo = Sabre_VObject_Component::create('VTODO'); $vtodo->DTSTART = '20111223T120000Z'; $tests[] = array($vtodo, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vtodo, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vtodo2 = clone $vtodo; $vtodo2->DURATION = 'P1D'; $tests[] = array($vtodo2, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vtodo2, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vtodo3 = clone $vtodo; $vtodo3->DUE = '20111225'; $tests[] = array($vtodo3, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vtodo3, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vtodo4 = Sabre_VObject_Component::create('VTODO'); $vtodo4->DUE = '20111225'; $tests[] = array($vtodo4, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vtodo4, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vtodo5 = Sabre_VObject_Component::create('VTODO'); $vtodo5->COMPLETED = '20111225'; $tests[] = array($vtodo5, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vtodo5, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vtodo6 = Sabre_VObject_Component::create('VTODO'); $vtodo6->CREATED = '20111225'; $tests[] = array($vtodo6, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vtodo6, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vtodo7 = Sabre_VObject_Component::create('VTODO'); $vtodo7->CREATED = '20111225'; $vtodo7->COMPLETED = '20111226'; $tests[] = array($vtodo7, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vtodo7, new DateTime('2011-01-01'), new DateTime('2011-11-01'), false); $vtodo7 = Sabre_VObject_Component::create('VTODO'); $tests[] = array($vtodo7, new DateTime('2011-01-01'), new DateTime('2012-01-01'), true); $tests[] = array($vtodo7, new DateTime('2011-01-01'), new DateTime('2011-11-01'), true); return $tests; }
/** * Creates the iterator * * You should pass a VCALENDAR component, as well as the UID of the event * we're going to traverse. * * @param Sabre_VObject_Component $comp */ public function __construct(Sabre_VObject_Component $vcal, $uid = null) { if (is_null($uid)) { if ($vcal->name === 'VCALENDAR') { throw new InvalidArgumentException('If you pass a VCALENDAR object, you must pass a uid argument as well'); } $components = array($vcal); $uid = (string) $vcal->uid; } else { $components = $vcal->select('VEVENT'); } foreach ($components as $component) { if ((string) $component->uid == $uid) { if (isset($component->{'RECURRENCE-ID'})) { $this->overriddenEvents[$component->DTSTART->getDateTime()->getTimeStamp()] = $component; $this->overriddenDates[] = $component->{'RECURRENCE-ID'}->getDateTime(); } else { $this->baseEvent = $component; } } } if (!$this->baseEvent) { throw new InvalidArgumentException('Could not find a base event with uid: ' . $uid); } $this->startDate = clone $this->baseEvent->DTSTART->getDateTime(); $this->endDate = null; if (isset($this->baseEvent->DTEND)) { $this->endDate = clone $this->baseEvent->DTEND->getDateTime(); } else { $this->endDate = clone $this->startDate; if (isset($this->baseEvent->DURATION)) { $this->endDate->add(Sabre_VObject_DateTimeParser::parse($this->baseEvent->DURATION->value)); } } $this->currentDate = clone $this->startDate; $rrule = (string) $this->baseEvent->RRULE; $parts = explode(';', $rrule); foreach ($parts as $part) { list($key, $value) = explode('=', $part, 2); switch (strtoupper($key)) { case 'FREQ': if (!in_array(strtolower($value), array('secondly', 'minutely', 'hourly', 'daily', 'weekly', 'monthly', 'yearly'))) { throw new InvalidArgumentException('Unknown value for FREQ=' . strtoupper($value)); } $this->frequency = strtolower($value); break; case 'UNTIL': $this->until = Sabre_VObject_DateTimeParser::parse($value); break; case 'COUNT': $this->count = (int) $value; break; case 'INTERVAL': $this->interval = (int) $value; break; case 'BYSECOND': $this->bySecond = explode(',', $value); break; case 'BYMINUTE': $this->byMinute = explode(',', $value); break; case 'BYHOUR': $this->byHour = explode(',', $value); break; case 'BYDAY': $this->byDay = explode(',', strtoupper($value)); break; case 'BYMONTHDAY': $this->byMonthDay = explode(',', $value); break; case 'BYYEARDAY': $this->byYearDay = explode(',', $value); break; case 'BYWEEKNO': $this->byWeekNo = explode(',', $value); break; case 'BYMONTH': $this->byMonth = explode(',', $value); break; case 'BYSETPOS': $this->bySetPos = explode(',', $value); break; case 'WKST': $this->weekStart = strtoupper($value); break; } } // Parsing exception dates if (isset($this->baseEvent->EXDATE)) { foreach ($this->baseEvent->EXDATE as $exDate) { foreach (explode(',', (string) $exDate) as $exceptionDate) { $this->exceptionDates[] = Sabre_VObject_DateTimeParser::parse($exceptionDate, $this->startDate->getTimeZone()); } } } }
/** * Parses the input data and returns a correct VFREEBUSY object, wrapped in * a VCALENDAR. * * @return Sabre_VObject_Component */ public function getResult() { $busyTimes = array(); foreach ($this->objects as $object) { foreach ($object->getBaseComponents() as $component) { switch ($component->name) { case 'VEVENT': $FBTYPE = 'BUSY'; if (isset($component->TRANSP) && strtoupper($component->TRANSP) === 'TRANSPARENT') { break; } if (isset($component->STATUS)) { $status = strtoupper($component->STATUS); if ($status === 'CANCELLED') { break; } if ($status === 'TENTATIVE') { $FBTYPE = 'BUSY-TENTATIVE'; } } $times = array(); if ($component->RRULE) { $iterator = new Sabre_VObject_RecurrenceIterator($object, (string) $component->uid); if ($this->start) { $iterator->fastForward($this->start); } $maxRecurrences = 200; while ($iterator->valid() && --$maxRecurrences) { $startTime = $iterator->getDTStart(); if ($this->end && $startTime > $this->end) { break; } $times[] = array($iterator->getDTStart(), $iterator->getDTEnd()); $iterator->next(); } } else { $startTime = $component->DTSTART->getDateTime(); if ($this->end && $startTime > $this->end) { break; } $endTime = null; if (isset($component->DTEND)) { $endTime = $component->DTEND->getDateTime(); } elseif (isset($component->DURATION)) { $duration = Sabre_VObject_DateTimeParser::parseDuration((string) $component->DURATION); $endTime = clone $startTime; $endTime->add($duration); } elseif ($component->DTSTART->getDateType() === Sabre_VObject_Property_DateTime::DATE) { $endTime = clone $startTime; $endTime->modify('+1 day'); } else { // The event had no duration (0 seconds) break; } $times[] = array($startTime, $endTime); } foreach ($times as $time) { if ($this->end && $time[0] > $this->end) { break; } if ($this->start && $time[1] < $this->start) { break; } $busyTimes[] = array($time[0], $time[1], $FBTYPE); } break; case 'VFREEBUSY': foreach ($component->FREEBUSY as $freebusy) { $fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY'; // Skipping intervals marked as 'free' if ($fbType === 'FREE') { continue; } $values = explode(',', $freebusy); foreach ($values as $value) { list($startTime, $endTime) = explode('/', $value); $startTime = Sabre_VObject_DateTimeParser::parseDateTime($startTime); if (substr($endTime, 0, 1) === 'P' || substr($endTime, 0, 2) === '-P') { $duration = Sabre_VObject_DateTimeParser::parseDuration($endTime); $endTime = clone $startTime; $endTime->add($duration); } else { $endTime = Sabre_VObject_DateTimeParser::parseDateTime($endTime); } if ($this->start && $this->start > $endTime) { continue; } if ($this->end && $this->end < $startTime) { continue; } $busyTimes[] = array($startTime, $endTime, $fbType); } } break; } } } if ($this->baseObject) { $calendar = $this->baseObject; } else { $calendar = new Sabre_VObject_Component('VCALENDAR'); $calendar->version = '2.0'; $calendar->prodid = '-//SabreDAV//Sabre VObject ' . Sabre_VObject_Version::VERSION . '//EN'; $calendar->calscale = 'GREGORIAN'; } $vfreebusy = new Sabre_VObject_Component('VFREEBUSY'); $calendar->add($vfreebusy); if ($this->start) { $dtstart = new Sabre_VObject_Property_DateTime('DTSTART'); $dtstart->setDateTime($this->start, Sabre_VObject_Property_DateTime::UTC); $vfreebusy->add($dtstart); } if ($this->end) { $dtend = new Sabre_VObject_Property_DateTime('DTEND'); $dtend->setDateTime($this->start, Sabre_VObject_Property_DateTime::UTC); $vfreebusy->add($dtend); } $dtstamp = new Sabre_VObject_Property_DateTime('DTSTAMP'); $dtstamp->setDateTime(new DateTime('now'), Sabre_VObject_Property_DateTime::UTC); $vfreebusy->add($dtstamp); foreach ($busyTimes as $busyTime) { $busyTime[0]->setTimeZone(new DateTimeZone('UTC')); $busyTime[1]->setTimeZone(new DateTimeZone('UTC')); $prop = new Sabre_VObject_Property('FREEBUSY', $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')); $prop['FBTYPE'] = $busyTime[2]; $vfreebusy->add($prop); } return $calendar; }
/** * Returns a Sabre_Vobject_Component representing this object. * * @param subevents All events with the uid of this one. If not given, these will be fetched from the database. * * @return Sabre_VObject_Component representing $this. */ public function asVObject($subevents = null) { $vobject = new Sabre_VObject_Component('vevent'); if ($this->summary) { $vobject->add('summary', $this->summary); } if ($this->description) { $vobject->add('description', $this->description); } if ($this->comments) { $vobject->add('comment', $this->comments); } if ($this->location) { $vobject->add('location', $this->location); } if ($this->recurrenceId) { $recurrenceId = new Datetime($this->recurrenceId); $vobject->add('recurrence-id', $recurrenceId->format('Ymd\\THis\\Z')); } else { if ($this->rrule) { $vobject->add('rrule', $this->rrule); $exdates = array(); foreach ($this->getExcludedDates() as $d) { $exdates[] = $d->format('Ymd\\THis\\Z'); } if (!empty($exdates)) { // The problem here ist that if we change a single occurrence of an recurring event in P6, we mark the // occurrence as excluded in the original event. In caldav, the exclusion takes precedence over the // extracted event, which means that events that have been changed will not show up in caldav clients. // To go around this, we filter these dates out of the excluded dates. if (is_null($subevents)) { $subevents = $this->fetchByUid($this->uid); } $subeventDates = array(); foreach ($subevents as $e) { if ($e->recurrenceId) { $dt = new Datetime($e->recurrenceId); $subeventDates[] = $dt->format('Ymd\\THis\\Z'); } } $exdates = array_diff($exdates, $subeventDates); $vobject->add('exdate', implode(',', $exdates)); } } } $start = new Datetime('@' . Phprojekt_Converter_Time::userToUtc($this->start)); $vobject->add('dtstart', $start->format('Ymd\\THis\\Z')); $end = new Datetime('@' . Phprojekt_Converter_Time::userToUtc($this->end)); $vobject->add('dtend', $end->format('Ymd\\THis\\Z')); $lastMod = new DateTime($this->lastModified); $vobject->add('dtstamp', $lastMod->format('Ymd\\THis\\Z')); $vobject->add('uid', $this->uid); return $vobject; }
/** * As defined in Sabre_CalDAV_Backend_Abstract * * Retrieves a single Calendar object. * * @param string $calendarId The id of the calendar. Corresponds to the id of the user it belongs to. * @param string $objectUri The uri of the calendarobject to retrieve. * * @return array As specified by SabreDAV. */ public function getCalendarObject($calendarId, $objectUri) { $db = Phprojekt::getInstance()->getDb(); $events = new Calendar2_Models_Calendar2(); $events = $events->fetchAll($db->quoteInto('uri = ?', $objectUri)); if (!is_array($events) || empty($events)) { return array(); } $calendarData = new Sabre_VObject_Component('vcalendar'); $calendarData->add('version', '2.0'); $calendarData->add('prodid', 'Phprojekt ' . Phprojekt::getVersion()); $lastModified = $events[0]->lastModified; foreach ($events as $e) { $calendarData->add($e->asVObject($events)); $lastModified = max($lastModified, $e->lastModified); } $lastModified = new Datetime($lastModified); return array('id' => $events[0]->uid, 'uri' => $objectUri, 'lastmodified' => $lastModified->format('Ymd\\THis\\Z'), 'calendarid' => $calendarId, 'calendardata' => $calendarData->serialize()); }
public static function createVCalendarFromRequest($request) { $vcalendar = new Sabre_VObject_Component('VCALENDAR'); $vcalendar->add('PRODID', 'ownCloud Calendar'); $vcalendar->add('VERSION', '2.0'); $now = new DateTime(); $vevent = new Sabre_VObject_Component('VEVENT'); $vcalendar->add($vevent); $created = new Sabre_VObject_Element_DateTime('CREATED'); $created->setDateTime($now, Sabre_VObject_Element_DateTime::UTC); $vevent->add($created); $uid = self::createUID(); $vevent->add('UID', $uid); return self::updateVCalendarFromRequest($request, $vcalendar); }
/** * @expectedException Sabre_DAV_Exception */ public function testInTimeRangeInvalidComponent() { $valarm = Sabre_VObject_Component::create('VALARM'); $valarm->TRIGGER = '-P1D'; $valarm->TRIGGER['RELATED'] = 'END'; $vjournal = Sabre_VObject_Component::create('VJOURNAL'); $vjournal->add($valarm); $valarm->isInTimeRange(new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00')); }
require_once '../../../lib/base.php'; $aid = $_POST['id']; $l10n = new OC_L10N('contacts'); // Check if we are a user OC_JSON::checkLoggedIn(); OC_JSON::checkAppEnabled('contacts'); $addressbook = OC_Contacts_Addressbook::find($aid); if ($addressbook === false || $addressbook['userid'] != OC_USER::getUser()) { OC_JSON::error(array('data' => array('message' => $l10n->t('This is not your addressbook.')))); // Same here (as with the contact error). Could this error be improved? exit; } $fn = $_POST['fn']; $values = $_POST['value']; $parameters = $_POST['parameters']; $vcard = new Sabre_VObject_Component('VCARD'); $vcard->add(new Sabre_VObject_Property('FN', $fn)); $vcard->add(new Sabre_VObject_Property('UID', OC_Contacts_VCard::createUID())); foreach (array('ADR', 'TEL', 'EMAIL', 'ORG') as $propname) { $value = $values[$propname]; if (isset($parameters[$propname])) { $prop_parameters = $parameters[$propname]; } else { $prop_parameters = array(); } OC_Contacts_VCard::addVCardProperty($vcard, $propname, $value, $prop_parameters); } $id = OC_Contacts_VCard::add($aid, $vcard->serialize()); $details = OC_Contacts_VCard::structureContact($vcard); $name = $details['FN'][0]['value']; $tmpl = new OC_Template('contacts', 'part.details');
public function __isset($name) { return $this->vobject->__isset($name); }
function testGetDateTimeBadTimeZone() { $default = date_default_timezone_get(); date_default_timezone_set('Canada/Eastern'); $elem = new Sabre_VObject_Element_DateTime('DTSTART', '19850704T013000'); $elem['TZID'] = 'Moon'; $event = new Sabre_VObject_Component('VEVENT'); $event->add($elem); $timezone = new Sabre_VObject_Component('VTIMEZONE'); $timezone->TZID = 'Moon'; $timezone->{'X-LIC-LOCATION'} = 'Moon'; $calendar = new Sabre_VObject_Component('VCALENDAR'); $calendar->add($event); $calendar->add($timezone); $dt = $elem->getDateTime(); $this->assertInstanceOf('DateTime', $dt); $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); $this->assertEquals('Canada/Eastern', $dt->getTimeZone()->getName()); $this->assertEquals(Sabre_VObject_Element_DateTime::LOCALTZ, $elem->getDateType()); date_default_timezone_set($default); }
function testSerializeChildren() { $comp = new Sabre_VObject_Component('VCALENDAR'); $comp->children = array(new Sabre_VObject_Component('VEVENT'), new Sabre_VObject_Component('VTODO')); $this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n", $comp->serialize()); }
/** * Returns free-busy information for a specific address. The returned * data is an array containing the following properties: * * calendar-data : A VFREEBUSY VObject * request-status : an iTip status code. * href: The principal's email address, as requested * * The following request status codes may be returned: * * 2.0;description * * 3.7;description * * @param string $email address * @param DateTime $start * @param DateTime $end * @param Sabre_VObject_Component $request * @return Sabre_VObject_Component */ protected function getFreeBusyForEmailTine20($email, DateTime $start, DateTime $end, Sabre_VObject_Component $request) { if (substr($email, 0, 7) === 'mailto:') { $email = substr($email, 7); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' serach freebusy of ' . $email); } // resolve email address to contact $filter = new Addressbook_Model_ContactFilter(array(array('field' => 'containerType', 'operator' => 'equals', 'value' => 'all'), array('field' => 'type', 'operator' => 'equals', 'value' => Addressbook_Model_Contact::CONTACTTYPE_USER), array('field' => 'email', 'operator' => 'equals', 'value' => $email))); $contact = Addressbook_Controller_Contact::getInstance()->search($filter)->getFirstRecord(); if ($contact === null) { return array('request-status' => '3.7;Could not find principal', 'href' => 'mailto:' . $email); } $period = array(array('from' => new Tinebase_DateTime($start->format(Tinebase_Record_Abstract::ISO8601LONG), 'UTC'), 'until' => new Tinebase_DateTime($end->format(Tinebase_Record_Abstract::ISO8601LONG), 'UTC'))); $attendees = new Tinebase_Record_RecordSet('Calendar_Model_Attender', array(new Calendar_Model_Attender(array('user_id' => $contact->getId(), 'user_type' => Calendar_Model_Attender::USERTYPE_USER)))); $freeBusyInfo = Calendar_Controller_Event::getInstance()->getFreeBusyInfo($period, $attendees); $vcalendar = new Sabre_VObject_Component('VCALENDAR'); $vcalendar->VERSION = '2.0'; $vcalendar->METHOD = 'REPLY'; $vcalendar->CALSCALE = 'GREGORIAN'; $vcalendar->PRODID = '-//SabreDAV//SabreDAV ' . Sabre_DAV_Version::VERSION . '//EN'; $vfreebusy = new Sabre_VObject_Component('VFREEBUSY'); $vcalendar->add($vfreebusy); $vfreebusy->DTSTAMP = $request->VFREEBUSY->dtstart->value; $vfreebusy->DTSTART = $request->VFREEBUSY->dtstart->value; $vfreebusy->DTEND = $request->VFREEBUSY->dtend->value; #$attendee = new Sabre_VObject_Property('ATTENDEE', 'mailto:' . $contact->email); #$attendee->add('CN', $contact->n_fileas); #$vfreebusy->add($attendee); foreach ($freeBusyInfo as $busyInfo) { $busy = $busyInfo->dtstart->format('Ymd\\THis\\Z') . '/' . $busyInfo->dtend->format('Ymd\\THis\\Z'); $freebusy = new Sabre_VObject_Property('FREEBUSY', $busy); $freebusy->add('FBTYPE', 'BUSY'); $vfreebusy->add($freebusy); } $vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email; $vcalendar->VFREEBUSY->UID = (string) $request->VFREEBUSY->UID; return array('calendar-data' => $vcalendar, 'request-status' => '2.0;Success', 'href' => 'mailto:' . $email); }
protected function _getCalendarVTimezone() { $timezone = Tinebase_Core::getPreference()->getValueForUser(Tinebase_Preference::TIMEZONE, Tinebase_Core::getUser()->getId()); // create vcalendar object with timezone information $vcalendar = new Sabre_VObject_Component('CALENDAR'); $vcalendar->add(new Sabre_VObject_Component_VTimezone($timezone)); // Taking out \r to not screw up the xml output return str_replace("\r", "", $vcalendar->serialize()); }
/** * Converts a timecard join project join module row to a vobject string. * * @param array $entry * * @return string */ private function _getDataForEntry(array $entry) { $v = new Sabre_VObject_Component('vevent'); if (1 == $entry['project_id']) { $v->add('summary', Phprojekt::getInstance()->translate('Unassigned')); } else { $v->add('summary', $entry['title'] . ' [' . $entry['project_id'] . ']'); } $notes = trim($entry['notes']); if (!is_null($entry['module_id'])) { if ($notes) { $notes .= "\n"; } $notes .= Phprojekt::getInstance()->translate('There is an attachment of type ') . Phprojekt::getInstance()->translate($entry['label']); } if ($notes) { $v->add('description', $notes); } $start = new DateTime('@' . Phprojekt_Converter_Time::userToUtc($entry['start_datetime'])); $end = substr($entry['start_datetime'], 0, 11) . $entry['end_time']; $end = new DateTime('@' . Phprojekt_Converter_Time::userToUtc($end)); $v->add('dtstart', $start->format('Ymd\\THis\\Z')); $v->add('dtend', $end->format('Ymd\\THis\\Z')); $v->add('uid', 'phprojekt-timecard-entry' . $entry['uid']); $calendarData = new Sabre_VObject_Component('vcalendar'); $calendarData->add('version', '2.0'); $calendarData->add('prodid', 'Phprojekt ' . Phprojekt::getVersion()); $calendarData->add($v); return $calendarData->serialize(); }
function testSerializeOrder() { $comp = new Sabre_VObject_Component('VCALENDAR'); $comp->add(new Sabre_VObject_Component('VEVENT')); $comp->add('PROP1', 'BLABLA'); $comp->add('VERSION', '2.0'); $comp->add(new Sabre_VObject_Component('VTIMEZONE')); $str = $comp->serialize(); $this->assertEquals("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPROP1:BLABLA\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", $str); }
/** * 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'); }
/** * converts Addressbook_Model_Contact to vcard * * @param Addressbook_Model_Contact $_record * @return string */ public function fromTine20Model(Tinebase_Record_Abstract $_record) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' contact ' . print_r($_record->toArray(), true)); } $card = new Sabre_VObject_Component('VCARD'); // required vcard fields $card->add(new Sabre_VObject_Property('VERSION', '3.0')); $card->add(new Sabre_VObject_Property('FN', $_record->n_fileas)); $card->add(new Sabre_VObject_Element_MultiValue('N', array($_record->n_family, $_record->n_given))); $card->add(new Sabre_VObject_Property('PRODID', '-//tine20.org//Tine 2.0//EN')); $card->add(new Sabre_VObject_Property('UID', $_record->getId())); // optional fields $card->add(new Sabre_VObject_Element_MultiValue('ORG', array($_record->org_name, $_record->org_unit))); $card->add(new Sabre_VObject_Property('TITLE', $_record->title)); $tel = new Sabre_VObject_Property('TEL', $_record->tel_work); $tel->add('TYPE', 'WORK'); $card->add($tel); $tel = new Sabre_VObject_Property('TEL', $_record->tel_home); $tel->add('TYPE', 'HOME'); $card->add($tel); $tel = new Sabre_VObject_Property('TEL', $_record->tel_cell); $tel->add('TYPE', 'CELL'); $card->add($tel); $tel = new Sabre_VObject_Property('TEL', $_record->tel_pager); $tel->add('TYPE', 'PAGER'); $card->add($tel); $tel = new Sabre_VObject_Property('TEL', $_record->tel_fax); $tel->add('TYPE', 'FAX'); $card->add($tel); #$tel = new Sabre_VObject_Property('TEL', $_record->tel_fax_home); #$tel->add('TYPE', 'FAX'); #$tel->add('TYPE', 'HOME'); #$card->add($tel); $adr = new Sabre_VObject_Element_MultiValue('ADR', array(null, $_record->adr_one_street2, $_record->adr_one_street, $_record->adr_one_locality, $_record->adr_one_region, $_record->adr_one_postalcode, $_record->adr_one_countryname)); $adr->add('TYPE', 'WORK'); $card->add($adr); $adr = new Sabre_VObject_Element_MultiValue('ADR', array(null, $_record->adr_two_street2, $_record->adr_two_street, $_record->adr_two_locality, $_record->adr_two_region, $_record->adr_two_postalcode, $_record->adr_two_countryname)); $adr->add('TYPE', 'HOME'); $card->add($adr); $card->add(new Sabre_VObject_Property('EMAIL;TYPE=work', $_record->email)); $card->add(new Sabre_VObject_Property('EMAIL;TYPE=home', $_record->email_home)); $card->add(new Sabre_VObject_Property('URL;TYPE=work', $_record->url)); $card->add(new Sabre_VObject_Property('URL;TYPE=home', $_record->url_home)); $card->add(new Sabre_VObject_Property('NOTE', $_record->note)); if (!empty($_record->jpegphoto)) { try { $image = Tinebase_Controller::getInstance()->getImage('Addressbook', $_record->getId()); $jpegData = $image->getBlob('image/jpeg'); $photo = new Sabre_VObject_Property('PHOTO', $jpegData); $photo->add('ENCODING', 'b'); $photo->add('TYPE', 'JPEG'); $card->add($photo); } catch (Exception $e) { Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Image for contact {$_record->getId()} not found or invalid"); } } if (isset($_record->tags) && count($_record->tags) > 0) { $card->add(new Sabre_VObject_Property('CATEGORIES', Sabre_VObject_Element_List((array) $_record->tags->name))); } if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' card ' . $card->serialize()); } return $card; }
/** * @depends testValues */ function testOverridenEventNoValuesExpected() { $vcal = Sabre_VObject_Component::create('VCALENDAR'); $ev1 = Sabre_VObject_Component::create('VEVENT'); $ev1->UID = 'overridden'; $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3'; $ev1->DTSTART = '20120124T120000Z'; $ev1->SUMMARY = 'baseEvent'; $vcal->add($ev1); // ev2 overrides an event, and puts it 6 days earlier instead. $ev2 = Sabre_VObject_Component::create('VEVENT'); $ev2->UID = 'overridden'; $ev2->{'RECURRENCE-ID'} = '20120131T120000Z'; $ev2->DTSTART = '20120125T120000Z'; $ev2->SUMMARY = 'Override!'; $vcal->add($ev2); $it = new Sabre_VObject_RecurrenceIterator($vcal, 'overridden'); $dates = array(); $summaries = array(); // The reported problem was specifically related to the VCALENDAR // expansion. In this parcitular case, we had to forward to the 28th of // january. $it->fastForward(new DateTime('2012-01-28 23:00:00')); // We stop the loop when it hits the 6th of februari. Normally this // iterator would hit 24, 25 (overriden from 31) and 7 feb but because // we 'filter' from the 28th till the 6th, we should get 0 results. while ($it->valid() && $it->getDTSTart() < new DateTime('2012-02-06 23:00:00')) { $dates[] = $it->getDTStart(); $summaries[] = (string) $it->getEventObject()->SUMMARY; $it->next(); } $this->assertEquals(array(), $dates); $this->assertEquals(array(), $summaries); }