Compare commits
4 commits
master
...
multiple_b
Author | SHA1 | Date | |
---|---|---|---|
|
d99cddad2d | ||
|
23191c9c8b | ||
|
a90ebffdc1 | ||
|
49b078e3ff |
24 changed files with 6035 additions and 213 deletions
727
calendar.php
727
calendar.php
File diff suppressed because it is too large
Load diff
|
@ -2891,7 +2891,7 @@ function rcube_calendar_ui(settings)
|
|||
calendar = { name:'', color:'cc0000', editable:true, showalarms:true };
|
||||
|
||||
var title = rcmail.gettext((calendar.id ? 'editcalendar' : 'createcalendar'), 'calendar'),
|
||||
params = {action: calendar.id ? 'form-edit' : 'form-new', c: {id: calendar.id}, _framed: 1},
|
||||
params = {action: calendar.id ? 'form-edit' : 'form-new', c: {id: calendar.id}, driver: calendar.driver, _framed: 1},
|
||||
$dialog = $('<iframe>').attr('src', rcmail.url('calendar', params)).on('load', function() {
|
||||
var contents = $(this).contents();
|
||||
contents.find('#calendar-name')
|
||||
|
@ -2929,7 +2929,7 @@ function rcube_calendar_ui(settings)
|
|||
data.id = calendar.id;
|
||||
|
||||
me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata');
|
||||
rcmail.http_post('calendar', { action:(calendar.id ? 'edit' : 'new'), c:data });
|
||||
rcmail.http_post('calendar', { action:(calendar.id ? 'edit' : 'new'), c:data, driver: calendar.driver });
|
||||
$dialog.dialog("close");
|
||||
};
|
||||
|
||||
|
@ -2950,7 +2950,7 @@ function rcube_calendar_ui(settings)
|
|||
{
|
||||
var label = calendar.children ? 'deletecalendarconfirmrecursive' : 'deletecalendarconfirm';
|
||||
rcmail.confirm_dialog(rcmail.gettext(label, 'calendar'), 'delete', function() {
|
||||
rcmail.http_post('calendar', { action:'delete', c:{ id:calendar.id } });
|
||||
rcmail.http_post('calendar', { action:'delete', c:{ id:calendar.id }, driver: calendar.driver });
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -3467,7 +3467,7 @@ function rcube_calendar_ui(settings)
|
|||
var brightness, select, id = cal.id;
|
||||
|
||||
me.calendars[id] = $.extend({
|
||||
url: rcmail.url('calendar/load_events', { source: id }),
|
||||
url: rcmail.url('calendar/load_events', { source: id, driver: cal.driver }),
|
||||
id: id
|
||||
}, cal);
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"name": "kolab/calendar",
|
||||
"name": "jodlidev/calendar",
|
||||
"type": "roundcube-plugin",
|
||||
"description": "Calendar plugin",
|
||||
"description": "Calendar plugin with CalDav",
|
||||
"homepage": "https://git.kolab.org/diffusion/RPK/",
|
||||
"license": "AGPLv3",
|
||||
"version": "3.5.7",
|
||||
"version": "3.5.7.1",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Thomas Bruederli",
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// backend type (database, kolab)
|
||||
$config['calendar_driver'] = "database";
|
||||
// backend type (database, kolab, caldav, ical)
|
||||
$config['calendar_driver'] = array("database", "caldav");
|
||||
$config['calendar_driver_default'] = "caldav";
|
||||
|
||||
// default calendar view (agendaDay, agendaWeek, month)
|
||||
$config['calendar_default_view'] = "agendaWeek";
|
||||
|
@ -139,6 +140,14 @@ $config['kolab_invitation_calendars'] = false;
|
|||
// %i - Calendar UUID
|
||||
// $config['calendar_caldav_url'] = 'http://%h/iRony/calendars/%u/%i';
|
||||
|
||||
// Crypt key to encrypt passwords for added iCAL/CalDAV calendars
|
||||
$config['calendar_crypt_key'] = "put some random string here";
|
||||
|
||||
// Set to false to allow CURL to connect with SSL hosts that it can't verify the certificates from
|
||||
// e.g. for self-signed certificates.
|
||||
// technical note: This sets CURLOPT_SSL_VERIFYPEER _and_ CURLOPT_SSL_VERIFYHOST.
|
||||
$config['calendar_curl_secure_ssl'] = true;
|
||||
|
||||
// Driver to provide a resource directory ('ldap' is the only implementation yet).
|
||||
// Leave empty or commented to disable resources support.
|
||||
// $config['calendar_resources_driver'] = 'ldap';
|
||||
|
@ -146,9 +155,34 @@ $config['kolab_invitation_calendars'] = false;
|
|||
// LDAP directory configuration to find avilable resources for events
|
||||
// $config['calendar_resources_directory'] = array(/* ldap_public-like address book configuration */);
|
||||
|
||||
// Enable debugging output for iCAL/CalDAV drivers
|
||||
$config['calendar_caldav_debug'] = false;
|
||||
$config['calendar_ical_debug'] = false;
|
||||
|
||||
// Enables displaying of free-busy URL with token-based authentication
|
||||
// Set it to the prefix URL, e.g. 'https://hostname/freebusy' or just '/freebusy'.
|
||||
// See freebusy_session_auth in configuration of kolab_auth plugin.
|
||||
$config['calendar_freebusy_session_auth_url'] = null;
|
||||
|
||||
|
||||
// Pre-installed calendars, added at first access to calendar section
|
||||
// Caldav driver is supported only
|
||||
// $config['calendar_preinstalled_calendars'] = array(
|
||||
// 'Caldav' => array(
|
||||
// 'driver' => 'caldav',
|
||||
// 'caldav_user' => '%u',
|
||||
// 'caldav_pass' => '%p',
|
||||
// 'caldav_url' => 'http://example.caldav.org/%u/calendar/',
|
||||
// 'color' => 'cccc00',
|
||||
// 'showAlarms' => 1),
|
||||
// 'Other' => array(
|
||||
// 'driver' => 'other',
|
||||
// 'other_user' => 'user@example.other.org',
|
||||
// 'other_pass' => 'password',
|
||||
// 'other_url' => 'http://example.other.org/user@example.other.org/other',
|
||||
// 'color' => 'cc0000',
|
||||
// 'other_property1' => 'value1',
|
||||
// 'other_property2' => 'value2',
|
||||
// 'showAlarms' => 1));
|
||||
|
||||
?>
|
||||
|
|
92
drivers/caldav/SQL/mysql.initial.sql
Normal file
92
drivers/caldav/SQL/mysql.initial.sql
Normal file
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
* CalDAV Client
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Daniel Morlock <daniel.morlock@awesome-it.de>
|
||||
*
|
||||
* Copyright (C) Awesome IT GbR <info@awesome-it.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `caldav_calendars` (
|
||||
`calendar_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` varchar(8) NOT NULL,
|
||||
`showalarms` tinyint(1) NOT NULL DEFAULT '1',
|
||||
|
||||
`caldav_url` varchar(255) NOT NULL,
|
||||
`caldav_tag` varchar(255) DEFAULT NULL,
|
||||
`caldav_user` varchar(255) DEFAULT NULL,
|
||||
`caldav_pass` varchar(1024) DEFAULT NULL,
|
||||
`caldav_last_change` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY(`calendar_id`),
|
||||
INDEX `caldav_user_name_idx` (`user_id`, `name`),
|
||||
CONSTRAINT `fk_caldav_calendars_user_id` FOREIGN KEY (`user_id`)
|
||||
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `caldav_events` (
|
||||
`event_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`calendar_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`recurrence_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`uid` varchar(255) NOT NULL DEFAULT '',
|
||||
`instance` varchar(16) NOT NULL DEFAULT '',
|
||||
`isexception` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||
`changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||
`sequence` int(1) UNSIGNED 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` text NULL DEFAULT NULL,
|
||||
`attendees` text DEFAULT NULL,
|
||||
`notifyat` datetime DEFAULT NULL,
|
||||
|
||||
`caldav_url` varchar(255) NOT NULL,
|
||||
`caldav_tag` varchar(255) DEFAULT NULL,
|
||||
`caldav_last_change` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY(`event_id`),
|
||||
INDEX `caldav_uid_idx` (`uid`),
|
||||
INDEX `caldav_recurrence_idx` (`recurrence_id`),
|
||||
INDEX `caldav_calendar_notify_idx` (`calendar_id`,`notifyat`),
|
||||
CONSTRAINT `fk_caldav_events_calendar_id` FOREIGN KEY (`calendar_id`)
|
||||
REFERENCES `caldav_calendars`(`calendar_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `caldav_attachments` (
|
||||
`attachment_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`event_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`filename` varchar(255) NOT NULL DEFAULT '',
|
||||
`mimetype` varchar(255) NOT NULL DEFAULT '',
|
||||
`size` int(11) NOT NULL DEFAULT '0',
|
||||
`data` longtext NOT NULL,
|
||||
PRIMARY KEY(`attachment_id`),
|
||||
CONSTRAINT `fk_caldav_attachments_event_id` FOREIGN KEY (`event_id`)
|
||||
REFERENCES `caldav_events`(`event_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
REPLACE INTO `system` (`name`, `value`) VALUES ('calendar-caldav-version', '2015022700');
|
0
drivers/caldav/SQL/mysql/.keep_dir
Normal file
0
drivers/caldav/SQL/mysql/.keep_dir
Normal file
24
drivers/caldav/SQL/mysql/2014081300.sql
Normal file
24
drivers/caldav/SQL/mysql/2014081300.sql
Normal file
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* CalDAV Client
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Daniel Morlock <daniel.morlock@awesome-it.de>
|
||||
*
|
||||
* Copyright (C) Awesome IT GbR <info@awesome-it.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
ALTER TABLE `caldav_props` change `user` `username` varchar(255);
|
||||
ALTER TABLE `events` ADD `status` VARCHAR(32) NOT NULL DEFAULT '' AFTER `sensitivity`;
|
125
drivers/caldav/SQL/mysql/2015022500.sql
Normal file
125
drivers/caldav/SQL/mysql/2015022500.sql
Normal file
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* CalDAV Client
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Daniel Morlock <daniel.morlock@awesome-it.de>
|
||||
*
|
||||
* Copyright (C) Awesome IT GbR <info@awesome-it.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Create new tables */
|
||||
CREATE TABLE IF NOT EXISTS `caldav_calendars` (
|
||||
`calendar_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` varchar(8) NOT NULL,
|
||||
`showalarms` tinyint(1) NOT NULL DEFAULT '1',
|
||||
|
||||
`caldav_url` varchar(255) NOT NULL,
|
||||
`caldav_tag` varchar(255) DEFAULT NULL,
|
||||
`caldav_user` varchar(255) DEFAULT NULL,
|
||||
`caldav_pass` varchar(1024) DEFAULT NULL,
|
||||
`caldav_last_change` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY(`calendar_id`),
|
||||
INDEX `caldav_user_name_idx` (`user_id`, `name`),
|
||||
CONSTRAINT `fk_caldav_calendars_user_id` FOREIGN KEY (`user_id`)
|
||||
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `caldav_events` (
|
||||
`event_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`calendar_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`recurrence_id` int(11) UNSIGNED 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` int(1) UNSIGNED 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,
|
||||
|
||||
`caldav_url` varchar(255) NOT NULL,
|
||||
`caldav_tag` varchar(255) DEFAULT NULL,
|
||||
`caldav_last_change` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY(`event_id`),
|
||||
INDEX `caldav_uid_idx` (`uid`),
|
||||
INDEX `caldav_recurrence_idx` (`recurrence_id`),
|
||||
INDEX `caldav_calendar_notify_idx` (`calendar_id`,`notifyat`),
|
||||
CONSTRAINT `fk_caldav_events_calendar_id` FOREIGN KEY (`calendar_id`)
|
||||
REFERENCES `calendars`(`calendar_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `caldav_attachments` (
|
||||
`attachment_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`event_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`filename` varchar(255) NOT NULL DEFAULT '',
|
||||
`mimetype` varchar(255) NOT NULL DEFAULT '',
|
||||
`size` int(11) NOT NULL DEFAULT '0',
|
||||
`data` longtext NOT NULL,
|
||||
PRIMARY KEY(`attachment_id`),
|
||||
CONSTRAINT `fk_caldav_attachments_event_id` FOREIGN KEY (`event_id`)
|
||||
REFERENCES `events`(`event_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
/* Migrate Data */
|
||||
INSERT INTO caldav_calendars SELECT calendar_id, user_id, `name`, color, showalarms, url as caldav_url,
|
||||
tag as caldav_tag, username as caldav_user, pass as caldav_pass,
|
||||
last_change as caldav_last_change
|
||||
FROM calendars cal, caldav_props dav
|
||||
WHERE dav.obj_id = cal.calendar_id
|
||||
AND dav.obj_type = 'vcal';
|
||||
|
||||
INSERT INTO caldav_events SELECT e.*, dav.url as caldav_url, dav.tag as caldav_tag, dav.last_change as caldav_last_change
|
||||
FROM `events` e, caldav_props dav
|
||||
WHERE dav.obj_id = e.event_id
|
||||
AND dav.obj_type = 'vevent';
|
||||
|
||||
INSERT INTO caldav_attachments SELECT * FROM attachments a
|
||||
WHERE a.event_id IN (
|
||||
SELECT obj_id FROM caldav_props dav
|
||||
WHERE dav.obj_type = 'vevent'
|
||||
);
|
||||
|
||||
/* Drop deprecated data */
|
||||
DELETE FROM `events` WHERE event_id IN (
|
||||
SELECT obj_id FROM caldav_props dav
|
||||
WHERE dav.obj_type = 'vevent'
|
||||
);
|
||||
DELETE FROM calendars WHERE calendar_id IN (
|
||||
SELECT obj_id FROM caldav_props dav
|
||||
WHERE dav.obj_type = 'vcal'
|
||||
);
|
||||
DELETE FROM attachments WHERE event_id IN (
|
||||
SELECT obj_id FROM caldav_props dav
|
||||
WHERE dav.obj_type = 'vevent'
|
||||
);
|
||||
DROP TABLE caldav_props;
|
||||
|
14
drivers/caldav/SQL/mysql/2015022700.sql
Normal file
14
drivers/caldav/SQL/mysql/2015022700.sql
Normal file
|
@ -0,0 +1,14 @@
|
|||
-- add identifier for recurring instances and exceptions
|
||||
|
||||
ALTER TABLE `caldav_events` ADD `instance` varchar(16) NOT NULL DEFAULT '' AFTER `uid`;
|
||||
ALTER TABLE `caldav_events` ADD `isexception` tinyint(1) NOT NULL DEFAULT '0' AFTER `instance`;
|
||||
|
||||
UPDATE `caldav_events` SET `instance` = DATE_FORMAT(`start`, '%Y%m%d')
|
||||
WHERE `recurrence_id` != 0 AND `instance` = '' AND `all_day` = 1;
|
||||
|
||||
UPDATE `caldav_events` SET `instance` = DATE_FORMAT(`start`, '%Y%m%dT%k%i%s')
|
||||
WHERE `recurrence_id` != 0 AND `instance` = '' AND `all_day` = 0;
|
||||
|
||||
-- extend alarms columns for multiple values
|
||||
|
||||
ALTER TABLE `caldav_events` CHANGE `alarms` `alarms` TEXT NULL DEFAULT NULL;
|
51
drivers/caldav/SQL/postgres.initial.sql
Normal file
51
drivers/caldav/SQL/postgres.initial.sql
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* CalDAV Client
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Hugo Slabbert <hugo@slabnet.com>
|
||||
*
|
||||
* Copyright (C) 2014, Hugo Slabbert <hugo@slabnet.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
CREATE TYPE caldav_type AS ENUM ('vcal','vevent','vtodo','');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS caldav_props (
|
||||
obj_id int NOT NULL,
|
||||
obj_type caldav_type NOT NULL,
|
||||
url varchar(255) NOT NULL,
|
||||
tag varchar(255) DEFAULT NULL,
|
||||
username varchar(255) DEFAULT NULL,
|
||||
pass varchar(1024) DEFAULT NULL,
|
||||
last_change timestamp without time zone DEFAULT now() NOT NULL,
|
||||
PRIMARY KEY (obj_id, obj_type)
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION upd_timestamp() RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS
|
||||
$$
|
||||
BEGIN
|
||||
NEW.last_change = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER update_timestamp
|
||||
BEFORE INSERT OR UPDATE
|
||||
ON caldav_props
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE upd_timestamp();
|
||||
|
2036
drivers/caldav/caldav_driver.php
Normal file
2036
drivers/caldav/caldav_driver.php
Normal file
File diff suppressed because it is too large
Load diff
253
drivers/caldav/caldav_sync.php
Normal file
253
drivers/caldav/caldav_sync.php
Normal file
|
@ -0,0 +1,253 @@
|
|||
<?php
|
||||
/**
|
||||
* CalDAV sync for the Calendar plugin
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Daniel Morlock <daniel.morlock@awesome-it.de>
|
||||
*
|
||||
* Copyright (C) Awesome IT GbR <info@awesome-it.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
require_once (dirname(__FILE__).'/../../lib/caldav-client.php');
|
||||
|
||||
class caldav_sync
|
||||
{
|
||||
const ACTION_NONE = 1;
|
||||
const ACTION_UPDATE = 2;
|
||||
const ACTION_CREATE = 4;
|
||||
|
||||
private $cal_id = null;
|
||||
private $ctag = null;
|
||||
private $username = null;
|
||||
private $pass = null;
|
||||
private $url = null;
|
||||
|
||||
/**
|
||||
* Default constructor for calendar synchronization adapter.
|
||||
*
|
||||
* @param array Hash array with caldav properties at least the following:
|
||||
* id: Calendar ID
|
||||
* caldav_url: Caldav calendar URL.
|
||||
* caldav_user: Caldav http basic auth user.
|
||||
* caldav_pass: Password für caldav user.
|
||||
* caldav_tag: Caldav ctag for calendar.
|
||||
*/
|
||||
public function __construct($cal)
|
||||
{
|
||||
$this->cal_id = $cal["id"];
|
||||
$this->url = $cal["caldav_url"];
|
||||
$this->ctag = isset($cal["caldav_tag"]) ? $cal["caldav_tag"] : null;
|
||||
$this->username = isset($cal["caldav_user"]) ? $cal["caldav_user"] : null;
|
||||
$this->pass = isset($cal["caldav_pass"]) ? $cal["caldav_pass"] : null;
|
||||
|
||||
$this->caldav = new caldav_client($this->url, $this->username, $this->pass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for current calendar ctag.
|
||||
* @return string
|
||||
*/
|
||||
public function get_ctag()
|
||||
{
|
||||
return $this->ctag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether current calendar needs to be synced
|
||||
* regarding the CalDAV ctag.
|
||||
*
|
||||
* @return True if the current calendar ctag differs from the CalDAV tag which
|
||||
* indicates that there are changes that must be synched. Returns false
|
||||
* if the calendar is up to date, no sync necesarry.
|
||||
*/
|
||||
public function is_synced()
|
||||
{
|
||||
$is_synced = $this->ctag == $this->caldav->get_ctag() && $this->ctag;
|
||||
caldav_driver::debug_log("Ctag indicates that calendar \"$this->cal_id\" ".($is_synced ? "is synced." : "needs update!"));
|
||||
|
||||
return $is_synced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes given events with caldav server and returns updates.
|
||||
*
|
||||
* @param array List of hash arrays with event properties, must include "caldav_url" and "tag".
|
||||
* @return array Tuple containing the following lists:
|
||||
*
|
||||
* Caldav properties for events to be created or to be updated with the keys:
|
||||
* url: Event ical URL relative to calendar URL
|
||||
* etag: Remote etag of the event
|
||||
* local_event: The local event in case of an update.
|
||||
* remote_event: The current event retrieved from caldav server.
|
||||
*
|
||||
* A list of event ids that are in sync.
|
||||
*/
|
||||
public function get_updates($events)
|
||||
{
|
||||
$ctag = $this->caldav->get_ctag();
|
||||
|
||||
if($ctag)
|
||||
{
|
||||
$this->ctag = $ctag;
|
||||
$etags = $this->caldav->get_etags();
|
||||
|
||||
list($updates, $synced_event_ids) = $this->_get_event_updates($events, $etags);
|
||||
return array($this->_get_event_data($updates), $synced_event_ids);
|
||||
}
|
||||
else
|
||||
{
|
||||
caldav_driver::debug_log("Unkown error while fetching calendar ctag for calendar \"$this->cal_id\"!");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines sync status and requried updates for the given events using given list of etags.
|
||||
*
|
||||
* @param array List of hash arrays with event properties, must include "caldav_url" and "caldav_tag".
|
||||
* @param array List of current remote etags.
|
||||
* @return array Tuple containing the following lists:
|
||||
*
|
||||
* Caldav properties for events to be created or to be updated with the keys:
|
||||
* url: Event ical URL relative to calendar URL
|
||||
* etag: Remote etag of the event
|
||||
* local_event: The local event in case of an update.
|
||||
*
|
||||
* A list of event ids that are in sync.
|
||||
*/
|
||||
private function _get_event_updates($events, $etags)
|
||||
{
|
||||
$updates = array();
|
||||
$in_sync = array();
|
||||
|
||||
foreach ($etags as $etag)
|
||||
{
|
||||
$url = $etag["url"];
|
||||
$etag = $etag["etag"];
|
||||
$event_found = false;
|
||||
foreach($events as $event)
|
||||
{
|
||||
if ($event["caldav_url"] == $url)
|
||||
{
|
||||
$event_found = true;
|
||||
|
||||
if ($event["caldav_tag"] != $etag)
|
||||
{
|
||||
caldav_driver::debug_log("Event ".$event["uid"]." needs update.");
|
||||
|
||||
array_push($updates, array(
|
||||
"local_event" => $event,
|
||||
"etag" => $etag,
|
||||
"url" => $url
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
array_push($in_sync, $event["id"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$event_found)
|
||||
{
|
||||
caldav_driver::debug_log("Found new event ".$url);
|
||||
|
||||
array_push($updates, array(
|
||||
"url" => $url,
|
||||
"etag" => $etag
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return array($updates, $in_sync);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches event data and attaches it to the given update properties.
|
||||
*
|
||||
* @param $updates List of update properties.
|
||||
* @return array List of update properties with additional key "remote_event" containing the current caldav event.
|
||||
*/
|
||||
private function _get_event_data($updates)
|
||||
{
|
||||
$urls = array();
|
||||
|
||||
foreach ($updates as $update)
|
||||
{
|
||||
array_push($urls, $update["url"]);
|
||||
}
|
||||
|
||||
$events = $this->caldav->get_events($urls);
|
||||
foreach($updates as &$update)
|
||||
{
|
||||
// Attach remote events to the appropriate updates.
|
||||
// Note that this assumes unique event URL's!
|
||||
$url = $update["url"];
|
||||
if($events[$url]) {
|
||||
$update["remote_event"] = $events[$url];
|
||||
$update["remote_event"]["calendar"] = $this->cal_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $updates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the given event on the CalDAV server.
|
||||
*
|
||||
* @param array Hash array with event properties.
|
||||
* @return Event with updated "caldav_url" and "caldav_tag" attributes, false on error.
|
||||
*/
|
||||
public function create_event($event)
|
||||
{
|
||||
$props = array(
|
||||
"caldav_url" => parse_url($this->url, PHP_URL_PATH)."/".$event["uid"].".ics",
|
||||
"caldav_tag" => null
|
||||
);
|
||||
|
||||
caldav_driver::debug_log("Push new event to url ".$props["caldav_url"]);
|
||||
$result = $this->caldav->put_event($props["caldav_url"], $event);
|
||||
|
||||
if($result == false || $result < 0) return false;
|
||||
return array_merge($event, $props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the given event on the CalDAV server.
|
||||
*
|
||||
* @param array Hash array with event properties to update, must include "uid", "caldav_url" and "caldav_tag".
|
||||
* @return True on success, false on error, -1 if the given event/etag is not up to date.
|
||||
*/
|
||||
public function update_event($event)
|
||||
{
|
||||
caldav_driver::debug_log("Updating event uid \"".$event["uid"]."\".");
|
||||
return $this->caldav->put_event($event["caldav_url"], $event, $event["caldav_tag"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given event from the caldav server.
|
||||
*
|
||||
* @param array Hash array with events properties, must include "caldav_url".
|
||||
* @return True on success, false on error.
|
||||
*/
|
||||
public function remove_event($event)
|
||||
{
|
||||
caldav_driver::debug_log("Removing event uid \"".$event["uid"]."\".");
|
||||
return $this->caldav->remove_event($event["caldav_url"]);
|
||||
}
|
||||
};
|
||||
?>
|
91
drivers/ical/SQL/mysql.initial.sql
Normal file
91
drivers/ical/SQL/mysql.initial.sql
Normal file
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* iCAL Client
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Daniel Morlock <daniel.morlock@awesome-it.de>
|
||||
*
|
||||
* Copyright (C) Awesome IT GbR <info@awesome-it.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ical_calendars` (
|
||||
`calendar_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` varchar(8) NOT NULL,
|
||||
`showalarms` tinyint(1) NOT NULL DEFAULT '1',
|
||||
|
||||
`ical_url` varchar(255) NOT NULL,
|
||||
`ical_user` varchar(255) DEFAULT NULL,
|
||||
`ical_pass` varchar(1024) DEFAULT NULL,
|
||||
`ical_last_change` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY(`calendar_id`),
|
||||
INDEX `ical_user_name_idx` (`user_id`, `name`),
|
||||
CONSTRAINT `fk_ical_calendars_user_id` FOREIGN KEY (`user_id`)
|
||||
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ical_events` (
|
||||
`event_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`calendar_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`recurrence_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`uid` varchar(255) NOT NULL DEFAULT '',
|
||||
`instance` varchar(16) NOT NULL DEFAULT '',
|
||||
`isexception` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||
`changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||
`sequence` int(1) UNSIGNED 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` text NULL DEFAULT NULL,
|
||||
`attendees` text DEFAULT NULL,
|
||||
`notifyat` datetime DEFAULT NULL,
|
||||
|
||||
`ical_url` varchar(255) NOT NULL,
|
||||
`ical_last_change` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY(`event_id`),
|
||||
INDEX `ical_uid_idx` (`uid`),
|
||||
INDEX `ical_recurrence_idx` (`recurrence_id`),
|
||||
INDEX `ical_calendar_notify_idx` (`calendar_id`,`notifyat`),
|
||||
CONSTRAINT `fk_ical_events_calendar_id` FOREIGN KEY (`calendar_id`)
|
||||
REFERENCES `ical_calendars`(`calendar_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ical_attachments` (
|
||||
`attachment_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`event_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`filename` varchar(255) NOT NULL DEFAULT '',
|
||||
`mimetype` varchar(255) NOT NULL DEFAULT '',
|
||||
`size` int(11) NOT NULL DEFAULT '0',
|
||||
`data` longtext NOT NULL,
|
||||
PRIMARY KEY(`attachment_id`),
|
||||
CONSTRAINT `fk_ical_attachments_event_id` FOREIGN KEY (`event_id`)
|
||||
REFERENCES `ical_events`(`event_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
REPLACE INTO `system` (`name`, `value`) VALUES ('calendar-ical-version', '2015022700');
|
0
drivers/ical/SQL/mysql/.keep_dir
Normal file
0
drivers/ical/SQL/mysql/.keep_dir
Normal file
124
drivers/ical/SQL/mysql/2015022500.sql
Normal file
124
drivers/ical/SQL/mysql/2015022500.sql
Normal file
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* iCAL Client
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Daniel Morlock <daniel.morlock@awesome-it.de>
|
||||
*
|
||||
* Copyright (C) Awesome IT GbR <info@awesome-it.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Create new tables */
|
||||
CREATE TABLE IF NOT EXISTS `ical_calendars` (
|
||||
`calendar_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` varchar(8) NOT NULL,
|
||||
`showalarms` tinyint(1) NOT NULL DEFAULT '1',
|
||||
|
||||
`ical_url` varchar(255) NOT NULL,
|
||||
`ical_user` varchar(255) DEFAULT NULL,
|
||||
`ical_pass` varchar(1024) DEFAULT NULL,
|
||||
`ical_last_change` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY(`calendar_id`),
|
||||
INDEX `ical_user_name_idx` (`user_id`, `name`),
|
||||
CONSTRAINT `fk_ical_calendars_user_id` FOREIGN KEY (`user_id`)
|
||||
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ical_events` (
|
||||
`event_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`calendar_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`recurrence_id` int(11) UNSIGNED 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` int(1) UNSIGNED 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,
|
||||
|
||||
PRIMARY KEY(`event_id`),
|
||||
INDEX `ical_uid_idx` (`uid`),
|
||||
INDEX `ical_recurrence_idx` (`recurrence_id`),
|
||||
INDEX `ical_calendar_notify_idx` (`calendar_id`,`notifyat`),
|
||||
CONSTRAINT `fk_ical_events_calendar_id` FOREIGN KEY (`calendar_id`)
|
||||
REFERENCES `calendars`(`calendar_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `ical_attachments` (
|
||||
`attachment_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`event_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`filename` varchar(255) NOT NULL DEFAULT '',
|
||||
`mimetype` varchar(255) NOT NULL DEFAULT '',
|
||||
`size` int(11) NOT NULL DEFAULT '0',
|
||||
`data` longtext NOT NULL,
|
||||
PRIMARY KEY(`attachment_id`),
|
||||
CONSTRAINT `fk_ical_attachments_event_id` FOREIGN KEY (`event_id`)
|
||||
REFERENCES `events`(`event_id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||
|
||||
/* Migrate Data */
|
||||
INSERT INTO ical_calendars
|
||||
SELECT calendar_id, user_id, `name`, color, showalarms,
|
||||
url as ical_url, NULL as ical_user, NULL as ical_pass, last_change as ical_last_change
|
||||
FROM calendars cal, ical_props dav
|
||||
WHERE dav.obj_id = cal.calendar_id
|
||||
AND dav.obj_type = 'ical';
|
||||
|
||||
INSERT INTO ical_events SELECT e.* FROM `events` e
|
||||
WHERE e.calendar_id IN (
|
||||
SELECT obj_id FROM ical_props
|
||||
WHERE obj_type = 'ical'
|
||||
);
|
||||
|
||||
INSERT INTO ical_attachments SELECT * FROM attachments a
|
||||
WHERE a.event_id IN (
|
||||
SELECT e.event_id FROM `events` e
|
||||
WHERE e.calendar_id IN (
|
||||
SELECT obj_id FROM ical_props
|
||||
WHERE obj_type = 'ical'
|
||||
)
|
||||
);
|
||||
|
||||
/* Drop deprecated data */
|
||||
DELETE FROM `events` WHERE event_id IN (
|
||||
SELECT obj_id FROM ical_props dav
|
||||
WHERE dav.obj_type = 'vevent'
|
||||
);
|
||||
DELETE FROM calendars WHERE calendar_id IN (
|
||||
SELECT obj_id FROM ical_props dav
|
||||
WHERE dav.obj_type = 'ical'
|
||||
);
|
||||
DELETE FROM attachments WHERE event_id IN (
|
||||
SELECT obj_id FROM ical_props dav
|
||||
WHERE dav.obj_type = 'vevent'
|
||||
);
|
||||
DROP TABLE ical_props;
|
||||
|
14
drivers/ical/SQL/mysql/2015022700.sql
Normal file
14
drivers/ical/SQL/mysql/2015022700.sql
Normal file
|
@ -0,0 +1,14 @@
|
|||
-- add identifier for recurring instances and exceptions
|
||||
|
||||
ALTER TABLE `ical_events` ADD `instance` varchar(16) NOT NULL DEFAULT '' AFTER `uid`;
|
||||
ALTER TABLE `ical_events` ADD `isexception` tinyint(1) NOT NULL DEFAULT '0' AFTER `instance`;
|
||||
|
||||
UPDATE `ical_events` SET `instance` = DATE_FORMAT(`start`, '%Y%m%d')
|
||||
WHERE `recurrence_id` != 0 AND `instance` = '' AND `all_day` = 1;
|
||||
|
||||
UPDATE `ical_events` SET `instance` = DATE_FORMAT(`start`, '%Y%m%dT%k%i%s')
|
||||
WHERE `recurrence_id` != 0 AND `instance` = '' AND `all_day` = 0;
|
||||
|
||||
-- extend alarms columns for multiple values
|
||||
|
||||
ALTER TABLE `ical_events` CHANGE `alarms` `alarms` TEXT NULL DEFAULT NULL;
|
1821
drivers/ical/ical_driver.php
Normal file
1821
drivers/ical/ical_driver.php
Normal file
File diff suppressed because it is too large
Load diff
125
drivers/ical/ical_sync.php
Normal file
125
drivers/ical/ical_sync.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* iCalendar sync for the Calendar plugin
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Daniel Morlock <daniel.morlock@awesome-it.de>
|
||||
*
|
||||
* Copyright (C) Awesome IT GbR <info@awesome-it.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class ical_sync
|
||||
{
|
||||
const ACTION_NONE = 1;
|
||||
const ACTION_UPDATE = 2;
|
||||
const ACTION_CREATE = 4;
|
||||
|
||||
private $cal_id = null;
|
||||
private $url = null;
|
||||
private $user = null;
|
||||
private $pass = null;
|
||||
private $ical = null;
|
||||
|
||||
/**
|
||||
* Default constructor for calendar synchronization adapter.
|
||||
*
|
||||
* @param int Calendar id.
|
||||
* @param array Hash array with ical properties:
|
||||
* url: Absolute URL to iCAL resource.
|
||||
*/
|
||||
public function __construct($cal_id, $props)
|
||||
{
|
||||
$this->ical = libcalendaring::get_ical();
|
||||
$this->cal_id = $cal_id;
|
||||
|
||||
$this->url = $props["ical_url"];
|
||||
$this->user = isset($props["ical_user"]) ? $props["ical_user"] : null;
|
||||
$this->pass = isset($props["ical_pass"]) ? $props["ical_pass"] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether current calendar needs to be synced.
|
||||
*
|
||||
* @return True if the current calendar needs to be synced, false otherwise.
|
||||
*/
|
||||
public function is_synced()
|
||||
{
|
||||
// No change to check that so far.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches events from iCAL resource and returns updates.
|
||||
*
|
||||
* @param array List of local events.
|
||||
* @return array Tuple containing the following lists:
|
||||
*
|
||||
* Hash list for iCAL events to be created or to be updated with the keys:
|
||||
* local_event: The local event in case of an update.
|
||||
* remote_event: The current event retrieved from caldav server.
|
||||
*
|
||||
* A list of event ids that are in sync.
|
||||
*/
|
||||
public function get_updates($events)
|
||||
{
|
||||
$context = null;
|
||||
if($this->user != null && $this->pass != null)
|
||||
{
|
||||
$context = stream_context_create(array(
|
||||
'http' => array(
|
||||
'header' => "Authorization: Basic " . base64_encode("$this->user:$this->pass")
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
$vcal = file_get_contents($this->url, false, $context);
|
||||
$updates = array();
|
||||
$synced = array();
|
||||
if($vcal !== false) {
|
||||
|
||||
// Hash existing events by uid.
|
||||
$events_hash = array();
|
||||
foreach($events as $event) {
|
||||
$events_hash[$event['uid']] = $event;
|
||||
}
|
||||
|
||||
foreach ($this->ical->import($vcal) as $remote_event) {
|
||||
|
||||
// Attach remote event to current calendar
|
||||
$remote_event["calendar"] = $this->cal_id;
|
||||
|
||||
$local_event = null;
|
||||
if($events_hash[$remote_event['uid']])
|
||||
$local_event = $events_hash[$remote_event['uid']];
|
||||
|
||||
// Determine whether event don't need an update.
|
||||
if($local_event && $local_event["changed"] >= $remote_event["changed"])
|
||||
{
|
||||
array_push($synced, $local_event["id"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
array_push($updates, array('local_event' => $local_event, 'remote_event' => $remote_event));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($updates, $synced);
|
||||
}
|
||||
}
|
||||
|
||||
;
|
||||
?>
|
379
lib/caldav-client.php
Normal file
379
lib/caldav-client.php
Normal file
|
@ -0,0 +1,379 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* CalDAV Client
|
||||
*
|
||||
* @version @package_version@
|
||||
* @author Daniel Morlock <daniel.morlock@awesome-it.de>
|
||||
*
|
||||
* Copyright (C) Awesome IT GbR <info@awesome-it.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
require_once (dirname(__FILE__).'/SabreDAV/vendor/autoload.php');
|
||||
|
||||
|
||||
class caldav_client extends OldSabre\DAV\Client
|
||||
{
|
||||
const CLARK_GETCTAG = '{http://calendarserver.org/ns/}getctag';
|
||||
const CLARK_GETETAG = '{DAV:}getetag';
|
||||
const CLARK_CALDATA = '{urn:ietf:params:xml:ns:caldav}calendar-data';
|
||||
|
||||
private $base_uri;
|
||||
private $path;
|
||||
private $libvcal;
|
||||
|
||||
/**
|
||||
* Default constructor for CalDAV client.
|
||||
*
|
||||
* @param string Caldav URI to appropriate calendar.
|
||||
* @param string Username for HTTP basic auth.
|
||||
* @param string Password for HTTP basic auth.
|
||||
*/
|
||||
public function __construct($uri, $user = null, $pass = null)
|
||||
{
|
||||
|
||||
// Include libvcalendar on demand ...
|
||||
if(!class_exists("libvcalendar"))
|
||||
require_once (dirname(__FILE__).'/../../libcalendaring/libvcalendar.php');
|
||||
|
||||
$this->libvcal = new libvcalendar();
|
||||
|
||||
$tokens = parse_url($uri);
|
||||
$this->base_uri = $tokens['scheme']."://".$tokens['host'].($tokens['port'] ? ":".$tokens['port'] : null);
|
||||
$this->path = $tokens['path'].($tokens['query'] ? "?".$tokens['query'] : null);
|
||||
|
||||
$settings = array(
|
||||
'baseUri' => $this->base_uri,
|
||||
'authType' => OldSabre\DAV\Client::AUTH_BASIC
|
||||
);
|
||||
|
||||
// Forward SSL certificate setting to Sabre\DAV an onwards to CURL
|
||||
$this->rc = rcmail::get_instance();
|
||||
parent::setVerifyPeer($this->rc->config->get('calendar_curl_secure_ssl', true));
|
||||
|
||||
if ($user) $settings['userName'] = $user;
|
||||
if ($pass) $settings['password'] = $pass;
|
||||
|
||||
parent::__construct($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches calendar ctag.
|
||||
*
|
||||
* @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Retrieving_calendar_information
|
||||
* @return Calendar ctag or null on error.
|
||||
*/
|
||||
public function get_ctag()
|
||||
{
|
||||
try
|
||||
{
|
||||
$arr = $this->propFind($this->path, array(self::CLARK_GETCTAG));
|
||||
|
||||
if (isset($arr[self::CLARK_GETCTAG]))
|
||||
return $arr[self::CLARK_GETCTAG];
|
||||
}
|
||||
catch(OldSabre\DAV\Exception $err)
|
||||
{
|
||||
rcube::raise_error(array(
|
||||
'code' => $err->getHTTPCode(),
|
||||
'type' => 'DAV',
|
||||
'file' => $err->getFile(),
|
||||
'line' => $err->getLine(),
|
||||
'message' => $err->getMessage()
|
||||
), true, false);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches event etags and urls.
|
||||
*
|
||||
* @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Finding_out_if_anything_changed
|
||||
*
|
||||
* @param array Optional list of relative event URL's to retrieve specific etags. If not specified, all etags of the current calendar are returned.
|
||||
* @return array List of etag properties with keys:
|
||||
* url: Event ical path relative to the calendar URL.
|
||||
* etag: Current event etag.
|
||||
*/
|
||||
public function get_etags(array $event_urls = array())
|
||||
{
|
||||
$etags = array();
|
||||
|
||||
try
|
||||
{
|
||||
$arr = $this->prop_report($this->path, array(self::CLARK_GETETAG), $event_urls);
|
||||
foreach ($arr as $path => $data)
|
||||
{
|
||||
// Some caldav server return an empty calendar as event where etag is missing. Skip this!
|
||||
if($data[self::CLARK_GETETAG])
|
||||
{
|
||||
array_push($etags, array(
|
||||
"url" => $path,
|
||||
"etag" => str_replace('"', null, $data[self::CLARK_GETETAG])
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(OldSabre\DAV\Exception $err)
|
||||
{
|
||||
rcube::raise_error(array(
|
||||
'code' => $err->getHTTPCode(),
|
||||
'type' => 'DAV',
|
||||
'file' => $err->getFile(),
|
||||
'line' => $err->getLine(),
|
||||
'message' => $err->getMessage()
|
||||
), true, false);
|
||||
}
|
||||
|
||||
return $etags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches calendar events.
|
||||
*
|
||||
* @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Downloading_objects
|
||||
* @param array $urls = array() Optional list of event URL's to fetch. If non is specified, all
|
||||
* events from the appropriate calendar will be fetched.
|
||||
* @return Array hash list that maps the events URL to the appropriate event properties.
|
||||
*/
|
||||
public function get_events($urls = array())
|
||||
{
|
||||
$events = array();
|
||||
|
||||
try
|
||||
{
|
||||
$vcals = $this->prop_report($this->path, array(
|
||||
self::CLARK_GETETAG,
|
||||
self::CLARK_CALDATA
|
||||
), $urls);
|
||||
|
||||
foreach ($vcals as $path => $response)
|
||||
{
|
||||
$vcal = $response[self::CLARK_CALDATA];
|
||||
foreach ($this->libvcal->import($vcal) as $event) {
|
||||
$events[$path] = $event;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(OldSabre\DAV\Exception $err)
|
||||
{
|
||||
rcube::raise_error(array(
|
||||
'code' => $err->getHTTPCode(),
|
||||
'type' => 'DAV',
|
||||
'file' => $err->getFile(),
|
||||
'line' => $err->getLine(),
|
||||
'message' => $err->getMessage()
|
||||
), true, false);
|
||||
}
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a REPORT request
|
||||
*
|
||||
* @param string $url
|
||||
* @param array $properties List of requested properties must be specified as an array, in clark
|
||||
* notation.
|
||||
* @param array $event_urls If specified, a multiget report request will be initiated with the
|
||||
* specified event urls.
|
||||
* @param int $depth = 1 Depth should be either 0 or 1. A depth of 1 will cause a request to be
|
||||
* made to the server to also return all child resources.
|
||||
* @return array Hash with ics event path as key and a hash array with properties and appropriate values.
|
||||
*/
|
||||
public function prop_report($url, array $properties, array $event_urls = array(), $depth = 1)
|
||||
{
|
||||
$parent_tag = sizeof($event_urls) > 0 ? "c:calendar-multiget" : "d:propfind";
|
||||
$method = sizeof($event_urls) > 0 ? 'REPORT' : 'PROPFIND';
|
||||
|
||||
$body = '<?xml version="1.0"?>'."\n".'<'.$parent_tag.' xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">'."\n";
|
||||
|
||||
$body .= ' <d:prop>'."\n";
|
||||
foreach ($properties as $property)
|
||||
{
|
||||
|
||||
list($namespace, $elementName) = OldSabre\DAV\XMLUtil::parseClarkNotation($property);
|
||||
|
||||
if ($namespace === 'DAV:')
|
||||
{
|
||||
$body .= ' <d:'.$elementName.' />'."\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$body .= ' <x:'.$elementName.' xmlns:x="'.$namespace.'"/>'."\n";
|
||||
}
|
||||
}
|
||||
$body .= ' </d:prop>'."\n";
|
||||
|
||||
// http://tools.ietf.org/html/rfc4791#page-90
|
||||
// http://www.bedework.org/trac/bedework/wiki/Bedework/DevDocs/Filters
|
||||
/*
|
||||
if($start && $end)
|
||||
{
|
||||
$body.= ' <c:filter>'."\n".
|
||||
' <c:comp-filter name="VCALENDAR">'."\n".
|
||||
' <c:comp-filter name="VEVENT">'."\n".
|
||||
' <c:time-range start="'.$start.'" end="'.$end.'" />'."\n".
|
||||
' </c:comp-filter>'."\n".
|
||||
' </c:comp-filter>'."\n".
|
||||
' </c:filter>' . "\n";
|
||||
}
|
||||
*/
|
||||
|
||||
foreach ($event_urls as $event_url)
|
||||
{
|
||||
$body .= '<d:href>'.$event_url.'</d:href>'."\n";
|
||||
}
|
||||
|
||||
$body .= '</'.$parent_tag.'>';
|
||||
|
||||
$response = $this->request($method, $url, $body, array(
|
||||
'Depth' => $depth,
|
||||
'Content-Type' => 'application/xml'
|
||||
));
|
||||
|
||||
$result = $this->parseMultiStatus($response['body']);
|
||||
|
||||
// If depth was 0, we only return the top item
|
||||
if ($depth === 0)
|
||||
{
|
||||
reset($result);
|
||||
$result = current($result);
|
||||
return isset($result[200]) ? $result[200] : array();
|
||||
}
|
||||
|
||||
$new_result = array();
|
||||
foreach ($result as $href => $status_list)
|
||||
{
|
||||
$new_result[$href] = isset($status_list[200]) ? $status_list[200] : array();
|
||||
}
|
||||
|
||||
return $new_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates or creates a calendar event.
|
||||
*
|
||||
* @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Updating_a_calendar_object
|
||||
* @param string Event ics path for the event.
|
||||
* @param array Hash array with event properties.
|
||||
* @param string Current event etag to match against server data. Pass null for new events.
|
||||
* @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error.
|
||||
*/
|
||||
public function put_event($path, $event, $etag = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
$headers = array("Content-Type" => "text/calendar; charset=utf-8");
|
||||
if ($etag) $headers["If-Match"] = '"'.$etag.'"';
|
||||
|
||||
// Temporarily disable error reporting since libvcal seems not checking array key properly.
|
||||
// TODO: Remove this todo if we could ensure that those errors come not from incomplete event properties.
|
||||
$err_rep = error_reporting(E_ERROR);
|
||||
$vcal = $this->libvcal->export(array($event));
|
||||
if (is_array($vcal))
|
||||
$vcal = array_shift($vcal);
|
||||
error_reporting($err_rep);
|
||||
|
||||
$response = $this->request('PUT', $path, $vcal, $headers);
|
||||
|
||||
// Following http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Creating_a_calendar_object, the
|
||||
// caldav server must not always return the new etag.
|
||||
|
||||
return $response["statusCode"] == 201 || // 201 (created, successfully created)
|
||||
$response["statusCode"] == 204; // 204 (no content, successfully updated)
|
||||
}
|
||||
catch(OldSabre\DAV\Exception\PreconditionFailed $err)
|
||||
{
|
||||
// Event tag not up to date, must be updated first ...
|
||||
return -1;
|
||||
}
|
||||
catch(OldSabre\DAV\Exception $err)
|
||||
{
|
||||
rcube::raise_error(array(
|
||||
'code' => $err->getHTTPCode(),
|
||||
'type' => 'DAV',
|
||||
'file' => $err->getFile(),
|
||||
'line' => $err->getLine(),
|
||||
'message' => $err->getMessage()
|
||||
), true, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes event of given URL.
|
||||
*
|
||||
* @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Deleting_a_calendar_object
|
||||
* @param string Event ics path for the event.
|
||||
* @param string Current event etag to match against server data. Pass null to force removing the event.
|
||||
* @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error.
|
||||
**/
|
||||
public function remove_event($path, $etag = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
$headers = array("Content-Type" => "text/calendar; charset=utf-8");
|
||||
if ($etag) $headers["If-Match"] = '"'.$etag.'"';
|
||||
|
||||
$response = $this->request('DELETE', $path, null, $headers);
|
||||
return $response["statusCode"] == 204 || // 204 (no content, successfully deleted)
|
||||
$response["statusCode"] == 200; // 200 (OK, successfully deleted)
|
||||
}
|
||||
catch(OldSabre\DAV\Exception\PreconditionFailed $err)
|
||||
{
|
||||
// Event tag not up to date, must be updated first ...
|
||||
return -1;
|
||||
}
|
||||
catch(OldSabre\DAV\Exception $err)
|
||||
{
|
||||
rcube::raise_error(array(
|
||||
'code' => $err->getHTTPCode(),
|
||||
'type' => 'DAV',
|
||||
'file' => $err->getFile(),
|
||||
'line' => $err->getLine(),
|
||||
'message' => $err->getMessage()
|
||||
), true, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a propFind query to caldav server
|
||||
* @param string $path absolute or relative URL to Resource
|
||||
* @param array $props list of properties to use for the query. Properties must have clark-notation.
|
||||
* @param int $depth 0 means no recurse while 1 means recurse
|
||||
* @return array
|
||||
*/
|
||||
public function prop_find($path, $props, $depth)
|
||||
{
|
||||
try {
|
||||
$response = $this->propFind($path, $props, $depth);
|
||||
}
|
||||
catch(OldSabre\DAV\Exception $err)
|
||||
{
|
||||
rcube::raise_error(array(
|
||||
'code' => $err->getHTTPCode(),
|
||||
'type' => 'DAV',
|
||||
'file' => $err->getFile(),
|
||||
'line' => $err->getLine(),
|
||||
'message' => $err->getMessage()
|
||||
), true, false);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
};
|
||||
?>
|
|
@ -103,10 +103,31 @@ class calendar_ui
|
|||
$this->cal->register_handler('plugin.events_export_form', [$this, 'events_export_form']);
|
||||
$this->cal->register_handler('plugin.object_changelog_table', ['libkolab', 'object_changelog_table']);
|
||||
$this->cal->register_handler('plugin.searchform', [$this->rc->output, 'search_form']);
|
||||
$this->cal->register_handler('plugin.calendar_create_menu', array($this, 'calendar_create_menu'));
|
||||
|
||||
kolab_attachments_handler::ui();
|
||||
}
|
||||
|
||||
/**
|
||||
* Added for CalDav
|
||||
* Handler for menu to choose the driver for calendar creation.
|
||||
*/
|
||||
function calendar_create_menu($attrib = array())
|
||||
{
|
||||
$content = "";
|
||||
foreach($this->cal->get_drivers() as $name => $driver)
|
||||
{
|
||||
$content .= html::tag('li', null, $this->rc->output->button(
|
||||
array('label' => 'calendar.calendar_'.$name,
|
||||
'class' => 'active',
|
||||
'prop' => json_encode(array('driver' => $name)),
|
||||
'command' => 'calendar-create',
|
||||
'title' => 'calendar.createcalendar')));
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds CSS stylesheets to the page header
|
||||
*/
|
||||
|
@ -153,28 +174,30 @@ class calendar_ui
|
|||
*/
|
||||
function calendar_css($attrib = [])
|
||||
{
|
||||
$categories = $this->cal->driver->list_categories();
|
||||
$calendars = $this->cal->driver->list_calendars();
|
||||
$js_categories = [];
|
||||
|
||||
$mode = $this->rc->config->get('calendar_event_coloring', $this->cal->defaults['calendar_event_coloring']);
|
||||
$css = "\n";
|
||||
$css = "\n";
|
||||
|
||||
foreach ((array) $categories as $class => $color) {
|
||||
if (!empty($color)) {
|
||||
$js_categories[$class] = $color;
|
||||
foreach ($this->cal->get_drivers() as $driver) {
|
||||
$categories = $driver->list_categories();
|
||||
$calendars = $driver->list_calendars();
|
||||
$js_categories = [];
|
||||
|
||||
$color = ltrim($color, '#');
|
||||
$class = 'cat-' . asciiwords(strtolower($class), true);
|
||||
$css .= ".$class { color: #$color; }\n";
|
||||
foreach((array)$categories as $class => $color) {
|
||||
if(!empty($color)) {
|
||||
$js_categories[$class] = $color;
|
||||
|
||||
$color = ltrim($color, '#');
|
||||
$class = 'cat-' . asciiwords(strtolower($class), true);
|
||||
$css .= ".$class { color: #$color; }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->rc->output->set_env('calendar_categories', $js_categories);
|
||||
$this->rc->output->set_env('calendar_categories', $js_categories);
|
||||
|
||||
foreach ((array) $calendars as $id => $prop) {
|
||||
if (!empty($prop['color'])) {
|
||||
$css .= $this->calendar_css_classes($id, $prop, $mode, $attrib);
|
||||
foreach((array)$calendars as $id => $prop) {
|
||||
if(!empty($prop['color'])) {
|
||||
$css .= $this->calendar_css_classes($id, $prop, $mode, $attrib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +234,8 @@ class calendar_ui
|
|||
$html = '';
|
||||
$jsenv = [];
|
||||
$tree = true;
|
||||
$calendars = $this->cal->driver->list_calendars(0, $tree);
|
||||
// TODO: Check whether get_calendars() exists. Original $calendars = $this->cal->driver->list_calendars(0, $tree);
|
||||
$calendars = $this->cal->get_calendars(false, false, $tree);
|
||||
|
||||
// walk folder tree
|
||||
if (is_object($tree)) {
|
||||
|
@ -296,12 +320,13 @@ class calendar_ui
|
|||
// enrich calendar properties with settings from the driver
|
||||
if (empty($prop['virtual'])) {
|
||||
unset($prop['user_id']);
|
||||
$driver = $this->cal->get_driver_by_cal($id);
|
||||
|
||||
$prop['alarms'] = $this->cal->driver->alarms;
|
||||
$prop['attendees'] = $this->cal->driver->attendees;
|
||||
$prop['freebusy'] = $this->cal->driver->freebusy;
|
||||
$prop['attachments'] = $this->cal->driver->attachments;
|
||||
$prop['undelete'] = $this->cal->driver->undelete;
|
||||
$prop['alarms'] = $driver->alarms;
|
||||
$prop['attendees'] = $driver->attendees;
|
||||
$prop['freebusy'] = $driver->freebusy;
|
||||
$prop['attachments'] = $driver->attachments;
|
||||
$prop['undelete'] = $driver->undelete;
|
||||
$prop['feedurl'] = $this->cal->get_url([
|
||||
'_cal' => $this->cal->ical_feed_hash($id) . '.ics',
|
||||
'action' => 'feed'
|
||||
|
@ -434,7 +459,7 @@ class calendar_ui
|
|||
|
||||
$select = new html_select($attrib);
|
||||
|
||||
foreach ((array) $this->cal->driver->list_calendars() as $id => $prop) {
|
||||
foreach ((array) $this->cal->get_calendars() as $id => $prop) {
|
||||
if (
|
||||
!empty($prop['editable'])
|
||||
|| (!empty($prop['rights']) && strpos($prop['rights'], 'i') !== false)
|
||||
|
@ -472,8 +497,10 @@ class calendar_ui
|
|||
|
||||
$select = new html_select($attrib);
|
||||
$select->add('---', '');
|
||||
foreach (array_keys((array) $this->cal->driver->list_categories()) as $cat) {
|
||||
$select->add($cat, $cat);
|
||||
foreach ($this->cal->get_drivers() as $driver) {
|
||||
foreach(array_keys((array)$driver->list_categories()) as $cat) {
|
||||
$select->add($cat, $cat);
|
||||
}
|
||||
}
|
||||
|
||||
return $select->show(null);
|
||||
|
@ -554,7 +581,14 @@ class calendar_ui
|
|||
*/
|
||||
function alarm_select($attrib = [])
|
||||
{
|
||||
return $this->cal->lib->alarm_select($attrib, $this->cal->driver->alarm_types, $this->cal->driver->alarm_absolute);
|
||||
// Try GPC
|
||||
$driver = $this->cal->get_driver_by_gpc(true /* quiet */);
|
||||
|
||||
// We assume that each calendar has equal alarm types, so fallback to default calendar is ok.
|
||||
if(!$driver)
|
||||
$driver = $this->cal->get_default_driver();
|
||||
|
||||
return $this->cal->lib->alarm_select($attrib, $driver->alarm_types, $driver->alarm_absolute);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
166
lib/encryption.php
Normal file
166
lib/encryption.php
Normal file
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
/**
|
||||
* A class to handle secure encryption and decryption of arbitrary data
|
||||
* Copyright http://stackoverflow.com/users/338665/ircmaxell
|
||||
* http://stackoverflow.com/questions/5089841/php-2-way-encryption-i-need-to-store-passwords-that-can-be-retrieved
|
||||
*
|
||||
*
|
||||
* Note that this is not just straight encryption. It also has a few other
|
||||
* features in it to make the encrypted data far more secure. Note that any
|
||||
* other implementations used to decrypt data will have to do the same exact
|
||||
* operations.
|
||||
*
|
||||
* Security Benefits:
|
||||
*
|
||||
* - Uses Key stretching
|
||||
* - Hides the Initialization Vector
|
||||
* - Does HMAC verification of source data
|
||||
*
|
||||
*/
|
||||
class Encryption {
|
||||
|
||||
/**
|
||||
* @var string $cipher The mcrypt cipher to use for this instance
|
||||
*/
|
||||
protected $cipher = '';
|
||||
|
||||
/**
|
||||
* @var int $mode The mcrypt cipher mode to use
|
||||
*/
|
||||
protected $mode = '';
|
||||
|
||||
/**
|
||||
* @var int $rounds The number of rounds to feed into PBKDF2 for key generation
|
||||
*/
|
||||
protected $rounds = 100;
|
||||
|
||||
/**
|
||||
* Constructor!
|
||||
*
|
||||
* @param string $cipher The MCRYPT_* cypher to use for this instance
|
||||
* @param int $mode The MCRYPT_MODE_* mode to use for this instance
|
||||
* @param int $rounds The number of PBKDF2 rounds to do on the key
|
||||
*/
|
||||
public function __construct($cipher, $mode, $rounds = 100) {
|
||||
$this->cipher = $cipher;
|
||||
$this->mode = $mode;
|
||||
$this->rounds = (int) $rounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the data with the provided key
|
||||
*
|
||||
* @param string $data The encrypted datat to decrypt
|
||||
* @param string $key The key to use for decryption
|
||||
*
|
||||
* @returns string|false The returned string if decryption is successful
|
||||
* false if it is not
|
||||
*/
|
||||
public function decrypt($data, $key) {
|
||||
$salt = substr($data, 0, 128);
|
||||
$enc = substr($data, 128, -64);
|
||||
$mac = substr($data, -64);
|
||||
|
||||
list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
|
||||
|
||||
if ($mac !== hash_hmac('sha512', $enc, $macKey, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);
|
||||
|
||||
$data = $this->unpad($dec);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the supplied data using the supplied key
|
||||
*
|
||||
* @param string $data The data to encrypt
|
||||
* @param string $key The key to encrypt with
|
||||
*
|
||||
* @returns string The encrypted data
|
||||
*/
|
||||
public function encrypt($data, $key) {
|
||||
$salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
|
||||
list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
|
||||
|
||||
$data = $this->pad($data);
|
||||
|
||||
$enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);
|
||||
|
||||
$mac = hash_hmac('sha512', $enc, $macKey, true);
|
||||
return $salt . $enc . $mac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a set of keys given a random salt and a master key
|
||||
*
|
||||
* @param string $salt A random string to change the keys each encryption
|
||||
* @param string $key The supplied key to encrypt with
|
||||
*
|
||||
* @returns array An array of keys (a cipher key, a mac key, and a IV)
|
||||
*/
|
||||
protected function getKeys($salt, $key) {
|
||||
$ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
|
||||
$keySize = mcrypt_get_key_size($this->cipher, $this->mode);
|
||||
$length = 2 * $keySize + $ivSize;
|
||||
|
||||
$key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);
|
||||
|
||||
$cipherKey = substr($key, 0, $keySize);
|
||||
$macKey = substr($key, $keySize, $keySize);
|
||||
$iv = substr($key, 2 * $keySize);
|
||||
return array($cipherKey, $macKey, $iv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stretch the key using the PBKDF2 algorithm
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/PBKDF2
|
||||
*
|
||||
* @param string $algo The algorithm to use
|
||||
* @param string $key The key to stretch
|
||||
* @param string $salt A random salt
|
||||
* @param int $rounds The number of rounds to derive
|
||||
* @param int $length The length of the output key
|
||||
*
|
||||
* @returns string The derived key.
|
||||
*/
|
||||
protected function pbkdf2($algo, $key, $salt, $rounds, $length) {
|
||||
$size = strlen(hash($algo, '', true));
|
||||
$len = ceil($length / $size);
|
||||
$result = '';
|
||||
for ($i = 1; $i <= $len; $i++) {
|
||||
$tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
|
||||
$res = $tmp;
|
||||
for ($j = 1; $j < $rounds; $j++) {
|
||||
$tmp = hash_hmac($algo, $tmp, $key, true);
|
||||
$res ^= $tmp;
|
||||
}
|
||||
$result .= $res;
|
||||
}
|
||||
return substr($result, 0, $length);
|
||||
}
|
||||
|
||||
protected function pad($data) {
|
||||
$length = mcrypt_get_block_size($this->cipher, $this->mode);
|
||||
$padAmount = $length - strlen($data) % $length;
|
||||
if ($padAmount == 0) {
|
||||
$padAmount = $length;
|
||||
}
|
||||
return $data . str_repeat(chr($padAmount), $padAmount);
|
||||
}
|
||||
|
||||
protected function unpad($data) {
|
||||
$length = mcrypt_get_block_size($this->cipher, $this->mode);
|
||||
$last = ord($data[strlen($data) - 1]);
|
||||
if ($last > $length) return false;
|
||||
if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
|
||||
return false;
|
||||
}
|
||||
return substr($data, 0, -1 * $last);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -32,6 +32,7 @@ $labels['calendars'] = 'Календари';
|
|||
$labels['category'] = 'Категория';
|
||||
$labels['categories'] = 'Категории';
|
||||
$labels['createcalendar'] = 'Създаване на нов календар';
|
||||
$labels['editcalendar'] = 'Промяна на свойствата на календара';
|
||||
$labels['name'] = 'Име';
|
||||
$labels['color'] = 'Цвят';
|
||||
$labels['day'] = 'Ден';
|
||||
|
|
|
@ -33,6 +33,7 @@ $labels['calendars'] = 'Kalender';
|
|||
$labels['category'] = 'Kategorie';
|
||||
$labels['categories'] = 'Kategorien';
|
||||
$labels['createcalendar'] = 'Neuen Kalender erstellen';
|
||||
$labels['editcalendar'] = 'Kalendereigenschaften bearbeiten';
|
||||
$labels['name'] = 'Name';
|
||||
$labels['color'] = 'Farbe';
|
||||
$labels['day'] = 'Tag';
|
||||
|
@ -153,6 +154,8 @@ $labels['availbusy'] = 'Gebucht';
|
|||
$labels['availunknown'] = 'Unbekannt';
|
||||
$labels['availtentative'] = 'Mit Vorbehalt';
|
||||
$labels['availoutofoffice'] = 'Abwesend';
|
||||
$labels['delegatedto'] = 'Delegiert an:';
|
||||
$labels['delegatedfrom'] = 'Delegiert von:';
|
||||
$labels['scheduletime'] = 'Verfügbarkeit anzeigen';
|
||||
$labels['sendinvitations'] = 'Einladungen versenden';
|
||||
$labels['sendnotifications'] = 'Teilnehmer über die Änderungen informieren';
|
||||
|
@ -276,6 +279,15 @@ $labels['birthdayeventtitle'] = '$names Geburtstag';
|
|||
$labels['birthdayage'] = 'Alter $age';
|
||||
$labels['objectchangelog'] = 'Änderungsverlauf';
|
||||
$labels['objectdiff'] = 'Änderungen aus $rev1 nach $rev2';
|
||||
$labels['revision'] = 'Version';
|
||||
$labels['user'] = 'Benutzer';
|
||||
$labels['operation'] = 'Aktion';
|
||||
$labels['actionappend'] = 'Gespeichert';
|
||||
$labels['actionmove'] = 'Verschoben';
|
||||
$labels['actiondelete'] = 'Gelöscht';
|
||||
$labels['compare'] = 'Vergleichen';
|
||||
$labels['showrevision'] = 'Diese Version anzeigen';
|
||||
$labels['restore'] = 'Diese Version wiederherstellen';
|
||||
$labels['objectnotfound'] = 'Termindaten sind leider nicht vergübar';
|
||||
$labels['objectchangelognotavailable'] = 'Änderungshistorie ist nicht verfügbar für diesen Termin';
|
||||
$labels['objectdiffnotavailable'] = 'Vergleich für die gewählten Versionen nicht möglich';
|
||||
|
@ -292,4 +304,11 @@ $labels['arialabeleventattendees'] = 'Teilehmerliste';
|
|||
$labels['arialabeleventresources'] = 'Liste der Terminressourcen';
|
||||
$labels['arialabelresourcesearchform'] = 'Suchformular für Ressourcen';
|
||||
$labels['arialabelresourceselection'] = 'Verfügbare Ressourcen';
|
||||
|
||||
$labels['calendar_database'] = 'Datenbank Kalender';
|
||||
$labels['calendar_kolab'] = 'Kolab Kalender';
|
||||
$labels['calendar_caldav'] = 'CalDAV Kalender';
|
||||
$labels['calendar_ical'] = 'iCAL Kalender';
|
||||
$labels['caldavurl'] = "CalDAV URL";
|
||||
$labels['icalurl'] = "iCal URL";
|
||||
?>
|
||||
|
|
|
@ -178,6 +178,8 @@ $labels['availbusy'] = 'Busy';
|
|||
$labels['availunknown'] = 'Unknown';
|
||||
$labels['availtentative'] = 'Tentative';
|
||||
$labels['availoutofoffice'] = 'Out of Office';
|
||||
$labels['delegatedto'] = 'Delegated to: ';
|
||||
$labels['delegatedfrom'] = 'Delegated from: ';
|
||||
$labels['scheduletime'] = 'Find availability';
|
||||
$labels['sendinvitations'] = 'Send invitations';
|
||||
$labels['sendnotifications'] = 'Notify participants about modifications';
|
||||
|
@ -296,6 +298,15 @@ $labels['birthdayage'] = 'Age $age';
|
|||
// history dialog
|
||||
$labels['objectchangelog'] = 'Change History';
|
||||
$labels['objectdiff'] = 'Changes from $rev1 to $rev2';
|
||||
$labels['revision'] = 'Revision';
|
||||
$labels['user'] = 'User';
|
||||
$labels['operation'] = 'Action';
|
||||
$labels['actionappend'] = 'Saved';
|
||||
$labels['actionmove'] = 'Moved';
|
||||
$labels['actiondelete'] = 'Deleted';
|
||||
$labels['compare'] = 'Compare';
|
||||
$labels['showrevision'] = 'Show this version';
|
||||
$labels['restore'] = 'Restore this version';
|
||||
$labels['objectnotfound'] = 'Failed to load event data';
|
||||
$labels['objectchangelognotavailable'] = 'Change history is not available for this event';
|
||||
$labels['objectdiffnotavailable'] = 'No comparison possible for the selected revisions';
|
||||
|
@ -317,4 +328,9 @@ $labels['arialabelresourcesearchform'] = 'Resources search form';
|
|||
$labels['arialabelresourceselection'] = 'Available resources';
|
||||
$labels['arialabeleventform'] = 'Event editing form';
|
||||
|
||||
$labels['calendar_kolab'] = 'Kolab Calender';
|
||||
$labels['calendar_caldav'] = 'CalDAV Calender';
|
||||
$labels['calendar_ical'] = 'iCAL Calender';
|
||||
$labels['caldavurl'] = "CalDAV URL";
|
||||
$labels['icalurl'] = "iCal URL";
|
||||
?>
|
||||
|
|
Loading…
Reference in a new issue