1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/agendav_ynh.git synced 2024-09-03 20:36:12 +02:00
agendav_ynh/sources/web/application/libraries/Icshelper.php
2014-01-07 17:53:08 +01:00

1038 lines
34 KiB
PHP

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
* Copyright 2011-2012 Jorge López Pérez <jorge@adobo.org>
*
* This file is part of AgenDAV.
*
* AgenDAV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* AgenDAV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AgenDAV. If not, see <http://www.gnu.org/licenses/>.
*/
class Icshelper {
private $config; // for iCalCreator
private $tz;
private $date_format; // Date format given by lang file
private $date_frontend_format, $time_frontend_format;
function __construct() {
$this->CI =& get_instance();
// Timezone
$this->tz = $this->CI->timezonemanager->getTz(
$this->CI->config->item('default_timezone'));
$this->date_format = $this->CI->config->item('format_full_date');
$this->date_frontend_format = $this->CI->dates->date_format_string('date');
$this->time_frontend_format = $this->CI->dates->time_format_string('date');
$this->config = array(
'unique_id' =>
$this->CI->config->item('icalendar_unique_id'),
);
require_once('iCalcreator.class.php');
}
/**
* Creates a new iCalendar resource
*
* Property keys can be lowercase
*
* Returns generated guid, FALSE on error. $generated will be filled with
* new generated resource (iCalComponent object)
*/
function new_resource($properties, &$generated, $tz, $reminders =
array()) {
$properties = array_change_key_case($properties, CASE_UPPER);
$contents = '';
$ical = new vcalendar($this->config);
// Default CALSCALE in standard
$ical->setProperty('calscale', 'GREGORIAN');
$allday = (isset($properties['ALLDAY']) && $properties['ALLDAY'] ==
'true');
if ($allday) {
// Discard timezone
$tz = $this->CI->timezonemanager->getTz('UTC');
}
// Add VTIMEZONE
$this->add_vtimezone($ical, $tz->getName());
$vevent =& $ical->newComponent('vevent');
$now = $this->CI->dates->datetime2idt();
$uid = $this->generate_guid();
$vevent->setProperty('CREATED', $now);
$vevent->setProperty('LAST-MODIFIED', $now);
$vevent->setProperty('DTSTAMP', $now);
$vevent->setProperty('UID', $uid);
$vevent->setProperty('SEQUENCE', '0'); // RFC5545, 3.8.7.4
$vevent->setProperty('SUMMARY', $properties['SUMMARY']);
// Rest of properties
$add_prop = array('DTSTART', 'DTEND', 'DESCRIPTION', 'LOCATION',
'DURATION', 'RRULE', 'TRANSP', 'CLASS');
foreach ($add_prop as $p) {
if (isset($properties[$p]) && !empty($properties[$p])) {
$params = FALSE;
// Generate DTSTART/DTEND
if ($p == 'DTSTART' || $p == 'DTEND') {
if ($tz->getName() != 'UTC') {
$params = array('TZID' => $tz->getName());
}
$properties[$p] = $this->CI->dates->datetime2idt(
$properties[$p], $tz);
// All day: use parameter VALUE=DATE
if ($allday) {
$params['VALUE'] = 'DATE';
}
}
$vevent->setProperty($p, $properties[$p], $params);
}
}
// VALARM components (reminders)
$vevent = $this->set_valarms($vevent, $reminders);
$generated = $ical;
return $uid;
}
/**
* Generates a new GUID
*
* Found on phunction PHP framework
* (http://sourceforge.net/projects/phunction/)
*/
function generate_guid()
{
if (function_exists('com_create_guid') === true)
{
return trim(com_create_guid(), '{}');
}
return sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X',
mt_rand(0, 65535), mt_rand(0, 65535),
mt_rand(0, 65535), mt_rand(16384, 20479),
mt_rand(32768, 49151), mt_rand(0, 65535),
mt_rand(0, 65535), mt_rand(0, 65535));
}
/**
* Expands a list of resources to repeated events, depending on
* recurrence rules and recurrence exceptions/modifications
*
* @param array() $resources Resources returned by GetEvents
* @param int $start Start timestamp
* @param int $end End timestamp
* @param string $calendar Current calendar
*/
function expand_and_parse_events($resources, $start, $end, $calendar) {
$result = array();
// Dates
$utc = $this->CI->timezonemanager->getTz('UTC');
$date_start = new DateTime($start, $utc);
$date_end = new DateTime($end, $utc);
foreach ($resources as $r) {
$event_href = $r['href'];
$event_etag = $r['etag'];
$ical = new vcalendar($this->config);
$res = $ical->parse($r['data']);
if ($res === FALSE) {
$this->CI->extended_logs->message('ERROR',
"Couldn't parse event with href=" . $calendar . '/'
.$event_href);
}
$ical->sort();
$timezones = $this->get_timezones($ical);
$sy = intval($date_start->format('Y'));
$sm = intval($date_start->format('m'));
$sd = intval($date_start->format('d'));
$ey = intval($date_end->format('Y'));
$em = intval($date_end->format('m'));
$ed = intval($date_end->format('d'));
/*
log_message('INTERNALS', 'Pidiendo expansión para ' . $sy . '-'
. $sm . '-' . $sd . ' a ' . $ey . '-' . $em . '-' .
$ed);
log_message('INTERNALS', $event_href);
log_message('INTERNALS', $r['data']);
*/
$expand = $ical->selectComponents($sy, $sm, $sd, $ey, $em, $ed,
'vevent', false, true, false);
if ($expand !== FALSE) {
foreach( $expand as $year => $year_arr ) {
foreach( $year_arr as $month => $month_arr ) {
foreach( $month_arr as $day => $day_arr ) {
foreach( $day_arr as $event ) {
$tz = $this->detect_tz($event, $timezones);
$result[] =
$this->parse_vevent_fullcalendar($event,
$event_href, $event_etag, $calendar,
$tz, $timezones);
}
}
}
}
} else {
$expand = $ical->selectComponents($sy, $sm, $sd, $ey, $em, $ed,
'vevent', true, true, false);
if ($expand === FALSE) {
$this->CI->extended_logs->message('ERROR',
"Server sent an event which doesn't fit in our dates interval");
} else {
foreach($expand as $event) {
$tz = $this->detect_tz($event, $timezones);
$result[] =
$this->parse_vevent_fullcalendar($event,
$event_href, $event_etag, $calendar,
$tz, $timezones);
}
}
}
}
return $result;
}
/**
* Parses an VEVENT for Fullcalendar
*/
function parse_vevent_fullcalendar($vevent,
$href, $etag, $calendar = 'calendario', $tz, $timezones) {
$this_event = array(
'href' => $href,
'calendar' => $calendar,
'etag' => $etag,
'disableDragging' => FALSE,
'disableResizing' => FALSE,
'ignoreTimezone' => TRUE,
'timezone' => $tz->getName(),
);
// Start and end date
$dtstart = $this->extract_date($vevent, 'DTSTART', $tz);
$dtend = $this->extract_date($vevent, 'DTEND', $tz);
// We have for sure DTSTART
$start = $dtstart['result'];
// Do we have DTEND?
if (!is_null($dtend)) {
$end = $dtend['result'];
} else {
$duration = $vevent->getProperty('duration',
false, false, true);
// Calculate dtend if not present
if ($duration !== FALSE) {
$end = $this->CI->dates->idt2datetime($duration,
$tz);
} else {
// RFC 2445, p52
if ($dtstart['value'] == 'DATE-TIME') {
$end = clone $start;
} else {
$end = clone $start;
$end->add(new DateInterval('P1D'));
}
}
}
// Is this a recurrent event?
if (FALSE !== ($current_dtstart =
$vevent->getProperty('x-current-dtstart'))) {
// Is this a multiday event? In that case, ignore this event
// Hack to avoid getProperty() ignore next getProperty() on
// RRULE.
if (FALSE === $vevent->rrule) {
return FALSE;
}
$this_event['expanded'] = TRUE;
// Format depends on DTSTART
if (!isset($dtstart['property']['value']['hour'])) {
$current_dtstart[1] .= ' 00:00:00';
}
// Keep a copy
$orig_start = clone $start;
$start = $this->CI->dates->x_current2datetime($current_dtstart[1], $tz);
unset($this_event['end']);
$current_dtend = $vevent->getProperty('x-current-dtend');
if ($current_dtend !== FALSE) {
if (!isset($dtstart['property']['value']['hour'])) {
$current_dtend[1] .= ' 00:00:00';
}
$orig_end = clone $end;
$end =
$this->CI->dates->x_current2datetime($current_dtend[1],
$tz);
}
}
$interesting_props = array(
'summary', 'uid', 'description', 'rrule',
'duration', 'location', 'class', 'recurrence-id',
'transp',
);
foreach ($interesting_props as $p) {
// TODO: more properties
// TODO multiple ocurrences of the same property?
// TODO current-dtstart
$prop = $vevent->getProperty($p, FALSE, TRUE);
if ($prop === FALSE) {
continue;
}
$val = $prop['value'];
$params = $prop['params'];
switch ($p) {
case 'summary':
$this_event['title'] = $val;
break;
case 'uid':
$this_event['uid'] = $val;
break;
case 'description':
$description = $val;
$this_event['description'] =
preg_replace('/\\\n|\\\r/', "\n", $description);
// Format
$this_event['formatted_description'] =
preg_replace('/\\\n|\\\r/', '<br />', $description);
break;
case 'rrule':
$this_event['rrule_serialized'] =
base64_encode(serialize($val));
$new_val = trim($vevent->_format_recur('RRULE',
array($prop)));
$this_event['rrule'] = $new_val;
$explanation =
$this->CI->recurrence->rrule_explain($val,
$unused);
if ($explanation !== FALSE) {
$this_event['rrule_explained'] = $explanation;
}
// TODO make it editable when able to parse it
$this_event['editable'] = FALSE;
break;
case 'duration':
$this_event['duration'] =
iCalUtilityFunctions::_format_duration($val);
break;
case 'location':
$this_event['location'] = $val;
break;
case 'class':
$this_event['icalendar_class'] = $val;
break;
case 'transp':
$this_event['transp'] = $val;
break;
case 'recurrence-id':
// TODO parse a little bit
$this_event['recurrence_id'] = $val;
break;
default:
$this->CI->extended_logs->message('ERROR',
'Attempt to parse iCalendar property ' . $p
. ' on VEVENT which is not developed '
.'yet');
break;
}
}
// Internal fullCalendar id
$this_event['id'] = $calendar . ':' . $this_event['uid'];
// Is this an all day event?
$this_event['allDay'] = FALSE;
if (isset($dtstart['value']) &&
$dtstart['value'] == 'DATE') {
$this_event['allDay'] = TRUE;
} else if ($start->diff($end)->format('s') == '86400') {
if ($start->format('Hi') == '0000') {
$this_event['allDay'] = TRUE;
}
// Check using UTC and local time
if ($start->getTimeZone()->getName() == 'UTC') {
$test_start = clone $start;
$test_start->setTimeZone($this->tz);
if ($test_start->format('Hi') == '0000') {
$this_event['allDay'] = TRUE;
}
}
}
if ($this_event['allDay'] === TRUE) {
// Fool fullcalendar (dates are inclusive).
// For expanded events have special care,
// iCalcreator expands them using start_day=end_day, which
// confuses fullCalendar
$start->setTime(0, 0, 0);
$end->setTime(0, 0, 0);
$end->sub(new DateInterval('P1D'))->add(new
DateInterval('PT1H'));
if (isset($this_event['expanded'])) {
$orig_start->setTime(0, 0, 0);
$orig_end->setTime(0, 0, 0);
$orig_end->sub(new DateInterval('P1D'))->add(new
DateInterval('PT1H'));
}
$this_event['orig_allday'] = TRUE;
} else {
$this_event['orig_allday'] = FALSE;
}
// To be used with strftime()
$ts_start = $start->getTimestamp();
$ts_end = $end->getTimestamp();
// Needed for some conversions (Fullcalendar timestamp and am/pm
// indicator)
if (!isset($this_event['allDay'])
|| $this_event['allDay'] !== TRUE) {
$start->setTimeZone($this->tz);
$end->setTimeZone($this->tz);
}
// Expanded events
if (isset($orig_start)) {
$orig_start->setTimeZone($this->tz);
$orig_end->setTimeZone($this->tz);
$this_event['orig_start'] = $orig_start->format(DateTime::ISO8601);
$this_event['orig_end'] = $orig_end->format(DateTime::ISO8601);
}
// Readable dates for start and end
// Keep all day events as they are (UTC)
$system_tz = date_default_timezone_get();
if (!isset($this_event['allDay'])
|| $this_event['allDay'] !== TRUE) {
date_default_timezone_set($this->tz->getName());
}
$this_event['formatted_start'] = strftime($this->date_format, $ts_start);
if (isset($this_event['allDay']) && $this_event['allDay'] == TRUE) {
// Next day?
if ($start->format('Ymd') == $end->format('Ymd')) {
$this_event['formatted_end'] =
'('.$this->CI->i18n->_('labels', 'allday').')';
} else {
$this_event['formatted_end'] = strftime($this->date_format, $ts_end);
}
} else {
// Are they in the same day?
$this_event['formatted_start'] .= ' '
. $this->CI->dates->strftime_time($ts_start, $start);
if ($start->format('Ymd') == $end->format('Ymd')) {
$this_event['formatted_end'] =
$this->CI->dates->strftime_time($ts_end, $end);
} else {
$this_event['formatted_end'] =
strftime($this->date_format, $ts_end) . ' ' .
$this->CI->dates->strftime_time($ts_end, $end);
}
}
// Restore TZ
date_default_timezone_set($system_tz);
// Empty title?
if (!isset($this_event['title'])) {
$this_event['title'] = $this->CI->i18n->_('labels', 'untitled');
}
$this_event['start'] = $start->format(DateTime::ISO8601);
$this_event['end'] = $end->format(DateTime::ISO8601);
// Reminders for this event
$this_event['visible_reminders'] = array();
$this_event['reminders'] = array();
$valarms = $this->parse_valarms($vevent, $timezones);
foreach ($valarms as $order => $reminder) {
$this_event['visible_reminders'][] = $order;
$this_event['reminders'][] = $reminder;
}
return $this_event;
}
/**
* Parses an iCalendar resource
*/
function parse_icalendar($data) {
$vcalendar = new vcalendar($this->config);
$vcalendar->parse($data);
return $vcalendar;
}
/**
* Collects all timezones (VTIMEZONE) present in a resource
*
* Returns an associative array with 'tzid' => DateTimeZone('real tz
* name')
*/
function get_timezones($icalendar) {
$result = array();
while ($vt = $icalendar->getComponent('vtimezone')) {
$tzid = $vt->getProperty('TZID');
// Contains (usually) the time zone name
$tzval = $vt->getProperty('X-LIC-LOCATION');
if ($tzval === FALSE || empty($tzval)) {
// Try to extract it from TZID name
$tzval = $tzid;
} else {
$tzval = $tzval[1];
}
// Do we have tzval?
if ($tzval !== FALSE && !empty($tzval)) {
$result[$tzid] = $this->CI->timezonemanager->getTz($tzval);
}
}
return $result;
}
/**
* Finds a component within a resource, and returns its index in the
* components array.
*
* Useful for replacing existing components by using GetComponents() to
* save resources directly
*
* @param iCalComponent $reosurce Full iCalComponent VCALENDAR
* @param string $type VEVENT, VTIMEZONE, etc
* @param conditions Associative array. Possible keys:
* - RECURRENCE-ID
* - ?
* @param iCalComponent The found object
*/
function find_component_position($resource, $type,
$conditions = array(), &$comp) {
// Position
$i = 1;
$found = FALSE;
$comp = null;
while ($found === FALSE && ($c = $resource->getComponent($type))) {
// Check conditions
if (isset($conditions['recurrence-id'])) {
$recurr_id = $c->getProperty('recurrence-id');
if ($recurr_id !== FALSE && $recurr_id ==
$conditions['recurrence-id']) {
$found = $i;
}
} else if (!isset($conditions['recurrence-id'])) {
$found = $i;
}
if ($found !== FALSE) {
$comp = $c;
}
}
return $found;
}
/**
* Replaces a component in the n-th position
*/
function replace_component($resource, $type, $n, $new) {
$resource->setComponent($new, $type, $n);
return $resource;
}
/**
* Applies a LAST-MODIFIED change on the iCalendar component
* (VEVENT, etc)
*/
function set_last_modified($component) {
$now = $this->CI->dates->datetime2idt();
$component->setProperty('last-modified', $now);
// SEQUENCE
$seq = $component->getProperty('sequence');
if ($seq !== FALSE) {
$seq = intval($seq);
$seq++;
$component->setProperty('sequence', $seq);
}
return $component;
}
/**
* Gets DTSTART/other property timezone from a component
*
*/
function detect_tz($component, $tzs, $prop = 'dtstart') {
$dtstart = $component->getProperty($prop, FALSE, TRUE);
$val = $dtstart['value'];
$params = $dtstart['params'];
$has_z = isset($val['tz']) ? ($val['tz']=='Z') : FALSE;
$value = $this->paramvalue($params, 'value');;
$used_tz = null;
if ($has_z || $value == 'DATE') {
$used_tz = $this->CI->timezonemanager->getTz('UTC');
} else {
$tzid = $this->paramvalue($params, 'tzid');;
if ($tzid !== FALSE && isset($tzs[$tzid])) {
$used_tz = $tzs[$tzid];
} else {
// Not UTC but no TZID/invalid TZID?!
$used_tz = $this->CI->timezonemanager->getTz(
$this->CI->config->item('default_timezone'));
}
}
return $used_tz;
}
/**
* Sets a component DTSTART value
*
* @param iCalComponent $component
* @param DateTimeZone $tz Used TZ
* @param DateTime $new_start
* @param string $increment
* @param string $force_new_value_type
* @param string $force_new_tzid
*/
function make_start($component, $tz,
$new_start = null,
$increment = null,
$force_new_value_type = null,
$force_new_tzid = null) {
$value = null;
$format = null;
$params = array();
$info = $this->extract_date($component, 'DTSTART', $tz);
// No current DTSTART?
if (is_null($info)) {
$params = array('VALUE' => (is_null($force_new_value_type) ?
'DATE-TIME' : $force_new_value_type));
$value = new DateTime('now', $tz);
} else {
$params = $info['property']['params'];
if (!is_null($force_new_value_type)) {
$params['VALUE'] = $force_new_value_type;
} elseif (!isset($params['VALUE'])) {
$params['VALUE'] = 'DATE-TIME';
}
$value = $this->CI->dates->idt2datetime($info['property']['value'],
$tz);
}
// DATE values can't have TZID
if ($params['VALUE'] == 'DATE') {
unset($params['TZID']);
} else if (!is_null($force_new_tzid)) {
$params['TZID'] = $force_new_tzid;
}
$format = $this->CI->dates->format_for($params['VALUE'], $tz);
// Use current DTSTART
if (!is_null($new_start)) {
$value = $new_start;
}
// Increment
if (!is_null($increment)) {
$value->add($this->CI->dates->duration2di($increment));
}
$component->setProperty('dtstart', $this->CI->dates->datetime2idt(
$value, $tz, $format), $params);
return $component;
}
/**
* Sets a component end value
*
* @param iCalComponent $component
* @param DateTimeZone $tz Used TZ
* @param DateTime $new_start
* @param string $increment
* @param string $force_new_value_type
*/
function make_end($component, $tz,
$new_end = null,
$increment = null,
$force_new_value_type = null,
$force_new_tzid = null) {
$value = null;
$format = null;
$params = array();
$dtend_info = $this->extract_date($component, 'DTEND', $tz);
if (is_null($dtend_info)) {
// No DTEND in event
if (is_null($new_end)) {
// Event has DURATION defined. Generate DTEND and remove
// DURATION property
$dtend_info = $this->getProperty('duration', FALSE, FALSE, TRUE);
if ($dtend_info === FALSE) {
// Something is wrong . No DTEND nor DURATION
// Return the component as is
$this->CI->extended_logs->message('ERROR',
'Event with uid=' . $component->getProperty('uid')
.' has neither DTEND nor DURATION properties');
return $component;
}
$value = $this->CI->dates->idt2datetime($dtend, $tz);
}
// Get current DTSTART params
$dtstart_info = $this->extract_date($component, 'DTSTART', $tz);
if (is_null($dtend_info)) {
// Neither DTSTART nor DTEND!?
$params = array('VALUE' => 'DATE-TIME');
} else {
$params = $dtstart_info['property']['params'];
}
// We prefer DTEND to DURATION
$component->deleteProperty('duration');
} else {
$params = $dtend_info['property']['params'];
$value = $this->CI->dates->idt2datetime($dtend_info['property']['value'],
$tz);
}
// VALUE parameter
if (!is_null($force_new_value_type)) {
$params['VALUE'] = $force_new_value_type;
} elseif (!isset($params['VALUE'])) {
$params['VALUE'] = 'DATE-TIME';
}
// Use retrieved DTEND (or calculated)
if (!is_null($new_end)) {
$value = $new_end;
}
// Increment
if (!is_null($increment)) {
$value->add($this->CI->dates->duration2di($increment));
}
// DATE values can't have TZID
if ($params['VALUE'] == 'DATE') {
unset($params['TZID']);
} else if (!is_null($force_new_tzid)) {
$params['TZID'] = $force_new_tzid;
}
$format = $this->CI->dates->format_for($params['VALUE'], $tz);
// Save new value
$component->setProperty('dtend',
$this->CI->dates->datetime2idt($value, $tz, $format),
$params);
return $component;
}
/**
* Make easy to parse a DTSTART/DTEND
*/
function extract_date($component, $name = 'DTSTART', $tz) {
$p = $component->getProperty($name, FALSE, TRUE);
if ($p === FALSE) {
return null;
} else {
$val = $p['value'];
$params = $p['params'];
}
$obj = $this->CI->dates->idt2datetime(
$val,
$tz);
$value_parameter = $this->paramvalue($params, 'value', 'DATE-TIME');
return array(
'property' => $p,
'value' => $value_parameter,
'result' => $obj,
);
}
/**
* Changes every property passed as an associative array (key will be
* uppercased) on given component. DTSTART, DTEND and
* DURATION are ignored, use make_start and make_end instead
*
* @param iCalComponent $component
* @param array $properties
*/
function change_properties($component, $properties) {
$properties = array_change_key_case($properties, CASE_UPPER);
foreach ($properties as $p => $v) {
if ($p == 'DTSTART' || $p == 'DTEND' || $p == 'DURATION') {
continue;
}
// TODO: multivalued properties?
// TRANSP
if ($p == 'TRANSP') {
if ($v != 'OPAQUE' && $v != 'TRANSPARENT') {
log_message('ERROR', 'Invalid TRANSP value ('.$v.'). Ignoring.');
continue;
}
}
$component->deleteProperty($p);
if (!empty($v)) {
$component->setProperty($p, $v);
}
}
return $component;
}
/**
* Changes an event to have all its components with a new timezone
*
* Affected properties: DTSTART, DTEND, DUE, EXDATE, RDATE
*
* Only changed if VALUE is DATE-TIME or TIME
* Information extracted from RFC 2445, 4.2.19
*/
function change_tz($component, $old_tz, $new_tzid, $new_tz) {
$change = array('DTSTART', 'DTEND', 'DUE', 'EXDATE', 'RDATE');
foreach ($change as $c) {
$new_prop = array();
$prop = $component->GetProperties($c);
foreach ($prop as $p) {
$valuep = $p->GetParameterValue('VALUE');
if (!is_null($valuep) && $valuep == 'DATE') {
$new_prop[] = $p;
continue;
}
$tzid = $p->GetParameterValue('TZID');
if (!is_null($tzid) && $tzid == $new_tzid) {
// Keep untouched
$new_prop[] = $p;
continue;
}
// No TZ or different TZ
$val = $p->Value();
$multiple = preg_split('/,/', $val);
foreach ($multiple as $v) {
$new_p = clone $p;
$current = $this->CI->dates->idt2datetime($v,
$this->CI->dates->format_for($valuep, $old_tz),
$old_tz);
$new_p->SetParameterValue('TZID', $new_tzid);
$new_p->Value($this->CI->dates->datetime2idt($current,
$new_tz));
$new_prop[] = $new_p;
}
} // end foreach $prop
// Set new properties
$component->SetProperties($new_prop, $c);
}
return $component;
}
/**
* Make it easy to access parameters
*/
function paramvalue($params, $name, $default_val = FALSE) {
$name = strtoupper($name);
return (isset($params[$name]) ? $params[$name] : $default_val);
}
/**
* Add a VTIMEZONE using the specified TZID
* If VTIMEZONE was already added, do nothing
*
* @param iCalcomponent
* @param string Timezone id to add
* @param array (Optional) result from get_timezones()
* @return Used TZID, even when it was not added
*/
function add_vtimezone(&$resource, $tzid, $timezones = array()) {
if ($tzid != 'UTC' && !isset($timezones[$tzid])) {
$res = iCalUtilityFunctions::createTimezone($resource,
$tzid, array( 'X-LIC-LOCATION' => $tzid));
if ($res === FALSE) {
$this->CI->extended_logs->message('ERROR',
"Couldn't create vtimezone with tzid=" . $tzid
.' Defaulting to UTC');
$tzid = 'UTC';
}
}
return $tzid;
}
/**
* Parses a VEVENT resource VALARM definitions
*
* Returns an associative array ('n1#' => new Reminder, 'n2#' => new
* Reminder...), where 'n#' is the order where this VALARM was found
*/
function parse_valarms($vevent, $timezones = array()) {
$parsed_reminders = array();
$order = 0;
while ($valarm = $vevent->getComponent('valarm')) {
$order++;
// TODO parse more actions
$action = $valarm->getProperty('action');
if ($action == 'DISPLAY') {
$trigger = $valarm->getProperty('trigger');
$reminder = null;
if (isset($trigger['before'])) {
// Related to event start/end
$reminder = Reminder::createFrom($trigger);
} else {
// Absolute date-time trigger
$tz = $this->detect_tz($valarm, $timezones, 'trigger');
$datetime = $this->CI->dates->idt2datetime($trigger, $tz);
// Use default timezone
$datetime->setTimezone($this->tz);
$reminder = Reminder::createFrom($datetime);
$reminder->tdate =
$datetime->format($this->date_frontend_format);
$reminder->ttime =
$datetime->format($this->time_frontend_format);
}
if ($reminder !== null) {
$reminder->order = $order;
$parsed_reminders[$order] = $reminder;
}
}
}
return $parsed_reminders;
}
/**
* Adds or replaces VALARM components (reminders) for a given VEVENT
* resource. Removes VALARMs that were deleted by user
*/
function set_valarms(&$resource, $reminders, $old_visible_reminders =
array()) {
foreach ($reminders as $r) {
$valarm = new valarm();
$valarm = $r->assign_properties($valarm);
if ($r->order !== FALSE) {
$resource = $this->replace_component($resource,
'valarm', $r->order, $valarm);
unset($old_visible_reminders[$r->order]);
} else {
$resource->setComponent($valarm);
}
}
// Any VALARMs left that was not present?
$remove_valarms = array_keys($old_visible_reminders);
foreach ($remove_valarms as $n) {
$resource->deleteComponent('valarm', $n);
}
return $resource;
}
}