xref: /plugin/davcal/helper.php (revision 3c86dda820bdac9817d70ca2f6d1cfa56482cf71)
1a1a3b679SAndreas Boehler<?php
2a1a3b679SAndreas Boehler/**
3cb71a62aSAndreas Boehler  * Helper Class for the DAVCal plugin
4a1a3b679SAndreas Boehler  * This helper does the actual work.
5a1a3b679SAndreas Boehler  *
6a1a3b679SAndreas Boehler  */
7a1a3b679SAndreas Boehler
8a1a3b679SAndreas Boehler// must be run within Dokuwiki
9a1a3b679SAndreas Boehlerif(!defined('DOKU_INC')) die();
10a1a3b679SAndreas Boehler
11a1a3b679SAndreas Boehlerclass helper_plugin_davcal extends DokuWiki_Plugin {
12a1a3b679SAndreas Boehler
13a1a3b679SAndreas Boehler  protected $sqlite = null;
14a1a3b679SAndreas Boehler
15a1a3b679SAndreas Boehler  /**
16cb71a62aSAndreas Boehler    * Constructor to load the configuration and the SQLite plugin
17a1a3b679SAndreas Boehler    */
18a1a3b679SAndreas Boehler  public function helper_plugin_davcal() {
19a1a3b679SAndreas Boehler    $this->sqlite =& plugin_load('helper', 'sqlite');
20a1a3b679SAndreas Boehler    if(!$this->sqlite)
21a1a3b679SAndreas Boehler    {
22a1a3b679SAndreas Boehler        msg('This plugin requires the sqlite plugin. Please install it.');
23a1a3b679SAndreas Boehler        return;
24a1a3b679SAndreas Boehler    }
25a1a3b679SAndreas Boehler
26a1a3b679SAndreas Boehler    if(!$this->sqlite->init('davcal', DOKU_PLUGIN.'davcal/db/'))
27a1a3b679SAndreas Boehler    {
28a1a3b679SAndreas Boehler        return;
29a1a3b679SAndreas Boehler    }
30a1a3b679SAndreas Boehler  }
31a1a3b679SAndreas Boehler
32cb71a62aSAndreas Boehler  /**
33cb71a62aSAndreas Boehler   * Set the calendar name and description for a given page with a given
34cb71a62aSAndreas Boehler   * page id.
35cb71a62aSAndreas Boehler   * If the calendar doesn't exist, the calendar is created!
36cb71a62aSAndreas Boehler   *
37cb71a62aSAndreas Boehler   * @param string  $name The name of the new calendar
38cb71a62aSAndreas Boehler   * @param string  $description The description of the new calendar
39cb71a62aSAndreas Boehler   * @param string  $id (optional) The ID of the page
40cb71a62aSAndreas Boehler   * @param string  $userid The userid of the creating user
41cb71a62aSAndreas Boehler   *
42cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false.
43cb71a62aSAndreas Boehler   */
44a1a3b679SAndreas Boehler  public function setCalendarNameForPage($name, $description, $id = null, $userid = null)
45a1a3b679SAndreas Boehler  {
46a1a3b679SAndreas Boehler      if(is_null($id))
47a1a3b679SAndreas Boehler      {
48a1a3b679SAndreas Boehler          global $ID;
49a1a3b679SAndreas Boehler          $id = $ID;
50a1a3b679SAndreas Boehler      }
51a1a3b679SAndreas Boehler      if(is_null($userid))
52a1a3b679SAndreas Boehler        $userid = $_SERVER['REMOTE_USER'];
53a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
54a1a3b679SAndreas Boehler      if($calid === false)
55a1a3b679SAndreas Boehler        return $this->createCalendarForPage($name, $description, $id, $userid);
56a1a3b679SAndreas Boehler
57b269830cSAndreas Boehler      $query = "UPDATE calendars SET displayname=".$this->sqlite->quote_string($name).", ".
58b269830cSAndreas Boehler               "description=".$this->sqlite->quote_string($description)." WHERE ".
59b269830cSAndreas Boehler               "id=".$this->sqlite->quote_string($calid);
60b269830cSAndreas Boehler      $res = $this->sqlite->query($query);
61b269830cSAndreas Boehler      if($res !== false)
62b269830cSAndreas Boehler        return true;
63b269830cSAndreas Boehler      return false;
64a1a3b679SAndreas Boehler  }
65a1a3b679SAndreas Boehler
66cb71a62aSAndreas Boehler  /**
67cb71a62aSAndreas Boehler   * Save the personal settings to the SQLite database 'calendarsettings'.
68cb71a62aSAndreas Boehler   *
69cb71a62aSAndreas Boehler   * @param array  $settings The settings array to store
70cb71a62aSAndreas Boehler   * @param string $userid (optional) The userid to store
71cb71a62aSAndreas Boehler   *
72cb71a62aSAndreas Boehler   * @param boolean True on success, otherwise false
73cb71a62aSAndreas Boehler   */
74a495d34cSAndreas Boehler  public function savePersonalSettings($settings, $userid = null)
75a495d34cSAndreas Boehler  {
76a495d34cSAndreas Boehler      if(is_null($userid))
77a495d34cSAndreas Boehler          $userid = $_SERVER['REMOTE_USER'];
78a495d34cSAndreas Boehler      $this->sqlite->query("BEGIN TRANSACTION");
79a495d34cSAndreas Boehler
80bd883736SAndreas Boehler      $query = "DELETE FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid);
81bd883736SAndreas Boehler      $this->sqlite->query($query);
82bd883736SAndreas Boehler
83a495d34cSAndreas Boehler      foreach($settings as $key => $value)
84a495d34cSAndreas Boehler      {
85bd883736SAndreas Boehler          $query = "INSERT INTO calendarsettings (userid, key, value) VALUES (".
86a495d34cSAndreas Boehler                   $this->sqlite->quote_string($userid).", ".
87a495d34cSAndreas Boehler                   $this->sqlite->quote_string($key).", ".
88a495d34cSAndreas Boehler                   $this->sqlite->quote_string($value).")";
89a495d34cSAndreas Boehler          $res = $this->sqlite->query($query);
90a495d34cSAndreas Boehler          if($res === false)
91a495d34cSAndreas Boehler              return false;
92a495d34cSAndreas Boehler      }
93a495d34cSAndreas Boehler      $this->sqlite->query("COMMIT TRANSACTION");
94a495d34cSAndreas Boehler      return true;
95a495d34cSAndreas Boehler  }
96a495d34cSAndreas Boehler
97cb71a62aSAndreas Boehler  /**
98cb71a62aSAndreas Boehler   * Retrieve the settings array for a given user id.
99cb71a62aSAndreas Boehler   * Some sane defaults are returned, currently:
100cb71a62aSAndreas Boehler   *
101cb71a62aSAndreas Boehler   *    timezone    => local
102cb71a62aSAndreas Boehler   *    weeknumbers => 0
103cb71a62aSAndreas Boehler   *    workweek    => 0
104cb71a62aSAndreas Boehler   *
105cb71a62aSAndreas Boehler   * @param string $userid (optional) The user id to retrieve
106cb71a62aSAndreas Boehler   *
107cb71a62aSAndreas Boehler   * @return array The settings array
108cb71a62aSAndreas Boehler   */
109a495d34cSAndreas Boehler  public function getPersonalSettings($userid = null)
110a495d34cSAndreas Boehler  {
111a495d34cSAndreas Boehler      if(is_null($userid))
112a495d34cSAndreas Boehler        $userid = $_SERVER['REMOTE_USER'];
113bd883736SAndreas Boehler      // Some sane default settings
114bd883736SAndreas Boehler      $settings = array(
115bd883736SAndreas Boehler        'timezone' => 'local',
116bd883736SAndreas Boehler        'weeknumbers' => '0',
117bd883736SAndreas Boehler        'workweek' => '0'
118bd883736SAndreas Boehler      );
119a495d34cSAndreas Boehler      $query = "SELECT key, value FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid);
120a495d34cSAndreas Boehler      $res = $this->sqlite->query($query);
121a495d34cSAndreas Boehler      $arr = $this->sqlite->res2arr($res);
122a495d34cSAndreas Boehler      foreach($arr as $row)
123a495d34cSAndreas Boehler      {
124a495d34cSAndreas Boehler          $settings[$row['key']] = $row['value'];
125a495d34cSAndreas Boehler      }
126a495d34cSAndreas Boehler      return $settings;
127a495d34cSAndreas Boehler  }
128a495d34cSAndreas Boehler
129cb71a62aSAndreas Boehler  /**
130cb71a62aSAndreas Boehler   * Retrieve the calendar ID based on a page ID from the SQLite table
131cb71a62aSAndreas Boehler   * 'pagetocalendarmapping'.
132cb71a62aSAndreas Boehler   *
133cb71a62aSAndreas Boehler   * @param string $id (optional) The page ID to retrieve the corresponding calendar
134cb71a62aSAndreas Boehler   *
135cb71a62aSAndreas Boehler   * @return mixed the ID on success, otherwise false
136cb71a62aSAndreas Boehler   */
137a1a3b679SAndreas Boehler  public function getCalendarIdForPage($id = null)
138a1a3b679SAndreas Boehler  {
139a1a3b679SAndreas Boehler      if(is_null($id))
140a1a3b679SAndreas Boehler      {
141a1a3b679SAndreas Boehler          global $ID;
142a1a3b679SAndreas Boehler          $id = $ID;
143a1a3b679SAndreas Boehler      }
144a1a3b679SAndreas Boehler
145a1a3b679SAndreas Boehler      $query = "SELECT calid FROM pagetocalendarmapping WHERE page=".$this->sqlite->quote_string($id);
146a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
147a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
148a1a3b679SAndreas Boehler      if(isset($row['calid']))
149a1a3b679SAndreas Boehler        return $row['calid'];
150a1a3b679SAndreas Boehler      else
151a1a3b679SAndreas Boehler        return false;
152a1a3b679SAndreas Boehler  }
153a1a3b679SAndreas Boehler
154cb71a62aSAndreas Boehler  /**
155cb71a62aSAndreas Boehler   * Retrieve the complete calendar id to page mapping.
156cb71a62aSAndreas Boehler   * This is necessary to be able to retrieve a list of
157cb71a62aSAndreas Boehler   * calendars for a given user and check the access rights.
158cb71a62aSAndreas Boehler   *
159cb71a62aSAndreas Boehler   * @return array The mapping array
160cb71a62aSAndreas Boehler   */
161a1a3b679SAndreas Boehler  public function getCalendarIdToPageMapping()
162a1a3b679SAndreas Boehler  {
163a1a3b679SAndreas Boehler      $query = "SELECT calid, page FROM pagetocalendarmapping";
164a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
165a1a3b679SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
166a1a3b679SAndreas Boehler      return $arr;
167a1a3b679SAndreas Boehler  }
168a1a3b679SAndreas Boehler
169cb71a62aSAndreas Boehler  /**
170cb71a62aSAndreas Boehler   * Retrieve all calendar IDs a given user has access to.
171cb71a62aSAndreas Boehler   * The user is specified by the principalUri, so the
172cb71a62aSAndreas Boehler   * user name is actually split from the URI component.
173cb71a62aSAndreas Boehler   *
174cb71a62aSAndreas Boehler   * Access rights are checked against DokuWiki's ACL
175cb71a62aSAndreas Boehler   * and applied accordingly.
176cb71a62aSAndreas Boehler   *
177cb71a62aSAndreas Boehler   * @param string $principalUri The principal URI to work on
178cb71a62aSAndreas Boehler   *
179cb71a62aSAndreas Boehler   * @return array An associative array of calendar IDs
180cb71a62aSAndreas Boehler   */
181a1a3b679SAndreas Boehler  public function getCalendarIdsForUser($principalUri)
182a1a3b679SAndreas Boehler  {
183a1a3b679SAndreas Boehler      $user = explode('/', $principalUri);
184a1a3b679SAndreas Boehler      $user = end($user);
185a1a3b679SAndreas Boehler      $mapping = $this->getCalendarIdToPageMapping();
186a1a3b679SAndreas Boehler      $calids = array();
187a1a3b679SAndreas Boehler      foreach($mapping as $row)
188a1a3b679SAndreas Boehler      {
189a1a3b679SAndreas Boehler          $id = $row['calid'];
190a1a3b679SAndreas Boehler          $page = $row['page'];
191a1a3b679SAndreas Boehler          $acl = auth_quickaclcheck($page);
192a1a3b679SAndreas Boehler          if($acl >= AUTH_READ)
193a1a3b679SAndreas Boehler          {
194a1a3b679SAndreas Boehler              $write = $acl > AUTH_READ;
195a1a3b679SAndreas Boehler              $calids[$id] = array('readonly' => !$write);
196a1a3b679SAndreas Boehler          }
197a1a3b679SAndreas Boehler      }
198a1a3b679SAndreas Boehler      return $calids;
199a1a3b679SAndreas Boehler  }
200a1a3b679SAndreas Boehler
201cb71a62aSAndreas Boehler  /**
202cb71a62aSAndreas Boehler   * Create a new calendar for a given page ID and set name and description
203cb71a62aSAndreas Boehler   * accordingly. Also update the pagetocalendarmapping table on success.
204cb71a62aSAndreas Boehler   *
205cb71a62aSAndreas Boehler   * @param string $name The calendar's name
206cb71a62aSAndreas Boehler   * @param string $description The calendar's description
207cb71a62aSAndreas Boehler   * @param string $id (optional) The page ID to work on
208cb71a62aSAndreas Boehler   * @param string $userid (optional) The user ID that created the calendar
209cb71a62aSAndreas Boehler   *
210cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
211cb71a62aSAndreas Boehler   */
212a1a3b679SAndreas Boehler  public function createCalendarForPage($name, $description, $id = null, $userid = null)
213a1a3b679SAndreas Boehler  {
214a1a3b679SAndreas Boehler      if(is_null($id))
215a1a3b679SAndreas Boehler      {
216a1a3b679SAndreas Boehler          global $ID;
217a1a3b679SAndreas Boehler          $id = $ID;
218a1a3b679SAndreas Boehler      }
219a1a3b679SAndreas Boehler      if(is_null($userid))
220a1a3b679SAndreas Boehler          $userid = $_SERVER['REMOTE_USER'];
221a1a3b679SAndreas Boehler      $values = array('principals/'.$userid,
222a1a3b679SAndreas Boehler                      $name,
223a1a3b679SAndreas Boehler                      str_replace(array('/', ' ', ':'), '_', $id),
224a1a3b679SAndreas Boehler                      $description,
225a1a3b679SAndreas Boehler                      'VEVENT,VTODO',
22655a741c0SAndreas Boehler                      0,
22755a741c0SAndreas Boehler                      1);
22855a741c0SAndreas Boehler      $query = "INSERT INTO calendars (principaluri, displayname, uri, description, components, transparent, synctoken) VALUES (".$this->sqlite->quote_and_join($values, ',').");";
229a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
23055a741c0SAndreas Boehler      if($res === false)
23155a741c0SAndreas Boehler        return false;
232cb71a62aSAndreas Boehler
233cb71a62aSAndreas Boehler      // Get the new calendar ID
234a1a3b679SAndreas Boehler      $query = "SELECT id FROM calendars WHERE principaluri=".$this->sqlite->quote_string($values[0])." AND ".
235a1a3b679SAndreas Boehler               "displayname=".$this->sqlite->quote_string($values[1])." AND ".
236a1a3b679SAndreas Boehler               "uri=".$this->sqlite->quote_string($values[2])." AND ".
237a1a3b679SAndreas Boehler               "description=".$this->sqlite->quote_string($values[3]);
238a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
239a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
240cb71a62aSAndreas Boehler
241cb71a62aSAndreas Boehler      // Update the pagetocalendarmapping table with the new calendar ID
242a1a3b679SAndreas Boehler      if(isset($row['id']))
243a1a3b679SAndreas Boehler      {
244a1a3b679SAndreas Boehler          $values = array($id, $row['id']);
245a1a3b679SAndreas Boehler          $query = "INSERT INTO pagetocalendarmapping (page, calid) VALUES (".$this->sqlite->quote_and_join($values, ',').")";
246a1a3b679SAndreas Boehler          $res = $this->sqlite->query($query);
24755a741c0SAndreas Boehler          return ($res !== false);
248a1a3b679SAndreas Boehler      }
249a1a3b679SAndreas Boehler
250a1a3b679SAndreas Boehler      return false;
251a1a3b679SAndreas Boehler  }
252a1a3b679SAndreas Boehler
253cb71a62aSAndreas Boehler  /**
254cb71a62aSAndreas Boehler   * Add a new iCal entry for a given page, i.e. a given calendar.
255cb71a62aSAndreas Boehler   *
256cb71a62aSAndreas Boehler   * The parameter array needs to contain
257cb71a62aSAndreas Boehler   *   timezone         => The timezone of the entries
258cb71a62aSAndreas Boehler   *   detectedtz       => The timezone as detected by the browser
259cb71a62aSAndreas Boehler   *   eventfrom        => The event's start date
260cb71a62aSAndreas Boehler   *   eventfromtime    => The event's start time
261cb71a62aSAndreas Boehler   *   eventto          => The event's end date
262cb71a62aSAndreas Boehler   *   eventtotime      => The event's end time
263cb71a62aSAndreas Boehler   *   eventname        => The event's name
264cb71a62aSAndreas Boehler   *   eventdescription => The event's description
265cb71a62aSAndreas Boehler   *
266cb71a62aSAndreas Boehler   * @param string $id The page ID to work on
267cb71a62aSAndreas Boehler   * @param string $user The user who created the calendar
268cb71a62aSAndreas Boehler   * @param string $params A parameter array with values to create
269cb71a62aSAndreas Boehler   *
270cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
271cb71a62aSAndreas Boehler   */
272a1a3b679SAndreas Boehler  public function addCalendarEntryToCalendarForPage($id, $user, $params)
273a1a3b679SAndreas Boehler  {
274bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
275bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
276bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
277a25c89eaSAndreas Boehler      elseif($settings['timezone'] === 'local')
278a25c89eaSAndreas Boehler          $timezone = new \DateTimeZone($params['detectedtz']);
279bd883736SAndreas Boehler      else
280bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
281cb71a62aSAndreas Boehler
282cb71a62aSAndreas Boehler      // Retrieve dates from settings
283b269830cSAndreas Boehler      $startDate = explode('-', $params['eventfrom']);
284b269830cSAndreas Boehler      $startTime = explode(':', $params['eventfromtime']);
285b269830cSAndreas Boehler      $endDate = explode('-', $params['eventto']);
286b269830cSAndreas Boehler      $endTime = explode(':', $params['eventtotime']);
287cb71a62aSAndreas Boehler
288cb71a62aSAndreas Boehler      // Load SabreDAV
289a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
290a1a3b679SAndreas Boehler      $vcalendar = new \Sabre\VObject\Component\VCalendar();
291cb71a62aSAndreas Boehler
292cb71a62aSAndreas Boehler      // Add VCalendar, UID and Event Name
293a1a3b679SAndreas Boehler      $event = $vcalendar->add('VEVENT');
294b269830cSAndreas Boehler      $uuid = \Sabre\VObject\UUIDUtil::getUUID();
295b269830cSAndreas Boehler      $event->add('UID', $uuid);
296a1a3b679SAndreas Boehler      $event->summary = $params['eventname'];
297cb71a62aSAndreas Boehler
298cb71a62aSAndreas Boehler      // Add a description if requested
2990eebc909SAndreas Boehler      $description = $params['eventdescription'];
3000eebc909SAndreas Boehler      if($description !== '')
3010eebc909SAndreas Boehler        $event->add('DESCRIPTION', $description);
302cb71a62aSAndreas Boehler
303cb71a62aSAndreas Boehler      // Create a timestamp for last modified, created and dtstamp values in UTC
304b269830cSAndreas Boehler      $dtStamp = new \DateTime(null, new \DateTimeZone('UTC'));
305b269830cSAndreas Boehler      $event->add('DTSTAMP', $dtStamp);
306b269830cSAndreas Boehler      $event->add('CREATED', $dtStamp);
307b269830cSAndreas Boehler      $event->add('LAST-MODIFIED', $dtStamp);
308cb71a62aSAndreas Boehler
309cb71a62aSAndreas Boehler      // Adjust the start date, based on the given timezone information
310b269830cSAndreas Boehler      $dtStart = new \DateTime();
311a25c89eaSAndreas Boehler      $dtStart->setTimezone($timezone);
312b269830cSAndreas Boehler      $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2]));
313cb71a62aSAndreas Boehler
314cb71a62aSAndreas Boehler      // Only add the time values if it's not an allday event
315b269830cSAndreas Boehler      if($params['allday'] != '1')
316b269830cSAndreas Boehler        $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0);
317cb71a62aSAndreas Boehler
318cb71a62aSAndreas Boehler      // Adjust the end date, based on the given timezone information
319b269830cSAndreas Boehler      $dtEnd = new \DateTime();
320a25c89eaSAndreas Boehler      $dtEnd->setTimezone($timezone);
321b269830cSAndreas Boehler      $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2]));
322cb71a62aSAndreas Boehler
323cb71a62aSAndreas Boehler      // Only add the time values if it's not an allday event
324b269830cSAndreas Boehler      if($params['allday'] != '1')
325b269830cSAndreas Boehler        $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0);
326cb71a62aSAndreas Boehler
327b269830cSAndreas Boehler      // According to the VCal spec, we need to add a whole day here
328b269830cSAndreas Boehler      if($params['allday'] == '1')
329b269830cSAndreas Boehler          $dtEnd->add(new \DateInterval('P1D'));
330cb71a62aSAndreas Boehler
331cb71a62aSAndreas Boehler      // Really add Start and End events
332b269830cSAndreas Boehler      $dtStartEv = $event->add('DTSTART', $dtStart);
333b269830cSAndreas Boehler      $dtEndEv = $event->add('DTEND', $dtEnd);
334cb71a62aSAndreas Boehler
335cb71a62aSAndreas Boehler      // Adjust the DATE format for allday events
336b269830cSAndreas Boehler      if($params['allday'] == '1')
337b269830cSAndreas Boehler      {
338b269830cSAndreas Boehler          $dtStartEv['VALUE'] = 'DATE';
339b269830cSAndreas Boehler          $dtEndEv['VALUE'] = 'DATE';
340b269830cSAndreas Boehler      }
341cb71a62aSAndreas Boehler
342cb71a62aSAndreas Boehler      // Actually add the values to the database
343a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
344a1a3b679SAndreas Boehler      $uri = uniqid('dokuwiki-').'.ics';
345a1a3b679SAndreas Boehler      $now = new DateTime();
346a1a3b679SAndreas Boehler      $eventStr = $vcalendar->serialize();
347a1a3b679SAndreas Boehler
348a1a3b679SAndreas Boehler      $values = array($calid,
349a1a3b679SAndreas Boehler                      $uri,
350a1a3b679SAndreas Boehler                      $eventStr,
351a1a3b679SAndreas Boehler                      $now->getTimestamp(),
352a1a3b679SAndreas Boehler                      'VEVENT',
353a1a3b679SAndreas Boehler                      $event->DTSTART->getDateTime()->getTimeStamp(),
354a1a3b679SAndreas Boehler                      $event->DTEND->getDateTime()->getTimeStamp(),
355a1a3b679SAndreas Boehler                      strlen($eventStr),
356a1a3b679SAndreas Boehler                      md5($eventStr),
357cb71a62aSAndreas Boehler                      $uuid
358a1a3b679SAndreas Boehler      );
359a1a3b679SAndreas Boehler
360a1a3b679SAndreas Boehler      $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, componenttype, firstoccurence, lastoccurence, size, etag, uid) VALUES (".$this->sqlite->quote_and_join($values, ',').")";
361a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
362cb71a62aSAndreas Boehler
363cb71a62aSAndreas Boehler      // If successfully, update the sync token database
36455a741c0SAndreas Boehler      if($res !== false)
36555a741c0SAndreas Boehler      {
36655a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'added');
367a1a3b679SAndreas Boehler          return true;
368a1a3b679SAndreas Boehler      }
36955a741c0SAndreas Boehler      return false;
37055a741c0SAndreas Boehler  }
371a1a3b679SAndreas Boehler
372cb71a62aSAndreas Boehler  /**
373cb71a62aSAndreas Boehler   * Retrieve the calendar settings of a given calendar id
374cb71a62aSAndreas Boehler   *
375cb71a62aSAndreas Boehler   * @param string $calid The calendar ID
376cb71a62aSAndreas Boehler   *
377cb71a62aSAndreas Boehler   * @return array The calendar settings array
378cb71a62aSAndreas Boehler   */
379b269830cSAndreas Boehler  public function getCalendarSettings($calid)
380b269830cSAndreas Boehler  {
381b269830cSAndreas Boehler      $query = "SELECT principaluri, displayname, uri, description, components, transparent, synctoken FROM calendars WHERE id=".$this->sqlite->quote_string($calid);
382b269830cSAndreas Boehler      $res = $this->sqlite->query($query);
383b269830cSAndreas Boehler      $row = $this->sqlite->res2row($res);
384b269830cSAndreas Boehler      return $row;
385b269830cSAndreas Boehler  }
386b269830cSAndreas Boehler
387cb71a62aSAndreas Boehler  /**
388cb71a62aSAndreas Boehler   * Retrieve all events that are within a given date range,
389cb71a62aSAndreas Boehler   * based on the timezone setting.
390cb71a62aSAndreas Boehler   *
391cb71a62aSAndreas Boehler   * There is also support for retrieving recurring events,
392cb71a62aSAndreas Boehler   * using Sabre's VObject Iterator. Recurring events are represented
393cb71a62aSAndreas Boehler   * as individual calendar entries with the same UID.
394cb71a62aSAndreas Boehler   *
395cb71a62aSAndreas Boehler   * @param string $id The page ID to work with
396cb71a62aSAndreas Boehler   * @param string $user The user ID to work with
397cb71a62aSAndreas Boehler   * @param string $startDate The start date as a string
398cb71a62aSAndreas Boehler   * @param string $endDate The end date as a string
399cb71a62aSAndreas Boehler   *
400cb71a62aSAndreas Boehler   * @return array An array containing the calendar entries.
401cb71a62aSAndreas Boehler   */
402a1a3b679SAndreas Boehler  public function getEventsWithinDateRange($id, $user, $startDate, $endDate)
403a1a3b679SAndreas Boehler  {
404bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
405bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
406bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
407bd883736SAndreas Boehler      else
408bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
409a1a3b679SAndreas Boehler      $data = array();
410cb71a62aSAndreas Boehler
411cb71a62aSAndreas Boehler      // Load SabreDAV
412a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
413a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
414a1a3b679SAndreas Boehler      $startTs = new \DateTime($startDate);
415a1a3b679SAndreas Boehler      $endTs = new \DateTime($endDate);
416cb71a62aSAndreas Boehler
417cb71a62aSAndreas Boehler      // Retrieve matching calendar objects
418ebc4eb57SAndreas Boehler      $query = "SELECT calendardata, componenttype, uid FROM calendarobjects WHERE calendarid=".
419ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($calid)." AND firstoccurence < ".
420ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($endTs->getTimestamp())." AND lastoccurence > ".
421ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($startTs->getTimestamp());
422a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
423a1a3b679SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
424cb71a62aSAndreas Boehler
425cb71a62aSAndreas Boehler      // Parse individual calendar entries
426a1a3b679SAndreas Boehler      foreach($arr as $row)
427a1a3b679SAndreas Boehler      {
428a1a3b679SAndreas Boehler          if(isset($row['calendardata']))
429a1a3b679SAndreas Boehler          {
430b269830cSAndreas Boehler              $entry = array();
431a1a3b679SAndreas Boehler              $vcal = \Sabre\VObject\Reader::read($row['calendardata']);
432ebc4eb57SAndreas Boehler              $recurrence = $vcal->VEVENT->RRULE;
433cb71a62aSAndreas Boehler              // If it is a recurring event, pass it through Sabre's EventIterator
434ebc4eb57SAndreas Boehler              if($recurrence != null)
435ebc4eb57SAndreas Boehler              {
436ebc4eb57SAndreas Boehler                  $rEvents = new \Sabre\VObject\Recur\EventIterator(array($vcal->VEVENT));
437ebc4eb57SAndreas Boehler                  $rEvents->rewind();
438ebc4eb57SAndreas Boehler                  $done = false;
439ebc4eb57SAndreas Boehler                  while($rEvents->valid() && !$done)
440ebc4eb57SAndreas Boehler                  {
441ebc4eb57SAndreas Boehler                      $event = $rEvents->getEventObject();
442cb71a62aSAndreas Boehler                      // If we are after the given time range, exit
443ebc4eb57SAndreas Boehler                      if(($rEvents->getDtStart()->getTimestamp() > $endTs->getTimestamp()) &&
444ebc4eb57SAndreas Boehler                         ($rEvents->getDtEnd()->getTimestamp() > $endTs->getTimestamp()))
445ebc4eb57SAndreas Boehler                        $done = true;
446cb71a62aSAndreas Boehler
447cb71a62aSAndreas Boehler                      // If we are before the given time range, continue
448ebc4eb57SAndreas Boehler                      if($rEvents->getDtEnd()->getTimestamp() < $startTs->getTimestamp())
449ebc4eb57SAndreas Boehler                      {
450ebc4eb57SAndreas Boehler                          $rEvents->next();
451ebc4eb57SAndreas Boehler                          continue;
452ebc4eb57SAndreas Boehler                      }
453cb71a62aSAndreas Boehler
454cb71a62aSAndreas Boehler                      // If we are within the given time range, parse the event
455*3c86dda8SAndreas Boehler                      $data[] = $this->convertIcalDataToEntry($event, $timezone, $row['uid'], true);
456ebc4eb57SAndreas Boehler                      $rEvents->next();
457ebc4eb57SAndreas Boehler                  }
458ebc4eb57SAndreas Boehler              }
459ebc4eb57SAndreas Boehler              else
460ebc4eb57SAndreas Boehler                $data[] = $this->convertIcalDataToEntry($vcal->VEVENT, $timezone, $row['uid']);
461ebc4eb57SAndreas Boehler          }
462ebc4eb57SAndreas Boehler      }
463ebc4eb57SAndreas Boehler      return $data;
464ebc4eb57SAndreas Boehler  }
465ebc4eb57SAndreas Boehler
466cb71a62aSAndreas Boehler  /**
467cb71a62aSAndreas Boehler   * Helper function that parses the iCal data of a VEVENT to a calendar entry.
468cb71a62aSAndreas Boehler   *
469cb71a62aSAndreas Boehler   * @param \Sabre\VObject\VEvent $event The event to parse
470cb71a62aSAndreas Boehler   * @param \DateTimeZone $timezone The timezone object
471cb71a62aSAndreas Boehler   * @param string $uid The entry's UID
472*3c86dda8SAndreas Boehler   * @param boolean $recurring (optional) Set to true to define a recurring event
473cb71a62aSAndreas Boehler   *
474cb71a62aSAndreas Boehler   * @return array The parse calendar entry
475cb71a62aSAndreas Boehler   */
476*3c86dda8SAndreas Boehler  private function convertIcalDataToEntry($event, $timezone, $uid, $recurring = false)
477ebc4eb57SAndreas Boehler  {
478ebc4eb57SAndreas Boehler      $entry = array();
479ebc4eb57SAndreas Boehler      $start = $event->DTSTART;
480cb71a62aSAndreas Boehler      // Parse only if the start date/time is present
481b269830cSAndreas Boehler      if($start !== null)
482b269830cSAndreas Boehler      {
483b269830cSAndreas Boehler        $dtStart = $start->getDateTime();
484b269830cSAndreas Boehler        $dtStart->setTimezone($timezone);
485b269830cSAndreas Boehler        $entry['start'] = $dtStart->format(\DateTime::ATOM);
486b269830cSAndreas Boehler        if($start['VALUE'] == 'DATE')
487b269830cSAndreas Boehler          $entry['allDay'] = true;
488b269830cSAndreas Boehler        else
489b269830cSAndreas Boehler          $entry['allDay'] = false;
490b269830cSAndreas Boehler      }
491ebc4eb57SAndreas Boehler      $end = $event->DTEND;
492cb71a62aSAndreas Boehler      // Parse onlyl if the end date/time is present
493b269830cSAndreas Boehler      if($end !== null)
494b269830cSAndreas Boehler      {
495b269830cSAndreas Boehler        $dtEnd = $end->getDateTime();
496b269830cSAndreas Boehler        $dtEnd->setTimezone($timezone);
497b269830cSAndreas Boehler        $entry['end'] = $dtEnd->format(\DateTime::ATOM);
498b269830cSAndreas Boehler      }
499ebc4eb57SAndreas Boehler      $description = $event->DESCRIPTION;
5000eebc909SAndreas Boehler      if($description !== null)
5010eebc909SAndreas Boehler        $entry['description'] = (string)$description;
5020eebc909SAndreas Boehler      else
5030eebc909SAndreas Boehler        $entry['description'] = '';
504ebc4eb57SAndreas Boehler      $entry['title'] = (string)$event->summary;
505ebc4eb57SAndreas Boehler      $entry['id'] = $uid;
506*3c86dda8SAndreas Boehler      $entry['recurring'] = $recurring;
507ebc4eb57SAndreas Boehler      return $entry;
508a1a3b679SAndreas Boehler  }
509a1a3b679SAndreas Boehler
510cb71a62aSAndreas Boehler  /**
511cb71a62aSAndreas Boehler   * Retrieve an event by its UID
512cb71a62aSAndreas Boehler   *
513cb71a62aSAndreas Boehler   * @param string $uid The event's UID
514cb71a62aSAndreas Boehler   *
515cb71a62aSAndreas Boehler   * @return mixed The table row with the given event
516cb71a62aSAndreas Boehler   */
517a1a3b679SAndreas Boehler  public function getEventWithUid($uid)
518a1a3b679SAndreas Boehler  {
51955a741c0SAndreas Boehler      $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid=".
520a1a3b679SAndreas Boehler                $this->sqlite->quote_string($uid);
521a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
522a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
523a1a3b679SAndreas Boehler      return $row;
524a1a3b679SAndreas Boehler  }
525a1a3b679SAndreas Boehler
526cb71a62aSAndreas Boehler  /**
527cb71a62aSAndreas Boehler   * Retrieve all calendar events for a given calendar ID
528cb71a62aSAndreas Boehler   *
529cb71a62aSAndreas Boehler   * @param string $calid The calendar's ID
530cb71a62aSAndreas Boehler   *
531cb71a62aSAndreas Boehler   * @return array An array containing all calendar data
532cb71a62aSAndreas Boehler   */
533f69bb449SAndreas Boehler  public function getAllCalendarEvents($calid)
534f69bb449SAndreas Boehler  {
535f69bb449SAndreas Boehler      $query = "SELECT calendardata, uid, componenttype, uri FROM calendarobjects WHERE calendarid=".
536f69bb449SAndreas Boehler               $this->sqlite->quote_string($calid);
537f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
538f69bb449SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
539f69bb449SAndreas Boehler      return $arr;
540f69bb449SAndreas Boehler  }
541f69bb449SAndreas Boehler
542cb71a62aSAndreas Boehler  /**
543cb71a62aSAndreas Boehler   * Edit a calendar entry for a page, given by its parameters.
544cb71a62aSAndreas Boehler   * The params array has the same format as @see addCalendarEntryForPage
545cb71a62aSAndreas Boehler   *
546cb71a62aSAndreas Boehler   * @param string $id The page's ID to work on
547cb71a62aSAndreas Boehler   * @param string $user The user's ID to work on
548cb71a62aSAndreas Boehler   * @param array $params The parameter array for the edited calendar event
549cb71a62aSAndreas Boehler   *
550cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
551cb71a62aSAndreas Boehler   */
552a1a3b679SAndreas Boehler  public function editCalendarEntryForPage($id, $user, $params)
553a1a3b679SAndreas Boehler  {
554bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
555bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
556bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
557a25c89eaSAndreas Boehler      elseif($settings['timezone'] === 'local')
558a25c89eaSAndreas Boehler          $timezone = new \DateTimeZone($params['detectedtz']);
559bd883736SAndreas Boehler      else
560bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
561cb71a62aSAndreas Boehler
562cb71a62aSAndreas Boehler      // Parse dates
563b269830cSAndreas Boehler      $startDate = explode('-', $params['eventfrom']);
564b269830cSAndreas Boehler      $startTime = explode(':', $params['eventfromtime']);
565b269830cSAndreas Boehler      $endDate = explode('-', $params['eventto']);
566b269830cSAndreas Boehler      $endTime = explode(':', $params['eventtotime']);
567cb71a62aSAndreas Boehler
568cb71a62aSAndreas Boehler      // Retrieve the existing event based on the UID
56955a741c0SAndreas Boehler      $uid = $params['uid'];
57055a741c0SAndreas Boehler      $event = $this->getEventWithUid($uid);
571cb71a62aSAndreas Boehler
572cb71a62aSAndreas Boehler      // Load SabreDAV
573a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
574a1a3b679SAndreas Boehler      if(!isset($event['calendardata']))
575a1a3b679SAndreas Boehler        return false;
57655a741c0SAndreas Boehler      $uri = $event['uri'];
57755a741c0SAndreas Boehler      $calid = $event['calendarid'];
578cb71a62aSAndreas Boehler
579cb71a62aSAndreas Boehler      // Parse the existing event
580a1a3b679SAndreas Boehler      $vcal = \Sabre\VObject\Reader::read($event['calendardata']);
581b269830cSAndreas Boehler      $vevent = $vcal->VEVENT;
582cb71a62aSAndreas Boehler
583cb71a62aSAndreas Boehler      // Set the new event values
584b269830cSAndreas Boehler      $vevent->summary = $params['eventname'];
585b269830cSAndreas Boehler      $dtStamp = new \DateTime(null, new \DateTimeZone('UTC'));
5860eebc909SAndreas Boehler      $description = $params['eventdescription'];
587cb71a62aSAndreas Boehler
588cb71a62aSAndreas Boehler      // Remove existing timestamps to overwrite them
5890eebc909SAndreas Boehler      $vevent->remove('DESCRIPTION');
590b269830cSAndreas Boehler      $vevent->remove('DTSTAMP');
591b269830cSAndreas Boehler      $vevent->remove('LAST-MODIFIED');
592cb71a62aSAndreas Boehler
593cb71a62aSAndreas Boehler      // Add new time stamps and description
594b269830cSAndreas Boehler      $vevent->add('DTSTAMP', $dtStamp);
595b269830cSAndreas Boehler      $vevent->add('LAST-MODIFIED', $dtStamp);
5960eebc909SAndreas Boehler      if($description !== '')
5970eebc909SAndreas Boehler        $vevent->add('DESCRIPTION', $description);
598cb71a62aSAndreas Boehler
599cb71a62aSAndreas Boehler      // Setup DTSTART
600b269830cSAndreas Boehler      $dtStart = new \DateTime();
601a25c89eaSAndreas Boehler      $dtStart->setTimezone($timezone);
602b269830cSAndreas Boehler      $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2]));
603b269830cSAndreas Boehler      if($params['allday'] != '1')
604b269830cSAndreas Boehler        $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0);
605cb71a62aSAndreas Boehler
606cb71a62aSAndreas Boehler      // Setup DETEND
607b269830cSAndreas Boehler      $dtEnd = new \DateTime();
608a25c89eaSAndreas Boehler      $dtEnd->setTimezone($timezone);
609b269830cSAndreas Boehler      $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2]));
610b269830cSAndreas Boehler      if($params['allday'] != '1')
611b269830cSAndreas Boehler        $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0);
612cb71a62aSAndreas Boehler
613b269830cSAndreas Boehler      // According to the VCal spec, we need to add a whole day here
614b269830cSAndreas Boehler      if($params['allday'] == '1')
615b269830cSAndreas Boehler          $dtEnd->add(new \DateInterval('P1D'));
616b269830cSAndreas Boehler      $vevent->remove('DTSTART');
617b269830cSAndreas Boehler      $vevent->remove('DTEND');
618b269830cSAndreas Boehler      $dtStartEv = $vevent->add('DTSTART', $dtStart);
619b269830cSAndreas Boehler      $dtEndEv = $vevent->add('DTEND', $dtEnd);
620cb71a62aSAndreas Boehler
621cb71a62aSAndreas Boehler      // Remove the time for allday events
622b269830cSAndreas Boehler      if($params['allday'] == '1')
623b269830cSAndreas Boehler      {
624b269830cSAndreas Boehler          $dtStartEv['VALUE'] = 'DATE';
625b269830cSAndreas Boehler          $dtEndEv['VALUE'] = 'DATE';
626b269830cSAndreas Boehler      }
627a1a3b679SAndreas Boehler      $now = new DateTime();
628a1a3b679SAndreas Boehler      $eventStr = $vcal->serialize();
629a1a3b679SAndreas Boehler
630cb71a62aSAndreas Boehler      // Actually write to the database
631a1a3b679SAndreas Boehler      $query = "UPDATE calendarobjects SET calendardata=".$this->sqlite->quote_string($eventStr).
632a1a3b679SAndreas Boehler               ", lastmodified=".$this->sqlite->quote_string($now->getTimestamp()).
633a1a3b679SAndreas Boehler               ", firstoccurence=".$this->sqlite->quote_string($dtStart->getTimestamp()).
634a1a3b679SAndreas Boehler               ", lastoccurence=".$this->sqlite->quote_string($dtEnd->getTimestamp()).
635a1a3b679SAndreas Boehler               ", size=".strlen($eventStr).
636a1a3b679SAndreas Boehler               ", etag=".$this->sqlite->quote_string(md5($eventStr)).
63755a741c0SAndreas Boehler               " WHERE uid=".$this->sqlite->quote_string($uid);
638a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
63955a741c0SAndreas Boehler      if($res !== false)
64055a741c0SAndreas Boehler      {
64155a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'modified');
642a1a3b679SAndreas Boehler          return true;
643a1a3b679SAndreas Boehler      }
64455a741c0SAndreas Boehler      return false;
64555a741c0SAndreas Boehler  }
646a1a3b679SAndreas Boehler
647cb71a62aSAndreas Boehler  /**
648cb71a62aSAndreas Boehler   * Delete a calendar entry for a given page. Actually, the event is removed
649cb71a62aSAndreas Boehler   * based on the entry's UID, so that page ID is no used.
650cb71a62aSAndreas Boehler   *
651cb71a62aSAndreas Boehler   * @param string $id The page's ID (unused)
652cb71a62aSAndreas Boehler   * @param array $params The parameter array to work with
653cb71a62aSAndreas Boehler   *
654cb71a62aSAndreas Boehler   * @return boolean True
655cb71a62aSAndreas Boehler   */
656a1a3b679SAndreas Boehler  public function deleteCalendarEntryForPage($id, $params)
657a1a3b679SAndreas Boehler  {
658a1a3b679SAndreas Boehler      $uid = $params['uid'];
65955a741c0SAndreas Boehler      $event = $this->getEventWithUid($uid);
6602c14b82bSAndreas Boehler      $calid = $event['calendarid'];
66155a741c0SAndreas Boehler      $uri = $event['uri'];
662a1a3b679SAndreas Boehler      $query = "DELETE FROM calendarobjects WHERE uid=".$this->sqlite->quote_string($uid);
663a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
66455a741c0SAndreas Boehler      if($res !== false)
66555a741c0SAndreas Boehler      {
66655a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'deleted');
66755a741c0SAndreas Boehler      }
668a1a3b679SAndreas Boehler      return true;
669a1a3b679SAndreas Boehler  }
670a1a3b679SAndreas Boehler
671cb71a62aSAndreas Boehler  /**
672cb71a62aSAndreas Boehler   * Retrieve the current sync token for a calendar
673cb71a62aSAndreas Boehler   *
674cb71a62aSAndreas Boehler   * @param string $calid The calendar id
675cb71a62aSAndreas Boehler   *
676cb71a62aSAndreas Boehler   * @return mixed The synctoken or false
677cb71a62aSAndreas Boehler   */
67855a741c0SAndreas Boehler  public function getSyncTokenForCalendar($calid)
67955a741c0SAndreas Boehler  {
680b269830cSAndreas Boehler      $row = $this->getCalendarSettings($calid);
68155a741c0SAndreas Boehler      if(isset($row['synctoken']))
68255a741c0SAndreas Boehler          return $row['synctoken'];
68355a741c0SAndreas Boehler      return false;
68455a741c0SAndreas Boehler  }
68555a741c0SAndreas Boehler
686cb71a62aSAndreas Boehler  /**
687cb71a62aSAndreas Boehler   * Helper function to convert the operation name to
688cb71a62aSAndreas Boehler   * an operation code as stored in the database
689cb71a62aSAndreas Boehler   *
690cb71a62aSAndreas Boehler   * @param string $operationName The operation name
691cb71a62aSAndreas Boehler   *
692cb71a62aSAndreas Boehler   * @return mixed The operation code or false
693cb71a62aSAndreas Boehler   */
69455a741c0SAndreas Boehler  public function operationNameToOperation($operationName)
69555a741c0SAndreas Boehler  {
69655a741c0SAndreas Boehler      switch($operationName)
69755a741c0SAndreas Boehler      {
69855a741c0SAndreas Boehler          case 'added':
69955a741c0SAndreas Boehler              return 1;
70055a741c0SAndreas Boehler          break;
70155a741c0SAndreas Boehler          case 'modified':
70255a741c0SAndreas Boehler              return 2;
70355a741c0SAndreas Boehler          break;
70455a741c0SAndreas Boehler          case 'deleted':
70555a741c0SAndreas Boehler              return 3;
70655a741c0SAndreas Boehler          break;
70755a741c0SAndreas Boehler      }
70855a741c0SAndreas Boehler      return false;
70955a741c0SAndreas Boehler  }
71055a741c0SAndreas Boehler
711cb71a62aSAndreas Boehler  /**
712cb71a62aSAndreas Boehler   * Update the sync token log based on the calendar id and the
713cb71a62aSAndreas Boehler   * operation that was performed.
714cb71a62aSAndreas Boehler   *
715cb71a62aSAndreas Boehler   * @param string $calid The calendar ID that was modified
716cb71a62aSAndreas Boehler   * @param string $uri The calendar URI that was modified
717cb71a62aSAndreas Boehler   * @param string $operation The operation that was performed
718cb71a62aSAndreas Boehler   *
719cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
720cb71a62aSAndreas Boehler   */
72155a741c0SAndreas Boehler  private function updateSyncTokenLog($calid, $uri, $operation)
72255a741c0SAndreas Boehler  {
72355a741c0SAndreas Boehler      $currentToken = $this->getSyncTokenForCalendar($calid);
72455a741c0SAndreas Boehler      $operationCode = $this->operationNameToOperation($operation);
72555a741c0SAndreas Boehler      if(($operationCode === false) || ($currentToken === false))
72655a741c0SAndreas Boehler          return false;
72755a741c0SAndreas Boehler      $values = array($uri,
72855a741c0SAndreas Boehler                      $currentToken,
72955a741c0SAndreas Boehler                      $calid,
73055a741c0SAndreas Boehler                      $operationCode
73155a741c0SAndreas Boehler      );
73255a741c0SAndreas Boehler      $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(".
73355a741c0SAndreas Boehler               $this->sqlite->quote_and_join($values, ',').")";
73455a741c0SAndreas Boehler      $res = $this->sqlite->query($query);
73555a741c0SAndreas Boehler      if($res === false)
73655a741c0SAndreas Boehler        return false;
73755a741c0SAndreas Boehler      $currentToken++;
73855a741c0SAndreas Boehler      $query = "UPDATE calendars SET synctoken=".$this->sqlite->quote_string($currentToken)." WHERE id=".
73955a741c0SAndreas Boehler               $this->sqlite->quote_string($calid);
74055a741c0SAndreas Boehler      $res = $this->sqlite->query($query);
74155a741c0SAndreas Boehler      return ($res !== false);
74255a741c0SAndreas Boehler  }
74355a741c0SAndreas Boehler
744cb71a62aSAndreas Boehler  /**
745cb71a62aSAndreas Boehler   * Return the sync URL for a given Page, i.e. a calendar
746cb71a62aSAndreas Boehler   *
747cb71a62aSAndreas Boehler   * @param string $id The page's ID
748cb71a62aSAndreas Boehler   * @param string $user (optional) The user's ID
749cb71a62aSAndreas Boehler   *
750cb71a62aSAndreas Boehler   * @return mixed The sync url or false
751cb71a62aSAndreas Boehler   */
752b269830cSAndreas Boehler  public function getSyncUrlForPage($id, $user = null)
753b269830cSAndreas Boehler  {
754b269830cSAndreas Boehler      if(is_null($user))
755b269830cSAndreas Boehler        $user = $_SERVER['REMOTE_USER'];
756b269830cSAndreas Boehler
757b269830cSAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
758b269830cSAndreas Boehler      if($calid === false)
759b269830cSAndreas Boehler        return false;
760b269830cSAndreas Boehler
761b269830cSAndreas Boehler      $calsettings = $this->getCalendarSettings($calid);
762b269830cSAndreas Boehler      if(!isset($calsettings['uri']))
763b269830cSAndreas Boehler        return false;
764b269830cSAndreas Boehler
765b269830cSAndreas Boehler      $syncurl = DOKU_URL.'lib/plugins/davcal/calendarserver.php/calendars/'.$user.'/'.$calsettings['uri'];
766b269830cSAndreas Boehler      return $syncurl;
767b269830cSAndreas Boehler  }
768b269830cSAndreas Boehler
769cb71a62aSAndreas Boehler  /**
770cb71a62aSAndreas Boehler   * Return the private calendar's URL for a given page
771cb71a62aSAndreas Boehler   *
772cb71a62aSAndreas Boehler   * @param string $id the page ID
773cb71a62aSAndreas Boehler   *
774cb71a62aSAndreas Boehler   * @return mixed The private URL or false
775cb71a62aSAndreas Boehler   */
776f69bb449SAndreas Boehler  public function getPrivateURLForPage($id)
777f69bb449SAndreas Boehler  {
778f69bb449SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
779f69bb449SAndreas Boehler      if($calid === false)
780f69bb449SAndreas Boehler        return false;
781f69bb449SAndreas Boehler
782f69bb449SAndreas Boehler      return $this->getPrivateURLForCalendar($calid);
783f69bb449SAndreas Boehler  }
784f69bb449SAndreas Boehler
785cb71a62aSAndreas Boehler  /**
786cb71a62aSAndreas Boehler   * Return the private calendar's URL for a given calendar ID
787cb71a62aSAndreas Boehler   *
788cb71a62aSAndreas Boehler   * @param string $calid The calendar's ID
789cb71a62aSAndreas Boehler   *
790cb71a62aSAndreas Boehler   * @return mixed The private URL or false
791cb71a62aSAndreas Boehler   */
792f69bb449SAndreas Boehler  public function getPrivateURLForCalendar($calid)
793f69bb449SAndreas Boehler  {
794f69bb449SAndreas Boehler      $query = "SELECT url FROM calendartoprivateurlmapping WHERE calid=".$this->sqlite->quote_string($calid);
795f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
796f69bb449SAndreas Boehler      $row = $this->sqlite->res2row($res);
797f69bb449SAndreas Boehler      if(!isset($row['url']))
798f69bb449SAndreas Boehler      {
799f69bb449SAndreas Boehler          $url = uniqid("dokuwiki-").".ics";
800f69bb449SAndreas Boehler          $values = array(
801f69bb449SAndreas Boehler                $url,
802f69bb449SAndreas Boehler                $calid
803f69bb449SAndreas Boehler          );
804f69bb449SAndreas Boehler          $query = "INSERT INTO calendartoprivateurlmapping (url, calid) VALUES(".
805f69bb449SAndreas Boehler                $this->sqlite->quote_and_join($values, ", ").")";
806f69bb449SAndreas Boehler          $res = $this->sqlite->query($query);
807f69bb449SAndreas Boehler          if($res === false)
808f69bb449SAndreas Boehler            return false;
809f69bb449SAndreas Boehler      }
810f69bb449SAndreas Boehler      else
811f69bb449SAndreas Boehler      {
812f69bb449SAndreas Boehler          $url = $row['url'];
813f69bb449SAndreas Boehler      }
81470d9aa2aSAndreas Boehler      return DOKU_URL.'lib/plugins/davcal/ics.php/'.$url;
815f69bb449SAndreas Boehler  }
816f69bb449SAndreas Boehler
817cb71a62aSAndreas Boehler  /**
818cb71a62aSAndreas Boehler   * Retrieve the calendar ID for a given private calendar URL
819cb71a62aSAndreas Boehler   *
820cb71a62aSAndreas Boehler   * @param string $url The private URL
821cb71a62aSAndreas Boehler   *
822cb71a62aSAndreas Boehler   * @return mixed The calendar ID or false
823cb71a62aSAndreas Boehler   */
824f69bb449SAndreas Boehler  public function getCalendarForPrivateURL($url)
825f69bb449SAndreas Boehler  {
826f69bb449SAndreas Boehler      $query = "SELECT calid FROM calendartoprivateurlmapping WHERE url=".$this->sqlite->quote_string($url);
827f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
828f69bb449SAndreas Boehler      $row = $this->sqlite->res2row($res);
829f69bb449SAndreas Boehler      if(!isset($row['calid']))
830f69bb449SAndreas Boehler        return false;
831f69bb449SAndreas Boehler      return $row['calid'];
832f69bb449SAndreas Boehler  }
833f69bb449SAndreas Boehler
834cb71a62aSAndreas Boehler  /**
835cb71a62aSAndreas Boehler   * Return a given calendar as ICS feed, i.e. all events in one ICS file.
836cb71a62aSAndreas Boehler   *
837cb71a62aSAndreas Boehler   * @param string $caldi The calendar ID to retrieve
838cb71a62aSAndreas Boehler   *
839cb71a62aSAndreas Boehler   * @return mixed The calendar events as string or false
840cb71a62aSAndreas Boehler   */
841f69bb449SAndreas Boehler  public function getCalendarAsICSFeed($calid)
842f69bb449SAndreas Boehler  {
843f69bb449SAndreas Boehler      $calSettings = $this->getCalendarSettings($calid);
844f69bb449SAndreas Boehler      if($calSettings === false)
845f69bb449SAndreas Boehler        return false;
846f69bb449SAndreas Boehler      $events = $this->getAllCalendarEvents($calid);
847f69bb449SAndreas Boehler      if($events === false)
848f69bb449SAndreas Boehler        return false;
849f69bb449SAndreas Boehler
850f69bb449SAndreas Boehler      $out = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//DAVCal//DAVCal for DokuWiki//EN\nCALSCALE:GREGORIAN\nX-WR-CALNAME:";
851f69bb449SAndreas Boehler      $out .= $calSettings['displayname']."\n";
852f69bb449SAndreas Boehler      foreach($events as $event)
853f69bb449SAndreas Boehler      {
854f69bb449SAndreas Boehler          $out .= rtrim($event['calendardata']);
855f69bb449SAndreas Boehler          $out .= "\n";
856f69bb449SAndreas Boehler      }
857f69bb449SAndreas Boehler      $out .= "END:VCALENDAR\n";
858f69bb449SAndreas Boehler      return $out;
859f69bb449SAndreas Boehler  }
860f69bb449SAndreas Boehler
861a1a3b679SAndreas Boehler}
862