1<?php
2
3use \Sabre\VObject;
4use \Sabre\CalDAV;
5use \Sabre\DAV;
6use \Sabre\DAV\Exception\Forbidden;
7/**
8 * PDO CalDAV backend for DokuWiki - based on Sabre's CalDAV backend
9 *
10 * This backend is used to store calendar-data in a PDO database, such as
11 * sqlite or MySQL
12 *
13 * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
14 * @author Evert Pot (http://evertpot.com/)
15 * @license http://sabre.io/license/ Modified BSD License
16 */
17class DokuWikiSabreCalendarBackend extends \Sabre\CalDAV\Backend\AbstractBackend
18{
19
20
21    /**
22     * DokuWiki PlugIn Helper
23     */
24    protected $hlp = null;
25    /**
26
27    /**
28     * List of CalDAV properties, and how they map to database fieldnames
29     * Add your own properties by simply adding on to this array.
30     *
31     * Note that only string-based properties are supported here.
32     *
33     * @var array
34     */
35    public $propertyMap = array(
36        '{DAV:}displayname'                                   => 'displayname',
37        '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description',
38        '{urn:ietf:params:xml:ns:caldav}calendar-timezone'    => 'timezone',
39        //'{http://apple.com/ns/ical/}calendar-order'           => 'calendarorder',
40        //'{http://apple.com/ns/ical/}calendar-color'           => 'calendarcolor',
41    );
42
43    /**
44     * Creates the backend
45     *
46     * @param \PDO $pdo
47     */
48    function __construct(&$hlp)
49    {
50
51        $this->hlp = $hlp;
52
53    }
54
55    /**
56     * Returns a list of calendars for a principal.
57     *
58     * Every project is an array with the following keys:
59     *  * id, a unique id that will be used by other functions to modify the
60     *    calendar. This can be the same as the uri or a database key.
61     *  * uri. This is just the 'base uri' or 'filename' of the calendar.
62     *  * principaluri. The owner of the calendar. Almost always the same as
63     *    principalUri passed to this method.
64     *
65     * Furthermore it can contain webdav properties in clark notation. A very
66     * common one is '{DAV:}displayname'.
67     *
68     * Many clients also require:
69     * {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
70     * For this property, you can just return an instance of
71     * Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet.
72     *
73     * If you return {http://sabredav.org/ns}read-only and set the value to 1,
74     * ACL will automatically be put in read-only mode.
75     *
76     * @param string $principalUri
77     * @return array
78     */
79    function getCalendarsForUser($principalUri)
80    {
81        \dokuwiki\Logger::debug('DAVCAL', 'getCalendarsForUser called for: '.$principalUri, __FILE__, __LINE__);
82        $fields = array_values($this->propertyMap);
83        $fields[] = 'id';
84        $fields[] = 'uri';
85        $fields[] = 'synctoken';
86        $fields[] = 'components';
87        $fields[] = 'principaluri';
88        $fields[] = 'transparent';
89
90        $idInfo = $this->hlp->getCalendarIdsForUser($principalUri);
91        $calendars = array();
92        foreach($idInfo as $id => $data)
93        {
94            $row = $this->hlp->getCalendarSettings($id);
95
96            // Skip this calendar if settings couldn't be retrieved
97            if (!$row) {
98                \dokuwiki\Logger::debug('DAVCAL', 'Skipping calendar '.$id.' - settings not found', __FILE__, __LINE__);
99                continue;
100            }
101
102            $components = array();
103            if ($row['components'])
104            {
105                $components = explode(',', $row['components']);
106            }
107
108            $calendar = array(
109                'id'                                                                 => $row['id'],
110                'uri'                                                                => $row['uri'],
111                'principaluri'                                                       => $principalUri,//Overwrite principaluri from database, we actually don't need it.
112                '{' . CalDAV\Plugin::NS_CALENDARSERVER . '}getctag'                  => 'http://sabre.io/ns/sync/' . ($row['synctoken'] ? $row['synctoken'] : '0'),
113                '{http://sabredav.org/ns}sync-token'                                 => $row['synctoken'] ? $row['synctoken'] : '0',
114                '{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet($components),
115                //'{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp'         => new CalDAV\Xml\Property\ScheduleCalendarTransp($row['transparent'] ? 'transparent' : 'opaque'),
116            );
117            if(isset($idInfo[$id]['readonly']) && $idInfo[$id]['readonly'] === true)
118                $calendar['{http://sabredav.org/ns}read-only'] = '1';
119
120
121            foreach ($this->propertyMap as $xmlName => $dbName)
122            {
123                $calendar[$xmlName] = $row[$dbName];
124            }
125
126            $calendars[] = $calendar;
127
128        }
129        \dokuwiki\Logger::debug('DAVCAL', 'Calendars returned: '.count($calendars), __FILE__, __LINE__);
130        return $calendars;
131
132    }
133
134    /**
135     * Creates a new calendar for a principal.
136     *
137     * If the creation was a success, an id must be returned that can be used
138     * to reference this calendar in other methods, such as updateCalendar.
139     *
140     * @param string $principalUri
141     * @param string $calendarUri
142     * @param array $properties
143     * @return string
144     */
145    function createCalendar($principalUri, $calendarUri, array $properties)
146    {
147        \dokuwiki\Logger::debug('DAVCAL', 'createCalendar called, returning false', __FILE__, __LINE__);
148        return false;
149    }
150
151    /**
152     * Updates properties for a calendar.
153     *
154     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
155     * To do the actual updates, you must tell this object which properties
156     * you're going to process with the handle() method.
157     *
158     * Calling the handle method is like telling the PropPatch object "I
159     * promise I can handle updating this property".
160     *
161     * Read the PropPatch documenation for more info and examples.
162     *
163     * @param string $calendarId
164     * @param \Sabre\DAV\PropPatch $propPatch
165     * @return void
166     */
167    function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch)
168    {
169        \dokuwiki\Logger::debug('DAVCAL', 'updateCalendar for calendarId '.$calendarId, __FILE__, __LINE__);
170        $supportedProperties = array_keys($this->propertyMap);
171
172        $propPatch->handle($supportedProperties, function($mutations) use ($calendarId)
173        {
174            foreach ($mutations as $propertyName => $propertyValue)
175            {
176
177                switch ($propertyName)
178                {
179                    case '{DAV:}displayname' :
180                        \dokuwiki\Logger::debug('DAVCAL', 'updateCalendarName', __FILE__, __LINE__);
181                        $this->hlp->updateCalendarName($calendarId, $propertyValue);
182                        break;
183                    case '{urn:ietf:params:xml:ns:caldav}calendar-description':
184                        \dokuwiki\Logger::debug('DAVCAL', 'updateCalendarDescription', __FILE__, __LINE__);
185                        $this->hlp->updateCalendarDescription($calendarId, $propertyValue);
186                        break;
187                    case '{urn:ietf:params:xml:ns:caldav}calendar-timezone':
188                        \dokuwiki\Logger::debug('DAVCAL', 'updateCalendarTimezone', __FILE__, __LINE__);
189                        $this->hlp->updateCalendarTimezone($calendarId, $propertyValue);
190                        break;
191                    default :
192                        break;
193                }
194
195            }
196            return true;
197
198        });
199
200    }
201
202    /**
203     * Delete a calendar and all it's objects
204     *
205     * @param string $calendarId
206     * @return void
207     */
208    function deleteCalendar($calendarId)
209    {
210        \dokuwiki\Logger::debug('DAVCAL', 'deleteCalendar called, returning false', __FILE__, __LINE__);
211        return;
212    }
213
214    /**
215     * Returns all calendar objects within a calendar.
216     *
217     * Every item contains an array with the following keys:
218     *   * calendardata - The iCalendar-compatible calendar data
219     *   * uri - a unique key which will be used to construct the uri. This can
220     *     be any arbitrary string, but making sure it ends with '.ics' is a
221     *     good idea. This is only the basename, or filename, not the full
222     *     path.
223     *   * lastmodified - a timestamp of the last modification time
224     *   * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
225     *   '  "abcdef"')
226     *   * size - The size of the calendar objects, in bytes.
227     *   * component - optional, a string containing the type of object, such
228     *     as 'vevent' or 'vtodo'. If specified, this will be used to populate
229     *     the Content-Type header.
230     *
231     * Note that the etag is optional, but it's highly encouraged to return for
232     * speed reasons.
233     *
234     * The calendardata is also optional. If it's not returned
235     * 'getCalendarObject' will be called later, which *is* expected to return
236     * calendardata.
237     *
238     * If neither etag or size are specified, the calendardata will be
239     * used/fetched to determine these numbers. If both are specified the
240     * amount of times this is needed is reduced by a great degree.
241     *
242     * @param string $calendarId
243     * @return array
244     */
245    function getCalendarObjects($calendarId)
246    {
247        \dokuwiki\Logger::debug('DAVCAL', 'getCalendarObjects for calendarId '.$calendarId, __FILE__, __LINE__);
248        $arr = $this->hlp->getCalendarObjects($calendarId);
249        $result = array();
250        foreach ($arr as $row)
251        {
252            $result[] = array(
253                'id'           => $row['id'],
254                'uri'          => $row['uri'],
255                'lastmodified' => $row['lastmodified'],
256                'etag'         => '"' . $row['etag'] . '"',
257                'calendarid'   => $row['calendarid'],
258                'size'         => (int)$row['size'],
259                'component'    => strtolower($row['componenttype']),
260            );
261        }
262        \dokuwiki\Logger::debug('DAVCAL', 'Calendar objects returned: '.count($result), __FILE__, __LINE__);
263        return $result;
264
265    }
266
267    /**
268     * Returns information from a single calendar object, based on it's object
269     * uri.
270     *
271     * The object uri is only the basename, or filename and not a full path.
272     *
273     * The returned array must have the same keys as getCalendarObjects. The
274     * 'calendardata' object is required here though, while it's not required
275     * for getCalendarObjects.
276     *
277     * This method must return null if the object did not exist.
278     *
279     * @param string $calendarId
280     * @param string $objectUri
281     * @return array|null
282     */
283    function getCalendarObject($calendarId, $objectUri)
284    {
285        \dokuwiki\Logger::debug('DAVCAL', 'getCalendarObject for calendarId '.$calendarId.' and objectUri '.$objectUri, __FILE__, __LINE__);
286        $row = $this->hlp->getCalendarObjectByUri($calendarId, $objectUri);
287        \dokuwiki\Logger::debug('DAVCAL', 'Calendar object row: '.($row ? 'found' : 'not found'), __FILE__, __LINE__);
288        if (!$row)
289            return null;
290
291        return array(
292            'id'            => $row['id'],
293            'uri'           => $row['uri'],
294            'lastmodified'  => $row['lastmodified'],
295            'etag'          => '"' . $row['etag'] . '"',
296            'calendarid'    => $row['calendarid'],
297            'size'          => (int)$row['size'],
298            'calendardata'  => $row['calendardata'],
299            'component'     => strtolower($row['componenttype']),
300         );
301
302    }
303
304    /**
305     * Returns a list of calendar objects.
306     *
307     * This method should work identical to getCalendarObject, but instead
308     * return all the calendar objects in the list as an array.
309     *
310     * If the backend supports this, it may allow for some speed-ups.
311     *
312     * @param mixed $calendarId
313     * @param array $uris
314     * @return array
315     */
316    function getMultipleCalendarObjects($calendarId, array $uris)
317    {
318        \dokuwiki\Logger::debug('DAVCAL', 'getMultipleCalendarObjects for calendarId '.$calendarId, __FILE__, __LINE__);
319        \dokuwiki\Logger::debug('DAVCAL', 'URIs requested: '.count($uris), __FILE__, __LINE__);
320        $arr = $this->hlp->getMultipleCalendarObjectsByUri($calendarId, $uris);
321
322        $result = array();
323        foreach($arr as $row)
324        {
325
326            $result[] = array(
327                'id'           => $row['id'],
328                'uri'          => $row['uri'],
329                'lastmodified' => $row['lastmodified'],
330                'etag'         => '"' . $row['etag'] . '"',
331                'calendarid'   => $row['calendarid'],
332                'size'         => (int)$row['size'],
333                'calendardata' => $row['calendardata'],
334                'component'    => strtolower($row['componenttype']),
335            );
336
337        }
338        \dokuwiki\Logger::debug('DAVCAL', 'Multiple calendar objects returned: '.count($result), __FILE__, __LINE__);
339        return $result;
340
341    }
342
343
344    /**
345     * Creates a new calendar object.
346     *
347     * The object uri is only the basename, or filename and not a full path.
348     *
349     * It is possible return an etag from this function, which will be used in
350     * the response to this PUT request. Note that the ETag must be surrounded
351     * by double-quotes.
352     *
353     * However, you should only really return this ETag if you don't mangle the
354     * calendar-data. If the result of a subsequent GET to this object is not
355     * the exact same as this request body, you should omit the ETag.
356     *
357     * @param mixed $calendarId
358     * @param string $objectUri
359     * @param string $calendarData
360     * @return string|null
361     */
362    function createCalendarObject($calendarId, $objectUri, $calendarData)
363    {
364        \dokuwiki\Logger::debug('DAVCAL', 'createCalendarObject for calendarId '.$calendarId.' and objectUri '.$objectUri, __FILE__, __LINE__);
365        \dokuwiki\Logger::debug('DAVCAL', 'Calendar data length: '.strlen($calendarData), __FILE__, __LINE__);
366        $etag = $this->hlp->addCalendarEntryToCalendarByICS($calendarId, $objectUri, $calendarData);
367        \dokuwiki\Logger::debug('DAVCAL', 'ETag generated: '.$etag, __FILE__, __LINE__);
368
369        return '"' . $etag . '"';
370    }
371
372    /**
373     * Updates an existing calendarobject, based on it's uri.
374     *
375     * The object uri is only the basename, or filename and not a full path.
376     *
377     * It is possible return an etag from this function, which will be used in
378     * the response to this PUT request. Note that the ETag must be surrounded
379     * by double-quotes.
380     *
381     * However, you should only really return this ETag if you don't mangle the
382     * calendar-data. If the result of a subsequent GET to this object is not
383     * the exact same as this request body, you should omit the ETag.
384     *
385     * @param mixed $calendarId
386     * @param string $objectUri
387     * @param string $calendarData
388     * @return string|null
389     */
390    function updateCalendarObject($calendarId, $objectUri, $calendarData)
391    {
392        \dokuwiki\Logger::debug('DAVCAL', 'updateCalendarObject for calendarId '.$calendarId.' and objectUri '.$objectUri, __FILE__, __LINE__);
393        \dokuwiki\Logger::debug('DAVCAL', 'Calendar data length: '.strlen($calendarData), __FILE__, __LINE__);
394        $etag = $this->hlp->editCalendarEntryToCalendarByICS($calendarId, $objectUri, $calendarData);
395        \dokuwiki\Logger::debug('DAVCAL', 'ETag generated: '.$etag, __FILE__, __LINE__);
396        return '"' . $etag. '"';
397
398    }
399
400
401
402    /**
403     * Deletes an existing calendar object.
404     *
405     * The object uri is only the basename, or filename and not a full path.
406     *
407     * @param string $calendarId
408     * @param string $objectUri
409     * @return void
410     */
411    function deleteCalendarObject($calendarId, $objectUri)
412    {
413        \dokuwiki\Logger::debug('DAVCAL', 'deleteCalendarObject for calendarId '.$calendarId.' and objectUri '.$objectUri, __FILE__, __LINE__);
414        $this->hlp->deleteCalendarEntryForCalendarByUri($calendarId, $objectUri);
415
416    }
417
418    /**
419     * Performs a calendar-query on the contents of this calendar.
420     *
421     * The calendar-query is defined in RFC4791 : CalDAV. Using the
422     * calendar-query it is possible for a client to request a specific set of
423     * object, based on contents of iCalendar properties, date-ranges and
424     * iCalendar component types (VTODO, VEVENT).
425     *
426     * This method should just return a list of (relative) urls that match this
427     * query.
428     *
429     * The list of filters are specified as an array. The exact array is
430     * documented by \Sabre\CalDAV\CalendarQueryParser.
431     *
432     * Note that it is extremely likely that getCalendarObject for every path
433     * returned from this method will be called almost immediately after. You
434     * may want to anticipate this to speed up these requests.
435     *
436     * This method provides a default implementation, which parses *all* the
437     * iCalendar objects in the specified calendar.
438     *
439     * This default may well be good enough for personal use, and calendars
440     * that aren't very large. But if you anticipate high usage, big calendars
441     * or high loads, you are strongly adviced to optimize certain paths.
442     *
443     * The best way to do so is override this method and to optimize
444     * specifically for 'common filters'.
445     *
446     * Requests that are extremely common are:
447     *   * requests for just VEVENTS
448     *   * requests for just VTODO
449     *   * requests with a time-range-filter on a VEVENT.
450     *
451     * ..and combinations of these requests. It may not be worth it to try to
452     * handle every possible situation and just rely on the (relatively
453     * easy to use) CalendarQueryValidator to handle the rest.
454     *
455     * Note that especially time-range-filters may be difficult to parse. A
456     * time-range filter specified on a VEVENT must for instance also handle
457     * recurrence rules correctly.
458     * A good example of how to interprete all these filters can also simply
459     * be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct
460     * as possible, so it gives you a good idea on what type of stuff you need
461     * to think of.
462     *
463     * This specific implementation (for the PDO) backend optimizes filters on
464     * specific components, and VEVENT time-ranges.
465     *
466     * @param string $calendarId
467     * @param array $filters
468     * @return array
469     */
470    function calendarQuery($calendarId, array $filters)
471    {
472        \dokuwiki\Logger::debug('DAVCAL', 'calendarQuery for calendarId '.$calendarId, __FILE__, __LINE__);
473        \dokuwiki\Logger::debug('DAVCAL', 'Filters count: '.count($filters), __FILE__, __LINE__);
474        $result = $this->hlp->calendarQuery($calendarId, $filters);
475        \dokuwiki\Logger::debug('DAVCAL', 'Query results: '.count($result), __FILE__, __LINE__);
476        return $result;
477    }
478
479    /**
480     * Searches through all of a users calendars and calendar objects to find
481     * an object with a specific UID.
482     *
483     * This method should return the path to this object, relative to the
484     * calendar home, so this path usually only contains two parts:
485     *
486     * calendarpath/objectpath.ics
487     *
488     * If the uid is not found, return null.
489     *
490     * This method should only consider * objects that the principal owns, so
491     * any calendars owned by other principals that also appear in this
492     * collection should be ignored.
493     *
494     * @param string $principalUri
495     * @param string $uid
496     * @return string|null
497     */
498    function getCalendarObjectByUID($principalUri, $uid)
499    {
500        \dokuwiki\Logger::debug('DAVCAL', 'getCalendarObjectByUID for principalUri '.$principalUri.' and uid '.$uid, __FILE__, __LINE__);
501        $calids = array_keys($this->hlp->getCalendarIsForUser($principalUri));
502        $event = $this->hlp->getEventWithUid($uid);
503
504        if(in_array($event['calendarid'], $calids))
505        {
506            $settings = $this->hlp->getCalendarSettings($event['calendarid']);
507            return $settings['uri'] . '/' . $event['uri'];
508        }
509        return null;
510    }
511
512    /**
513     * The getChanges method returns all the changes that have happened, since
514     * the specified syncToken in the specified calendar.
515     *
516     * This function should return an array, such as the following:
517     *
518     * [
519     *   'syncToken' => 'The current synctoken',
520     *   'added'   => [
521     *      'new.txt',
522     *   ],
523     *   'modified'   => [
524     *      'modified.txt',
525     *   ],
526     *   'deleted' => [
527     *      'foo.php.bak',
528     *      'old.txt'
529     *   ]
530     * ];
531     *
532     * The returned syncToken property should reflect the *current* syncToken
533     * of the calendar, as reported in the {http://sabredav.org/ns}sync-token
534     * property this is needed here too, to ensure the operation is atomic.
535     *
536     * If the $syncToken argument is specified as null, this is an initial
537     * sync, and all members should be reported.
538     *
539     * The modified property is an array of nodenames that have changed since
540     * the last token.
541     *
542     * The deleted property is an array with nodenames, that have been deleted
543     * from collection.
544     *
545     * The $syncLevel argument is basically the 'depth' of the report. If it's
546     * 1, you only have to report changes that happened only directly in
547     * immediate descendants. If it's 2, it should also include changes from
548     * the nodes below the child collections. (grandchildren)
549     *
550     * The $limit argument allows a client to specify how many results should
551     * be returned at most. If the limit is not specified, it should be treated
552     * as infinite.
553     *
554     * If the limit (infinite or not) is higher than you're willing to return,
555     * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
556     *
557     * If the syncToken is expired (due to data cleanup) or unknown, you must
558     * return null.
559     *
560     * The limit is 'suggestive'. You are free to ignore it.
561     *
562     * @param string $calendarId
563     * @param string $syncToken
564     * @param int $syncLevel
565     * @param int $limit
566     * @return array
567     */
568    function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null)
569    {
570        \dokuwiki\Logger::debug('DAVCAL', 'getChangesForCalendar for calendarId '.$calendarId.' and syncToken '.$syncToken.' and syncLevel '.$syncLevel, __FILE__, __LINE__);
571        $result = $this->hlp->getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit);
572        \dokuwiki\Logger::debug('DAVCAL', 'Changes result: '.($result ? 'found' : 'not found'), __FILE__, __LINE__);
573        return $result;
574    }
575
576    /**
577     * Returns a list of subscriptions for a principal.
578     *
579     * Every subscription is an array with the following keys:
580     *  * id, a unique id that will be used by other functions to modify the
581     *    subscription. This can be the same as the uri or a database key.
582     *  * uri. This is just the 'base uri' or 'filename' of the subscription.
583     *  * principaluri. The owner of the subscription. Almost always the same as
584     *    principalUri passed to this method.
585     *  * source. Url to the actual feed
586     *
587     * Furthermore, all the subscription info must be returned too:
588     *
589     * 1. {DAV:}displayname
590     * 2. {http://apple.com/ns/ical/}refreshrate
591     * 3. {http://calendarserver.org/ns/}subscribed-strip-todos (omit if todos
592     *    should not be stripped).
593     * 4. {http://calendarserver.org/ns/}subscribed-strip-alarms (omit if alarms
594     *    should not be stripped).
595     * 5. {http://calendarserver.org/ns/}subscribed-strip-attachments (omit if
596     *    attachments should not be stripped).
597     * 7. {http://apple.com/ns/ical/}calendar-color
598     * 8. {http://apple.com/ns/ical/}calendar-order
599     * 9. {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
600     *    (should just be an instance of
601     *    Sabre\CalDAV\Property\SupportedCalendarComponentSet, with a bunch of
602     *    default components).
603     *
604     * @param string $principalUri
605     * @return array
606     */
607    function getSubscriptionsForUser($principalUri)
608    {
609        \dokuwiki\Logger::debug('DAVCAL', 'getSubscriptionsForUser with principalUri '.$principalUri.', returning empty array()', __FILE__, __LINE__);
610        return array();
611
612    }
613
614    /**
615     * Creates a new subscription for a principal.
616     *
617     * If the creation was a success, an id must be returned that can be used to reference
618     * this subscription in other methods, such as updateSubscription.
619     *
620     * @param string $principalUri
621     * @param string $uri
622     * @param array $properties
623     * @return mixed
624     */
625    function createSubscription($principalUri, $uri, array $properties)
626    {
627        \dokuwiki\Logger::debug('DAVCAL', 'createSubscription for principalUri '.$principalUri.' and uri '.$uri.', returning null', __FILE__, __LINE__);
628        return null;
629
630    }
631
632    /**
633     * Updates a subscription
634     *
635     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
636     * To do the actual updates, you must tell this object which properties
637     * you're going to process with the handle() method.
638     *
639     * Calling the handle method is like telling the PropPatch object "I
640     * promise I can handle updating this property".
641     *
642     * Read the PropPatch documenation for more info and examples.
643     *
644     * @param mixed $subscriptionId
645     * @param \Sabre\DAV\PropPatch $propPatch
646     * @return void
647     */
648    function updateSubscription($subscriptionId, DAV\PropPatch $propPatch)
649    {
650        \dokuwiki\Logger::debug('DAVCAL', 'updateSubscription with subscriptionId '.$subscriptionId.', returning false', __FILE__, __LINE__);
651        return;
652    }
653
654    /**
655     * Deletes a subscription
656     *
657     * @param mixed $subscriptionId
658     * @return void
659     */
660    function deleteSubscription($subscriptionId)
661    {
662        \dokuwiki\Logger::debug('DAVCAL', 'deleteSubscription with subscriptionId '.$subscriptionId.', returning', __FILE__, __LINE__);
663        return;
664
665    }
666
667    /**
668     * Returns a single scheduling object.
669     *
670     * The returned array should contain the following elements:
671     *   * uri - A unique basename for the object. This will be used to
672     *           construct a full uri.
673     *   * calendardata - The iCalendar object
674     *   * lastmodified - The last modification date. Can be an int for a unix
675     *                    timestamp, or a PHP DateTime object.
676     *   * etag - A unique token that must change if the object changed.
677     *   * size - The size of the object, in bytes.
678     *
679     * @param string $principalUri
680     * @param string $objectUri
681     * @return array
682     */
683    function getSchedulingObject($principalUri, $objectUri)
684    {
685        \dokuwiki\Logger::debug('DAVCAL', 'getSchedulingObject with principalUri '.$principalUri.' and objectUri '.$objectUri.', returning null', __FILE__, __LINE__);
686        return null;
687
688    }
689
690    /**
691     * Returns all scheduling objects for the inbox collection.
692     *
693     * These objects should be returned as an array. Every item in the array
694     * should follow the same structure as returned from getSchedulingObject.
695     *
696     * The main difference is that 'calendardata' is optional.
697     *
698     * @param string $principalUri
699     * @return array
700     */
701    function getSchedulingObjects($principalUri)
702    {
703        \dokuwiki\Logger::debug('DAVCAL', 'getSchedulingObjects for principalUri '.$principalUri.', returning null', __FILE__, __LINE__);
704        return null;
705
706    }
707
708    /**
709     * Deletes a scheduling object
710     *
711     * @param string $principalUri
712     * @param string $objectUri
713     * @return void
714     */
715    function deleteSchedulingObject($principalUri, $objectUri)
716    {
717        \dokuwiki\Logger::debug('DAVCAL', 'deleteSchedulingObject for principalUri '.$principalUri.' and objectUri '.$objectUri.', returning', __FILE__, __LINE__);
718        return;
719    }
720
721    /**
722     * Creates a new scheduling object. This should land in a users' inbox.
723     *
724     * @param string $principalUri
725     * @param string $objectUri
726     * @param string $objectData
727     * @return void
728     */
729    function createSchedulingObject($principalUri, $objectUri, $objectData)
730    {
731        \dokuwiki\Logger::debug('DAVCAL', 'createSchedulingObject with principalUri '.$principalUri.' and objectUri '.$objectUri.', returning', __FILE__, __LINE__);
732        return;
733
734    }
735
736}
737