- Support exceptions and iTip messages with thisansfuture range
- Store two exceptions for the same occurence if necessary (with differing range) - Update attendee status from iTip REPLY to all exceptions stored for the event - Correctly handle exceptions on the first instance (main event)
This commit is contained in:
parent
7fd2eb873d
commit
8a90069071
6 changed files with 239 additions and 61 deletions
|
@ -863,6 +863,7 @@ class calendar extends rcube_plugin
|
|||
$this->write_preprocess($event, $action);
|
||||
if ($success = $this->driver->new_event($event)) {
|
||||
$event['id'] = $event['uid'];
|
||||
$event['_savemode'] = 'all';
|
||||
$this->cleanup_event($event);
|
||||
}
|
||||
$reload = $success && $event['recurrence'] ? 2 : 1;
|
||||
|
@ -1017,11 +1018,18 @@ class calendar extends rcube_plugin
|
|||
$itip = $this->load_itip();
|
||||
$itip->set_sender_email($reply_sender);
|
||||
$event['comment'] = $reply_comment;
|
||||
$event['thisandfuture'] = $event['_savemode'] == 'future';
|
||||
if ($organizer && $itip->send_itip_message($event, 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status))
|
||||
$this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation');
|
||||
else
|
||||
$this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error');
|
||||
}
|
||||
|
||||
// refresh all calendars
|
||||
if ($event['calendar'] != $ev['calendar']) {
|
||||
$this->rc->output->command('plugin.refresh_calendar', array('source' => null, 'refetch' => true));
|
||||
$reload = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1139,11 +1147,13 @@ class calendar extends rcube_plugin
|
|||
|
||||
// make sure we have the complete record
|
||||
$event = $action == 'remove' ? $old : $this->driver->get_event($event);
|
||||
$event['_savemode'] = $_savemode;
|
||||
|
||||
// send notification for the main event when savemode is 'all'
|
||||
if ($_savemode == 'all' && $event['recurrence_id']) {
|
||||
$event['id'] = $event['recurrence_id'];
|
||||
$event = $this->driver->get_event($event);
|
||||
unset($event['_instance'], $event['recurrence_date']);
|
||||
}
|
||||
|
||||
// only notify if data really changed (TODO: do diff check on client already)
|
||||
|
@ -2763,9 +2773,11 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
}
|
||||
$event_attendee = null;
|
||||
$update_attendees = array();
|
||||
foreach ($event['attendees'] as $attendee) {
|
||||
if ($event['_sender'] && ($attendee['email'] == $event['_sender'] || $attendee['email'] == $event['_sender_utf'])) {
|
||||
$event_attendee = $attendee;
|
||||
$update_attendees[] = $attendee;
|
||||
$metadata['fallback'] = $attendee['status'];
|
||||
$metadata['attendee'] = $attendee['email'];
|
||||
$metadata['rsvp'] = $attendee['rsvp'] || $attendee['role'] != 'NON-PARTICIPANT';
|
||||
|
@ -2775,9 +2787,12 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
// also copy delegate attendee
|
||||
else if (!empty($attendee['delegated-from']) &&
|
||||
(stripos($attendee['delegated-from'], $event['_sender']) !== false || stripos($attendee['delegated-from'], $event['_sender_utf']) !== false) &&
|
||||
(!in_array($attendee['email'], $existing_attendee_emails))) {
|
||||
$existing['attendees'][] = $attendee;
|
||||
(stripos($attendee['delegated-from'], $event['_sender']) !== false ||
|
||||
stripos($attendee['delegated-from'], $event['_sender_utf']) !== false)) {
|
||||
$update_attendees[] = $attendee;
|
||||
if (!in_array($attendee['email'], $existing_attendee_emails)) {
|
||||
$existing['attendees'][] = $attendee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2794,12 +2809,12 @@ class calendar extends rcube_plugin
|
|||
// found matching attendee entry in both existing and new events
|
||||
if ($existing_attendee >= 0 && $event_attendee) {
|
||||
$existing['attendees'][$existing_attendee] = $event_attendee;
|
||||
$success = $this->driver->edit_event($existing);
|
||||
$success = $this->driver->update_attendees($existing, $update_attendees);
|
||||
}
|
||||
// update the entire attendees block
|
||||
else if (($event['sequence'] >= $existing['sequence'] || $event['changed'] >= $existing['changed']) && $event_attendee) {
|
||||
$existing['attendees'][] = $event_attendee;
|
||||
$success = $this->driver->edit_event($existing);
|
||||
$success = $this->driver->update_attendees($existing, $update_attendees);
|
||||
}
|
||||
else {
|
||||
$error_msg = $this->gettext('newerversionexists');
|
||||
|
@ -2855,7 +2870,7 @@ class calendar extends rcube_plugin
|
|||
|
||||
// if the RSVP reply only refers to a single instance:
|
||||
// store unmodified master event with current instance as exception
|
||||
if (!empty($instance) && $savemode != 'all') {
|
||||
if (!empty($instance) && !empty($savemode) && $savemode != 'all') {
|
||||
$master = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event');
|
||||
if ($master['recurrence'] && !$master['_instance']) {
|
||||
// compute recurring events until this instance's date
|
||||
|
|
|
@ -204,6 +204,18 @@ abstract class calendar_driver
|
|||
return $this->edit_event($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the participant status for the given attendee
|
||||
*
|
||||
* @param array Hash array with event properties
|
||||
* @param array List of hash arrays each represeting an updated attendee
|
||||
* @return boolean True on success, False on error
|
||||
*/
|
||||
public function update_attendees(&$event, $attendees)
|
||||
{
|
||||
return $this->edit_event($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a single event
|
||||
*
|
||||
|
|
|
@ -195,7 +195,11 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
if ($master_id != $id && ($record = $this->storage->get_object($master_id)))
|
||||
$this->events[$master_id] = $this->_to_rcube_event($record);
|
||||
|
||||
if (($master = $this->events[$master_id]) && $master['recurrence']) {
|
||||
// check for match on the first instance already
|
||||
if (($_instance = $this->events[$master_id]['_instance']) && $id == $master_id . '-' . $_instance) {
|
||||
$this->events[$id] = $this->events[$master_id];
|
||||
}
|
||||
else if (($master = $this->events[$master_id]) && $master['recurrence']) {
|
||||
$this->get_recurring_events($record, $master['start'], null, $id);
|
||||
}
|
||||
}
|
||||
|
@ -274,17 +278,10 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
$add = true;
|
||||
|
||||
// skip the first instance of a recurring event if listed in exdate
|
||||
if ($virtual && (!empty($event['recurrence']['EXDATE']) || !empty($event['recurrence']['EXCEPTIONS']))) {
|
||||
if ($virtual && !empty($event['recurrence']['EXDATE'])) {
|
||||
$event_date = $event['start']->format('Ymd');
|
||||
$exdates = (array)$event['recurrence']['EXDATE'];
|
||||
|
||||
// add dates from exceptions to list
|
||||
if (is_array($event['recurrence']['EXCEPTIONS'])) {
|
||||
foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
|
||||
$exdates[] = clone $exception['start'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($exdates as $exdate) {
|
||||
if ($exdate->format('Ymd') == $event_date) {
|
||||
$add = false;
|
||||
|
@ -293,6 +290,18 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
}
|
||||
}
|
||||
|
||||
// find and merge exception for the first instance
|
||||
if (!empty($event['recurrence']) && is_array($event['recurrence']['EXCEPTIONS'])) {
|
||||
$event_date = $event['start']->format('Ymd');
|
||||
foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
|
||||
$exdate = $exception['recurrence_date'] ? $exception['recurrence_date']->format('Ymd') : substr($exception['_instance'], 0, 8);
|
||||
if ($exdate == $event_date) {
|
||||
$event['_instance'] = $exception['_instance'];
|
||||
kolab_driver::merge_event_data($event, $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($add)
|
||||
$events[] = $event;
|
||||
}
|
||||
|
@ -583,24 +592,29 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
$rec_event['id'] = $event['uid'] . '-' . $exception['_instance'];
|
||||
$rec_event['isexception'] = 1;
|
||||
|
||||
// found the specifically requested instance, exiting...
|
||||
if ($rec_event['id'] == $event_id) {
|
||||
// found the specifically requested instance: register exception (single occurrence wins)
|
||||
if ($rec_event['id'] == $event_id && (!$this->events[$event_id] || $this->events[$event_id]['thisandfuture'])) {
|
||||
$rec_event['recurrence'] = $recurrence_rule;
|
||||
$rec_event['recurrence_id'] = $event['uid'];
|
||||
$events[] = $rec_event;
|
||||
$this->events[$rec_event['id']] = $rec_event;
|
||||
return $events;
|
||||
}
|
||||
|
||||
// remember this exception's date
|
||||
$exdate = substr($exception['_instance'], 0, 8);
|
||||
$exdata[$exdate] = $rec_event;
|
||||
if (!$exdata[$exdate] || $exdata[$exdate]['thisandfuture']) {
|
||||
$exdata[$exdate] = $rec_event;
|
||||
}
|
||||
if ($rec_event['thisandfuture']) {
|
||||
$futuredata[$exdate] = $rec_event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// found the specifically requested instance, exiting...
|
||||
if ($event_id && !empty($this->events[$event_id])) {
|
||||
return array($this->events[$event_id]);
|
||||
}
|
||||
|
||||
// use libkolab to compute recurring events
|
||||
if (class_exists('kolabcalendaring')) {
|
||||
$recurrence = new kolab_date_recurrence($object);
|
||||
|
@ -627,7 +641,7 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
$rec_event['_instance'] = $instance_id;
|
||||
|
||||
if ($overlay_data || $exdata[$datestr]) // copy data from exception
|
||||
$this->_merge_event_data($rec_event, $exdata[$datestr] ?: $overlay_data);
|
||||
kolab_driver::merge_event_data($rec_event, $exdata[$datestr] ?: $overlay_data);
|
||||
|
||||
$rec_event['id'] = $rec_id;
|
||||
$rec_event['recurrence_id'] = $event['uid'];
|
||||
|
@ -651,38 +665,11 @@ class kolab_calendar extends kolab_storage_folder_api
|
|||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge certain properties from the overlay event to the base event object
|
||||
*
|
||||
* @param array The event object to be altered
|
||||
* @param array The overlay event object to be merged over $event
|
||||
*/
|
||||
private function _merge_event_data(&$event, $overlay)
|
||||
{
|
||||
static $forbidden = array('id','uid','recurrence','recurrence_date','organizer','_attachments');
|
||||
|
||||
foreach ($overlay as $prop => $value) {
|
||||
// adjust time of the recurring event instance
|
||||
if ($prop == 'start' || $prop == 'end') {
|
||||
if (is_object($event[$prop]) && is_a($event[$prop], 'DateTime')) {
|
||||
$event[$prop]->setTime($value->format('G'), intval($value->format('i')), intval($value->format('s')));
|
||||
// set date value if overlay is an exception of the current instance
|
||||
if (substr($overlay['_instance'], 0, 8) == substr($event['_instance'], 0, 8)) {
|
||||
$event[$prop]->setDate(intval($value->format('Y')), intval($value->format('n')), intval($value->format('j')));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($prop[0] != '_' && !in_array($prop, $forbidden))
|
||||
$event[$prop] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from Kolab_Format to internal representation
|
||||
*/
|
||||
private function _to_rcube_event($record)
|
||||
{
|
||||
$record['id'] = $record['uid'];
|
||||
$record['calendar'] = $this->id;
|
||||
$record['links'] = $this->get_links($record['uid']);
|
||||
|
||||
|
|
|
@ -537,7 +537,7 @@ class kolab_driver extends calendar_driver
|
|||
$id = $event['id'] ?: $event['uid'];
|
||||
$cal = $event['calendar'];
|
||||
|
||||
// we're looking for a recurring instance: expand the ID to our internal convention for recurring instanced
|
||||
// we're looking for a recurring instance: expand the ID to our internal convention for recurring instances
|
||||
if (!$event['id'] && $event['_instance']) {
|
||||
$id .= '-' . $event['_instance'];
|
||||
}
|
||||
|
@ -634,6 +634,48 @@ class kolab_driver extends calendar_driver
|
|||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the participant status for the given attendees
|
||||
*
|
||||
* @see calendar_driver::update_attendees()
|
||||
*/
|
||||
public function update_attendees(&$event, $attendees)
|
||||
{
|
||||
// for this-and-future updates, merge the updated attendees onto all exceptions in range
|
||||
if (($event['_savemode'] == 'future' && $event['recurrence_id']) || !empty($event['recurrence'])) {
|
||||
if (!($storage = $this->get_calendar($event['calendar'])))
|
||||
return false;
|
||||
|
||||
// load master event
|
||||
$master = $event['recurrence_id'] ? $storage->get_event($event['recurrence_id']) : $event;
|
||||
|
||||
// apply attendee update to each existing exception
|
||||
if ($master['recurrence'] && !empty($master['recurrence']['EXCEPTIONS'])) {
|
||||
$saved = false;
|
||||
foreach ($master['recurrence']['EXCEPTIONS'] as $i => $exception) {
|
||||
// merge the new event properties onto future exceptions
|
||||
if ($exception['_instance'] >= $event['_instance']) {
|
||||
self::merge_attendee_data($master['recurrence']['EXCEPTIONS'][$i], $attendees);
|
||||
}
|
||||
// update a specific instance
|
||||
if ($exception['_instance'] == $event['_instance'] && $exception['thisandfuture']) {
|
||||
$saved = true;
|
||||
}
|
||||
}
|
||||
|
||||
// add the given event as new exception
|
||||
if (!$saved && $event['id'] != $master['id']) {
|
||||
$event['thisandfuture'] = true;
|
||||
$master['recurrence']['EXCEPTIONS'][] = $event;
|
||||
}
|
||||
|
||||
return $this->update_event($master);
|
||||
}
|
||||
}
|
||||
|
||||
// just update the given event (instance)
|
||||
return $this->update_event($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move a single event
|
||||
|
@ -933,15 +975,10 @@ class kolab_driver extends calendar_driver
|
|||
}
|
||||
|
||||
// save properties to a recurrence exception instance
|
||||
if ($old['recurrence_id'] && is_array($master['recurrence']['EXCEPTIONS'])) {
|
||||
foreach ($master['recurrence']['EXCEPTIONS'] as $i => $exception) {
|
||||
if ($exception['_instance'] == $old['_instance']) {
|
||||
$event['_instance'] = $old['_instance'];
|
||||
$event['recurrence_date'] = $old['recurrence_date'];
|
||||
$master['recurrence']['EXCEPTIONS'][$i] = $event;
|
||||
$success = $storage->update_event($master, $old['id']);
|
||||
break 2;
|
||||
}
|
||||
if ($old['_instance'] && is_array($master['recurrence']['EXCEPTIONS'])) {
|
||||
if ($this->update_recurrence_exceptions($master, $event, $old, $savemode)) {
|
||||
$success = $storage->update_event($master, $old['id']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -962,7 +999,7 @@ class kolab_driver extends calendar_driver
|
|||
// save as new exception to master event
|
||||
if ($add_exception) {
|
||||
$event['_instance'] = $old['_instance'];
|
||||
$event['recurrence_date'] = $old['recurrence_date'];
|
||||
$event['recurrence_date'] = $old['recurrence_date'] ?: $old['start'];
|
||||
$master['recurrence']['EXCEPTIONS'][] = $event;
|
||||
}
|
||||
$success = $storage->update_event($master);
|
||||
|
@ -1004,6 +1041,8 @@ class kolab_driver extends calendar_driver
|
|||
$event['end'] = $master['end'];
|
||||
}
|
||||
|
||||
// TODO: forward changes to exceptions (which do not yet have differing values stored)
|
||||
|
||||
// adjust recurrence-id when start changed and therefore the entire recurrence chain changes
|
||||
if (($old_start_date != $new_start_date || $old_start_time != $new_start_time) &&
|
||||
is_array($event['recurrence']) && is_array($event['recurrence']['EXCEPTIONS']) && !$with_exceptions) {
|
||||
|
@ -1070,6 +1109,120 @@ class kolab_driver extends calendar_driver
|
|||
return $reschedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given changes to already existing exceptions
|
||||
*/
|
||||
protected function update_recurrence_exceptions(&$master, $event, $old, $savemode)
|
||||
{
|
||||
$saved = false;
|
||||
$existing = null;
|
||||
|
||||
foreach ($master['recurrence']['EXCEPTIONS'] as $i => $exception) {
|
||||
// update a specific instance
|
||||
if ($exception['_instance'] == $old['_instance']) {
|
||||
$existing = $i;
|
||||
|
||||
// check savemode against existing exception mode.
|
||||
// if matches, we can update this existing exception
|
||||
if ((bool)$exception['thisandfuture'] === ($savemode == 'future')) {
|
||||
$event['_instance'] = $old['_instance'];
|
||||
$event['thisandfuture'] = $old['thisandfuture'];
|
||||
$event['recurrence_date'] = $old['recurrence_date'];
|
||||
$master['recurrence']['EXCEPTIONS'][$i] = $event;
|
||||
$saved = true;
|
||||
}
|
||||
}
|
||||
// merge the new event properties onto future exceptions
|
||||
if ($savemode == 'future' && $exception['_instance'] >= $old['_instance']) {
|
||||
unset($event['thisandfuture']);
|
||||
self::merge_event_data($master['recurrence']['EXCEPTIONS'][$i], $event);
|
||||
}
|
||||
}
|
||||
/*
|
||||
// we could not update the existing exception due to savemode mismatch...
|
||||
if (!$saved && $existing !== null && $master['recurrence']['EXCEPTIONS'][$existing]['thisandfuture']) {
|
||||
// ... try to move the existing this-and-future exception to the next occurrence
|
||||
foreach ($this->get_recurring_events($master, $existing['start']) as $candidate) {
|
||||
// our old this-and-future exception is obsolete
|
||||
if ($candidate['thisandfuture']) {
|
||||
unset($master['recurrence']['EXCEPTIONS'][$existing]);
|
||||
$saved = true;
|
||||
break;
|
||||
}
|
||||
// this occurrence doesn't yet have an exception
|
||||
else if (!$candidate['isexception']) {
|
||||
$event['_instance'] = $candidate['_instance'];
|
||||
$event['recurrence_date'] = $candidate['recurrence_date'];
|
||||
$master['recurrence']['EXCEPTIONS'][$i] = $event;
|
||||
$saved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// returning false here will add a new exception
|
||||
return $saved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge certain properties from the overlay event to the base event object
|
||||
*
|
||||
* @param array The event object to be altered
|
||||
* @param array The overlay event object to be merged over $event
|
||||
*/
|
||||
public static function merge_event_data(&$event, $overlay)
|
||||
{
|
||||
static $forbidden = array('id','uid','recurrence','recurrence_date','thisandfuture','organizer','_attachments');
|
||||
|
||||
foreach ($overlay as $prop => $value) {
|
||||
// adjust time of the recurring event instance
|
||||
if ($prop == 'start' || $prop == 'end') {
|
||||
if (is_object($event[$prop]) && is_a($event[$prop], 'DateTime')) {
|
||||
$event[$prop]->setTime($value->format('G'), intval($value->format('i')), intval($value->format('s')));
|
||||
// set date value if overlay is an exception of the current instance
|
||||
if (substr($overlay['_instance'], 0, 8) == substr($event['_instance'], 0, 8)) {
|
||||
$event[$prop]->setDate(intval($value->format('Y')), intval($value->format('n')), intval($value->format('j')));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($prop == 'thisandfuture' && $overlay['_instance'] == $event['_instance']) {
|
||||
$event[$prop] = $value;
|
||||
}
|
||||
else if ($prop[0] != '_' && !in_array($prop, $forbidden))
|
||||
$event[$prop] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update attendee properties on the given event object
|
||||
*
|
||||
* @param array The event object to be altered
|
||||
* @param array List of hash arrays each represeting an updated/added attendee
|
||||
*/
|
||||
public static function merge_attendee_data(&$event, $attendees)
|
||||
{
|
||||
if (!empty($attendees) && !is_array($attendees[0])) {
|
||||
$attendees = array($attendees);
|
||||
}
|
||||
|
||||
foreach ($attendees as $attendee) {
|
||||
$found = false;
|
||||
|
||||
foreach ($event['attendees'] as $i => $candidate) {
|
||||
if ($candidate['email'] == $attendee['email']) {
|
||||
$event['attendees'][$i] = $attendee;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
$event['attendees'][] = $attendee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get events from source.
|
||||
*
|
||||
|
@ -1520,6 +1673,13 @@ class kolab_driver extends calendar_driver
|
|||
if (empty($record['recurrence']))
|
||||
unset($record['recurrence']);
|
||||
|
||||
// add instance identifier to first occurrence (master event)
|
||||
if ($record['recurrence'] && !$record['recurrence_id'] && !$record['_instance']) {
|
||||
$recurrence_id_format = $event['allday'] ? 'Ymd' : 'Ymd\THis';
|
||||
$record['recurrence_date'] = $record['start'];
|
||||
$record['_instance'] = $record['recurrence_date']->format($recurrence_id_format);
|
||||
}
|
||||
|
||||
// remove internals
|
||||
unset($record['_mailbox'], $record['_msguid'], $record['_formatobj'], $record['_attachments'], $record['x-custom']);
|
||||
|
||||
|
|
|
@ -1410,8 +1410,12 @@ class libcalendaring extends rcube_plugin
|
|||
*/
|
||||
public static function identify_recurrence_instance(&$object)
|
||||
{
|
||||
// for savemode=all, remove recurrence instance identifiers
|
||||
if (!empty($object['_savemode']) && $object['_savemode'] == 'all') {
|
||||
unset($object['_instance'], $object['recurrence_date']);
|
||||
}
|
||||
// set instance and 'savemode' according to recurrence-id
|
||||
if (!empty($object['recurrence_date']) && is_a($object['recurrence_date'], 'DateTime')) {
|
||||
else if (!empty($object['recurrence_date']) && is_a($object['recurrence_date'], 'DateTime')) {
|
||||
$recurrence_id_format = $object['allday'] ? 'Ymd' : 'Ymd\THis';
|
||||
$object['_instance'] = $object['recurrence_date']->format($recurrence_id_format);
|
||||
$object['_savemode'] = $object['thisandfuture'] ? 'future' : 'current';
|
||||
|
|
|
@ -109,7 +109,7 @@ $labels['acceptattendee'] = 'Accept participant';
|
|||
$labels['declineattendee'] = 'Decline participant';
|
||||
$labels['declineattendeeconfirm'] = 'Enter a message to the declined participant (optional):';
|
||||
$labels['rsvpmodeall'] = 'The entire series';
|
||||
$labels['rsvpmodecurrent'] = 'This occurrence';
|
||||
$labels['rsvpmodecurrent'] = 'This occurrence only';
|
||||
$labels['rsvpmodefuture'] = 'This and future occurrences';
|
||||
|
||||
$labels['itipsingleoccurrence'] = 'This is a <em>single occurrence</em> out of a series of events';
|
||||
|
|
Loading…
Add table
Reference in a new issue