mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-07-29 13:19:26 +00:00
Initial support for draft-daboo-webdav-sync-01
This commit is contained in:
parent
64571a284e
commit
24a8971080
@ -44,6 +44,7 @@ GRANT SELECT,UPDATE
|
||||
ON session_session_id_seq
|
||||
ON principal_principal_id_seq
|
||||
ON principal_type_principal_type_id_seq
|
||||
ON sync_tokens_sync_token_seq
|
||||
|
||||
GRANT SELECT,INSERT
|
||||
ON time_zone
|
||||
|
||||
@ -3,10 +3,391 @@
|
||||
-- as an integer to make calculation of merged permissions simpler
|
||||
-- through simple binary 'AND'
|
||||
|
||||
CREATE or REPLACE FUNCTION legacy_privilege_to_bits( TEXT ) RETURNS BIT(24) AS $$
|
||||
DECLARE
|
||||
in_priv ALIAS FOR $1;
|
||||
out_bits BIT(24);
|
||||
BEGIN
|
||||
out_bits := 0::BIT(24);
|
||||
IF in_priv ~* 'A' THEN
|
||||
out_bits = ~ out_bits;
|
||||
RETURN out_bits;
|
||||
END IF;
|
||||
|
||||
-- The CALDAV:read-free-busy privilege MUST be aggregated in the DAV:read privilege.
|
||||
-- 1 DAV:read
|
||||
-- 512 CalDAV:read-free-busy
|
||||
-- 4096 CALDAV:schedule-query-freebusy
|
||||
IF in_priv ~* 'R' THEN
|
||||
out_bits := out_bits | 4609::BIT(24);
|
||||
END IF;
|
||||
|
||||
-- DAV:write => DAV:write MUST contain DAV:bind, DAV:unbind, DAV:write-properties and DAV:write-content
|
||||
-- 2 DAV:write-properties
|
||||
-- 4 DAV:write-content
|
||||
-- 64 DAV:bind
|
||||
-- 128 DAV:unbind
|
||||
IF in_priv ~* 'W' THEN
|
||||
out_bits := out_bits | 198::BIT(24);
|
||||
END IF;
|
||||
|
||||
-- 64 DAV:bind
|
||||
IF in_priv ~* 'B' THEN
|
||||
out_bits := out_bits | 64::BIT(24);
|
||||
END IF;
|
||||
|
||||
-- 128 DAV:unbind
|
||||
IF in_priv ~* 'U' THEN
|
||||
out_bits := out_bits | 128::BIT(24);
|
||||
END IF;
|
||||
|
||||
-- 512 CalDAV:read-free-busy
|
||||
-- 4096 CALDAV:schedule-query-freebusy
|
||||
IF in_priv ~* 'F' THEN
|
||||
out_bits := out_bits | 4608::BIT(24);
|
||||
END IF;
|
||||
|
||||
RETURN out_bits;
|
||||
END
|
||||
$$
|
||||
LANGUAGE 'PlPgSQL' IMMUTABLE STRICT;
|
||||
|
||||
-- This legacy conversion function will eventually be removed, once all logic
|
||||
-- has been converted to use bitmaps, or to use the bits_to_priv() output.
|
||||
--
|
||||
-- NOTE: Round-trip through this and then back through legacy_privilege_to_bits
|
||||
-- function is lossy! Through legacy_privilege_to_bits() and back through
|
||||
-- this one is not.
|
||||
--
|
||||
CREATE or REPLACE FUNCTION bits_to_legacy_privilege( BIT(24) ) RETURNS TEXT AS $$
|
||||
DECLARE
|
||||
in_bits ALIAS FOR $1;
|
||||
out_priv TEXT;
|
||||
BEGIN
|
||||
out_priv := '';
|
||||
IF in_bits = (~ 0::BIT(24)) THEN
|
||||
out_priv = 'A';
|
||||
RETURN out_priv;
|
||||
END IF;
|
||||
|
||||
-- The CALDAV:read-free-busy privilege MUST be aggregated in the DAV:read privilege.
|
||||
-- 1 DAV:read
|
||||
-- 512 CalDAV:read-free-busy
|
||||
-- 4096 CALDAV:schedule-query-freebusy
|
||||
IF (in_bits & 4609::BIT(24)) != 0::BIT(24) THEN
|
||||
IF (in_bits & 1::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := 'R';
|
||||
ELSE
|
||||
out_priv := 'F';
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- DAV:write => DAV:write MUST contain DAV:bind, DAV:unbind, DAV:write-properties and DAV:write-content
|
||||
-- 2 DAV:write-properties
|
||||
-- 4 DAV:write-content
|
||||
-- 64 DAV:bind
|
||||
-- 128 DAV:unbind
|
||||
IF (in_bits & 198::BIT(24)) != 0::BIT(24) THEN
|
||||
IF (in_bits & 6::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || 'W';
|
||||
ELSE
|
||||
IF (in_bits & 64::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || 'B';
|
||||
END IF;
|
||||
IF (in_bits & 128::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || 'U';
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
RETURN out_priv;
|
||||
END
|
||||
$$
|
||||
LANGUAGE 'PlPgSQL' IMMUTABLE STRICT;
|
||||
|
||||
CREATE or REPLACE FUNCTION get_permissions( INT, INT ) RETURNS TEXT AS $$
|
||||
DECLARE
|
||||
in_from ALIAS FOR $1;
|
||||
in_to ALIAS FOR $2;
|
||||
out_confers TEXT;
|
||||
bit_confers BIT(24);
|
||||
group_role_no INT;
|
||||
tmp_txt TEXT;
|
||||
dbg TEXT DEFAULT '';
|
||||
r RECORD;
|
||||
counter INT;
|
||||
BEGIN
|
||||
-- Self can always have full access
|
||||
IF in_from = in_to THEN
|
||||
RETURN 'A';
|
||||
END IF;
|
||||
|
||||
-- dbg := 'S-';
|
||||
SELECT bits_to_legacy_privilege(r1.confers) INTO out_confers FROM relationship r1
|
||||
WHERE r1.from_user = in_from AND r1.to_user = in_to AND NOT usr_is_role(r1.to_user,'Group');
|
||||
IF FOUND THEN
|
||||
RETURN dbg || out_confers;
|
||||
END IF;
|
||||
-- RAISE NOTICE 'No simple relationships between % and %', in_from, in_to;
|
||||
|
||||
SELECT bit_or(r1.confers & r2.confers) INTO bit_confers
|
||||
FROM relationship r1
|
||||
JOIN relationship r2 ON r1.to_user=r2.from_user
|
||||
WHERE r1.from_user=in_from AND r2.to_user=in_to
|
||||
AND r2.from_user IN (SELECT user_no FROM roles LEFT JOIN role_member USING(role_no) WHERE role_name='Group');
|
||||
IF bit_confers != 0::BIT(24) THEN
|
||||
RETURN dbg || bits_to_legacy_privilege(bit_confers);
|
||||
END IF;
|
||||
|
||||
RETURN '';
|
||||
-- RAISE NOTICE 'No complex relationships between % and %', in_from, in_to;
|
||||
|
||||
SELECT bits_to_legacy_privilege(r1.confers) INTO out_confers FROM relationship r1 LEFT OUTER JOIN relationship r2 ON(r1.to_user = r2.to_user)
|
||||
WHERE r1.from_user = in_from AND r2.from_user = in_to AND r1.from_user != r2.from_user
|
||||
AND NOT EXISTS( SELECT 1 FROM relationship r3 WHERE r3.from_user = r1.to_user ) ;
|
||||
|
||||
IF FOUND THEN
|
||||
-- dbg := 'H-';
|
||||
-- RAISE NOTICE 'Permissions to shared group % ', out_confers;
|
||||
RETURN dbg || out_confers;
|
||||
END IF;
|
||||
|
||||
-- RAISE NOTICE 'No common group relationships between % and %', in_from, in_to;
|
||||
|
||||
RETURN '';
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT;
|
||||
|
||||
|
||||
CREATE or REPLACE FUNCTION get_group_role_no() RETURNS INT AS $$
|
||||
SELECT role_no FROM roles WHERE role_name = 'Group'
|
||||
$$ LANGUAGE 'SQL' IMMUTABLE;
|
||||
|
||||
CREATE or REPLACE FUNCTION has_legacy_privilege( INT, TEXT, INT ) RETURNS BOOLEAN AS $$
|
||||
DECLARE
|
||||
in_from ALIAS FOR $1;
|
||||
in_legacy_privilege ALIAS FOR $2;
|
||||
in_to ALIAS FOR $3;
|
||||
in_confers BIT(24);
|
||||
group_role_no INT;
|
||||
BEGIN
|
||||
-- Self can always have full access
|
||||
IF in_from = in_to THEN
|
||||
RETURN TRUE;
|
||||
END IF;
|
||||
|
||||
SELECT get_group_role_no() INTO group_role_no;
|
||||
SELECT legacy_privilege_to_bits(in_legacy_privilege) INTO in_confers;
|
||||
|
||||
IF EXISTS(SELECT 1 FROM relationship WHERE from_user = in_from AND to_user = in_to
|
||||
AND (in_confers & confers) = in_confers
|
||||
AND NOT EXISTS(SELECT 1 FROM role_member WHERE to_user = user_no AND role_no = group_role_no) ) THEN
|
||||
-- A direct relationship from A to B that grants sufficient
|
||||
-- RAISE NOTICE 'Permissions directly granted';
|
||||
RETURN TRUE;
|
||||
END IF;
|
||||
|
||||
IF EXISTS( SELECT 1 FROM relationship r1 JOIN relationship r2 ON r1.to_user=r2.from_user
|
||||
WHERE (in_confers & r1.confers & r2.confers) = in_confers
|
||||
AND r1.from_user=in_from AND r2.to_user=in_to
|
||||
AND r2.from_user IN (SELECT user_no FROM role_member WHERE role_no=group_role_no) ) THEN
|
||||
-- An indirect relationship from A to B via group G that grants sufficient
|
||||
-- RAISE NOTICE 'Permissions mediated via group';
|
||||
RETURN TRUE;
|
||||
END IF;
|
||||
|
||||
IF EXISTS( SELECT 1 FROM relationship r1 JOIN relationship r2 ON r1.to_user=r2.to_user
|
||||
WHERE (in_confers & r1.confers & r2.confers) = in_confers
|
||||
AND r1.from_user=in_from AND r2.from_user=in_to
|
||||
AND r2.to_user IN (SELECT user_no FROM role_member WHERE role_no=group_role_no)
|
||||
AND NOT EXISTS(SELECT 1 FROM relationship WHERE from_user=r2.to_user) ) THEN
|
||||
-- An indirect reflexive relationship from both A & B to group G which grants sufficient
|
||||
-- RAISE NOTICE 'Permissions to shared group';
|
||||
RETURN TRUE;
|
||||
END IF;
|
||||
|
||||
-- RAISE NOTICE 'No common group relationships between % and %', in_from, in_to;
|
||||
|
||||
RETURN FALSE;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT;
|
||||
|
||||
|
||||
-- Given a verbose DAV: or CalDAV: privilege name return the bitmask
|
||||
CREATE or REPLACE FUNCTION privilege_to_bits( TEXT ) RETURNS BIT(24) AS $$
|
||||
DECLARE
|
||||
raw_priv ALIAS FOR $1;
|
||||
in_priv TEXT;
|
||||
BEGIN
|
||||
in_priv := trim(lower(regexp_replace(raw_priv, '^.*:', '')));
|
||||
IF in_priv = 'all' THEN
|
||||
RETURN ~ 0::BIT(24);
|
||||
END IF;
|
||||
|
||||
RETURN (CASE
|
||||
WHEN in_priv = 'read' THEN 4609 -- 1 + 512 + 4096
|
||||
WHEN in_priv = 'write' THEN 198 -- 2 + 4 + 64 + 128
|
||||
WHEN in_priv = 'write-properties' THEN 2
|
||||
WHEN in_priv = 'write-content' THEN 4
|
||||
WHEN in_priv = 'unlock' THEN 8
|
||||
WHEN in_priv = 'read-acl' THEN 16
|
||||
WHEN in_priv = 'read-current-user-privilege-set' THEN 32
|
||||
WHEN in_priv = 'bind' THEN 64
|
||||
WHEN in_priv = 'unbind' THEN 128
|
||||
WHEN in_priv = 'write-acl' THEN 256
|
||||
WHEN in_priv = 'read-free-busy' THEN 4608 -- 512 + 4096
|
||||
WHEN in_priv = 'schedule-deliver' THEN 7168 -- 1024 + 2048 + 4096
|
||||
WHEN in_priv = 'schedule-deliver-invite' THEN 1024
|
||||
WHEN in_priv = 'schedule-deliver-reply' THEN 2048
|
||||
WHEN in_priv = 'schedule-query-freebusy' THEN 4096
|
||||
WHEN in_priv = 'schedule-send' THEN 57344 -- 8192 + 16384 + 32768
|
||||
WHEN in_priv = 'schedule-send-invite' THEN 8192
|
||||
WHEN in_priv = 'schedule-send-reply' THEN 16384
|
||||
WHEN in_priv = 'schedule-send-freebusy' THEN 32768
|
||||
ELSE 0 END)::BIT(24);
|
||||
END
|
||||
$$
|
||||
LANGUAGE 'PlPgSQL' IMMUTABLE STRICT;
|
||||
|
||||
|
||||
-- Given an array of verbose DAV: or CalDAV: privilege names return the bitmask
|
||||
CREATE or REPLACE FUNCTION privilege_to_bits( TEXT[] ) RETURNS BIT(24) AS $$
|
||||
DECLARE
|
||||
raw_privs ALIAS FOR $1;
|
||||
in_priv TEXT;
|
||||
out_bits BIT(24);
|
||||
i INT;
|
||||
all BIT(24);
|
||||
start INT;
|
||||
finish INT;
|
||||
BEGIN
|
||||
out_bits := 0::BIT(24);
|
||||
all := ~ out_bits;
|
||||
SELECT array_lower(raw_privs,1) INTO start;
|
||||
SELECT array_upper(raw_privs,1) INTO finish;
|
||||
FOR i IN start .. finish LOOP
|
||||
SELECT out_bits | privilege_to_bits(raw_privs[i]) INTO out_bits;
|
||||
IF out_bits = all THEN
|
||||
RETURN all;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN out_bits;
|
||||
END
|
||||
$$
|
||||
LANGUAGE 'PlPgSQL' IMMUTABLE STRICT;
|
||||
|
||||
|
||||
-- This legacy conversion function will eventually be removed, once all logic
|
||||
-- has been converted to use bitmaps, or to use the bits_to_priv() output.
|
||||
--
|
||||
-- NOTE: Round-trip through this and then back through privilege_to_bits
|
||||
-- function is lossy! Through privilege_to_bits() and back through
|
||||
-- this one is not.
|
||||
--
|
||||
CREATE or REPLACE FUNCTION bits_to_privilege( BIT(24) ) RETURNS TEXT[] AS $$
|
||||
DECLARE
|
||||
in_bits ALIAS FOR $1;
|
||||
out_priv TEXT[];
|
||||
BEGIN
|
||||
out_priv := ARRAY[]::text[];
|
||||
IF in_bits = (~ 0::BIT(24)) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:all'];
|
||||
END IF;
|
||||
|
||||
IF (in_bits & 513::BIT(24)) != 0::BIT(24) THEN
|
||||
IF (in_bits & 1::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:read'];
|
||||
END IF;
|
||||
IF (in_bits & 512::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:read-free-busy'];
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF (in_bits & 198::BIT(24)) != 0::BIT(24) THEN
|
||||
IF (in_bits & 198::BIT(24)) = 198::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:write'];
|
||||
ELSE
|
||||
IF (in_bits & 2::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:write-properties'];
|
||||
END IF;
|
||||
IF (in_bits & 4::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:write-content'];
|
||||
END IF;
|
||||
IF (in_bits & 64::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:bind'];
|
||||
END IF;
|
||||
IF (in_bits & 128::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:unbind'];
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF (in_bits & 8::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:unlock'];
|
||||
END IF;
|
||||
|
||||
IF (in_bits & 16::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:read-acl'];
|
||||
END IF;
|
||||
|
||||
IF (in_bits & 32::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:read-current-user-privilege-set'];
|
||||
END IF;
|
||||
|
||||
IF (in_bits & 256::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['DAV:write-acl'];
|
||||
END IF;
|
||||
|
||||
IF (in_bits & 7168::BIT(24)) != 0::BIT(24) THEN
|
||||
IF (in_bits & 7168::BIT(24)) = 7168::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:schedule-deliver'];
|
||||
ELSE
|
||||
IF (in_bits & 1024::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:schedule-deliver-invite'];
|
||||
END IF;
|
||||
IF (in_bits & 2048::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:schedule-deliver-reply'];
|
||||
END IF;
|
||||
IF (in_bits & 4096::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:schedule-query-freebusy'];
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF (in_bits & 57344::BIT(24)) != 0::BIT(24) THEN
|
||||
IF (in_bits & 57344::BIT(24)) = 57344::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:schedule-send'];
|
||||
ELSE
|
||||
IF (in_bits & 8192::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:schedule-send-invite'];
|
||||
END IF;
|
||||
IF (in_bits & 16384::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:schedule-send-reply'];
|
||||
END IF;
|
||||
IF (in_bits & 32768::BIT(24)) != 0::BIT(24) THEN
|
||||
out_priv := out_priv || ARRAY['caldav:schedule-send-freebusy'];
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
RETURN out_priv;
|
||||
END
|
||||
$$
|
||||
LANGUAGE 'PlPgSQL' IMMUTABLE STRICT;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BEGIN;
|
||||
SELECT check_db_revision(1,2,5);
|
||||
|
||||
\i dba/better_perms.sql
|
||||
|
||||
-- DAV Privileges implementation
|
||||
--
|
||||
|
||||
@ -14,8 +14,10 @@ CREATE TABLE sync_tokens (
|
||||
|
||||
CREATE TABLE sync_changes (
|
||||
sync_time TIMESTAMP WITH TIME ZONE DEFAULT current_timestamp,
|
||||
status INT2,
|
||||
dav_id INT8 REFERENCES calendar_item(dav_id)
|
||||
collection_id INT8 REFERENCES collection(collection_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
sync_status INT,
|
||||
dav_id INT8 REFERENCES calendar_item(dav_id) ON DELETE SET NULL ON UPDATE RESTRICT,
|
||||
dav_name TEXT
|
||||
);
|
||||
|
||||
SELECT new_db_revision(1,2,7, 'Juli' );
|
||||
@ -38,8 +40,8 @@ BEGIN
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
SELECT dav_id INTO tmp_int FROM calendar_item WHERE dav_name = in_dav_name;
|
||||
INSERT INTO sync_changes ( collection_id, status, dav_id)
|
||||
VALUES( in_collection_id, in_status::INT2, tmp_int);
|
||||
INSERT INTO sync_changes ( collection_id, sync_status, dav_id, dav_name)
|
||||
VALUES( in_collection_id, in_status, tmp_int, in_dav_name);
|
||||
RETURN TRUE;
|
||||
END
|
||||
$$ LANGUAGE 'PlPgSQL' VOLATILE STRICT;
|
||||
@ -51,14 +53,16 @@ DECLARE
|
||||
in_collection_id ALIAS FOR $2;
|
||||
tmp_int INT8;
|
||||
BEGIN
|
||||
SELECT 1 INTO tmp_int FROM sync_changes
|
||||
WHERE collection_id = in_collection_id
|
||||
AND sync_time > (SELECT modification_time FROM sync_tokens WHERE sync_token = in_old_sync_token)
|
||||
LIMIT 1;
|
||||
IF NOT FOUND THEN
|
||||
RETURN in_old_sync_token;
|
||||
IF in_old_sync_token > 0 THEN
|
||||
SELECT 1 INTO tmp_int FROM sync_changes
|
||||
WHERE collection_id = in_collection_id
|
||||
AND sync_time > (SELECT modification_time FROM sync_tokens WHERE sync_token = in_old_sync_token)
|
||||
LIMIT 1;
|
||||
IF NOT FOUND THEN
|
||||
RETURN in_old_sync_token;
|
||||
END IF;
|
||||
END IF;
|
||||
SELECT nextval('dav_id_seq') INTO tmp_int;
|
||||
SELECT nextval('sync_tokens_sync_token_seq') INTO tmp_int;
|
||||
INSERT INTO sync_tokens(collection_id, sync_token) VALUES( in_collection_id, tmp_int );
|
||||
RETURN tmp_int;
|
||||
END
|
||||
|
||||
@ -823,6 +823,14 @@ EOSQL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ID of the collection of, or containing this request
|
||||
*/
|
||||
function CollectionId( ) {
|
||||
return $this->collection_id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the array of supported privileges converted into XMLElements
|
||||
*/
|
||||
|
||||
@ -81,41 +81,16 @@ class DAVResource
|
||||
global $c;
|
||||
|
||||
foreach( $row AS $k => $v ) {
|
||||
dbg_error_log( 'resource', 'Processing resource property "%s" has "%s".', $row->dav_name, $k );
|
||||
switch ( $k ) {
|
||||
case 'dav_name':
|
||||
$this->href = ConstructURL( '/'.$this->dav_name.'/', true );
|
||||
$this->{$k} = $v;
|
||||
break;
|
||||
|
||||
case 'dav_etag':
|
||||
$this->unique_tag = $this->dav_etag;
|
||||
break;
|
||||
|
||||
case 'caldav_data':
|
||||
$this->content = $this->caldav_data;
|
||||
break;
|
||||
|
||||
case 'updated':
|
||||
$this->modified = ISODateToHTTPDate($this->updated);
|
||||
break;
|
||||
|
||||
case 'created':
|
||||
$this->modified = ISODateToHTTPDate($this->joined);
|
||||
break;
|
||||
|
||||
case 'username':
|
||||
$this->owner = ConstructURL( '/'.$this->username.'/', true );;
|
||||
$this->principal_url = ConstructURL( '/'.$this->username.'/', true );;
|
||||
$this->unique_tag = '"'.$v.'"';
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset($this->content) ) {
|
||||
$this->contenttype = 'http/unix-directory';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -127,9 +102,13 @@ class DAVResource
|
||||
|
||||
if ( $reply === null ) $reply = $GLOBALS['reply'];
|
||||
|
||||
dbg_error_log( 'caldav', 'Processing "%s" on "%s".', $tag, $this->path );
|
||||
dbg_error_log( 'resource', 'Processing "%s" on "%s".', $tag, $this->dav_name );
|
||||
|
||||
switch( $tag ) {
|
||||
case 'DAV::href':
|
||||
$prop->NewElement('href', ConstructURL($this->dav_name) );
|
||||
break;
|
||||
|
||||
case 'DAV::getcontenttype':
|
||||
$prop->NewElement('getcontenttype', $this->contenttype );
|
||||
break;
|
||||
@ -142,13 +121,13 @@ class DAVResource
|
||||
$prop->NewElement('displayname', $this->displayname );
|
||||
break;
|
||||
|
||||
case 'DAV::getlastmodified':
|
||||
$prop->NewElement('getlastmodified', $this->modified );
|
||||
break;
|
||||
// case 'DAV::getlastmodified':
|
||||
// $prop->NewElement('getlastmodified', $this->modified );
|
||||
// break;
|
||||
|
||||
case 'DAV::creationdate':
|
||||
$prop->NewElement('creationdate', $this->created );
|
||||
break;
|
||||
// case 'DAV::creationdate':
|
||||
// $prop->NewElement('creationdate', $this->created );
|
||||
// break;
|
||||
|
||||
case 'DAV::getcontentlanguage':
|
||||
$locale = (isset($c->current_locale) ? $c->current_locale : '');
|
||||
@ -156,10 +135,10 @@ class DAVResource
|
||||
$prop->NewElement('getcontentlanguage', $locale );
|
||||
break;
|
||||
|
||||
case 'DAV::owner':
|
||||
// After a careful reading of RFC3744 we see that this must be the principal-URL of the owner
|
||||
$reply->DAVElement( $prop, 'owner', $reply->href( $this->principal_url ) );
|
||||
break;
|
||||
// case 'DAV::owner':
|
||||
// // After a careful reading of RFC3744 we see that this must be the principal-URL of the owner
|
||||
// $reply->DAVElement( $prop, 'owner', $reply->href( $this->principal_url) ) );
|
||||
// break;
|
||||
|
||||
// Empty tag responses.
|
||||
case 'DAV::alternate-URI-set':
|
||||
@ -172,7 +151,7 @@ class DAVResource
|
||||
$not_found[] = $reply->Tag($tag);
|
||||
}
|
||||
else {
|
||||
$prop->NewElement('getetag', $this->etag );
|
||||
$prop->NewElement('getetag', $this->unique_tag );
|
||||
}
|
||||
break;
|
||||
|
||||
@ -189,23 +168,61 @@ class DAVResource
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DAV::sync-token':
|
||||
if ( $this->_is_collection ) {
|
||||
$prop->NewElement('sync-token', $this->NewSyncToken() );
|
||||
}
|
||||
else {
|
||||
$not_found[] = $reply->Tag($tag);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dbg_error_log( 'caldav', 'Request for unsupported property "%s" of path "%s".', $tag, $this->href );
|
||||
dbg_error_log( 'resource', 'Request for unsupported property "%s" of path "%s".', $tag, $this->href );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct XML propstat fragment for this resource
|
||||
*
|
||||
* @param array $properties The requested properties for this resource
|
||||
*
|
||||
* @return string An XML fragment with the requested properties for this resource
|
||||
*/
|
||||
function GetPropStat( $properties ) {
|
||||
global $session, $c, $request, $reply;
|
||||
|
||||
dbg_error_log('resource',': GetPropStat: href "%s"', $this->dav_name );
|
||||
|
||||
$prop = new XMLElement('prop');
|
||||
$denied = array();
|
||||
$not_found = array();
|
||||
foreach( $properties AS $k => $tag ) {
|
||||
dbg_error_log( 'resource', 'Looking at resource "%s" for property [%s]"%s".', $this->href, $k, $tag );
|
||||
if ( ! $this->ResourceProperty($tag, $prop, $reply) ) {
|
||||
dbg_error_log( 'resource', 'Request for unsupported property "%s" of resource "%s".', $tag, $this->href );
|
||||
$not_found[] = $reply->Tag($tag);
|
||||
}
|
||||
}
|
||||
$status = new XMLElement('status', 'HTTP/1.1 200 OK' );
|
||||
|
||||
$elements = array( new XMLElement( 'propstat', array($prop,$status) ) );
|
||||
|
||||
if ( count($denied) > 0 ) {
|
||||
$status = new XMLElement('status', 'HTTP/1.1 403 Forbidden' );
|
||||
$noprop = new XMLElement('prop');
|
||||
foreach( $denied AS $k => $v ) {
|
||||
$noprop->NewElement( $v );
|
||||
}
|
||||
$elements[] = new XMLElement( 'propstat', array( $noprop, $status) );
|
||||
}
|
||||
|
||||
if ( count($not_found) > 0 ) {
|
||||
$status = new XMLElement('status', 'HTTP/1.1 404 Not Found' );
|
||||
$noprop = new XMLElement('prop');
|
||||
foreach( $not_found AS $k => $v ) {
|
||||
$noprop->NewElement( $v );
|
||||
}
|
||||
$elements[] = new XMLElement( 'propstat', array( $noprop, $status) );
|
||||
}
|
||||
return $elements;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render XML for this resource
|
||||
*
|
||||
@ -228,14 +245,6 @@ class DAVResource
|
||||
dbg_error_log( 'principal', 'Request for unsupported property "%s" of principal "%s".', $tag, $this->username );
|
||||
$not_found[] = $reply->Tag($tag);
|
||||
}
|
||||
|
||||
default:
|
||||
if ( ! $request->ServerProperty( $tag, $prop, $reply ) ) {
|
||||
dbg_error_log( 'principal', 'Request for unsupported property "%s" of principal "%s".', $tag, $this->username );
|
||||
$not_found[] = $reply->Tag($tag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $props_only ) return $prop;
|
||||
|
||||
@ -66,15 +66,22 @@ else {
|
||||
/**
|
||||
* We read the resource first, so we can check if it matches (or does not match)
|
||||
*/
|
||||
$qry = new PgQuery( "SELECT cd.dav_etag, ci.uid FROM caldav_data cd JOIN calendar_item ci USING (dav_id) WHERE cd.user_no = ? AND cd.dav_name = ?;", $request->user_no, $request->path );
|
||||
$escaped_path = qpg($request->path);
|
||||
$qry = new PgQuery( "SELECT cd.dav_etag, ci.uid, cd.collection_id FROM caldav_data cd JOIN calendar_item ci USING (dav_id) WHERE cd.user_no = ? AND cd.dav_name = $escaped_path;", $request->user_no );
|
||||
if ( $qry->Exec("DELETE") && $qry->rows == 1 ) {
|
||||
$delete_row = $qry->Fetch();
|
||||
if ( (isset($request->etag_if_match) && $request->etag_if_match != $delete_row->dav_etag) ) {
|
||||
$request->DoResponse( 412, translate("Resource has changed on server - not deleted") );
|
||||
}
|
||||
$qry = new PgQuery( "DELETE FROM caldav_data WHERE user_no = ? AND dav_name = ?;", $request->user_no, $request->path );
|
||||
|
||||
$collection_id = $delete_row->collection_id;
|
||||
$sql = <<<EOSQL
|
||||
DELETE FROM caldav_data WHERE collection_id = $collection_id AND dav_name = $escaped_path;
|
||||
SELECT write_sync_change( $collection_id, 404, $escaped_path);
|
||||
EOSQL;
|
||||
$qry = new PgQuery( $sql );
|
||||
if ( $qry->Exec("DELETE") ) {
|
||||
$qry = new PgQuery( "DELETE FROM property WHERE dav_name = ?;", $request->path ); $qry->Exec("DELETE"); /** @todo we should write a trigger to delete property records when caldav_data or collection is deleted */
|
||||
$qry = new PgQuery( "DELETE FROM property WHERE dav_name = $escaped_path;" ); $qry->Exec("DELETE"); /** @todo we should write a trigger to delete property records when caldav_data or collection is deleted */
|
||||
@dbg_error_log( "DELETE", "DELETE: User: %d, ETag: %s, Path: %s", $session->user_no, $request->etag_if_match, $request->path);
|
||||
if ( function_exists('log_caldav_action') ) {
|
||||
log_caldav_action( 'DELETE', $delete_row->uid, $request->user_no, $request->collection_id, $request->path );
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
require("DAVObject.php");
|
||||
require("DAVResource.php");
|
||||
$responses = array();
|
||||
|
||||
/**
|
||||
@ -11,13 +11,17 @@ if ( !isset($sync_token) ) $sync_token = 0;
|
||||
$sync_token = intval($sync_token);
|
||||
dbg_error_log( 'sync', " sync-token: %s", $sync_token );
|
||||
|
||||
$props = $xmltree->GetPath('/DAV::sync-collection/DAV::prop');
|
||||
|
||||
$props = $xmltree->GetElements('DAV::prop');
|
||||
$v = $props[0];
|
||||
$props = $v->GetContent();
|
||||
$proplist = array();
|
||||
foreach( $props AS $k => $v ) {
|
||||
$proplist[] = $v->GetContent();
|
||||
$proplist[] = $v->GetTag();
|
||||
}
|
||||
|
||||
function display_status( $status_code ) {
|
||||
return sprintf( 'HTTP/1.1 %03d %s', $status_code, getStatusMessage($status_code) );
|
||||
return sprintf( 'HTTP/1.1 %03d %s', intval($status_code), getStatusMessage($status_code) );
|
||||
}
|
||||
|
||||
$sql = "SELECT new_sync_token(?,?)";
|
||||
@ -25,22 +29,42 @@ $qry = new PgQuery($sql, $sync_token, $request->CollectionId());
|
||||
if ( !$qry->Exec("REPORT",__LINE__,__FILE__) || $qry->rows <= 0 ) {
|
||||
$request->DoResponse( 500, translate("Database error") );
|
||||
}
|
||||
$row = $qry->Fetch();
|
||||
$new_token = $row->new_sync_token;
|
||||
|
||||
$sql = "SELECT * FROM collection LEFT JOIN sync_changes USING(collection_id) sync_changes LEFT JOIN calendar_item USING (dav_id) LEFT JOIN caldav_data USING (dav_id) WHERE collection_id = ? AND sync_time > (SELECT modification_time FROM sync_tokens WHERE sync_token = ?)";
|
||||
$qry = new PgQuery($sql, $request->CollectionId(), $sync_token);
|
||||
if ( $sync_token == 0 ) {
|
||||
$sql = <<<EOSQL
|
||||
SELECT *, 201 AS sync_status FROM collection
|
||||
LEFT JOIN caldav_data USING (collection_id)
|
||||
LEFT JOIN calendar_item USING (dav_id)
|
||||
WHERE collection.collection_id = ?
|
||||
EOSQL;
|
||||
$qry = new PgQuery($sql, $request->CollectionId());
|
||||
}
|
||||
else {
|
||||
$sql = <<<EOSQL
|
||||
SELECT * FROM collection LEFT JOIN sync_changes USING(collection_id)
|
||||
LEFT JOIN calendar_item USING (dav_id)
|
||||
LEFT JOIN caldav_data USING (dav_id)
|
||||
WHERE collection.collection_id = ?
|
||||
AND sync_time > (SELECT modification_time FROM sync_tokens WHERE sync_token = ?)
|
||||
EOSQL;
|
||||
$qry = new PgQuery($sql, $request->CollectionId(), $sync_token);
|
||||
}
|
||||
|
||||
if ( $qry->Exec("REPORT",__LINE__,__FILE__) && $qry->rows > 0 ) {
|
||||
if ( $qry->Exec("REPORT",__LINE__,__FILE__) ) {
|
||||
while( $object = $qry->Fetch() ) {
|
||||
$resultset = array(
|
||||
new XMLElement( 'href', $object->href ),
|
||||
new XMLElement( 'status', display_status($object->status) )
|
||||
new XMLElement( 'href', ConstructURL($object->dav_name) ),
|
||||
new XMLElement( 'status', display_status($object->sync_status) )
|
||||
);
|
||||
if ( $status != 404 ) {
|
||||
$dav_object = new DavObject($object);
|
||||
$resultset[] = $dav_object->GetPropStat( $proplist );
|
||||
$dav_resource = new DAVResource($object);
|
||||
$resultset = array_merge( $resultset, $dav_resource->GetPropStat($proplist) );
|
||||
}
|
||||
$responses[] = new XMLElement( 'sync-response', $resultset );
|
||||
}
|
||||
$responses[] = new XMLElement( 'sync-token', $new_token );
|
||||
}
|
||||
else {
|
||||
$request->DoResponse( 500, translate("Database error") );
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
|
||||
ETag: "d668266633188d6d2690a2eb491bba0c"
|
||||
Content-Length: 404
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<multistatus xmlns="DAV:">
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-token>1</sync-token>
|
||||
</multistatus>
|
||||
19
testing/tests/regression-suite/099-REPORT-sync-initial.test
Normal file
19
testing/tests/regression-suite/099-REPORT-sync-initial.test
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Check for support of REPORT sync-collection with no sync-token
|
||||
#
|
||||
TYPE=REPORT
|
||||
URL=http://mycaldav/caldav.php/user1/home/
|
||||
HEADER=User-agent: sync-collection initial REPORT
|
||||
HEADER=Content-type: text/xml
|
||||
HEAD
|
||||
|
||||
BEGINDATA
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:sync-collection xmlns:D="DAV:">
|
||||
<D:sync-token/>
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
</D:sync-collection>
|
||||
ENDDATA
|
||||
|
||||
161
testing/tests/regression-suite/598-REPORT-sync-initial.result
Normal file
161
testing/tests/regression-suite/598-REPORT-sync-initial.result
Normal file
@ -0,0 +1,161 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
|
||||
ETag: "7ab7cf2174a67bf4fc26271956be7d90"
|
||||
Content-Length: 4528
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<multistatus xmlns="DAV:">
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"5f050eca5480bbebbe9428222570913d"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"421abf7e4848d2fecbf64217ed205d4b"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/71e2ae82-7870-11db-c6d6-f6927c144649.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"0d7a68984bf525342d22b8924a57e8e2"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"8f581a053df6d833254756dfd7553d37"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"e8060931f30c1798ac58ffbe4ec0bffc"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/b1679f77-673d-4f46-b3eb-2420e1bba301.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"a2990674708634a311bb98a59865ca50"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/0575d895-a006-4ed8-9be6-0d1b6b6b1f96.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"00ad5eb1eb5507884710b0b66aa5d5c4"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/917b9e47-b748-4550-a566-657fbe672447.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"cb3d9dc3e8c157f53eba3ea0e1e0f146"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/2178279a-aec2-471f-832d-1f6df6203f2f.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"509b0f0d8a3363379f9f5727f5dd74a0"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"ac90acd649c25070b1a2a17fb31a105a"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/1906b3ca-4890-468a-9b58-1de74bf2c716.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"5def8ae2b20893a1c7f4dbaeb008f2f1"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/9d050be7-8a02-4355-8ed3-02a9fc5f473f.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"08a435c2abaf38f4a50a997343c098a7"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"a1c6404d61190f9574e2bfd69383f144"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/20061101T073004Z.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"c3658901fd4689d4a1e1d6f08601ef4f"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-token>2</sync-token>
|
||||
</multistatus>
|
||||
19
testing/tests/regression-suite/598-REPORT-sync-initial.test
Normal file
19
testing/tests/regression-suite/598-REPORT-sync-initial.test
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Check for support of REPORT sync-collection with no sync-token
|
||||
#
|
||||
TYPE=REPORT
|
||||
URL=http://mycaldav/caldav.php/user1/home/
|
||||
HEADER=User-agent: sync-collection initial REPORT
|
||||
HEADER=Content-type: text/xml
|
||||
HEAD
|
||||
|
||||
BEGINDATA
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:sync-collection xmlns:D="DAV:">
|
||||
<D:sync-token/>
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
</D:sync-collection>
|
||||
ENDDATA
|
||||
|
||||
161
testing/tests/regression-suite/599-REPORT-sync-changed.result
Normal file
161
testing/tests/regression-suite/599-REPORT-sync-changed.result
Normal file
@ -0,0 +1,161 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Date: Dow, 01 Jan 2000 00:00:00 GMT
|
||||
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
|
||||
ETag: "1e80e92dfce8e43ed452a56e350b577b"
|
||||
Content-Length: 4525
|
||||
Content-Type: text/xml; charset="utf-8"
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<multistatus xmlns="DAV:">
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/20061101T073004Z.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"c3658901fd4689d4a1e1d6f08601ef4f"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"a1c6404d61190f9574e2bfd69383f144"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/9d050be7-8a02-4355-8ed3-02a9fc5f473f.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"08a435c2abaf38f4a50a997343c098a7"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/1906b3ca-4890-468a-9b58-1de74bf2c716.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"5def8ae2b20893a1c7f4dbaeb008f2f1"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"ac90acd649c25070b1a2a17fb31a105a"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/2178279a-aec2-471f-832d-1f6df6203f2f.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"509b0f0d8a3363379f9f5727f5dd74a0"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/917b9e47-b748-4550-a566-657fbe672447.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"cb3d9dc3e8c157f53eba3ea0e1e0f146"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/0575d895-a006-4ed8-9be6-0d1b6b6b1f96.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"00ad5eb1eb5507884710b0b66aa5d5c4"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/b1679f77-673d-4f46-b3eb-2420e1bba301.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"a2990674708634a311bb98a59865ca50"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"e8060931f30c1798ac58ffbe4ec0bffc"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"8f581a053df6d833254756dfd7553d37"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/71e2ae82-7870-11db-c6d6-f6927c144649.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"0d7a68984bf525342d22b8924a57e8e2"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"421abf7e4848d2fecbf64217ed205d4b"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href>
|
||||
<status>HTTP/1.1 201 Created</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"5f050eca5480bbebbe9428222570913d"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-response>
|
||||
<href>/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
<propstat>
|
||||
<prop>
|
||||
<getetag>"5f050eca5480bbebbe9428222570913d"</getetag>
|
||||
</prop>
|
||||
<status>HTTP/1.1 200 OK</status>
|
||||
</propstat>
|
||||
</sync-response>
|
||||
<sync-token>3</sync-token>
|
||||
</multistatus>
|
||||
19
testing/tests/regression-suite/599-REPORT-sync-changed.test
Normal file
19
testing/tests/regression-suite/599-REPORT-sync-changed.test
Normal file
@ -0,0 +1,19 @@
|
||||
#
|
||||
# Check for support of REPORT sync-collection with no sync-token
|
||||
#
|
||||
TYPE=REPORT
|
||||
URL=http://mycaldav/caldav.php/user1/home/
|
||||
HEADER=User-agent: sync-collection changes REPORT
|
||||
HEADER=Content-type: text/xml
|
||||
HEAD
|
||||
|
||||
BEGINDATA
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:sync-collection xmlns:D="DAV:">
|
||||
<D:sync-token>1</D:sync-token>
|
||||
<D:prop>
|
||||
<D:getetag/>
|
||||
</D:prop>
|
||||
</D:sync-collection>
|
||||
ENDDATA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user