diff --git a/plugins/libcalendaring/libcalendaring.php b/plugins/libcalendaring/libcalendaring.php index 6a02b9e3..379bd945 100644 --- a/plugins/libcalendaring/libcalendaring.php +++ b/plugins/libcalendaring/libcalendaring.php @@ -610,33 +610,45 @@ class libcalendaring extends rcube_plugin */ 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; + } if ($type == 'task') { $timezone = self::get_instance()->timezone; - if ($rec['startdate']) - $rec['start'] = new DateTime($rec['startdate'] . ' ' . ($rec['starttime'] ?: '12:00'), $timezone); - if ($rec['date']) - $rec[($rec['start'] ? 'end' : 'start')] = new DateTime($rec['date'] . ' ' . ($rec['time'] ?: '12:00'), $timezone); + if (!empty($rec['startdate'])) { + $time = !empty($rec['starttime']) ? $rec['starttime'] : '12:00'; + $rec['start'] = new DateTime($rec['startdate'] . ' ' . $time, $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']; + } // support legacy format - if (!$rec['valarms']) { + if (empty($rec['valarms'])) { list($trigger, $action) = explode(':', $rec['alarms'], 2); if ($alarm = self::parse_alarm_value($trigger)) { $rec['valarms'] = array(array('action' => $action, 'trigger' => $alarm[3] ?: $alarm[0])); } } - $expires = new DateTime('now - 12 hours'); - $alarm_id = $rec['id']; // alarm ID eq. record ID by default to keep backwards compatibility + // 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'); + $notify_at = null; // handle multiple alarms - $notify_at = null; foreach ($rec['valarms'] as $alarm) { $notify_time = null; @@ -644,11 +656,12 @@ class libcalendaring extends rcube_plugin $notify_time = $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 - if (!is_a($refdate, 'DateTime')) + if (!is_a($refdate, 'DateTime')) { continue; + } // 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))) { $notify_at = $notify_time; - $action = $alarm['action']; + $action = isset($alarm['action']) ? $alarm['action'] : null; $alarm_prop = $alarm; // generate a unique alarm ID if multiple alarms are set 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( 'time' => $notify_at->format('U'), - 'action' => $action ? strtoupper($action) : 'DISPLAY', + 'action' => !empty($action) ? strtoupper($action) : 'DISPLAY', 'id' => $alarm_id, 'prop' => $alarm_prop, ); @@ -716,10 +730,12 @@ class libcalendaring extends rcube_plugin $data['ids'] = explode(',', $data['id']); $plugin = $this->rc->plugins->exec_hook('dismiss_alarms', $data); - if ($plugin['success']) + if (!empty($plugin['success'])) { $this->rc->output->show_message('successfullysaved', 'confirmation'); - else + } + else { $this->rc->output->show_message('calendar.errorsaving', 'error'); + } } /** @@ -731,9 +747,9 @@ class libcalendaring extends rcube_plugin foreach ($alarms as $alarm) { $out[] = array( 'id' => $alarm['id'], - 'start' => $alarm['start'] ? $this->adjust_timezone($alarm['start'])->format('c') : '', - 'end' => $alarm['end'] ? $this->adjust_timezone($alarm['end'])->format('c') : '', - 'allDay' => $alarm['allday'] == 1, + 'start' => !empty($alarm['start']) ? $this->adjust_timezone($alarm['start'])->format('c') : '', + 'end' => !empty($alarm['end'])? $this->adjust_timezone($alarm['end'])->format('c') : '', + 'allDay' => !empty($alarm['allday']), 'action' => $alarm['action'], 'title' => $alarm['title'], 'location' => $alarm['location'], @@ -1427,8 +1443,9 @@ class libcalendaring extends rcube_plugin */ public static function to_rrule($recurrence, $allday = false) { - if (is_string($recurrence)) + if (is_string($recurrence)) { return $recurrence; + } $rrule = ''; foreach ((array)$recurrence as $k => $val) { @@ -1437,7 +1454,7 @@ class libcalendaring extends rcube_plugin case 'UNTIL': // convert to UTC according to RFC 5545 if (is_a($val, 'DateTime')) { - if (!$allday && !$val->_dateonly) { + if (!$allday && empty($val->_dateonly)) { $until = clone $val; $until->setTimezone(new DateTimeZone('UTC')); $val = $until->format('Ymd\THis\Z'); @@ -1450,8 +1467,9 @@ class libcalendaring extends rcube_plugin case 'RDATE': case 'EXDATE': foreach ((array)$val as $i => $ex) { - if (is_a($ex, 'DateTime')) + if (is_a($ex, 'DateTime')) { $val[$i] = $ex->format('Ymd\THis'); + } } $val = join(',', (array)$val); break; @@ -1459,8 +1477,9 @@ class libcalendaring extends rcube_plugin continue 2; } - if (strlen($val)) + if (strlen($val)) { $rrule .= $k . '=' . $val . ';'; + } } return rtrim($rrule, ';'); diff --git a/plugins/libcalendaring/libvcalendar.php b/plugins/libcalendaring/libvcalendar.php index 164d1841..3dda65d4 100644 --- a/plugins/libcalendaring/libvcalendar.php +++ b/plugins/libcalendaring/libvcalendar.php @@ -326,10 +326,11 @@ class libvcalendar implements Iterator $object = $this->_to_array($ve); // temporarily store this as exception - if ($object['recurrence_date']) { + if (!empty($object['recurrence_date'])) { $exceptions[] = $object; } - else if (!$seen[$object['uid']]++) { + else if (empty($seen[$object['uid']])) { + $seen[$object['uid']] = true; $this->objects[] = $object; } } @@ -343,7 +344,8 @@ class libvcalendar implements Iterator $uid = $exception['uid']; // make this exception the master - if (!$seen[$uid]++) { + if (empty($seen[$uid])) { + $seen[$uid] = true; $this->objects[] = $exception; } else { @@ -412,7 +414,7 @@ class libvcalendar implements Iterator // We can skip these fields, they aren't critical foreach (array('CREATED' => 'created', 'LAST-MODIFIED' => 'changed', 'DTSTAMP' => 'changed') as $attr => $field) { try { - if (!$event[$field] && $ve->{$attr}) { + if (empty($event[$field]) && !empty($ve->{$attr})) { $event[$field] = $ve->{$attr}->getDateTime(); } } catch (Exception $e) {} @@ -461,15 +463,17 @@ class libvcalendar implements Iterator break; 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 foreach ($prop->getParts() as $k => $v) { $params[strtoupper($k)] = is_array($v) ? implode(',', $v) : $v; } - if ($params['UNTIL']) + if (!empty($params['UNTIL'])) { $params['UNTIL'] = date_create($params['UNTIL']); - if (!$params['INTERVAL']) + } + if (empty($params['INTERVAL'])) { $params['INTERVAL'] = 1; + } $event['recurrence'] = array_filter($params); break; @@ -477,14 +481,24 @@ class libvcalendar implements Iterator case 'EXDATE': if (!empty($value)) { $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; case 'RDATE': if (!empty($value)) { $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; @@ -519,7 +533,12 @@ class libvcalendar implements Iterator case 'CATEGORY': case 'CATEGORIES': - $event['categories'] = array_merge((array)$event['categories'], $prop->getParts()); + if (!empty($event['categories'])) { + $event['categories'] = array_merge((array) $event['categories'], $prop->getParts()); + } + else { + $event['categories'] = $prop->getParts(); + } break; case 'CLASS': @@ -528,10 +547,12 @@ class libvcalendar implements Iterator break; case 'X-MICROSOFT-CDO-BUSYSTATUS': - if ($value == 'OOF') + if ($value == 'OOF') { $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); + } break; case 'ATTENDEE': @@ -596,12 +617,7 @@ class libvcalendar implements Iterator // validate event dates if ($event['_type'] == 'event') { - $event['allday'] = false; - - // check for all-day dates - if ($event['start']->_dateonly) { - $event['allday'] = true; - } + $event['allday'] = !empty($event['start']->_dateonly); // events may lack the DTEND property, set it to DTSTART (RFC5545 3.6.1) if (empty($event['end'])) { @@ -647,11 +663,12 @@ class libvcalendar implements Iterator $trigger = $values[2]; } - if (!$alarm['trigger']) { + if (empty($alarm['trigger'])) { $alarm['trigger'] = rtrim(preg_replace('/([A-Z])0[WDHMS]/', '\\1', $value), 'T'); // if all 0-values have been stripped, assume 'at time' - if ($alarm['trigger'] == 'P') + if ($alarm['trigger'] == 'P') { $alarm['trigger'] = 'PT0S'; + } } break; @@ -684,23 +701,26 @@ class libvcalendar implements Iterator } 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; + } - if ($alarm['trigger']) + if (!empty($alarm['trigger'])) { $event['valarms'][] = $alarm; + } } } // 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']); } else { unset($event['start']); } - if ($event['end'] instanceof DateTime) { + if (!empty($event['end']) && $event['end'] instanceof DateTime) { $this->_apply_timezone($event['end']); } else { @@ -708,7 +728,7 @@ class libvcalendar implements Iterator } // 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']; } @@ -767,7 +787,13 @@ class libvcalendar implements Iterator case 'DTSTAMP': case 'DTSTART': 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); break; @@ -781,8 +807,11 @@ class libvcalendar implements Iterator $fbtype = strval($prop['FBTYPE']) ?: 'BUSY'; // skip dupes - if ($seen[$value.':'.$fbtype]++) + if (!empty($seen[$value.':'.$fbtype])) { break; + } + + $seen[$value.':'.$fbtype] = true; foreach ($periods as $period) { // Every period is formatted as [start]/[end]. The start is an @@ -905,7 +934,7 @@ class libvcalendar implements Iterator else { $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'); if ($is_dateonly) { @@ -918,7 +947,7 @@ class libvcalendar implements Iterator // register timezone for VTIMEZONE block if (!$is_utc && !$dateonly && $tz && ($tzname = $tz->getName())) { $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][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) { - $type = $event['_type'] ?: 'event'; + $type = !empty($event['_type']) ? $event['_type'] : 'event'; $cal = $vcal ?: new VObject\Component\VCalendar(); $ve = $cal->create($this->type_component_map[$type]); @@ -1036,27 +1065,33 @@ class libvcalendar implements Iterator $ve->DTSTAMP = $this->datetime_prop($cal, 'DTSTAMP', $dtstamp, true); // 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']->add(new \DateInterval('P1D')); $event['end']->_dateonly = true; } - if (!empty($event['created'])) + if (!empty($event['created'])) { $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)); - if (!empty($event['start'])) - $ve->add($this->datetime_prop($cal, 'DTSTART', $event['start'], false, (bool)$event['allday'])); - if (!empty($event['end'])) - $ve->add($this->datetime_prop($cal, 'DTEND', $event['end'], false, (bool)$event['allday'])); - if (!empty($event['due'])) - $ve->add($this->datetime_prop($cal, 'DUE', $event['due'], false)); + } + if (!empty($event['start'])) { + $ve->add($this->datetime_prop($cal, 'DTSTART', $event['start'], false, !empty($event['allday']))); + } + 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)); + } // we're exporting a recurrence instance only - if (!$recurrence_id && $event['recurrence_date'] && $event['recurrence_date'] instanceof DateTime) { - $recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $event['recurrence_date'], false, (bool)$event['allday']); - if ($event['thisandfuture']) + if (!$recurrence_id && !empty($event['recurrence_date']) && $event['recurrence_date'] instanceof DateTime) { + $recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $event['recurrence_date'], false, !empty($event['allday'])); + if (!empty($event['thisandfuture'])) { $recurrence_id->add('RANGE', 'THISANDFUTURE'); + } } if ($recurrence_id) { @@ -1065,15 +1100,18 @@ class libvcalendar implements Iterator $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'])); - if ($event['description']) + } + if (!empty($event['description'])) { $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']); + } - if ($event['recurrence'] && !$recurrence_id) { + if (!empty($event['recurrence']) && !$recurrence_id) { $exdates = $rdates = null; if (isset($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 } - if ($event['recurrence']['FREQ']) { - $ve->add('RRULE', libcalendaring::to_rrule($event['recurrence'], (bool)$event['allday'])); + if (!empty($event['recurrence']['FREQ'])) { + $ve->add('RRULE', libcalendaring::to_rrule($event['recurrence'], !empty($event['allday']))); } // 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->setParts((array)$event['categories']); $ve->add($cat); @@ -1119,17 +1157,22 @@ class libvcalendar implements Iterator } } - if ($event['priority']) - $ve->add('PRIORITY', $event['priority']); + if (!empty($event['priority'])) { + $ve->add('PRIORITY', $event['priority']); + } - if ($event['cancelled']) + if (!empty($event['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'); - else if ($event['complete'] == 100) + } + else if (!empty($event['complete']) && $event['complete'] == 100) { $ve->add('STATUS', 'COMPLETED'); - else if (!empty($event['status'])) + } + else if (!empty($event['status'])) { $ve->add('STATUS', $event['status']); + } if (!empty($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 - if ($event['status'] == 'COMPLETED' || $event['complete'] == 100) { - $ve->add($this->datetime_prop($cal, 'COMPLETED', $event['changed'] ?: new DateTime('now - 1 hour'), true)); + if ( + (!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) { $va = $cal->createComponent('VALARM'); $va->action = $alarm['action']; @@ -1152,85 +1199,96 @@ class libvcalendar implements Iterator } else { $alarm_props = array(); - if (strtoupper($alarm['related']) == 'END') { + if (!empty($alarm['related']) && strtoupper($alarm['related']) == 'END') { $alarm_props['RELATED'] = 'END'; } $va->add('TRIGGER', $alarm['trigger'], $alarm_props); } - if ($alarm['action'] == 'EMAIL') { - foreach ((array)$alarm['attendees'] as $attendee) { - $va->add('ATTENDEE', 'mailto:' . $attendee); + if (!empty($alarm['action']) && $alarm['action'] == 'EMAIL') { + if (!empty($alarm['attendees'])) { + foreach ((array) $alarm['attendees'] as $attendee) { + $va->add('ATTENDEE', 'mailto:' . $attendee); + } } } - if ($alarm['description']) { - $va->add('DESCRIPTION', $alarm['description'] ?: $event['title']); + if (!empty($alarm['description'])) { + $va->add('DESCRIPTION', $alarm['description']); } - if ($alarm['summary']) { + if (!empty($alarm['summary'])) { $va->add('SUMMARY', $alarm['summary']); } - if ($alarm['duration']) { + if (!empty($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')); } $ve->add($va); } } // legacy support - else if ($event['alarms']) { + else if (!empty($event['alarms'])) { $va = $cal->createComponent('VALARM'); list($trigger, $va->action) = explode(':', $event['alarms']); $val = libcalendaring::parse_alarm_value($trigger); - if ($val[3]) + if (!empty($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)); + } $ve->add($va); } // Find SCHEDULE-AGENT - foreach ((array)$event['x-custom'] as $prop) { - if ($prop[0] === 'SCHEDULE-AGENT') { - $schedule_agent = $prop[1]; - } - } - - foreach ((array)$event['attendees'] as $attendee) { - if ($attendee['role'] == 'ORGANIZER') { - if (empty($event['organizer'])) - $event['organizer'] = $attendee; - } - else if (!empty($attendee['email'])) { - if (isset($attendee['rsvp'])) - $attendee['rsvp'] = $attendee['rsvp'] ? 'TRUE' : null; - - $mailto = $attendee['email']; - $attendee = array_filter(self::map_keys($attendee, $this->attendee_keymap)); - - if ($schedule_agent !== null && !isset($attendee['SCHEDULE-AGENT'])) { - $attendee['SCHEDULE-AGENT'] = $schedule_agent; + if (!empty($event['x-custom'])) { + foreach ((array) $event['x-custom'] as $prop) { + if ($prop[0] === 'SCHEDULE-AGENT') { + $schedule_agent = $prop[1]; } - - $ve->add('ATTENDEE', 'mailto:' . $mailto, $attendee); } } - if ($event['organizer']) { + if (!empty($event['attendees'])) { + foreach ((array) $event['attendees'] as $attendee) { + if ($attendee['role'] == 'ORGANIZER') { + if (empty($event['organizer'])) + $event['organizer'] = $attendee; + } + else if (!empty($attendee['email'])) { + if (isset($attendee['rsvp'])) { + $attendee['rsvp'] = $attendee['rsvp'] ? 'TRUE' : null; + } + + $mailto = $attendee['email']; + $attendee = array_filter(self::map_keys($attendee, $this->attendee_keymap)); + + if (isset($schedule_agent) && !isset($attendee['SCHEDULE-AGENT'])) { + $attendee['SCHEDULE-AGENT'] = $schedule_agent; + } + + $ve->add('ATTENDEE', 'mailto:' . $mailto, $attendee); + } + } + } + + if (!empty($event['organizer'])) { $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; } $ve->add('ORGANIZER', 'mailto:' . $event['organizer']['email'], $organizer); } - foreach ((array)$event['url'] as $url) { - if (!empty($url)) { - $ve->add('URL', $url); + if (!empty($event['url'])) { + foreach ((array) $event['url'] as $url) { + if (!empty($url)) { + $ve->add('URL', $url); + } } } @@ -1238,8 +1296,9 @@ class libvcalendar implements Iterator $ve->add('RELATED-TO', $event['parent_id'], array('RELTYPE' => 'PARENT')); } - if ($event['comment']) + if (!empty($event['comment'])) { $ve->add('COMMENT', $event['comment']); + } $memory_limit = parse_bytes(ini_get('memory_limit')); @@ -1273,13 +1332,17 @@ class libvcalendar implements Iterator } } - foreach ((array)$event['links'] as $uri) { - $ve->add('ATTACH', $uri); + if (!empty($event['links'])) { + foreach ((array) $event['links'] as $uri) { + $ve->add('ATTACH', $uri); + } } // add custom properties - foreach ((array)$event['x-custom'] as $prop) { - $ve->add($prop[0], $prop[1]); + if (!empty($event['x-custom'])) { + foreach ((array) $event['x-custom'] as $prop) { + $ve->add($prop[0], $prop[1]); + } } // append to vcalendar container @@ -1291,12 +1354,13 @@ class libvcalendar implements Iterator } // 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) { - $exdate = $ex['recurrence_date'] ?: $ex['start']; - $recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $exdate, false, (bool)$event['allday']); - if ($ex['thisandfuture']) + $exdate = !empty($ex['recurrence_date']) ? $ex['recurrence_date'] : $ex['start']; + $recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $exdate, false, !empty($event['allday'])); + if (!empty($ex['thisandfuture'])) { $recurrence_id->add('RANGE', 'THISANDFUTURE'); + } $this->_to_ical($ex, $vcal, $get_attachment, $recurrence_id); } } @@ -1334,7 +1398,7 @@ class libvcalendar implements Iterator $tz = $tzid; } - if (!is_a($tz, '\\DateTimeZone')) { + if (empty($tz) || !is_a($tz, '\\DateTimeZone')) { return false; } @@ -1424,7 +1488,7 @@ class libvcalendar implements Iterator $this->iteratorkey++; // 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); } diff --git a/plugins/libcalendaring/tests/libcalendaring.php b/plugins/libcalendaring/tests/libcalendaring.php index 311d25e2..e93e0b32 100644 --- a/plugins/libcalendaring/tests/libcalendaring.php +++ b/plugins/libcalendaring/tests/libcalendaring.php @@ -21,7 +21,7 @@ * along with this program. If not, see . */ -class libcalendaring_test extends PHPUnit_Framework_TestCase +class libcalendaring_test extends PHPUnit\Framework\TestCase { function setUp() { diff --git a/plugins/libcalendaring/tests/libvcalendar.php b/plugins/libcalendaring/tests/libvcalendar.php index 29f73520..5e2503ed 100644 --- a/plugins/libcalendaring/tests/libvcalendar.php +++ b/plugins/libcalendaring/tests/libvcalendar.php @@ -21,7 +21,7 @@ * along with this program. If not, see . */ -class libvcalendar_test extends PHPUnit_Framework_TestCase +class libvcalendar_test extends PHPUnit\Framework\TestCase { 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('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(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'}); // 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('20140330T010000', $dst->DTSTART); $this->assertEquals('+0100', $dst->TZOFFSETFROM); @@ -561,7 +561,8 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase $this->assertEquals('CEST', $dst->TZNAME); // 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('20141026T010000', $std->DTSTART); $this->assertEquals('+0200', $std->TZOFFSETFROM); diff --git a/plugins/libkolab/libkolab.php b/plugins/libkolab/libkolab.php index 8ad0838b..db120aa2 100644 --- a/plugins/libkolab/libkolab.php +++ b/plugins/libkolab/libkolab.php @@ -60,7 +60,7 @@ class libkolab extends rcube_plugin $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')); $this->include_stylesheet($this->local_skin_path() . '/libkolab.css'); } diff --git a/plugins/libkolab/tests/kolab_date_recurrence.php b/plugins/libkolab/tests/kolab_date_recurrence.php index ad0f3216..ed3e3bd3 100644 --- a/plugins/libkolab/tests/kolab_date_recurrence.php +++ b/plugins/libkolab/tests/kolab_date_recurrence.php @@ -21,7 +21,7 @@ * along with this program. If not, see . */ -class kolab_date_recurrence_test extends PHPUnit_Framework_TestCase +class kolab_date_recurrence_test extends PHPUnit\Framework\TestCase { function setUp() { diff --git a/plugins/libkolab/tests/kolab_storage_config.php b/plugins/libkolab/tests/kolab_storage_config.php index 50a894f2..d0c0ba3f 100644 --- a/plugins/libkolab/tests/kolab_storage_config.php +++ b/plugins/libkolab/tests/kolab_storage_config.php @@ -1,6 +1,6 @@ 'Archive', diff --git a/plugins/libkolab/tests/kolab_storage_folder.php b/plugins/libkolab/tests/kolab_storage_folder.php index 273ece26..c242b979 100644 --- a/plugins/libkolab/tests/kolab_storage_folder.php +++ b/plugins/libkolab/tests/kolab_storage_folder.php @@ -21,7 +21,7 @@ * along with this program. If not, see . */ -class kolab_storage_folder_test extends PHPUnit_Framework_TestCase +class kolab_storage_folder_test extends PHPUnit\Framework\TestCase { public static function setUpBeforeClass() {