diff options
Diffstat (limited to '3rdparty/Sabre/VObject')
23 files changed, 2917 insertions, 642 deletions
diff --git a/3rdparty/Sabre/VObject/Component.php b/3rdparty/Sabre/VObject/Component.php index 47cf9f3d812..b78a26133fa 100644..100755 --- a/3rdparty/Sabre/VObject/Component.php +++ b/3rdparty/Sabre/VObject/Component.php @@ -4,39 +4,73 @@ * VObject Component * * This class represents a VCALENDAR/VCARD component. A component is for example - * VEVENT, VTODO and also VCALENDAR. It starts with BEGIN:COMPONENTNAME and + * VEVENT, VTODO and also VCALENDAR. It starts with BEGIN:COMPONENTNAME and * ends with END:COMPONENTNAME * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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 extends Sabre_VObject_Element { /** - * Name, for example VEVENT - * - * @var string + * Name, for example VEVENT + * + * @var string */ public $name; /** - * Children properties and components - * + * Children properties and components + * * @var array */ public $children = array(); + /** + * If coponents are added to this map, they will be automatically mapped + * to their respective classes, if parsed by the reader or constructed with + * the 'create' method. + * + * @var array + */ + static public $classMap = array( + 'VCALENDAR' => 'Sabre_VObject_Component_VCalendar', + 'VEVENT' => 'Sabre_VObject_Component_VEvent', + 'VTODO' => 'Sabre_VObject_Component_VTodo', + 'VJOURNAL' => 'Sabre_VObject_Component_VJournal', + 'VALARM' => 'Sabre_VObject_Component_VAlarm', + ); + + /** + * Creates the new component by name, but in addition will also see if + * there's a class mapped to the property name. + * + * @param string $name + * @param string $value + * @return Sabre_VObject_Component + */ + static public function create($name, $value = null) { + + $name = strtoupper($name); + + if (isset(self::$classMap[$name])) { + return new self::$classMap[$name]($name, $value); + } else { + return new self($name, $value); + } + + } /** * Creates a new component. * - * By default this object will iterate over its own children, but this can + * By default this object will iterate over its own children, but this can * be overridden with the iterator argument - * - * @param string $name + * + * @param string $name * @param Sabre_VObject_ElementList $iterator */ public function __construct($name, Sabre_VObject_ElementList $iterator = null) { @@ -47,23 +81,65 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { } /** - * Turns the object back into a serialized blob. - * - * @return string + * Turns the object back into a serialized blob. + * + * @return string */ public function serialize() { $str = "BEGIN:" . $this->name . "\r\n"; + + /** + * Gives a component a 'score' for sorting purposes. + * + * This is solely used by the childrenSort method. + * + * A higher score means the item will be higher in the list + * + * @param Sabre_VObject_Node $n + * @return int + */ + $sortScore = function($n) { + + if ($n instanceof Sabre_VObject_Component) { + // We want to encode VTIMEZONE first, this is a personal + // preference. + if ($n->name === 'VTIMEZONE') { + return 1; + } else { + return 0; + } + } else { + // VCARD version 4.0 wants the VERSION property to appear first + if ($n->name === 'VERSION') { + return 3; + } else { + return 2; + } + } + + }; + + usort($this->children, function($a, $b) use ($sortScore) { + + $sA = $sortScore($a); + $sB = $sortScore($b); + + if ($sA === $sB) return 0; + + return ($sA > $sB) ? -1 : 1; + + }); + foreach($this->children as $child) $str.=$child->serialize(); $str.= "END:" . $this->name . "\r\n"; - + return $str; } - /** - * Adds a new componenten or element + * Adds a new component or element * * You can call this method with the following syntaxes: * @@ -71,10 +147,10 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { * add(string $name, $value) * * The first version adds an Element - * The second adds a property as a string. - * - * @param mixed $item - * @param mixed $itemValue + * The second adds a property as a string. + * + * @param mixed $item + * @param mixed $itemValue * @return void */ public function add($item, $itemValue = null) { @@ -90,12 +166,12 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { if (!is_scalar($itemValue)) { throw new InvalidArgumentException('The second argument must be scalar'); } - $item = new Sabre_VObject_Property($item,$itemValue); + $item = Sabre_VObject_Property::create($item,$itemValue); $item->parent = $this; $this->children[] = $item; } else { - + throw new InvalidArgumentException('The first argument must either be a Sabre_VObject_Element or a string'); } @@ -103,9 +179,9 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { } /** - * Returns an iterable list of children - * - * @return Sabre_VObject_ElementList + * Returns an iterable list of children + * + * @return Sabre_VObject_ElementList */ public function children() { @@ -116,18 +192,18 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { /** * Returns an array with elements that match the specified name. * - * This function is also aware of MIME-Directory groups (as they appear in - * vcards). This means that if a property is grouped as "HOME.EMAIL", it - * will also be returned when searching for just "EMAIL". If you want to - * search for a property in a specific group, you can select on the entire - * string ("HOME.EMAIL"). If you want to search on a specific property that + * This function is also aware of MIME-Directory groups (as they appear in + * vcards). This means that if a property is grouped as "HOME.EMAIL", it + * will also be returned when searching for just "EMAIL". If you want to + * search for a property in a specific group, you can select on the entire + * string ("HOME.EMAIL"). If you want to search on a specific property that * has not been assigned a group, specify ".EMAIL". * - * Keys are retained from the 'children' array, which may be confusing in - * certain cases. + * Keys are retained from the 'children' array, which may be confusing in + * certain cases. * - * @param string $name - * @return array + * @param string $name + * @return array */ public function select($name) { @@ -144,7 +220,7 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { strtoupper($child->name) === $name && (is_null($group) || ( $child instanceof Sabre_VObject_Property && strtoupper($child->group) === $group)) ) { - + $result[$key] = $child; } @@ -155,16 +231,35 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { } + /** + * This method only returns a list of sub-components. Properties are + * ignored. + * + * @return array + */ + public function getComponents() { + + $result = array(); + foreach($this->children as $child) { + if ($child instanceof Sabre_VObject_Component) { + $result[] = $child; + } + } + + return $result; + + } + /* Magic property accessors {{{ */ /** - * Using 'get' you will either get a propery or component, + * Using 'get' you will either get a property or component, * * If there were no child-elements found with the specified name, * null is returned. - * - * @param string $name - * @return void + * + * @param string $name + * @return Sabre_VObject_Property */ public function __get($name) { @@ -173,6 +268,7 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { return null; } else { $firstMatch = current($matches); + /** @var $firstMatch Sabre_VObject_Property */ $firstMatch->setIterator(new Sabre_VObject_ElementList(array_values($matches))); return $firstMatch; } @@ -180,10 +276,10 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { } /** - * This method checks if a sub-element with the specified name exists. - * - * @param string $name - * @return bool + * This method checks if a sub-element with the specified name exists. + * + * @param string $name + * @return bool */ public function __isset($name) { @@ -200,7 +296,7 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { * * If the item already exists, it will be removed. If you want to add * a new item with the same name, always use the add() method. - * + * * @param string $name * @param mixed $value * @return void @@ -218,7 +314,7 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { $this->children[] = $value; } } elseif (is_scalar($value)) { - $property = new Sabre_VObject_Property($name,$value); + $property = Sabre_VObject_Property::create($name,$value); $property->parent = $this; if (!is_null($overWrite)) { $this->children[$overWrite] = $property; @@ -232,9 +328,9 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { } /** - * Removes all properties and components within this component. - * - * @param string $name + * Removes all properties and components within this component. + * + * @param string $name * @return void */ public function __unset($name) { @@ -251,4 +347,19 @@ class Sabre_VObject_Component extends Sabre_VObject_Element { /* }}} */ + /** + * This method is automatically called when the object is cloned. + * Specifically, this will ensure all child elements are also cloned. + * + * @return void + */ + public function __clone() { + + foreach($this->children as $key=>$child) { + $this->children[$key] = clone $child; + $this->children[$key]->parent = $this; + } + + } + } diff --git a/3rdparty/Sabre/VObject/Component/VAlarm.php b/3rdparty/Sabre/VObject/Component/VAlarm.php new file mode 100755 index 00000000000..ebb4a9b18f6 --- /dev/null +++ b/3rdparty/Sabre/VObject/Component/VAlarm.php @@ -0,0 +1,102 @@ +<?php + +/** + * VAlarm component + * + * This component contains some additional functionality specific for VALARMs. + * + * @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_VAlarm extends Sabre_VObject_Component { + + /** + * Returns a DateTime object when this alarm is going to trigger. + * + * This ignores repeated alarm, only the first trigger is returned. + * + * @return DateTime + */ + public function getEffectiveTriggerTime() { + + $trigger = $this->TRIGGER; + if(!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') { + $triggerDuration = Sabre_VObject_DateTimeParser::parseDuration($this->TRIGGER); + $related = (isset($trigger['RELATED']) && strtoupper($trigger['RELATED']) == 'END') ? 'END' : 'START'; + + $parentComponent = $this->parent; + if ($related === 'START') { + $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime(); + $effectiveTrigger->add($triggerDuration); + } else { + if ($parentComponent->name === 'VTODO') { + $endProp = 'DUE'; + } elseif ($parentComponent->name === 'VEVENT') { + $endProp = 'DTEND'; + } else { + throw new Sabre_DAV_Exception('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT'); + } + + if (isset($parentComponent->$endProp)) { + $effectiveTrigger = clone $parentComponent->$endProp->getDateTime(); + $effectiveTrigger->add($triggerDuration); + } elseif (isset($parentComponent->DURATION)) { + $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime(); + $duration = Sabre_VObject_DateTimeParser::parseDuration($parentComponent->DURATION); + $effectiveTrigger->add($duration); + $effectiveTrigger->add($triggerDuration); + } else { + $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime(); + $effectiveTrigger->add($triggerDuration); + } + } + } else { + $effectiveTrigger = $trigger->getDateTime(); + } + return $effectiveTrigger; + + } + + /** + * Returns true or false depending on if the event falls in the specified + * time-range. This is used for filtering purposes. + * + * The rules used to determine if an event falls within the specified + * time-range is based on the CalDAV specification. + * + * @param DateTime $start + * @param DateTime $end + * @return bool + */ + public function isInTimeRange(DateTime $start, DateTime $end) { + + $effectiveTrigger = $this->getEffectiveTriggerTime(); + + if (isset($this->DURATION)) { + $duration = Sabre_VObject_DateTimeParser::parseDuration($this->DURATION); + $repeat = (string)$this->repeat; + if (!$repeat) { + $repeat = 1; + } + + $period = new DatePeriod($effectiveTrigger, $duration, (int)$repeat); + + foreach($period as $occurrence) { + + if ($start <= $occurrence && $end > $occurrence) { + return true; + } + } + return false; + } else { + return ($start <= $effectiveTrigger && $end > $effectiveTrigger); + } + + } + +} + +?> diff --git a/3rdparty/Sabre/VObject/Component/VCalendar.php b/3rdparty/Sabre/VObject/Component/VCalendar.php new file mode 100755 index 00000000000..f3be29afdbb --- /dev/null +++ b/3rdparty/Sabre/VObject/Component/VCalendar.php @@ -0,0 +1,133 @@ +<?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); + + } + +} + diff --git a/3rdparty/Sabre/VObject/Component/VEvent.php b/3rdparty/Sabre/VObject/Component/VEvent.php new file mode 100755 index 00000000000..4cc1e36d7d6 --- /dev/null +++ b/3rdparty/Sabre/VObject/Component/VEvent.php @@ -0,0 +1,70 @@ +<?php + +/** + * VEvent component + * + * This component contains some additional functionality specific for VEVENT's. + * + * @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_VEvent extends Sabre_VObject_Component { + + /** + * Returns true or false depending on if the event falls in the specified + * time-range. This is used for filtering purposes. + * + * The rules used to determine if an event falls within the specified + * time-range is based on the CalDAV specification. + * + * @param DateTime $start + * @param DateTime $end + * @return bool + */ + public function isInTimeRange(DateTime $start, DateTime $end) { + + if ($this->RRULE) { + $it = new Sabre_VObject_RecurrenceIterator($this); + $it->fastForward($start); + + // We fast-forwarded to a spot where the end-time of the + // recurrence instance exceeded the start of the requested + // time-range. + // + // If the starttime of the recurrence did not exceed the + // end of the time range as well, we have a match. + return ($it->getDTStart() < $end && $it->getDTEnd() > $start); + + } + + $effectiveStart = $this->DTSTART->getDateTime(); + if (isset($this->DTEND)) { + $effectiveEnd = $this->DTEND->getDateTime(); + // If this was an all-day event, we should just increase the + // end-date by 1. Otherwise the event will last until the second + // the date changed, by increasing this by 1 day the event lasts + // all of the last day as well. + if ($this->DTSTART->getDateType() == Sabre_VObject_Element_DateTime::DATE) { + $effectiveEnd->modify('+1 day'); + } + } elseif (isset($this->DURATION)) { + $effectiveEnd = clone $effectiveStart; + $effectiveEnd->add( Sabre_VObject_DateTimeParser::parseDuration($this->DURATION) ); + } elseif ($this->DTSTART->getDateType() == Sabre_VObject_Element_DateTime::DATE) { + $effectiveEnd = clone $effectiveStart; + $effectiveEnd->modify('+1 day'); + } else { + $effectiveEnd = clone $effectiveStart; + } + return ( + ($start <= $effectiveEnd) && ($end > $effectiveStart) + ); + + } + +} + +?> diff --git a/3rdparty/Sabre/VObject/Component/VJournal.php b/3rdparty/Sabre/VObject/Component/VJournal.php new file mode 100755 index 00000000000..22b3ec921e5 --- /dev/null +++ b/3rdparty/Sabre/VObject/Component/VJournal.php @@ -0,0 +1,46 @@ +<?php + +/** + * VJournal component + * + * This component contains some additional functionality specific for VJOURNALs. + * + * @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_VJournal extends Sabre_VObject_Component { + + /** + * Returns true or false depending on if the event falls in the specified + * time-range. This is used for filtering purposes. + * + * The rules used to determine if an event falls within the specified + * time-range is based on the CalDAV specification. + * + * @param DateTime $start + * @param DateTime $end + * @return bool + */ + public function isInTimeRange(DateTime $start, DateTime $end) { + + $dtstart = isset($this->DTSTART)?$this->DTSTART->getDateTime():null; + if ($dtstart) { + $effectiveEnd = clone $dtstart; + if ($this->DTSTART->getDateType() == Sabre_VObject_Element_DateTime::DATE) { + $effectiveEnd->modify('+1 day'); + } + + return ($start <= $effectiveEnd && $end > $dtstart); + + } + return false; + + + } + +} + +?> diff --git a/3rdparty/Sabre/VObject/Component/VTodo.php b/3rdparty/Sabre/VObject/Component/VTodo.php new file mode 100755 index 00000000000..79d06298d7f --- /dev/null +++ b/3rdparty/Sabre/VObject/Component/VTodo.php @@ -0,0 +1,68 @@ +<?php + +/** + * VTodo component + * + * This component contains some additional functionality specific for VTODOs. + * + * @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_VTodo extends Sabre_VObject_Component { + + /** + * Returns true or false depending on if the event falls in the specified + * time-range. This is used for filtering purposes. + * + * The rules used to determine if an event falls within the specified + * time-range is based on the CalDAV specification. + * + * @param DateTime $start + * @param DateTime $end + * @return bool + */ + public function isInTimeRange(DateTime $start, DateTime $end) { + + $dtstart = isset($this->DTSTART)?$this->DTSTART->getDateTime():null; + $duration = isset($this->DURATION)?Sabre_VObject_DateTimeParser::parseDuration($this->DURATION):null; + $due = isset($this->DUE)?$this->DUE->getDateTime():null; + $completed = isset($this->COMPLETED)?$this->COMPLETED->getDateTime():null; + $created = isset($this->CREATED)?$this->CREATED->getDateTime():null; + + if ($dtstart) { + if ($duration) { + $effectiveEnd = clone $dtstart; + $effectiveEnd->add($duration); + return $start <= $effectiveEnd && $end > $dtstart; + } elseif ($due) { + return + ($start < $due || $start <= $dtstart) && + ($end > $dtstart || $end >= $due); + } else { + return $start <= $dtstart && $end > $dtstart; + } + } + if ($due) { + return ($start < $due && $end >= $due); + } + if ($completed && $created) { + return + ($start <= $created || $start <= $completed) && + ($end >= $created || $end >= $completed); + } + if ($completed) { + return ($start <= $completed && $end >= $completed); + } + if ($created) { + return ($end > $created); + } + return true; + + } + +} + +?> diff --git a/3rdparty/Sabre/VObject/DateTimeParser.php b/3rdparty/Sabre/VObject/DateTimeParser.php new file mode 100755 index 00000000000..1e2d54ef3a9 --- /dev/null +++ b/3rdparty/Sabre/VObject/DateTimeParser.php @@ -0,0 +1,177 @@ +<?php + +/** + * DateTimeParser + * + * This class is responsible for parsing the several different date and time + * formats iCalendar and vCards have. + * + * @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_DateTimeParser { + + /** + * Parses an iCalendar (rfc5545) formatted datetime and returns a DateTime object + * + * Specifying a reference timezone is optional. It will only be used + * if the non-UTC format is used. The argument is used as a reference, the + * returned DateTime object will still be in the UTC timezone. + * + * @param string $dt + * @param DateTimeZone $tz + * @return DateTime + */ + static public function parseDateTime($dt,DateTimeZone $tz = null) { + + // Format is YYYYMMDD + "T" + hhmmss + $result = preg_match('/^([1-3][0-9]{3})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/',$dt,$matches); + + if (!$result) { + throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar datetime value is incorrect: ' . $dt); + } + + if ($matches[7]==='Z' || is_null($tz)) { + $tz = new DateTimeZone('UTC'); + } + $date = new DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3] . ' ' . $matches[4] . ':' . $matches[5] .':' . $matches[6], $tz); + + // Still resetting the timezone, to normalize everything to UTC + $date->setTimeZone(new DateTimeZone('UTC')); + return $date; + + } + + /** + * Parses an iCalendar (rfc5545) formatted date and returns a DateTime object + * + * @param string $date + * @return DateTime + */ + static public function parseDate($date) { + + // Format is YYYYMMDD + $result = preg_match('/^([1-3][0-9]{3})([0-1][0-9])([0-3][0-9])$/',$date,$matches); + + if (!$result) { + throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar date value is incorrect: ' . $date); + } + + $date = new DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3], new DateTimeZone('UTC')); + return $date; + + } + + /** + * Parses an iCalendar (RFC5545) formatted duration value. + * + * This method will either return a DateTimeInterval object, or a string + * suitable for strtotime or DateTime::modify. + * + * @param string $duration + * @param bool $asString + * @return DateInterval|string + */ + static public function parseDuration($duration, $asString = false) { + + $result = preg_match('/^(?P<plusminus>\+|-)?P((?P<week>\d+)W)?((?P<day>\d+)D)?(T((?P<hour>\d+)H)?((?P<minute>\d+)M)?((?P<second>\d+)S)?)?$/', $duration, $matches); + if (!$result) { + throw new Sabre_DAV_Exception_BadRequest('The supplied iCalendar duration value is incorrect: ' . $duration); + } + + if (!$asString) { + $invert = false; + if ($matches['plusminus']==='-') { + $invert = true; + } + + + $parts = array( + 'week', + 'day', + 'hour', + 'minute', + 'second', + ); + foreach($parts as $part) { + $matches[$part] = isset($matches[$part])&&$matches[$part]?(int)$matches[$part]:0; + } + + + // We need to re-construct the $duration string, because weeks and + // days are not supported by DateInterval in the same string. + $duration = 'P'; + $days = $matches['day']; + if ($matches['week']) { + $days+=$matches['week']*7; + } + if ($days) + $duration.=$days . 'D'; + + if ($matches['minute'] || $matches['second'] || $matches['hour']) { + $duration.='T'; + + if ($matches['hour']) + $duration.=$matches['hour'].'H'; + + if ($matches['minute']) + $duration.=$matches['minute'].'M'; + + if ($matches['second']) + $duration.=$matches['second'].'S'; + + } + + $iv = new DateInterval($duration); + if ($invert) $iv->invert = true; + + return $iv; + + } + + + + $parts = array( + 'week', + 'day', + 'hour', + 'minute', + 'second', + ); + + $newDur = ''; + foreach($parts as $part) { + if (isset($matches[$part]) && $matches[$part]) { + $newDur.=' '.$matches[$part] . ' ' . $part . 's'; + } + } + + $newDur = ($matches['plusminus']==='-'?'-':'+') . trim($newDur); + return $newDur; + + } + + /** + * Parses either a Date or DateTime, or Duration value. + * + * @param string $date + * @param DateTimeZone|string $referenceTZ + * @return DateTime|DateInterval + */ + static public function parse($date, $referenceTZ = null) { + + if ($date[0]==='P' || ($date[0]==='-' && $date[1]==='P')) { + return self::parseDuration($date); + } elseif (strlen($date)===8) { + return self::parseDate($date); + } else { + return self::parseDateTime($date, $referenceTZ); + } + + } + + +} diff --git a/3rdparty/Sabre/VObject/Element.php b/3rdparty/Sabre/VObject/Element.php index 8d2b0aaacd1..e20ff0b353c 100644..100755 --- a/3rdparty/Sabre/VObject/Element.php +++ b/3rdparty/Sabre/VObject/Element.php @@ -2,14 +2,15 @@ /** * Base class for all elements - * + * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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 */ abstract class Sabre_VObject_Element extends Sabre_VObject_Node { + public $parent = null; } diff --git a/3rdparty/Sabre/VObject/Element/DateTime.php b/3rdparty/Sabre/VObject/Element/DateTime.php index 3350ec02c88..5e5eb7ab6f2 100644..100755 --- a/3rdparty/Sabre/VObject/Element/DateTime.php +++ b/3rdparty/Sabre/VObject/Element/DateTime.php @@ -1,25 +1,18 @@ <?php /** - * DateTime property + * DateTime property * - * This element is used for iCalendar properties such as the DTSTART property. - * It basically provides a few helper functions that make it easier to deal - * with these. It supports both DATE-TIME and DATE values. + * this class got renamed to Sabre_VObject_Property_DateTime * - * In order to use this correctly, you must call setDateTime and getDateTime to - * retrieve and modify dates respectively. - * - * If you use the 'value' or properties directly, this object does not keep - * reference and results might appear incorrectly. - * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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 + * @deprecated */ -class Sabre_VObject_Element_DateTime extends Sabre_VObject_Property { +class Sabre_VObject_Element_DateTime extends Sabre_VObject_Property_DateTime { /** * Local 'floating' time @@ -41,205 +34,4 @@ class Sabre_VObject_Element_DateTime extends Sabre_VObject_Property { */ const DATE = 4; - /** - * DateTime representation - * - * @var DateTime - */ - protected $dateTime; - - /** - * dateType - * - * @var int - */ - protected $dateType; - - /** - * Updates the Date and Time. - * - * @param DateTime $dt - * @param int $dateType - * @return void - */ - public function setDateTime(DateTime $dt, $dateType = self::LOCALTZ) { - - switch($dateType) { - - case self::LOCAL : - $this->setValue($dt->format('Ymd\\THis')); - $this->offsetUnset('VALUE'); - $this->offsetUnset('TZID'); - $this->offsetSet('VALUE','DATE-TIME'); - break; - case self::UTC : - $dt->setTimeZone(new DateTimeZone('UTC')); - $this->setValue($dt->format('Ymd\\THis\\Z')); - $this->offsetUnset('VALUE'); - $this->offsetUnset('TZID'); - $this->offsetSet('VALUE','DATE-TIME'); - break; - case self::LOCALTZ : - $this->setValue($dt->format('Ymd\\THis')); - $this->offsetUnset('VALUE'); - $this->offsetUnset('TZID'); - $this->offsetSet('VALUE','DATE-TIME'); - $this->offsetSet('TZID', $dt->getTimeZone()->getName()); - break; - case self::DATE : - $this->setValue($dt->format('Ymd')); - $this->offsetUnset('VALUE'); - $this->offsetUnset('TZID'); - $this->offsetSet('VALUE','DATE'); - break; - default : - throw new InvalidArgumentException('You must pass a valid dateType constant'); - - } - $this->dateTime = $dt; - $this->dateType = $dateType; - - } - - /** - * Returns the current DateTime value. - * - * If no value was set, this method returns null. - * - * @return DateTime|null - */ - public function getDateTime() { - - if ($this->dateTime) - return $this->dateTime; - - list( - $this->dateType, - $this->dateTime - ) = self::parseData($this->value, $this); - return $this->dateTime; - - } - - /** - * Returns the type of Date format. - * - * This method returns one of the format constants. If no date was set, - * this method will return null. - * - * @return int|null - */ - public function getDateType() { - - if ($this->dateType) - return $this->dateType; - - list( - $this->dateType, - $this->dateTime, - ) = self::parseData($this->value, $this); - return $this->dateType; - - } - - /** - * Parses the internal data structure to figure out what the current date - * and time is. - * - * The returned array contains two elements: - * 1. A 'DateType' constant (as defined on this class), or null. - * 2. A DateTime object (or null) - * - * @param string|null $propertyValue The string to parse (yymmdd or - * ymmddThhmmss, etc..) - * @param Sabre_VObject_Property|null $property The instance of the - * property we're parsing. - * @return array - */ - static public function parseData($propertyValue, Sabre_VObject_Property $property = null) { - - if (is_null($propertyValue)) { - return array(null, null); - } - - $date = '(?P<year>[1-2][0-9]{3})(?P<month>[0-1][0-9])(?P<date>[0-3][0-9])'; - $time = '(?P<hour>[0-2][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9])'; - $regex = "/^$date(T$time(?P<isutc>Z)?)?$/"; - - if (!preg_match($regex, $propertyValue, $matches)) { - throw new InvalidArgumentException($propertyValue . ' is not a valid DateTime or Date string'); - } - - if (!isset($matches['hour'])) { - // Date-only - return array( - self::DATE, - new DateTime($matches['year'] . '-' . $matches['month'] . '-' . $matches['date'] . ' 00:00:00'), - ); - } - - $dateStr = - $matches['year'] .'-' . - $matches['month'] . '-' . - $matches['date'] . ' ' . - $matches['hour'] . ':' . - $matches['minute'] . ':' . - $matches['second']; - - if (isset($matches['isutc'])) { - $dt = new DateTime($dateStr,new DateTimeZone('UTC')); - $dt->setTimeZone(new DateTimeZone('UTC')); - return array( - self::UTC, - $dt - ); - } - - // Finding the timezone. - $tzid = $property['TZID']; - if (!$tzid) { - return array( - self::LOCAL, - new DateTime($dateStr) - ); - } - - try { - $tz = new DateTimeZone($tzid->value); - } catch (Exception $e) { - - // The id was invalid, we're going to try to find the information - // through the VTIMEZONE object. - - // First we find the root object - $root = $property; - while($root->parent) { - $root = $root->parent; - } - - if (isset($root->VTIMEZONE)) { - foreach($root->VTIMEZONE as $vtimezone) { - if (((string)$vtimezone->TZID) == $tzid) { - if (isset($vtimezone->{'X-LIC-LOCATION'})) { - $tzid = (string)$vtimezone->{'X-LIC-LOCATION'}; - } - } - } - } - - $tz = new DateTimeZone($tzid); - - } - $dt = new DateTime($dateStr, $tz); - $dt->setTimeZone($tz); - - return array( - self::LOCALTZ, - $dt - ); - - } - } - -?> diff --git a/3rdparty/Sabre/VObject/Element/MultiDateTime.php b/3rdparty/Sabre/VObject/Element/MultiDateTime.php index dc6ca5abb80..8a12ced94a8 100644..100755 --- a/3rdparty/Sabre/VObject/Element/MultiDateTime.php +++ b/3rdparty/Sabre/VObject/Element/MultiDateTime.php @@ -1,168 +1,17 @@ <?php /** - * Multi-DateTime property + * Multi-DateTime property * - * This element is used for iCalendar properties such as the EXDATE property. - * It basically provides a few helper functions that make it easier to deal - * with these. It supports both DATE-TIME and DATE values. + * This class got renamed to Sabre_VObject_Property_MultiDateTime * - * In order to use this correctly, you must call setDateTimes and getDateTimes - * to retrieve and modify dates respectively. - * - * If you use the 'value' or properties directly, this object does not keep - * reference and results might appear incorrectly. - * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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 + * @deprecated */ -class Sabre_VObject_Element_MultiDateTime extends Sabre_VObject_Property { - - /** - * DateTime representation - * - * @var DateTime[] - */ - protected $dateTimes; - - /** - * dateType - * - * This is one of the Sabre_VObject_Element_DateTime constants. - * - * @var int - */ - protected $dateType; - - /** - * Updates the value - * - * @param array $dt Must be an array of DateTime objects. - * @param int $dateType - * @return void - */ - public function setDateTimes(array $dt, $dateType = Sabre_VObject_Element_DateTime::LOCALTZ) { - - foreach($dt as $i) - if (!$i instanceof DateTime) - throw new InvalidArgumentException('You must pass an array of DateTime objects'); - - $this->offsetUnset('VALUE'); - $this->offsetUnset('TZID'); - switch($dateType) { - - case Sabre_VObject_Element_DateTime::LOCAL : - $val = array(); - foreach($dt as $i) { - $val[] = $i->format('Ymd\\THis'); - } - $this->setValue(implode(',',$val)); - $this->offsetSet('VALUE','DATE-TIME'); - break; - case Sabre_VObject_Element_DateTime::UTC : - $val = array(); - foreach($dt as $i) { - $i->setTimeZone(new DateTimeZone('UTC')); - $val[] = $i->format('Ymd\\THis\\Z'); - } - $this->setValue(implode(',',$val)); - $this->offsetSet('VALUE','DATE-TIME'); - break; - case Sabre_VObject_Element_DateTime::LOCALTZ : - $val = array(); - foreach($dt as $i) { - $val[] = $i->format('Ymd\\THis'); - } - $this->setValue(implode(',',$val)); - $this->offsetSet('VALUE','DATE-TIME'); - $this->offsetSet('TZID', $dt[0]->getTimeZone()->getName()); - break; - case Sabre_VObject_Element_DateTime::DATE : - $val = array(); - foreach($dt as $i) { - $val[] = $i->format('Ymd'); - } - $this->setValue(implode(',',$val)); - $this->offsetSet('VALUE','DATE'); - break; - default : - throw new InvalidArgumentException('You must pass a valid dateType constant'); - - } - $this->dateTimes = $dt; - $this->dateType = $dateType; - - } - - /** - * Returns the current DateTime value. - * - * If no value was set, this method returns null. - * - * @return array|null - */ - public function getDateTimes() { - - if ($this->dateTimes) - return $this->dateTimes; - - $dts = array(); - - if (!$this->value) { - $this->dateTimes = null; - $this->dateType = null; - return null; - } - - foreach(explode(',',$this->value) as $val) { - list( - $type, - $dt - ) = Sabre_VObject_Element_DateTime::parseData($val, $this); - $dts[] = $dt; - $this->dateType = $type; - } - $this->dateTimes = $dts; - return $this->dateTimes; - - } - - /** - * Returns the type of Date format. - * - * This method returns one of the format constants. If no date was set, - * this method will return null. - * - * @return int|null - */ - public function getDateType() { - - if ($this->dateType) - return $this->dateType; - - if (!$this->value) { - $this->dateTimes = null; - $this->dateType = null; - return null; - } - - $dts = array(); - foreach(explode(',',$this->value) as $val) { - list( - $type, - $dt - ) = Sabre_VObject_Element_DateTime::parseData($val, $this); - $dts[] = $dt; - $this->dateType = $type; - } - $this->dateTimes = $dts; - return $this->dateType; - - } +class Sabre_VObject_Element_MultiDateTime extends Sabre_VObject_Property_MultiDateTime { } - -?> diff --git a/3rdparty/Sabre/VObject/ElementList.php b/3rdparty/Sabre/VObject/ElementList.php index 9922cd587bc..7e508db20f0 100644..100755 --- a/3rdparty/Sabre/VObject/ElementList.php +++ b/3rdparty/Sabre/VObject/ElementList.php @@ -8,15 +8,15 @@ * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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_ElementList implements Iterator, Countable, ArrayAccess { /** - * Inner elements - * + * Inner elements + * * @var array */ protected $elements = array(); @@ -24,37 +24,37 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { /** * Creates the element list. * - * @param array $elements + * @param array $elements */ public function __construct(array $elements) { $this->elements = $elements; - } + } /* {{{ Iterator interface */ /** - * Current position - * - * @var int + * Current position + * + * @var int */ private $key = 0; /** - * Returns current item in iteration - * - * @return Sabre_VObject_Element + * Returns current item in iteration + * + * @return Sabre_VObject_Element */ public function current() { return $this->elements[$this->key]; } - + /** - * To the next item in the iterator - * + * To the next item in the iterator + * * @return void */ public function next() { @@ -64,8 +64,8 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { } /** - * Returns the current iterator key - * + * Returns the current iterator key + * * @return int */ public function key() { @@ -75,9 +75,9 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { } /** - * Returns true if the current position in the iterator is a valid one - * - * @return bool + * Returns true if the current position in the iterator is a valid one + * + * @return bool */ public function valid() { @@ -86,9 +86,9 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { } /** - * Rewinds the iterator - * - * @return void + * Rewinds the iterator + * + * @return void */ public function rewind() { @@ -101,9 +101,9 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { /* {{{ Countable interface */ /** - * Returns the number of elements - * - * @return int + * Returns the number of elements + * + * @return int */ public function count() { @@ -115,12 +115,12 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { /* {{{ ArrayAccess Interface */ - + /** * Checks if an item exists through ArrayAccess. * - * @param int $offset - * @return bool + * @param int $offset + * @return bool */ public function offsetExists($offset) { @@ -131,8 +131,8 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { /** * Gets an item through ArrayAccess. * - * @param int $offset - * @return mixed + * @param int $offset + * @return mixed */ public function offsetGet($offset) { @@ -143,8 +143,8 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { /** * Sets an item through ArrayAccess. * - * @param int $offset - * @param mixed $value + * @param int $offset + * @param mixed $value * @return void */ public function offsetSet($offset,$value) { @@ -158,7 +158,7 @@ class Sabre_VObject_ElementList implements Iterator, Countable, ArrayAccess { * * This method just forwards the request to the inner iterator * - * @param int $offset + * @param int $offset * @return void */ public function offsetUnset($offset) { diff --git a/3rdparty/Sabre/VObject/FreeBusyGenerator.php b/3rdparty/Sabre/VObject/FreeBusyGenerator.php new file mode 100755 index 00000000000..1c96a64a004 --- /dev/null +++ b/3rdparty/Sabre/VObject/FreeBusyGenerator.php @@ -0,0 +1,297 @@ +<?php + +/** + * This class helps with generating FREEBUSY reports based on existing sets of + * objects. + * + * It only looks at VEVENT and VFREEBUSY objects from the sourcedata, and + * generates a single VFREEBUSY object. + * + * VFREEBUSY components are described in RFC5545, The rules for what should + * go in a single freebusy report is taken from RFC4791, section 7.10. + * + * @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_FreeBusyGenerator { + + /** + * Input objects + * + * @var array + */ + protected $objects; + + /** + * Start of range + * + * @var DateTime|null + */ + protected $start; + + /** + * End of range + * + * @var DateTime|null + */ + protected $end; + + /** + * VCALENDAR object + * + * @var Sabre_VObject_Component + */ + protected $baseObject; + + /** + * Sets the VCALENDAR object. + * + * If this is set, it will not be generated for you. You are responsible + * for setting things like the METHOD, CALSCALE, VERSION, etc.. + * + * The VFREEBUSY object will be automatically added though. + * + * @param Sabre_VObject_Component $vcalendar + * @return void + */ + public function setBaseObject(Sabre_VObject_Component $vcalendar) { + + $this->baseObject = $vcalendar; + + } + + /** + * Sets the input objects + * + * Every object must either be a string or a Sabre_VObject_Component. + * + * @param array $objects + * @return void + */ + public function setObjects(array $objects) { + + $this->objects = array(); + foreach($objects as $object) { + + if (is_string($object)) { + $this->objects[] = Sabre_VObject_Reader::read($object); + } elseif ($object instanceof Sabre_VObject_Component) { + $this->objects[] = $object; + } else { + throw new InvalidArgumentException('You can only pass strings or Sabre_VObject_Component arguments to setObjects'); + } + + } + + } + + /** + * Sets the time range + * + * Any freebusy object falling outside of this time range will be ignored. + * + * @param DateTime $start + * @param DateTime $end + * @return void + */ + public function setTimeRange(DateTime $start = null, DateTime $end = null) { + + $this->start = $start; + $this->end = $end; + + } + + /** + * 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'; + if (Sabre_DAV_Server::$exposeVersion) { + $calendar->prodid = '-//SabreDAV//Sabre VObject ' . Sabre_VObject_Version::VERSION . '//EN'; + } else { + $calendar->prodid = '-//SabreDAV//Sabre VObject//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; + + } + +} + diff --git a/3rdparty/Sabre/VObject/Node.php b/3rdparty/Sabre/VObject/Node.php index 7100b62f1cb..d89e01b56c6 100644..100755 --- a/3rdparty/Sabre/VObject/Node.php +++ b/3rdparty/Sabre/VObject/Node.php @@ -1,47 +1,47 @@ <?php /** - * Base class for all nodes - * + * Base class for all nodes + * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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 */ abstract class Sabre_VObject_Node implements IteratorAggregate, ArrayAccess, Countable { /** - * Turns the object back into a serialized blob. - * - * @return string + * Turns the object back into a serialized blob. + * + * @return string */ abstract function serialize(); /** - * Iterator override - * - * @var Sabre_VObject_ElementList + * Iterator override + * + * @var Sabre_VObject_ElementList */ protected $iterator = null; /** * A link to the parent node - * - * @var Sabre_VObject_Node + * + * @var Sabre_VObject_Node */ - protected $parent = null; + public $parent = null; /* {{{ IteratorAggregator interface */ /** - * Returns the iterator for this object - * - * @return Sabre_VObject_ElementList + * Returns the iterator for this object + * + * @return Sabre_VObject_ElementList */ public function getIterator() { - if (!is_null($this->iterator)) + if (!is_null($this->iterator)) return $this->iterator; return new Sabre_VObject_ElementList(array($this)); @@ -52,8 +52,8 @@ abstract class Sabre_VObject_Node implements IteratorAggregate, ArrayAccess, Cou * Sets the overridden iterator * * Note that this is not actually part of the iterator interface - * - * @param Sabre_VObject_ElementList $iterator + * + * @param Sabre_VObject_ElementList $iterator * @return void */ public function setIterator(Sabre_VObject_ElementList $iterator) { @@ -67,9 +67,9 @@ abstract class Sabre_VObject_Node implements IteratorAggregate, ArrayAccess, Cou /* {{{ Countable interface */ /** - * Returns the number of elements - * - * @return int + * Returns the number of elements + * + * @return int */ public function count() { @@ -82,14 +82,14 @@ abstract class Sabre_VObject_Node implements IteratorAggregate, ArrayAccess, Cou /* {{{ ArrayAccess Interface */ - + /** * Checks if an item exists through ArrayAccess. * * This method just forwards the request to the inner iterator - * - * @param int $offset - * @return bool + * + * @param int $offset + * @return bool */ public function offsetExists($offset) { @@ -103,8 +103,8 @@ abstract class Sabre_VObject_Node implements IteratorAggregate, ArrayAccess, Cou * * This method just forwards the request to the inner iterator * - * @param int $offset - * @return mixed + * @param int $offset + * @return mixed */ public function offsetGet($offset) { @@ -118,8 +118,8 @@ abstract class Sabre_VObject_Node implements IteratorAggregate, ArrayAccess, Cou * * This method just forwards the request to the inner iterator * - * @param int $offset - * @param mixed $value + * @param int $offset + * @param mixed $value * @return void */ public function offsetSet($offset,$value) { @@ -134,7 +134,7 @@ abstract class Sabre_VObject_Node implements IteratorAggregate, ArrayAccess, Cou * * This method just forwards the request to the inner iterator * - * @param int $offset + * @param int $offset * @return void */ public function offsetUnset($offset) { diff --git a/3rdparty/Sabre/VObject/Parameter.php b/3rdparty/Sabre/VObject/Parameter.php index 9ebab6ec69b..2e39af5f78a 100644..100755 --- a/3rdparty/Sabre/VObject/Parameter.php +++ b/3rdparty/Sabre/VObject/Parameter.php @@ -5,51 +5,54 @@ * * This class represents a parameter. A parameter is always tied to a property. * In the case of: - * DTSTART;VALUE=DATE:20101108 + * DTSTART;VALUE=DATE:20101108 * VALUE=DATE would be the parameter name and value. - * + * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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_Parameter extends Sabre_VObject_Node { /** - * Parameter name - * - * @var string + * Parameter name + * + * @var string */ public $name; /** - * Parameter value - * - * @var string + * Parameter value + * + * @var string */ public $value; /** - * Sets up the object - * - * @param string $name - * @param string $value + * Sets up the object + * + * @param string $name + * @param string $value */ public function __construct($name, $value = null) { $this->name = strtoupper($name); $this->value = $value; - } + } /** - * Turns the object back into a serialized blob. - * - * @return string + * Turns the object back into a serialized blob. + * + * @return string */ public function serialize() { + if (is_null($this->value)) { + return $this->name; + } $src = array( '\\', "\n", @@ -68,9 +71,9 @@ class Sabre_VObject_Parameter extends Sabre_VObject_Node { } /** - * Called when this object is being cast to a string - * - * @return string + * Called when this object is being cast to a string + * + * @return string */ public function __toString() { diff --git a/3rdparty/Sabre/VObject/ParseException.php b/3rdparty/Sabre/VObject/ParseException.php index ed4ef2e8592..1b5e95bf16e 100644..100755 --- a/3rdparty/Sabre/VObject/ParseException.php +++ b/3rdparty/Sabre/VObject/ParseException.php @@ -2,11 +2,11 @@ /** * Exception thrown by Sabre_VObject_Reader if an invalid object was attempted to be parsed. - * + * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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_ParseException extends Exception { } diff --git a/3rdparty/Sabre/VObject/Property.php b/3rdparty/Sabre/VObject/Property.php index 06058229043..ce74fe3865b 100644..100755 --- a/3rdparty/Sabre/VObject/Property.php +++ b/3rdparty/Sabre/VObject/Property.php @@ -4,58 +4,103 @@ * VObject Property * * A property in VObject is usually in the form PARAMNAME:paramValue. - * An example is : SUMMARY:Weekly meeting + * An example is : SUMMARY:Weekly meeting * * Properties can also have parameters: * SUMMARY;LANG=en:Weekly meeting. * - * Parameters can be accessed using the ArrayAccess interface. + * Parameters can be accessed using the ArrayAccess interface. * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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_Property extends Sabre_VObject_Element { /** - * Propertyname - * - * @var string + * Propertyname + * + * @var string */ public $name; /** * Group name - * + * * This may be something like 'HOME' for vcards. * - * @var string + * @var string */ public $group; /** - * Property parameters - * - * @var array + * Property parameters + * + * @var array */ public $parameters = array(); /** - * Property value - * - * @var string + * Property value + * + * @var string */ public $value; /** + * If properties are added to this map, they will be automatically mapped + * to their respective classes, if parsed by the reader or constructed with + * the 'create' method. + * + * @var array + */ + static public $classMap = array( + 'COMPLETED' => 'Sabre_VObject_Property_DateTime', + 'CREATED' => 'Sabre_VObject_Property_DateTime', + 'DTEND' => 'Sabre_VObject_Property_DateTime', + 'DTSTAMP' => 'Sabre_VObject_Property_DateTime', + 'DTSTART' => 'Sabre_VObject_Property_DateTime', + 'DUE' => 'Sabre_VObject_Property_DateTime', + 'EXDATE' => 'Sabre_VObject_Property_MultiDateTime', + 'LAST-MODIFIED' => 'Sabre_VObject_Property_DateTime', + 'RECURRENCE-ID' => 'Sabre_VObject_Property_DateTime', + 'TRIGGER' => 'Sabre_VObject_Property_DateTime', + ); + + /** + * Creates the new property by name, but in addition will also see if + * there's a class mapped to the property name. + * + * @param string $name + * @param string $value + * @return void + */ + static public function create($name, $value = null) { + + $name = strtoupper($name); + $shortName = $name; + $group = null; + if (strpos($shortName,'.')!==false) { + list($group, $shortName) = explode('.', $shortName); + } + + if (isset(self::$classMap[$shortName])) { + return new self::$classMap[$shortName]($name, $value); + } else { + return new self($name, $value); + } + + } + + /** * Creates a new property object - * - * By default this object will iterate over its own children, but this can + * + * By default this object will iterate over its own children, but this can * be overridden with the iterator argument - * - * @param string $name + * + * @param string $name * @param string $value * @param Sabre_VObject_ElementList $iterator */ @@ -73,10 +118,12 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { } + + /** - * Updates the internal value - * - * @param string $value + * Updates the internal value + * + * @param string $value * @return void */ public function setValue($value) { @@ -86,9 +133,9 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { } /** - * Turns the object back into a serialized blob. - * - * @return string + * Turns the object back into a serialized blob. + * + * @return string */ public function serialize() { @@ -97,7 +144,7 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { if (count($this->parameters)) { foreach($this->parameters as $param) { - + $str.=';' . $param->serialize(); } @@ -115,8 +162,8 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { $out = ''; while(strlen($str)>0) { if (strlen($str)>75) { - $out.= substr($str,0,75) . "\r\n"; - $str = ' ' . substr($str,75); + $out.= mb_strcut($str,0,75,'utf-8') . "\r\n"; + $str = ' ' . mb_strcut($str,75,strlen($str),'utf-8'); } else { $out.=$str . "\r\n"; $str=''; @@ -136,11 +183,11 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { * add(Sabre_VObject_Parameter $element) * add(string $name, $value) * - * The first version adds an Parameter - * The second adds a property as a string. - * - * @param mixed $item - * @param mixed $itemValue + * The first version adds an Parameter + * The second adds a property as a string. + * + * @param mixed $item + * @param mixed $itemValue * @return void */ public function add($item, $itemValue = null) { @@ -153,7 +200,7 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { $this->parameters[] = $item; } elseif(is_string($item)) { - if (!is_scalar($itemValue)) { + if (!is_scalar($itemValue) && !is_null($itemValue)) { throw new InvalidArgumentException('The second argument must be scalar'); } $parameter = new Sabre_VObject_Parameter($item,$itemValue); @@ -161,21 +208,20 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { $this->parameters[] = $parameter; } else { - + throw new InvalidArgumentException('The first argument must either be a Sabre_VObject_Element or a string'); } } - /* ArrayAccess interface {{{ */ /** * Checks if an array element exists - * - * @param mixed $name - * @return bool + * + * @param mixed $name + * @return bool */ public function offsetExists($name) { @@ -191,16 +237,16 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { } /** - * Returns a parameter, or parameter list. - * - * @param string $name - * @return Sabre_VObject_Element + * Returns a parameter, or parameter list. + * + * @param string $name + * @return Sabre_VObject_Element */ public function offsetGet($name) { if (is_int($name)) return parent::offsetGet($name); $name = strtoupper($name); - + $result = array(); foreach($this->parameters as $parameter) { if ($parameter->name == $name) @@ -219,8 +265,8 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { } /** - * Creates a new parameter - * + * Creates a new parameter + * * @param string $name * @param mixed $value * @return void @@ -230,7 +276,7 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { if (is_int($name)) return parent::offsetSet($name, $value); if (is_scalar($value)) { - if (!is_string($name)) + if (!is_string($name)) throw new InvalidArgumentException('A parameter name must be specified. This means you cannot use the $array[]="string" to add parameters.'); $this->offsetUnset($name); @@ -242,7 +288,7 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { if (!is_null($name)) throw new InvalidArgumentException('Don\'t specify a parameter name if you\'re passing a Sabre_VObject_Parameter. Add using $array[]=$parameterObject.'); - $value->parent = $this; + $value->parent = $this; $this->parameters[] = $value; } else { throw new InvalidArgumentException('You can only add parameters to the property object'); @@ -251,17 +297,16 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { } /** - * Removes one or more parameters with the specified name - * - * @param string $name - * @return void + * Removes one or more parameters with the specified name + * + * @param string $name + * @return void */ public function offsetUnset($name) { - if (is_int($name)) return parent::offsetUnset($name, $value); + if (is_int($name)) return parent::offsetUnset($name); $name = strtoupper($name); - - $result = array(); + foreach($this->parameters as $key=>$parameter) { if ($parameter->name == $name) { $parameter->parent = null; @@ -275,15 +320,29 @@ class Sabre_VObject_Property extends Sabre_VObject_Element { /* }}} */ /** - * Called when this object is being cast to a string - * - * @return string + * Called when this object is being cast to a string + * + * @return string */ public function __toString() { - return $this->value; + return (string)$this->value; } + /** + * This method is automatically called when the object is cloned. + * Specifically, this will ensure all child elements are also cloned. + * + * @return void + */ + public function __clone() { + + foreach($this->parameters as $key=>$child) { + $this->parameters[$key] = clone $child; + $this->parameters[$key]->parent = $this; + } + + } } diff --git a/3rdparty/Sabre/VObject/Property/DateTime.php b/3rdparty/Sabre/VObject/Property/DateTime.php new file mode 100755 index 00000000000..fe2372caa81 --- /dev/null +++ b/3rdparty/Sabre/VObject/Property/DateTime.php @@ -0,0 +1,260 @@ +<?php + +/** + * DateTime property + * + * This element is used for iCalendar properties such as the DTSTART property. + * It basically provides a few helper functions that make it easier to deal + * with these. It supports both DATE-TIME and DATE values. + * + * In order to use this correctly, you must call setDateTime and getDateTime to + * retrieve and modify dates respectively. + * + * If you use the 'value' or properties directly, this object does not keep + * reference and results might appear incorrectly. + * + * @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_Property_DateTime extends Sabre_VObject_Property { + + /** + * Local 'floating' time + */ + const LOCAL = 1; + + /** + * UTC-based time + */ + const UTC = 2; + + /** + * Local time plus timezone + */ + const LOCALTZ = 3; + + /** + * Only a date, time is ignored + */ + const DATE = 4; + + /** + * DateTime representation + * + * @var DateTime + */ + protected $dateTime; + + /** + * dateType + * + * @var int + */ + protected $dateType; + + /** + * Updates the Date and Time. + * + * @param DateTime $dt + * @param int $dateType + * @return void + */ + public function setDateTime(DateTime $dt, $dateType = self::LOCALTZ) { + + switch($dateType) { + + case self::LOCAL : + $this->setValue($dt->format('Ymd\\THis')); + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + $this->offsetSet('VALUE','DATE-TIME'); + break; + case self::UTC : + $dt->setTimeZone(new DateTimeZone('UTC')); + $this->setValue($dt->format('Ymd\\THis\\Z')); + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + $this->offsetSet('VALUE','DATE-TIME'); + break; + case self::LOCALTZ : + $this->setValue($dt->format('Ymd\\THis')); + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + $this->offsetSet('VALUE','DATE-TIME'); + $this->offsetSet('TZID', $dt->getTimeZone()->getName()); + break; + case self::DATE : + $this->setValue($dt->format('Ymd')); + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + $this->offsetSet('VALUE','DATE'); + break; + default : + throw new InvalidArgumentException('You must pass a valid dateType constant'); + + } + $this->dateTime = $dt; + $this->dateType = $dateType; + + } + + /** + * Returns the current DateTime value. + * + * If no value was set, this method returns null. + * + * @return DateTime|null + */ + public function getDateTime() { + + if ($this->dateTime) + return $this->dateTime; + + list( + $this->dateType, + $this->dateTime + ) = self::parseData($this->value, $this); + return $this->dateTime; + + } + + /** + * Returns the type of Date format. + * + * This method returns one of the format constants. If no date was set, + * this method will return null. + * + * @return int|null + */ + public function getDateType() { + + if ($this->dateType) + return $this->dateType; + + list( + $this->dateType, + $this->dateTime, + ) = self::parseData($this->value, $this); + return $this->dateType; + + } + + /** + * Parses the internal data structure to figure out what the current date + * and time is. + * + * The returned array contains two elements: + * 1. A 'DateType' constant (as defined on this class), or null. + * 2. A DateTime object (or null) + * + * @param string|null $propertyValue The string to parse (yymmdd or + * ymmddThhmmss, etc..) + * @param Sabre_VObject_Property|null $property The instance of the + * property we're parsing. + * @return array + */ + static public function parseData($propertyValue, Sabre_VObject_Property $property = null) { + + if (is_null($propertyValue)) { + return array(null, null); + } + + $date = '(?P<year>[1-2][0-9]{3})(?P<month>[0-1][0-9])(?P<date>[0-3][0-9])'; + $time = '(?P<hour>[0-2][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9])'; + $regex = "/^$date(T$time(?P<isutc>Z)?)?$/"; + + if (!preg_match($regex, $propertyValue, $matches)) { + throw new InvalidArgumentException($propertyValue . ' is not a valid DateTime or Date string'); + } + + if (!isset($matches['hour'])) { + // Date-only + return array( + self::DATE, + new DateTime($matches['year'] . '-' . $matches['month'] . '-' . $matches['date'] . ' 00:00:00'), + ); + } + + $dateStr = + $matches['year'] .'-' . + $matches['month'] . '-' . + $matches['date'] . ' ' . + $matches['hour'] . ':' . + $matches['minute'] . ':' . + $matches['second']; + + if (isset($matches['isutc'])) { + $dt = new DateTime($dateStr,new DateTimeZone('UTC')); + $dt->setTimeZone(new DateTimeZone('UTC')); + return array( + self::UTC, + $dt + ); + } + + // Finding the timezone. + $tzid = $property['TZID']; + if (!$tzid) { + return array( + self::LOCAL, + new DateTime($dateStr) + ); + } + + try { + // tzid an Olson identifier? + $tz = new DateTimeZone($tzid->value); + } catch (Exception $e) { + + // Not an Olson id, we're going to try to find the information + // through the time zone name map. + $newtzid = Sabre_VObject_WindowsTimezoneMap::lookup($tzid->value); + if (is_null($newtzid)) { + + // Not a well known time zone name either, we're going to try + // to find the information through the VTIMEZONE object. + + // First we find the root object + $root = $property; + while($root->parent) { + $root = $root->parent; + } + + if (isset($root->VTIMEZONE)) { + foreach($root->VTIMEZONE as $vtimezone) { + if (((string)$vtimezone->TZID) == $tzid) { + if (isset($vtimezone->{'X-LIC-LOCATION'})) { + $newtzid = (string)$vtimezone->{'X-LIC-LOCATION'}; + } else { + // No libical location specified. As a last resort we could + // try matching $vtimezone's DST rules against all known + // time zones returned by DateTimeZone::list* + + // TODO + } + } + } + } + } + + try { + $tz = new DateTimeZone($newtzid); + } catch (Exception $e) { + // If all else fails, we use the default PHP timezone + $tz = new DateTimeZone(date_default_timezone_get()); + } + } + $dt = new DateTime($dateStr, $tz); + $dt->setTimeZone($tz); + + return array( + self::LOCALTZ, + $dt + ); + + } + +} diff --git a/3rdparty/Sabre/VObject/Property/MultiDateTime.php b/3rdparty/Sabre/VObject/Property/MultiDateTime.php new file mode 100755 index 00000000000..ae53ab6a617 --- /dev/null +++ b/3rdparty/Sabre/VObject/Property/MultiDateTime.php @@ -0,0 +1,166 @@ +<?php + +/** + * Multi-DateTime property + * + * This element is used for iCalendar properties such as the EXDATE property. + * It basically provides a few helper functions that make it easier to deal + * with these. It supports both DATE-TIME and DATE values. + * + * In order to use this correctly, you must call setDateTimes and getDateTimes + * to retrieve and modify dates respectively. + * + * If you use the 'value' or properties directly, this object does not keep + * reference and results might appear incorrectly. + * + * @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_Property_MultiDateTime extends Sabre_VObject_Property { + + /** + * DateTime representation + * + * @var DateTime[] + */ + protected $dateTimes; + + /** + * dateType + * + * This is one of the Sabre_VObject_Property_DateTime constants. + * + * @var int + */ + protected $dateType; + + /** + * Updates the value + * + * @param array $dt Must be an array of DateTime objects. + * @param int $dateType + * @return void + */ + public function setDateTimes(array $dt, $dateType = Sabre_VObject_Property_DateTime::LOCALTZ) { + + foreach($dt as $i) + if (!$i instanceof DateTime) + throw new InvalidArgumentException('You must pass an array of DateTime objects'); + + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + switch($dateType) { + + case Sabre_VObject_Property_DateTime::LOCAL : + $val = array(); + foreach($dt as $i) { + $val[] = $i->format('Ymd\\THis'); + } + $this->setValue(implode(',',$val)); + $this->offsetSet('VALUE','DATE-TIME'); + break; + case Sabre_VObject_Property_DateTime::UTC : + $val = array(); + foreach($dt as $i) { + $i->setTimeZone(new DateTimeZone('UTC')); + $val[] = $i->format('Ymd\\THis\\Z'); + } + $this->setValue(implode(',',$val)); + $this->offsetSet('VALUE','DATE-TIME'); + break; + case Sabre_VObject_Property_DateTime::LOCALTZ : + $val = array(); + foreach($dt as $i) { + $val[] = $i->format('Ymd\\THis'); + } + $this->setValue(implode(',',$val)); + $this->offsetSet('VALUE','DATE-TIME'); + $this->offsetSet('TZID', $dt[0]->getTimeZone()->getName()); + break; + case Sabre_VObject_Property_DateTime::DATE : + $val = array(); + foreach($dt as $i) { + $val[] = $i->format('Ymd'); + } + $this->setValue(implode(',',$val)); + $this->offsetSet('VALUE','DATE'); + break; + default : + throw new InvalidArgumentException('You must pass a valid dateType constant'); + + } + $this->dateTimes = $dt; + $this->dateType = $dateType; + + } + + /** + * Returns the current DateTime value. + * + * If no value was set, this method returns null. + * + * @return array|null + */ + public function getDateTimes() { + + if ($this->dateTimes) + return $this->dateTimes; + + $dts = array(); + + if (!$this->value) { + $this->dateTimes = null; + $this->dateType = null; + return null; + } + + foreach(explode(',',$this->value) as $val) { + list( + $type, + $dt + ) = Sabre_VObject_Property_DateTime::parseData($val, $this); + $dts[] = $dt; + $this->dateType = $type; + } + $this->dateTimes = $dts; + return $this->dateTimes; + + } + + /** + * Returns the type of Date format. + * + * This method returns one of the format constants. If no date was set, + * this method will return null. + * + * @return int|null + */ + public function getDateType() { + + if ($this->dateType) + return $this->dateType; + + if (!$this->value) { + $this->dateTimes = null; + $this->dateType = null; + return null; + } + + $dts = array(); + foreach(explode(',',$this->value) as $val) { + list( + $type, + $dt + ) = Sabre_VObject_Property_DateTime::parseData($val, $this); + $dts[] = $dt; + $this->dateType = $type; + } + $this->dateTimes = $dts; + return $this->dateType; + + } + +} diff --git a/3rdparty/Sabre/VObject/Reader.php b/3rdparty/Sabre/VObject/Reader.php index 7d1c282838e..eea73fa3dce 100644..100755 --- a/3rdparty/Sabre/VObject/Reader.php +++ b/3rdparty/Sabre/VObject/Reader.php @@ -5,40 +5,22 @@ * * This class reads the vobject file, and returns a full element tree. * + * TODO: this class currently completely works 'statically'. This is pointless, + * and defeats OOP principals. Needs refactoring in a future version. * - * TODO: this class currently completely works 'statically'. This is pointless, - * and defeats OOP principals. Needs refaxtoring in a future version. - * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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_Reader { /** - * This array contains a list of Property names that are automatically - * mapped to specific class names. + * Parses the file and returns the top component * - * Adding to this list allows you to specify custom property classes, - * adding extra functionality. - * - * @var array - */ - static public $elementMap = array( - 'DTSTART' => 'Sabre_VObject_Element_DateTime', - 'DTEND' => 'Sabre_VObject_Element_DateTime', - 'COMPLETED' => 'Sabre_VObject_Element_DateTime', - 'DUE' => 'Sabre_VObject_Element_DateTime', - 'EXDATE' => 'Sabre_VObject_Element_MultiDateTime', - ); - - /** - * Parses the file and returns the top component - * - * @param string $data - * @return Sabre_VObject_Element + * @param string $data + * @return Sabre_VObject_Element */ static function read($data) { @@ -63,11 +45,11 @@ class Sabre_VObject_Reader { } unset($lines); - + reset($lines2); return self::readLine($lines2); - + } /** @@ -75,9 +57,9 @@ class Sabre_VObject_Reader { * * This method receives the full array of lines. The array pointer is used * to traverse. - * - * @param array $lines - * @return Sabre_VObject_Element + * + * @param array $lines + * @return Sabre_VObject_Element */ static private function readLine(&$lines) { @@ -88,22 +70,23 @@ class Sabre_VObject_Reader { // Components if (stripos($line,"BEGIN:")===0) { - // This is a component - $obj = new Sabre_VObject_Component(strtoupper(substr($line,6))); + $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) + if ($nextLine===false) throw new Sabre_VObject_ParseException('Invalid VObject. Document ended prematurely.'); } - // Checking component name of the 'END:' line. + // 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 . '"'); } @@ -117,7 +100,7 @@ class Sabre_VObject_Reader { //$result = preg_match('/(?P<name>[A-Z0-9-]+)(?:;(?P<parameters>^(?<!:):))(.*)$/',$line,$matches); - $token = '[A-Z0-9-\/\.]+'; + $token = '[A-Z0-9-\.]+'; $parameters = "(?:;(?P<parameters>([^:^\"]|\"([^\"]*)\")*))?"; $regex = "/^(?P<name>$token)$parameters:(?P<value>.*)$/i"; @@ -128,22 +111,23 @@ class Sabre_VObject_Reader { } $propertyName = strtoupper($matches['name']); - $propertyValue = stripcslashes($matches['value']); - - if (isset(self::$elementMap[$propertyName])) { - $className = self::$elementMap[$propertyName]; - } else { - $className = 'Sabre_VObject_Property'; - } + $propertyValue = preg_replace_callback('#(\\\\(\\\\|N|n|;|,))#',function($matches) { + if ($matches[2]==='n' || $matches[2]==='N') { + return "\n"; + } else { + return $matches[2]; + } + }, $matches['value']); - $obj = new $className($propertyName, $propertyValue); + $obj = Sabre_VObject_Property::create($propertyName, $propertyValue); if ($matches['parameters']) { foreach(self::readParameters($matches['parameters']) as $param) { $obj->add($param); } - } + + } return $obj; @@ -151,12 +135,12 @@ class Sabre_VObject_Reader { } /** - * Reads a parameter list from a property + * Reads a parameter list from a property * * This method returns an array of Sabre_VObject_Parameter * - * @param string $parameters - * @return array + * @param string $parameters + * @return array */ static private function readParameters($parameters) { @@ -179,7 +163,15 @@ class Sabre_VObject_Reader { $value = ''; } - $params[] = new Sabre_VObject_Parameter($match['paramName'], stripcslashes($value)); + $value = preg_replace_callback('#(\\\\(\\\\|N|n|;|,))#',function($matches) { + if ($matches[2]==='n' || $matches[2]==='N') { + return "\n"; + } else { + return $matches[2]; + } + }, $value); + + $params[] = new Sabre_VObject_Parameter($match['paramName'], $value); } diff --git a/3rdparty/Sabre/VObject/RecurrenceIterator.php b/3rdparty/Sabre/VObject/RecurrenceIterator.php new file mode 100755 index 00000000000..833aa091ab7 --- /dev/null +++ b/3rdparty/Sabre/VObject/RecurrenceIterator.php @@ -0,0 +1,1009 @@ +<?php + +/** + * This class is used to determine new for a recurring event, when the next + * events occur. + * + * This iterator may loop infinitely in the future, therefore it is important + * that if you use this class, you set hard limits for the amount of iterations + * you want to handle. + * + * Note that currently there is not full support for the entire iCalendar + * specification, as it's very complex and contains a lot of permutations + * that's not yet used very often in software. + * + * For the focus has been on features as they actually appear in Calendaring + * software, but this may well get expanded as needed / on demand + * + * The following RRULE properties are supported + * * UNTIL + * * INTERVAL + * * COUNT + * * FREQ=DAILY + * * BYDAY + * * FREQ=WEEKLY + * * BYDAY + * * WKST + * * FREQ=MONTHLY + * * BYMONTHDAY + * * BYDAY + * * BYSETPOS + * * FREQ=YEARLY + * * BYMONTH + * * BYMONTHDAY (only if BYMONTH is also set) + * * BYDAY (only if BYMONTH is also set) + * + * Anything beyond this is 'undefined', which means that it may get ignored, or + * you may get unexpected results. The effect is that in some applications the + * specified recurrence may look incorrect, or is missing. + * + * @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_RecurrenceIterator implements Iterator { + + /** + * The initial event date + * + * @var DateTime + */ + public $startDate; + + /** + * The end-date of the initial event + * + * @var DateTime + */ + public $endDate; + + /** + * The 'current' recurrence. + * + * This will be increased for every iteration. + * + * @var DateTime + */ + public $currentDate; + + + /** + * List of dates that are excluded from the rules. + * + * This list contains the items that have been overriden by the EXDATE + * property. + * + * @var array + */ + public $exceptionDates = array(); + + /** + * Base event + * + * @var Sabre_VObject_Component_VEvent + */ + public $baseEvent; + + /** + * List of dates that are overridden by other events. + * Similar to $overriddenEvents, but this just contains the original dates. + * + * @var array + */ + public $overriddenDates = array(); + + /** + * list of events that are 'overridden'. + * + * This is an array of Sabre_VObject_Component_VEvent objects. + * + * @var array + */ + public $overriddenEvents = array(); + + + /** + * Frequency is one of: secondly, minutely, hourly, daily, weekly, monthly, + * yearly. + * + * @var string + */ + public $frequency; + + /** + * The last instance of this recurrence, inclusively + * + * @var DateTime|null + */ + public $until; + + /** + * The number of recurrences, or 'null' if infinitely recurring. + * + * @var int + */ + public $count; + + /** + * The interval. + * + * If for example frequency is set to daily, interval = 2 would mean every + * 2 days. + * + * @var int + */ + public $interval = 1; + + /** + * Which seconds to recur. + * + * This is an array of integers (between 0 and 60) + * + * @var array + */ + public $bySecond; + + /** + * Which minutes to recur + * + * This is an array of integers (between 0 and 59) + * + * @var array + */ + public $byMinute; + + /** + * Which hours to recur + * + * This is an array of integers (between 0 and 23) + * + * @var array + */ + public $byHour; + + /** + * Which weekdays to recur. + * + * This is an array of weekdays + * + * This may also be preceeded by a positive or negative integer. If present, + * this indicates the nth occurrence of a specific day within the monthly or + * yearly rrule. For instance, -2TU indicates the second-last tuesday of + * the month, or year. + * + * @var array + */ + public $byDay; + + /** + * Which days of the month to recur + * + * This is an array of days of the months (1-31). The value can also be + * negative. -5 for instance means the 5th last day of the month. + * + * @var array + */ + public $byMonthDay; + + /** + * Which days of the year to recur. + * + * This is an array with days of the year (1 to 366). The values can also + * be negative. For instance, -1 will always represent the last day of the + * year. (December 31st). + * + * @var array + */ + public $byYearDay; + + /** + * Which week numbers to recur. + * + * This is an array of integers from 1 to 53. The values can also be + * negative. -1 will always refer to the last week of the year. + * + * @var array + */ + public $byWeekNo; + + /** + * Which months to recur + * + * This is an array of integers from 1 to 12. + * + * @var array + */ + public $byMonth; + + /** + * Which items in an existing st to recur. + * + * These numbers work together with an existing by* rule. It specifies + * exactly which items of the existing by-rule to filter. + * + * Valid values are 1 to 366 and -1 to -366. As an example, this can be + * used to recur the last workday of the month. + * + * This would be done by setting frequency to 'monthly', byDay to + * 'MO,TU,WE,TH,FR' and bySetPos to -1. + * + * @var array + */ + public $bySetPos; + + /** + * When a week starts + * + * @var string + */ + public $weekStart = 'MO'; + + /** + * The current item in the list + * + * @var int + */ + public $counter = 0; + + /** + * Simple mapping from iCalendar day names to day numbers + * + * @var array + */ + private $dayMap = array( + 'SU' => 0, + 'MO' => 1, + 'TU' => 2, + 'WE' => 3, + 'TH' => 4, + 'FR' => 5, + 'SA' => 6, + ); + + /** + * Mappings between the day number and english day name. + * + * @var array + */ + private $dayNames = array( + 0 => 'Sunday', + 1 => 'Monday', + 2 => 'Tuesday', + 3 => 'Wednesday', + 4 => 'Thursday', + 5 => 'Friday', + 6 => 'Saturday', + ); + + /** + * If the current iteration of the event is an overriden event, this + * property will hold the VObject + * + * @var Sabre_Component_VObject + */ + private $currentOverriddenEvent; + + /** + * This property may contain the date of the next not-overridden event. + * This date is calculated sometimes a bit early, before overridden events + * are evaluated. + * + * @var DateTime + */ + private $nextDate; + + /** + * 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 $vcal + * @param string|null $uid + */ + 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()); + + } + + } + + } + + } + + /** + * Returns the current item in the list + * + * @return DateTime + */ + public function current() { + + if (!$this->valid()) return null; + return clone $this->currentDate; + + } + + /** + * This method returns the startdate for the current iteration of the + * event. + * + * @return DateTime + */ + public function getDtStart() { + + if (!$this->valid()) return null; + return clone $this->currentDate; + + } + + /** + * This method returns the enddate for the current iteration of the + * event. + * + * @return DateTime + */ + public function getDtEnd() { + + if (!$this->valid()) return null; + $dtEnd = clone $this->currentDate; + $dtEnd->add( $this->startDate->diff( $this->endDate ) ); + return clone $dtEnd; + + } + + /** + * Returns a VEVENT object with the updated start and end date. + * + * Any recurrence information is removed, and this function may return an + * 'overridden' event instead. + * + * This method always returns a cloned instance. + * + * @return void + */ + public function getEventObject() { + + if ($this->currentOverriddenEvent) { + return clone $this->currentOverriddenEvent; + } + $event = clone $this->baseEvent; + unset($event->RRULE); + unset($event->EXDATE); + unset($event->RDATE); + unset($event->EXRULE); + + $event->DTSTART->setDateTime($this->getDTStart(), $event->DTSTART->getDateType()); + if (isset($event->DTEND)) { + $event->DTEND->setDateTime($this->getDtEnd(), $event->DTSTART->getDateType()); + } + if ($this->counter > 0) { + $event->{'RECURRENCE-ID'} = (string)$event->DTSTART; + } + + return $event; + + } + + /** + * Returns the current item number + * + * @return int + */ + public function key() { + + return $this->counter; + + } + + /** + * Whether or not there is a 'next item' + * + * @return bool + */ + public function valid() { + + if (!is_null($this->count)) { + return $this->counter < $this->count; + } + if (!is_null($this->until)) { + return $this->currentDate <= $this->until; + } + return true; + + } + + /** + * Resets the iterator + * + * @return void + */ + public function rewind() { + + $this->currentDate = clone $this->startDate; + $this->counter = 0; + + } + + /** + * This method allows you to quickly go to the next occurrence after the + * specified date. + * + * Note that this checks the current 'endDate', not the 'stardDate'. This + * means that if you forward to January 1st, the iterator will stop at the + * first event that ends *after* January 1st. + * + * @param DateTime $dt + * @return void + */ + public function fastForward(DateTime $dt) { + + while($this->valid() && $this->getDTEnd() < $dt) { + $this->next(); + } + + } + + /** + * Goes on to the next iteration + * + * @return void + */ + public function next() { + + /* + if (!is_null($this->count) && $this->counter >= $this->count) { + $this->currentDate = null; + }*/ + + + $previousStamp = $this->currentDate->getTimeStamp(); + + while(true) { + + $this->currentOverriddenEvent = null; + + // If we have a next date 'stored', we use that + if ($this->nextDate) { + $this->currentDate = $this->nextDate; + $currentStamp = $this->currentDate->getTimeStamp(); + $this->nextDate = null; + } else { + + // Otherwise, we calculate it + switch($this->frequency) { + + case 'daily' : + $this->nextDaily(); + break; + + case 'weekly' : + $this->nextWeekly(); + break; + + case 'monthly' : + $this->nextMonthly(); + break; + + case 'yearly' : + $this->nextYearly(); + break; + + } + $currentStamp = $this->currentDate->getTimeStamp(); + + // Checking exception dates + foreach($this->exceptionDates as $exceptionDate) { + if ($this->currentDate == $exceptionDate) { + $this->counter++; + continue 2; + } + } + foreach($this->overriddenDates as $overriddenDate) { + if ($this->currentDate == $overriddenDate) { + continue 2; + } + } + + } + + // Checking overriden events + foreach($this->overriddenEvents as $index=>$event) { + if ($index > $previousStamp && $index <= $currentStamp) { + + // We're moving the 'next date' aside, for later use. + $this->nextDate = clone $this->currentDate; + + $this->currentDate = $event->DTSTART->getDateTime(); + $this->currentOverriddenEvent = $event; + + break; + } + } + + break; + + } + + /* + if (!is_null($this->until)) { + if($this->currentDate > $this->until) { + $this->currentDate = null; + } + }*/ + + $this->counter++; + + } + + /** + * Does the processing for advancing the iterator for daily frequency. + * + * @return void + */ + protected function nextDaily() { + + if (!$this->byDay) { + $this->currentDate->modify('+' . $this->interval . ' days'); + return; + } + + $recurrenceDays = array(); + foreach($this->byDay as $byDay) { + + // The day may be preceeded with a positive (+n) or + // negative (-n) integer. However, this does not make + // sense in 'weekly' so we ignore it here. + $recurrenceDays[] = $this->dayMap[substr($byDay,-2)]; + + } + + do { + + $this->currentDate->modify('+' . $this->interval . ' days'); + + // Current day of the week + $currentDay = $this->currentDate->format('w'); + + } while (!in_array($currentDay, $recurrenceDays)); + + } + + /** + * Does the processing for advancing the iterator for weekly frequency. + * + * @return void + */ + protected function nextWeekly() { + + if (!$this->byDay) { + $this->currentDate->modify('+' . $this->interval . ' weeks'); + return; + } + + $recurrenceDays = array(); + foreach($this->byDay as $byDay) { + + // The day may be preceeded with a positive (+n) or + // negative (-n) integer. However, this does not make + // sense in 'weekly' so we ignore it here. + $recurrenceDays[] = $this->dayMap[substr($byDay,-2)]; + + } + + // Current day of the week + $currentDay = $this->currentDate->format('w'); + + // First day of the week: + $firstDay = $this->dayMap[$this->weekStart]; + + $time = array( + $this->currentDate->format('H'), + $this->currentDate->format('i'), + $this->currentDate->format('s') + ); + + // Increasing the 'current day' until we find our next + // occurrence. + while(true) { + + $currentDay++; + + if ($currentDay>6) { + $currentDay = 0; + } + + // We need to roll over to the next week + if ($currentDay === $firstDay) { + $this->currentDate->modify('+' . $this->interval . ' weeks'); + + // We need to go to the first day of this week, but only if we + // are not already on this first day of this week. + if($this->currentDate->format('w') != $firstDay) { + $this->currentDate->modify('last ' . $this->dayNames[$this->dayMap[$this->weekStart]]); + $this->currentDate->setTime($time[0],$time[1],$time[2]); + } + } + + // We have a match + if (in_array($currentDay ,$recurrenceDays)) { + $this->currentDate->modify($this->dayNames[$currentDay]); + $this->currentDate->setTime($time[0],$time[1],$time[2]); + break; + } + + } + + } + + /** + * Does the processing for advancing the iterator for monthly frequency. + * + * @return void + */ + protected function nextMonthly() { + + $currentDayOfMonth = $this->currentDate->format('j'); + if (!$this->byMonthDay && !$this->byDay) { + + // If the current day is higher than the 28th, rollover can + // occur to the next month. We Must skip these invalid + // entries. + if ($currentDayOfMonth < 29) { + $this->currentDate->modify('+' . $this->interval . ' months'); + } else { + $increase = 0; + do { + $increase++; + $tempDate = clone $this->currentDate; + $tempDate->modify('+ ' . ($this->interval*$increase) . ' months'); + } while ($tempDate->format('j') != $currentDayOfMonth); + $this->currentDate = $tempDate; + } + return; + } + + while(true) { + + $occurrences = $this->getMonthlyOccurrences(); + + foreach($occurrences as $occurrence) { + + // The first occurrence thats higher than the current + // day of the month wins. + if ($occurrence > $currentDayOfMonth) { + break 2; + } + + } + + // If we made it all the way here, it means there were no + // valid occurrences, and we need to advance to the next + // month. + $this->currentDate->modify('first day of this month'); + $this->currentDate->modify('+ ' . $this->interval . ' months'); + + // This goes to 0 because we need to start counting at hte + // beginning. + $currentDayOfMonth = 0; + + } + + $this->currentDate->setDate($this->currentDate->format('Y'), $this->currentDate->format('n'), $occurrence); + + } + + /** + * Does the processing for advancing the iterator for yearly frequency. + * + * @return void + */ + protected function nextYearly() { + + if (!$this->byMonth) { + $this->currentDate->modify('+' . $this->interval . ' years'); + return; + } + + $currentMonth = $this->currentDate->format('n'); + $currentYear = $this->currentDate->format('Y'); + $currentDayOfMonth = $this->currentDate->format('j'); + + $advancedToNewMonth = false; + + // If we got a byDay or getMonthDay filter, we must first expand + // further. + if ($this->byDay || $this->byMonthDay) { + + while(true) { + + $occurrences = $this->getMonthlyOccurrences(); + + foreach($occurrences as $occurrence) { + + // The first occurrence that's higher than the current + // day of the month wins. + // If we advanced to the next month or year, the first + // occurence is always correct. + if ($occurrence > $currentDayOfMonth || $advancedToNewMonth) { + break 2; + } + + } + + // If we made it here, it means we need to advance to + // the next month or year. + $currentDayOfMonth = 1; + $advancedToNewMonth = true; + do { + + $currentMonth++; + if ($currentMonth>12) { + $currentYear+=$this->interval; + $currentMonth = 1; + } + } while (!in_array($currentMonth, $this->byMonth)); + + $this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth); + + } + + // If we made it here, it means we got a valid occurrence + $this->currentDate->setDate($currentYear, $currentMonth, $occurrence); + return; + + } else { + + // no byDay or byMonthDay, so we can just loop through the + // months. + do { + + $currentMonth++; + if ($currentMonth>12) { + $currentYear+=$this->interval; + $currentMonth = 1; + } + } while (!in_array($currentMonth, $this->byMonth)); + $this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth); + return; + + } + + } + + /** + * Returns all the occurrences for a monthly frequency with a 'byDay' or + * 'byMonthDay' expansion for the current month. + * + * The returned list is an array of integers with the day of month (1-31). + * + * @return array + */ + protected function getMonthlyOccurrences() { + + $startDate = clone $this->currentDate; + + $byDayResults = array(); + + // Our strategy is to simply go through the byDays, advance the date to + // that point and add it to the results. + if ($this->byDay) foreach($this->byDay as $day) { + + $dayName = $this->dayNames[$this->dayMap[substr($day,-2)]]; + + // Dayname will be something like 'wednesday'. Now we need to find + // all wednesdays in this month. + $dayHits = array(); + + $checkDate = clone $startDate; + $checkDate->modify('first day of this month'); + $checkDate->modify($dayName); + + do { + $dayHits[] = $checkDate->format('j'); + $checkDate->modify('next ' . $dayName); + } while ($checkDate->format('n') === $startDate->format('n')); + + // So now we have 'all wednesdays' for month. It is however + // possible that the user only really wanted the 1st, 2nd or last + // wednesday. + if (strlen($day)>2) { + $offset = (int)substr($day,0,-2); + + if ($offset>0) { + // It is possible that the day does not exist, such as a + // 5th or 6th wednesday of the month. + if (isset($dayHits[$offset-1])) { + $byDayResults[] = $dayHits[$offset-1]; + } + } else { + + // if it was negative we count from the end of the array + $byDayResults[] = $dayHits[count($dayHits) + $offset]; + } + } else { + // There was no counter (first, second, last wednesdays), so we + // just need to add the all to the list). + $byDayResults = array_merge($byDayResults, $dayHits); + + } + + } + + $byMonthDayResults = array(); + if ($this->byMonthDay) foreach($this->byMonthDay as $monthDay) { + + // Removing values that are out of range for this month + if ($monthDay > $startDate->format('t') || + $monthDay < 0-$startDate->format('t')) { + continue; + } + if ($monthDay>0) { + $byMonthDayResults[] = $monthDay; + } else { + // Negative values + $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay; + } + } + + // If there was just byDay or just byMonthDay, they just specify our + // (almost) final list. If both were provided, then byDay limits the + // list. + if ($this->byMonthDay && $this->byDay) { + $result = array_intersect($byMonthDayResults, $byDayResults); + } elseif ($this->byMonthDay) { + $result = $byMonthDayResults; + } else { + $result = $byDayResults; + } + $result = array_unique($result); + sort($result, SORT_NUMERIC); + + // The last thing that needs checking is the BYSETPOS. If it's set, it + // means only certain items in the set survive the filter. + if (!$this->bySetPos) { + return $result; + } + + $filteredResult = array(); + foreach($this->bySetPos as $setPos) { + + if ($setPos<0) { + $setPos = count($result)-($setPos+1); + } + if (isset($result[$setPos-1])) { + $filteredResult[] = $result[$setPos-1]; + } + } + + sort($filteredResult, SORT_NUMERIC); + return $filteredResult; + + } + + +} + diff --git a/3rdparty/Sabre/VObject/Version.php b/3rdparty/Sabre/VObject/Version.php index 937c367e222..00110febc07 100644..100755 --- a/3rdparty/Sabre/VObject/Version.php +++ b/3rdparty/Sabre/VObject/Version.php @@ -2,10 +2,10 @@ /** * This class contains the version number for the VObject package - * + * * @package Sabre - * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. + * @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 */ @@ -14,7 +14,7 @@ class Sabre_VObject_Version { /** * Full version number */ - const VERSION = '1.2.4'; + const VERSION = '1.3.2'; /** * Stability : alpha, beta, stable diff --git a/3rdparty/Sabre/VObject/WindowsTimezoneMap.php b/3rdparty/Sabre/VObject/WindowsTimezoneMap.php new file mode 100755 index 00000000000..5e1cc5d479b --- /dev/null +++ b/3rdparty/Sabre/VObject/WindowsTimezoneMap.php @@ -0,0 +1,128 @@ +<?php + +/** + * Time zone name translation + * + * This file translates well-known time zone names into "Olson database" time zone names. + * + * @package Sabre + * @subpackage VObject + * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved. + * @author Frank Edelhaeuser (fedel@users.sourceforge.net) + * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License + */ +class Sabre_VObject_WindowsTimezoneMap { + + protected static $map = array( + + // from http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html + // snapshot taken on 2012/01/16 + + // windows + 'AUS Central Standard Time'=>'Australia/Darwin', + 'AUS Eastern Standard Time'=>'Australia/Sydney', + 'Afghanistan Standard Time'=>'Asia/Kabul', + 'Alaskan Standard Time'=>'America/Anchorage', + 'Arab Standard Time'=>'Asia/Riyadh', + 'Arabian Standard Time'=>'Asia/Dubai', + 'Arabic Standard Time'=>'Asia/Baghdad', + 'Argentina Standard Time'=>'America/Buenos_Aires', + 'Armenian Standard Time'=>'Asia/Yerevan', + 'Atlantic Standard Time'=>'America/Halifax', + 'Azerbaijan Standard Time'=>'Asia/Baku', + 'Azores Standard Time'=>'Atlantic/Azores', + 'Bangladesh Standard Time'=>'Asia/Dhaka', + 'Canada Central Standard Time'=>'America/Regina', + 'Cape Verde Standard Time'=>'Atlantic/Cape_Verde', + 'Caucasus Standard Time'=>'Asia/Yerevan', + 'Cen. Australia Standard Time'=>'Australia/Adelaide', + 'Central America Standard Time'=>'America/Guatemala', + 'Central Asia Standard Time'=>'Asia/Almaty', + 'Central Brazilian Standard Time'=>'America/Cuiaba', + 'Central Europe Standard Time'=>'Europe/Budapest', + 'Central European Standard Time'=>'Europe/Warsaw', + 'Central Pacific Standard Time'=>'Pacific/Guadalcanal', + 'Central Standard Time'=>'America/Chicago', + 'Central Standard Time (Mexico)'=>'America/Mexico_City', + 'China Standard Time'=>'Asia/Shanghai', + 'Dateline Standard Time'=>'Etc/GMT+12', + 'E. Africa Standard Time'=>'Africa/Nairobi', + 'E. Australia Standard Time'=>'Australia/Brisbane', + 'E. Europe Standard Time'=>'Europe/Minsk', + 'E. South America Standard Time'=>'America/Sao_Paulo', + 'Eastern Standard Time'=>'America/New_York', + 'Egypt Standard Time'=>'Africa/Cairo', + 'Ekaterinburg Standard Time'=>'Asia/Yekaterinburg', + 'FLE Standard Time'=>'Europe/Kiev', + 'Fiji Standard Time'=>'Pacific/Fiji', + 'GMT Standard Time'=>'Europe/London', + 'GTB Standard Time'=>'Europe/Istanbul', + 'Georgian Standard Time'=>'Asia/Tbilisi', + 'Greenland Standard Time'=>'America/Godthab', + 'Greenwich Standard Time'=>'Atlantic/Reykjavik', + 'Hawaiian Standard Time'=>'Pacific/Honolulu', + 'India Standard Time'=>'Asia/Calcutta', + 'Iran Standard Time'=>'Asia/Tehran', + 'Israel Standard Time'=>'Asia/Jerusalem', + 'Jordan Standard Time'=>'Asia/Amman', + 'Kamchatka Standard Time'=>'Asia/Kamchatka', + 'Korea Standard Time'=>'Asia/Seoul', + 'Magadan Standard Time'=>'Asia/Magadan', + 'Mauritius Standard Time'=>'Indian/Mauritius', + 'Mexico Standard Time'=>'America/Mexico_City', + 'Mexico Standard Time 2'=>'America/Chihuahua', + 'Mid-Atlantic Standard Time'=>'Etc/GMT+2', + 'Middle East Standard Time'=>'Asia/Beirut', + 'Montevideo Standard Time'=>'America/Montevideo', + 'Morocco Standard Time'=>'Africa/Casablanca', + 'Mountain Standard Time'=>'America/Denver', + 'Mountain Standard Time (Mexico)'=>'America/Chihuahua', + 'Myanmar Standard Time'=>'Asia/Rangoon', + 'N. Central Asia Standard Time'=>'Asia/Novosibirsk', + 'Namibia Standard Time'=>'Africa/Windhoek', + 'Nepal Standard Time'=>'Asia/Katmandu', + 'New Zealand Standard Time'=>'Pacific/Auckland', + 'Newfoundland Standard Time'=>'America/St_Johns', + 'North Asia East Standard Time'=>'Asia/Irkutsk', + 'North Asia Standard Time'=>'Asia/Krasnoyarsk', + 'Pacific SA Standard Time'=>'America/Santiago', + 'Pacific Standard Time'=>'America/Los_Angeles', + 'Pacific Standard Time (Mexico)'=>'America/Santa_Isabel', + 'Pakistan Standard Time'=>'Asia/Karachi', + 'Paraguay Standard Time'=>'America/Asuncion', + 'Romance Standard Time'=>'Europe/Paris', + 'Russian Standard Time'=>'Europe/Moscow', + 'SA Eastern Standard Time'=>'America/Cayenne', + 'SA Pacific Standard Time'=>'America/Bogota', + 'SA Western Standard Time'=>'America/La_Paz', + 'SE Asia Standard Time'=>'Asia/Bangkok', + 'Samoa Standard Time'=>'Pacific/Apia', + 'Singapore Standard Time'=>'Asia/Singapore', + 'South Africa Standard Time'=>'Africa/Johannesburg', + 'Sri Lanka Standard Time'=>'Asia/Colombo', + 'Syria Standard Time'=>'Asia/Damascus', + 'Taipei Standard Time'=>'Asia/Taipei', + 'Tasmania Standard Time'=>'Australia/Hobart', + 'Tokyo Standard Time'=>'Asia/Tokyo', + 'Tonga Standard Time'=>'Pacific/Tongatapu', + 'US Eastern Standard Time'=>'America/Indianapolis', + 'US Mountain Standard Time'=>'America/Phoenix', + 'UTC'=>'Etc/GMT', + 'UTC+12'=>'Etc/GMT-12', + 'UTC-02'=>'Etc/GMT+2', + 'UTC-11'=>'Etc/GMT+11', + 'Ulaanbaatar Standard Time'=>'Asia/Ulaanbaatar', + 'Venezuela Standard Time'=>'America/Caracas', + 'Vladivostok Standard Time'=>'Asia/Vladivostok', + 'W. Australia Standard Time'=>'Australia/Perth', + 'W. Central Africa Standard Time'=>'Africa/Lagos', + 'W. Europe Standard Time'=>'Europe/Berlin', + 'West Asia Standard Time'=>'Asia/Tashkent', + 'West Pacific Standard Time'=>'Pacific/Port_Moresby', + 'Yakutsk Standard Time'=>'Asia/Yakutsk', + ); + + static public function lookup($tzid) { + return isset(self::$map[$tzid]) ? self::$map[$tzid] : null; + } +} diff --git a/3rdparty/Sabre/VObject/includes.php b/3rdparty/Sabre/VObject/includes.php index f21010fb275..0177a8f1ba6 100644..100755 --- a/3rdparty/Sabre/VObject/includes.php +++ b/3rdparty/Sabre/VObject/includes.php @@ -1,29 +1,41 @@ <?php /** - * VObject includes + * Sabre_VObject includes file * - * This file automatically includes all VObject classes + * Including this file will automatically include all files from the VObject + * package. + * + * This often allows faster loadtimes, as autoload-speed is often quite slow. * * @package Sabre * @subpackage VObject - * @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved. - * @author Evert Pot (http://www.rooftopsolutions.nl/) + * @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 */ - -include dirname(__FILE__) . '/ParseException.php'; - -include dirname(__FILE__) . '/Node.php'; -include dirname(__FILE__) . '/Element.php'; -include dirname(__FILE__) . '/ElementList.php'; -include dirname(__FILE__) . '/Parameter.php'; -include dirname(__FILE__) . '/Property.php'; -include dirname(__FILE__) . '/Component.php'; - -include dirname(__FILE__) . '/Element/DateTime.php'; -include dirname(__FILE__) . '/Element/MultiDateTime.php'; - -include dirname(__FILE__) . '/Reader.php'; -include dirname(__FILE__) . '/Version.php'; +// Begin includes +include __DIR__ . '/DateTimeParser.php'; +include __DIR__ . '/ElementList.php'; +include __DIR__ . '/FreeBusyGenerator.php'; +include __DIR__ . '/Node.php'; +include __DIR__ . '/Parameter.php'; +include __DIR__ . '/ParseException.php'; +include __DIR__ . '/Reader.php'; +include __DIR__ . '/RecurrenceIterator.php'; +include __DIR__ . '/Version.php'; +include __DIR__ . '/WindowsTimezoneMap.php'; +include __DIR__ . '/Element.php'; +include __DIR__ . '/Property.php'; +include __DIR__ . '/Component.php'; +include __DIR__ . '/Property/DateTime.php'; +include __DIR__ . '/Property/MultiDateTime.php'; +include __DIR__ . '/Component/VAlarm.php'; +include __DIR__ . '/Component/VCalendar.php'; +include __DIR__ . '/Component/VEvent.php'; +include __DIR__ . '/Component/VJournal.php'; +include __DIR__ . '/Component/VTodo.php'; +include __DIR__ . '/Element/DateTime.php'; +include __DIR__ . '/Element/MultiDateTime.php'; +// End includes |