mirror of
https://git.friendi.ca/friendica/friendica-addons.git
synced 2025-07-07 17:08:48 +00:00
Second part of refactoring; should be runnable again, yet not thoroughly tested
This commit is contained in:
parent
b8234a1cb8
commit
6186153f68
88 changed files with 2135 additions and 1186 deletions
412
dav/sabre-vobject/lib/Sabre/VObject/Component.php
Normal file
412
dav/sabre-vobject/lib/Sabre/VObject/Component.php
Normal file
|
@ -0,0 +1,412 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* ends with END:COMPONENTNAME
|
||||
*
|
||||
* @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 Component extends Element {
|
||||
|
||||
/**
|
||||
* Name, for example VEVENT
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Children properties and components
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $children = array();
|
||||
|
||||
/**
|
||||
* The following constants are used by the validate() method.
|
||||
*/
|
||||
const REPAIR = 1;
|
||||
|
||||
/**
|
||||
* If components 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(
|
||||
'VALARM' => 'Sabre\\VObject\\Component\\VAlarm',
|
||||
'VCALENDAR' => 'Sabre\\VObject\\Component\\VCalendar',
|
||||
'VCARD' => 'Sabre\\VObject\\Component\\VCard',
|
||||
'VEVENT' => 'Sabre\\VObject\\Component\\VEvent',
|
||||
'VJOURNAL' => 'Sabre\\VObject\\Component\\VJournal',
|
||||
'VTODO' => 'Sabre\\VObject\\Component\\VTodo',
|
||||
);
|
||||
|
||||
/**
|
||||
* 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 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
|
||||
* be overridden with the iterator argument
|
||||
*
|
||||
* @param string $name
|
||||
* @param ElementList $iterator
|
||||
*/
|
||||
public function __construct($name, ElementList $iterator = null) {
|
||||
|
||||
$this->name = strtoupper($name);
|
||||
if (!is_null($iterator)) $this->iterator = $iterator;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 lower in the list.
|
||||
* To avoid score collisions, each "score category" has a reasonable
|
||||
* space to accomodate elements. The $key is added to the $score to
|
||||
* preserve the original relative order of elements.
|
||||
*
|
||||
* @param int $key
|
||||
* @param array $array
|
||||
* @return int
|
||||
*/
|
||||
$sortScore = function($key, $array) {
|
||||
|
||||
if ($array[$key] instanceof Component) {
|
||||
|
||||
// We want to encode VTIMEZONE first, this is a personal
|
||||
// preference.
|
||||
if ($array[$key]->name === 'VTIMEZONE') {
|
||||
$score=300000000;
|
||||
return $score+$key;
|
||||
} else {
|
||||
$score=400000000;
|
||||
return $score+$key;
|
||||
}
|
||||
} else {
|
||||
// Properties get encoded first
|
||||
// VCARD version 4.0 wants the VERSION property to appear first
|
||||
if ($array[$key] instanceof Property) {
|
||||
if ($array[$key]->name === 'VERSION') {
|
||||
$score=100000000;
|
||||
return $score+$key;
|
||||
} else {
|
||||
// All other properties
|
||||
$score=200000000;
|
||||
return $score+$key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$tmp = $this->children;
|
||||
uksort($this->children, function($a, $b) use ($sortScore, $tmp) {
|
||||
|
||||
$sA = $sortScore($a, $tmp);
|
||||
$sB = $sortScore($b, $tmp);
|
||||
|
||||
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 component or element
|
||||
*
|
||||
* You can call this method with the following syntaxes:
|
||||
*
|
||||
* add(Element $element)
|
||||
* add(string $name, $value, array $parameters = array())
|
||||
*
|
||||
* The first version adds an Element
|
||||
* The second adds a property as a string.
|
||||
*
|
||||
* @param mixed $item
|
||||
* @param mixed $itemValue
|
||||
* @return void
|
||||
*/
|
||||
public function add($item, $itemValue = null, array $parameters = array()) {
|
||||
|
||||
if ($item instanceof Element) {
|
||||
if (!is_null($itemValue)) {
|
||||
throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject');
|
||||
}
|
||||
$item->parent = $this;
|
||||
$this->children[] = $item;
|
||||
} elseif(is_string($item)) {
|
||||
|
||||
if (!is_scalar($itemValue)) {
|
||||
throw new \InvalidArgumentException('The second argument must be scalar');
|
||||
}
|
||||
$item = Property::create($item,$itemValue, $parameters);
|
||||
$item->parent = $this;
|
||||
$this->children[] = $item;
|
||||
|
||||
} else {
|
||||
|
||||
throw new \InvalidArgumentException('The first argument must either be a \\Sabre\\VObject\\Element or a string');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable list of children
|
||||
*
|
||||
* @return ElementList
|
||||
*/
|
||||
public function children() {
|
||||
|
||||
return new ElementList($this->children);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* has not been assigned a group, specify ".EMAIL".
|
||||
*
|
||||
* Keys are retained from the 'children' array, which may be confusing in
|
||||
* certain cases.
|
||||
*
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
public function select($name) {
|
||||
|
||||
$group = null;
|
||||
$name = strtoupper($name);
|
||||
if (strpos($name,'.')!==false) {
|
||||
list($group,$name) = explode('.', $name, 2);
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach($this->children as $key=>$child) {
|
||||
|
||||
if (
|
||||
strtoupper($child->name) === $name &&
|
||||
(is_null($group) || ( $child instanceof Property && strtoupper($child->group) === $group))
|
||||
) {
|
||||
|
||||
$result[$key] = $child;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
reset($result);
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Component) {
|
||||
$result[] = $child;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the node for correctness.
|
||||
*
|
||||
* The following options are supported:
|
||||
* - Component::REPAIR - If something is broken, and automatic repair may
|
||||
* be attempted.
|
||||
*
|
||||
* An array is returned with warnings.
|
||||
*
|
||||
* Every item in the array has the following properties:
|
||||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @param int $options
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0) {
|
||||
|
||||
$result = array();
|
||||
foreach($this->children as $child) {
|
||||
$result = array_merge($result, $child->validate());
|
||||
}
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/* Magic property accessors {{{ */
|
||||
|
||||
/**
|
||||
* 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 Property
|
||||
*/
|
||||
public function __get($name) {
|
||||
|
||||
$matches = $this->select($name);
|
||||
if (count($matches)===0) {
|
||||
return null;
|
||||
} else {
|
||||
$firstMatch = current($matches);
|
||||
/** @var $firstMatch Property */
|
||||
$firstMatch->setIterator(new ElementList(array_values($matches)));
|
||||
return $firstMatch;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if a sub-element with the specified name exists.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name) {
|
||||
|
||||
$matches = $this->select($name);
|
||||
return count($matches)>0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the setter method you can add properties or subcomponents
|
||||
*
|
||||
* You can either pass a Component, Property
|
||||
* object, or a string to automatically create a Property.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
public function __set($name, $value) {
|
||||
|
||||
$matches = $this->select($name);
|
||||
$overWrite = count($matches)?key($matches):null;
|
||||
|
||||
if ($value instanceof Component || $value instanceof Property) {
|
||||
$value->parent = $this;
|
||||
if (!is_null($overWrite)) {
|
||||
$this->children[$overWrite] = $value;
|
||||
} else {
|
||||
$this->children[] = $value;
|
||||
}
|
||||
} elseif (is_scalar($value)) {
|
||||
$property = Property::create($name,$value);
|
||||
$property->parent = $this;
|
||||
if (!is_null($overWrite)) {
|
||||
$this->children[$overWrite] = $property;
|
||||
} else {
|
||||
$this->children[] = $property;
|
||||
}
|
||||
} else {
|
||||
throw new \InvalidArgumentException('You must pass a \\Sabre\\VObject\\Component, \\Sabre\\VObject\\Property or scalar type');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all properties and components within this component.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function __unset($name) {
|
||||
|
||||
$matches = $this->select($name);
|
||||
foreach($matches as $k=>$child) {
|
||||
|
||||
unset($this->children[$k]);
|
||||
$child->parent = null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
101
dav/sabre-vobject/lib/Sabre/VObject/Component/VAlarm.php
Normal file
101
dav/sabre-vobject/lib/Sabre/VObject/Component/VAlarm.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject\Component;
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* VAlarm component
|
||||
*
|
||||
* This component contains some additional functionality specific for VALARMs.
|
||||
*
|
||||
* @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 VAlarm extends 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 = 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 \LogicException('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 = 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 = 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
242
dav/sabre-vobject/lib/Sabre/VObject/Component/VCalendar.php
Normal file
242
dav/sabre-vobject/lib/Sabre/VObject/Component/VCalendar.php
Normal file
|
@ -0,0 +1,242 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* The VCalendar component
|
||||
*
|
||||
* This component adds functionality to a component, specific for a VCALENDAR.
|
||||
*
|
||||
* @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 VCalendar extends 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 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 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 VObject\Property\DateTime &&
|
||||
$child->getDateType() == VObject\Property\DateTime::LOCALTZ) {
|
||||
$child->setDateTime($child->getDateTime(),VObject\Property\DateTime::UTC);
|
||||
}
|
||||
}
|
||||
|
||||
$this->add($newEvent);
|
||||
|
||||
}
|
||||
|
||||
// Removing all VTIMEZONE components
|
||||
unset($this->VTIMEZONE);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the node for correctness.
|
||||
* An array is returned with warnings.
|
||||
*
|
||||
* Every item in the array has the following properties:
|
||||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
/*
|
||||
public function validate() {
|
||||
|
||||
$warnings = array();
|
||||
|
||||
$version = $this->select('VERSION');
|
||||
if (count($version)!==1) {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time',
|
||||
'node' => $this,
|
||||
);
|
||||
} else {
|
||||
if ((string)$this->VERSION !== '2.0') {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
}
|
||||
$version = $this->select('PRODID');
|
||||
if (count($version)!==1) {
|
||||
$warnings[] = array(
|
||||
'level' => 2,
|
||||
'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
if (count($this->CALSCALE) > 1) {
|
||||
$warnings[] = array(
|
||||
'level' => 2,
|
||||
'message' => 'The CALSCALE property must not be specified more than once.',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
if (count($this->METHOD) > 1) {
|
||||
$warnings[] = array(
|
||||
'level' => 2,
|
||||
'message' => 'The METHOD property must not be specified more than once.',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
|
||||
$allowedComponents = array(
|
||||
'VEVENT',
|
||||
'VTODO',
|
||||
'VJOURNAL',
|
||||
'VFREEBUSY',
|
||||
'VTIMEZONE',
|
||||
);
|
||||
$allowedProperties = array(
|
||||
'PRODID',
|
||||
'VERSION',
|
||||
'CALSCALE',
|
||||
'METHOD',
|
||||
);
|
||||
$componentsFound = 0;
|
||||
foreach($this->children as $child) {
|
||||
if($child instanceof Component) {
|
||||
$componentsFound++;
|
||||
if (!in_array($child->name, $allowedComponents)) {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component",
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($child instanceof Property) {
|
||||
if (!in_array($child->name, $allowedProperties)) {
|
||||
$warnings[] = array(
|
||||
'level' => 2,
|
||||
'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component",
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($componentsFound===0) {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'An iCalendar object must have at least 1 component.',
|
||||
'node' => $this,
|
||||
);
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
$warnings,
|
||||
parent::validate()
|
||||
);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
105
dav/sabre-vobject/lib/Sabre/VObject/Component/VCard.php
Normal file
105
dav/sabre-vobject/lib/Sabre/VObject/Component/VCard.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* The VCard component
|
||||
*
|
||||
* This component represents the BEGIN:VCARD and END:VCARD found in every
|
||||
* vcard.
|
||||
*
|
||||
* @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 VCard extends VObject\Component {
|
||||
|
||||
/**
|
||||
* VCards with version 2.1, 3.0 and 4.0 are found.
|
||||
*
|
||||
* If the VCARD doesn't know its version, 4.0 is assumed.
|
||||
*/
|
||||
const DEFAULT_VERSION = '4.0';
|
||||
|
||||
/**
|
||||
* Validates the node for correctness.
|
||||
*
|
||||
* The following options are supported:
|
||||
* - Component::REPAIR - If something is broken, and automatic repair may
|
||||
* be attempted.
|
||||
*
|
||||
* An array is returned with warnings.
|
||||
*
|
||||
* Every item in the array has the following properties:
|
||||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @param int $options
|
||||
* @return array
|
||||
*/
|
||||
public function validate($options = 0) {
|
||||
|
||||
$warnings = array();
|
||||
|
||||
$version = $this->select('VERSION');
|
||||
if (count($version)!==1) {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'The VERSION property must appear in the VCARD component exactly 1 time',
|
||||
'node' => $this,
|
||||
);
|
||||
if ($options & self::REPAIR) {
|
||||
$this->VERSION = self::DEFAULT_VERSION;
|
||||
}
|
||||
} else {
|
||||
$version = (string)$this->VERSION;
|
||||
if ($version!=='2.1' && $version!=='3.0' && $version!=='4.0') {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
|
||||
'node' => $this,
|
||||
);
|
||||
if ($options & self::REPAIR) {
|
||||
$this->VERSION = '4.0';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$version = $this->select('FN');
|
||||
if (count($version)!==1) {
|
||||
$warnings[] = array(
|
||||
'level' => 1,
|
||||
'message' => 'The FN property must appear in the VCARD component exactly 1 time',
|
||||
'node' => $this,
|
||||
);
|
||||
if (($options & self::REPAIR) && count($version) === 0) {
|
||||
// We're going to try to see if we can use the contents of the
|
||||
// N property.
|
||||
if (isset($this->N)) {
|
||||
$value = explode(';', (string)$this->N);
|
||||
if (isset($value[1]) && $value[1]) {
|
||||
$this->FN = $value[1] . ' ' . $value[0];
|
||||
} else {
|
||||
$this->FN = $value[0];
|
||||
}
|
||||
|
||||
// Otherwise, the ORG property may work
|
||||
} elseif (isset($this->ORG)) {
|
||||
$this->FN = (string)$this->ORG;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
parent::validate($options),
|
||||
$warnings
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
70
dav/sabre-vobject/lib/Sabre/VObject/Component/VEvent.php
Normal file
70
dav/sabre-vobject/lib/Sabre/VObject/Component/VEvent.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject\Component;
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* VEvent component
|
||||
*
|
||||
* This component contains some additional functionality specific for VEVENT's.
|
||||
*
|
||||
* @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 VEvent extends 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 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)) {
|
||||
|
||||
// The DTEND property is considered non inclusive. So for a 3 day
|
||||
// event in july, dtstart and dtend would have to be July 1st and
|
||||
// July 4th respectively.
|
||||
//
|
||||
// See:
|
||||
// http://tools.ietf.org/html/rfc5545#page-54
|
||||
$effectiveEnd = $this->DTEND->getDateTime();
|
||||
|
||||
} elseif (isset($this->DURATION)) {
|
||||
$effectiveEnd = clone $effectiveStart;
|
||||
$effectiveEnd->add( VObject\DateTimeParser::parseDuration($this->DURATION) );
|
||||
} elseif ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) {
|
||||
$effectiveEnd = clone $effectiveStart;
|
||||
$effectiveEnd->modify('+1 day');
|
||||
} else {
|
||||
$effectiveEnd = clone $effectiveStart;
|
||||
}
|
||||
return (
|
||||
($start <= $effectiveEnd) && ($end > $effectiveStart)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
46
dav/sabre-vobject/lib/Sabre/VObject/Component/VJournal.php
Normal file
46
dav/sabre-vobject/lib/Sabre/VObject/Component/VJournal.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* VJournal component
|
||||
*
|
||||
* This component contains some additional functionality specific for VJOURNALs.
|
||||
*
|
||||
* @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 VJournal extends 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() == VObject\Property\DateTime::DATE) {
|
||||
$effectiveEnd->modify('+1 day');
|
||||
}
|
||||
|
||||
return ($start <= $effectiveEnd && $end > $dtstart);
|
||||
|
||||
}
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
68
dav/sabre-vobject/lib/Sabre/VObject/Component/VTodo.php
Normal file
68
dav/sabre-vobject/lib/Sabre/VObject/Component/VTodo.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject\Component;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* VTodo component
|
||||
*
|
||||
* This component contains some additional functionality specific for VTODOs.
|
||||
*
|
||||
* @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 VTodo extends 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)?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;
|
||||
|
||||
}
|
||||
|
||||
}
|
181
dav/sabre-vobject/lib/Sabre/VObject/DateTimeParser.php
Normal file
181
dav/sabre-vobject/lib/Sabre/VObject/DateTimeParser.php
Normal file
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* DateTimeParser
|
||||
*
|
||||
* This class is responsible for parsing the several different date and time
|
||||
* formats iCalendar and vCards have.
|
||||
*
|
||||
* @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 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 \LogicException('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 \LogicException('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 \LogicException('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';
|
||||
|
||||
}
|
||||
|
||||
if ($duration==='P') {
|
||||
$duration = 'PT0S';
|
||||
}
|
||||
$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);
|
||||
if ($newDur === '+') { $newDur = '+0 seconds'; };
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
16
dav/sabre-vobject/lib/Sabre/VObject/Element.php
Normal file
16
dav/sabre-vobject/lib/Sabre/VObject/Element.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* Base class for all elements
|
||||
*
|
||||
* @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 Element extends Node {
|
||||
|
||||
public $parent = null;
|
||||
|
||||
}
|
172
dav/sabre-vobject/lib/Sabre/VObject/ElementList.php
Normal file
172
dav/sabre-vobject/lib/Sabre/VObject/ElementList.php
Normal file
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* VObject ElementList
|
||||
*
|
||||
* This class represents a list of elements. Lists are the result of queries,
|
||||
* such as doing $vcalendar->vevent where there's multiple VEVENT objects.
|
||||
*
|
||||
* @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 ElementList implements \Iterator, \Countable, \ArrayAccess {
|
||||
|
||||
/**
|
||||
* Inner elements
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $elements = array();
|
||||
|
||||
/**
|
||||
* Creates the element list.
|
||||
*
|
||||
* @param array $elements
|
||||
*/
|
||||
public function __construct(array $elements) {
|
||||
|
||||
$this->elements = $elements;
|
||||
|
||||
}
|
||||
|
||||
/* {{{ Iterator interface */
|
||||
|
||||
/**
|
||||
* Current position
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $key = 0;
|
||||
|
||||
/**
|
||||
* Returns current item in iteration
|
||||
*
|
||||
* @return Element
|
||||
*/
|
||||
public function current() {
|
||||
|
||||
return $this->elements[$this->key];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* To the next item in the iterator
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function next() {
|
||||
|
||||
$this->key++;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current iterator key
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function key() {
|
||||
|
||||
return $this->key;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current position in the iterator is a valid one
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function valid() {
|
||||
|
||||
return isset($this->elements[$this->key]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewinds the iterator
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function rewind() {
|
||||
|
||||
$this->key = 0;
|
||||
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Countable interface */
|
||||
|
||||
/**
|
||||
* Returns the number of elements
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count() {
|
||||
|
||||
return count($this->elements);
|
||||
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ ArrayAccess Interface */
|
||||
|
||||
|
||||
/**
|
||||
* Checks if an item exists through ArrayAccess.
|
||||
*
|
||||
* @param int $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset) {
|
||||
|
||||
return isset($this->elements[$offset]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an item through ArrayAccess.
|
||||
*
|
||||
* @param int $offset
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset) {
|
||||
|
||||
return $this->elements[$offset];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an item through ArrayAccess.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet($offset,$value) {
|
||||
|
||||
throw new \LogicException('You can not add new objects to an ElementList');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an item through ArrayAccess.
|
||||
*
|
||||
* This method just forwards the request to the inner iterator
|
||||
*
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function offsetUnset($offset) {
|
||||
|
||||
throw new \LogicException('You can not remove objects from an ElementList');
|
||||
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
}
|
322
dav/sabre-vobject/lib/Sabre/VObject/FreeBusyGenerator.php
Normal file
322
dav/sabre-vobject/lib/Sabre/VObject/FreeBusyGenerator.php
Normal file
|
@ -0,0 +1,322 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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 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 Component
|
||||
*/
|
||||
protected $baseObject;
|
||||
|
||||
/**
|
||||
* Creates the generator.
|
||||
*
|
||||
* Check the setTimeRange and setObjects methods for details about the
|
||||
* arguments.
|
||||
*
|
||||
* @param DateTime $start
|
||||
* @param DateTime $end
|
||||
* @param mixed $objects
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(\DateTime $start = null, \DateTime $end = null, $objects = null) {
|
||||
|
||||
if ($start && $end) {
|
||||
$this->setTimeRange($start, $end);
|
||||
}
|
||||
|
||||
if ($objects) {
|
||||
$this->setObjects($objects);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Component $vcalendar
|
||||
* @return void
|
||||
*/
|
||||
public function setBaseObject(Component $vcalendar) {
|
||||
|
||||
$this->baseObject = $vcalendar;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input objects
|
||||
*
|
||||
* You must either specify a valendar object as a strong, or as the parse
|
||||
* Component.
|
||||
* It's also possible to specify multiple objects as an array.
|
||||
*
|
||||
* @param mixed $objects
|
||||
* @return void
|
||||
*/
|
||||
public function setObjects($objects) {
|
||||
|
||||
if (!is_array($objects)) {
|
||||
$objects = array($objects);
|
||||
}
|
||||
|
||||
$this->objects = array();
|
||||
foreach($objects as $object) {
|
||||
|
||||
if (is_string($object)) {
|
||||
$this->objects[] = Reader::read($object);
|
||||
} elseif ($object instanceof 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 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 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 = DateTimeParser::parseDuration((string)$component->DURATION);
|
||||
$endTime = clone $startTime;
|
||||
$endTime->add($duration);
|
||||
} elseif ($component->DTSTART->getDateType() === 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 = DateTimeParser::parseDateTime($startTime);
|
||||
|
||||
if (substr($endTime,0,1)==='P' || substr($endTime,0,2)==='-P') {
|
||||
$duration = DateTimeParser::parseDuration($endTime);
|
||||
$endTime = clone $startTime;
|
||||
$endTime->add($duration);
|
||||
} else {
|
||||
$endTime = 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 Component('VCALENDAR');
|
||||
$calendar->version = '2.0';
|
||||
$calendar->prodid = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN';
|
||||
$calendar->calscale = 'GREGORIAN';
|
||||
}
|
||||
|
||||
$vfreebusy = new Component('VFREEBUSY');
|
||||
$calendar->add($vfreebusy);
|
||||
|
||||
if ($this->start) {
|
||||
$dtstart = new Property\DateTime('DTSTART');
|
||||
$dtstart->setDateTime($this->start,Property\DateTime::UTC);
|
||||
$vfreebusy->add($dtstart);
|
||||
}
|
||||
if ($this->end) {
|
||||
$dtend = new Property\DateTime('DTEND');
|
||||
$dtend->setDateTime($this->start,Property\DateTime::UTC);
|
||||
$vfreebusy->add($dtend);
|
||||
}
|
||||
$dtstamp = new Property\DateTime('DTSTAMP');
|
||||
$dtstamp->setDateTime(new \DateTime('now'), Property\DateTime::UTC);
|
||||
$vfreebusy->add($dtstamp);
|
||||
|
||||
foreach($busyTimes as $busyTime) {
|
||||
|
||||
$busyTime[0]->setTimeZone(new \DateTimeZone('UTC'));
|
||||
$busyTime[1]->setTimeZone(new \DateTimeZone('UTC'));
|
||||
|
||||
$prop = new Property(
|
||||
'FREEBUSY',
|
||||
$busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')
|
||||
);
|
||||
$prop['FBTYPE'] = $busyTime[2];
|
||||
$vfreebusy->add($prop);
|
||||
|
||||
}
|
||||
|
||||
return $calendar;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
166
dav/sabre-vobject/lib/Sabre/VObject/Node.php
Normal file
166
dav/sabre-vobject/lib/Sabre/VObject/Node.php
Normal file
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* Base class for all nodes
|
||||
*
|
||||
* @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 Node implements \IteratorAggregate, \ArrayAccess, \Countable {
|
||||
|
||||
/**
|
||||
* Turns the object back into a serialized blob.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract function serialize();
|
||||
|
||||
/**
|
||||
* Iterator override
|
||||
*
|
||||
* @var ElementList
|
||||
*/
|
||||
protected $iterator = null;
|
||||
|
||||
/**
|
||||
* A link to the parent node
|
||||
*
|
||||
* @var Node
|
||||
*/
|
||||
public $parent = null;
|
||||
|
||||
/**
|
||||
* Validates the node for correctness.
|
||||
* An array is returned with warnings.
|
||||
*
|
||||
* Every item in the array has the following properties:
|
||||
* * level - (number between 1 and 3 with severity information)
|
||||
* * message - (human readable message)
|
||||
* * node - (reference to the offending node)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validate() {
|
||||
|
||||
return array();
|
||||
|
||||
}
|
||||
|
||||
/* {{{ IteratorAggregator interface */
|
||||
|
||||
/**
|
||||
* Returns the iterator for this object
|
||||
*
|
||||
* @return ElementList
|
||||
*/
|
||||
public function getIterator() {
|
||||
|
||||
if (!is_null($this->iterator))
|
||||
return $this->iterator;
|
||||
|
||||
return new ElementList(array($this));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the overridden iterator
|
||||
*
|
||||
* Note that this is not actually part of the iterator interface
|
||||
*
|
||||
* @param ElementList $iterator
|
||||
* @return void
|
||||
*/
|
||||
public function setIterator(ElementList $iterator) {
|
||||
|
||||
$this->iterator = $iterator;
|
||||
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Countable interface */
|
||||
|
||||
/**
|
||||
* Returns the number of elements
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count() {
|
||||
|
||||
$it = $this->getIterator();
|
||||
return $it->count();
|
||||
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ ArrayAccess Interface */
|
||||
|
||||
|
||||
/**
|
||||
* Checks if an item exists through ArrayAccess.
|
||||
*
|
||||
* This method just forwards the request to the inner iterator
|
||||
*
|
||||
* @param int $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($offset) {
|
||||
|
||||
$iterator = $this->getIterator();
|
||||
return $iterator->offsetExists($offset);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an item through ArrayAccess.
|
||||
*
|
||||
* This method just forwards the request to the inner iterator
|
||||
*
|
||||
* @param int $offset
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($offset) {
|
||||
|
||||
$iterator = $this->getIterator();
|
||||
return $iterator->offsetGet($offset);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an item through ArrayAccess.
|
||||
*
|
||||
* This method just forwards the request to the inner iterator
|
||||
*
|
||||
* @param int $offset
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet($offset,$value) {
|
||||
|
||||
$iterator = $this->getIterator();
|
||||
$iterator->offsetSet($offset,$value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an item through ArrayAccess.
|
||||
*
|
||||
* This method just forwards the request to the inner iterator
|
||||
*
|
||||
* @param int $offset
|
||||
* @return void
|
||||
*/
|
||||
public function offsetUnset($offset) {
|
||||
|
||||
$iterator = $this->getIterator();
|
||||
$iterator->offsetUnset($offset);
|
||||
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
}
|
84
dav/sabre-vobject/lib/Sabre/VObject/Parameter.php
Normal file
84
dav/sabre-vobject/lib/Sabre/VObject/Parameter.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* VObject Parameter
|
||||
*
|
||||
* This class represents a parameter. A parameter is always tied to a property.
|
||||
* In the case of:
|
||||
* DTSTART;VALUE=DATE:20101108
|
||||
* VALUE=DATE would be the parameter name and value.
|
||||
*
|
||||
* @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 Parameter extends Node {
|
||||
|
||||
/**
|
||||
* Parameter name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Parameter value
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $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
|
||||
*/
|
||||
public function serialize() {
|
||||
|
||||
if (is_null($this->value)) {
|
||||
return $this->name;
|
||||
}
|
||||
$src = array(
|
||||
'\\',
|
||||
"\n",
|
||||
';',
|
||||
',',
|
||||
);
|
||||
$out = array(
|
||||
'\\\\',
|
||||
'\n',
|
||||
'\;',
|
||||
'\,',
|
||||
);
|
||||
|
||||
return $this->name . '=' . str_replace($src, $out, $this->value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this object is being cast to a string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
|
||||
return $this->value;
|
||||
|
||||
}
|
||||
|
||||
}
|
12
dav/sabre-vobject/lib/Sabre/VObject/ParseException.php
Normal file
12
dav/sabre-vobject/lib/Sabre/VObject/ParseException.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* Exception thrown by Reader if an invalid object was attempted to be parsed.
|
||||
*
|
||||
* @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 ParseException extends \Exception { }
|
365
dav/sabre-vobject/lib/Sabre/VObject/Property.php
Normal file
365
dav/sabre-vobject/lib/Sabre/VObject/Property.php
Normal file
|
@ -0,0 +1,365 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* VObject Property
|
||||
*
|
||||
* A property in VObject is usually in the form PARAMNAME:paramValue.
|
||||
* An example is : SUMMARY:Weekly meeting
|
||||
*
|
||||
* Properties can also have parameters:
|
||||
* SUMMARY;LANG=en:Weekly meeting.
|
||||
*
|
||||
* Parameters can be accessed using the ArrayAccess interface.
|
||||
*
|
||||
* @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 Property extends Element {
|
||||
|
||||
/**
|
||||
* Propertyname
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* Group name
|
||||
*
|
||||
* This may be something like 'HOME' for vcards.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $group;
|
||||
|
||||
/**
|
||||
* Property parameters
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $parameters = array();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Parameters can be specified with the optional third argument. Parameters
|
||||
* must be a key->value map of the parameter name, and value. If the value
|
||||
* is specified as an array, it is assumed that multiple parameters with
|
||||
* the same name should be added.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @param array $parameters
|
||||
* @return Property
|
||||
*/
|
||||
static public function create($name, $value = null, array $parameters = array()) {
|
||||
|
||||
$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, $parameters);
|
||||
} else {
|
||||
return new self($name, $value, $parameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new property object
|
||||
*
|
||||
* Parameters can be specified with the optional third argument. Parameters
|
||||
* must be a key->value map of the parameter name, and value. If the value
|
||||
* is specified as an array, it is assumed that multiple parameters with
|
||||
* the same name should be added.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @param array $parameters
|
||||
*/
|
||||
public function __construct($name, $value = null, array $parameters = array()) {
|
||||
|
||||
$name = strtoupper($name);
|
||||
$group = null;
|
||||
if (strpos($name,'.')!==false) {
|
||||
list($group, $name) = explode('.', $name);
|
||||
}
|
||||
$this->name = $name;
|
||||
$this->group = $group;
|
||||
$this->setValue($value);
|
||||
|
||||
foreach($parameters as $paramName => $paramValues) {
|
||||
|
||||
if (!is_array($paramValues)) {
|
||||
$paramValues = array($paramValues);
|
||||
}
|
||||
|
||||
foreach($paramValues as $paramValue) {
|
||||
$this->add($paramName, $paramValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the internal value
|
||||
*
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function setValue($value) {
|
||||
|
||||
$this->value = $value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the object back into a serialized blob.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize() {
|
||||
|
||||
$str = $this->name;
|
||||
if ($this->group) $str = $this->group . '.' . $this->name;
|
||||
|
||||
if (count($this->parameters)) {
|
||||
foreach($this->parameters as $param) {
|
||||
|
||||
$str.=';' . $param->serialize();
|
||||
|
||||
}
|
||||
}
|
||||
$src = array(
|
||||
'\\',
|
||||
"\n",
|
||||
);
|
||||
$out = array(
|
||||
'\\\\',
|
||||
'\n',
|
||||
);
|
||||
$str.=':' . str_replace($src, $out, $this->value);
|
||||
|
||||
$out = '';
|
||||
while(strlen($str)>0) {
|
||||
if (strlen($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='';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new componenten or element
|
||||
*
|
||||
* You can call this method with the following syntaxes:
|
||||
*
|
||||
* add(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
|
||||
* @return void
|
||||
*/
|
||||
public function add($item, $itemValue = null) {
|
||||
|
||||
if ($item instanceof Parameter) {
|
||||
if (!is_null($itemValue)) {
|
||||
throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject');
|
||||
}
|
||||
$item->parent = $this;
|
||||
$this->parameters[] = $item;
|
||||
} elseif(is_string($item)) {
|
||||
|
||||
if (!is_scalar($itemValue) && !is_null($itemValue)) {
|
||||
throw new \InvalidArgumentException('The second argument must be scalar');
|
||||
}
|
||||
$parameter = new Parameter($item,$itemValue);
|
||||
$parameter->parent = $this;
|
||||
$this->parameters[] = $parameter;
|
||||
|
||||
} else {
|
||||
|
||||
throw new \InvalidArgumentException('The first argument must either be a Element or a string');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ArrayAccess interface {{{ */
|
||||
|
||||
/**
|
||||
* Checks if an array element exists
|
||||
*
|
||||
* @param mixed $name
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($name) {
|
||||
|
||||
if (is_int($name)) return parent::offsetExists($name);
|
||||
|
||||
$name = strtoupper($name);
|
||||
|
||||
foreach($this->parameters as $parameter) {
|
||||
if ($parameter->name == $name) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a parameter, or parameter list.
|
||||
*
|
||||
* @param string $name
|
||||
* @return 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)
|
||||
$result[] = $parameter;
|
||||
}
|
||||
|
||||
if (count($result)===0) {
|
||||
return null;
|
||||
} elseif (count($result)===1) {
|
||||
return $result[0];
|
||||
} else {
|
||||
$result[0]->setIterator(new ElementList($result));
|
||||
return $result[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new parameter
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet($name, $value) {
|
||||
|
||||
if (is_int($name)) parent::offsetSet($name, $value);
|
||||
|
||||
if (is_scalar($value)) {
|
||||
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);
|
||||
$parameter = new Parameter($name, $value);
|
||||
$parameter->parent = $this;
|
||||
$this->parameters[] = $parameter;
|
||||
|
||||
} elseif ($value instanceof Parameter) {
|
||||
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;
|
||||
$this->parameters[] = $value;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('You can only add parameters to the property object');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes one or more parameters with the specified name
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function offsetUnset($name) {
|
||||
|
||||
if (is_int($name)) parent::offsetUnset($name);
|
||||
$name = strtoupper($name);
|
||||
|
||||
foreach($this->parameters as $key=>$parameter) {
|
||||
if ($parameter->name == $name) {
|
||||
$parameter->parent = null;
|
||||
unset($this->parameters[$key]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/**
|
||||
* Called when this object is being cast to a string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
233
dav/sabre-vobject/lib/Sabre/VObject/Property/DateTime.php
Normal file
233
dav/sabre-vobject/lib/Sabre/VObject/Property/DateTime.php
Normal file
|
@ -0,0 +1,233 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject\Property;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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 DateTime extends 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, 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', new \DateTimeZone('UTC')),
|
||||
);
|
||||
}
|
||||
|
||||
$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) {
|
||||
// This was a floating time string. This implies we use the
|
||||
// timezone from date_default_timezone_set / date.timezone ini
|
||||
// setting.
|
||||
return array(
|
||||
self::LOCAL,
|
||||
new \DateTime($dateStr)
|
||||
);
|
||||
}
|
||||
|
||||
// To look up the timezone, we must first find the VCALENDAR component.
|
||||
$root = $property;
|
||||
while($root->parent) {
|
||||
$root = $root->parent;
|
||||
}
|
||||
if ($root->name === 'VCALENDAR') {
|
||||
$tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid, $root);
|
||||
} else {
|
||||
$tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid);
|
||||
}
|
||||
|
||||
$dt = new \DateTime($dateStr, $tz);
|
||||
$dt->setTimeZone($tz);
|
||||
|
||||
return array(
|
||||
self::LOCALTZ,
|
||||
$dt
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
168
dav/sabre-vobject/lib/Sabre/VObject/Property/MultiDateTime.php
Normal file
168
dav/sabre-vobject/lib/Sabre/VObject/Property/MultiDateTime.php
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject\Property;
|
||||
|
||||
use Sabre\VObject;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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 MultiDateTime extends 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 = 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 DateTime::LOCAL :
|
||||
$val = array();
|
||||
foreach($dt as $i) {
|
||||
$val[] = $i->format('Ymd\\THis');
|
||||
}
|
||||
$this->setValue(implode(',',$val));
|
||||
$this->offsetSet('VALUE','DATE-TIME');
|
||||
break;
|
||||
case 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 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 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
|
||||
) = 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
|
||||
) = DateTime::parseData($val, $this);
|
||||
$dts[] = $dt;
|
||||
$this->dateType = $type;
|
||||
}
|
||||
$this->dateTimes = $dts;
|
||||
return $this->dateType;
|
||||
|
||||
}
|
||||
|
||||
}
|
183
dav/sabre-vobject/lib/Sabre/VObject/Reader.php
Normal file
183
dav/sabre-vobject/lib/Sabre/VObject/Reader.php
Normal file
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* VCALENDAR/VCARD reader
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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 Reader {
|
||||
|
||||
/**
|
||||
* Parses the file and returns the top component
|
||||
*
|
||||
* @param string $data
|
||||
* @return Element
|
||||
*/
|
||||
static function read($data) {
|
||||
|
||||
// Normalizing newlines
|
||||
$data = str_replace(array("\r","\n\n"), array("\n","\n"), $data);
|
||||
|
||||
$lines = explode("\n", $data);
|
||||
|
||||
// Unfolding lines
|
||||
$lines2 = array();
|
||||
foreach($lines as $line) {
|
||||
|
||||
// Skipping empty lines
|
||||
if (!$line) continue;
|
||||
|
||||
if ($line[0]===" " || $line[0]==="\t") {
|
||||
$lines2[count($lines2)-1].=substr($line,1);
|
||||
} else {
|
||||
$lines2[] = $line;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unset($lines);
|
||||
|
||||
reset($lines2);
|
||||
|
||||
return self::readLine($lines2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and parses a single line.
|
||||
*
|
||||
* This method receives the full array of lines. The array pointer is used
|
||||
* to traverse.
|
||||
*
|
||||
* @param array $lines
|
||||
* @return Element
|
||||
*/
|
||||
static private function readLine(&$lines) {
|
||||
|
||||
$line = current($lines);
|
||||
$lineNr = key($lines);
|
||||
next($lines);
|
||||
|
||||
// Components
|
||||
if (stripos($line,"BEGIN:")===0) {
|
||||
|
||||
$componentName = strtoupper(substr($line,6));
|
||||
$obj = Component::create($componentName);
|
||||
|
||||
$nextLine = current($lines);
|
||||
|
||||
while(stripos($nextLine,"END:")!==0) {
|
||||
|
||||
$obj->add(self::readLine($lines));
|
||||
|
||||
$nextLine = current($lines);
|
||||
|
||||
if ($nextLine===false)
|
||||
throw new ParseException('Invalid VObject. Document ended prematurely.');
|
||||
|
||||
}
|
||||
|
||||
// Checking component name of the 'END:' line.
|
||||
if (substr($nextLine,4)!==$obj->name) {
|
||||
throw new ParseException('Invalid VObject, expected: "END:' . $obj->name . '" got: "' . $nextLine . '"');
|
||||
}
|
||||
next($lines);
|
||||
|
||||
return $obj;
|
||||
|
||||
}
|
||||
|
||||
// Properties
|
||||
//$result = preg_match('/(?P<name>[A-Z0-9-]+)(?:;(?P<parameters>^(?<!:):))(.*)$/',$line,$matches);
|
||||
|
||||
|
||||
$token = '[A-Z0-9-\.]+';
|
||||
$parameters = "(?:;(?P<parameters>([^:^\"]|\"([^\"]*)\")*))?";
|
||||
$regex = "/^(?P<name>$token)$parameters:(?P<value>.*)$/i";
|
||||
|
||||
$result = preg_match($regex,$line,$matches);
|
||||
|
||||
if (!$result) {
|
||||
throw new ParseException('Invalid VObject, line ' . ($lineNr+1) . ' did not follow the icalendar/vcard format');
|
||||
}
|
||||
|
||||
$propertyName = strtoupper($matches['name']);
|
||||
$propertyValue = preg_replace_callback('#(\\\\(\\\\|N|n|;|,))#',function($matches) {
|
||||
if ($matches[2]==='n' || $matches[2]==='N') {
|
||||
return "\n";
|
||||
} else {
|
||||
return $matches[2];
|
||||
}
|
||||
}, $matches['value']);
|
||||
|
||||
$obj = Property::create($propertyName, $propertyValue);
|
||||
|
||||
if ($matches['parameters']) {
|
||||
|
||||
foreach(self::readParameters($matches['parameters']) as $param) {
|
||||
$obj->add($param);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $obj;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a parameter list from a property
|
||||
*
|
||||
* This method returns an array of Parameter
|
||||
*
|
||||
* @param string $parameters
|
||||
* @return array
|
||||
*/
|
||||
static private function readParameters($parameters) {
|
||||
|
||||
$token = '[A-Z0-9-]+';
|
||||
|
||||
$paramValue = '(?P<paramValue>[^\"^;]*|"[^"]*")';
|
||||
|
||||
$regex = "/(?<=^|;)(?P<paramName>$token)(=$paramValue(?=$|;))?/i";
|
||||
preg_match_all($regex, $parameters, $matches, PREG_SET_ORDER);
|
||||
|
||||
$params = array();
|
||||
foreach($matches as $match) {
|
||||
|
||||
$value = isset($match['paramValue'])?$match['paramValue']:null;
|
||||
|
||||
if (isset($value[0])) {
|
||||
// Stripping quotes, if needed
|
||||
if ($value[0] === '"') $value = substr($value,1,strlen($value)-2);
|
||||
} else {
|
||||
$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 Parameter($match['paramName'], $value);
|
||||
|
||||
}
|
||||
|
||||
return $params;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
1058
dav/sabre-vobject/lib/Sabre/VObject/RecurrenceIterator.php
Normal file
1058
dav/sabre-vobject/lib/Sabre/VObject/RecurrenceIterator.php
Normal file
File diff suppressed because it is too large
Load diff
351
dav/sabre-vobject/lib/Sabre/VObject/TimeZoneUtil.php
Normal file
351
dav/sabre-vobject/lib/Sabre/VObject/TimeZoneUtil.php
Normal file
|
@ -0,0 +1,351 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* Time zone name translation
|
||||
*
|
||||
* This file translates well-known time zone names into "Olson database" time zone names.
|
||||
*
|
||||
* @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
|
||||
* @author Frank Edelhaeuser (fedel@users.sourceforge.net)
|
||||
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class TimeZoneUtil {
|
||||
|
||||
public 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',
|
||||
|
||||
// Microsoft exchange timezones
|
||||
// Source:
|
||||
// http://msdn.microsoft.com/en-us/library/ms988620%28v=exchg.65%29.aspx
|
||||
//
|
||||
// Correct timezones deduced with help from:
|
||||
// http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
'Universal Coordinated Time' => 'UTC',
|
||||
'Casablanca, Monrovia' => 'Africa/Casablanca',
|
||||
'Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London' => 'Europe/Lisbon',
|
||||
'Greenwich Mean Time; Dublin, Edinburgh, London' => 'Europe/London',
|
||||
'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin',
|
||||
'Belgrade, Pozsony, Budapest, Ljubljana, Prague' => 'Europe/Prague',
|
||||
'Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris',
|
||||
'Paris, Madrid, Brussels, Copenhagen' => 'Europe/Paris',
|
||||
'Prague, Central Europe' => 'Europe/Prague',
|
||||
'Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb' => 'Europe/Sarajevo',
|
||||
'West Central Africa' => 'Africa/Luanda', // This was a best guess
|
||||
'Athens, Istanbul, Minsk' => 'Europe/Athens',
|
||||
'Bucharest' => 'Europe/Bucharest',
|
||||
'Cairo' => 'Africa/Cairo',
|
||||
'Harare, Pretoria' => 'Africa/Harare',
|
||||
'Helsinki, Riga, Tallinn' => 'Europe/Helsinki',
|
||||
'Israel, Jerusalem Standard Time' => 'Asia/Jerusalem',
|
||||
'Baghdad' => 'Asia/Baghdad',
|
||||
'Arab, Kuwait, Riyadh' => 'Asia/Kuwait',
|
||||
'Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow',
|
||||
'East Africa, Nairobi' => 'Africa/Nairobi',
|
||||
'Tehran' => 'Asia/Tehran',
|
||||
'Abu Dhabi, Muscat' => 'Asia/Muscat', // Best guess
|
||||
'Baku, Tbilisi, Yerevan' => 'Asia/Baku',
|
||||
'Kabul' => 'Asia/Kabul',
|
||||
'Ekaterinburg' => 'Asia/Yekaterinburg',
|
||||
'Islamabad, Karachi, Tashkent' => 'Asia/Karachi',
|
||||
'Kolkata, Chennai, Mumbai, New Delhi, India Standard Time' => 'Asia/Calcutta',
|
||||
'Kathmandu, Nepal' => 'Asia/Kathmandu',
|
||||
'Almaty, Novosibirsk, North Central Asia' => 'Asia/Almaty',
|
||||
'Astana, Dhaka' => 'Asia/Dhaka',
|
||||
'Sri Jayawardenepura, Sri Lanka' => 'Asia/Colombo',
|
||||
'Rangoon' => 'Asia/Rangoon',
|
||||
'Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok',
|
||||
'Krasnoyarsk' => 'Asia/Krasnoyarsk',
|
||||
'Beijing, Chongqing, Hong Kong SAR, Urumqi' => 'Asia/Shanghai',
|
||||
'Irkutsk, Ulaan Bataar' => 'Asia/Irkutsk',
|
||||
'Kuala Lumpur, Singapore' => 'Asia/Singapore',
|
||||
'Perth, Western Australia' => 'Australia/Perth',
|
||||
'Taipei' => 'Asia/Taipei',
|
||||
'Osaka, Sapporo, Tokyo' => 'Asia/Tokyo',
|
||||
'Seoul, Korea Standard time' => 'Asia/Seoul',
|
||||
'Yakutsk' => 'Asia/Yakutsk',
|
||||
'Adelaide, Central Australia' => 'Australia/Adelaide',
|
||||
'Darwin' => 'Australia/Darwin',
|
||||
'Brisbane, East Australia' => 'Australia/Brisbane',
|
||||
'Canberra, Melbourne, Sydney, Hobart (year 2000 only)' => 'Australia/Sydney',
|
||||
'Guam, Port Moresby' => 'Pacific/Guam',
|
||||
'Hobart, Tasmania' => 'Australia/Hobart',
|
||||
'Vladivostok' => 'Asia/Vladivostok',
|
||||
'Magadan, Solomon Is., New Caledonia' => 'Asia/Magadan',
|
||||
'Auckland, Wellington' => 'Pacific/Auckland',
|
||||
'Fiji Islands, Kamchatka, Marshall Is.' => 'Pacific/Fiji',
|
||||
'Nuku\'alofa, Tonga' => 'Pacific/Tongatapu',
|
||||
'Azores' => 'Atlantic/Azores',
|
||||
'Cape Verde Is.' => 'Atlantic/Cape_Verde',
|
||||
'Mid-Atlantic' => 'America/Noronha',
|
||||
'Brasilia' => 'America/Sao_Paulo', // Best guess
|
||||
'Buenos Aires' => 'America/Argentina/Buenos_Aires',
|
||||
'Greenland' => 'America/Godthab',
|
||||
'Newfoundland' => 'America/St_Johns',
|
||||
'Atlantic Time (Canada)' => 'America/Halifax',
|
||||
'Caracas, La Paz' => 'America/Caracas',
|
||||
'Santiago' => 'America/Santiago',
|
||||
'Bogota, Lima, Quito' => 'America/Bogota',
|
||||
'Eastern Time (US & Canada)' => 'America/New_York',
|
||||
'Indiana (East)' => 'America/Indiana/Indianapolis',
|
||||
'Central America' => 'America/Guatemala',
|
||||
'Central Time (US & Canada)' => 'America/Chicago',
|
||||
'Mexico City, Tegucigalpa' => 'America/Mexico_City',
|
||||
'Saskatchewan' => 'America/Edmonton',
|
||||
'Arizona' => 'America/Phoenix',
|
||||
'Mountain Time (US & Canada)' => 'America/Denver', // Best guess
|
||||
'Pacific Time (US & Canada); Tijuana' => 'America/Los_Angeles', // Best guess
|
||||
'Alaska' => 'America/Anchorage',
|
||||
'Hawaii' => 'Pacific/Honolulu',
|
||||
'Midway Island, Samoa' => 'Pacific/Midway',
|
||||
'Eniwetok, Kwajalein, Dateline Time' => 'Pacific/Kwajalein',
|
||||
|
||||
);
|
||||
|
||||
public static $microsoftExchangeMap = array(
|
||||
0 => 'UTC',
|
||||
31 => 'Africa/Casablanca',
|
||||
2 => 'Europe/Lisbon',
|
||||
1 => 'Europe/London',
|
||||
4 => 'Europe/Berlin',
|
||||
6 => 'Europe/Prague',
|
||||
3 => 'Europe/Paris',
|
||||
69 => 'Africa/Luanda', // This was a best guess
|
||||
7 => 'Europe/Athens',
|
||||
5 => 'Europe/Bucharest',
|
||||
49 => 'Africa/Cairo',
|
||||
50 => 'Africa/Harare',
|
||||
59 => 'Europe/Helsinki',
|
||||
27 => 'Asia/Jerusalem',
|
||||
26 => 'Asia/Baghdad',
|
||||
74 => 'Asia/Kuwait',
|
||||
51 => 'Europe/Moscow',
|
||||
56 => 'Africa/Nairobi',
|
||||
25 => 'Asia/Tehran',
|
||||
24 => 'Asia/Muscat', // Best guess
|
||||
54 => 'Asia/Baku',
|
||||
48 => 'Asia/Kabul',
|
||||
58 => 'Asia/Yekaterinburg',
|
||||
47 => 'Asia/Karachi',
|
||||
23 => 'Asia/Calcutta',
|
||||
62 => 'Asia/Kathmandu',
|
||||
46 => 'Asia/Almaty',
|
||||
71 => 'Asia/Dhaka',
|
||||
66 => 'Asia/Colombo',
|
||||
61 => 'Asia/Rangoon',
|
||||
22 => 'Asia/Bangkok',
|
||||
64 => 'Asia/Krasnoyarsk',
|
||||
45 => 'Asia/Shanghai',
|
||||
63 => 'Asia/Irkutsk',
|
||||
21 => 'Asia/Singapore',
|
||||
73 => 'Australia/Perth',
|
||||
75 => 'Asia/Taipei',
|
||||
20 => 'Asia/Tokyo',
|
||||
72 => 'Asia/Seoul',
|
||||
70 => 'Asia/Yakutsk',
|
||||
19 => 'Australia/Adelaide',
|
||||
44 => 'Australia/Darwin',
|
||||
18 => 'Australia/Brisbane',
|
||||
76 => 'Australia/Sydney',
|
||||
43 => 'Pacific/Guam',
|
||||
42 => 'Australia/Hobart',
|
||||
68 => 'Asia/Vladivostok',
|
||||
41 => 'Asia/Magadan',
|
||||
17 => 'Pacific/Auckland',
|
||||
40 => 'Pacific/Fiji',
|
||||
67 => 'Pacific/Tongatapu',
|
||||
29 => 'Atlantic/Azores',
|
||||
53 => 'Atlantic/Cape_Verde',
|
||||
30 => 'America/Noronha',
|
||||
8 => 'America/Sao_Paulo', // Best guess
|
||||
32 => 'America/Argentina/Buenos_Aires',
|
||||
69 => 'America/Godthab',
|
||||
28 => 'America/St_Johns',
|
||||
9 => 'America/Halifax',
|
||||
33 => 'America/Caracas',
|
||||
65 => 'America/Santiago',
|
||||
35 => 'America/Bogota',
|
||||
10 => 'America/New_York',
|
||||
34 => 'America/Indiana/Indianapolis',
|
||||
55 => 'America/Guatemala',
|
||||
11 => 'America/Chicago',
|
||||
37 => 'America/Mexico_City',
|
||||
36 => 'America/Edmonton',
|
||||
38 => 'America/Phoenix',
|
||||
12 => 'America/Denver', // Best guess
|
||||
13 => 'America/Los_Angeles', // Best guess
|
||||
14 => 'America/Anchorage',
|
||||
15 => 'Pacific/Honolulu',
|
||||
16 => 'Pacific/Midway',
|
||||
39 => 'Pacific/Kwajalein',
|
||||
);
|
||||
|
||||
/**
|
||||
* This method will try to find out the correct timezone for an iCalendar
|
||||
* date-time value.
|
||||
*
|
||||
* You must pass the contents of the TZID parameter, as well as the full
|
||||
* calendar.
|
||||
*
|
||||
* If the lookup fails, this method will return UTC.
|
||||
*
|
||||
* @param string $tzid
|
||||
* @param Sabre\VObject\Component $vcalendar
|
||||
* @return DateTimeZone
|
||||
*/
|
||||
static public function getTimeZone($tzid, Component $vcalendar = null) {
|
||||
|
||||
// First we will just see if the tzid is a support timezone identifier.
|
||||
try {
|
||||
return new \DateTimeZone($tzid);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
// Next, we check if the tzid is somewhere in our tzid map.
|
||||
if (isset(self::$map[$tzid])) {
|
||||
return new \DateTimeZone(self::$map[$tzid]);
|
||||
}
|
||||
|
||||
if ($vcalendar) {
|
||||
|
||||
// If that didn't work, we will scan VTIMEZONE objects
|
||||
foreach($vcalendar->select('VTIMEZONE') as $vtimezone) {
|
||||
|
||||
if ((string)$vtimezone->TZID === $tzid) {
|
||||
|
||||
// Some clients add 'X-LIC-LOCATION' with the olson name.
|
||||
if (isset($vtimezone->{'X-LIC-LOCATION'})) {
|
||||
try {
|
||||
return new \DateTimeZone($vtimezone->{'X-LIC-LOCATION'});
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
}
|
||||
// Microsoft may add a magic number, which we also have an
|
||||
// answer for.
|
||||
if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
|
||||
if (isset(self::$microsoftExchangeMap[(int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value])) {
|
||||
return new \DateTimeZone(self::$microsoftExchangeMap[(int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If we got all the way here, we default to UTC.
|
||||
return new \DateTimeZone(date_default_timezone_get());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
24
dav/sabre-vobject/lib/Sabre/VObject/Version.php
Normal file
24
dav/sabre-vobject/lib/Sabre/VObject/Version.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Sabre\VObject;
|
||||
|
||||
/**
|
||||
* This class contains the version number for the VObject package
|
||||
*
|
||||
* @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 Version {
|
||||
|
||||
/**
|
||||
* Full version number
|
||||
*/
|
||||
const VERSION = '2.0';
|
||||
|
||||
/**
|
||||
* Stability : alpha, beta, stable
|
||||
*/
|
||||
const STABILITY = 'stable';
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue