mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-05-31 03:34:18 +00:00
Kind of working now, with either Lighting or Evolution.
This commit is contained in:
parent
a57d690167
commit
2b8b67ab0b
190
dba/caldav_functions.sql
Normal file
190
dba/caldav_functions.sql
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
-- Functions for CalDAV handling
|
||||||
|
|
||||||
|
CREATE or REPLACE FUNCTION apply_month_byday( TIMESTAMP WITH TIME ZONE, TEXT ) RETURNS TIMESTAMP WITH TIME ZONE AS '
|
||||||
|
DECLARE
|
||||||
|
in_time ALIAS FOR $1;
|
||||||
|
byday ALIAS FOR $2;
|
||||||
|
weeks INT;
|
||||||
|
dow INT;
|
||||||
|
temp_txt TEXT;
|
||||||
|
dd INT;
|
||||||
|
mm INT;
|
||||||
|
yy INT;
|
||||||
|
our_dow INT;
|
||||||
|
our_answer TIMESTAMP WITH TIME ZONE;
|
||||||
|
BEGIN
|
||||||
|
dow := position(substring( byday from ''..$'') in ''SUMOTUWETHFRSA'') / 2;
|
||||||
|
temp_txt := substring(byday from ''([0-9]+)'');
|
||||||
|
weeks := temp_txt::int;
|
||||||
|
|
||||||
|
-- RAISE NOTICE ''DOW: %, Weeks: %(%s)'', dow, weeks, temp_txt;
|
||||||
|
|
||||||
|
IF substring(byday for 1) = ''-'' THEN
|
||||||
|
-- Last XX of month, or possibly second-to-last, but unlikely
|
||||||
|
mm := extract( ''month'' from in_time);
|
||||||
|
yy := extract( ''year'' from in_time);
|
||||||
|
|
||||||
|
-- Start with the last day of the month
|
||||||
|
our_answer := (yy::text || ''-'' || (mm+1)::text || ''-01'')::timestamp - ''1 day''::interval;
|
||||||
|
dd := extract( ''dow'' from our_answer);
|
||||||
|
dd := dd - dow;
|
||||||
|
IF dd < 0 THEN
|
||||||
|
dd := dd + 7;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Having calculated the right day of the month, we now apply that back to in_time
|
||||||
|
-- which contains the otherwise-unobtainable timezone detail (and the time)
|
||||||
|
our_answer = our_answer - (dd::text || ''days'')::interval;
|
||||||
|
dd := extract( ''day'' from our_answer) - extract( ''day'' from in_time);
|
||||||
|
our_answer := in_time + (dd::text || ''days'')::interval;
|
||||||
|
|
||||||
|
IF weeks > 1 THEN
|
||||||
|
weeks := weeks - 1;
|
||||||
|
our_answer := our_answer - (weeks::text || ''weeks'')::interval;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
ELSE
|
||||||
|
|
||||||
|
-- Shift our date to the correct day of week..
|
||||||
|
our_dow := extract( ''dow'' from in_time);
|
||||||
|
our_dow := our_dow - dow;
|
||||||
|
dd := extract( ''day'' from in_time);
|
||||||
|
IF our_dow >= dd THEN
|
||||||
|
our_dow := our_dow - 7;
|
||||||
|
END IF;
|
||||||
|
our_answer := in_time - (our_dow::text || ''days'')::interval;
|
||||||
|
dd = extract( ''day'' from our_answer);
|
||||||
|
|
||||||
|
-- Shift the date to the correct week...
|
||||||
|
dd := weeks - ((dd+6) / 7);
|
||||||
|
IF dd != 0 THEN
|
||||||
|
our_answer := our_answer + ((dd::text || ''weeks'')::interval);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN our_answer;
|
||||||
|
|
||||||
|
END;
|
||||||
|
' LANGUAGE 'plpgsql' IMMUTABLE STRICT;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE or REPLACE FUNCTION calculate_later_timestamp( TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH TIME ZONE, TEXT ) RETURNS TIMESTAMP WITH TIME ZONE AS '
|
||||||
|
DECLARE
|
||||||
|
earliest ALIAS FOR $1;
|
||||||
|
basedate ALIAS FOR $2;
|
||||||
|
repeatrule ALIAS FOR $3;
|
||||||
|
frequency TEXT;
|
||||||
|
temp_txt TEXT;
|
||||||
|
length INT;
|
||||||
|
count INT;
|
||||||
|
byday TEXT;
|
||||||
|
bymonthday INT;
|
||||||
|
basediff INTERVAL;
|
||||||
|
past_repeats INT8;
|
||||||
|
units TEXT;
|
||||||
|
dow TEXT;
|
||||||
|
our_answer TIMESTAMP WITH TIME ZONE;
|
||||||
|
loopcount INT;
|
||||||
|
BEGIN
|
||||||
|
temp_txt := substring(repeatrule from ''UNTIL=([0-9TZ]+)(;|$)'');
|
||||||
|
IF temp_txt::timestamp with time zone < earliest THEN
|
||||||
|
RETURN NULL;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
frequency := substring(repeatrule from ''FREQ=([A-Z]+)(;|$)'');
|
||||||
|
temp_txt := substring(repeatrule from ''INTERVAL=([0-9]+)(;|$)'');
|
||||||
|
length := temp_txt::int;
|
||||||
|
basediff := earliest - basedate;
|
||||||
|
|
||||||
|
-- RAISE NOTICE ''Frequency: %, Length: %(%), Basediff: %'', frequency, length, temp_txt, basediff;
|
||||||
|
|
||||||
|
-- Calculate the number of past periods between our base date and our earliest date
|
||||||
|
IF frequency = ''WEEKLY'' OR frequency = ''DAILY'' THEN
|
||||||
|
past_repeats := extract(''epoch'' from basediff)::INT8 / 86400;
|
||||||
|
-- RAISE NOTICE ''Days: %'', past_repeats;
|
||||||
|
IF frequency = ''WEEKLY'' THEN
|
||||||
|
past_repeats := past_repeats / 7;
|
||||||
|
END IF;
|
||||||
|
ELSE
|
||||||
|
past_repeats = extract( ''years'' from basediff );
|
||||||
|
IF frequency = ''MONTHLY'' THEN
|
||||||
|
past_repeats = (past_repeats *12) + extract( ''months'' from basediff );
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
past_repeats = (past_repeats / length) + 1;
|
||||||
|
|
||||||
|
-- Check that we have not exceeded the COUNT= limit
|
||||||
|
temp_txt := substring(repeatrule from ''COUNT=([0-9]+)(;|$)'');
|
||||||
|
count := temp_txt::int;
|
||||||
|
-- RAISE NOTICE ''Periods: %, Count: %(%)'', past_repeats, count, temp_txt;
|
||||||
|
IF ( count <= past_repeats ) THEN
|
||||||
|
RETURN NULL;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
temp_txt := substring(repeatrule from ''BYSETPOS=([0-9-]+)(;|$)'');
|
||||||
|
byday := substring(repeatrule from ''BYDAY=([0-9A-Z,]+-)(;|$)'');
|
||||||
|
IF byday IS NOT NULL AND frequency = ''MONTHLY'' THEN
|
||||||
|
-- Since this could move the date around a month we go back one
|
||||||
|
-- period just to be extra sure.
|
||||||
|
past_repeats = past_repeats - 1;
|
||||||
|
|
||||||
|
IF temp_txt IS NOT NULL THEN
|
||||||
|
-- Crudely hack the BYSETPOS onto the front of BYDAY. While this
|
||||||
|
-- is not as per rfc2445, RRULE syntax is so complex and overblown
|
||||||
|
-- that nobody correctly uses comma-separated BYDAY or BYSETPOS, and
|
||||||
|
-- certainly not within a MONTHLY RRULE.
|
||||||
|
byday := temp_txt || byday;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
past_repeats = past_repeats * length;
|
||||||
|
|
||||||
|
units := CASE
|
||||||
|
WHEN frequency = ''DAILY'' THEN ''days''
|
||||||
|
WHEN frequency = ''WEEKLY'' THEN ''weeks''
|
||||||
|
WHEN frequency = ''MONTHLY'' THEN ''months''
|
||||||
|
WHEN frequency = ''YEARLY'' THEN ''years''
|
||||||
|
END;
|
||||||
|
|
||||||
|
temp_txt := substring(repeatrule from ''BYMONTHDAY=([0-9,]+)(;|$)'');
|
||||||
|
bymonthday := temp_txt::int;
|
||||||
|
|
||||||
|
-- With all of the above calculation, this date should be close to (but less than)
|
||||||
|
-- the target, and we should only loop once or twice.
|
||||||
|
our_answer := basedate + (past_repeats::text || units)::interval;
|
||||||
|
|
||||||
|
loopcount := 1000; -- Not really needed, but stops an infinite loop if there is a bug!
|
||||||
|
LOOP
|
||||||
|
-- RAISE NOTICE ''Testing date: %'', our_answer;
|
||||||
|
IF frequency = ''WEEKLY'' THEN
|
||||||
|
-- Weekly repeats are only on specific days
|
||||||
|
-- I think this is not really right, since a WEEKLY on MO,WE,FR should
|
||||||
|
-- occur three times each week and this will only be once a week.
|
||||||
|
dow = substring( to_char( our_answer, ''DY'' ) for 2);
|
||||||
|
CONTINUE WHEN position( dow in byday ) = 0;
|
||||||
|
ELSIF frequency = ''MONTHLY'' AND byday IS NOT NULL THEN
|
||||||
|
-- This works fine, except that maybe there are multiple BYDAY
|
||||||
|
-- components. e.g. 1TU,3TU might be 1st & 3rd tuesdays.
|
||||||
|
our_answer := apply_month_byday( our_answer, byday );
|
||||||
|
ELSIF bymonthday IS NOT NULL AND frequency = ''MONTHLY'' AND bymonthday < 1 THEN
|
||||||
|
-- We do not deal with this situation at present
|
||||||
|
RAISE NOTICE ''The case of negative BYMONTHDAY is not handled yet.'';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
EXIT WHEN our_answer >= earliest;
|
||||||
|
|
||||||
|
loopcount := loopcount - 1;
|
||||||
|
IF loopcount < 0 THEN
|
||||||
|
RAISE EXCEPTION ''Could not cope with dates after % using % from %'', earliest, repeatrule, basedate;
|
||||||
|
RETURN NULL;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Increment for our next time through the loop...
|
||||||
|
our_answer := our_answer + (length::text || units)::interval;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN our_answer;
|
||||||
|
|
||||||
|
END;
|
||||||
|
' LANGUAGE 'plpgsql' IMMUTABLE STRICT;
|
||||||
@ -14,10 +14,10 @@ CREATE TABLE caldav_data (
|
|||||||
caldav_type TEXT,
|
caldav_type TEXT,
|
||||||
logged_user INT references usr(user_no),
|
logged_user INT references usr(user_no),
|
||||||
|
|
||||||
PRIMARY KEY ( user_no, vevent_name, vevent_etag )
|
PRIMARY KEY ( user_no, dav_name )
|
||||||
);
|
);
|
||||||
|
|
||||||
GRANT SELECT,INSERT,UPDATE,DELETE ON vevent_data TO general;
|
GRANT SELECT,INSERT,UPDATE,DELETE ON caldav_data TO general;
|
||||||
|
|
||||||
-- Not particularly needed, perhaps, except as a way to collect
|
-- Not particularly needed, perhaps, except as a way to collect
|
||||||
-- a bunch of valid iCalendar time zone specifications... :-)
|
-- a bunch of valid iCalendar time zone specifications... :-)
|
||||||
@ -31,30 +31,84 @@ GRANT SELECT,INSERT ON time_zone TO general;
|
|||||||
-- The parsed event. Here we have pulled those events apart somewhat.
|
-- The parsed event. Here we have pulled those events apart somewhat.
|
||||||
CREATE TABLE event (
|
CREATE TABLE event (
|
||||||
user_no INT references usr(user_no),
|
user_no INT references usr(user_no),
|
||||||
vevent_name TEXT,
|
dav_name TEXT,
|
||||||
vevent_etag TEXT,
|
dav_etag TEXT,
|
||||||
|
|
||||||
-- Extracted vEvent event data
|
-- Extracted vEvent event data
|
||||||
uid TEXT,
|
uid TEXT,
|
||||||
dtstamp TEXT,
|
created TIMESTAMP,
|
||||||
|
last_modified TIMESTAMP,
|
||||||
|
dtstamp TIMESTAMP,
|
||||||
dtstart TIMESTAMP WITH TIME ZONE,
|
dtstart TIMESTAMP WITH TIME ZONE,
|
||||||
dtend TIMESTAMP WITH TIME ZONE,
|
dtend TIMESTAMP WITH TIME ZONE,
|
||||||
|
due TIMESTAMP WITH TIME ZONE,
|
||||||
summary TEXT,
|
summary TEXT,
|
||||||
location TEXT,
|
location TEXT,
|
||||||
|
description TEXT,
|
||||||
|
priority INT,
|
||||||
class TEXT,
|
class TEXT,
|
||||||
transp TEXT,
|
transp TEXT,
|
||||||
description TEXT,
|
|
||||||
rrule TEXT,
|
rrule TEXT,
|
||||||
|
url TEXT,
|
||||||
|
percent_complete NUMERIC(7,2),
|
||||||
tz_id TEXT REFERENCES time_zone( tz_id ),
|
tz_id TEXT REFERENCES time_zone( tz_id ),
|
||||||
|
|
||||||
-- Cascade updates / deletes from the vevent_data table
|
-- Cascade updates / deletes from the caldav_data table
|
||||||
CONSTRAINT vevent_exists FOREIGN KEY ( user_no, vevent_name, vevent_etag )
|
CONSTRAINT caldav_exists FOREIGN KEY ( user_no, dav_name )
|
||||||
REFERENCES vevent_data ( user_no, vevent_name, vevent_etag )
|
REFERENCES caldav_data ( user_no, dav_name )
|
||||||
MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE
|
MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE
|
||||||
);
|
);
|
||||||
|
|
||||||
GRANT SELECT,INSERT,UPDATE,DELETE ON event TO general;
|
GRANT SELECT,INSERT,UPDATE,DELETE ON event TO general;
|
||||||
|
|
||||||
|
-- BEGIN:VTODO
|
||||||
|
-- CREATED:20060921T035148Z
|
||||||
|
-- LAST-MODIFIED:20060921T035301Z
|
||||||
|
-- DTSTAMP:20060921T035301Z
|
||||||
|
-- UID:9a495928-276c-406b-8acd-e0883dfe68e3
|
||||||
|
-- SUMMARY:Something to do
|
||||||
|
-- PRIORITY:0
|
||||||
|
-- CLASS:PUBLIC
|
||||||
|
-- DUE;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20060922T155149
|
||||||
|
-- X-MOZ-LOCATIONPATH:9a495928-276c-406b-8acd-e0883dfe68e3.ics
|
||||||
|
-- LOCATION:At work...
|
||||||
|
-- DESCRIPTION:This needs to be done.
|
||||||
|
-- URL:http://mcmillan.net.nz/
|
||||||
|
-- END:VTODO
|
||||||
|
|
||||||
|
-- The parsed todo. Here we have pulled those todos apart somewhat.
|
||||||
|
CREATE TABLE todo (
|
||||||
|
user_no INT references usr(user_no),
|
||||||
|
dav_name TEXT,
|
||||||
|
dav_etag TEXT,
|
||||||
|
|
||||||
|
-- Extracted VTODO data
|
||||||
|
uid TEXT,
|
||||||
|
created TIMESTAMP,
|
||||||
|
last_modified TIMESTAMP,
|
||||||
|
dtstamp TIMESTAMP,
|
||||||
|
dtstart TIMESTAMP WITH TIME ZONE,
|
||||||
|
dtend TIMESTAMP WITH TIME ZONE,
|
||||||
|
due TIMESTAMP WITH TIME ZONE,
|
||||||
|
priority INT,
|
||||||
|
summary TEXT,
|
||||||
|
location TEXT,
|
||||||
|
description TEXT,
|
||||||
|
class TEXT,
|
||||||
|
transp TEXT,
|
||||||
|
rrule TEXT,
|
||||||
|
url TEXT,
|
||||||
|
percent_complete NUMERIC(7,2),
|
||||||
|
tz_id TEXT REFERENCES time_zone( tz_id ),
|
||||||
|
|
||||||
|
-- Cascade updates / deletes from the caldav_data table
|
||||||
|
CONSTRAINT caldav_exists FOREIGN KEY ( user_no, dav_name )
|
||||||
|
REFERENCES caldav_data ( user_no, dav_name )
|
||||||
|
MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE
|
||||||
|
);
|
||||||
|
|
||||||
|
GRANT SELECT,INSERT,UPDATE,DELETE ON todo TO general;
|
||||||
|
|
||||||
-- Each user can be related to each other user. This mechanism can also
|
-- Each user can be related to each other user. This mechanism can also
|
||||||
-- be used to define groups of users, since some relationships are transitive.
|
-- be used to define groups of users, since some relationships are transitive.
|
||||||
CREATE TABLE relationship_type (
|
CREATE TABLE relationship_type (
|
||||||
|
|||||||
@ -7,9 +7,17 @@ dbg_error_log("delete", "DELETE method handler");
|
|||||||
$get_path = $_SERVER['PATH_INFO'];
|
$get_path = $_SERVER['PATH_INFO'];
|
||||||
$etag_none_match = str_replace('"','',$_SERVER["HTTP_IF_NONE_MATCH"]);
|
$etag_none_match = str_replace('"','',$_SERVER["HTTP_IF_NONE_MATCH"]);
|
||||||
|
|
||||||
$qry = new PgQuery( "SELECT * FROM vevent_data WHERE user_no = ? AND vevent_name = ? AND vevent_etag = ?;", $session->user_no, $get_path, $etag_none_match );
|
if ( $etag_none_match != '' ) {
|
||||||
|
/**
|
||||||
|
* etag_none_match is saying that we should only delete a row if it matches this etag
|
||||||
|
* (only rows not matching should exist afterwards, I guess.)
|
||||||
|
*/
|
||||||
|
$only_this_etag = " AND dav_etag = ".qpg($etag_none_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
$qry = new PgQuery( "SELECT * FROM caldav_data WHERE user_no = ? AND dav_name = ? $only_this_etag;", $session->user_no, $get_path );
|
||||||
if ( $qry->Exec("caldav-DELETE") && $qry->rows == 1 ) {
|
if ( $qry->Exec("caldav-DELETE") && $qry->rows == 1 ) {
|
||||||
$qry = new PgQuery( "DELETE FROM vevent_data WHERE user_no = ? AND vevent_name = ? AND vevent_etag = ?;", $session->user_no, $get_path, $etag_none_match );
|
$qry = new PgQuery( "DELETE FROM caldav_data WHERE user_no = ? AND dav_name = ? $only_this_etag;", $session->user_no, $get_path );
|
||||||
if ( $qry->Exec("caldav-DELETE") ) {
|
if ( $qry->Exec("caldav-DELETE") ) {
|
||||||
header("HTTP/1.1 200 OK");
|
header("HTTP/1.1 200 OK");
|
||||||
dbg_error_log( "delete", "DELETE: User: %d, ETag: %s, Path: %s", $session->user_no, $etag_none_match, $get_path);
|
dbg_error_log( "delete", "DELETE: User: %d, ETag: %s, Path: %s", $session->user_no, $etag_none_match, $get_path);
|
||||||
|
|||||||
@ -7,23 +7,23 @@ dbg_error_log("get", "GET method handler");
|
|||||||
$get_path = $_SERVER['PATH_INFO'];
|
$get_path = $_SERVER['PATH_INFO'];
|
||||||
$etag_none_match = str_replace('"','',$_SERVER["HTTP_IF_NONE_MATCH"]);
|
$etag_none_match = str_replace('"','',$_SERVER["HTTP_IF_NONE_MATCH"]);
|
||||||
|
|
||||||
$qry = new PgQuery( "SELECT * FROM vevent_data WHERE user_no = ? AND vevent_name = ? ;", $session->user_no, $get_path);
|
$qry = new PgQuery( "SELECT * FROM caldav_data WHERE user_no = ? AND dav_name = ? ;", $session->user_no, $get_path);
|
||||||
dbg_error_log("get", "%s", $qry->querystring );
|
dbg_error_log("get", "%s", $qry->querystring );
|
||||||
if ( $qry->Exec("GET") && $qry->rows == 1 ) {
|
if ( $qry->Exec("GET") && $qry->rows == 1 ) {
|
||||||
$event = $qry->Fetch();
|
$event = $qry->Fetch();
|
||||||
|
|
||||||
header("HTTP/1.1 200 OK");
|
header("HTTP/1.1 200 OK");
|
||||||
header("ETag: $event->vevent_etag");
|
header("ETag: $event->dav_etag");
|
||||||
header("Content-Type: text/calendar");
|
header("Content-Type: text/calendar");
|
||||||
|
|
||||||
print $event->vevent_data;
|
print $event->caldav_data;
|
||||||
|
|
||||||
dbg_error_log( "GET", "User: %d, ETag: %s, Path: %s", $session->user_no, $event->vevent_etag, $get_path);
|
dbg_error_log( "GET", "User: %d, ETag: %s, Path: %s", $session->user_no, $event->dav_etag, $get_path);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if ( $qry->rows != 1 ) {
|
else if ( $qry->rows != 1 ) {
|
||||||
header("HTTP/1.1 500 Internal Server Error");
|
header("HTTP/1.1 500 Internal Server Error");
|
||||||
dbg_error_log("ERROR", "Multiple rows match for User: %d, ETag: %s, Path: %s", $session->user_no, $event->vevent_etag, $get_path);
|
dbg_error_log("ERROR", "Multiple rows match for User: %d, ETag: %s, Path: %s", $session->user_no, $event->dav_etag, $get_path);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
header("HTTP/1.1 500 Infernal Server Error");
|
header("HTTP/1.1 500 Infernal Server Error");
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
dbg_error_log("OPTIONS", "method handler");
|
dbg_error_log("OPTIONS", "method handler");
|
||||||
header( "Content-type: text/plain");
|
header( "Content-type: text/plain");
|
||||||
header( "Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE, PROPFIND, PROPPATCH, LOCK, UNLOCK, REPORT, ACL");
|
// header( "Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE, PROPFIND, PROPPATCH, LOCK, UNLOCK, REPORT, ACL");
|
||||||
header( "DAV: 1, 2, 3, access-control, calendar-access");
|
header( "Allow: OPTIONS, GET, PUT, DELETE, REPORT");
|
||||||
|
// header( "DAV: 1, 2, 3, access-control, calendar-access");
|
||||||
|
header( "DAV: 1, calendar-access");
|
||||||
?>
|
?>
|
||||||
@ -28,7 +28,7 @@ if ( $etag_match == '*' || $etag_match == '' ) {
|
|||||||
* If they didn't send an etag_match header, we need to check if the PUT object already exists
|
* If they didn't send an etag_match header, we need to check if the PUT object already exists
|
||||||
* and we are hence updating it. And we just set our etag_match to that.
|
* and we are hence updating it. And we just set our etag_match to that.
|
||||||
*/
|
*/
|
||||||
$qry = new PgQuery( "SELECT * FROM vevent_data WHERE user_no=? AND vevent_name=?", $session->user_no, $put_path );
|
$qry = new PgQuery( "SELECT * FROM caldav_data WHERE user_no=? AND dav_name=?", $session->user_no, $put_path );
|
||||||
$qry->Exec("PUT");
|
$qry->Exec("PUT");
|
||||||
if ( $qry->rows > 1 ) {
|
if ( $qry->rows > 1 ) {
|
||||||
header("HTTP/1.1 500 Infernal Server Error");
|
header("HTTP/1.1 500 Infernal Server Error");
|
||||||
@ -37,7 +37,7 @@ if ( $etag_match == '*' || $etag_match == '' ) {
|
|||||||
}
|
}
|
||||||
elseif ( $qry->rows == 1 ) {
|
elseif ( $qry->rows == 1 ) {
|
||||||
$event = $qry->Fetch();
|
$event = $qry->Fetch();
|
||||||
$etag_match = $event->vevent_etag;
|
$etag_match = $event->dav_etag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,45 +45,54 @@ if ( $etag_match == '*' || $etag_match == '' ) {
|
|||||||
/**
|
/**
|
||||||
* If we got this far without an etag we must be inserting it.
|
* If we got this far without an etag we must be inserting it.
|
||||||
*/
|
*/
|
||||||
$qry = new PgQuery( "INSERT INTO vevent_data ( user_no, vevent_name, vevent_etag, vevent_data, logged_user ) VALUES( ?, ?, ?, ?, ?)",
|
$qry = new PgQuery( "INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user ) VALUES( ?, ?, ?, ?, ?, ?)",
|
||||||
$session->user_no, $put_path, $etag, $raw_post, $session->user_no );
|
$session->user_no, $put_path, $etag, $raw_post, $ev->type, $session->user_no );
|
||||||
$qry->Exec("PUT");
|
$qry->Exec("PUT");
|
||||||
|
|
||||||
header("HTTP/1.1 201 Created");
|
header("HTTP/1.1 201 Created");
|
||||||
header("ETag: $etag");
|
header("ETag: $etag");
|
||||||
dbg_error_log( "PUT", "INSERT INTO vevent_data ( user_no, vevent_name, vevent_etag, vevent_data, logged_user ) VALUES( %d, '%s', '%s', '%s', %d)",
|
|
||||||
$session->user_no, $put_path, $etag, $raw_post, $session->user_no );
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$qry = new PgQuery( "UPDATE vevent_data SET vevent_data=?, vevent_etag=?, logged_user=? WHERE user_no=? AND vevent_name=? AND vevent_etag=?",
|
$qry = new PgQuery( "UPDATE caldav_data SET caldav_data=?, dav_etag=?, caldav_type=?, logged_user=? WHERE user_no=? AND dav_name=? AND dav_etag=?",
|
||||||
$raw_post, $etag, $session->user_no, $session->user_no, $put_path, $etag_match );
|
$raw_post, $etag, $ev->type, $session->user_no, $session->user_no, $put_path, $etag_match );
|
||||||
$qry->Exec("PUT");
|
$qry->Exec("PUT");
|
||||||
|
|
||||||
header("HTTP/1.1 201 Replaced");
|
header("HTTP/1.1 201 Replaced");
|
||||||
header("ETag: $etag");
|
header("ETag: $etag");
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = "SET TIMEZONE TO ".qpg($ev->tz_locn).";";
|
if ( $ev->type == 'VEVENT' ) $table = 'event';
|
||||||
|
elseif ( $ev->type == 'VTODO' ) $table = 'todo';
|
||||||
|
|
||||||
|
$sql = ( $ev->tz_locn == '' ? '' : "SET TIMEZONE TO ".qpg($ev->tz_locn).";" );
|
||||||
|
|
||||||
if ( $etag_match == '*' || $etag_match == '' ) {
|
if ( $etag_match == '*' || $etag_match == '' ) {
|
||||||
$sql .= <<<EOSQL
|
$sql .= <<<EOSQL
|
||||||
INSERT INTO event (user_no, vevent_name, vevent_etag, uid, dtstamp, dtstart, dtend, summary, location, class, transp, description, rrule, tz_id)
|
INSERT INTO $table (user_no, dav_name, dav_etag, uid, dtstamp, dtstart, dtend, summary, location, class, transp,
|
||||||
VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
description, rrule, tz_id, last_modified, url, priority, created, due, percent_complete )
|
||||||
|
VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
EOSQL;
|
EOSQL;
|
||||||
|
|
||||||
$qry = new PgQuery( $sql, $session->user_no, $put_path, $etag, $ev->Get('uid'), $ev->Get('dtstamp'),
|
$qry = new PgQuery( $sql, $session->user_no, $put_path, $etag, $ev->Get('uid'), $ev->Get('dtstamp'),
|
||||||
$ev->Get('dtstart'), $ev->Get('dtend'), $ev->Get('summary'), $ev->Get('location'),
|
$ev->Get('dtstart'), $ev->Get('dtend'), $ev->Get('summary'), $ev->Get('location'),
|
||||||
$ev->Get('class'), $ev->Get('transp'), $ev->Get('description'), $ev->Get('rrule'), $ev->Get('tz_id') );
|
$ev->Get('class'), $ev->Get('transp'), $ev->Get('description'), $ev->Get('rrule'), $ev->Get('tz_id'),
|
||||||
|
$ev->Get('last-modified'), $ev->Get('url'), $ev->Get('priority'), $ev->Get('created'),
|
||||||
|
$ev->Get('due'), $ev->Get('percent-complete')
|
||||||
|
);
|
||||||
$qry->Exec("PUT");
|
$qry->Exec("PUT");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$sql = <<<EOSQL
|
$sql = <<<EOSQL
|
||||||
UPDATE event SET uid=?, dtstamp=?, dtstart=?, dtend=?, summary=?, location=?, class=?, transp=?, description=?, rrule=?, tz_id=?
|
UPDATE $table SET uid=?, dtstamp=?, dtstart=?, dtend=?, summary=?, location=?, class=?, transp=?, description=?, rrule=?,
|
||||||
WHERE user_no=? AND vevent_name=? AND vevent_etag=?
|
tz_id=?, last_modified=?, url=?, priority=?, dav_etag=?, due=?, percent_complete=?
|
||||||
|
WHERE user_no=? AND dav_name=?
|
||||||
EOSQL;
|
EOSQL;
|
||||||
|
|
||||||
$qry = new PgQuery( $sql, $ev->Get('uid'), $ev->Get('dtstamp'), $ev->Get('dtstart'), $ev->Get('dtend'), $ev->Get('summary'),
|
$qry = new PgQuery( $sql, $ev->Get('uid'), $ev->Get('dtstamp'), $ev->Get('dtstart'), $ev->Get('dtend'), $ev->Get('summary'),
|
||||||
$ev->Get('location'), $ev->Get('class'), $ev->Get('transp'), $ev->Get('description'), $ev->Get('rrule'),
|
$ev->Get('location'), $ev->Get('class'), $ev->Get('transp'), $ev->Get('description'), $ev->Get('rrule'),
|
||||||
$ev->Get('tz_id'), $session->user_no, $put_path, $etag );
|
$ev->Get('tz_id'), $ev->Get('last-modified'), $ev->Get('url'), $ev->Get('priority'), $etag,
|
||||||
|
$ev->Get('due'), $ev->Get('percent-complete'),
|
||||||
|
$session->user_no, $put_path );
|
||||||
$qry->Exec("PUT");
|
$qry->Exec("PUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,18 @@ foreach( $rpt_request AS $k => $v ) {
|
|||||||
|
|
||||||
switch ( $v['tag'] ) {
|
switch ( $v['tag'] ) {
|
||||||
|
|
||||||
|
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-MULTIGET':
|
||||||
|
dbg_log_array( "REPORT", "CALENDAR-MULTIGET", $v, true );
|
||||||
|
$report[$reportnum]['multiget'] = 1;
|
||||||
|
if ( $v['type'] == "open" ) {
|
||||||
|
$multiget_names = array();
|
||||||
|
}
|
||||||
|
else if ( $v['type'] == "close" ) {
|
||||||
|
$report[$reportnum]['get_names'] = $multiget_names;
|
||||||
|
unset($multiget_names);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DATA':
|
case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DATA':
|
||||||
dbg_log_array( "REPORT", "CALENDAR-DATA", $v, true );
|
dbg_log_array( "REPORT", "CALENDAR-DATA", $v, true );
|
||||||
if ( $v['type'] == "complete" ) {
|
if ( $v['type'] == "complete" ) {
|
||||||
@ -109,6 +121,12 @@ foreach( $rpt_request AS $k => $v ) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'DAV::HREF':
|
||||||
|
dbg_log_array( "REPORT", "DAV::HREF", $v, true );
|
||||||
|
if ( isset($report[$reportnum]['multiget']) ) {
|
||||||
|
$multiget_names[] = $v['value'];
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dbg_error_log( "REPORT", "Unhandled tag >>".$v['tag']."<<");
|
dbg_error_log( "REPORT", "Unhandled tag >>".$v['tag']."<<");
|
||||||
}
|
}
|
||||||
@ -172,29 +190,54 @@ REPORTHDR;
|
|||||||
if ( isset($report[$i]['calendar-event']) ) {
|
if ( isset($report[$i]['calendar-event']) ) {
|
||||||
if ( isset($report[$i]['include_href']) ) dbg_error_log( "REPORT", "Returning href event data" );
|
if ( isset($report[$i]['include_href']) ) dbg_error_log( "REPORT", "Returning href event data" );
|
||||||
if ( isset($report[$i]['include_data']) ) dbg_error_log( "REPORT", "Returning full event data" );
|
if ( isset($report[$i]['include_data']) ) dbg_error_log( "REPORT", "Returning full event data" );
|
||||||
$sql = "SELECT * FROM vevent_data NATURAL JOIN event ";
|
$sql = "SELECT * FROM caldav_data NATURAL JOIN event WHERE caldav_type = 'VEVENT' ";
|
||||||
$where = "";
|
$where = "";
|
||||||
if ( isset( $report[$i]['start'] ) ) {
|
if ( isset( $report[$i]['start'] ) ) {
|
||||||
$where = "WHERE dtend >= ".qpg($report[$i]['start'])."::timestamp with time zone ";
|
$where = "AND (dtend >= ".qpg($report[$i]['start'])."::timestamp with time zone ";
|
||||||
|
$where .= "OR calculate_later_timestamp(".qpg($report[$i]['start'])."::timestamp with time zone,dtend,rrule) >= ".qpg($report[$i]['start'])."::timestamp with time zone) ";
|
||||||
}
|
}
|
||||||
if ( isset( $report[$i]['end'] ) ) {
|
if ( isset( $report[$i]['end'] ) ) {
|
||||||
if ( $where != "" ) $where .= "AND ";
|
$where .= "AND dtstart <= ".qpg($report[$i]['end'])."::timestamp with time zone ";
|
||||||
$where .= "dtstart <= ".qpg($report[$i]['end'])."::timestamp with time zone ";
|
|
||||||
}
|
}
|
||||||
$sql .= $where;
|
$sql .= $where;
|
||||||
$qry = new PgQuery( $sql );
|
$qry = new PgQuery( $sql );
|
||||||
if ( $qry->Exec() && $qry->rows > 0 ) {
|
if ( $qry->Exec() && $qry->rows > 0 ) {
|
||||||
while( $event = $qry->Fetch() ) {
|
while( $event = $qry->Fetch() ) {
|
||||||
$calhref = ( isset($report[$i]['include_href']) ? sprintf( $calendar_href_tpl, $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->vevent_name ) : "" );
|
$calhref = ( isset($report[$i]['include_href']) ? sprintf( $calendar_href_tpl, $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->dav_name ) : "" );
|
||||||
$caldata = ( isset($report[$i]['include_data']) ? sprintf( $calendar_data_tpl, $event->vevent_data ) : "" );
|
$caldata = ( isset($report[$i]['include_data']) ? sprintf( $calendar_data_tpl, $event->caldav_data ) : "" );
|
||||||
printf( $response_tpl, $calhref, $event->vevent_etag, $caldata );
|
printf( $response_tpl, $calhref, $event->dav_etag, $caldata );
|
||||||
dbg_error_log("REPORT", "ETag >>%s<< >>http://%s:%s%s%s<<", $event->vevent_etag,
|
dbg_error_log("REPORT", "ETag >>%s<< >>http://%s:%s%s%s<<", $event->dav_etag,
|
||||||
$_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->vevent_name);
|
$_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->dav_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($report[$i]['calendar-todo']) ) {
|
if ( isset($report[$i]['calendar-todo']) ) {
|
||||||
if ( isset($report[$i]['include_data']) ) dbg_error_log( "REPORT", "FIXME: Not returning full todo data" );
|
/**
|
||||||
|
* Produce VTODO data.
|
||||||
|
*/
|
||||||
|
if ( isset($report[$i]['include_href']) ) dbg_error_log( "REPORT", "Returning href event data" );
|
||||||
|
if ( isset($report[$i]['include_data']) ) dbg_error_log( "REPORT", "Returning full event data" );
|
||||||
|
$sql = "SELECT * FROM caldav_data NATURAL JOIN todo WHERE caldav_type = 'VTODO' ";
|
||||||
|
$where = "";
|
||||||
|
if ( isset( $report[$i]['start'] ) ) {
|
||||||
|
$where = "AND (dtend >= ".qpg($report[$i]['start'])."::timestamp with time zone ";
|
||||||
|
$where .= "OR calculate_later_timestamp(".qpg($report[$i]['start'])."::timestamp with time zone,dtend,rrule) >= ".qpg($report[$i]['start'])."::timestamp with time zone) ";
|
||||||
|
}
|
||||||
|
if ( isset( $report[$i]['end'] ) ) {
|
||||||
|
$where .= "AND dtstart <= ".qpg($report[$i]['end'])."::timestamp with time zone ";
|
||||||
|
}
|
||||||
|
$sql .= $where;
|
||||||
|
$qry = new PgQuery( $sql );
|
||||||
|
if ( $qry->Exec() && $qry->rows > 0 ) {
|
||||||
|
while( $event = $qry->Fetch() ) {
|
||||||
|
$calhref = ( isset($report[$i]['include_href']) ? sprintf( $calendar_href_tpl, $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->dav_name ) : "" );
|
||||||
|
$caldata = ( isset($report[$i]['include_data']) ? sprintf( $calendar_data_tpl, $event->caldav_data ) : "" );
|
||||||
|
printf( $response_tpl, $calhref, $event->dav_etag, $caldata );
|
||||||
|
dbg_error_log("REPORT", "ETag >>%s<< >>http://%s:%s%s%s<<", $event->dav_etag,
|
||||||
|
$_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['SCRIPT_NAME'], $event->dav_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ( isset($report[$i]['calendar-freebusy']) ) {
|
if ( isset($report[$i]['calendar-freebusy']) ) {
|
||||||
if ( isset($report[$i]['include_data']) ) dbg_error_log( "REPORT", "FIXME: Not returning full freebusy data" );
|
if ( isset($report[$i]['include_data']) ) dbg_error_log( "REPORT", "FIXME: Not returning full freebusy data" );
|
||||||
|
|||||||
161
inc/vEvent.php
161
inc/vEvent.php
@ -38,6 +38,12 @@ class vEvent {
|
|||||||
*/
|
*/
|
||||||
var $tz_locn;
|
var $tz_locn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of iCalendar data VEVENT/VTODO
|
||||||
|
* @var type string
|
||||||
|
*/
|
||||||
|
var $type;
|
||||||
|
|
||||||
/**#@-*/
|
/**#@-*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,13 +55,10 @@ class vEvent {
|
|||||||
global $c;
|
global $c;
|
||||||
|
|
||||||
// Probably a good idea to always have values for these things...
|
// Probably a good idea to always have values for these things...
|
||||||
$this->properties['tz_id'] = $c->local_tzid;
|
if ( isset($c->local_tzid ) ) $this->properties['tz_id'] = $c->local_tzid;
|
||||||
$this->properties['modified'] = time();
|
$this->properties['dtstamp'] = date('Ymd\THis');
|
||||||
$this->properties['sequence'] = 1;
|
$this->properties['sequence'] = 1;
|
||||||
$this->properties['uid'] = sprintf( "%s@%s", time() * 1000 + rand(0,1000), $c->domain_name);
|
$this->properties['uid'] = sprintf( "%s@%s", time() * 1000 + rand(0,1000), $c->domain_name);
|
||||||
$this->properties['guid'] = sprintf( "%s@%s", time() * 1000 + rand(0,1000), $c->domain_name);
|
|
||||||
$this->properties['duration'] = "PT1H";
|
|
||||||
$this->properties['status'] = "TENTATIVE";
|
|
||||||
|
|
||||||
if ( !isset($args) || !is_array($args) ) return;
|
if ( !isset($args) || !is_array($args) ) return;
|
||||||
|
|
||||||
@ -87,7 +90,14 @@ class vEvent {
|
|||||||
|
|
||||||
switch( $state ) {
|
switch( $state ) {
|
||||||
case 0:
|
case 0:
|
||||||
if ( $v == 'BEGIN:VEVENT' ) $state = $v;
|
if ( $v == 'BEGIN:VEVENT' ) {
|
||||||
|
$state = $v;
|
||||||
|
$this->type = 'VEVENT';
|
||||||
|
}
|
||||||
|
else if ( $v == 'BEGIN:VTODO' ) {
|
||||||
|
$state = $v;
|
||||||
|
$this->type = 'VTODO';
|
||||||
|
}
|
||||||
else if ( $v == 'BEGIN:VTIMEZONE' ) $state = $v;
|
else if ( $v == 'BEGIN:VTIMEZONE' ) $state = $v;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -95,6 +105,10 @@ class vEvent {
|
|||||||
if ( $v == 'END:VEVENT' ) $state = 0;
|
if ( $v == 'END:VEVENT' ) $state = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'BEGIN:VTODO':
|
||||||
|
if ( $v == 'END:VTODO' ) $state = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'BEGIN:VTIMEZONE':
|
case 'BEGIN:VTIMEZONE':
|
||||||
if ( $v == 'END:VTIMEZONE' ) {
|
if ( $v == 'END:VTIMEZONE' ) {
|
||||||
$state = 0;
|
$state = 0;
|
||||||
@ -103,7 +117,7 @@ class vEvent {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $state == 'BEGIN:VEVENT' && $state != $v ) {
|
if ( ($state == 'BEGIN:VEVENT' || $state == 'BEGIN:VTODO') && $state != $v ) {
|
||||||
list( $parameter, $value ) = preg_split('/:/', $v );
|
list( $parameter, $value ) = preg_split('/:/', $v );
|
||||||
if ( preg_match('/^DT[A-Z]+;TZID=/', $parameter) ) {
|
if ( preg_match('/^DT[A-Z]+;TZID=/', $parameter) ) {
|
||||||
list( $parameter, $tz_id ) = preg_split('/;/', $parameter );
|
list( $parameter, $tz_id ) = preg_split('/;/', $parameter );
|
||||||
@ -133,22 +147,27 @@ class vEvent {
|
|||||||
* them into something that PostgreSQL can understand...
|
* them into something that PostgreSQL can understand...
|
||||||
*/
|
*/
|
||||||
function DealWithTimeZones() {
|
function DealWithTimeZones() {
|
||||||
$qry = new PgQuery( "SELECT tz_locn FROM time_zone WHERE tz_id = ?;", $this->properties['TZID'] );
|
if ( isset($c->save_time_zone_defs) ) {
|
||||||
if ( $qry->Exec('vEvent') && $qry->rows == 1 ) {
|
$qry = new PgQuery( "SELECT tz_locn FROM time_zone WHERE tz_id = ?;", $this->properties['TZID'] );
|
||||||
$row = $qry->Fetch();
|
if ( $qry->Exec('vEvent') && $qry->rows == 1 ) {
|
||||||
$this->tz_locn = $row->tz_locn;
|
$row = $qry->Fetch();
|
||||||
}
|
$this->tz_locn = $row->tz_locn;
|
||||||
else {
|
|
||||||
if ( !isset($this->tz_locn) ) {
|
|
||||||
// In case there was no X-LIC-LOCATION defined, let's hope there is something in the TZID
|
|
||||||
$this->tz_locn = preg_replace('/^.*([a-z]+\/[a-z]+)$/i','$1',$this->properties['TZID'] );
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !isset($this->tz_locn) ) {
|
||||||
|
// In case there was no X-LIC-LOCATION defined, let's hope there is something in the TZID
|
||||||
|
$this->tz_locn = preg_replace('/^.*([a-z]+\/[a-z]+)$/i','$1',$this->properties['TZID'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isset($c->save_time_zone_defs) && $qry->rows != 1 ) {
|
||||||
$qry2 = new PgQuery( "INSERT INTO time_zone (tz_id, tz_locn, tz_spec) VALUES( ?, ?, ? );",
|
$qry2 = new PgQuery( "INSERT INTO time_zone (tz_id, tz_locn, tz_spec) VALUES( ?, ?, ? );",
|
||||||
$this->properties['TZID'], $this->tz_locn, $this->properties['VTIMEZONE'] );
|
$this->properties['TZID'], $this->tz_locn, $this->properties['VTIMEZONE'] );
|
||||||
$qry2->Exec("vEvent");
|
$qry2->Exec("vEvent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of a property
|
* Get the value of a property
|
||||||
*/
|
*/
|
||||||
@ -156,6 +175,114 @@ class vEvent {
|
|||||||
return $this->properties[strtoupper($key)];
|
return $this->properties[strtoupper($key)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put the value of a property
|
||||||
|
*/
|
||||||
|
function Put( $key, $value ) {
|
||||||
|
return $this->properties[strtoupper($key)] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a PostgreSQL Date Format string suitable for returning iCal dates
|
||||||
|
*/
|
||||||
|
function SqlDateFormat() {
|
||||||
|
return "'IYYYMMDD\"T\"HH24MISS'";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a PostgreSQL Date Format string suitable for returning iCal durations
|
||||||
|
* - this doesn't work for negative intervals, but events should not have such!
|
||||||
|
*/
|
||||||
|
function SqlDurationFormat() {
|
||||||
|
return "'\"PT\"HH24\"H\"MI\"M\"'";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
CALSCALE:GREGORIAN
|
||||||
|
PRODID:-//Ximian//NONSGML Evolution Calendar//EN
|
||||||
|
VERSION:2.0
|
||||||
|
BEGIN:VEVENT
|
||||||
|
UID:20060918T005755Z-21151-1000-1-7@ubu
|
||||||
|
DTSTAMP:20060918T005755Z
|
||||||
|
DTSTART;TZID=/softwarestudio.org/Olson_20011030_5/Pacific/Auckland:
|
||||||
|
20060918T153000
|
||||||
|
DTEND;TZID=/softwarestudio.org/Olson_20011030_5/Pacific/Auckland:
|
||||||
|
20060918T160000
|
||||||
|
SUMMARY:Lunch
|
||||||
|
X-EVOLUTION-CALDAV-HREF:http:
|
||||||
|
//andrew@mycaldav/caldav.php/andrew/20060918T005757Z.ics
|
||||||
|
BEGIN:VALARM
|
||||||
|
X-EVOLUTION-ALARM-UID:20060918T005755Z-21149-1000-1-12@ubu
|
||||||
|
ACTION:DISPLAY
|
||||||
|
TRIGGER;VALUE=DURATION;RELATED=START:-PT15M
|
||||||
|
DESCRIPTION:Lunch
|
||||||
|
END:VALARM
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VTIMEZONE
|
||||||
|
TZID:/softwarestudio.org/Olson_20011030_5/Pacific/Auckland
|
||||||
|
X-LIC-LOCATION:Pacific/Auckland
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+1300
|
||||||
|
TZOFFSETTO:+1200
|
||||||
|
TZNAME:NZST
|
||||||
|
DTSTART:19700315T030000
|
||||||
|
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SU;BYMONTH=3
|
||||||
|
END:STANDARD
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+1200
|
||||||
|
TZOFFSETTO:+1300
|
||||||
|
TZNAME:NZDT
|
||||||
|
DTSTART:19701004T020000
|
||||||
|
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=10
|
||||||
|
END:DAYLIGHT
|
||||||
|
END:VTIMEZONE
|
||||||
|
END:VCALENDAR
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Render the vEvent object as a text string which is a single VEVENT
|
||||||
|
*/
|
||||||
|
function Render( ) {
|
||||||
|
$interesting = array( "uid", "dtstamp", "dtstart", "dtend", "duration", "summary",
|
||||||
|
"location", "description", "action", "class", "transp", "sequence");
|
||||||
|
|
||||||
|
$result = <<<EOTXT
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
CALSCALE:GREGORIAN
|
||||||
|
PRODID:-//Catalyst.Net.NZ//NONSGML AWL Calendar//EN
|
||||||
|
VERSION:2.0
|
||||||
|
BEGIN:VEVENT
|
||||||
|
|
||||||
|
EOTXT;
|
||||||
|
|
||||||
|
foreach( $interesting AS $k => $v ) {
|
||||||
|
$v = strtoupper($v);
|
||||||
|
if ( isset($this->properties[$v]) )
|
||||||
|
$result .= sprintf("%s:%s\n", $v, $this->properties[$v]);
|
||||||
|
}
|
||||||
|
$result .= <<<EOTXT
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
||||||
|
|
||||||
|
EOTXT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
$result = sprintf( $format,
|
||||||
|
$this->properties['UID'],
|
||||||
|
$this->properties['DTSTART'],
|
||||||
|
$this->properties['DURATION'],
|
||||||
|
$this->properties['SUMMARY'],
|
||||||
|
$this->properties['LOCATION']
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@ -41,5 +41,6 @@
|
|||||||
<item url="htdocs/help.php" uploadstatus="1" />
|
<item url="htdocs/help.php" uploadstatus="1" />
|
||||||
<item url="htdocs/roles.php" uploadstatus="1" />
|
<item url="htdocs/roles.php" uploadstatus="1" />
|
||||||
<item url="htdocs/relationships.php" uploadstatus="1" />
|
<item url="htdocs/relationships.php" uploadstatus="1" />
|
||||||
|
<item url="dba/caldav_functions.sql" />
|
||||||
</project>
|
</project>
|
||||||
</webproject>
|
</webproject>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user