diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index 19aa4bdb..e4c3b291 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -1652,11 +1652,11 @@ class calendar extends rcube_plugin
*/
private function notify_attendees($event, $old, $action = 'edit')
{
- if ($action == 'remove') {
+ if ($action == 'remove' || ($event['status'] == 'CANCELLED' && $old['status'] != $event['status'])) {
$event['cancelled'] = true;
$is_cancelled = true;
}
-
+
$itip = $this->load_itip();
$emails = $this->get_user_emails();
diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js
index e8678564..92a17653 100644
--- a/plugins/calendar/calendar_ui.js
+++ b/plugins/calendar/calendar_ui.js
@@ -325,6 +325,11 @@ function rcube_calendar_ui(settings)
$('#event-priority').show().children('.event-text').html(Q(event.priority+' '+priolabels[event.priority]));
}
+ if (event.status) {
+ var status_lc = String(event.status).toLowerCase();
+ $('#event-status').show().children('.event-text').html(Q(rcmail.gettext(status_lc,'calendar')));
+ $dialog.addClass('status-'+status_lc);
+ }
if (event.sensitivity && event.sensitivity != 'public') {
$('#event-sensitivity').show().children('.event-text').html(Q(sensitivitylabels[event.sensitivity]));
$dialog.addClass('sensitivity-'+event.sensitivity);
@@ -491,6 +496,7 @@ function rcube_calendar_ui(settings)
var vurl = $('#edit-url').val(event.vurl || '');
var categories = $('#edit-categories').val(event.categories);
var calendars = $('#edit-calendar').val(event.calendar);
+ var eventstatus = $('#edit-event-status').val(event.status);
var freebusy = $('#edit-free-busy').val(event.free_busy);
var priority = $('#edit-priority').val(event.priority);
var sensitivity = $('#edit-sensitivity').val(event.sensitivity);
@@ -682,6 +688,7 @@ function rcube_calendar_ui(settings)
free_busy: freebusy.val(),
priority: priority.val(),
sensitivity: sensitivity.val(),
+ status: eventstatus.val(),
recurrence: '',
alarms: '',
attendees: event_attendees,
@@ -2146,6 +2153,9 @@ function rcube_calendar_ui(settings)
if (event.alarms)
element.find('div.fc-event-time').append('');
}
+ if (event.status) {
+ element.addClass('cal-event-status-' + String(event.status).toLowerCase());
+ }
};
diff --git a/plugins/calendar/drivers/calendar_driver.php b/plugins/calendar/drivers/calendar_driver.php
index d883f18c..6769cfdc 100644
--- a/plugins/calendar/drivers/calendar_driver.php
+++ b/plugins/calendar/drivers/calendar_driver.php
@@ -52,6 +52,7 @@
* 'recurrence_id' => 'ID of the recurrence group', // usually the ID of the starting event
* 'categories' => 'Event category',
* 'free_busy' => 'free|busy|outofoffice|tentative', // Show time as
+ * 'status' => 'TENTATIVE|CONFIRMED|CANCELLED', // event status according to RFC 2445
* 'priority' => 0-9, // Event priority (0=undefined, 1=highest, 9=lowest)
* 'sensitivity' => 'public|private|confidential', // Event sensitivity
* 'alarms' => '-15M:DISPLAY', // DEPRECATED Reminder settings inspired by valarm definition (e.g. display alert 15 minutes before event)
diff --git a/plugins/calendar/drivers/database/SQL/mysql.initial.sql b/plugins/calendar/drivers/database/SQL/mysql.initial.sql
index 945d429b..c45b3f2a 100644
--- a/plugins/calendar/drivers/database/SQL/mysql.initial.sql
+++ b/plugins/calendar/drivers/database/SQL/mysql.initial.sql
@@ -44,6 +44,7 @@ CREATE TABLE IF NOT EXISTS `events` (
`free_busy` tinyint(1) NOT NULL DEFAULT '0',
`priority` tinyint(1) NOT NULL DEFAULT '0',
`sensitivity` tinyint(1) NOT NULL DEFAULT '0',
+ `status` varchar(32) NOT NULL DEFAULT '',
`alarms` varchar(255) DEFAULT NULL,
`attendees` text DEFAULT NULL,
`notifyat` datetime DEFAULT NULL,
diff --git a/plugins/calendar/drivers/database/SQL/mysql/2014040900.sql b/plugins/calendar/drivers/database/SQL/mysql/2014040900.sql
new file mode 100644
index 00000000..814e10d4
--- /dev/null
+++ b/plugins/calendar/drivers/database/SQL/mysql/2014040900.sql
@@ -0,0 +1,3 @@
+-- MySQL database updates since version 1.0
+
+ALTER TABLE `events` ADD `status` VARCHAR(32) NOT NULL AFTER `sensitivity`;
diff --git a/plugins/calendar/drivers/database/SQL/postgres.initial.sql b/plugins/calendar/drivers/database/SQL/postgres.initial.sql
index 00a91c20..007bbf29 100644
--- a/plugins/calendar/drivers/database/SQL/postgres.initial.sql
+++ b/plugins/calendar/drivers/database/SQL/postgres.initial.sql
@@ -60,6 +60,7 @@ CREATE TABLE events (
free_busy smallint NOT NULL DEFAULT 0,
priority smallint NOT NULL DEFAULT 0,
sensitivity smallint NOT NULL DEFAULT 0,
+ status character varying(32) NOT NULL,
alarms varchar(255) DEFAULT NULL,
attendees text DEFAULT NULL,
notifyat timestamp without time zone DEFAULT NULL,
diff --git a/plugins/calendar/drivers/database/SQL/postgres/2014040900.sql b/plugins/calendar/drivers/database/SQL/postgres/2014040900.sql
new file mode 100644
index 00000000..310744c9
--- /dev/null
+++ b/plugins/calendar/drivers/database/SQL/postgres/2014040900.sql
@@ -0,0 +1,3 @@
+-- Postgres database updates since version 1.0
+
+ALTER TABLE events ADD status character varying(32) NOT NULL;
diff --git a/plugins/calendar/drivers/database/SQL/sqlite.initial.sql b/plugins/calendar/drivers/database/SQL/sqlite.initial.sql
index 6e0643b1..3d359073 100644
--- a/plugins/calendar/drivers/database/SQL/sqlite.initial.sql
+++ b/plugins/calendar/drivers/database/SQL/sqlite.initial.sql
@@ -43,6 +43,7 @@ CREATE TABLE events (
free_busy tinyint(1) NOT NULL default '0',
priority tinyint(1) NOT NULL default '0',
sensitivity tinyint(1) NOT NULL default '0',
+ status varchar(32) NOT NULL default '',
alarms varchar(255) default NULL,
attendees text default NULL,
notifyat datetime default NULL,
diff --git a/plugins/calendar/drivers/database/SQL/sqlite/2014040900.sql b/plugins/calendar/drivers/database/SQL/sqlite/2014040900.sql
new file mode 100644
index 00000000..ff8ed173
--- /dev/null
+++ b/plugins/calendar/drivers/database/SQL/sqlite/2014040900.sql
@@ -0,0 +1,67 @@
+-- SQLite database updates since version 0.9-beta
+
+-- ALTER TABLE events ADD url varchar(255) NOT NULL AFTER categories;
+
+CREATE TABLE temp_events (
+ event_id integer NOT NULL PRIMARY KEY,
+ calendar_id integer NOT NULL default '0',
+ recurrence_id integer NOT NULL default '0',
+ uid varchar(255) NOT NULL default '',
+ created datetime NOT NULL default '1000-01-01 00:00:00',
+ changed datetime NOT NULL default '1000-01-01 00:00:00',
+ sequence integer NOT NULL default '0',
+ start datetime NOT NULL default '1000-01-01 00:00:00',
+ end datetime NOT NULL default '1000-01-01 00:00:00',
+ recurrence varchar(255) default NULL,
+ title varchar(255) NOT NULL,
+ description text NOT NULL,
+ location varchar(255) NOT NULL default '',
+ categories varchar(255) NOT NULL default '',
+ url varchar(255) NOT NULL default '',
+ all_day tinyint(1) NOT NULL default '0',
+ free_busy tinyint(1) NOT NULL default '0',
+ priority tinyint(1) NOT NULL default '0',
+ sensitivity tinyint(1) NOT NULL default '0',
+ alarms varchar(255) default NULL,
+ attendees text default NULL,
+ notifyat datetime default NULL
+);
+
+INSERT INTO temp_events (event_id, calendar_id, recurrence_id, uid, created, changed, sequence, start, end, recurrence, title, description, location, categories, url, all_day, free_busy, priority, sensitivity, alarms, attendees, notifyat)
+ SELECT event_id, calendar_id, recurrence_id, uid, created, changed, sequence, start, end, recurrence, title, description, location, categories, url, all_day, free_busy, priority, sensitivity, alarms, attendees, notifyat
+ FROM events;
+
+DROP TABLE events;
+
+CREATE TABLE events (
+ event_id integer NOT NULL PRIMARY KEY,
+ calendar_id integer NOT NULL default '0',
+ recurrence_id integer NOT NULL default '0',
+ uid varchar(255) NOT NULL default '',
+ created datetime NOT NULL default '1000-01-01 00:00:00',
+ changed datetime NOT NULL default '1000-01-01 00:00:00',
+ sequence integer NOT NULL default '0',
+ start datetime NOT NULL default '1000-01-01 00:00:00',
+ end datetime NOT NULL default '1000-01-01 00:00:00',
+ recurrence varchar(255) default NULL,
+ title varchar(255) NOT NULL,
+ description text NOT NULL,
+ location varchar(255) NOT NULL default '',
+ categories varchar(255) NOT NULL default '',
+ url varchar(255) NOT NULL default '',
+ all_day tinyint(1) NOT NULL default '0',
+ free_busy tinyint(1) NOT NULL default '0',
+ priority tinyint(1) NOT NULL default '0',
+ sensitivity tinyint(1) NOT NULL default '0',
+ status varchar(32) NOT NULL default '',
+ alarms varchar(255) default NULL,
+ attendees text default NULL,
+ notifyat datetime default NULL,
+ CONSTRAINT fk_events_calendar_id FOREIGN KEY (calendar_id)
+ REFERENCES calendars(calendar_id)
+);
+
+INSERT INTO events (event_id, calendar_id, recurrence_id, uid, created, changed, sequence, start, end, recurrence, title, description, location, categories, url, all_day, free_busy, priority, sensitivity, alarms, attendees, notifyat)
+ SELECT event_id, calendar_id, recurrence_id, uid, created, changed, sequence, start, end, recurrence, title, description, location, categories, url, all_day, free_busy, priority, sensitivity, alarms, attendees, notifyat
+ FROM temp_events;
+
diff --git a/plugins/calendar/drivers/database/database_driver.php b/plugins/calendar/drivers/database/database_driver.php
index b50b23bb..77e49518 100644
--- a/plugins/calendar/drivers/database/database_driver.php
+++ b/plugins/calendar/drivers/database/database_driver.php
@@ -271,8 +271,8 @@ class database_driver extends calendar_driver
$this->rc->db->query(sprintf(
"INSERT INTO " . $this->db_events . "
- (calendar_id, created, changed, uid, %s, %s, all_day, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, attendees, alarms, notifyat)
- VALUES (?, %s, %s, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+ (calendar_id, created, changed, uid, %s, %s, all_day, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, status, attendees, alarms, notifyat)
+ VALUES (?, %s, %s, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
$this->rc->db->quote_identifier('start'),
$this->rc->db->quote_identifier('end'),
$this->rc->db->now(),
@@ -292,6 +292,7 @@ class database_driver extends calendar_driver
intval($event['free_busy']),
intval($event['priority']),
intval($event['sensitivity']),
+ strval($event['status']),
$event['attendees'],
$event['alarms'],
$event['notifyat']
@@ -450,7 +451,11 @@ class database_driver extends calendar_driver
$event['_recurrence'] = rtrim($rrule, ';');
$event['free_busy'] = intval($this->free_busy_map[strtolower($event['free_busy'])]);
$event['sensitivity'] = intval($this->sensitivity_map[strtolower($event['sensitivity'])]);
-
+
+ if ($event['free_busy'] == 'tentative') {
+ $event['status'] = 'TENTATIVE';
+ }
+
if (isset($event['allday'])) {
$event['all_day'] = $event['allday'] ? 1 : 0;
}
@@ -499,13 +504,13 @@ class database_driver extends calendar_driver
{
$event = $this->_save_preprocess($event);
$sql_set = array();
- $set_cols = array('start', 'end', 'all_day', 'recurrence_id', 'sequence', 'title', 'description', 'location', 'categories', 'url', 'free_busy', 'priority', 'sensitivity', 'attendees', 'alarms', 'notifyat');
+ $set_cols = array('start', 'end', 'all_day', 'recurrence_id', 'sequence', 'title', 'description', 'location', 'categories', 'url', 'free_busy', 'priority', 'sensitivity', 'status', 'attendees', 'alarms', 'notifyat');
foreach ($set_cols as $col) {
if (is_object($event[$col]) && is_a($event[$col], 'DateTime'))
$sql_set[] = $this->rc->db->quote_identifier($col) . '=' . $this->rc->db->quote($event[$col]->format(self::DB_DATE_FORMAT));
else if (is_array($event[$col]))
$sql_set[] = $this->rc->db->quote_identifier($col) . '=' . $this->rc->db->quote(join(',', $event[$col]));
- else if (isset($event[$col]))
+ else if (array_key_exists($col, $event))
$sql_set[] = $this->rc->db->quote_identifier($col) . '=' . $this->rc->db->quote($event[$col]);
}
@@ -581,11 +586,11 @@ class database_driver extends calendar_driver
$next_start->setTimezone($this->server_timezone);
$next_end = clone $next_start;
$next_end->add($duration);
- $notify_at = $this->_get_notification(array('alarms' => $event['alarms'], 'start' => $next_start, 'end' => $next_end));
+ $notify_at = $this->_get_notification(array('alarms' => $event['alarms'], 'start' => $next_start, 'end' => $next_end, 'status' => $event['status']));
$query = $this->rc->db->query(sprintf(
"INSERT INTO " . $this->db_events . "
- (calendar_id, recurrence_id, created, changed, uid, %s, %s, all_day, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, alarms, attendees, notifyat)
- SELECT calendar_id, ?, %s, %s, uid, ?, ?, all_day, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, alarms, attendees, ?
+ (calendar_id, recurrence_id, created, changed, uid, %s, %s, all_day, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, status, alarms, attendees, notifyat)
+ SELECT calendar_id, ?, %s, %s, uid, ?, ?, all_day, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, status, alarms, attendees, ?
FROM " . $this->db_events . " WHERE event_id=? AND calendar_id IN (" . $this->calendar_ids . ")",
$this->rc->db->quote_identifier('start'),
$this->rc->db->quote_identifier('end'),
diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
index 129d30f4..46fbed90 100644
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -597,6 +597,10 @@ class kolab_calendar
if (is_array($record['categories']))
$record['categories'] = $record['categories'][0];
+ // the cancelled flag transltes into status=CANCELLED
+ if ($record['cancelled'])
+ $record['status'] = 'CANCELLED';
+
// The web client only supports DISPLAY type of alarms
if (!empty($record['alarms']))
$record['alarms'] = preg_replace('/:[A-Z]+$/', ':DISPLAY', $record['alarms']);
diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php
index 00306859..2f544999 100644
--- a/plugins/calendar/lib/calendar_ui.php
+++ b/plugins/calendar/lib/calendar_ui.php
@@ -74,6 +74,7 @@ class calendar_ui
$this->cal->register_handler('plugin.calendar_select', array($this, 'calendar_select'));
$this->cal->register_handler('plugin.identity_select', array($this, 'identity_select'));
$this->cal->register_handler('plugin.category_select', array($this, 'category_select'));
+ $this->cal->register_handler('plugin.status_select', array($this, 'status_select'));
$this->cal->register_handler('plugin.freebusy_select', array($this, 'freebusy_select'));
$this->cal->register_handler('plugin.priority_select', array($this, 'priority_select'));
$this->cal->register_handler('plugin.sensitivity_select', array($this, 'sensitivity_select'));
@@ -303,6 +304,20 @@ class calendar_ui
return $select->show(null);
}
+ /**
+ * Render a HTML select box for status property
+ */
+ function status_select($attrib = array())
+ {
+ $attrib['name'] = 'status';
+ $select = new html_select($attrib);
+ $select->add('---', '');
+ $select->add($this->cal->gettext('confirmed'), 'CONFIRMED');
+ $select->add($this->cal->gettext('cancelled'), 'CANCELLED');
+ //$select->add($this->cal->gettext('tentative'), 'TENTATIVE');
+ return $select->show(null);
+ }
+
/**
* Render a HTML select box for free/busy/out-of-office property
*/
diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc
index b243c24b..3df791cd 100644
--- a/plugins/calendar/localization/en_US.inc
+++ b/plugins/calendar/localization/en_US.inc
@@ -60,6 +60,9 @@ $labels['free'] = 'Free';
$labels['busy'] = 'Busy';
$labels['outofoffice'] = 'Out of Office';
$labels['tentative'] = 'Tentative';
+$labels['status'] = 'Status';
+$labels['confirmed'] = 'Confirmed';
+$labels['cancelled'] = 'Cancelled';
$labels['priority'] = 'Priority';
$labels['sensitivity'] = 'Privacy';
$labels['public'] = 'public';
diff --git a/plugins/calendar/skins/classic/calendar.css b/plugins/calendar/skins/classic/calendar.css
index 87ef2da0..937a7b65 100644
--- a/plugins/calendar/skins/classic/calendar.css
+++ b/plugins/calendar/skins/classic/calendar.css
@@ -446,6 +446,10 @@ a.miniColors-trigger {
margin: 0 -0.2em;
}
+#eventshow.status-cancelled {
+ background: url(images/badge_cancelled.png) top right no-repeat;
+}
+
#eventshow.sensitivity-private {
background: url(images/badge_private.png) top right no-repeat;
}
@@ -1257,6 +1261,10 @@ span.spacer {
font-weight: bold;
}
+.cal-event-status-cancelled .fc-event-title {
+ text-decoration: line-through;
+}
+
.fc-event-hori .fc-event-title {
font-weight: normal;
white-space: nowrap;
diff --git a/plugins/calendar/skins/classic/images/badge_cancelled.png b/plugins/calendar/skins/classic/images/badge_cancelled.png
new file mode 100644
index 00000000..b89029e0
Binary files /dev/null and b/plugins/calendar/skins/classic/images/badge_cancelled.png differ
diff --git a/plugins/calendar/skins/classic/templates/eventedit.html b/plugins/calendar/skins/classic/templates/eventedit.html
index 3bc4a488..7e7170d2 100644
--- a/plugins/calendar/skins/classic/templates/eventedit.html
+++ b/plugins/calendar/skins/classic/templates/eventedit.html
@@ -52,6 +52,10 @@