CardDAV (pre-alpha/unstable)

This commit is contained in:
RainLoop Team 2013-12-23 04:06:48 +04:00
parent 0ec965bccb
commit 599e934b4a
76 changed files with 6984 additions and 1512 deletions

View file

@ -2,7 +2,9 @@
namespace Sabre\VObject\Component;
use Sabre\VObject;
use
Sabre\VObject,
Sabre\VObject\Component;
/**
* The VCalendar component
@ -15,7 +17,140 @@ use Sabre\VObject;
*/
class VCalendar extends VObject\Document {
static $defaultName = 'VCALENDAR';
/**
* The default name for this component.
*
* This should be 'VCALENDAR' or 'VCARD'.
*
* @var string
*/
static public $defaultName = 'VCALENDAR';
/**
* This is a list of components, and which classes they should map to.
*
* @var array
*/
static public $componentMap = array(
'VEVENT' => 'Sabre\\VObject\\Component\\VEvent',
'VFREEBUSY' => 'Sabre\\VObject\\Component\\VFreeBusy',
'VJOURNAL' => 'Sabre\\VObject\\Component\\VJournal',
'VTODO' => 'Sabre\\VObject\\Component\\VTodo',
'VALARM' => 'Sabre\\VObject\\Component\\VAlarm',
);
/**
* List of value-types, and which classes they map to.
*
* @var array
*/
static public $valueMap = array(
'BINARY' => 'Sabre\\VObject\\Property\\Binary',
'BOOLEAN' => 'Sabre\\VObject\\Property\\Boolean',
'CAL-ADDRESS' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
'DATE' => 'Sabre\\VObject\\Property\\ICalendar\\Date',
'DATE-TIME' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
'FLOAT' => 'Sabre\\VObject\\Property\\Float',
'INTEGER' => 'Sabre\\VObject\\Property\\Integer',
'PERIOD' => 'Sabre\\VObject\\Property\\ICalendar\\Period',
'RECUR' => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
'TEXT' => 'Sabre\\VObject\\Property\\Text',
'TIME' => 'Sabre\\VObject\\Property\\Time',
'UNKNOWN' => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
'URI' => 'Sabre\\VObject\\Property\\Uri',
'UTC-OFFSET' => 'Sabre\\VObject\\Property\\UtcOffset',
);
/**
* List of properties, and which classes they map to.
*
* @var array
*/
static public $propertyMap = array(
// Calendar properties
'CALSCALE' => 'Sabre\\VObject\\Property\\FlatText',
'METHOD' => 'Sabre\\VObject\\Property\\FlatText',
'PRODID' => 'Sabre\\VObject\\Property\\FlatText',
'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
// Component properties
'ATTACH' => 'Sabre\\VObject\\Property\\Binary',
'CATEGORIES' => 'Sabre\\VObject\\Property\\Text',
'CLASS' => 'Sabre\\VObject\\Property\\FlatText',
'COMMENT' => 'Sabre\\VObject\\Property\\FlatText',
'DESCRIPTION' => 'Sabre\\VObject\\Property\\FlatText',
'GEO' => 'Sabre\\VObject\\Property\\Float',
'LOCATION' => 'Sabre\\VObject\\Property\\FlatText',
'PERCENT-COMPLETE' => 'Sabre\\VObject\\Property\\Integer',
'PRIORITY' => 'Sabre\\VObject\\Property\\Integer',
'RESOURCES' => 'Sabre\\VObject\\Property\\Text',
'STATUS' => 'Sabre\\VObject\\Property\\FlatText',
'SUMMARY' => 'Sabre\\VObject\\Property\\FlatText',
// Date and Time Component Properties
'COMPLETED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'DTEND' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'DUE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'DTSTART' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
'FREEBUSY' => 'Sabre\\VObject\\Property\\ICalendar\\Period',
'TRANSP' => 'Sabre\\VObject\\Property\\FlatText',
// Time Zone Component Properties
'TZID' => 'Sabre\\VObject\\Property\\FlatText',
'TZNAME' => 'Sabre\\VObject\\Property\\FlatText',
'TZOFFSETFROM' => 'Sabre\\VObject\\Property\\UtcOffset',
'TZOFFSETTO' => 'Sabre\\VObject\\Property\\UtcOffset',
'TZURL' => 'Sabre\\VObject\\Property\\Uri',
// Relationship Component Properties
'ATTENDEE' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
'CONTACT' => 'Sabre\\VObject\\Property\\FlatText',
'ORGANIZER' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'RELATED-TO' => 'Sabre\\VObject\\Property\\FlatText',
'URL' => 'Sabre\\VObject\\Property\\Uri',
'UID' => 'Sabre\\VObject\\Property\\FlatText',
// Recurrence Component Properties
'EXDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'RDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'RRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
'EXRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', // Deprecated since rfc5545
// Alarm Component Properties
'ACTION' => 'Sabre\\VObject\\Property\\FlatText',
'REPEAT' => 'Sabre\\VObject\\Property\\Integer',
'TRIGGER' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
// Change Management Component Properties
'CREATED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'DTSTAMP' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'SEQUENCE' => 'Sabre\\VObject\\Property\\Integer',
// Request Status
'REQUEST-STATUS' => 'Sabre\\VObject\\Property\\Text',
// Additions from draft-daboo-valarm-extensions-04
'ALARM-AGENT' => 'Sabre\\VObject\\Property\\Text',
'ACKNOWLEDGED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
'PROXIMITY' => 'Sabre\\VObject\\Property\\Text',
'DEFAULT-ALARM' => 'Sabre\\VObject\\Property\\Boolean',
);
/**
* Returns the current document type.
*
* @return void
*/
public function getDocumentType() {
return self::ICALENDAR20;
}
/**
* Returns a list of all 'base components'. For instance, if an Event has
@ -115,13 +250,19 @@ class VCalendar extends VObject\Document {
}
// Setting all properties to UTC time.
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);
}
if ($child instanceof VObject\Property\ICalendar\DateTime && $child->hasTime()) {
$dt = $child->getDateTimes();
// We only need to update the first timezone, because
// setDateTimes will match all other timezones to the
// first.
$dt[0]->setTimeZone(new \DateTimeZone('UTC'));
$child->setDateTimes($dt);
}
}
$this->add($newEvent);
@ -133,6 +274,21 @@ class VCalendar extends VObject\Document {
}
/**
* This method should return a list of default property values.
*
* @return array
*/
protected function getDefaults() {
return array(
'VERSION' => '2.0',
'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
'CALSCALE' => 'GREGORIAN',
);
}
/**
* Validates the node for correctness.
* An array is returned with warnings.
@ -144,8 +300,7 @@ class VCalendar extends VObject\Document {
*
* @return array
*/
/*
public function validate() {
public function validate($options = 0) {
$warnings = array();
@ -188,39 +343,10 @@ class VCalendar extends VObject\Document {
);
}
$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,
);
}
}
}
@ -238,7 +364,6 @@ class VCalendar extends VObject\Document {
);
}
*/
}

View file

@ -2,7 +2,8 @@
namespace Sabre\VObject\Component;
use Sabre\VObject;
use
Sabre\VObject;
/**
* The VCard component
@ -14,16 +15,164 @@ use Sabre\VObject;
* @author Evert Pot (http://evertpot.com/)
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
*/
class VCard extends VObject\Component {
class VCard extends VObject\Document {
static $defaultName = 'VCARD';
/**
* The default name for this component.
*
* This should be 'VCALENDAR' or 'VCARD'.
*
* @var string
*/
static public $defaultName = 'VCARD';
/**
* Caching the version number
*
* @var int
*/
private $version = null;
/**
* List of value-types, and which classes they map to.
*
* @var array
*/
static public $valueMap = array(
'BINARY' => 'Sabre\\VObject\\Property\\Binary',
'BOOLEAN' => 'Sabre\\VObject\\Property\\Boolean',
'CONTENT-ID' => 'Sabre\\VObject\\Property\\FlatText', // vCard 2.1 only
'DATE' => 'Sabre\\VObject\\Property\\VCard\\Date',
'DATE-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateTime',
'DATE-AND-OR-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', // vCard only
'FLOAT' => 'Sabre\\VObject\\Property\\Float',
'INTEGER' => 'Sabre\\VObject\\Property\\Integer',
'LANGUAGE-TAG' => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
'TIMESTAMP' => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
'TEXT' => 'Sabre\\VObject\\Property\\Text',
'TIME' => 'Sabre\\VObject\\Property\\Time',
'UNKNOWN' => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
'URI' => 'Sabre\\VObject\\Property\\Uri',
'URL' => 'Sabre\\VObject\\Property\\Uri', // vCard 2.1 only
'UTC-OFFSET' => 'Sabre\\VObject\\Property\\UtcOffset',
);
/**
* List of properties, and which classes they map to.
*
* @var array
*/
static public $propertyMap = array(
// vCard 2.1 properties and up
'N' => 'Sabre\\VObject\\Property\\Text',
'FN' => 'Sabre\\VObject\\Property\\FlatText',
'PHOTO' => 'Sabre\\VObject\\Property\\Binary', // Todo: we should add a class for Binary values.
'BDAY' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
'ADR' => 'Sabre\\VObject\\Property\\Text',
'LABEL' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
'TEL' => 'Sabre\\VObject\\Property\\FlatText',
'EMAIL' => 'Sabre\\VObject\\Property\\FlatText',
'MAILER' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
'GEO' => 'Sabre\\VObject\\Property\\FlatText',
'TITLE' => 'Sabre\\VObject\\Property\\FlatText',
'ROLE' => 'Sabre\\VObject\\Property\\FlatText',
'LOGO' => 'Sabre\\VObject\\Property\\Binary',
// 'AGENT' => 'Sabre\\VObject\\Property\\', // Todo: is an embedded vCard. Probably rare, so
// not supported at the moment
'ORG' => 'Sabre\\VObject\\Property\\Text',
'NOTE' => 'Sabre\\VObject\\Property\\FlatText',
'REV' => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
'SOUND' => 'Sabre\\VObject\\Property\\FlatText',
'URL' => 'Sabre\\VObject\\Property\\Uri',
'UID' => 'Sabre\\VObject\\Property\\FlatText',
'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
'KEY' => 'Sabre\\VObject\\Property\\FlatText',
'TZ' => 'Sabre\\VObject\\Property\\Text',
// vCard 3.0 properties
'CATEGORIES' => 'Sabre\\VObject\\Property\\Text',
'SORT-STRING' => 'Sabre\\VObject\\Property\\FlatText',
'PRODID' => 'Sabre\\VObject\\Property\\FlatText',
'NICKNAME' => 'Sabre\\VObject\\Property\\Text',
'CLASS' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
// rfc2739 properties
'FBURL' => 'Sabre\\VObject\\Property\\Uri',
'CAPURI' => 'Sabre\\VObject\\Property\\Uri',
'CALURI' => 'Sabre\\VObject\\Property\\Uri',
// rfc4770 properties
'IMPP' => 'Sabre\\VObject\\Property\\Uri',
// vCard 4.0 properties
'XML' => 'Sabre\\VObject\\Property\\FlatText',
'ANNIVERSARY' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
'CLIENTPIDMAP' => 'Sabre\\VObject\\Property\\Text',
'LANG' => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
'GENDER' => 'Sabre\\VObject\\Property\\Text',
'KIND' => 'Sabre\\VObject\\Property\\FlatText',
);
/**
* Returns the current document type.
*
* @return void
*/
public function getDocumentType() {
if (!$this->version) {
$version = (string)$this->VERSION;
switch($version) {
case '2.1' :
$this->version = self::VCARD21;
break;
case '3.0' :
$this->version = self::VCARD30;
break;
case '4.0' :
$this->version = self::VCARD40;
break;
default :
$this->version = self::UNKNOWN;
break;
}
}
return $this->version;
}
/**
* Converts the document to a different vcard version.
*
* Use one of the VCARD constants for the target. This method will return
* a copy of the vcard in the new version.
*
* At the moment the only supported conversion is from 3.0 to 4.0.
*
* If input and output version are identical, a clone is returned.
*
* @param int $target
* @return VCard
*/
public function convert($target) {
$converter = new VObject\VCardConverter();
return $converter->convert($this, $target);
}
/**
* VCards with version 2.1, 3.0 and 4.0 are found.
*
* If the VCARD doesn't know its version, 4.0 is assumed.
* If the VCARD doesn't know its version, 2.1 is assumed.
*/
const DEFAULT_VERSION = '4.0';
const DEFAULT_VERSION = self::VCARD21;
/**
* Validates the node for correctness.
@ -46,6 +195,12 @@ class VCard extends VObject\Component {
$warnings = array();
$versionMap = array(
self::VCARD21 => '2.1',
self::VCARD30 => '3.0',
self::VCARD40 => '4.0',
);
$version = $this->select('VERSION');
if (count($version)!==1) {
$warnings[] = array(
@ -54,7 +209,7 @@ class VCard extends VObject\Component {
'node' => $this,
);
if ($options & self::REPAIR) {
$this->VERSION = self::DEFAULT_VERSION;
$this->VERSION = $versionMap[self::DEFAULT_VERSION];
}
} else {
$version = (string)$this->VERSION;
@ -65,7 +220,7 @@ class VCard extends VObject\Component {
'node' => $this,
);
if ($options & self::REPAIR) {
$this->VERSION = '4.0';
$this->VERSION = $versionMap[self::DEFAULT_VERSION];
}
}
@ -103,5 +258,96 @@ class VCard extends VObject\Component {
}
/**
* Returns a preferred field.
*
* VCards can indicate wether a field such as ADR, TEL or EMAIL is
* preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
* being a number between 1 and 100).
*
* If neither of those parameters are specified, the first is returned, if
* a field with that name does not exist, null is returned.
*
* @param string $fieldName
* @return VObject\Property|null
*/
public function preferred($propertyName) {
$preferred = null;
$lastPref = 101;
foreach($this->select($propertyName) as $field) {
$pref = 101;
if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
$pref = 1;
} elseif (isset($field['PREF'])) {
$pref = $field['PREF']->getValue();
}
if ($pref < $lastPref || is_null($preferred)) {
$preferred = $field;
$lastPref = $pref;
}
}
return $preferred;
}
/**
* This method should return a list of default property values.
*
* @return array
*/
protected function getDefaults() {
return array(
'VERSION' => '3.0',
'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
);
}
/**
* This method returns an array, with the representation as it should be
* encoded in json. This is used to create jCard or jCal documents.
*
* @return array
*/
public function jsonSerialize() {
// A vcard does not have sub-components, so we're overriding this
// method to remove that array element.
$properties = array();
foreach($this->children as $child) {
$properties[] = $child->jsonSerialize();
}
return array(
strtolower($this->name),
$properties,
);
}
/**
* Returns the default class for a property name.
*
* @param string $propertyName
* @return string
*/
public function getClassNameForPropertyName($propertyName) {
$className = parent::getClassNameForPropertyName($propertyName);
// In vCard 4, BINARY no longer exists, and we need URI instead.
if ($className == 'Sabre\\VObject\\Property\\Binary' && $this->getDocumentType()===self::VCARD40) {
return 'Sabre\\VObject\\Property\\Uri';
}
return $className;
}
}

View file

@ -55,7 +55,7 @@ class VEvent extends VObject\Component {
} elseif (isset($this->DURATION)) {
$effectiveEnd = clone $effectiveStart;
$effectiveEnd->add( VObject\DateTimeParser::parseDuration($this->DURATION) );
} elseif ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) {
} elseif (!$this->DTSTART->hasTime()) {
$effectiveEnd = clone $effectiveStart;
$effectiveEnd->modify('+1 day');
} else {

View file

@ -31,7 +31,7 @@ class VJournal extends VObject\Component {
$dtstart = isset($this->DTSTART)?$this->DTSTART->getDateTime():null;
if ($dtstart) {
$effectiveEnd = clone $dtstart;
if ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) {
if (!$this->DTSTART->hasTime()) {
$effectiveEnd->modify('+1 day');
}