You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
3.9 KiB

  1. <?php
  2. /**
  3. * ICS Exporter
  4. *
  5. * This plugin adds the ability to export entire calendars as .ics files.
  6. * This is useful for clients that don't support CalDAV yet. They often do
  7. * support ics files.
  8. *
  9. * @package Sabre
  10. * @subpackage CalDAV
  11. * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
  12. * @author Evert Pot (http://www.rooftopsolutions.nl/)
  13. * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
  14. */
  15. class Sabre_CalDAV_ICSExportPlugin extends Sabre_DAV_ServerPlugin {
  16. /**
  17. * Reference to Server class
  18. *
  19. * @var Sabre_DAV_Server
  20. */
  21. private $server;
  22. /**
  23. * Initializes the plugin and registers event handlers
  24. *
  25. * @param Sabre_DAV_Server $server
  26. * @return void
  27. */
  28. public function initialize(Sabre_DAV_Server $server) {
  29. $this->server = $server;
  30. $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90);
  31. }
  32. /**
  33. * 'beforeMethod' event handles. This event handles intercepts GET requests ending
  34. * with ?export
  35. *
  36. * @param string $method
  37. * @param string $uri
  38. * @return bool
  39. */
  40. public function beforeMethod($method, $uri) {
  41. if ($method!='GET') return;
  42. if ($this->server->httpRequest->getQueryString()!='export') return;
  43. // splitting uri
  44. list($uri) = explode('?',$uri,2);
  45. $node = $this->server->tree->getNodeForPath($uri);
  46. if (!($node instanceof Sabre_CalDAV_Calendar)) return;
  47. // Checking ACL, if available.
  48. if ($aclPlugin = $this->server->getPlugin('acl')) {
  49. $aclPlugin->checkPrivileges($uri, '{DAV:}read');
  50. }
  51. $this->server->httpResponse->setHeader('Content-Type','text/calendar');
  52. $this->server->httpResponse->sendStatus(200);
  53. $nodes = $this->server->getPropertiesForPath($uri, array(
  54. '{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data',
  55. ),1);
  56. $this->server->httpResponse->sendBody($this->generateICS($nodes));
  57. // Returning false to break the event chain
  58. return false;
  59. }
  60. /**
  61. * Merges all calendar objects, and builds one big ics export
  62. *
  63. * @param array $nodes
  64. * @return string
  65. */
  66. public function generateICS(array $nodes) {
  67. $calendar = new Sabre_VObject_Component('vcalendar');
  68. $calendar->version = '2.0';
  69. if (Sabre_DAV_Server::$exposeVersion) {
  70. $calendar->prodid = '-//SabreDAV//SabreDAV ' . Sabre_DAV_Version::VERSION . '//EN';
  71. } else {
  72. $calendar->prodid = '-//SabreDAV//SabreDAV//EN';
  73. }
  74. $calendar->calscale = 'GREGORIAN';
  75. $collectedTimezones = array();
  76. $timezones = array();
  77. $objects = array();
  78. foreach($nodes as $node) {
  79. if (!isset($node[200]['{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data'])) {
  80. continue;
  81. }
  82. $nodeData = $node[200]['{' . Sabre_CalDAV_Plugin::NS_CALDAV . '}calendar-data'];
  83. $nodeComp = Sabre_VObject_Reader::read($nodeData);
  84. foreach($nodeComp->children() as $child) {
  85. switch($child->name) {
  86. case 'VEVENT' :
  87. case 'VTODO' :
  88. case 'VJOURNAL' :
  89. $objects[] = $child;
  90. break;
  91. // VTIMEZONE is special, because we need to filter out the duplicates
  92. case 'VTIMEZONE' :
  93. // Naively just checking tzid.
  94. if (in_array((string)$child->TZID, $collectedTimezones)) continue;
  95. $timezones[] = $child;
  96. $collectedTimezones[] = $child->TZID;
  97. break;
  98. }
  99. }
  100. }
  101. foreach($timezones as $tz) $calendar->add($tz);
  102. foreach($objects as $obj) $calendar->add($obj);
  103. return $calendar->serialize();
  104. }
  105. }