diff --git a/plugins/calendar/lib/calendar_ical.php b/plugins/calendar/lib/calendar_ical.php index 6d7474ec..3dfe4c16 100644 --- a/plugins/calendar/lib/calendar_ical.php +++ b/plugins/calendar/lib/calendar_ical.php @@ -347,27 +347,32 @@ class calendar_ical * @param boolean Directly send data to stdout instead of returning * @return string Events in iCalendar format (http://tools.ietf.org/html/rfc5545) */ - public function export($events, $method = null, $write = false) + public function export($events, $method = null, $write = false, $recurrence_id = null) { - $ical = "BEGIN:VCALENDAR" . self::EOL; - $ical .= "VERSION:2.0" . self::EOL; - $ical .= "PRODID:-//Roundcube Webmail " . RCMAIL_VERSION . "//NONSGML Calendar//EN" . self::EOL; - $ical .= "CALSCALE:GREGORIAN" . self::EOL; - - if ($method) - $ical .= "METHOD:" . strtoupper($method) . self::EOL; - - if ($write) { - echo $ical; - $ical = ''; + if (!$recurrence_id) { + $ical = "BEGIN:VCALENDAR" . self::EOL; + $ical .= "VERSION:2.0" . self::EOL; + $ical .= "PRODID:-//Roundcube Webmail " . RCMAIL_VERSION . "//NONSGML Calendar//EN" . self::EOL; + $ical .= "CALSCALE:GREGORIAN" . self::EOL; + + if ($method) + $ical .= "METHOD:" . strtoupper($method) . self::EOL; + + if ($write) { + echo $ical; + $ical = ''; + } } - + foreach ($events as $event) { $vevent = "BEGIN:VEVENT" . self::EOL; $vevent .= "UID:" . self::escpape($event['uid']) . self::EOL; $vevent .= $this->format_datetime("DTSTAMP", $event['changed'] ?: new DateTime(), false, true) . self::EOL; if ($event['sequence']) - $vevent .= "SEQUENCE:" . intval($event['sequence']) . self::EOL; + $vevent .= "SEQUENCE:" . intval($event['sequence']) . self::EOL; + if ($recurrence_id) + $vevent .= $recurrence_id . self::EOL; + // correctly set all-day dates if ($event['allday']) { $event['end'] = clone $event['end']; @@ -389,7 +394,7 @@ class calendar_ical if (!empty($event['location'])) { $vevent .= "LOCATION:" . self::escpape($event['location']) . self::EOL; } - if ($event['recurrence']) { + if ($event['recurrence'] && !$recurrence_id) { $vevent .= "RRULE:" . libcalendaring::to_rrule($event['recurrence'], self::EOL) . self::EOL; } if(!empty($event['categories'])) { @@ -426,18 +431,30 @@ class calendar_ical // TODO: export attachments $vevent .= "END:VEVENT" . self::EOL; - + + // append recurrence exceptions + if ($event['recurrence']['EXCEPTIONS'] && !$recurrence_id) { + foreach ($event['recurrence']['EXCEPTIONS'] as $ex) { + $exdate = clone $event['start']; + $exdate->setDate($ex['start']->format('Y'), $ex['start']->format('n'), $ex['start']->format('j')); + $vevent .= $this->export(array($ex), null, false, + $this->format_datetime('RECURRENCE-ID', $exdate, $event['allday'])); + } + } + if ($write) echo rcube_vcard::rfc2425_fold($vevent); else $ical .= $vevent; } - $ical .= "END:VCALENDAR" . self::EOL; + if (!$recurrence_id) { + $ical .= "END:VCALENDAR" . self::EOL; - if ($write) { - echo $ical; - return true; + if ($write) { + echo $ical; + return true; + } } // fold lines to 75 chars