forked from friendica/friendica-addons
239 lines
7.2 KiB
PHP
239 lines
7.2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* The VCalendar component
|
|
*
|
|
* This component adds functionality to a component, specific for a VCALENDAR.
|
|
*
|
|
* @package Sabre
|
|
* @subpackage VObject
|
|
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
|
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
|
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
|
*/
|
|
class Sabre_VObject_Component_VCalendar extends Sabre_VObject_Component {
|
|
|
|
/**
|
|
* Returns a list of all 'base components'. For instance, if an Event has
|
|
* a recurrence rule, and one instance is overridden, the overridden event
|
|
* will have the same UID, but will be excluded from this list.
|
|
*
|
|
* VTIMEZONE components will always be excluded.
|
|
*
|
|
* @param string $componentName filter by component name
|
|
* @return array
|
|
*/
|
|
public function getBaseComponents($componentName = null) {
|
|
|
|
$components = array();
|
|
foreach($this->children as $component) {
|
|
|
|
if (!$component instanceof Sabre_VObject_Component)
|
|
continue;
|
|
|
|
if (isset($component->{'RECURRENCE-ID'}))
|
|
continue;
|
|
|
|
if ($componentName && $component->name !== strtoupper($componentName))
|
|
continue;
|
|
|
|
if ($component->name === 'VTIMEZONE')
|
|
continue;
|
|
|
|
$components[] = $component;
|
|
|
|
}
|
|
|
|
return $components;
|
|
|
|
}
|
|
|
|
/**
|
|
* If this calendar object, has events with recurrence rules, this method
|
|
* can be used to expand the event into multiple sub-events.
|
|
*
|
|
* Each event will be stripped from it's recurrence information, and only
|
|
* the instances of the event in the specified timerange will be left
|
|
* alone.
|
|
*
|
|
* In addition, this method will cause timezone information to be stripped,
|
|
* and normalized to UTC.
|
|
*
|
|
* This method will alter the VCalendar. This cannot be reversed.
|
|
*
|
|
* This functionality is specifically used by the CalDAV standard. It is
|
|
* possible for clients to request expand events, if they are rather simple
|
|
* clients and do not have the possibility to calculate recurrences.
|
|
*
|
|
* @param DateTime $start
|
|
* @param DateTime $end
|
|
* @return void
|
|
*/
|
|
public function expand(DateTime $start, DateTime $end) {
|
|
|
|
$newEvents = array();
|
|
|
|
foreach($this->select('VEVENT') as $key=>$vevent) {
|
|
|
|
if (isset($vevent->{'RECURRENCE-ID'})) {
|
|
unset($this->children[$key]);
|
|
continue;
|
|
}
|
|
|
|
|
|
if (!$vevent->rrule) {
|
|
unset($this->children[$key]);
|
|
if ($vevent->isInTimeRange($start, $end)) {
|
|
$newEvents[] = $vevent;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
$uid = (string)$vevent->uid;
|
|
if (!$uid) {
|
|
throw new LogicException('Event did not have a UID!');
|
|
}
|
|
|
|
$it = new Sabre_VObject_RecurrenceIterator($this, $vevent->uid);
|
|
$it->fastForward($start);
|
|
|
|
while($it->valid() && $it->getDTStart() < $end) {
|
|
|
|
if ($it->getDTEnd() > $start) {
|
|
|
|
$newEvents[] = $it->getEventObject();
|
|
|
|
}
|
|
$it->next();
|
|
|
|
}
|
|
unset($this->children[$key]);
|
|
|
|
}
|
|
|
|
foreach($newEvents as $newEvent) {
|
|
|
|
foreach($newEvent->children as $child) {
|
|
if ($child instanceof Sabre_VObject_Property_DateTime &&
|
|
$child->getDateType() == Sabre_VObject_Property_DateTime::LOCALTZ) {
|
|
$child->setDateTime($child->getDateTime(),Sabre_VObject_Property_DateTime::UTC);
|
|
}
|
|
}
|
|
|
|
$this->add($newEvent);
|
|
|
|
}
|
|
|
|
// Removing all VTIMEZONE components
|
|
unset($this->VTIMEZONE);
|
|
|
|
}
|
|
|
|
/**
|
|
* Validates the node for correctness.
|
|
* An array is returned with warnings.
|
|
*
|
|
* Every item in the array has the following properties:
|
|
* * level - (number between 1 and 3 with severity information)
|
|
* * message - (human readable message)
|
|
* * node - (reference to the offending node)
|
|
*
|
|
* @return array
|
|
*/
|
|
public function validate() {
|
|
|
|
$warnings = array();
|
|
|
|
$version = $this->select('VERSION');
|
|
if (count($version)!==1) {
|
|
$warnings[] = array(
|
|
'level' => 1,
|
|
'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time',
|
|
'node' => $this,
|
|
);
|
|
} else {
|
|
if ((string)$this->VERSION !== '2.0') {
|
|
$warnings[] = array(
|
|
'level' => 1,
|
|
'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
|
|
'node' => $this,
|
|
);
|
|
}
|
|
}
|
|
$version = $this->select('PRODID');
|
|
if (count($version)!==1) {
|
|
$warnings[] = array(
|
|
'level' => 2,
|
|
'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time',
|
|
'node' => $this,
|
|
);
|
|
}
|
|
if (count($this->CALSCALE) > 1) {
|
|
$warnings[] = array(
|
|
'level' => 2,
|
|
'message' => 'The CALSCALE property must not be specified more than once.',
|
|
'node' => $this,
|
|
);
|
|
}
|
|
if (count($this->METHOD) > 1) {
|
|
$warnings[] = array(
|
|
'level' => 2,
|
|
'message' => 'The METHOD property must not be specified more than once.',
|
|
'node' => $this,
|
|
);
|
|
}
|
|
|
|
$allowedComponents = array(
|
|
'VEVENT',
|
|
'VTODO',
|
|
'VJOURNAL',
|
|
'VFREEBUSY',
|
|
'VTIMEZONE',
|
|
);
|
|
$allowedProperties = array(
|
|
'PRODID',
|
|
'VERSION',
|
|
'CALSCALE',
|
|
'METHOD',
|
|
);
|
|
$componentsFound = 0;
|
|
foreach($this->children as $child) {
|
|
if($child instanceof Sabre_VObject_Component) {
|
|
$componentsFound++;
|
|
if (!in_array($child->name, $allowedComponents)) {
|
|
$warnings[] = array(
|
|
'level' => 1,
|
|
'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component",
|
|
'node' => $this,
|
|
);
|
|
}
|
|
}
|
|
if ($child instanceof Sabre_VObject_Property) {
|
|
if (!in_array($child->name, $allowedProperties)) {
|
|
$warnings[] = array(
|
|
'level' => 2,
|
|
'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component",
|
|
'node' => $this,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($componentsFound===0) {
|
|
$warnings[] = array(
|
|
'level' => 1,
|
|
'message' => 'An iCalendar object must have at least 1 component.',
|
|
'node' => $this,
|
|
);
|
|
}
|
|
|
|
return array_merge(
|
|
$warnings,
|
|
parent::validate()
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|