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