PHP8 compatibility fixes

This commit is contained in:
Aleksander Machniak 2020-12-26 20:41:54 +01:00
parent f8ba2e6fc7
commit d36017592a
8 changed files with 226 additions and 142 deletions

View file

@ -610,33 +610,45 @@ class libcalendaring extends rcube_plugin
*/ */
public static function get_next_alarm($rec, $type = 'event') public static function get_next_alarm($rec, $type = 'event')
{ {
if (!($rec['valarms'] || $rec['alarms']) || $rec['cancelled'] || $rec['status'] == 'CANCELLED') if (
(empty($rec['valarms']) && empty($rec['alarms']))
|| !empty($rec['cancelled'])
|| (!empty($rec['status']) && $rec['status'] == 'CANCELLED')
) {
return null; return null;
}
if ($type == 'task') { if ($type == 'task') {
$timezone = self::get_instance()->timezone; $timezone = self::get_instance()->timezone;
if ($rec['startdate']) if (!empty($rec['startdate'])) {
$rec['start'] = new DateTime($rec['startdate'] . ' ' . ($rec['starttime'] ?: '12:00'), $timezone); $time = !empty($rec['starttime']) ? $rec['starttime'] : '12:00';
if ($rec['date']) $rec['start'] = new DateTime($rec['startdate'] . ' ' . $time, $timezone);
$rec[($rec['start'] ? 'end' : 'start')] = new DateTime($rec['date'] . ' ' . ($rec['time'] ?: '12:00'), $timezone); }
if (!empty($rec['date'])) {
$time = !empty($rec['time']) ? $rec['time'] : '12:00';
$rec[!empty($rec['start']) ? 'end' : 'start'] = new DateTime($rec['date'] . ' ' . $time, $timezone);
}
} }
if (!$rec['end']) if (empty($rec['end'])) {
$rec['end'] = $rec['start']; $rec['end'] = $rec['start'];
}
// support legacy format // support legacy format
if (!$rec['valarms']) { if (empty($rec['valarms'])) {
list($trigger, $action) = explode(':', $rec['alarms'], 2); list($trigger, $action) = explode(':', $rec['alarms'], 2);
if ($alarm = self::parse_alarm_value($trigger)) { if ($alarm = self::parse_alarm_value($trigger)) {
$rec['valarms'] = array(array('action' => $action, 'trigger' => $alarm[3] ?: $alarm[0])); $rec['valarms'] = array(array('action' => $action, 'trigger' => $alarm[3] ?: $alarm[0]));
} }
} }
// alarm ID eq. record ID by default to keep backwards compatibility
$alarm_id = isset($rec['id']) ? $rec['id'] : null;
$alarm_prop = null;
$expires = new DateTime('now - 12 hours'); $expires = new DateTime('now - 12 hours');
$alarm_id = $rec['id']; // alarm ID eq. record ID by default to keep backwards compatibility $notify_at = null;
// handle multiple alarms // handle multiple alarms
$notify_at = null;
foreach ($rec['valarms'] as $alarm) { foreach ($rec['valarms'] as $alarm) {
$notify_time = null; $notify_time = null;
@ -644,11 +656,12 @@ class libcalendaring extends rcube_plugin
$notify_time = $alarm['trigger']; $notify_time = $alarm['trigger'];
} }
else if (is_string($alarm['trigger'])) { else if (is_string($alarm['trigger'])) {
$refdate = $alarm['related'] == 'END' ? $rec['end'] : $rec['start']; $refdate = !empty($alarm['related']) && $alarm['related'] == 'END' ? $rec['end'] : $rec['start'];
// abort if no reference date is available to compute notification time // abort if no reference date is available to compute notification time
if (!is_a($refdate, 'DateTime')) if (!is_a($refdate, 'DateTime')) {
continue; continue;
}
// TODO: for all-day events, take start @ 00:00 as reference date ? // TODO: for all-day events, take start @ 00:00 as reference date ?
@ -666,19 +679,20 @@ class libcalendaring extends rcube_plugin
if ($notify_time && (!$notify_at || ($notify_time > $notify_at && $notify_time > $expires))) { if ($notify_time && (!$notify_at || ($notify_time > $notify_at && $notify_time > $expires))) {
$notify_at = $notify_time; $notify_at = $notify_time;
$action = $alarm['action']; $action = isset($alarm['action']) ? $alarm['action'] : null;
$alarm_prop = $alarm; $alarm_prop = $alarm;
// generate a unique alarm ID if multiple alarms are set // generate a unique alarm ID if multiple alarms are set
if (count($rec['valarms']) > 1) { if (count($rec['valarms']) > 1) {
$alarm_id = substr(md5($rec['id']), 0, 16) . '-' . $notify_at->format('Ymd\THis'); $rec_id = substr(md5(isset($rec['id']) ? $rec['id'] : 'none'), 0, 16);
$alarm_id = $rec_id . '-' . $notify_at->format('Ymd\THis');
} }
} }
} }
return !$notify_at ? null : array( return !$notify_at ? null : array(
'time' => $notify_at->format('U'), 'time' => $notify_at->format('U'),
'action' => $action ? strtoupper($action) : 'DISPLAY', 'action' => !empty($action) ? strtoupper($action) : 'DISPLAY',
'id' => $alarm_id, 'id' => $alarm_id,
'prop' => $alarm_prop, 'prop' => $alarm_prop,
); );
@ -716,11 +730,13 @@ class libcalendaring extends rcube_plugin
$data['ids'] = explode(',', $data['id']); $data['ids'] = explode(',', $data['id']);
$plugin = $this->rc->plugins->exec_hook('dismiss_alarms', $data); $plugin = $this->rc->plugins->exec_hook('dismiss_alarms', $data);
if ($plugin['success']) if (!empty($plugin['success'])) {
$this->rc->output->show_message('successfullysaved', 'confirmation'); $this->rc->output->show_message('successfullysaved', 'confirmation');
else }
else {
$this->rc->output->show_message('calendar.errorsaving', 'error'); $this->rc->output->show_message('calendar.errorsaving', 'error');
} }
}
/** /**
* Generate reduced and streamlined output for pending alarms * Generate reduced and streamlined output for pending alarms
@ -731,9 +747,9 @@ class libcalendaring extends rcube_plugin
foreach ($alarms as $alarm) { foreach ($alarms as $alarm) {
$out[] = array( $out[] = array(
'id' => $alarm['id'], 'id' => $alarm['id'],
'start' => $alarm['start'] ? $this->adjust_timezone($alarm['start'])->format('c') : '', 'start' => !empty($alarm['start']) ? $this->adjust_timezone($alarm['start'])->format('c') : '',
'end' => $alarm['end'] ? $this->adjust_timezone($alarm['end'])->format('c') : '', 'end' => !empty($alarm['end'])? $this->adjust_timezone($alarm['end'])->format('c') : '',
'allDay' => $alarm['allday'] == 1, 'allDay' => !empty($alarm['allday']),
'action' => $alarm['action'], 'action' => $alarm['action'],
'title' => $alarm['title'], 'title' => $alarm['title'],
'location' => $alarm['location'], 'location' => $alarm['location'],
@ -1427,8 +1443,9 @@ class libcalendaring extends rcube_plugin
*/ */
public static function to_rrule($recurrence, $allday = false) public static function to_rrule($recurrence, $allday = false)
{ {
if (is_string($recurrence)) if (is_string($recurrence)) {
return $recurrence; return $recurrence;
}
$rrule = ''; $rrule = '';
foreach ((array)$recurrence as $k => $val) { foreach ((array)$recurrence as $k => $val) {
@ -1437,7 +1454,7 @@ class libcalendaring extends rcube_plugin
case 'UNTIL': case 'UNTIL':
// convert to UTC according to RFC 5545 // convert to UTC according to RFC 5545
if (is_a($val, 'DateTime')) { if (is_a($val, 'DateTime')) {
if (!$allday && !$val->_dateonly) { if (!$allday && empty($val->_dateonly)) {
$until = clone $val; $until = clone $val;
$until->setTimezone(new DateTimeZone('UTC')); $until->setTimezone(new DateTimeZone('UTC'));
$val = $until->format('Ymd\THis\Z'); $val = $until->format('Ymd\THis\Z');
@ -1450,18 +1467,20 @@ class libcalendaring extends rcube_plugin
case 'RDATE': case 'RDATE':
case 'EXDATE': case 'EXDATE':
foreach ((array)$val as $i => $ex) { foreach ((array)$val as $i => $ex) {
if (is_a($ex, 'DateTime')) if (is_a($ex, 'DateTime')) {
$val[$i] = $ex->format('Ymd\THis'); $val[$i] = $ex->format('Ymd\THis');
} }
}
$val = join(',', (array)$val); $val = join(',', (array)$val);
break; break;
case 'EXCEPTIONS': case 'EXCEPTIONS':
continue 2; continue 2;
} }
if (strlen($val)) if (strlen($val)) {
$rrule .= $k . '=' . $val . ';'; $rrule .= $k . '=' . $val . ';';
} }
}
return rtrim($rrule, ';'); return rtrim($rrule, ';');
} }

View file

@ -326,10 +326,11 @@ class libvcalendar implements Iterator
$object = $this->_to_array($ve); $object = $this->_to_array($ve);
// temporarily store this as exception // temporarily store this as exception
if ($object['recurrence_date']) { if (!empty($object['recurrence_date'])) {
$exceptions[] = $object; $exceptions[] = $object;
} }
else if (!$seen[$object['uid']]++) { else if (empty($seen[$object['uid']])) {
$seen[$object['uid']] = true;
$this->objects[] = $object; $this->objects[] = $object;
} }
} }
@ -343,7 +344,8 @@ class libvcalendar implements Iterator
$uid = $exception['uid']; $uid = $exception['uid'];
// make this exception the master // make this exception the master
if (!$seen[$uid]++) { if (empty($seen[$uid])) {
$seen[$uid] = true;
$this->objects[] = $exception; $this->objects[] = $exception;
} }
else { else {
@ -412,7 +414,7 @@ class libvcalendar implements Iterator
// We can skip these fields, they aren't critical // We can skip these fields, they aren't critical
foreach (array('CREATED' => 'created', 'LAST-MODIFIED' => 'changed', 'DTSTAMP' => 'changed') as $attr => $field) { foreach (array('CREATED' => 'created', 'LAST-MODIFIED' => 'changed', 'DTSTAMP' => 'changed') as $attr => $field) {
try { try {
if (!$event[$field] && $ve->{$attr}) { if (empty($event[$field]) && !empty($ve->{$attr})) {
$event[$field] = $ve->{$attr}->getDateTime(); $event[$field] = $ve->{$attr}->getDateTime();
} }
} catch (Exception $e) {} } catch (Exception $e) {}
@ -461,15 +463,17 @@ class libvcalendar implements Iterator
break; break;
case 'RRULE': case 'RRULE':
$params = is_array($event['recurrence']) ? $event['recurrence'] : array(); $params = !empty($event['recurrence']) && is_array($event['recurrence']) ? $event['recurrence'] : array();
// parse recurrence rule attributes // parse recurrence rule attributes
foreach ($prop->getParts() as $k => $v) { foreach ($prop->getParts() as $k => $v) {
$params[strtoupper($k)] = is_array($v) ? implode(',', $v) : $v; $params[strtoupper($k)] = is_array($v) ? implode(',', $v) : $v;
} }
if ($params['UNTIL']) if (!empty($params['UNTIL'])) {
$params['UNTIL'] = date_create($params['UNTIL']); $params['UNTIL'] = date_create($params['UNTIL']);
if (!$params['INTERVAL']) }
if (empty($params['INTERVAL'])) {
$params['INTERVAL'] = 1; $params['INTERVAL'] = 1;
}
$event['recurrence'] = array_filter($params); $event['recurrence'] = array_filter($params);
break; break;
@ -477,14 +481,24 @@ class libvcalendar implements Iterator
case 'EXDATE': case 'EXDATE':
if (!empty($value)) { if (!empty($value)) {
$exdates = array_map(function($_) { return is_array($_) ? $_[0] : $_; }, self::convert_datetime($prop, true)); $exdates = array_map(function($_) { return is_array($_) ? $_[0] : $_; }, self::convert_datetime($prop, true));
$event['recurrence']['EXDATE'] = array_merge((array)$event['recurrence']['EXDATE'], $exdates); if (!empty($event['recurrence']['EXDATE'])) {
$event['recurrence']['EXDATE'] = array_merge($event['recurrence']['EXDATE'], $exdates);
}
else {
$event['recurrence']['EXDATE'] = $exdates;
}
} }
break; break;
case 'RDATE': case 'RDATE':
if (!empty($value)) { if (!empty($value)) {
$rdates = array_map(function($_) { return is_array($_) ? $_[0] : $_; }, self::convert_datetime($prop, true)); $rdates = array_map(function($_) { return is_array($_) ? $_[0] : $_; }, self::convert_datetime($prop, true));
$event['recurrence']['RDATE'] = array_merge((array)$event['recurrence']['RDATE'], $rdates); if (!empty($event['recurrence']['RDATE'])) {
$event['recurrence']['RDATE'] = array_merge($event['recurrence']['RDATE'], $rdates);
}
else {
$event['recurrence']['RDATE'] = $rdates;
}
} }
break; break;
@ -519,7 +533,12 @@ class libvcalendar implements Iterator
case 'CATEGORY': case 'CATEGORY':
case 'CATEGORIES': case 'CATEGORIES':
if (!empty($event['categories'])) {
$event['categories'] = array_merge((array) $event['categories'], $prop->getParts()); $event['categories'] = array_merge((array) $event['categories'], $prop->getParts());
}
else {
$event['categories'] = $prop->getParts();
}
break; break;
case 'CLASS': case 'CLASS':
@ -528,10 +547,12 @@ class libvcalendar implements Iterator
break; break;
case 'X-MICROSOFT-CDO-BUSYSTATUS': case 'X-MICROSOFT-CDO-BUSYSTATUS':
if ($value == 'OOF') if ($value == 'OOF') {
$event['free_busy'] = 'outofoffice'; $event['free_busy'] = 'outofoffice';
else if (in_array($value, array('FREE', 'BUSY', 'TENTATIVE'))) }
else if (in_array($value, array('FREE', 'BUSY', 'TENTATIVE'))) {
$event['free_busy'] = strtolower($value); $event['free_busy'] = strtolower($value);
}
break; break;
case 'ATTENDEE': case 'ATTENDEE':
@ -596,12 +617,7 @@ class libvcalendar implements Iterator
// validate event dates // validate event dates
if ($event['_type'] == 'event') { if ($event['_type'] == 'event') {
$event['allday'] = false; $event['allday'] = !empty($event['start']->_dateonly);
// check for all-day dates
if ($event['start']->_dateonly) {
$event['allday'] = true;
}
// events may lack the DTEND property, set it to DTSTART (RFC5545 3.6.1) // events may lack the DTEND property, set it to DTSTART (RFC5545 3.6.1)
if (empty($event['end'])) { if (empty($event['end'])) {
@ -647,12 +663,13 @@ class libvcalendar implements Iterator
$trigger = $values[2]; $trigger = $values[2];
} }
if (!$alarm['trigger']) { if (empty($alarm['trigger'])) {
$alarm['trigger'] = rtrim(preg_replace('/([A-Z])0[WDHMS]/', '\\1', $value), 'T'); $alarm['trigger'] = rtrim(preg_replace('/([A-Z])0[WDHMS]/', '\\1', $value), 'T');
// if all 0-values have been stripped, assume 'at time' // if all 0-values have been stripped, assume 'at time'
if ($alarm['trigger'] == 'P') if ($alarm['trigger'] == 'P') {
$alarm['trigger'] = 'PT0S'; $alarm['trigger'] = 'PT0S';
} }
}
break; break;
case 'ACTION': case 'ACTION':
@ -684,23 +701,26 @@ class libvcalendar implements Iterator
} }
if ($action != 'NONE') { if ($action != 'NONE') {
if ($trigger && !$event['alarms']) // store first alarm in legacy property // store first alarm in legacy property
if ($trigger && empty($event['alarms'])) {
$event['alarms'] = $trigger . ':' . $action; $event['alarms'] = $trigger . ':' . $action;
}
if ($alarm['trigger']) if (!empty($alarm['trigger'])) {
$event['valarms'][] = $alarm; $event['valarms'][] = $alarm;
} }
} }
}
// assign current timezone to event start/end // assign current timezone to event start/end
if ($event['start'] instanceof DateTime) { if (!empty($event['start']) && $event['start'] instanceof DateTime) {
$this->_apply_timezone($event['start']); $this->_apply_timezone($event['start']);
} }
else { else {
unset($event['start']); unset($event['start']);
} }
if ($event['end'] instanceof DateTime) { if (!empty($event['end']) && $event['end'] instanceof DateTime) {
$this->_apply_timezone($event['end']); $this->_apply_timezone($event['end']);
} }
else { else {
@ -708,7 +728,7 @@ class libvcalendar implements Iterator
} }
// some iTip CANCEL messages only contain the start date // some iTip CANCEL messages only contain the start date
if (!$event['end'] && $event['start'] && $this->method == 'CANCEL') { if (empty($event['end']) && !empty($event['start']) && $this->method == 'CANCEL') {
$event['end'] = clone $event['start']; $event['end'] = clone $event['start'];
} }
@ -767,7 +787,13 @@ class libvcalendar implements Iterator
case 'DTSTAMP': case 'DTSTAMP':
case 'DTSTART': case 'DTSTART':
case 'DTEND': case 'DTEND':
$propmap = array('DTSTART' => 'start', 'DTEND' => 'end', 'CREATED' => 'created', 'LAST-MODIFIED' => 'changed', 'DTSTAMP' => 'changed'); $propmap = array(
'DTSTART' => 'start',
'DTEND' => 'end',
'CREATED' => 'created',
'LAST-MODIFIED' => 'changed',
'DTSTAMP' => 'changed'
);
$this->freebusy[$propmap[$prop->name]] = self::convert_datetime($prop); $this->freebusy[$propmap[$prop->name]] = self::convert_datetime($prop);
break; break;
@ -781,8 +807,11 @@ class libvcalendar implements Iterator
$fbtype = strval($prop['FBTYPE']) ?: 'BUSY'; $fbtype = strval($prop['FBTYPE']) ?: 'BUSY';
// skip dupes // skip dupes
if ($seen[$value.':'.$fbtype]++) if (!empty($seen[$value.':'.$fbtype])) {
break; break;
}
$seen[$value.':'.$fbtype] = true;
foreach ($periods as $period) { foreach ($periods as $period) {
// Every period is formatted as [start]/[end]. The start is an // Every period is formatted as [start]/[end]. The start is an
@ -905,7 +934,7 @@ class libvcalendar implements Iterator
else { else {
$is_utc = ($tz = $dt->getTimezone()) && in_array($tz->getName(), array('UTC','GMT','Z')); $is_utc = ($tz = $dt->getTimezone()) && in_array($tz->getName(), array('UTC','GMT','Z'));
} }
$is_dateonly = $dateonly === null ? (bool)$dt->_dateonly : (bool)$dateonly; $is_dateonly = $dateonly === null ? !empty($dt->_dateonly) : (bool) $dateonly;
$vdt = $cal->createProperty($name, $dt, null, $is_dateonly ? 'DATE' : 'DATE-TIME'); $vdt = $cal->createProperty($name, $dt, null, $is_dateonly ? 'DATE' : 'DATE-TIME');
if ($is_dateonly) { if ($is_dateonly) {
@ -918,7 +947,7 @@ class libvcalendar implements Iterator
// register timezone for VTIMEZONE block // register timezone for VTIMEZONE block
if (!$is_utc && !$dateonly && $tz && ($tzname = $tz->getName())) { if (!$is_utc && !$dateonly && $tz && ($tzname = $tz->getName())) {
$ts = $dt->format('U'); $ts = $dt->format('U');
if (is_array($this->vtimezones[$tzname])) { if (!empty($this->vtimezones[$tzname])) {
$this->vtimezones[$tzname][0] = min($this->vtimezones[$tzname][0], $ts); $this->vtimezones[$tzname][0] = min($this->vtimezones[$tzname][0], $ts);
$this->vtimezones[$tzname][1] = max($this->vtimezones[$tzname][1], $ts); $this->vtimezones[$tzname][1] = max($this->vtimezones[$tzname][1], $ts);
} }
@ -1025,7 +1054,7 @@ class libvcalendar implements Iterator
*/ */
private function _to_ical($event, $vcal, $get_attachment, $recurrence_id = null) private function _to_ical($event, $vcal, $get_attachment, $recurrence_id = null)
{ {
$type = $event['_type'] ?: 'event'; $type = !empty($event['_type']) ? $event['_type'] : 'event';
$cal = $vcal ?: new VObject\Component\VCalendar(); $cal = $vcal ?: new VObject\Component\VCalendar();
$ve = $cal->create($this->type_component_map[$type]); $ve = $cal->create($this->type_component_map[$type]);
@ -1036,28 +1065,34 @@ class libvcalendar implements Iterator
$ve->DTSTAMP = $this->datetime_prop($cal, 'DTSTAMP', $dtstamp, true); $ve->DTSTAMP = $this->datetime_prop($cal, 'DTSTAMP', $dtstamp, true);
// all-day events end the next day // all-day events end the next day
if ($event['allday'] && !empty($event['end'])) { if (!empty($event['allday']) && !empty($event['end'])) {
$event['end'] = clone $event['end']; $event['end'] = clone $event['end'];
$event['end']->add(new \DateInterval('P1D')); $event['end']->add(new \DateInterval('P1D'));
$event['end']->_dateonly = true; $event['end']->_dateonly = true;
} }
if (!empty($event['created'])) if (!empty($event['created'])) {
$ve->add($this->datetime_prop($cal, 'CREATED', $event['created'], true)); $ve->add($this->datetime_prop($cal, 'CREATED', $event['created'], true));
if (!empty($event['changed'])) }
if (!empty($event['changed'])) {
$ve->add($this->datetime_prop($cal, 'LAST-MODIFIED', $event['changed'], true)); $ve->add($this->datetime_prop($cal, 'LAST-MODIFIED', $event['changed'], true));
if (!empty($event['start'])) }
$ve->add($this->datetime_prop($cal, 'DTSTART', $event['start'], false, (bool)$event['allday'])); if (!empty($event['start'])) {
if (!empty($event['end'])) $ve->add($this->datetime_prop($cal, 'DTSTART', $event['start'], false, !empty($event['allday'])));
$ve->add($this->datetime_prop($cal, 'DTEND', $event['end'], false, (bool)$event['allday'])); }
if (!empty($event['due'])) if (!empty($event['end'])) {
$ve->add($this->datetime_prop($cal, 'DTEND', $event['end'], false, !empty($event['allday'])));
}
if (!empty($event['due'])) {
$ve->add($this->datetime_prop($cal, 'DUE', $event['due'], false)); $ve->add($this->datetime_prop($cal, 'DUE', $event['due'], false));
}
// we're exporting a recurrence instance only // we're exporting a recurrence instance only
if (!$recurrence_id && $event['recurrence_date'] && $event['recurrence_date'] instanceof DateTime) { if (!$recurrence_id && !empty($event['recurrence_date']) && $event['recurrence_date'] instanceof DateTime) {
$recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $event['recurrence_date'], false, (bool)$event['allday']); $recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $event['recurrence_date'], false, !empty($event['allday']));
if ($event['thisandfuture']) if (!empty($event['thisandfuture'])) {
$recurrence_id->add('RANGE', 'THISANDFUTURE'); $recurrence_id->add('RANGE', 'THISANDFUTURE');
} }
}
if ($recurrence_id) { if ($recurrence_id) {
$ve->add($recurrence_id); $ve->add($recurrence_id);
@ -1065,15 +1100,18 @@ class libvcalendar implements Iterator
$ve->add('SUMMARY', $event['title']); $ve->add('SUMMARY', $event['title']);
if ($event['location']) if (!empty($event['location'])) {
$ve->add($this->is_apple() ? new vobject_location_property($cal, 'LOCATION', $event['location']) : $cal->create('LOCATION', $event['location'])); $ve->add($this->is_apple() ? new vobject_location_property($cal, 'LOCATION', $event['location']) : $cal->create('LOCATION', $event['location']));
if ($event['description']) }
if (!empty($event['description'])) {
$ve->add('DESCRIPTION', strtr($event['description'], array("\r\n" => "\n", "\r" => "\n"))); // normalize line endings $ve->add('DESCRIPTION', strtr($event['description'], array("\r\n" => "\n", "\r" => "\n"))); // normalize line endings
}
if (isset($event['sequence'])) if (isset($event['sequence'])) {
$ve->add('SEQUENCE', $event['sequence']); $ve->add('SEQUENCE', $event['sequence']);
}
if ($event['recurrence'] && !$recurrence_id) { if (!empty($event['recurrence']) && !$recurrence_id) {
$exdates = $rdates = null; $exdates = $rdates = null;
if (isset($event['recurrence']['EXDATE'])) { if (isset($event['recurrence']['EXDATE'])) {
$exdates = $event['recurrence']['EXDATE']; $exdates = $event['recurrence']['EXDATE'];
@ -1084,8 +1122,8 @@ class libvcalendar implements Iterator
unset($event['recurrence']['RDATE']); // don't serialize RDATEs into RRULE value unset($event['recurrence']['RDATE']); // don't serialize RDATEs into RRULE value
} }
if ($event['recurrence']['FREQ']) { if (!empty($event['recurrence']['FREQ'])) {
$ve->add('RRULE', libcalendaring::to_rrule($event['recurrence'], (bool)$event['allday'])); $ve->add('RRULE', libcalendaring::to_rrule($event['recurrence'], !empty($event['allday'])));
} }
// add EXDATEs each one per line (for Thunderbird Lightning) // add EXDATEs each one per line (for Thunderbird Lightning)
@ -1104,7 +1142,7 @@ class libvcalendar implements Iterator
} }
} }
if ($event['categories']) { if (!empty($event['categories'])) {
$cat = $cal->create('CATEGORIES'); $cat = $cal->create('CATEGORIES');
$cat->setParts((array)$event['categories']); $cat->setParts((array)$event['categories']);
$ve->add($cat); $ve->add($cat);
@ -1119,17 +1157,22 @@ class libvcalendar implements Iterator
} }
} }
if ($event['priority']) if (!empty($event['priority'])) {
$ve->add('PRIORITY', $event['priority']); $ve->add('PRIORITY', $event['priority']);
}
if ($event['cancelled']) if (!empty($event['cancelled'])) {
$ve->add('STATUS', 'CANCELLED'); $ve->add('STATUS', 'CANCELLED');
else if ($event['free_busy'] == 'tentative') }
else if (!empty($event['free_busy']) && $event['free_busy'] == 'tentative') {
$ve->add('STATUS', 'TENTATIVE'); $ve->add('STATUS', 'TENTATIVE');
else if ($event['complete'] == 100) }
else if (!empty($event['complete']) && $event['complete'] == 100) {
$ve->add('STATUS', 'COMPLETED'); $ve->add('STATUS', 'COMPLETED');
else if (!empty($event['status'])) }
else if (!empty($event['status'])) {
$ve->add('STATUS', $event['status']); $ve->add('STATUS', $event['status']);
}
if (!empty($event['sensitivity'])) if (!empty($event['sensitivity']))
$ve->add('CLASS', strtoupper($event['sensitivity'])); $ve->add('CLASS', strtoupper($event['sensitivity']));
@ -1139,11 +1182,15 @@ class libvcalendar implements Iterator
} }
// Apple iCal and BusyCal required the COMPLETED date to be set in order to consider a task complete // Apple iCal and BusyCal required the COMPLETED date to be set in order to consider a task complete
if ($event['status'] == 'COMPLETED' || $event['complete'] == 100) { if (
$ve->add($this->datetime_prop($cal, 'COMPLETED', $event['changed'] ?: new DateTime('now - 1 hour'), true)); (!empty($event['status']) && $event['status'] == 'COMPLETED')
|| (!empty($event['complete']) && $event['complete'] == 100)
) {
$completed = !empty($event['changed']) ? $event['changed'] : new DateTime('now - 1 hour');
$ve->add($this->datetime_prop($cal, 'COMPLETED', $completed, true));
} }
if ($event['valarms']) { if (!empty($event['valarms'])) {
foreach ($event['valarms'] as $alarm) { foreach ($event['valarms'] as $alarm) {
$va = $cal->createComponent('VALARM'); $va = $cal->createComponent('VALARM');
$va->action = $alarm['action']; $va->action = $alarm['action'];
@ -1152,94 +1199,106 @@ class libvcalendar implements Iterator
} }
else { else {
$alarm_props = array(); $alarm_props = array();
if (strtoupper($alarm['related']) == 'END') { if (!empty($alarm['related']) && strtoupper($alarm['related']) == 'END') {
$alarm_props['RELATED'] = 'END'; $alarm_props['RELATED'] = 'END';
} }
$va->add('TRIGGER', $alarm['trigger'], $alarm_props); $va->add('TRIGGER', $alarm['trigger'], $alarm_props);
} }
if ($alarm['action'] == 'EMAIL') { if (!empty($alarm['action']) && $alarm['action'] == 'EMAIL') {
if (!empty($alarm['attendees'])) {
foreach ((array) $alarm['attendees'] as $attendee) { foreach ((array) $alarm['attendees'] as $attendee) {
$va->add('ATTENDEE', 'mailto:' . $attendee); $va->add('ATTENDEE', 'mailto:' . $attendee);
} }
} }
if ($alarm['description']) {
$va->add('DESCRIPTION', $alarm['description'] ?: $event['title']);
} }
if ($alarm['summary']) { if (!empty($alarm['description'])) {
$va->add('DESCRIPTION', $alarm['description']);
}
if (!empty($alarm['summary'])) {
$va->add('SUMMARY', $alarm['summary']); $va->add('SUMMARY', $alarm['summary']);
} }
if ($alarm['duration']) { if (!empty($alarm['duration'])) {
$va->add('DURATION', $alarm['duration']); $va->add('DURATION', $alarm['duration']);
$va->add('REPEAT', intval($alarm['repeat'])); $va->add('REPEAT', !empty($alarm['repeat']) ? intval($alarm['repeat']) : 0);
} }
if ($alarm['uri']) { if (!empty($alarm['uri'])) {
$va->add('ATTACH', $alarm['uri'], array('VALUE' => 'URI')); $va->add('ATTACH', $alarm['uri'], array('VALUE' => 'URI'));
} }
$ve->add($va); $ve->add($va);
} }
} }
// legacy support // legacy support
else if ($event['alarms']) { else if (!empty($event['alarms'])) {
$va = $cal->createComponent('VALARM'); $va = $cal->createComponent('VALARM');
list($trigger, $va->action) = explode(':', $event['alarms']); list($trigger, $va->action) = explode(':', $event['alarms']);
$val = libcalendaring::parse_alarm_value($trigger); $val = libcalendaring::parse_alarm_value($trigger);
if ($val[3]) if (!empty($val[3])) {
$va->add('TRIGGER', $val[3]); $va->add('TRIGGER', $val[3]);
else if ($val[0] instanceof DateTime) }
else if ($val[0] instanceof DateTime) {
$va->add($this->datetime_prop($cal, 'TRIGGER', $val[0], true, null, true)); $va->add($this->datetime_prop($cal, 'TRIGGER', $val[0], true, null, true));
}
$ve->add($va); $ve->add($va);
} }
// Find SCHEDULE-AGENT // Find SCHEDULE-AGENT
if (!empty($event['x-custom'])) {
foreach ((array) $event['x-custom'] as $prop) { foreach ((array) $event['x-custom'] as $prop) {
if ($prop[0] === 'SCHEDULE-AGENT') { if ($prop[0] === 'SCHEDULE-AGENT') {
$schedule_agent = $prop[1]; $schedule_agent = $prop[1];
} }
} }
}
if (!empty($event['attendees'])) {
foreach ((array) $event['attendees'] as $attendee) { foreach ((array) $event['attendees'] as $attendee) {
if ($attendee['role'] == 'ORGANIZER') { if ($attendee['role'] == 'ORGANIZER') {
if (empty($event['organizer'])) if (empty($event['organizer']))
$event['organizer'] = $attendee; $event['organizer'] = $attendee;
} }
else if (!empty($attendee['email'])) { else if (!empty($attendee['email'])) {
if (isset($attendee['rsvp'])) if (isset($attendee['rsvp'])) {
$attendee['rsvp'] = $attendee['rsvp'] ? 'TRUE' : null; $attendee['rsvp'] = $attendee['rsvp'] ? 'TRUE' : null;
}
$mailto = $attendee['email']; $mailto = $attendee['email'];
$attendee = array_filter(self::map_keys($attendee, $this->attendee_keymap)); $attendee = array_filter(self::map_keys($attendee, $this->attendee_keymap));
if ($schedule_agent !== null && !isset($attendee['SCHEDULE-AGENT'])) { if (isset($schedule_agent) && !isset($attendee['SCHEDULE-AGENT'])) {
$attendee['SCHEDULE-AGENT'] = $schedule_agent; $attendee['SCHEDULE-AGENT'] = $schedule_agent;
} }
$ve->add('ATTENDEE', 'mailto:' . $mailto, $attendee); $ve->add('ATTENDEE', 'mailto:' . $mailto, $attendee);
} }
} }
}
if ($event['organizer']) { if (!empty($event['organizer'])) {
$organizer = array_filter(self::map_keys($event['organizer'], $this->organizer_keymap)); $organizer = array_filter(self::map_keys($event['organizer'], $this->organizer_keymap));
if ($schedule_agent !== null && !isset($organizer['SCHEDULE-AGENT'])) { if (isset($schedule_agent) && !isset($organizer['SCHEDULE-AGENT'])) {
$organizer['SCHEDULE-AGENT'] = $schedule_agent; $organizer['SCHEDULE-AGENT'] = $schedule_agent;
} }
$ve->add('ORGANIZER', 'mailto:' . $event['organizer']['email'], $organizer); $ve->add('ORGANIZER', 'mailto:' . $event['organizer']['email'], $organizer);
} }
if (!empty($event['url'])) {
foreach ((array) $event['url'] as $url) { foreach ((array) $event['url'] as $url) {
if (!empty($url)) { if (!empty($url)) {
$ve->add('URL', $url); $ve->add('URL', $url);
} }
} }
}
if (!empty($event['parent_id'])) { if (!empty($event['parent_id'])) {
$ve->add('RELATED-TO', $event['parent_id'], array('RELTYPE' => 'PARENT')); $ve->add('RELATED-TO', $event['parent_id'], array('RELTYPE' => 'PARENT'));
} }
if ($event['comment']) if (!empty($event['comment'])) {
$ve->add('COMMENT', $event['comment']); $ve->add('COMMENT', $event['comment']);
}
$memory_limit = parse_bytes(ini_get('memory_limit')); $memory_limit = parse_bytes(ini_get('memory_limit'));
@ -1273,14 +1332,18 @@ class libvcalendar implements Iterator
} }
} }
if (!empty($event['links'])) {
foreach ((array) $event['links'] as $uri) { foreach ((array) $event['links'] as $uri) {
$ve->add('ATTACH', $uri); $ve->add('ATTACH', $uri);
} }
}
// add custom properties // add custom properties
if (!empty($event['x-custom'])) {
foreach ((array) $event['x-custom'] as $prop) { foreach ((array) $event['x-custom'] as $prop) {
$ve->add($prop[0], $prop[1]); $ve->add($prop[0], $prop[1]);
} }
}
// append to vcalendar container // append to vcalendar container
if ($vcal) { if ($vcal) {
@ -1291,12 +1354,13 @@ class libvcalendar implements Iterator
} }
// append recurrence exceptions // append recurrence exceptions
if (is_array($event['recurrence']) && $event['recurrence']['EXCEPTIONS']) { if (!empty($event['recurrence']) && !empty($event['recurrence']['EXCEPTIONS'])) {
foreach ($event['recurrence']['EXCEPTIONS'] as $ex) { foreach ($event['recurrence']['EXCEPTIONS'] as $ex) {
$exdate = $ex['recurrence_date'] ?: $ex['start']; $exdate = !empty($ex['recurrence_date']) ? $ex['recurrence_date'] : $ex['start'];
$recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $exdate, false, (bool)$event['allday']); $recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $exdate, false, !empty($event['allday']));
if ($ex['thisandfuture']) if (!empty($ex['thisandfuture'])) {
$recurrence_id->add('RANGE', 'THISANDFUTURE'); $recurrence_id->add('RANGE', 'THISANDFUTURE');
}
$this->_to_ical($ex, $vcal, $get_attachment, $recurrence_id); $this->_to_ical($ex, $vcal, $get_attachment, $recurrence_id);
} }
} }
@ -1334,7 +1398,7 @@ class libvcalendar implements Iterator
$tz = $tzid; $tz = $tzid;
} }
if (!is_a($tz, '\\DateTimeZone')) { if (empty($tz) || !is_a($tz, '\\DateTimeZone')) {
return false; return false;
} }
@ -1424,7 +1488,7 @@ class libvcalendar implements Iterator
$this->iteratorkey++; $this->iteratorkey++;
// read next chunk if we're reading from a file // read next chunk if we're reading from a file
if (!$this->objects[$this->iteratorkey] && $this->fp) { if (empty($this->objects[$this->iteratorkey]) && $this->fp) {
$this->_parse_next(true); $this->_parse_next(true);
} }

View file

@ -21,7 +21,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
class libcalendaring_test extends PHPUnit_Framework_TestCase class libcalendaring_test extends PHPUnit\Framework\TestCase
{ {
function setUp() function setUp()
{ {

View file

@ -21,7 +21,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
class libvcalendar_test extends PHPUnit_Framework_TestCase class libvcalendar_test extends PHPUnit\Framework\TestCase
{ {
function setUp() function setUp()
{ {
@ -209,7 +209,7 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
$this->assertEquals('-PT30M', $alarm[3], "Unified alarm string (stripped zero-values)"); $this->assertEquals('-PT30M', $alarm[3], "Unified alarm string (stripped zero-values)");
$this->assertEquals('DISPLAY', $event['valarms'][0]['action'], "First alarm action"); $this->assertEquals('DISPLAY', $event['valarms'][0]['action'], "First alarm action");
$this->assertEquals('', $event['valarms'][0]['related'], "First alarm related property"); $this->assertTrue(empty($event['valarms'][0]['related']), "First alarm related property");
$this->assertEquals('This is the first event reminder', $event['valarms'][0]['description'], "First alarm text"); $this->assertEquals('This is the first event reminder', $event['valarms'][0]['description'], "First alarm text");
$this->assertEquals(3, count($event['valarms']), "List all VALARM blocks"); $this->assertEquals(3, count($event['valarms']), "List all VALARM blocks");
@ -553,7 +553,7 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
$this->assertEquals('4', $vtz->{'X-MICROSOFT-CDO-TZID'}); $this->assertEquals('4', $vtz->{'X-MICROSOFT-CDO-TZID'});
// check for transition to daylight saving time which is BEFORE the given date // check for transition to daylight saving time which is BEFORE the given date
$dst = reset($vtz->select('DAYLIGHT')); $dst = array_first($vtz->select('DAYLIGHT'));
$this->assertEquals('DAYLIGHT', $dst->name); $this->assertEquals('DAYLIGHT', $dst->name);
$this->assertEquals('20140330T010000', $dst->DTSTART); $this->assertEquals('20140330T010000', $dst->DTSTART);
$this->assertEquals('+0100', $dst->TZOFFSETFROM); $this->assertEquals('+0100', $dst->TZOFFSETFROM);
@ -561,7 +561,8 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
$this->assertEquals('CEST', $dst->TZNAME); $this->assertEquals('CEST', $dst->TZNAME);
// check (last) transition to standard time which is AFTER the given date // check (last) transition to standard time which is AFTER the given date
$std = end($vtz->select('STANDARD')); $std = $vtz->select('STANDARD');
$std = end($std);
$this->assertEquals('STANDARD', $std->name); $this->assertEquals('STANDARD', $std->name);
$this->assertEquals('20141026T010000', $std->DTSTART); $this->assertEquals('20141026T010000', $std->DTSTART);
$this->assertEquals('+0200', $std->TZOFFSETFROM); $this->assertEquals('+0200', $std->TZOFFSETFROM);

View file

@ -60,7 +60,7 @@ class libkolab extends rcube_plugin
$this->add_texts('localization/', false); $this->add_texts('localization/', false);
if ($rcmail->output->type == 'html') { if (!empty($rcmail->output->type) && $rcmail->output->type == 'html') {
$rcmail->output->add_handler('libkolab.folder_search_form', array($this, 'folder_search_form')); $rcmail->output->add_handler('libkolab.folder_search_form', array($this, 'folder_search_form'));
$this->include_stylesheet($this->local_skin_path() . '/libkolab.css'); $this->include_stylesheet($this->local_skin_path() . '/libkolab.css');
} }

View file

@ -21,7 +21,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
class kolab_date_recurrence_test extends PHPUnit_Framework_TestCase class kolab_date_recurrence_test extends PHPUnit\Framework\TestCase
{ {
function setUp() function setUp()
{ {

View file

@ -1,6 +1,6 @@
<?php <?php
class kolab_storage_config_test extends PHPUnit_Framework_TestCase class kolab_storage_config_test extends PHPUnit\Framework\TestCase
{ {
private $params_personal = array( private $params_personal = array(
'folder' => 'Archive', 'folder' => 'Archive',

View file

@ -21,7 +21,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
class kolab_storage_folder_test extends PHPUnit_Framework_TestCase class kolab_storage_folder_test extends PHPUnit\Framework\TestCase
{ {
public static function setUpBeforeClass() public static function setUpBeforeClass()
{ {