From c8e0efc3ecb9926675fc3583d6d035dc10be7565 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 20 Oct 2007 11:57:54 +1300 Subject: [PATCH 001/189] Fix references to components of the version. --- inc/always.php.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/always.php.in b/inc/always.php.in index f226bfe3..f453126d 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -83,8 +83,8 @@ $c->code_version = 0; $c->version_string = '0.7.0~rc3'; // The actual version # is replaced into that during the build /release process if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) { $c->code_major = $matches[1]; - $c->code_minor = $matches[1]; - $c->code_patch = $matches[1]; + $c->code_minor = $matches[2]; + $c->code_patch = $matches[3]; $c->code_version = (($c->code_major * 1000) + $c->code_minor).".".$c->code_patch; } dbg_error_log("caldav", "Version %s (%d.%d.%d) == %s", $c->code_pkgver, $c->code_major, $c->code_minor, $c->code_patch, $c->code_version); From 07e17a3701395951a3c56bc5729e985a4dbae144 Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Tue, 23 Oct 2007 09:35:24 +1300 Subject: [PATCH 002/189] State how to make LDAP use an anonymous bind initially. --- config/example-config.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/example-config.php b/config/example-config.php index 66334922..6a8817d3 100644 --- a/config/example-config.php +++ b/config/example-config.php @@ -169,8 +169,12 @@ $c->admin_email ='calendar-admin@example.com'; //$c->authenticate_hook['config'] = array( // 'host' => 'www.tennaxia.net', //host name of your LDAP Server // 'port' => '389', //port + + /* For the initial bind to be anonymous leave bindDN and passDN + commented out */ // 'bindDN'=> 'cn=manager,cn=internal,dc=tennaxia,dc=net', //DN to bind to this server enabling to perform request // 'passDN'=> 'xxxxxxxx', //Password of the previous bindDN to bind to this server enabling to perform request + // 'protocolVersion' => '3', //Version of LDAP protocol to use // 'baseDNUsers'=> 'dc=tennaxia,dc=net', //where to look at valid user // 'filterUsers' => 'objectClass=kolabInetOrgPerson', //filter which must validate a user according to RFC4515, i.e. surrounded by brackets @@ -227,4 +231,4 @@ $c->admin_email ='calendar-admin@example.com'; // $c->local_tzid; -?> \ No newline at end of file +?> From c84cd7bcb143d7ed02ea4dbcbf51d78c9765c165 Mon Sep 17 00:00:00 2001 From: Maxime Delorme Date: Tue, 23 Oct 2007 21:37:40 +1300 Subject: [PATCH 003/189] Refactoring caldav-PUT to allow calling from a different code path. --- inc/caldav-PUT-functions.php | 219 +++++++++++++++++++++++++++++------ inc/caldav-PUT.php | 125 +------------------- 2 files changed, 183 insertions(+), 161 deletions(-) diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index 34df4264..7deee23b 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -8,7 +8,39 @@ include_once("iCalendar.php"); -function controlRequestContainer( $username, $user_no, $path, $context ) { +/** +* This function launches an error +* @param boolean $caldav_context Whether we are responding via CalDAV or interactively +* @param int $user_no the user wich will receive this ics file +* @param string $path the $path where it will be store such as /user_foo/home/ +* @param boolean $caldav_context Whether we are responding via CalDAV or interactively +* @param string $message An optional error message to return to the client +* @param int $error_no An optional value for the HTTP error code +*/ +function rollback_on_error( $caldav_context, $user_no, $path, $message='', $error_no=500 ) { + if ( !$message ) $message = translate("Database error"); + $qry = new PgQuery("ROLLBACK;"); $qry->Exec("PUT-collection"); + if ( $caldav_context ) { + global $request; + $request->DoResponse( $error_no, $message ); + } + else { + global $c; + $c->messages[] = sprintf("Status: %d, Message: %s, User: %d, Path: %s", $error_no, $message, $user_no, $path); + } +} + + + +/** +* Work out the location we are doing the PUT to, and check that we have the rights to +* do the needful. +* @param string $username The name of the destination user +* @param int $user_no The user making the change +* @param string $path The DAV path the resource is bing PUT to +* @param boolean $caldav_context Whether we are responding via CalDAV or interactively +*/ +function controlRequestContainer( $username, $user_no, $path, $caldav_context ) { // Check to see if the path is like /foo /foo/bar or /foo/bar/baz etc. (not ending with a '/', but contains at least one) if ( preg_match( '#^(.*/)([^/]+)$#', $path, $matches ) ) {//( @@ -34,14 +66,7 @@ function controlRequestContainer( $username, $user_no, $path, $context ) { $sql = "SELECT * FROM collection WHERE user_no = ? AND dav_name = ?;"; $qry = new PgQuery( $sql, $user_no, $request_container ); if ( ! $qry->Exec("PUT") ) { - if($context){ - global $request; - $request->DoResponse( 500, translate("Error querying database.") ); - } - else { - global $c; - $c->messages[] = sprintf("Status: %d, Message: %s, User: %d, Path: %s", 500, translate("Error querying database."),$user_no,$path); - } + rollback_on_error( $caldav_context, $user_no, $path ); } if ( $qry->rows == 0 ) { if ( preg_match( '#^(.*/)([^/]+/)$#', $request_container, $matches ) ) {//( @@ -58,39 +83,24 @@ function controlRequestContainer( $username, $user_no, $path, $context ) { return $is_collection; } -/** -* This function launches an error -* @param int $user_no the user wich will receive this ics file -* @param string $path the $path where it will be store such as /user_foo/home/ -* @param boolean $context is true if this function is called from a way where $request is defined -*/ -function rollback_on_error($context,$user_no,$path) { - $qry = new PgQuery("ROLLBACK;"); $qry->Exec("PUT-collection"); - if($context){ - global $request; - $request->DoResponse( 500, translate("Database error") ); - } - else { - global $c; - $c->messages[] = sprintf("Status: %d, Message: %s, User: %d, Path: %s", 500, translate("Database error"),$user_no,$path); - } -} - /** * This function will import a whole calendar * @param string $ics_content the ics file to import * @param int $user_no the user wich will receive this ics file * @param string $path the $path where it will be store such as /user_foo/home/ -* @param boolean $context is true if this function is called from a way where $request is defined +* @param boolean $caldav_context Whether we are responding via CalDAV or interactively */ -function import_collection($ics_content, $user_no, $path,$context){ +function import_collection( $ics_content, $user_no, $path, $caldav_context ) { + global $c; // According to RFC2445 we should always end with CRLF, but the CalDAV spec says // that normalising XML parses often muck with it and may remove the CR. $icalendar = preg_replace('/\r?\n /', '', $ics_content ); - $fh = fopen('/tmp/PUT-2.txt','w'); - fwrite($fh,$icalendar); - fclose($fh); + if ( isset($c->dbg['ALL']) || isset($c->dbg['put']) ) { + $fh = fopen('/tmp/PUT-2.txt','w'); + fwrite($fh,$icalendar); + fclose($fh); + } $lines = preg_split('/\r?\n/', $icalendar ); @@ -132,7 +142,7 @@ function import_collection($ics_content, $user_no, $path,$context){ } } $qry = new PgQuery("BEGIN; DELETE FROM calendar_item WHERE user_no=? AND dav_name ~ ?; DELETE FROM caldav_data WHERE user_no=? AND dav_name ~ ?;", $user_no, $path.'[^/]+$', $user_no, $path.'[^/]+$'); - if ( !$qry->Exec("PUT") ) rollback_on_error($context,$user_no,$path); + if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path ); foreach( $events AS $k => $event ) { dbg_error_log( "PUT", "Putting event %d with data: %s", $k, $event['data'] ); @@ -142,7 +152,7 @@ function import_collection($ics_content, $user_no, $path,$context){ $event_path = sprintf( "%s%d.ics", $path, $k); $qry = new PgQuery( "INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp )", $user_no, $event_path, $etag, $icalendar, $ic->type, $session->user_no ); - if ( !$qry->Exec("PUT") ) rollback_on_error($context,$user_no,$path); + if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path ); $sql = ""; if ( preg_match(':^(Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Brazil|Canada|Chile|Etc|Europe|Indian|Mexico|Mideast|Pacific|US)/[a-z]+$:i', $ic->tz_locn ) ) { @@ -187,10 +197,145 @@ EOSQL; $last_modified, $ic->Get('url'), $ic->Get('priority'), $ic->Get('created'), $ic->Get('due'), $ic->Get('percent-complete') ); - if ( !$qry->Exec("PUT") ) rollback_on_error($context,$user_no,$path); + if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path); } $qry = new PgQuery("COMMIT;"); - if ( !$qry->Exec("PUT") ) rollback_on_error($context,$user_no,$path); + if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $user_no, $path); } -?> \ No newline at end of file + + +/** +* Put the resource from this request +* @param object $request A reference to the request object +* @param int $user_no The owner of the collection where we are putting this resource +* @param boolean $caldav_context Whether we are responding via CalDAV or interactively +* @return string Either 'INSERT' or 'UPDATE': the type of action that the PUT resulted in +*/ +function putCalendarResource( &$request, $author, $caldav_context ) { + $etag = md5($request->raw_post); + $ic = new iCalendar(array( 'icalendar' => $request->raw_post )); + + dbg_log_array( "PUT", 'EVENT', $ic->properties['VCALENDAR'][0], true ); + + /** + * We read any existing object so we can check the ETag. + */ + unset($put_action_type); + $qry = new PgQuery( "SELECT * FROM caldav_data WHERE user_no=? AND dav_name=?", $request->user_no, $request->path ); + if ( !$qry->Exec("PUT") || $qry->rows > 1 ) { + rollback_on_error( $caldav_context, $request->user_no, $request->path ); + } + elseif ( $qry->rows < 1 ) { + if ( isset($request->etag_if_match) && $request->etag_if_match != '' ) { + /** + * RFC2068, 14.25: + * If none of the entity tags match, or if "*" is given and no current + * entity exists, the server MUST NOT perform the requested method, and + * MUST return a 412 (Precondition Failed) response. + */ + rollback_on_error( $caldav_context, $request->user_no, $request->path, 412, translate("Resource changed on server - not changed.") ); + } + + $put_action_type = 'INSERT'; + + if ( ! $request->AllowedTo("create") ) { + rollback_on_error( $caldav_context, $request->user_no, $request->path, 403, translate("You may not add entries to this calendar.") ); + } + } + elseif ( $qry->rows == 1 ) { + $icalendar = $qry->Fetch(); + + if ( ( isset($request->etag_if_match) && $request->etag_if_match != '' && $request->etag_if_match != $icalendar->dav_etag ) + || ( isset($request->etag_none_match) && $request->etag_none_match != '' && ($request->etag_none_match == $icalendar->dav_etag || $request->etag_none_match == '*') ) ) { + /** + * RFC2068, 14.25: + * If none of the entity tags match, or if "*" is given and no current + * entity exists, the server MUST NOT perform the requested method, and + * MUST return a 412 (Precondition Failed) response. + * + * RFC2068, 14.26: + * If any of the entity tags match the entity tag of the entity that + * would have been returned in the response to a similar GET request + * (without the If-None-Match header) on that resource, or if "*" is + * given and any current entity exists for that resource, then the + * server MUST NOT perform the requested method. + */ + if ( isset($request->etag_if_match) && $request->etag_if_match != $icalendar->dav_etag ) { + $error = translate( "Existing resource does not match 'If-Match' header - not accepted."); + } + if ( isset($etag_none_match) && $etag_none_match != '' && ($etag_none_match == $icalendar->dav_etag || $etag_none_match == '*') ) { + $error = translate( "Existing resource matches 'If-None-Match' header - not accepted."); + } + $request->DoResponse( 412, $error ); + } + + $put_action_type = 'UPDATE'; + + if ( ! $request->AllowedTo("modify") ) { + $request->DoResponse( 403, translate("You may not modify entries on this calendar.") ); + } + } + + if ( $put_action_type == 'INSERT' ) { + $qry = new PgQuery( "BEGIN; INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp )", + $request->user_no, $request->path, $etag, $request->raw_post, $ic->type, $author ); + if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $request->user_no, $request->path); + } + else { + $qry = new PgQuery( "BEGIN;UPDATE caldav_data SET caldav_data=?, dav_etag=?, caldav_type=?, logged_user=?, modified=current_timestamp WHERE user_no=? AND dav_name=?", + $request->raw_post, $etag, $ic->type, $author, $request->user_no, $request->path ); + if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $request->user_no, $request->path); + } + + $sql = ( $ic->tz_locn == '' ? '' : "SET TIMEZONE TO ".qpg($ic->tz_locn).";" ); + + $dtstart = $ic->Get('DTSTART'); + if ( (!isset($dtstart) || $dtstart == "") && $ic->Get('DUE') != "" ) { + $dtstart = $ic->Get('DUE'); + } + + $dtend = $ic->Get('DTEND'); + if ( (!isset($dtend) || "$dtend" == "") && $ic->Get('DURATION') != "" AND $dtstart != "" ) { + $duration = preg_replace( '#[PT]#', ' ', $ic->Get('DURATION') ); + $dtend = '('.qpg($dtstart).'::timestamp with time zone + '.qpg($duration).'::interval)'; + } + else { + dbg_error_log( "PUT", " DTEND: '%s', DTSTART: '%s', DURATION: '%s'", $dtend, $dtstart, $ic->Get('DURATION') ); + $dtend = qpg($dtend); + } + + $last_modified = $ic->Get("LAST-MODIFIED"); + if ( !isset($last_modified) || $last_modified == '' ) { + $last_modified = gmdate( 'Ymd\THis\Z' ); + } + + $dtstamp = $ic->Get("DTSTAMP"); + if ( !isset($dtstamp) || $dtstamp == '' ) { + $dtstamp = $last_modified; + } + + if ( $put_action_type != 'INSERT' ) { + $sql .= "DELETE FROM calendar_item WHERE user_no=$request->user_no AND dav_name=".qpg($request->path).";"; + } + $sql .= <<user_no, $request->path, $etag, $ic->Get('UID'), $dtstamp, + $ic->Get('DTSTART'), $ic->Get('SUMMARY'), $ic->Get('LOCATION'), + $ic->Get('CLASS'), $ic->Get('TRANSP'), $ic->Get('DESCRIPTION'), $ic->Get('RRULE'), $ic->Get('TZ_ID'), + $last_modified, $ic->Get('URL'), $ic->Get('PRIORITY'), $ic->Get('CREATED'), + $ic->Get('DUE'), $ic->Get('PERCENT-COMPLETE'), $ic->Get('STATUS') + ); + if ( !$qry->Exec("PUT") ) rollback_on_error( $caldav_context, $request->user_no, $request->path); + dbg_error_log( "PUT", "User: %d, ETag: %s, Path: %s", $author, $etag, $request->path); + + header(sprintf('ETag: "%s"', (isset($bogus_etag) ? $bogus_etag : $etag) ) ); + + return $put_action_type; +} + diff --git a/inc/caldav-PUT.php b/inc/caldav-PUT.php index 4ada9891..cf8b9d57 100644 --- a/inc/caldav-PUT.php +++ b/inc/caldav-PUT.php @@ -36,128 +36,5 @@ if ( $is_collection ) { return; } -$etag = md5($request->raw_post); -$ic = new iCalendar(array( 'icalendar' => $request->raw_post )); - -dbg_log_array( "PUT", 'EVENT', $ic->properties['VCALENDAR'][0], true ); - - -/** -* We read any existing object so we can check the ETag. -*/ -unset($put_action_type); -$qry = new PgQuery( "SELECT * FROM caldav_data WHERE user_no=? AND dav_name=?", $request->user_no, $request->path ); -if ( !$qry->Exec("PUT") || $qry->rows > 1 ) { - $request->DoResponse( 500, translate("Error querying database.") ); -} -elseif ( $qry->rows < 1 ) { - if ( isset($request->etag_if_match) && $request->etag_if_match != '' ) { - /** - * RFC2068, 14.25: - * If none of the entity tags match, or if "*" is given and no current - * entity exists, the server MUST NOT perform the requested method, and - * MUST return a 412 (Precondition Failed) response. - */ - $request->DoResponse( 412, translate("Resource changed on server - not changed.") ); - } - - $put_action_type = 'INSERT'; - - if ( ! $request->AllowedTo("create") ) { - $request->DoResponse( 403, translate("You may not add entries to this calendar.") ); - } -} -elseif ( $qry->rows == 1 ) { - $icalendar = $qry->Fetch(); - - if ( ( isset($request->etag_if_match) && $request->etag_if_match != '' && $request->etag_if_match != $icalendar->dav_etag ) - || ( isset($request->etag_none_match) && $request->etag_none_match != '' && ($request->etag_none_match == $icalendar->dav_etag || $request->etag_none_match == '*') ) ) { - /** - * RFC2068, 14.25: - * If none of the entity tags match, or if "*" is given and no current - * entity exists, the server MUST NOT perform the requested method, and - * MUST return a 412 (Precondition Failed) response. - * - * RFC2068, 14.26: - * If any of the entity tags match the entity tag of the entity that - * would have been returned in the response to a similar GET request - * (without the If-None-Match header) on that resource, or if "*" is - * given and any current entity exists for that resource, then the - * server MUST NOT perform the requested method. - */ - if ( isset($request->etag_if_match) && $request->etag_if_match != $icalendar->dav_etag ) { - $error = translate( "Existing resource does not match 'If-Match' header - not accepted."); - } - if ( isset($etag_none_match) && $etag_none_match != '' && ($etag_none_match == $icalendar->dav_etag || $etag_none_match == '*') ) { - $error = translate( "Existing resource matches 'If-None-Match' header - not accepted."); - } - $request->DoResponse( 412, $error ); - } - - $put_action_type = 'UPDATE'; - - if ( ! $request->AllowedTo("modify") ) { - $request->DoResponse( 403, translate("You may not modify entries on this calendar.") ); - } -} - -if ( $put_action_type == 'INSERT' ) { - $qry = new PgQuery( "INSERT INTO caldav_data ( user_no, dav_name, dav_etag, caldav_data, caldav_type, logged_user, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp )", - $request->user_no, $request->path, $etag, $request->raw_post, $ic->type, $session->user_no ); - $qry->Exec("PUT"); -} -else { - $qry = new PgQuery( "UPDATE caldav_data SET caldav_data=?, dav_etag=?, caldav_type=?, logged_user=?, modified=current_timestamp WHERE user_no=? AND dav_name=?", - $request->raw_post, $etag, $ic->type, $session->user_no, $request->user_no, $request->path ); - $qry->Exec("PUT"); -} - -$sql = "BEGIN;".( $ic->tz_locn == '' ? '' : "SET TIMEZONE TO ".qpg($ic->tz_locn).";" ); - -$dtstart = $ic->Get('DTSTART'); -if ( (!isset($dtstart) || $dtstart == "") && $ic->Get('DUE') != "" ) { - $dtstart = $ic->Get('DUE'); -} - -$dtend = $ic->Get('DTEND'); -if ( (!isset($dtend) || "$dtend" == "") && $ic->Get('DURATION') != "" AND $dtstart != "" ) { - $duration = preg_replace( '#[PT]#', ' ', $ic->Get('DURATION') ); - $dtend = '('.qpg($dtstart).'::timestamp with time zone + '.qpg($duration).'::interval)'; -} -else { - dbg_error_log( "PUT", " DTEND: '%s', DTSTART: '%s', DURATION: '%s'", $dtend, $dtstart, $ic->Get('DURATION') ); - $dtend = qpg($dtend); -} - -$last_modified = $ic->Get("LAST-MODIFIED"); -if ( !isset($last_modified) || $last_modified == '' ) { - $last_modified = gmdate( 'Ymd\THis\Z' ); -} - -$dtstamp = $ic->Get("DTSTAMP"); -if ( !isset($dtstamp) || $dtstamp == '' ) { - $dtstamp = $last_modified; -} - -if ( $put_action_type != 'INSERT' ) { - $sql .= "DELETE FROM calendar_item WHERE user_no=$request->user_no AND dav_name=".qpg($request->path).";"; -} -$sql .= <<user_no, $request->path, $etag, $ic->Get('UID'), $dtstamp, - $ic->Get('DTSTART'), $ic->Get('SUMMARY'), $ic->Get('LOCATION'), - $ic->Get('CLASS'), $ic->Get('TRANSP'), $ic->Get('DESCRIPTION'), $ic->Get('RRULE'), $ic->Get('TZ_ID'), - $last_modified, $ic->Get('URL'), $ic->Get('PRIORITY'), $ic->Get('CREATED'), - $ic->Get('DUE'), $ic->Get('PERCENT-COMPLETE'), $ic->Get('STATUS') - ); -$qry->Exec("PUT"); -dbg_error_log( "PUT", "User: %d, ETag: %s, Path: %s", $session->user_no, $etag, $request->path); - -header(sprintf('ETag: "%s"', (isset($bogus_etag) ? $bogus_etag : $etag) ) ); +$put_action_type = putCalendarResource( $request, $session->user_no, true ); $request->DoResponse( ($put_action_type == 'INSERT' ? 201 : 204) ); -?> \ No newline at end of file From 5b06b82bd56e1449ec1fc1847726d0eadc6acc0d Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Tue, 23 Oct 2007 22:00:18 +1300 Subject: [PATCH 004/189] Quanta droppings. --- rscds.webprj | 1 + 1 file changed, 1 insertion(+) diff --git a/rscds.webprj b/rscds.webprj index 7b259807..7c6652fa 100644 --- a/rscds.webprj +++ b/rscds.webprj @@ -236,6 +236,7 @@ + From b42f3d4aef39c42b4d0289da0113da35d1713bfc Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Wed, 24 Oct 2007 21:42:25 +1300 Subject: [PATCH 005/189] Get rid of the uninitialised $c->pkgver variable. --- inc/always.php | 8 ++++---- inc/always.php.in | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/always.php b/inc/always.php index 9ed926b7..33fdfe65 100644 --- a/inc/always.php +++ b/inc/always.php @@ -83,12 +83,12 @@ $c->code_version = 0; $c->version_string = '0.9.0'; // The actual version # is replaced into that during the build /release process if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) { $c->code_major = $matches[1]; - $c->code_minor = $matches[1]; - $c->code_patch = $matches[1]; + $c->code_minor = $matches[2]; + $c->code_patch = $matches[3]; $c->code_version = (($c->code_major * 1000) + $c->code_minor).".".$c->code_patch; } -dbg_error_log("caldav", "Version %s (%d.%d.%d) == %s", $c->code_pkgver, $c->code_major, $c->code_minor, $c->code_patch, $c->code_version); -header( sprintf("Server: %s/%d.%d", $c->code_pkgver, $c->code_major, $c->code_minor) ); +dbg_error_log("caldav", "Version (%d.%d.%d) == %s", $c->code_major, $c->code_minor, $c->code_patch, $c->code_version); +header( sprintf("Server: %d.%d", $c->code_major, $c->code_minor) ); /** * Force the domain name to what was in the configuration file diff --git a/inc/always.php.in b/inc/always.php.in index f453126d..b98eccf8 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -87,8 +87,8 @@ if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->v $c->code_patch = $matches[3]; $c->code_version = (($c->code_major * 1000) + $c->code_minor).".".$c->code_patch; } -dbg_error_log("caldav", "Version %s (%d.%d.%d) == %s", $c->code_pkgver, $c->code_major, $c->code_minor, $c->code_patch, $c->code_version); -header( sprintf("Server: %s/%d.%d", $c->code_pkgver, $c->code_major, $c->code_minor) ); +dbg_error_log("caldav", "Version (%d.%d.%d) == %s", $c->code_major, $c->code_minor, $c->code_patch, $c->code_version); +header( sprintf("Server: %d.%d", $c->code_major, $c->code_minor) ); /** * Force the domain name to what was in the configuration file From 1d1f987233879f1b74527200f84da04bd3fde3a6 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 25 Oct 2007 15:20:18 +1300 Subject: [PATCH 006/189] Ensure that we have a default auth mode. --- inc/HTTPAuthSession.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/HTTPAuthSession.php b/inc/HTTPAuthSession.php index 5ce70e98..b066148f 100644 --- a/inc/HTTPAuthSession.php +++ b/inc/HTTPAuthSession.php @@ -50,7 +50,7 @@ class HTTPAuthSession { function HTTPAuthSession() { global $c; - if ( $c->http_auth_mode == "Digest" ) { + if ( isset($c->http_auth_mode) && $c->http_auth_mode == "Digest" ) { $this->DigestAuthSession(); } else { From 94b6418fd3cd7c6b2298009c408ae986d759d421 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 25 Oct 2007 15:20:55 +1300 Subject: [PATCH 007/189] When class is NULL we should consider it to be PUBLIC. --- inc/caldav-GET.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/caldav-GET.php b/inc/caldav-GET.php index 575bc203..44ccd728 100644 --- a/inc/caldav-GET.php +++ b/inc/caldav-GET.php @@ -15,7 +15,7 @@ if ( ! $request->AllowedTo('read') ) { } $privacy_clause = ""; if ( ! $request->AllowedTo('all') ) { - $privacy_clause = "AND calendar_item.class != 'PRIVATE'"; + $privacy_clause = "AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL) "; } if ( $request->IsCollection() ) { From 628dec32099b04950823445d39cee5ff462d85f0 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 25 Oct 2007 15:24:46 +1300 Subject: [PATCH 008/189] Only log start of debugging if some debugging is enabled. --- inc/always.php | 7 ++++++- inc/always.php.in | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/inc/always.php b/inc/always.php index 33fdfe65..89d33411 100644 --- a/inc/always.php +++ b/inc/always.php @@ -18,6 +18,7 @@ $c->save_time_zone_defs = true; $c->collections_always_exist = true; $c->home_calendar_name = 'home'; $c->enable_row_linking = true; +$c->http_auth_mode = 'Basic'; // $c->default_locale = array('es_MX', 'es_MX.UTF-8', 'es'); // $c->local_tzid = 'Pacific/Auckland'; // Perhaps we should read from /etc/timezone - I wonder how standard that is? $c->default_locale = "en_NZ"; @@ -50,7 +51,11 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS ), $_SERVER['SCRIPT_NAME'] ); -@dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); +if ( count($c->dbg) > 0 ) { + // Only log this if debugging of some sort is turned on, somewhere + @dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", + $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); +} init_gettext( 'rscds', '../locale' ); diff --git a/inc/always.php.in b/inc/always.php.in index b98eccf8..1ae708fd 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -18,6 +18,7 @@ $c->save_time_zone_defs = true; $c->collections_always_exist = true; $c->home_calendar_name = 'home'; $c->enable_row_linking = true; +$c->http_auth_mode = 'Basic'; // $c->default_locale = array('es_MX', 'es_MX.UTF-8', 'es'); // $c->local_tzid = 'Pacific/Auckland'; // Perhaps we should read from /etc/timezone - I wonder how standard that is? $c->default_locale = "en_NZ"; @@ -50,7 +51,11 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS ), $_SERVER['SCRIPT_NAME'] ); -@dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); +if ( count($c->dbg) > 0 ) { + // Only log this if debugging of some sort is turned on, somewhere + @dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", + $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); +} init_gettext( 'rscds', '../locale' ); From 17a21eaa15b5e81077c38c01ff863bee9bb4c2d8 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 25 Oct 2007 16:29:26 +1300 Subject: [PATCH 009/189] Release 0.9.1 --- VERSION | 2 +- debian/changelog | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ac39a106..f374f666 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.9.0 +0.9.1 diff --git a/debian/changelog b/debian/changelog index 639afdb4..001b2726 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,18 @@ +rscds (0.9.1) unstable; urgency=low + + * Reduce debug logging noise when debugging is iff + * When class is NULL we should consider it to be PUBLIC. + * Clean up some uninitialised variable warnings. + * Refactoring caldav-PUT to allow calling from a different code path. + * State how to make LDAP use an anonymous bind initially. + * Include any VTODO in GET for a collection. + * Minor permissions changes. + * Fix VTODO handling by time-range queries. + * Various fixes to LDAP authentication. + * Fix permissions for RW access. + + -- Andrew McMillan Thu, 25 Oct 2007 16:06:02 +1300 + rscds (0.9.0) unstable; urgency=low * Changes preparatory to renaming to DAViCal From a30442581c5fd36b0cbe4271f8d338726920681b Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 25 Oct 2007 21:48:33 +1300 Subject: [PATCH 010/189] Really release 0.9.1, for what it's worth. --- debian/changelog | 2 +- inc/always.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 001b2726..d1a508fc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,7 +11,7 @@ rscds (0.9.1) unstable; urgency=low * Various fixes to LDAP authentication. * Fix permissions for RW access. - -- Andrew McMillan Thu, 25 Oct 2007 16:06:02 +1300 + -- Andrew McMillan Thu, 25 Oct 2007 16:30:06 +1300 rscds (0.9.0) unstable; urgency=low diff --git a/inc/always.php b/inc/always.php index 89d33411..ea88f309 100644 --- a/inc/always.php +++ b/inc/always.php @@ -85,7 +85,7 @@ awl_set_locale($c->default_locale); * */ $c->code_version = 0; -$c->version_string = '0.9.0'; // The actual version # is replaced into that during the build /release process +$c->version_string = '0.9.1'; // The actual version # is replaced into that during the build /release process if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) { $c->code_major = $matches[1]; $c->code_minor = $matches[2]; From 613fcb4417f154a5840a999121546651f1faa14a Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 25 Oct 2007 22:46:32 +1300 Subject: [PATCH 011/189] Use the right variable name. --- inc/caldav-PROPFIND.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 2054da96..2c705f90 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -93,7 +93,7 @@ foreach( $request->xml_tags AS $k => $v ) { */ default: $arbitrary[$tag] = $tag; - dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $attribute ); + dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $tag ); break; } } From 06431170c894ab661ee97a790294a242e905e008 Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Fri, 26 Oct 2007 09:41:18 +1300 Subject: [PATCH 012/189] By default calendar items are PUBLIC. --- dba/patches/1.1.9.sql | 8 ++++---- inc/caldav-PUT-functions.php | 25 +++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/dba/patches/1.1.9.sql b/dba/patches/1.1.9.sql index 056cd100..e3d49113 100644 --- a/dba/patches/1.1.9.sql +++ b/dba/patches/1.1.9.sql @@ -1,13 +1,13 @@ --- Adding a primary key to the calendar_item table +-- Make sure that class is set to something, by default PUBLIC. +-- According to RFC2445, 4.8.1.3. BEGIN; SELECT check_db_revision(1,1,8); -ALTER TABLE calendar_item ADD PRIMARY KEY (user_no, dav_name ); +UPDATE calendar_item SET class = 'PUBLIC' WHERE class IS NULL; -SELECT new_db_revision(1,1,9, 'September' ); +SELECT new_db_revision(1,1,9, 'October' ); COMMIT; ROLLBACK; -VACUUM FULL ANALYZE; \ No newline at end of file diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index 7deee23b..7b2ae3d5 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -185,6 +185,16 @@ function import_collection( $ics_content, $user_no, $path, $caldav_context ) { $dtstamp = $last_modified; } + /* + * It seems that some calendar clients don't set a class... + * RFC2445, 4.8.1.3: + * Default is PUBLIC + */ + $class = $ic->Get("class"); + if ( !isset($class) || $class == '' ) { + $class = 'PUBLIC' + } + $sql .= <<Get('uid'), $dtstamp, $ic->Get('dtstart'), $ic->Get('summary'), $ic->Get('location'), - $ic->Get('class'), $ic->Get('transp'), $ic->Get('description'), $ic->Get('rrule'), $ic->Get('tz_id'), + $class, $ic->Get('transp'), $ic->Get('description'), $ic->Get('rrule'), $ic->Get('tz_id'), $last_modified, $ic->Get('url'), $ic->Get('priority'), $ic->Get('created'), $ic->Get('due'), $ic->Get('percent-complete') ); @@ -315,6 +325,17 @@ function putCalendarResource( &$request, $author, $caldav_context ) { $dtstamp = $last_modified; } + /* + * It seems that some calendar clients don't set a class... + * RFC2445, 4.8.1.3: + * Default is PUBLIC + */ + $class = $ic->Get("class"); + if ( !isset($class) || $class == '' ) { + $class = 'PUBLIC' + } + + if ( $put_action_type != 'INSERT' ) { $sql .= "DELETE FROM calendar_item WHERE user_no=$request->user_no AND dav_name=".qpg($request->path).";"; } @@ -327,7 +348,7 @@ EOSQL; $qry = new PgQuery( $sql, $request->user_no, $request->path, $etag, $ic->Get('UID'), $dtstamp, $ic->Get('DTSTART'), $ic->Get('SUMMARY'), $ic->Get('LOCATION'), - $ic->Get('CLASS'), $ic->Get('TRANSP'), $ic->Get('DESCRIPTION'), $ic->Get('RRULE'), $ic->Get('TZ_ID'), + $class, $ic->Get('TRANSP'), $ic->Get('DESCRIPTION'), $ic->Get('RRULE'), $ic->Get('TZ_ID'), $last_modified, $ic->Get('URL'), $ic->Get('PRIORITY'), $ic->Get('CREATED'), $ic->Get('DUE'), $ic->Get('PERCENT-COMPLETE'), $ic->Get('STATUS') ); From bbcd6a82acc9e7df8144917ecdc7ce61ca22b369 Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Fri, 26 Oct 2007 09:50:45 +1300 Subject: [PATCH 013/189] Bugger, fix up the DB patches. --- dba/patches/1.1.10.sql | 13 +++++++++++++ dba/patches/1.1.9.sql | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 dba/patches/1.1.10.sql diff --git a/dba/patches/1.1.10.sql b/dba/patches/1.1.10.sql new file mode 100644 index 00000000..0dcefe57 --- /dev/null +++ b/dba/patches/1.1.10.sql @@ -0,0 +1,13 @@ + +-- Make sure that class is set to something, by default PUBLIC. +-- According to RFC2445, 4.8.1.3. + +BEGIN; +SELECT check_db_revision(1,1,9); + +UPDATE calendar_item SET class = 'PUBLIC' WHERE class IS NULL; + +SELECT new_db_revision(1,1,10, 'October' ); +COMMIT; +ROLLBACK; + diff --git a/dba/patches/1.1.9.sql b/dba/patches/1.1.9.sql index e3d49113..056cd100 100644 --- a/dba/patches/1.1.9.sql +++ b/dba/patches/1.1.9.sql @@ -1,13 +1,13 @@ --- Make sure that class is set to something, by default PUBLIC. --- According to RFC2445, 4.8.1.3. +-- Adding a primary key to the calendar_item table BEGIN; SELECT check_db_revision(1,1,8); -UPDATE calendar_item SET class = 'PUBLIC' WHERE class IS NULL; +ALTER TABLE calendar_item ADD PRIMARY KEY (user_no, dav_name ); -SELECT new_db_revision(1,1,9, 'October' ); +SELECT new_db_revision(1,1,9, 'September' ); COMMIT; ROLLBACK; +VACUUM FULL ANALYZE; \ No newline at end of file From e0746e058eca9904cedfde8bc76d4e3379fdbbbf Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Fri, 26 Oct 2007 11:05:32 +1300 Subject: [PATCH 014/189] Allow forcing all events in a collection to a specified class. --- dba/patches/1.1.10.sql | 8 ++++++-- inc/caldav-PUT-functions.php | 37 ++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/dba/patches/1.1.10.sql b/dba/patches/1.1.10.sql index 0dcefe57..d7cce76a 100644 --- a/dba/patches/1.1.10.sql +++ b/dba/patches/1.1.10.sql @@ -1,12 +1,16 @@ --- Make sure that class is set to something, by default PUBLIC. --- According to RFC2445, 4.8.1.3. +-- Sort out accessing calendar entries. BEGIN; SELECT check_db_revision(1,1,9); +-- Make sure that class is set to something, by default PUBLIC. +-- According to RFC2445, 4.8.1.3. UPDATE calendar_item SET class = 'PUBLIC' WHERE class IS NULL; +-- Allow forcing all events in a calendar to a specific class +ALTER TABLE collection ADD COLUMN force_class TEXT; + SELECT new_db_revision(1,1,10, 'October' ); COMMIT; ROLLBACK; diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index 7b2ae3d5..fbe4383c 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -83,6 +83,27 @@ function controlRequestContainer( $username, $user_no, $path, $caldav_context ) return $is_collection; } +/** +* Check if there is a class that new events should be forced to. +* @param string $user_no the user that owns the collection +* @param string $dav_name the collection to check +*/ +function find_forced_class( $user_no, $dav_name ) { + $sql = "SELECT force_class "; + $sql .= "FROM collection "; + $sql .= "WHERE user_no=? AND dav_name=?"); + + $qry = new PgQuery($sql); + + if( $qry->Exec($user_no, $dav_name) && $qry->rows == 1 ) { + $collection = $qry->Fetch(); + + if ( ( isset($collection->force_class) && $collection->force_class != '' ) { + return $collection->force_class; + } + } +} + /** * This function will import a whole calendar @@ -185,12 +206,18 @@ function import_collection( $ics_content, $user_no, $path, $caldav_context ) { $dtstamp = $last_modified; } + $class = $ic->Get("class"); + /* Check and see if we should over ride the class. */ + $force_class = find_forced_class($user_no, $path); + if ( isset($force_class) ) { + $class = $force_class; + } + /* * It seems that some calendar clients don't set a class... * RFC2445, 4.8.1.3: * Default is PUBLIC */ - $class = $ic->Get("class"); if ( !isset($class) || $class == '' ) { $class = 'PUBLIC' } @@ -325,12 +352,18 @@ function putCalendarResource( &$request, $author, $caldav_context ) { $dtstamp = $last_modified; } + $class = $ic->Get("class"); + /* Check and see if we should over ride the class. */ + $force_class = find_forced_class($user_no, $path); + if ( isset($force_class) ) { + $class = $force_class; + } + /* * It seems that some calendar clients don't set a class... * RFC2445, 4.8.1.3: * Default is PUBLIC */ - $class = $ic->Get("class"); if ( !isset($class) || $class == '' ) { $class = 'PUBLIC' } From e72559061228a57b18d17c15b1a7e2cfe6530680 Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Fri, 26 Oct 2007 11:35:19 +1300 Subject: [PATCH 015/189] Rewrite force events to public logic to be PUBLIC only, not general. --- dba/patches/1.1.10.sql | 6 ++++-- inc/caldav-PUT-functions.php | 24 +++++++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/dba/patches/1.1.10.sql b/dba/patches/1.1.10.sql index d7cce76a..532a3bb0 100644 --- a/dba/patches/1.1.10.sql +++ b/dba/patches/1.1.10.sql @@ -8,8 +8,10 @@ SELECT check_db_revision(1,1,9); -- According to RFC2445, 4.8.1.3. UPDATE calendar_item SET class = 'PUBLIC' WHERE class IS NULL; --- Allow forcing all events in a calendar to a specific class -ALTER TABLE collection ADD COLUMN force_class TEXT; +-- Allow forcing all events in a calendar to be public +ALTER TABLE collection ADD COLUMN public_events_only BOOLEAN; +ALTER TABLE collection ALTER public_events_only SET NOT NULL; +ALTER TABLE collection ALTER public_events_only SET DEFAULT 'f'; SELECT new_db_revision(1,1,10, 'October' ); COMMIT; diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index fbe4383c..8bea00a2 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -84,12 +84,13 @@ function controlRequestContainer( $username, $user_no, $path, $caldav_context ) } /** -* Check if there is a class that new events should be forced to. +* Check if this collection sould force all events to be PUBLIC. * @param string $user_no the user that owns the collection * @param string $dav_name the collection to check +* @return boolean Return true if public events only are allowed. */ -function find_forced_class( $user_no, $dav_name ) { - $sql = "SELECT force_class "; +function public_events_only( $user_no, $dav_name ) { + $sql = "SELECT public_events_only "; $sql .= "FROM collection "; $sql .= "WHERE user_no=? AND dav_name=?"); @@ -98,10 +99,13 @@ function find_forced_class( $user_no, $dav_name ) { if( $qry->Exec($user_no, $dav_name) && $qry->rows == 1 ) { $collection = $qry->Fetch(); - if ( ( isset($collection->force_class) && $collection->force_class != '' ) { - return $collection->force_class; + if ($collection->public_events_only == 't') { + return true; } } + + // Something went wrong, must be false. + return false; } @@ -208,9 +212,8 @@ function import_collection( $ics_content, $user_no, $path, $caldav_context ) { $class = $ic->Get("class"); /* Check and see if we should over ride the class. */ - $force_class = find_forced_class($user_no, $path); - if ( isset($force_class) ) { - $class = $force_class; + if ( public_events_only($user_no, $path) ) { + $class = 'PUBLIC'; } /* @@ -354,9 +357,8 @@ function putCalendarResource( &$request, $author, $caldav_context ) { $class = $ic->Get("class"); /* Check and see if we should over ride the class. */ - $force_class = find_forced_class($user_no, $path); - if ( isset($force_class) ) { - $class = $force_class; + if ( public_events_only($user_no, $path) ) { + $class = 'PUBLIC'; } /* From e64db0fae4665e26a40a13075bc0ba29d5164d86 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 26 Oct 2007 12:00:47 +1300 Subject: [PATCH 016/189] If an event is public, we should show it! --- inc/caldav-GET.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inc/caldav-GET.php b/inc/caldav-GET.php index 44ccd728..9c3b4547 100644 --- a/inc/caldav-GET.php +++ b/inc/caldav-GET.php @@ -65,6 +65,9 @@ else if ( $qry->rows > 1 ) { // Otherwise we hide the alarms (if configured to) $response .= $ical->Render( false, $event->caldav_type, $ical->DefaultPropertyList() ); } + else { + $response .= $ical->Render( false, $event->caldav_type ); + } } else { $response .= $ical->Render( false, $event->caldav_type ); From 9bb9141f562a22a9f5112cd02621eb20c350ad8a Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 26 Oct 2007 21:11:19 +1300 Subject: [PATCH 017/189] Introduce a rudimentary 'principal' attribute to the request object. --- inc/CalDAVRequest.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index d5f4c7c4..cfc6983a 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -27,6 +27,17 @@ class CalDAVRequest { var $options; + /** + * The depth parameter from the request headers, coerced into a valid integer: 0, 1 + * or DEPTH_INFINITY which is defined above. The default is set per various RFCs. + */ + var $depth; + + /** + * The 'principal' (user/resource/...) which this request seeks to access + */ + var $principal; + /** * Create a new CalDAVRequest object. */ @@ -34,6 +45,7 @@ class CalDAVRequest global $session, $c, $debugging; $this->options = $options; + $this->principal = (object) array( 'username' => $session->username, 'user_no' => $session->user_no ); $this->raw_post = file_get_contents ( 'php://input'); @@ -140,8 +152,11 @@ class CalDAVRequest /** * Extract the user whom we are accessing + * TODO: Replace this by something which properly sets up the DAV 'principal' */ $this->UserFromPath(); + $this->principal->url = sprintf( "%s/%s/", $c->protocol_server_port_script, $this->principal->username); + $this->principal->calendar_home_set = sprintf( "%s/%s/%s/", $c->protocol_server_port_script, $this->principal->username, $c->home_calendar_name); /** * Evaluate our permissions for accessing the target @@ -200,7 +215,8 @@ class CalDAVRequest $this->user_no = $user->user_no; } } - elseif( $user = getUserByName($this->username,'caldav',__LINE__,__FILE__)){ + elseif( $user = getUserByName($this->username,'caldav',__LINE__,__FILE__)) { + $this->principal = $user; $this->user_no = $user->user_no; } } From f8b0f0383e0d1df7de0ceb000e6fbad33efcef21 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 26 Oct 2007 21:12:26 +1300 Subject: [PATCH 018/189] Initial support for DAV::PRINCIPAL-URL and CalDAV calendar-home-set --- inc/caldav-PROPFIND.php | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 2c705f90..01da492e 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -40,7 +40,6 @@ foreach( $request->xml_tags AS $k => $v ) { case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-DATE-TIME': case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-INSTANCES': case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-ATTENDEES-PER-INSTANCE': - case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-HOME-SET': case 'HTTP://APACHE.ORG/DAV/PROPS/:EXECUTABLE': case 'DAV::CHECKED-OUT': case 'DAV::CHECKED-IN': @@ -57,16 +56,23 @@ foreach( $request->xml_tags AS $k => $v ) { case 'DAV::GETCONTENTTYPE': /** getcontenttype - should work fine */ case 'DAV::GETETAG': /** getetag - should work fine */ case 'DAV::SUPPORTEDLOCK': /** supportedlock - should work fine */ + case 'DAV::PRINCIPAL-URL': /** principal-url - should work fine */ case 'DAV::RESOURCETYPE': /** resourcetype - should work fine */ case 'DAV::GETCONTENTLANGUAGE': /** resourcetype - should return the user's chosen locale, or default locale */ case 'DAV::SUPPORTED-PRIVILEGE-SET': /** supported-privilege-set - should work fine */ - case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-COLLATION-SET': /** fixed server definition - should work fine */ - case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET': /** fixed server definition - should work fine */ case 'DAV::CURRENT-USER-PRIVILEGE-SET': /** current-user-privilege-set - only vaguely supported */ case 'DAV::ALLPROP': /** allprop - limited support */ $attribute = substr($v['tag'],5); $attribute_list[$attribute] = 1; - dbg_error_log( "PROPFIND", "Adding attribute '%s'", $attribute ); + dbg_error_log( "PROPFIND", "Adding DAV: attribute '%s'", $attribute ); + break; + + case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-HOME-SET': /** calendar-home-set is used by iCal in Leopard - should work fine */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-COLLATION-SET': /** fixed server definition - should work fine */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET': /** fixed server definition - should work fine */ + $attribute = substr($v['tag'],30); + $attribute_list[$attribute] = 1; + dbg_error_log( "PROPFIND", "Adding CalDAV attribute '%s'", $attribute ); break; case 'DAV::HREF': @@ -180,6 +186,14 @@ function collection_to_xml( $collection ) { $prop->NewElement("getcontenttype", "httpd/unix-directory" ); } + if ( isset($attribute_list['PRINCIPAL-URL'] ) ) { + $prop->NewElement("principal-url", $request->principal->url ); + } + + if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) { + $prop->NewElement("calendar-home-set", $request->principal->calendar_home_set, array("xmlns" => "urn:ietf:params:xml:ns:caldav") ); + } + /** * Second process any dynamic values we do support */ @@ -290,6 +304,14 @@ function item_to_xml( $item ) { $prop->NewElement("getetag", '"'.$item->dav_etag.'"' ); } + if ( isset($attribute_list['PRINCIPAL-URL'] ) ) { + $prop->NewElement("principal-url", $request->principal->url ); + } + + if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) { + $prop->NewElement("calendar-home-set", $request->principal->calendar_home_set, array("xmlns" => "urn:ietf:params:xml:ns:caldav") ); + } + if ( isset($attribute_list['ACL']) ) { /** * FIXME: This information is semantically valid but presents an incorrect picture. From 0bbcc11367a4445bf4e946578dec807f4a7d6e38 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 26 Oct 2007 21:13:14 +1300 Subject: [PATCH 019/189] A first regression test for the way iCal 10.5 does things. --- .../regression-suite/510-iCal-PROPFIND.test | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 testing/tests/regression-suite/510-iCal-PROPFIND.test diff --git a/testing/tests/regression-suite/510-iCal-PROPFIND.test b/testing/tests/regression-suite/510-iCal-PROPFIND.test new file mode 100644 index 00000000..05a670ec --- /dev/null +++ b/testing/tests/regression-suite/510-iCal-PROPFIND.test @@ -0,0 +1,23 @@ +# +# Testing with a process similar to iCal 10.5 +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/home/ +HEADER=User-Agent: DAVKit/2.0 (10.5; wrbt) iCal 3.0 +HEADER=Content-Type: text/xml +HEADER=Depth: 0 + +BEGINDATA + + + + + + + + + + + + +ENDDATA From 9623b216b2054f001b628851bf882dedd5f78d01 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 26 Oct 2007 21:13:42 +1300 Subject: [PATCH 020/189] Get rid of a couple more unassigned variable warnings. --- inc/caldav-REPORT.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index d2cd9fc9..e688cc76 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -29,6 +29,8 @@ require_once("iCalendar.php"); $reportnum = -1; $report = array(); +$denied = array(); +$unsupported = array(); if ( isset($prop_filter) ) unset($prop_filter); $position = 0; From ae3e35d0360d18d1f42774af17c669d9823d5359 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 26 Oct 2007 21:14:12 +1300 Subject: [PATCH 021/189] Update the URL of the scheduling extensions draft. --- inc/caldav-OPTIONS.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/caldav-OPTIONS.php b/inc/caldav-OPTIONS.php index fb91367b..33c99232 100644 --- a/inc/caldav-OPTIONS.php +++ b/inc/caldav-OPTIONS.php @@ -61,7 +61,7 @@ header( "Allow: $allowed"); /** * From reading the "Scheduling Extensions to CalDAV" draft I don't think that we will * be doing 'calendar-schedule' any time soon. The current spec is at: -* http://www.ietf.org/internet-drafts/draft-desruisseaux-caldav-sched-02.txt +* http://www.ietf.org/internet-drafts/draft-desruisseaux-caldav-sched-03.txt * * access-control is rfc3744, so we will say we do it, but I doubt if we do it * in all (or even much of) it's glory really. From ff55979bfd39f5859636ac4a6b9ae7e9cb180518 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 26 Oct 2007 21:37:23 +1300 Subject: [PATCH 022/189] More filesss. --- rscds.webprj | 1 + 1 file changed, 1 insertion(+) diff --git a/rscds.webprj b/rscds.webprj index 7c6652fa..3f2bb97a 100644 --- a/rscds.webprj +++ b/rscds.webprj @@ -238,5 +238,6 @@ + From 04656674f7f5a4d757a2c64776f43df64963424d Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 27 Oct 2007 00:11:44 +1300 Subject: [PATCH 023/189] Make puck's patches for PUBLIC events actually work. --- dba/patches/1.1.10.sql | 3 ++- dba/rscds.sql | 3 ++- inc/caldav-PUT-functions.php | 18 +++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/dba/patches/1.1.10.sql b/dba/patches/1.1.10.sql index 532a3bb0..2a059cb6 100644 --- a/dba/patches/1.1.10.sql +++ b/dba/patches/1.1.10.sql @@ -10,8 +10,9 @@ UPDATE calendar_item SET class = 'PUBLIC' WHERE class IS NULL; -- Allow forcing all events in a calendar to be public ALTER TABLE collection ADD COLUMN public_events_only BOOLEAN; +UPDATE collection SET public_events_only = FALSE; ALTER TABLE collection ALTER public_events_only SET NOT NULL; -ALTER TABLE collection ALTER public_events_only SET DEFAULT 'f'; +ALTER TABLE collection ALTER public_events_only SET DEFAULT FALSE; SELECT new_db_revision(1,1,10, 'October' ); COMMIT; diff --git a/dba/rscds.sql b/dba/rscds.sql index 2e76a617..33382bfa 100644 --- a/dba/rscds.sql +++ b/dba/rscds.sql @@ -77,6 +77,7 @@ CREATE TABLE collection ( is_calendar BOOLEAN, created TIMESTAMP WITH TIME ZONE, modified TIMESTAMP WITH TIME ZONE, + public_events_only BOOLEAN NOT NULL DEFAULT FALSE, PRIMARY KEY ( user_no, dav_name ) ); @@ -141,4 +142,4 @@ CREATE TABLE freebusy_ticket ( GRANT INSERT,SELECT,UPDATE,DELETE ON TABLE freebusy_ticket TO general; -SELECT new_db_revision(1,1,9, 'September' ); +SELECT new_db_revision(1,1,10, 'October' ); diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index 8bea00a2..8a33f938 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -92,11 +92,11 @@ function controlRequestContainer( $username, $user_no, $path, $caldav_context ) function public_events_only( $user_no, $dav_name ) { $sql = "SELECT public_events_only "; $sql .= "FROM collection "; - $sql .= "WHERE user_no=? AND dav_name=?"); + $sql .= "WHERE user_no=? AND dav_name=?"; - $qry = new PgQuery($sql); + $qry = new PgQuery($sql, $user_no, $dav_name); - if( $qry->Exec($user_no, $dav_name) && $qry->rows == 1 ) { + if( $qry->Exec('PUT') && $qry->rows == 1 ) { $collection = $qry->Fetch(); if ($collection->public_events_only == 't') { @@ -215,14 +215,14 @@ function import_collection( $ics_content, $user_no, $path, $caldav_context ) { if ( public_events_only($user_no, $path) ) { $class = 'PUBLIC'; } - + /* * It seems that some calendar clients don't set a class... * RFC2445, 4.8.1.3: * Default is PUBLIC - */ + */ if ( !isset($class) || $class == '' ) { - $class = 'PUBLIC' + $class = 'PUBLIC'; } $sql .= << Date: Sat, 27 Oct 2007 00:29:59 +1300 Subject: [PATCH 024/189] Make the code work with or without upgrading the DB to 1.1.10. --- inc/caldav-PUT-functions.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index 8a33f938..ebf9851a 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -90,6 +90,10 @@ function controlRequestContainer( $username, $user_no, $path, $caldav_context ) * @return boolean Return true if public events only are allowed. */ function public_events_only( $user_no, $dav_name ) { + global $c; + // Not supported until DB versions from 1.001.010 + if ( $c->schema_version < 1001.010 ) return false; + $sql = "SELECT public_events_only "; $sql .= "FROM collection "; $sql .= "WHERE user_no=? AND dav_name=?"; From 96a4825c886d47f1182d727928bda26aa9d43241 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 27 Oct 2007 00:30:49 +1300 Subject: [PATCH 025/189] The result from a first test for iCal support. --- .../regression-suite/510-iCal-PROPFIND.result | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 testing/tests/regression-suite/510-iCal-PROPFIND.result diff --git a/testing/tests/regression-suite/510-iCal-PROPFIND.result b/testing/tests/regression-suite/510-iCal-PROPFIND.result new file mode 100644 index 00000000..f2446d6c --- /dev/null +++ b/testing/tests/regression-suite/510-iCal-PROPFIND.result @@ -0,0 +1,18 @@ + + + + /caldav.php/user1/home/ + + + http://mycaldav/caldav.php/user1/home/ + home + + + + + + + HTTP/1.1 200 OK + + + From e5e2002c74c4d2fc5861ec708a639add6008f467 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 27 Oct 2007 15:18:37 +1300 Subject: [PATCH 026/189] URLs seem to need to be unescaped. --- htdocs/js/browse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/js/browse.js b/htdocs/js/browse.js index e1b83404..101fbde5 100644 --- a/htdocs/js/browse.js +++ b/htdocs/js/browse.js @@ -11,7 +11,7 @@ function Go( url ) { */ function LinkTo( tag, url ) { tag.style.cursor = "pointer"; - tag.setAttribute('onClick', "Go('" + url + "')"); + tag.setAttribute('onClick', "Go('" + url.replace('&','&') + "')"); tag.setAttribute('onMouseOut', "window.status='';return true;"); window.status = window.location.protocol + '//' + document.domain + url; tag.setAttribute('onMouseover', "window.status = window.location.protocol + '//' + document.domain + '" + url + "';return true;"); From 82410d39fc5a1e25ae597d8b5f1cbac94eb445c5 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 27 Oct 2007 15:19:13 +1300 Subject: [PATCH 027/189] Automatically create some relationships when the user is added. --- inc/RSCDSUser.php | 68 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/inc/RSCDSUser.php b/inc/RSCDSUser.php index 2e2b2b4e..223cc9c6 100644 --- a/inc/RSCDSUser.php +++ b/inc/RSCDSUser.php @@ -298,6 +298,56 @@ EOSQL; } + /** + * Create a default home calendar for the user. + */ + function CreateHomeCalendar() { + global $session, $c; + if ( ! isset($c->home_calendar_name) || strlen($c->home_calendar_name) == 0 ) return true; + + $parent_path = "/".$this->Get('username')."/"; + $calendar_path = $parent_path . $c->home_calendar_name."/"; + $dav_etag = md5($this->user_no . $calendar_path); + $sql = "INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, "; + $sql .= "created, modified) VALUES( ?, ?, ?, ?, ?, true, current_timestamp, current_timestamp );"; + $qry = new PgQuery( $sql, $this->user_no, $parent_path, $calendar_path, $dav_etag, $this->Get('fullname') ); + if ( $qry->Exec() ) { + $c->messages[] = i18n("Home calendar added."); + dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path ); + } + else { + $c->messages[] = i18n("There was an error writing to the database."); + return false; + } + return true; + } + + + /** + * Create default relationships + */ + function CreateDefaultRelationships() { + global $session, $c; + if ( ! isset($c->default_relationships) || !is_array($c->default_relationships) || count($c->default_relationships) == 0 ) return false; + + $sql = ""; + foreach( $c->default_relationships AS $to_user => $permission ) { + $sql .= "INSERT INTO relationship (from_user, to_user, rt_id) "; + $sql .= "VALUES( $this->user_no, $to_user, (select rt_id from relationship_type where confers = '$permission' order by rt_id limit 1) );"; + } + $qry = new PgQuery( $sql ); + if ( $qry->Exec() ) { + $c->messages[] = i18n("Default relationships added."); + dbg_error_log("User",":Write: Added default relationships" ); + } + else { + $c->messages[] = i18n("There was an error writing to the database."); + return false; + } + return true; + } + + /** * Write the record to the file */ @@ -306,22 +356,8 @@ EOSQL; if ( parent::Write() ) { if ( $this->WriteType == 'insert' ) { - if ( isset($c->home_calendar_name) && strlen($c->home_calendar_name) > 0 ) { - $parent_path = "/".$this->Get('username')."/"; - $calendar_path = $parent_path . $c->home_calendar_name."/"; - $dav_etag = md5($this->user_no . $calendar_path); - $sql = "INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, "; - $sql .= "created, modified) VALUES( ?, ?, ?, ?, ?, true, current_timestamp, current_timestamp );"; - $qry = new PgQuery( $sql, $this->user_no, $parent_path, $calendar_path, $dav_etag, $this->Get('fullname') ); - if ( $qry->Exec() ) { - $c->messages[] = i18n("Home calendar added."); - dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path ); - } - else { - $c->messages[] = i18n("There was an error writing to the database."); - return false; - } - } + $this->CreateHomeCalendar(); + $this->CreateDefaultRelationships(); } if ( $this->AllowedTo("Admin") && isset($_POST['relate_to']) && isset($_POST['relate_as']) && isset($_POST['submit']) && $_POST['submit'] == htmlspecialchars(translate('Add Relationship')) ) { dbg_error_log("User",":Write: Adding relationship as %d to %d", $_POST['relate_as'], isset($_POST['relate_to'] ) ); From fc66ea3bd0fc3854d407eaedb00a0ad8310f99a8 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 27 Oct 2007 15:24:55 +1300 Subject: [PATCH 028/189] Only display the relationships menu for Admin users. --- inc/interactive-page.php | 4 ++-- inc/page-header.php | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/inc/interactive-page.php b/inc/interactive-page.php index 1235a06a..8d0ee70d 100644 --- a/inc/interactive-page.php +++ b/inc/interactive-page.php @@ -5,14 +5,14 @@ $page_menu->AddOption(translate("Home"),"$c->base_url/index.php",translate("Brow if ( $session->AllowedTo("Admin" )) { // $page_menu->AddOption(translate("Setup"),"$c->base_url/setup.php",translate("Setup RSCDS"), false, 5000 ); $page_menu->AddOption(translate("Operations"),"$c->base_url/tools.php",translate("Operations on your calendar"), false, 5200 ); + + $relationship_menu = new MenuSet('submenu', 'submenu', 'submenu_active'); } $page_menu->AddOption(translate("Logout"),"$c->base_url/index.php?logout",translate("Log out of the").$c->system_name, false, 5400 ); $page_menu->AddOption(translate("Help"),"$c->base_url/help.php",translate("Help on something or other"), false, 8500 ); $page_menu->AddOption(translate("Report Bug"),"http://sourceforge.net/tracker/?func=add&group_id=179845&atid=890785",translate("Report a bug in the system"), false, 9000 ); -$relationship_menu = new MenuSet('submenu', 'submenu', 'submenu_active'); $user_menu = new MenuSet('submenu', 'submenu', 'submenu_active'); -// $role_menu = new MenuSet('submenu', 'submenu', 'submenu_active'); $user_menu->AddOption(translate("My Details"),"$c->base_url/usr.php?user_no=$session->user_no",translate("View my own user record"), false, 700); diff --git a/inc/page-header.php b/inc/page-header.php index b6ae34d6..1893b17c 100644 --- a/inc/page-header.php +++ b/inc/page-header.php @@ -69,8 +69,10 @@ EOHDR; echo "
\n"; if ( isset($page_menu) && is_object($page_menu) ) { - $page_menu->AddSubMenu( $relationship_menu, translate("Relationships"), + if ( isset($relationship_menu) && is_object($relationship_menu) ) { + $page_menu->AddSubMenu( $relationship_menu, translate("Relationships"), "$c->base_url/relationship_types.php", translate("Browse all relationship types"), false, 4050 ); + } $page_menu->AddSubMenu( $user_menu, translate("Users"), "$c->base_url/users.php", translate("Browse all users"), false, 4100 ); // $page_menu->AddSubMenu( $role_menu, "Roles", "/roles.php", "Browse all roles", false, 4300 ); $page_menu->MakeSomethingActive($active_menu_pattern); From 2b9b5634c8f9393e92b2f1dc716f9d9d4c07896e Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 27 Oct 2007 20:31:42 +1300 Subject: [PATCH 029/189] Removing closing tags which are not required. --- config/example-config.php | 3 --- inc/RSCDSUser.php | 1 - 2 files changed, 4 deletions(-) diff --git a/config/example-config.php b/config/example-config.php index 6a8817d3..9195fb73 100644 --- a/config/example-config.php +++ b/config/example-config.php @@ -229,6 +229,3 @@ $c->admin_email ='calendar-admin@example.com'; * of a VEVENT. The local (server) time zone will be used as a default. */ // $c->local_tzid; - - -?> diff --git a/inc/RSCDSUser.php b/inc/RSCDSUser.php index 223cc9c6..56db0e03 100644 --- a/inc/RSCDSUser.php +++ b/inc/RSCDSUser.php @@ -376,4 +376,3 @@ EOSQL; } } -?> From e49987b0699d5eba3eef4ead33ca28f949523255 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 28 Oct 2007 10:25:23 +1300 Subject: [PATCH 030/189] Remove erroneous messages when you just hi 'Enter' instead of clicking submit. --- inc/RSCDSUser.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inc/RSCDSUser.php b/inc/RSCDSUser.php index 56db0e03..656a7159 100644 --- a/inc/RSCDSUser.php +++ b/inc/RSCDSUser.php @@ -359,7 +359,7 @@ EOSQL; $this->CreateHomeCalendar(); $this->CreateDefaultRelationships(); } - if ( $this->AllowedTo("Admin") && isset($_POST['relate_to']) && isset($_POST['relate_as']) && isset($_POST['submit']) && $_POST['submit'] == htmlspecialchars(translate('Add Relationship')) ) { + if ( $this->AllowedTo("Admin") && isset($_POST['relate_to']) && $_POST['relate_to'] != '' && isset($_POST['relate_as']) && $_POST['relate_as'] != '' && isset($_POST['submit']) && $_POST['submit'] == htmlspecialchars(translate('Add Relationship')) ) { dbg_error_log("User",":Write: Adding relationship as %d to %d", $_POST['relate_as'], isset($_POST['relate_to'] ) ); $qry = new PgQuery("INSERT INTO relationship (from_user, to_user, rt_id ) VALUES( $this->user_no, ?, ? )", $_POST['relate_to'], $_POST['relate_as'] ); if ( $qry->Exec() ) { @@ -374,5 +374,6 @@ EOSQL; } return false; } + } From b27b0d4c7b62de20c327caa98f91dd4d68063632 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 28 Oct 2007 10:27:16 +1300 Subject: [PATCH 031/189] Added auth functions to implement creation of home calendar and addition of default relationships, and write replacement for auth_other_awl which uses these. --- inc/auth-functions.php | 142 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 inc/auth-functions.php diff --git a/inc/auth-functions.php b/inc/auth-functions.php new file mode 100644 index 00000000..51d59e3a --- /dev/null +++ b/inc/auth-functions.php @@ -0,0 +1,142 @@ +authenticate_hook['config'], which might be an array, or whatever is needed. +* +* In order to be called: +* - This file should be included +* - $c->authenticate_hook['call'] should be set to the name of the plugin +* - $c->authenticate_hook['config'] should be set up with any configuration data for the plugin +* +* @package davical +* @subpackage authentication +* @author Andrew McMillan +* @copyright Catalyst IT Ltd +* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 +*/ + +require_once("AWLUtilities.php"); + +/** +* Create a default home calendar for the user. +* @param string $username The username of the user we are creating relationships for. +*/ +function CreateHomeCalendar( $username ) { + global $session, $c; + if ( ! isset($c->home_calendar_name) || strlen($c->home_calendar_name) == 0 ) return true; + + $usr = getUserByName( $username ); + $parent_path = "/".$username."/"; + $calendar_path = $parent_path . $c->home_calendar_name."/"; + $dav_etag = md5($usr->user_no . $calendar_path); + $sql = "INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, "; + $sql .= "created, modified) VALUES( ?, ?, ?, ?, ?, true, current_timestamp, current_timestamp );"; + $qry = new PgQuery( $sql, $this->user_no, $parent_path, $calendar_path, $dav_etag, $usr->fullname) ); + if ( $qry->Exec() ) { + $c->messages[] = i18n("Home calendar added."); + dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path ); + } + else { + $c->messages[] = i18n("There was an error writing to the database."); + return false; + } + return true; +} + + +/** +* Create default relationships +* @param string $username The username of the user we are creating relationships for. +*/ +function CreateDefaultRelationships( $username ) { + global $session, $c; + if ( ! isset($c->default_relationships) || !is_array($c->default_relationships) || count($c->default_relationships) == 0 ) return false; + + $usr = getUserByName( $username ); + $sql = ""; + foreach( $c->default_relationships AS $to_user => $permission ) { + $sql .= "INSERT INTO relationship (from_user, to_user, rt_id) "; + $sql .= "VALUES( $usr->user_no, $to_user, (select rt_id from relationship_type where confers = '$permission' order by rt_id limit 1) );"; + } + $qry = new PgQuery( $sql ); + if ( $qry->Exec() ) { + $c->messages[] = i18n("Default relationships added."); + dbg_error_log("User",":Write: Added default relationships" ); + } + else { + $c->messages[] = i18n("There was an error writing to the database."); + return false; + } + return true; +} + + +/** +* Authenticate against a different PostgreSQL database which contains a usr table in +* the AWL format. +* +* @package davical +*/ +function AuthExternalAWL( $username, $password ) { + global $c; + + $authconn = pg_Connect($c->authenticate_hook['config']['connection']); + if ( ! $authconn ) { + echo <<Database Connection Failure +

Database Error

+

Could not connect to PostgreSQL database

+ + +EOERRMSG; + exit(1); + } + + if ( isset($c->authenticate_hook['config']['columns']) ) + $cols = $c->authenticate_hook['config']['columns']; + else + $cols = "*"; + + $qry = new PgQuery("SELECT $cols FROM usr WHERE lower(username) = ? ", strtolower($username) ); + $qry->SetConnection($authconn); + if ( $qry->Exec('Login',__LINE,__FILE__) && $qry->rows == 1 ) { + $usr = $qry->Fetch(); + if ( session_validate_password( $password, $usr->password ) ) { + + $qry = new PgQuery("SELECT * FROM usr WHERE user_no = $usr->user_no;" ); + if ( $qry->Exec('Login',__LINE,__FILE__) && $qry->rows == 1 ) + $type = "UPDATE"; + else + $type = "INSERT"; + + include_once("DataUpdate.php"); + $qry = new PgQuery( sql_from_object( $usr, $type, 'usr', "WHERE user_no=$usr->user_no" ) ); + $qry->Exec('Login',__LINE,__FILE__); + + /** + * We disallow login by inactive users _after_ we have updated the local copy + */ + if ( isset($usr->active) && $usr->active == 'f' ) return false; + + if ( $type == 'INSERT' ) { + CreateHomeCalendar($usr->username); + CreateDefaultRelationships($usr->username); + } + + return $usr; + } + } + + return false; + +} From a79967dfa866cd7cf867b48db4c6e1f0e4fdedb5 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 28 Oct 2007 18:18:06 +1300 Subject: [PATCH 032/189] This should now use the auth functions to create default relationships & calendar. --- inc/RSCDSUser.php | 56 ++++------------------------------------------- 1 file changed, 4 insertions(+), 52 deletions(-) diff --git a/inc/RSCDSUser.php b/inc/RSCDSUser.php index 656a7159..b63de84a 100644 --- a/inc/RSCDSUser.php +++ b/inc/RSCDSUser.php @@ -11,6 +11,7 @@ require_once("User.php"); require_once("classBrowser.php"); +require_once("auth-functions.php"); $c->stylesheets[] = "$c->base_url/css/browse.css"; $c->scripts[] = "$c->base_url/js/browse.js"; @@ -298,56 +299,6 @@ EOSQL; } - /** - * Create a default home calendar for the user. - */ - function CreateHomeCalendar() { - global $session, $c; - if ( ! isset($c->home_calendar_name) || strlen($c->home_calendar_name) == 0 ) return true; - - $parent_path = "/".$this->Get('username')."/"; - $calendar_path = $parent_path . $c->home_calendar_name."/"; - $dav_etag = md5($this->user_no . $calendar_path); - $sql = "INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, "; - $sql .= "created, modified) VALUES( ?, ?, ?, ?, ?, true, current_timestamp, current_timestamp );"; - $qry = new PgQuery( $sql, $this->user_no, $parent_path, $calendar_path, $dav_etag, $this->Get('fullname') ); - if ( $qry->Exec() ) { - $c->messages[] = i18n("Home calendar added."); - dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path ); - } - else { - $c->messages[] = i18n("There was an error writing to the database."); - return false; - } - return true; - } - - - /** - * Create default relationships - */ - function CreateDefaultRelationships() { - global $session, $c; - if ( ! isset($c->default_relationships) || !is_array($c->default_relationships) || count($c->default_relationships) == 0 ) return false; - - $sql = ""; - foreach( $c->default_relationships AS $to_user => $permission ) { - $sql .= "INSERT INTO relationship (from_user, to_user, rt_id) "; - $sql .= "VALUES( $this->user_no, $to_user, (select rt_id from relationship_type where confers = '$permission' order by rt_id limit 1) );"; - } - $qry = new PgQuery( $sql ); - if ( $qry->Exec() ) { - $c->messages[] = i18n("Default relationships added."); - dbg_error_log("User",":Write: Added default relationships" ); - } - else { - $c->messages[] = i18n("There was an error writing to the database."); - return false; - } - return true; - } - - /** * Write the record to the file */ @@ -356,8 +307,9 @@ EOSQL; if ( parent::Write() ) { if ( $this->WriteType == 'insert' ) { - $this->CreateHomeCalendar(); - $this->CreateDefaultRelationships(); + $username = $this->Get('username'); + CreateHomeCalendar($username); + CreateDefaultRelationships($username); } if ( $this->AllowedTo("Admin") && isset($_POST['relate_to']) && $_POST['relate_to'] != '' && isset($_POST['relate_as']) && $_POST['relate_as'] != '' && isset($_POST['submit']) && $_POST['submit'] == htmlspecialchars(translate('Add Relationship')) ) { dbg_error_log("User",":Write: Adding relationship as %d to %d", $_POST['relate_as'], isset($_POST['relate_to'] ) ); From c2794db775aa34ea4708f71bae02be4f715fc425 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 28 Oct 2007 18:19:14 +1300 Subject: [PATCH 033/189] Maxime Delorme suggested that we should do this differently now that the iCalendar class is more functional. I agree. --- inc/caldav-GET.php | 7 ++++++- inc/caldav-REPORT.php | 11 ++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/inc/caldav-GET.php b/inc/caldav-GET.php index 9c3b4547..e2b1bb57 100644 --- a/inc/caldav-GET.php +++ b/inc/caldav-GET.php @@ -45,6 +45,10 @@ else if ( $qry->rows > 1 ) { */ include_once("iCalendar.php"); $response = iCalendar::iCalHeader(); + $collqry = new PgQuery( "SELECT * FROM collection WHERE collection.user_no = ? AND collection.dav_name = ?;", $request->user_no, $request->path); + if ( $collqry->Exec("GET") && $collection = $collqry->Fetch() ) { + $response .= "X-WR-CALNAME:$collection->dav_displayname\r\n"; + } $timezones = array(); while( $event = $qry->Fetch() ) { $ical = new iCalendar( array( "icalendar" => $event->caldav_data ) ); @@ -63,7 +67,8 @@ else if ( $qry->rows > 1 ) { } elseif ( $c->hide_alarm ) { // Otherwise we hide the alarms (if configured to) - $response .= $ical->Render( false, $event->caldav_type, $ical->DefaultPropertyList() ); + $ical->component->ClearComponents('VALARM'); + $response .= $ical->render(true, $event->caldav_type ); } else { $response .= $ical->Render( false, $event->caldav_type ); diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index e688cc76..02c7abd1 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -73,14 +73,15 @@ function calendar_to_xml( $properties, $item ) { if ( $item->class == 'CONFIDENTIAL' ) { // if the event is confidential we fake one that just says "Busy" $displayname = translate("Busy"); - $ical = new iCalendar( array( "icalendar" => $item->caldav_data) ); + $ical = new iCalendar( array( "icalendar" => $caldav_data) ); $ical->Put( 'SUMMARY', $displayname ); - $caldav_data = $ical->render(true, $item->caldav_type, $ical->DefaultPropertyList() ); + $caldav_data = $ical->render(true, $caldav_type, $ical->DefaultPropertyList() ); } elseif ( $c->hide_alarm ) { // Otherwise we hide the alarms (if configured to) - $ical = new iCalendar( array( "icalendar" => $item->caldav_data) ); - $caldav_data = $ical->render(true, $item->caldav_type, $ical->DefaultPropertyList() ); + $ical = new iCalendar( array( "icalendar" => $caldav_data) ); + $ical->component->ClearComponents('VALARM'); + $caldav_data = $ical->render(true, $caldav_type ); } } } @@ -90,7 +91,7 @@ function calendar_to_xml( $properties, $item ) { foreach( $properties AS $k => $v ) { switch( $k ) { case 'GETCONTENTLENGTH': - $contentlength = strlen($item->caldav_data); + $contentlength = strlen($caldav_data); $prop->NewElement("getcontentlength", $contentlength ); break; case 'CALENDAR-DATA': From 1083970df86f2ad3836c0de817de75f41cfaf61d Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 28 Oct 2007 20:40:39 +1300 Subject: [PATCH 034/189] Some vague changes in the hope that it might work better with iCal. I really need to spend some time with a Mac to make this work, I think... --- inc/caldav-PROPFIND.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 01da492e..0a0c67e1 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -2,8 +2,8 @@ /** * CalDAV Server - handle PROPFIND method * -* @package rscds -* @subpackage caldav +* @package davical +* @subpackage propfind * @author Andrew McMillan * @copyright Catalyst .Net Ltd * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 @@ -41,6 +41,8 @@ foreach( $request->xml_tags AS $k => $v ) { case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-INSTANCES': case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-ATTENDEES-PER-INSTANCE': case 'HTTP://APACHE.ORG/DAV/PROPS/:EXECUTABLE': + case 'HTTP://CALENDARSERVER.ORG/NS/:DROPBOX-HOME-URL': + case 'HTTP://CALENDARSERVER.ORG/NS/:NOTIFICATIONS-URL': case 'DAV::CHECKED-OUT': case 'DAV::CHECKED-IN': case 'DAV::SOURCE': @@ -84,6 +86,9 @@ foreach( $request->xml_tags AS $k => $v ) { /** * Add the ones that are specifically unsupported here. */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-USER-ADDRESS-SET': /** calendar-schedule is not supported */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:SCHEDULE-INBOX-URL': /** calendar-schedule is not supported */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:SCHEDULE-OUTBOX-URL': /** calendar-schedule is not supported */ case 'UNSUPPORTED': if ( preg_match('/^(.*):([^:]+)$/', $tag, $matches) ) { $unsupported[$matches[2]] = $matches[1]; From 0479ca423ad6b81668779b3f81b937f7bee3bbd6 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 28 Oct 2007 20:42:00 +1300 Subject: [PATCH 035/189] New files. --- rscds.webprj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rscds.webprj b/rscds.webprj index 3f2bb97a..a32321e0 100644 --- a/rscds.webprj +++ b/rscds.webprj @@ -239,5 +239,7 @@ + + From 973a8235b4e72f5e1717ed5f5c4e55106d5e400a Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Mon, 29 Oct 2007 18:12:20 +1300 Subject: [PATCH 036/189] Remove extraneous bracket. --- inc/auth-functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/auth-functions.php b/inc/auth-functions.php index 51d59e3a..202b203c 100644 --- a/inc/auth-functions.php +++ b/inc/auth-functions.php @@ -41,7 +41,7 @@ function CreateHomeCalendar( $username ) { $dav_etag = md5($usr->user_no . $calendar_path); $sql = "INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, "; $sql .= "created, modified) VALUES( ?, ?, ?, ?, ?, true, current_timestamp, current_timestamp );"; - $qry = new PgQuery( $sql, $this->user_no, $parent_path, $calendar_path, $dav_etag, $usr->fullname) ); + $qry = new PgQuery( $sql, $this->user_no, $parent_path, $calendar_path, $dav_etag, $usr->fullname); if ( $qry->Exec() ) { $c->messages[] = i18n("Home calendar added."); dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path ); From c0a00fd41927f1b73f38ae5bc55a7d26e4cb0479 Mon Sep 17 00:00:00 2001 From: Maxime Delorme Date: Mon, 29 Oct 2007 18:13:17 +1300 Subject: [PATCH 037/189] Fix some comments. --- inc/caldav-PUT-functions.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index ebf9851a..e58af608 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -12,8 +12,7 @@ include_once("iCalendar.php"); * This function launches an error * @param boolean $caldav_context Whether we are responding via CalDAV or interactively * @param int $user_no the user wich will receive this ics file -* @param string $path the $path where it will be store such as /user_foo/home/ -* @param boolean $caldav_context Whether we are responding via CalDAV or interactively +* @param string $path the $path where the PUT failed to store such as /user_foo/home/ * @param string $message An optional error message to return to the client * @param int $error_no An optional value for the HTTP error code */ @@ -84,7 +83,7 @@ function controlRequestContainer( $username, $user_no, $path, $caldav_context ) } /** -* Check if this collection sould force all events to be PUBLIC. +* Check if this collection should force all events to be PUBLIC. * @param string $user_no the user that owns the collection * @param string $dav_name the collection to check * @return boolean Return true if public events only are allowed. @@ -252,7 +251,7 @@ EOSQL; /** * Put the resource from this request * @param object $request A reference to the request object -* @param int $user_no The owner of the collection where we are putting this resource +* @param int $author The user_no who wants to put this resource on the server * @param boolean $caldav_context Whether we are responding via CalDAV or interactively * @return string Either 'INSERT' or 'UPDATE': the type of action that the PUT resulted in */ From ca10fb50c1dcf4cf409c55309fd6c246cd0ccb50 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Mon, 29 Oct 2007 18:14:10 +1300 Subject: [PATCH 038/189] Move the DAV: header to caldav.php, rather than only sending it for the OPTIONS request. --- htdocs/caldav.php | 12 ++++++++++++ inc/caldav-OPTIONS.php | 12 ------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/htdocs/caldav.php b/htdocs/caldav.php index ccecb73f..4d89ba1b 100644 --- a/htdocs/caldav.php +++ b/htdocs/caldav.php @@ -14,6 +14,18 @@ require_once("HTTPAuthSession.php"); $session = new HTTPAuthSession(); dbg_log_array( "headers", '_SERVER', $_SERVER, true ); +/** +* From reading the "Scheduling Extensions to CalDAV" draft I don't think that we will +* be doing 'calendar-schedule' any time soon. The current spec is at: +* http://www.ietf.org/internet-drafts/draft-desruisseaux-caldav-sched-03.txt +* +* access-control is rfc3744, so we will say we do it, but I doubt if we do it +* in all (or even much of) it's glory really. +*/ +$dav = "1, 2, access-control, calendar-access"; +header( "DAV: $dav"); +// header( "DAV: 1, 2, access-control, calendar-access, calendar-schedule"); + require_once("CalDAVRequest.php"); $request = new CalDAVRequest(); diff --git a/inc/caldav-OPTIONS.php b/inc/caldav-OPTIONS.php index 33c99232..2f1197ea 100644 --- a/inc/caldav-OPTIONS.php +++ b/inc/caldav-OPTIONS.php @@ -58,18 +58,6 @@ else { } header( "Allow: $allowed"); -/** -* From reading the "Scheduling Extensions to CalDAV" draft I don't think that we will -* be doing 'calendar-schedule' any time soon. The current spec is at: -* http://www.ietf.org/internet-drafts/draft-desruisseaux-caldav-sched-03.txt -* -* access-control is rfc3744, so we will say we do it, but I doubt if we do it -* in all (or even much of) it's glory really. -*/ -$dav = "1, 2, access-control, calendar-access"; -header( "Allow: $allowed"); -header( "DAV: $dav"); -// header( "DAV: 1, 2, access-control, calendar-access, calendar-schedule"); $request->DoResponse( 200, "" ); From 48dc44eba769f14dc10f13c2dd8bb75641e6b50e Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Mon, 29 Oct 2007 18:14:52 +1300 Subject: [PATCH 039/189] Fleshing out the 'principal' object slightly. --- inc/CalDAVRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index cfc6983a..7e900200 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -156,7 +156,9 @@ class CalDAVRequest */ $this->UserFromPath(); $this->principal->url = sprintf( "%s/%s/", $c->protocol_server_port_script, $this->principal->username); - $this->principal->calendar_home_set = sprintf( "%s/%s/%s/", $c->protocol_server_port_script, $this->principal->username, $c->home_calendar_name); + $this->principal->calendar_home_set = sprintf( "%s%s/", $this->principal->url, $c->home_calendar_name); + $this->principal->schedule_inbox_url = sprintf( "%s.inbox/", $this->principal->url); + $this->principal->schedule_outbox_url = sprintf( "%s.outbox/", $this->principal->url); /** * Evaluate our permissions for accessing the target From 85707c9eba17cacc40675e341c35942dcda7295e Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Tue, 30 Oct 2007 10:15:06 +1300 Subject: [PATCH 040/189] Results change due to moving the DAV: header and PROPFIND changes --- .../regression-suite/001-Mulberry-1.result | 2 +- .../regression-suite/002-Mulberry-1.result | 7 ++-- .../regression-suite/003-Mulberry-1.result | 7 ++-- .../regression-suite/004-Mulberry-1.result | 1 + .../regression-suite/005-Mulberry-1.result | 9 ++--- .../regression-suite/006-Mulberry-1.result | 9 ++--- .../regression-suite/007-Mulberry-1.result | 1 + .../010-Mulberry-PUT-1.result | 1 + .../011-Mulberry-PUT-1b.result | 1 + .../012-Mulberry-PUT-2.result | 1 + .../013-Mulberry-PROPFIND-5.result | 9 ++--- .../014-Mulberry-PUT-3.result | 1 + .../015-Mulberry-PROPFIND-6.result | 9 ++--- .../016-Mulberry-MKCALENDAR-3.result | 1 + .../017-Mulberry-MKCALENDAR-4.result | 1 + .../018-Mulberry-PUT-4.result | 1 + .../019-Mulberry-OPTIONS-3.result | 1 + .../020-Mulberry-DELETE-1.result | 1 + .../021-Mulberry-DELETE-2.result | 1 + .../022-Mulberry-PUT-5.result | 1 + .../023-Mulberry-DELETE-3.result | 1 + .../regression-suite/101-Evo-OPTIONS-1.result | 2 +- .../regression-suite/102-Evo-REPORT-1.result | 1 + .../regression-suite/103-Evo-GET-1.result | 1 + .../regression-suite/104-Evo-PUT-1.result | 1 + .../regression-suite/105-Evo-REPORT-1.result | 1 + .../regression-suite/106-Evo-GET-1.result | 1 + .../regression-suite/107-Evo-REPORT-1.result | 1 + .../regression-suite/108-Evo-REPORT-1.result | 1 + .../regression-suite/201-Moz-OPTIONS-2.result | 2 +- .../regression-suite/203-Moz-REPORT-2.result | 1 + .../regression-suite/204-Moz-REPORT-3.result | 1 + .../205-Moz-PROPFIND-1.result | 9 ++--- .../regression-suite/206-Moz-PUT-1.result | 1 + .../regression-suite/207-Moz-REPORT-4.result | 1 + .../regression-suite/208-Moz-REPORT-5.result | 1 + .../209-Moz-PUT-CONFIDENTIAL.result | 1 + .../210-Moz-PUT-PRIVATE.result | 1 + .../211-Moz-PUT-TENTATIVE.result | 1 + .../regression-suite/212-Moz-PROPFIND.result | 9 ++--- .../213-Moz-MKCALENDAR.result | 1 + .../214-Moz-PUT-New-Task.result | 1 + .../215-Moz-PUT-InProgress-Task.result | 1 + .../216-Moz-PUT-Completed-Task.result | 1 + .../217-Moz-PUT-Cancelled-Task.result | 1 + .../230-Moz-REPORT-Tasks-Completed.result | 1 + .../231-Moz-REPORT-All-Tasks.result | 1 + .../302-Chandler-OPTIONS-2.result | 2 +- .../303-Chandler-PROPFIND-1.result | 9 ++--- .../304-Chandler-PROPFIND-2.result | 9 ++--- .../305-Chandler-MKCOL-1.result | 1 + .../306-Chandler-DELETE-1.result | 1 + .../308-Chandler-OPTIONS-3.result | 2 +- .../309-Chandler-PROPFIND-3.result | 9 ++--- .../309-Chandler-PROPFIND-4.result | 9 ++--- .../310-Chandler-PUT-1.result | 1 + .../311-Chandler-PUT-2.result | 1 + .../400-Cadaver-OPTIONS-1.result | 2 +- .../401-Cadaver-PROPFIND-1.result | 12 +++++-- .../regression-suite/510-iCal-PROPFIND.result | 35 +++++++++++++++---- .../regression-suite/800-Spec-LOCK-1.result | 1 + .../regression-suite/801-Spec-LOCK-1.result | 1 + .../regression-suite/802-Spec-LOCK-1.result | 1 + .../803-Mulberry-PUT-1.result | 1 + .../804-Mulberry-PUT-1.result | 1 + .../805-Mulberry-DELETE-1.result | 1 + .../806-Mulberry-DELETE-1.result | 1 + .../regression-suite/808-Spec-UNLOCK-1.result | 1 + .../regression-suite/809-Spec-UNLOCK-1.result | 1 + .../regression-suite/810-Spec-LOCK-1.result | 1 + .../regression-suite/811-Spec-LOCK-1.result | 1 + .../regression-suite/812-Spec-LOCK-1.result | 1 + .../regression-suite/815-Spec-UNLOCK-1.result | 1 + .../regression-suite/816-Spec-UNLOCK-1.result | 1 + .../820-Spec-PROPFIND-1.result | 13 +++++-- .../821-Spec-PROPFIND-2.result | 20 ++++++++--- .../822-Spec-PROPFIND-3.result | 13 +++++-- .../823-Spec-PROPFIND-4.result | 2 +- .../824-Spec-PROPFIND-5.result | 20 +++++------ .../825-Spec-PROPFIND-6.result | 2 +- .../830-Spec-FREEBUSY-1.result | 1 + .../regression-suite/831-Spec-RRULE-1.result | 1 + .../834-Spec-FREEBUSY-1.result | 1 + .../840-Spec-PROPPATCH-1.result | 1 + .../841-Spec-PROPPATCH-2.result | 1 + .../842-Spec-PROPPATCH-3.result | 1 + .../regression-suite/843-Spec-PROPFIND.result | 9 +++-- .../regression-suite/850-Spec-REPORT-1.result | 1 + .../regression-suite/851-Spec-REPORT-1.result | 1 + .../860-Spec-REPORT-principal.result | 1 + .../861-Spec-REPORT-principal.result | 1 + .../862-Spec-REPORT-principal.result | 1 + .../863-Spec-REPORT-principal.result | 1 + .../regression-suite/900-Moz-REPORT.result | 1 + .../901-GET-Collection.result | 4 ++- .../902-PUT-collection.result | 1 + .../903-GET-Collection.result | 4 ++- 97 files changed, 232 insertions(+), 86 deletions(-) diff --git a/testing/tests/regression-suite/001-Mulberry-1.result b/testing/tests/regression-suite/001-Mulberry-1.result index b6a4a51f..b8f2be75 100644 --- a/testing/tests/regression-suite/001-Mulberry-1.result +++ b/testing/tests/regression-suite/001-Mulberry-1.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH DAV: 1, 2, access-control, calendar-access +Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/002-Mulberry-1.result b/testing/tests/regression-suite/002-Mulberry-1.result index 5a4fff79..4eed464e 100644 --- a/testing/tests/regression-suite/002-Mulberry-1.result +++ b/testing/tests/regression-suite/002-Mulberry-1.result @@ -1,11 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "373430133d9c51260783bc61177aa1d3" -Content-Length: 1880 +DAV: 1, 2, access-control, calendar-access +ETag: "e4c5d91096060db78286e699730987a1" +Content-Length: 1920 Content-Type: text/xml; charset="utf-8" - + /caldav.php/ diff --git a/testing/tests/regression-suite/003-Mulberry-1.result b/testing/tests/regression-suite/003-Mulberry-1.result index 6013ef34..dbc49d44 100644 --- a/testing/tests/regression-suite/003-Mulberry-1.result +++ b/testing/tests/regression-suite/003-Mulberry-1.result @@ -1,11 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "cc0f368288b5b8373d00e28f842190e6" -Content-Length: 383 +DAV: 1, 2, access-control, calendar-access +ETag: "792db2309cf4d54e7c00bbe79633895f" +Content-Length: 423 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/ diff --git a/testing/tests/regression-suite/004-Mulberry-1.result b/testing/tests/regression-suite/004-Mulberry-1.result index 6e110ab3..6b4bc2bf 100644 --- a/testing/tests/regression-suite/004-Mulberry-1.result +++ b/testing/tests/regression-suite/004-Mulberry-1.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Cache-Control: no-cache Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/005-Mulberry-1.result b/testing/tests/regression-suite/005-Mulberry-1.result index b0a0ee71..09b6e087 100644 --- a/testing/tests/regression-suite/005-Mulberry-1.result +++ b/testing/tests/regression-suite/005-Mulberry-1.result @@ -1,11 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "4bbc059be0ae780aa041d72b2ee837a6" -Content-Length: 726 +DAV: 1, 2, access-control, calendar-access +ETag: "a30e9b8f2662cd1da17252d3b814ef04" +Content-Length: 730 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/ @@ -28,7 +29,7 @@ Content-Type: text/xml; charset="utf-8" - + HTTP/1.1 200 OK diff --git a/testing/tests/regression-suite/006-Mulberry-1.result b/testing/tests/regression-suite/006-Mulberry-1.result index e9e0df4c..d8cee0d6 100644 --- a/testing/tests/regression-suite/006-Mulberry-1.result +++ b/testing/tests/regression-suite/006-Mulberry-1.result @@ -1,11 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "63c4632cd1f99190e4613ed7912bc44a" -Content-Length: 483 +DAV: 1, 2, access-control, calendar-access +ETag: "7364b32495feb0c9bbe89cdb10988762" +Content-Length: 487 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ @@ -14,7 +15,7 @@ Content-Type: text/xml; charset="utf-8" - + "faf25336de0e470a54075c14cbcf5272" diff --git a/testing/tests/regression-suite/007-Mulberry-1.result b/testing/tests/regression-suite/007-Mulberry-1.result index 8863aeea..2940ced5 100644 --- a/testing/tests/regression-suite/007-Mulberry-1.result +++ b/testing/tests/regression-suite/007-Mulberry-1.result @@ -1,5 +1,6 @@ HTTP/1.1 405 Method Not Allowed Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 45 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/010-Mulberry-PUT-1.result b/testing/tests/regression-suite/010-Mulberry-PUT-1.result index 0a6ba774..405e9f72 100644 --- a/testing/tests/regression-suite/010-Mulberry-PUT-1.result +++ b/testing/tests/regression-suite/010-Mulberry-PUT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "b000d7defa19ccb7cd21e546b54155ee" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/011-Mulberry-PUT-1b.result b/testing/tests/regression-suite/011-Mulberry-PUT-1b.result index 5dc03f38..2e1952c6 100644 --- a/testing/tests/regression-suite/011-Mulberry-PUT-1b.result +++ b/testing/tests/regression-suite/011-Mulberry-PUT-1b.result @@ -1,5 +1,6 @@ HTTP/1.1 204 No Content Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "b000d7defa19ccb7cd21e546b54155ee" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/012-Mulberry-PUT-2.result b/testing/tests/regression-suite/012-Mulberry-PUT-2.result index 1de81e3d..fbf7eaf9 100644 --- a/testing/tests/regression-suite/012-Mulberry-PUT-2.result +++ b/testing/tests/regression-suite/012-Mulberry-PUT-2.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "22158fc45876987b2b00749a3a1684d8" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result b/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result index 692abad2..a3dd940f 100644 --- a/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result +++ b/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result @@ -1,11 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "3f528a647491c5f1bd3e5ac60dc7d471" -Content-Length: 1051 +DAV: 1, 2, access-control, calendar-access +ETag: "4cd4df7d08592927b92bcd697c2cdde7" +Content-Length: 1055 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ @@ -14,7 +15,7 @@ Content-Type: text/xml; charset="utf-8" 1425 - + HTTP/1.1 200 OK diff --git a/testing/tests/regression-suite/014-Mulberry-PUT-3.result b/testing/tests/regression-suite/014-Mulberry-PUT-3.result index 45589c03..b2d87cd2 100644 --- a/testing/tests/regression-suite/014-Mulberry-PUT-3.result +++ b/testing/tests/regression-suite/014-Mulberry-PUT-3.result @@ -1,5 +1,6 @@ HTTP/1.1 204 No Content Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "2c32a2f8aba853654eb17fe037a4db4d" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result b/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result index b255f0f6..44ab7700 100644 --- a/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result +++ b/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result @@ -1,11 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "c195de52b2e0c2e02fb1da08051bde14" -Content-Length: 1051 +DAV: 1, 2, access-control, calendar-access +ETag: "d880baf3102a9de9bcea4d5f71a6b500" +Content-Length: 1055 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ @@ -14,7 +15,7 @@ Content-Type: text/xml; charset="utf-8" 1467 - + HTTP/1.1 200 OK diff --git a/testing/tests/regression-suite/016-Mulberry-MKCALENDAR-3.result b/testing/tests/regression-suite/016-Mulberry-MKCALENDAR-3.result index 6e110ab3..6b4bc2bf 100644 --- a/testing/tests/regression-suite/016-Mulberry-MKCALENDAR-3.result +++ b/testing/tests/regression-suite/016-Mulberry-MKCALENDAR-3.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Cache-Control: no-cache Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/017-Mulberry-MKCALENDAR-4.result b/testing/tests/regression-suite/017-Mulberry-MKCALENDAR-4.result index 96547dad..1227762d 100644 --- a/testing/tests/regression-suite/017-Mulberry-MKCALENDAR-4.result +++ b/testing/tests/regression-suite/017-Mulberry-MKCALENDAR-4.result @@ -1,5 +1,6 @@ HTTP/1.1 403 Forbidden Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 36 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/018-Mulberry-PUT-4.result b/testing/tests/regression-suite/018-Mulberry-PUT-4.result index 32f2fba3..dc38ace3 100644 --- a/testing/tests/regression-suite/018-Mulberry-PUT-4.result +++ b/testing/tests/regression-suite/018-Mulberry-PUT-4.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "75a75e1c7c4546074aab7645b5323738" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/019-Mulberry-OPTIONS-3.result b/testing/tests/regression-suite/019-Mulberry-OPTIONS-3.result index 1125a74c..9f8da0b1 100644 --- a/testing/tests/regression-suite/019-Mulberry-OPTIONS-3.result +++ b/testing/tests/regression-suite/019-Mulberry-OPTIONS-3.result @@ -1,5 +1,6 @@ HTTP/1.1 400 Bad Request Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 46 Connection: close Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/020-Mulberry-DELETE-1.result b/testing/tests/regression-suite/020-Mulberry-DELETE-1.result index e81072c3..065ea916 100644 --- a/testing/tests/regression-suite/020-Mulberry-DELETE-1.result +++ b/testing/tests/regression-suite/020-Mulberry-DELETE-1.result @@ -1,5 +1,6 @@ HTTP/1.1 412 Precondition Failed Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 44 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/021-Mulberry-DELETE-2.result b/testing/tests/regression-suite/021-Mulberry-DELETE-2.result index acd10a41..f69b0439 100644 --- a/testing/tests/regression-suite/021-Mulberry-DELETE-2.result +++ b/testing/tests/regression-suite/021-Mulberry-DELETE-2.result @@ -1,5 +1,6 @@ HTTP/1.1 204 No Content Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/022-Mulberry-PUT-5.result b/testing/tests/regression-suite/022-Mulberry-PUT-5.result index ea2ed7cd..509ee1ca 100644 --- a/testing/tests/regression-suite/022-Mulberry-PUT-5.result +++ b/testing/tests/regression-suite/022-Mulberry-PUT-5.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "81979ab45975368d619171a4c3e1e5e2" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/023-Mulberry-DELETE-3.result b/testing/tests/regression-suite/023-Mulberry-DELETE-3.result index acd10a41..f69b0439 100644 --- a/testing/tests/regression-suite/023-Mulberry-DELETE-3.result +++ b/testing/tests/regression-suite/023-Mulberry-DELETE-3.result @@ -1,5 +1,6 @@ HTTP/1.1 204 No Content Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/101-Evo-OPTIONS-1.result b/testing/tests/regression-suite/101-Evo-OPTIONS-1.result index b6a4a51f..b8f2be75 100644 --- a/testing/tests/regression-suite/101-Evo-OPTIONS-1.result +++ b/testing/tests/regression-suite/101-Evo-OPTIONS-1.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH DAV: 1, 2, access-control, calendar-access +Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/102-Evo-REPORT-1.result b/testing/tests/regression-suite/102-Evo-REPORT-1.result index d99b90f6..d45bdd9f 100644 --- a/testing/tests/regression-suite/102-Evo-REPORT-1.result +++ b/testing/tests/regression-suite/102-Evo-REPORT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "7dd087918d1ab4ba7e7861307b57c6dd" Content-Length: 341 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/103-Evo-GET-1.result b/testing/tests/regression-suite/103-Evo-GET-1.result index a42dbfc4..1de6864e 100644 --- a/testing/tests/regression-suite/103-Evo-GET-1.result +++ b/testing/tests/regression-suite/103-Evo-GET-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Etag: "2c32a2f8aba853654eb17fe037a4db4d" Content-Length: 747 Content-Type: text/calendar diff --git a/testing/tests/regression-suite/104-Evo-PUT-1.result b/testing/tests/regression-suite/104-Evo-PUT-1.result index 82f5ac6f..7634dd0c 100644 --- a/testing/tests/regression-suite/104-Evo-PUT-1.result +++ b/testing/tests/regression-suite/104-Evo-PUT-1.result @@ -2,6 +2,7 @@ HTTP/1.1 100 Continue HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "c3658901fd4689d4a1e1d6f08601ef4f" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/105-Evo-REPORT-1.result b/testing/tests/regression-suite/105-Evo-REPORT-1.result index 06c90554..911c06d3 100644 --- a/testing/tests/regression-suite/105-Evo-REPORT-1.result +++ b/testing/tests/regression-suite/105-Evo-REPORT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "4b08329b0bd43cb3a95a0e4f8286c423" Content-Length: 582 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/106-Evo-GET-1.result b/testing/tests/regression-suite/106-Evo-GET-1.result index 402587fc..d779e57f 100644 --- a/testing/tests/regression-suite/106-Evo-GET-1.result +++ b/testing/tests/regression-suite/106-Evo-GET-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Etag: "c3658901fd4689d4a1e1d6f08601ef4f" Content-Length: 1059 Content-Type: text/calendar diff --git a/testing/tests/regression-suite/107-Evo-REPORT-1.result b/testing/tests/regression-suite/107-Evo-REPORT-1.result index 0847191f..f0d5e883 100644 --- a/testing/tests/regression-suite/107-Evo-REPORT-1.result +++ b/testing/tests/regression-suite/107-Evo-REPORT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "709206be6ed57942c30d98aa629efc6f" Content-Length: 560 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/108-Evo-REPORT-1.result b/testing/tests/regression-suite/108-Evo-REPORT-1.result index c5bf4a77..32b5acc4 100644 --- a/testing/tests/regression-suite/108-Evo-REPORT-1.result +++ b/testing/tests/regression-suite/108-Evo-REPORT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "5a05dff964308972a179d2e7f44bf751" Content-Length: 596 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/201-Moz-OPTIONS-2.result b/testing/tests/regression-suite/201-Moz-OPTIONS-2.result index b6a4a51f..b8f2be75 100644 --- a/testing/tests/regression-suite/201-Moz-OPTIONS-2.result +++ b/testing/tests/regression-suite/201-Moz-OPTIONS-2.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH DAV: 1, 2, access-control, calendar-access +Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/203-Moz-REPORT-2.result b/testing/tests/regression-suite/203-Moz-REPORT-2.result index 49fe44ce..607ee9da 100644 --- a/testing/tests/regression-suite/203-Moz-REPORT-2.result +++ b/testing/tests/regression-suite/203-Moz-REPORT-2.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "a57a6c930b230c67301c4295254a3521" Content-Length: 2420 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/204-Moz-REPORT-3.result b/testing/tests/regression-suite/204-Moz-REPORT-3.result index ac605afc..f9b61fc8 100644 --- a/testing/tests/regression-suite/204-Moz-REPORT-3.result +++ b/testing/tests/regression-suite/204-Moz-REPORT-3.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "46061ea7ac75102dbb315b82c666c24d" Content-Length: 1110 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/205-Moz-PROPFIND-1.result b/testing/tests/regression-suite/205-Moz-PROPFIND-1.result index 1ee96881..61354633 100644 --- a/testing/tests/regression-suite/205-Moz-PROPFIND-1.result +++ b/testing/tests/regression-suite/205-Moz-PROPFIND-1.result @@ -1,18 +1,19 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "69c451806ff9146e8c1f3113e1aa01a3" -Content-Length: 343 +DAV: 1, 2, access-control, calendar-access +ETag: "334c8abc0ac73261cdbf963fc7269d76" +Content-Length: 347 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ - + HTTP/1.1 200 OK diff --git a/testing/tests/regression-suite/206-Moz-PUT-1.result b/testing/tests/regression-suite/206-Moz-PUT-1.result index 914cb826..3cf48ddd 100644 --- a/testing/tests/regression-suite/206-Moz-PUT-1.result +++ b/testing/tests/regression-suite/206-Moz-PUT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "a1c6404d61190f9574e2bfd69383f144" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/207-Moz-REPORT-4.result b/testing/tests/regression-suite/207-Moz-REPORT-4.result index 7e0d9cbf..33886f34 100644 --- a/testing/tests/regression-suite/207-Moz-REPORT-4.result +++ b/testing/tests/regression-suite/207-Moz-REPORT-4.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "5ea083d59cfcd77e3baf11ef74297e6e" Content-Length: 1358 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/208-Moz-REPORT-5.result b/testing/tests/regression-suite/208-Moz-REPORT-5.result index b54904ce..c09243d2 100644 --- a/testing/tests/regression-suite/208-Moz-REPORT-5.result +++ b/testing/tests/regression-suite/208-Moz-REPORT-5.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "07474790757c5e1b526ce4901889d6d3" Content-Length: 68 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/209-Moz-PUT-CONFIDENTIAL.result b/testing/tests/regression-suite/209-Moz-PUT-CONFIDENTIAL.result index b912c6e2..020a839b 100644 --- a/testing/tests/regression-suite/209-Moz-PUT-CONFIDENTIAL.result +++ b/testing/tests/regression-suite/209-Moz-PUT-CONFIDENTIAL.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "08a435c2abaf38f4a50a997343c098a7" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/210-Moz-PUT-PRIVATE.result b/testing/tests/regression-suite/210-Moz-PUT-PRIVATE.result index 62437c7e..d11ac9b8 100644 --- a/testing/tests/regression-suite/210-Moz-PUT-PRIVATE.result +++ b/testing/tests/regression-suite/210-Moz-PUT-PRIVATE.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "5def8ae2b20893a1c7f4dbaeb008f2f1" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/211-Moz-PUT-TENTATIVE.result b/testing/tests/regression-suite/211-Moz-PUT-TENTATIVE.result index 1463944c..9ebb4d9a 100644 --- a/testing/tests/regression-suite/211-Moz-PUT-TENTATIVE.result +++ b/testing/tests/regression-suite/211-Moz-PUT-TENTATIVE.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "ac90acd649c25070b1a2a17fb31a105a" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/212-Moz-PROPFIND.result b/testing/tests/regression-suite/212-Moz-PROPFIND.result index c86e5c29..6b8b8031 100644 --- a/testing/tests/regression-suite/212-Moz-PROPFIND.result +++ b/testing/tests/regression-suite/212-Moz-PROPFIND.result @@ -1,19 +1,20 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Location: /user1/home/ -ETag: "69c451806ff9146e8c1f3113e1aa01a3" -Content-Length: 343 +ETag: "334c8abc0ac73261cdbf963fc7269d76" +Content-Length: 347 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ - + HTTP/1.1 200 OK diff --git a/testing/tests/regression-suite/213-Moz-MKCALENDAR.result b/testing/tests/regression-suite/213-Moz-MKCALENDAR.result index 6e110ab3..6b4bc2bf 100644 --- a/testing/tests/regression-suite/213-Moz-MKCALENDAR.result +++ b/testing/tests/regression-suite/213-Moz-MKCALENDAR.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Cache-Control: no-cache Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/214-Moz-PUT-New-Task.result b/testing/tests/regression-suite/214-Moz-PUT-New-Task.result index e17164ed..d0004d30 100644 --- a/testing/tests/regression-suite/214-Moz-PUT-New-Task.result +++ b/testing/tests/regression-suite/214-Moz-PUT-New-Task.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "509b0f0d8a3363379f9f5727f5dd74a0" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/215-Moz-PUT-InProgress-Task.result b/testing/tests/regression-suite/215-Moz-PUT-InProgress-Task.result index 2fbdb90d..c465e1b8 100644 --- a/testing/tests/regression-suite/215-Moz-PUT-InProgress-Task.result +++ b/testing/tests/regression-suite/215-Moz-PUT-InProgress-Task.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "cb3d9dc3e8c157f53eba3ea0e1e0f146" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/216-Moz-PUT-Completed-Task.result b/testing/tests/regression-suite/216-Moz-PUT-Completed-Task.result index 65a1e795..9e9452ab 100644 --- a/testing/tests/regression-suite/216-Moz-PUT-Completed-Task.result +++ b/testing/tests/regression-suite/216-Moz-PUT-Completed-Task.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "00ad5eb1eb5507884710b0b66aa5d5c4" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/217-Moz-PUT-Cancelled-Task.result b/testing/tests/regression-suite/217-Moz-PUT-Cancelled-Task.result index 711d62f2..ddf0bb73 100644 --- a/testing/tests/regression-suite/217-Moz-PUT-Cancelled-Task.result +++ b/testing/tests/regression-suite/217-Moz-PUT-Cancelled-Task.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "a2990674708634a311bb98a59865ca50" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/230-Moz-REPORT-Tasks-Completed.result b/testing/tests/regression-suite/230-Moz-REPORT-Tasks-Completed.result index 71abec17..fc880a82 100644 --- a/testing/tests/regression-suite/230-Moz-REPORT-Tasks-Completed.result +++ b/testing/tests/regression-suite/230-Moz-REPORT-Tasks-Completed.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "8f48e613721a5ccb5e44c277f7a1a909" Content-Length: 1630 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/231-Moz-REPORT-All-Tasks.result b/testing/tests/regression-suite/231-Moz-REPORT-All-Tasks.result index 0d3a7d83..225ff38b 100644 --- a/testing/tests/regression-suite/231-Moz-REPORT-All-Tasks.result +++ b/testing/tests/regression-suite/231-Moz-REPORT-All-Tasks.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "2d56ad662a3857cbba346a51e2287e22" Content-Length: 4276 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/302-Chandler-OPTIONS-2.result b/testing/tests/regression-suite/302-Chandler-OPTIONS-2.result index b6a4a51f..b8f2be75 100644 --- a/testing/tests/regression-suite/302-Chandler-OPTIONS-2.result +++ b/testing/tests/regression-suite/302-Chandler-OPTIONS-2.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH DAV: 1, 2, access-control, calendar-access +Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result b/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result index d78ca2d3..0d775c90 100644 --- a/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result +++ b/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result @@ -1,18 +1,19 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "1600fce3e77c55492cbdabff16d30d4f" -Content-Length: 437 +DAV: 1, 2, access-control, calendar-access +ETag: "de5751155d5d8961c7fc9d38a690dd49" +Content-Length: 441 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ - + home "faf25336de0e470a54075c14cbcf5272" diff --git a/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result b/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result index bbcccc21..526427b6 100644 --- a/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result +++ b/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result @@ -1,18 +1,19 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "2c2763425add12e59c8c0b581747f249" -Content-Length: 552 +DAV: 1, 2, access-control, calendar-access +ETag: "5c2a97317978ca314ada6490cbebcc81" +Content-Length: 556 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ - + home "faf25336de0e470a54075c14cbcf5272" diff --git a/testing/tests/regression-suite/305-Chandler-MKCOL-1.result b/testing/tests/regression-suite/305-Chandler-MKCOL-1.result index 20e731b0..f0d92dc8 100644 --- a/testing/tests/regression-suite/305-Chandler-MKCOL-1.result +++ b/testing/tests/regression-suite/305-Chandler-MKCOL-1.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Cache-Control: no-cache Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/306-Chandler-DELETE-1.result b/testing/tests/regression-suite/306-Chandler-DELETE-1.result index e6ad1353..cb1291e1 100644 --- a/testing/tests/regression-suite/306-Chandler-DELETE-1.result +++ b/testing/tests/regression-suite/306-Chandler-DELETE-1.result @@ -1,5 +1,6 @@ HTTP/1.1 204 No Content Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/308-Chandler-OPTIONS-3.result b/testing/tests/regression-suite/308-Chandler-OPTIONS-3.result index b6a4a51f..b8f2be75 100644 --- a/testing/tests/regression-suite/308-Chandler-OPTIONS-3.result +++ b/testing/tests/regression-suite/308-Chandler-OPTIONS-3.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH DAV: 1, 2, access-control, calendar-access +Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result b/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result index d733f1d7..97451c46 100644 --- a/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result +++ b/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result @@ -1,18 +1,19 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "f81b76c70be67ab1e4f0e3c1eb7fd5f5" -Content-Length: 465 +DAV: 1, 2, access-control, calendar-access +ETag: "2d33f4ae017a778547da61069d95e18f" +Content-Length: 469 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/.chandler/ - + /user1/home/.chandler/ "a150b8e5ab38926a153b90c6546dc610" diff --git a/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result b/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result index 82138ed0..c4513138 100644 --- a/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result +++ b/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result @@ -1,18 +1,19 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -ETag: "a0d964965269357ef26c8c4ab7f7ad29" -Content-Length: 3605 +DAV: 1, 2, access-control, calendar-access +ETag: "f678e2f00e4582d963162b293e1e8ecb" +Content-Length: 3609 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ - + home "faf25336de0e470a54075c14cbcf5272" diff --git a/testing/tests/regression-suite/310-Chandler-PUT-1.result b/testing/tests/regression-suite/310-Chandler-PUT-1.result index 92a9a4a5..7d640ed1 100644 --- a/testing/tests/regression-suite/310-Chandler-PUT-1.result +++ b/testing/tests/regression-suite/310-Chandler-PUT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "0d7a68984bf525342d22b8924a57e8e2" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/311-Chandler-PUT-2.result b/testing/tests/regression-suite/311-Chandler-PUT-2.result index dab67f6a..7d88ec4e 100644 --- a/testing/tests/regression-suite/311-Chandler-PUT-2.result +++ b/testing/tests/regression-suite/311-Chandler-PUT-2.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "421abf7e4848d2fecbf64217ed205d4b" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/400-Cadaver-OPTIONS-1.result b/testing/tests/regression-suite/400-Cadaver-OPTIONS-1.result index b6a4a51f..b8f2be75 100644 --- a/testing/tests/regression-suite/400-Cadaver-OPTIONS-1.result +++ b/testing/tests/regression-suite/400-Cadaver-OPTIONS-1.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH DAV: 1, 2, access-control, calendar-access +Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result index a22424e8..1d5e2f8b 100644 --- a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result +++ b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result @@ -1,5 +1,5 @@ - + /caldav.php/user1/home/ @@ -8,10 +8,18 @@ 9531 - + HTTP/1.1 200 OK + + + + + + + HTTP/1.1 404 Not Found + diff --git a/testing/tests/regression-suite/510-iCal-PROPFIND.result b/testing/tests/regression-suite/510-iCal-PROPFIND.result index f2446d6c..7a4c8f18 100644 --- a/testing/tests/regression-suite/510-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/510-iCal-PROPFIND.result @@ -1,18 +1,39 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "d48322f182f679c3bdcf47af918de025" +Content-Length: 1022 +Content-Type: text/xml; charset="utf-8" + - + /caldav.php/user1/home/ - http://mycaldav/caldav.php/user1/home/ + + http://mycaldav/caldav.php/user1/ + + + http://mycaldav/caldav.php/user1/.inbox/ + + + http://mycaldav/caldav.php/user1/.outbox/ + + + http://mycaldav/caldav.php/user1/ + mailto:user1@example.net + home - - - - - HTTP/1.1 200 OK + + + + + + HTTP/1.1 404 Not Found + diff --git a/testing/tests/regression-suite/800-Spec-LOCK-1.result b/testing/tests/regression-suite/800-Spec-LOCK-1.result index 630f7d01..1120111f 100644 --- a/testing/tests/regression-suite/800-Spec-LOCK-1.result +++ b/testing/tests/regression-suite/800-Spec-LOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Lock-Token: Content-Length: 473 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/801-Spec-LOCK-1.result b/testing/tests/regression-suite/801-Spec-LOCK-1.result index 232fc691..d2c4b6dc 100644 --- a/testing/tests/regression-suite/801-Spec-LOCK-1.result +++ b/testing/tests/regression-suite/801-Spec-LOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 473 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/802-Spec-LOCK-1.result b/testing/tests/regression-suite/802-Spec-LOCK-1.result index beb062b1..1acf45d0 100644 --- a/testing/tests/regression-suite/802-Spec-LOCK-1.result +++ b/testing/tests/regression-suite/802-Spec-LOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 198 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/803-Mulberry-PUT-1.result b/testing/tests/regression-suite/803-Mulberry-PUT-1.result index beb062b1..1acf45d0 100644 --- a/testing/tests/regression-suite/803-Mulberry-PUT-1.result +++ b/testing/tests/regression-suite/803-Mulberry-PUT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 198 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/804-Mulberry-PUT-1.result b/testing/tests/regression-suite/804-Mulberry-PUT-1.result index 0a6ba774..405e9f72 100644 --- a/testing/tests/regression-suite/804-Mulberry-PUT-1.result +++ b/testing/tests/regression-suite/804-Mulberry-PUT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 201 Created Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "b000d7defa19ccb7cd21e546b54155ee" Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/805-Mulberry-DELETE-1.result b/testing/tests/regression-suite/805-Mulberry-DELETE-1.result index beb062b1..1acf45d0 100644 --- a/testing/tests/regression-suite/805-Mulberry-DELETE-1.result +++ b/testing/tests/regression-suite/805-Mulberry-DELETE-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 198 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/806-Mulberry-DELETE-1.result b/testing/tests/regression-suite/806-Mulberry-DELETE-1.result index acd10a41..f69b0439 100644 --- a/testing/tests/regression-suite/806-Mulberry-DELETE-1.result +++ b/testing/tests/regression-suite/806-Mulberry-DELETE-1.result @@ -1,5 +1,6 @@ HTTP/1.1 204 No Content Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/808-Spec-UNLOCK-1.result b/testing/tests/regression-suite/808-Spec-UNLOCK-1.result index beb062b1..1acf45d0 100644 --- a/testing/tests/regression-suite/808-Spec-UNLOCK-1.result +++ b/testing/tests/regression-suite/808-Spec-UNLOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 198 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/809-Spec-UNLOCK-1.result b/testing/tests/regression-suite/809-Spec-UNLOCK-1.result index acd10a41..f69b0439 100644 --- a/testing/tests/regression-suite/809-Spec-UNLOCK-1.result +++ b/testing/tests/regression-suite/809-Spec-UNLOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 204 No Content Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/810-Spec-LOCK-1.result b/testing/tests/regression-suite/810-Spec-LOCK-1.result index 630f7d01..1120111f 100644 --- a/testing/tests/regression-suite/810-Spec-LOCK-1.result +++ b/testing/tests/regression-suite/810-Spec-LOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Lock-Token: Content-Length: 473 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/811-Spec-LOCK-1.result b/testing/tests/regression-suite/811-Spec-LOCK-1.result index 232fc691..d2c4b6dc 100644 --- a/testing/tests/regression-suite/811-Spec-LOCK-1.result +++ b/testing/tests/regression-suite/811-Spec-LOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 473 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/812-Spec-LOCK-1.result b/testing/tests/regression-suite/812-Spec-LOCK-1.result index ed3747cf..dabb8a32 100644 --- a/testing/tests/regression-suite/812-Spec-LOCK-1.result +++ b/testing/tests/regression-suite/812-Spec-LOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 183 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/815-Spec-UNLOCK-1.result b/testing/tests/regression-suite/815-Spec-UNLOCK-1.result index ed3747cf..dabb8a32 100644 --- a/testing/tests/regression-suite/815-Spec-UNLOCK-1.result +++ b/testing/tests/regression-suite/815-Spec-UNLOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 183 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/816-Spec-UNLOCK-1.result b/testing/tests/regression-suite/816-Spec-UNLOCK-1.result index acd10a41..f69b0439 100644 --- a/testing/tests/regression-suite/816-Spec-UNLOCK-1.result +++ b/testing/tests/regression-suite/816-Spec-UNLOCK-1.result @@ -1,5 +1,6 @@ HTTP/1.1 204 No Content Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result index 40303510..68fa8512 100644 --- a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result +++ b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result @@ -1,5 +1,5 @@ - + /caldav.php/user1/home/ @@ -10,7 +10,7 @@ Dow, 01 Jan 2000 00:00:00 GMT - + home "faf25336de0e470a54075c14cbcf5272" @@ -37,5 +37,14 @@ HTTP/1.1 200 OK + + + + + + + + HTTP/1.1 404 Not Found + diff --git a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result index 95a5abd4..50032b87 100644 --- a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result +++ b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result @@ -1,11 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "deadbeefcafefeeddeadbeefcafefeed" -Content-Length: 969 +Content-Length: 1204 Content-Type: text/xml; charset="utf-8" - + /caldav.php/user1/home/ @@ -16,12 +17,10 @@ Content-Type: text/xml; charset="utf-8" Dow, 01 Jan 2000 00:00:00 GMT - + home "faf25336de0e470a54075c14cbcf5272" - - en_NZ.UTF-8 @@ -36,5 +35,16 @@ Content-Type: text/xml; charset="utf-8" HTTP/1.1 200 OK + + + + + + + + + + HTTP/1.1 404 Not Found + diff --git a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result index 4dbdc162..a1acd006 100644 --- a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result +++ b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result @@ -1,5 +1,5 @@ - + /caldav.php/user1/home/ @@ -10,7 +10,7 @@ Dow, 01 Jan 2000 00:00:00 GMT - + home "faf25336de0e470a54075c14cbcf5272" @@ -28,6 +28,15 @@ HTTP/1.1 200 OK + + + + + + + + HTTP/1.1 404 Not Found + /caldav.php/user1/home/0575d895-a006-4ed8-9be6-0d1b6b6b1f96.ics diff --git a/testing/tests/regression-suite/823-Spec-PROPFIND-4.result b/testing/tests/regression-suite/823-Spec-PROPFIND-4.result index 7683f515..013d78e8 100644 --- a/testing/tests/regression-suite/823-Spec-PROPFIND-4.result +++ b/testing/tests/regression-suite/823-Spec-PROPFIND-4.result @@ -1,5 +1,5 @@ - + /caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics diff --git a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result index ef0d0c12..010089e7 100644 --- a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result +++ b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result @@ -1,24 +1,24 @@ - + /caldav.php/user1/home/ - - i;ascii-casemap - i;octet - - - - - + + i;ascii-casemap + i;octet + + + + + httpd/unix-directory Dow, 01 Jan 2000 00:00:00 GMT 9531 Dow, 01 Jan 2000 00:00:00 GMT - + home "faf25336de0e470a54075c14cbcf5272" diff --git a/testing/tests/regression-suite/825-Spec-PROPFIND-6.result b/testing/tests/regression-suite/825-Spec-PROPFIND-6.result index 2f2a7489..6e2f02d6 100644 --- a/testing/tests/regression-suite/825-Spec-PROPFIND-6.result +++ b/testing/tests/regression-suite/825-Spec-PROPFIND-6.result @@ -1,5 +1,5 @@ - + /caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics diff --git a/testing/tests/regression-suite/830-Spec-FREEBUSY-1.result b/testing/tests/regression-suite/830-Spec-FREEBUSY-1.result index a829152e..99cf07e0 100644 --- a/testing/tests/regression-suite/830-Spec-FREEBUSY-1.result +++ b/testing/tests/regression-suite/830-Spec-FREEBUSY-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 928 Content-Type: text/calendar diff --git a/testing/tests/regression-suite/831-Spec-RRULE-1.result b/testing/tests/regression-suite/831-Spec-RRULE-1.result index 3070325a..da710c29 100644 --- a/testing/tests/regression-suite/831-Spec-RRULE-1.result +++ b/testing/tests/regression-suite/831-Spec-RRULE-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 5020 Content-Type: text/plain diff --git a/testing/tests/regression-suite/834-Spec-FREEBUSY-1.result b/testing/tests/regression-suite/834-Spec-FREEBUSY-1.result index 0c5a7987..4b60fca8 100644 --- a/testing/tests/regression-suite/834-Spec-FREEBUSY-1.result +++ b/testing/tests/regression-suite/834-Spec-FREEBUSY-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 1957 Content-Type: text/calendar diff --git a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result index 2fb0d185..b39a61c1 100644 --- a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result +++ b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 239 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/841-Spec-PROPPATCH-2.result b/testing/tests/regression-suite/841-Spec-PROPPATCH-2.result index 34294aaf..30ce8085 100644 --- a/testing/tests/regression-suite/841-Spec-PROPPATCH-2.result +++ b/testing/tests/regression-suite/841-Spec-PROPPATCH-2.result @@ -1,5 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 239 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/842-Spec-PROPPATCH-3.result b/testing/tests/regression-suite/842-Spec-PROPPATCH-3.result index 86c448d3..2c138f46 100644 --- a/testing/tests/regression-suite/842-Spec-PROPPATCH-3.result +++ b/testing/tests/regression-suite/842-Spec-PROPPATCH-3.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 464 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/843-Spec-PROPFIND.result b/testing/tests/regression-suite/843-Spec-PROPFIND.result index e94aecab..c9a1dd68 100644 --- a/testing/tests/regression-suite/843-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/843-Spec-PROPFIND.result @@ -1,14 +1,19 @@ - + /caldav.php/user1/home/ User One's Calendar - A completely bogus property which should be saved. HTTP/1.1 200 OK + + + + + HTTP/1.1 404 Not Found + diff --git a/testing/tests/regression-suite/850-Spec-REPORT-1.result b/testing/tests/regression-suite/850-Spec-REPORT-1.result index c7741cd1..8a783df5 100644 --- a/testing/tests/regression-suite/850-Spec-REPORT-1.result +++ b/testing/tests/regression-suite/850-Spec-REPORT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "3140e532d35ae4918005eb9bf5fcc26b" Content-Length: 1456 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/851-Spec-REPORT-1.result b/testing/tests/regression-suite/851-Spec-REPORT-1.result index 65b824a8..33c243fb 100644 --- a/testing/tests/regression-suite/851-Spec-REPORT-1.result +++ b/testing/tests/regression-suite/851-Spec-REPORT-1.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "8bb1ae7c599f81130860154adb77364b" Content-Length: 5175 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/860-Spec-REPORT-principal.result b/testing/tests/regression-suite/860-Spec-REPORT-principal.result index 19fcee2e..adb16f6d 100644 --- a/testing/tests/regression-suite/860-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/860-Spec-REPORT-principal.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "c345629a9689adce5411818c3c29aa43" Content-Length: 358 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/861-Spec-REPORT-principal.result b/testing/tests/regression-suite/861-Spec-REPORT-principal.result index b68509fe..7b9526f7 100644 --- a/testing/tests/regression-suite/861-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/861-Spec-REPORT-principal.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "8ee6bd9a1b7e15f40e6e24f149c6bf20" Content-Length: 3720 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/862-Spec-REPORT-principal.result b/testing/tests/regression-suite/862-Spec-REPORT-principal.result index 718b1ae4..c55a5655 100644 --- a/testing/tests/regression-suite/862-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/862-Spec-REPORT-principal.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "d8fe1f4720e6249cb2fb0711fbed9794" Content-Length: 688 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/863-Spec-REPORT-principal.result b/testing/tests/regression-suite/863-Spec-REPORT-principal.result index d48a7cd4..7b38fea1 100644 --- a/testing/tests/regression-suite/863-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/863-Spec-REPORT-principal.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "f9a0b07b2c7b0347a9ae26a412baef6b" Content-Length: 743 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/900-Moz-REPORT.result b/testing/tests/regression-suite/900-Moz-REPORT.result index 27273bc3..793501b2 100644 --- a/testing/tests/regression-suite/900-Moz-REPORT.result +++ b/testing/tests/regression-suite/900-Moz-REPORT.result @@ -1,5 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access ETag: "d19579c20ab7e6349b50af9e16ef5abd" Content-Length: 6643 Keep-Alive: timeout=15, max=100 diff --git a/testing/tests/regression-suite/901-GET-Collection.result b/testing/tests/regression-suite/901-GET-Collection.result index ad36009c..db60777d 100644 --- a/testing/tests/regression-suite/901-GET-Collection.result +++ b/testing/tests/regression-suite/901-GET-Collection.result @@ -1,11 +1,13 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Content-Length: 5750 +DAV: 1, 2, access-control, calendar-access +Content-Length: 5784 Content-Type: text/calendar BEGIN:VCALENDAR PRODID:-//Catalyst.Net.NZ//NONSGML AWL Calendar//EN VERSION:2.0 +X-WR-CALNAME:User One's Calendar BEGIN:VTODO CREATED:20070805T201647Z LAST-MODIFIED:20070805T201834Z diff --git a/testing/tests/regression-suite/902-PUT-collection.result b/testing/tests/regression-suite/902-PUT-collection.result index b55065c2..d6e58f46 100644 --- a/testing/tests/regression-suite/902-PUT-collection.result +++ b/testing/tests/regression-suite/902-PUT-collection.result @@ -2,6 +2,7 @@ HTTP/1.1 100 Continue HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/903-GET-Collection.result b/testing/tests/regression-suite/903-GET-Collection.result index e7568466..f04832b7 100644 --- a/testing/tests/regression-suite/903-GET-Collection.result +++ b/testing/tests/regression-suite/903-GET-Collection.result @@ -1,11 +1,13 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Content-Length: 23628 +DAV: 1, 2, access-control, calendar-access +Content-Length: 23650 Content-Type: text/calendar BEGIN:VCALENDAR PRODID:-//Catalyst.Net.NZ//NONSGML AWL Calendar//EN VERSION:2.0 +X-WR-CALNAME:entire/ BEGIN:VEVENT UID:20061119T201927Z-5105-1000-5103-8@ubu DTSTAMP:20061119T201927Z From 5ad40f969ac09257783d983f9bb8938a9e936d7d Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Tue, 30 Oct 2007 10:22:33 +1300 Subject: [PATCH 041/189] Change the CALENDAR-HOME-SET property to be the parent of any calendars. --- inc/CalDAVRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index 7e900200..749bd2f7 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -156,7 +156,7 @@ class CalDAVRequest */ $this->UserFromPath(); $this->principal->url = sprintf( "%s/%s/", $c->protocol_server_port_script, $this->principal->username); - $this->principal->calendar_home_set = sprintf( "%s%s/", $this->principal->url, $c->home_calendar_name); + $this->principal->calendar_home_set = sprintf( "%s", $this->principal->url); $this->principal->schedule_inbox_url = sprintf( "%s.inbox/", $this->principal->url); $this->principal->schedule_outbox_url = sprintf( "%s.outbox/", $this->principal->url); From aa2941316f78776ec384010b11821f10bfe601c0 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Tue, 30 Oct 2007 10:23:16 +1300 Subject: [PATCH 042/189] Include the headers in the validated response. --- testing/tests/regression-suite/510-iCal-PROPFIND.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/tests/regression-suite/510-iCal-PROPFIND.test b/testing/tests/regression-suite/510-iCal-PROPFIND.test index 05a670ec..a4fcf29b 100644 --- a/testing/tests/regression-suite/510-iCal-PROPFIND.test +++ b/testing/tests/regression-suite/510-iCal-PROPFIND.test @@ -3,6 +3,8 @@ # TYPE=PROPFIND URL=http://mycaldav/caldav.php/user1/home/ +HEAD + HEADER=User-Agent: DAVKit/2.0 (10.5; wrbt) iCal 3.0 HEADER=Content-Type: text/xml HEADER=Depth: 0 From 91b457099797bea2e346684f04af6d4e48f59067 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Tue, 30 Oct 2007 12:07:50 +1300 Subject: [PATCH 043/189] Some changes to PROPFIND handling for iCal 3 support (not yet). --- inc/caldav-PROPFIND.php | 236 +++++++++++++++++++++++++--------------- 1 file changed, 146 insertions(+), 90 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 0a0c67e1..6ce90b16 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -24,87 +24,98 @@ $arbitrary = array(); foreach( $request->xml_tags AS $k => $v ) { - $tag = $v['tag']; + $ns_tag = $v['tag']; + if ( preg_match('/^(.*):([^:]+)$/', $ns_tag, $matches) ) { + $namespace = $matches[1]; + $tag = $matches[2]; + } + else { + $namespace = ""; + $tag = $ns_tag; + } dbg_error_log( "PROPFIND", " Handling Tag '%s' => '%s' ", $k, $v ); + switch ( $tag ) { - case 'DAV::PROPFIND': - case 'DAV::PROP': + case 'PROPFIND': + case 'PROP': dbg_error_log( "PROPFIND", ":Request: %s -> %s", $v['type'], $tag ); break; - case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DESCRIPTION': - case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-TIMEZONE': - case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-DATA': - case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-RESOURCE-SIZE': - case 'URN:IETF:PARAMS:XML:NS:CALDAV:MIN-DATE-TIME': - case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-DATE-TIME': - case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-INSTANCES': - case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-ATTENDEES-PER-INSTANCE': - case 'HTTP://APACHE.ORG/DAV/PROPS/:EXECUTABLE': - case 'HTTP://CALENDARSERVER.ORG/NS/:DROPBOX-HOME-URL': - case 'HTTP://CALENDARSERVER.ORG/NS/:NOTIFICATIONS-URL': - case 'DAV::CHECKED-OUT': - case 'DAV::CHECKED-IN': - case 'DAV::SOURCE': - case 'DAV::LOCKDISCOVERY': - /** These are ignored */ - break; - - case 'DAV::ACL': /** acl - only vaguely supported */ - case 'DAV::CREATIONDATE': /** creationdate - should work fine */ - case 'DAV::GETLASTMODIFIED': /** getlastmodified - should work fine */ - case 'DAV::DISPLAYNAME': /** displayname - should work fine */ - case 'DAV::GETCONTENTLENGTH': /** getcontentlength- should work fine */ - case 'DAV::GETCONTENTTYPE': /** getcontenttype - should work fine */ - case 'DAV::GETETAG': /** getetag - should work fine */ - case 'DAV::SUPPORTEDLOCK': /** supportedlock - should work fine */ - case 'DAV::PRINCIPAL-URL': /** principal-url - should work fine */ - case 'DAV::RESOURCETYPE': /** resourcetype - should work fine */ - case 'DAV::GETCONTENTLANGUAGE': /** resourcetype - should return the user's chosen locale, or default locale */ - case 'DAV::SUPPORTED-PRIVILEGE-SET': /** supported-privilege-set - should work fine */ - case 'DAV::CURRENT-USER-PRIVILEGE-SET': /** current-user-privilege-set - only vaguely supported */ - case 'DAV::ALLPROP': /** allprop - limited support */ - $attribute = substr($v['tag'],5); - $attribute_list[$attribute] = 1; - dbg_error_log( "PROPFIND", "Adding DAV: attribute '%s'", $attribute ); - break; - - case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-HOME-SET': /** calendar-home-set is used by iCal in Leopard - should work fine */ - case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-COLLATION-SET': /** fixed server definition - should work fine */ - case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET': /** fixed server definition - should work fine */ - $attribute = substr($v['tag'],30); - $attribute_list[$attribute] = 1; - dbg_error_log( "PROPFIND", "Adding CalDAV attribute '%s'", $attribute ); - break; - - case 'DAV::HREF': - // dbg_log_array( "PROPFIND", "DAV::HREF", $v, true ); + case 'HREF': + // dbg_log_array( "PROPFIND", "HREF", $v, true ); $href_list[] = $v['value']; - dbg_error_log( "PROPFIND", "Adding attribute '%s'", $attribute ); + dbg_error_log( "PROPFIND", "Adding href '%s'", $v['value'] ); + break; + + + /** + * Handled DAV properties + */ + case 'ACL': /** acl - only vaguely supported */ + case 'CREATIONDATE': /** creationdate - should work fine */ + case 'GETLASTMODIFIED': /** getlastmodified - should work fine */ + case 'DISPLAYNAME': /** displayname - should work fine */ + case 'GETCONTENTLENGTH': /** getcontentlength- should work fine */ + case 'GETCONTENTTYPE': /** getcontenttype - should work fine */ + case 'GETETAG': /** getetag - should work fine */ + case 'SUPPORTEDLOCK': /** supportedlock - should work fine */ + case 'PRINCIPAL-URL': /** principal-url - should work fine */ + case 'RESOURCETYPE': /** resourcetype - should work fine */ + case 'GETCONTENTLANGUAGE': /** resourcetype - should return the user's chosen locale, or default locale */ + case 'SUPPORTED-PRIVILEGE-SET': /** supported-privilege-set - should work fine */ + case 'CURRENT-USER-PRIVILEGE-SET': /** current-user-privilege-set - only vaguely supported */ + case 'ALLPROP': /** allprop - limited support */ + + /** + * Handled CalDAV properties + */ + case 'CALENDAR-HOME-SET': /** calendar-home-set is used by iCal in Leopard - should work fine */ + case 'SUPPORTED-COLLATION-SET': /** fixed server definition - should work fine */ + case 'SUPPORTED-CALENDAR-COMPONENT-SET': /** fixed server definition - should work fine */ + + /** + * Handled calendar-schedule properties + */ + case 'CALENDAR-USER-ADDRESS-SET': /** CalDAV+s: slightly supported */ + case 'SCHEDULE-INBOX-URL': /** CalDAV+s: not supported */ + case 'SCHEDULE-OUTBOX-URL': /** CalDAV+s: not supported */ + $attribute_list[$tag] = 1; + dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag ); + break; + + + case 'CALENDAR-TIMEZONE': // CalDAV + case 'SUPPORTED-CALENDAR-DATA': // CalDAV + case 'MAX-RESOURCE-SIZE': // CalDAV + case 'MIN-DATE-TIME': // CalDAV + case 'MAX-DATE-TIME': // CalDAV + case 'MAX-INSTANCES': // CalDAV + case 'MAX-ATTENDEES-PER-INSTANCE': // CalDAV +// case 'CHECKED-OUT': // DAV: +// case 'CHECKED-IN': // DAV: +// case 'SOURCE': // DAV: +// case 'LOCKDISCOVERY': // DAV: +// case 'EXECUTABLE': // HTTP://APACHE.ORG/DAV/PROPS/ +// case 'DROPBOX-HOME-URL': // HTTP://CALENDARSERVER.ORG/NS/ +// case 'NOTIFICATIONS-URL': // HTTP://CALENDARSERVER.ORG/NS/ + /** These are ignored specifically */ break; /** * Add the ones that are specifically unsupported here. */ - case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-USER-ADDRESS-SET': /** calendar-schedule is not supported */ - case 'URN:IETF:PARAMS:XML:NS:CALDAV:SCHEDULE-INBOX-URL': /** calendar-schedule is not supported */ - case 'URN:IETF:PARAMS:XML:NS:CALDAV:SCHEDULE-OUTBOX-URL': /** calendar-schedule is not supported */ - case 'UNSUPPORTED': - if ( preg_match('/^(.*):([^:]+)$/', $tag, $matches) ) { - $unsupported[$matches[2]] = $matches[1]; - } - else { - $unsupported[$tag] = ""; - } - dbg_error_log( "PROPFIND", "Unsupported tag >>%s<<", $tag); + case 'This is not a supported property': // an impossible example + $unsupported[$tag] = ""; + dbg_error_log( "PROPFIND", "Unsupported tag >>%s<< in xmlns >>%s<<", $tag, $namespace); break; /** - * Add the ones that are specifically unsupported here. + * Arbitrary DAV properties may also be reported */ + case 'CALENDAR-DESCRIPTION': // CalDAV, informational default: - $arbitrary[$tag] = $tag; - dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $tag ); + $arbitrary[$ns_tag] = $ns_tag; + dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $ns_tag ); break; } } @@ -130,7 +141,7 @@ function privileges($privilege_names, $container="privilege") { function get_arbitrary_properties($dav_name) { global $arbitrary; - $results = array(); + $results = (object) array( 'found' => array(), 'missing' => $arbitrary ); if ( count($arbitrary) > 0 ) { $sql = ""; @@ -139,7 +150,8 @@ function get_arbitrary_properties($dav_name) { } $qry = new PgQuery("SELECT property_name, property_value FROM property WHERE dav_name=? AND property_name IN ($sql)", $dav_name ); while( $qry->Exec("PROPFIND") && $property = $qry->Fetch() ) { - $results[$property->property_name] = $property->property_value; + $results->found[$property->property_name] = $property->property_value; + unset($results->missing[$property->property_name]); } } @@ -147,6 +159,34 @@ function get_arbitrary_properties($dav_name) { } +/** +* Handles any properties related to the DAV::PRINCIPAL in the request +*/ +function add_principal_properties( &$prop ) { + global $attribute_list, $session, $c, $request; + + if ( isset($attribute_list['PRINCIPAL-URL'] ) ) { + $prop->NewElement("principal-url", new XMLElement('href', $request->principal->url ) ); + } + + if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) { + $prop->NewElement("C:calendar-home-set", new XMLElement('href', $request->principal->calendar_home_set ) ); + } + if ( isset($attribute_list['SCHEDULE-INBOX-URL'] ) ) { + $prop->NewElement("C:schedule-inbox-url", new XMLElement('href', $request->principal->schedule_inbox_url) ); + } + if ( isset($attribute_list['SCHEDULE-OUTBOX-URL'] ) ) { + $prop->NewElement("C:schedule-outbox-url", new XMLElement('href', $request->principal->schedule_outbox_url) ); + } + + if ( isset($attribute_list['CALENDAR-USER-ADDRESS-SET'] ) ) { + $email = new XMLElement('href', 'mailto:'.$request->principal->email ); + $calendar = new XMLElement('href', $request->principal->calendar_home_set ); + $prop->NewElement("C:calendar-user-address-set", array( $calendar, $email) ); + } +} + + /** * Returns an XML sub-tree for a single collection record from the DB */ @@ -155,13 +195,14 @@ function collection_to_xml( $collection ) { dbg_error_log("PROPFIND","Building XML Response for collection '%s'", $collection->dav_name ); - $collection->properties = get_arbitrary_properties($collection->dav_name); + $arbitrary_results = get_arbitrary_properties($collection->dav_name); + $collection->properties = $arbitrary_results->found; $url = $_SERVER['SCRIPT_NAME'] . $collection->dav_name; $resourcetypes = array( new XMLElement("collection") ); $contentlength = false; if ( $collection->is_calendar == 't' ) { - $resourcetypes[] = new XMLElement("calendar", false, array("xmlns" => "urn:ietf:params:xml:ns:caldav")); + $resourcetypes[] = new XMLElement("C:calendar", false); $lqry = new PgQuery("SELECT sum(length(caldav_data)) FROM caldav_data WHERE user_no = ? AND dav_name ~ ?;", $collection->user_no, $collection->dav_name.'[^/]+$' ); if ( $lqry->Exec("PROPFIND",__LINE__,__FILE__) && $row = $lqry->Fetch() ) { $contentlength = $row->sum; @@ -177,28 +218,20 @@ function collection_to_xml( $collection ) { */ if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-COLLATION-SET']) ) { $collations = array(); - $collations[] = new XMLElement("supported-collation", 'i;ascii-casemap'); - $collations[] = new XMLElement("supported-collation", 'i;octet'); - $prop->NewElement("supported-collation-set", $collations, array("xmlns" => "urn:ietf:params:xml:ns:caldav") ); + $collations[] = new XMLElement("C:supported-collation", 'i;ascii-casemap'); + $collations[] = new XMLElement("C:supported-collation", 'i;octet'); + $prop->NewElement("C:supported-collation-set", $collations ); } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-CALENDAR-COMPONENT-SET']) ) { $components = array(); - $components[] = new XMLElement("comp", '', array("name" => "VEVENT")); - $components[] = new XMLElement("comp", '', array("name" => "VTODO")); - $prop->NewElement("supported-calendar-component-set", $components, array("xmlns" => "urn:ietf:params:xml:ns:caldav") ); + $components[] = new XMLElement("C:comp", '', array("name" => "VEVENT")); + $components[] = new XMLElement("C:comp", '', array("name" => "VTODO")); + $prop->NewElement("C:supported-calendar-component-set", $components ); } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTTYPE']) ) { $prop->NewElement("getcontenttype", "httpd/unix-directory" ); } - if ( isset($attribute_list['PRINCIPAL-URL'] ) ) { - $prop->NewElement("principal-url", $request->principal->url ); - } - - if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) { - $prop->NewElement("calendar-home-set", $request->principal->calendar_home_set, array("xmlns" => "urn:ietf:params:xml:ns:caldav") ); - } - /** * Second process any dynamic values we do support */ @@ -225,9 +258,14 @@ function collection_to_xml( $collection ) { $prop->NewElement("current-user-privilege-set", privileges($request->permissions) ); } - if ( count($arbitrary) > 0 ) { - foreach( $arbitrary AS $k => $v ) { - $prop->NewElement($k, $collection->properties[$k]); + /** + * Then look at any properties related to the principal + */ + add_principal_properties( $prop ); + + if ( count($collection->properties) > 0 ) { + foreach( $collection->properties AS $k => $v ) { + $prop->NewElement($k, $v ); } } @@ -264,8 +302,27 @@ function collection_to_xml( $collection ) { $propstat = new XMLElement( "propstat", array( $prop, $status) ); $href = new XMLElement("href", $url ); + $response = array($href,$propstat); - $response = new XMLElement( "response", array($href,$propstat)); + if ( count($arbitrary_results->missing) > 0 ) { + $missing = new XMLElement("prop"); + foreach( $arbitrary_results->missing AS $k => $v ) { + if ( preg_match('/^(.*):([^:]+)$/', $k, $matches) ) { + $namespace = $matches[1]; + $tag = $matches[2]; + } + else { + $namespace = ""; + $tag = $k; + } + $missing->NewElement(strtolower($tag), '', array("xmlns" => strtolower($namespace)) ); + } + $status = new XMLElement("status", "HTTP/1.1 404 Not Found" ); + $propstat = new XMLElement( "propstat", array( $missing, $status) ); + $response[] = $propstat; + } + + $response = new XMLElement( "response", $response ); return $response; } @@ -314,7 +371,7 @@ function item_to_xml( $item ) { } if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) { - $prop->NewElement("calendar-home-set", $request->principal->calendar_home_set, array("xmlns" => "urn:ietf:params:xml:ns:caldav") ); + $prop->NewElement("C:calendar-home-set", $request->principal->calendar_home_set ); } if ( isset($attribute_list['ACL']) ) { @@ -514,7 +571,7 @@ else { $request->DoResponse( 403, translate("You do not have appropriate rights to view that resource.") ); } -$multistatus = new XMLElement( "multistatus", $responses, array('xmlns'=>'DAV:') ); +$multistatus = new XMLElement( "multistatus", $responses, array('xmlns'=>'DAV:', "xmlns:C" => "urn:ietf:params:xml:ns:caldav") ); // dbg_log_array( "PROPFIND", "XML", $multistatus, true ); $xmldoc = $multistatus->Render(0,''); @@ -522,4 +579,3 @@ $etag = md5($xmldoc); header("ETag: \"$etag\""); $request->DoResponse( 207, $xmldoc, 'text/xml; charset="utf-8"' ); -?> \ No newline at end of file From 7c05f9c189e5b032584e10124e8f0f01d69f78bf Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Tue, 30 Oct 2007 14:48:46 +1300 Subject: [PATCH 044/189] Pulling out the User create/update so other drivers can use it as well. --- inc/auth-functions.php | 62 +++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/inc/auth-functions.php b/inc/auth-functions.php index 202b203c..2d952e35 100644 --- a/inc/auth-functions.php +++ b/inc/auth-functions.php @@ -26,6 +26,8 @@ */ require_once("AWLUtilities.php"); +require_once("DataUpdate.php"); + /** * Create a default home calendar for the user. @@ -41,7 +43,7 @@ function CreateHomeCalendar( $username ) { $dav_etag = md5($usr->user_no . $calendar_path); $sql = "INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, "; $sql .= "created, modified) VALUES( ?, ?, ?, ?, ?, true, current_timestamp, current_timestamp );"; - $qry = new PgQuery( $sql, $this->user_no, $parent_path, $calendar_path, $dav_etag, $usr->fullname); + $qry = new PgQuery( $sql, $usr->user_no, $parent_path, $calendar_path, $dav_etag, $usr->fullname); if ( $qry->Exec() ) { $c->messages[] = i18n("Home calendar added."); dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path ); @@ -81,6 +83,42 @@ function CreateDefaultRelationships( $username ) { } +/** +* Update the local cache of the remote user details +* @param object $usr The user details we read from the remote. +*/ +function UpdateUserFromExternal( &$usr ) { + /** + * When we're doing the create we will usually need to generate a user number + */ + if ( !isset($usr->user_no) || intval($usr->user_no) == 0 ) { + $qry = new PgQuery( "SELECT currval('usr_user_no_seq');" ); + $qry->Exec('Login',__LINE,__FILE__); + $sequence_value = $qry->Fetch(true); // Fetch as an array + $usr->user_no = $sequence_value[0]; + } + + $qry = new PgQuery("SELECT * FROM usr WHERE user_no = $usr->user_no;" ); + if ( $qry->Exec('Login',__LINE,__FILE__) && $qry->rows == 1 ) + $type = "UPDATE"; + else + $type = "INSERT"; + + $qry = new PgQuery( sql_from_object( $usr, $type, 'usr', "WHERE user_no=$usr->user_no" ) ); + $qry->Exec('Login',__LINE,__FILE__); + + /** + * We disallow login by inactive users _after_ we have updated the local copy + */ + if ( isset($usr->active) && $usr->active == 'f' ) return false; + + if ( $type == 'INSERT' ) { + CreateHomeCalendar($usr->username); + CreateDefaultRelationships($usr->username); + } +} + + /** * Authenticate against a different PostgreSQL database which contains a usr table in * the AWL format. @@ -112,27 +150,7 @@ EOERRMSG; if ( $qry->Exec('Login',__LINE,__FILE__) && $qry->rows == 1 ) { $usr = $qry->Fetch(); if ( session_validate_password( $password, $usr->password ) ) { - - $qry = new PgQuery("SELECT * FROM usr WHERE user_no = $usr->user_no;" ); - if ( $qry->Exec('Login',__LINE,__FILE__) && $qry->rows == 1 ) - $type = "UPDATE"; - else - $type = "INSERT"; - - include_once("DataUpdate.php"); - $qry = new PgQuery( sql_from_object( $usr, $type, 'usr', "WHERE user_no=$usr->user_no" ) ); - $qry->Exec('Login',__LINE,__FILE__); - - /** - * We disallow login by inactive users _after_ we have updated the local copy - */ - if ( isset($usr->active) && $usr->active == 'f' ) return false; - - if ( $type == 'INSERT' ) { - CreateHomeCalendar($usr->username); - CreateDefaultRelationships($usr->username); - } - + UpdateUserFromExternal(); return $usr; } } From 13f915ee1be756ddb0a8c2937289b673c252ccf1 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Tue, 30 Oct 2007 14:51:06 +1300 Subject: [PATCH 045/189] Substantial refactoring of drivers_ldap for efficiency and code reuse. Also switched to using the auth-functions for user create/update. --- inc/drivers_ldap.php | 288 +++++++++++++++++++++++-------------------- 1 file changed, 153 insertions(+), 135 deletions(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index d5c7faff..0d94335d 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -2,14 +2,15 @@ /** * Manages LDAP repository connection * -* @package rscds +* @package davical * @category Technical -* @subpackage caldav +* @subpackage ldap * @author Maxime Delorme * @copyright Maxime Delorme * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ +require_once("auth-functions.php"); class ldapDrivers { @@ -80,20 +81,20 @@ class ldapDrivers /** * Retrieve all users from the LDAP directory */ - function getAllUsers($attributs){ + function getAllUsers($attributes){ global $c; - $entry = ldap_list($this->connect,$this->baseDNUsers,$this->filterUsers,$attributs); + $entry = ldap_list($this->connect,$this->baseDNUsers,$this->filterUsers,$attributes); if (!ldap_first_entry($this->connect,$entry)) - $c->messages[] = sprintf(i18n("Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"),$this->filterUsers,join(', ',$attributs), $this->baseDNUsers); + $c->messages[] = sprintf(i18n("Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"),$this->filterUsers,join(', ',$attributes), $this->baseDNUsers); for($i=ldap_first_entry($this->connect,$entry); $i&&$arr=ldap_get_attributes($this->connect,$i); $i=ldap_next_entry($this->connect,$i) ) { - for($j=0;$j<$arr['count'];$j++){ - $row[$arr[$j]] = $arr[$arr[$j]][0]; - } - $ret[]=$row; + for($j=0;$j<$arr['count'];$j++){ + $row[$arr[$j]] = $arr[$arr[$j]][0]; + } + $ret[]=$row; } return $ret; } @@ -102,30 +103,29 @@ class ldapDrivers * Returns the result of the LDAP query * * @param string $filter The filter used to search entries - * @param array $attributs Attributes to be returned + * @param array $attributes Attributes to be returned * @param string $passwd password to check * @return array Contains selected attributes from all entries corresponding to the given filter */ - function requestUser($filter,$attributs=NULL,$passwd) - { + function requestUser( $filter, $attributes=NULL, $passwd) { - $entry=NULL; - // We get the DN of the USER - $entry = ldap_search($this->connect,$this->baseDNUsers,$filter,$attributs); - if ( !ldap_first_entry($this->connect,$entry) ){ - dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter ); - return false; - } - $dnUser = ldap_get_dn($this->connect, ldap_first_entry($this->connect,$entry)); - if(!@ldap_bind($this->connect,$dnUser,$passwd)) - return false; + $entry=NULL; + // We get the DN of the USER + $entry = ldap_search($this->connect, $this->baseDNUsers, $filter,$attributs); + if ( !ldap_first_entry($this->connect, $entry) ){ + dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter ); + return false; + } + $dnUser = ldap_get_dn($this->connect, ldap_first_entry($this->connect,$entry)); + if ( !@ldap_bind($this->connect, $dnUser, $passwd) ) + return false; - $i=ldap_first_entry($this->connect,$entry); - $arr=ldap_get_attributes($this->connect,$i); - for($i=0;$i<$arr['count'];$i++){ - $ret[$arr[$i]]=$arr[$arr[$i]][0]; - } - return $ret; + $i = ldap_first_entry($this->connect,$entry); + $arr = ldap_get_attributes($this->connect,$i); + for( $i=0; $i<$arr['count']; $i++ ) { + $ret[$arr[$i]]=$arr[$arr[$i]][0]; + } + return $ret; } } @@ -146,70 +146,93 @@ function getStaticLdap() { return $ldapDrivers; } + +/** +* Synchronise a cached user with one from LDAP +* @param object $usr A user record to be updated (or created) +*/ +function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ); + $validUserFields = get_fields('usr'); + + foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { + if ( in_array($field, $validUserFields) ) $usr->{$field} = $value; + } + + foreach ( $mapping as $field => $value ) { + if ( in_array($field, $validUserFields) ) $usr->{$field} = $ldap_values[$value]; + } + + $user->updated = "$Y-$m-$d $H:$M:$S"; + + UpdateUserFromExternal( $usr ); +} + + /** * Check the username / password against the LDAP server */ function LDAP_check($username, $password ){ global $c; + $ldapDriver = getStaticLdap(); - if ( $ldapDriver->valid ) { - $mapping = $c->authenticate_hook['config']['mapping_field']; - $attributs=array_values($mapping); - - // If the config contains a filter that starts with a ( then believe - // them and don't modify it, otherwise wrap the filter. - $filter_munge = ""; - if ( preg_match( '/^\(/', $ldapDriver->filterUsers ) ) { - $filter_munge = $ldapDriver->filterUsers; - } else { - $filter_munge = "($ldapDriver->filterUsers)"; - } - - $filter="(&$filter_munge(".$mapping["username"]."=$username))"; - dbg_error_log( "LDAP", "checking user %s for password %s against LDAP",$username,$password ); - $valid = $ldapDriver->requestUser($filter,$attributs,$password); - - //is a valid user or not - if ( !$valid ) return false; - - - $ldap_timestamp = $valid[$mapping["updated"]]; - foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) - $$k = substr($ldap_timestamp,$v[0],$v[1]); - - //ok it is valid is already exist in db ? - $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; - if ( $usr = getUserByName($username) ){ - //should we update it ? - $db_timestamp = $usr->updated; - $db_timestamp = substr(strtr($db_timestamp, array(':' => '',' '=>'','-'=>'')),0,14); - if($ldap_timestamp <= $db_timestamp){ - return $usr;//no need to update - } - //we should update the user record - } - - //it doesn't exist so we create the new user or if we should be updated the user record - require_once("RSCDSUser.php"); - - $user_no = ( isset($usr->user_no) ? $usr->user_no:0); - $user = new RSCDSUser($user_no); - $validUserField = array_keys($user->Fields); - - foreach($c->authenticate_hook['config']['default_value'] as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $value); - - foreach($mapping as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]); - - $user->Set("updated", "$Y-$m-$d $H:$M:$S"); - $user->write(); + if ( !$ldapDriver->valid ) { + dbg_error_log( "ERROR", "Couldn't contact LDAP server for authentication" ); + return false; } - if ( $return = getUserByName($username) ){ - return $return; + $mapping = $c->authenticate_hook['config']['mapping_field']; + $attributes = array_values($mapping); + + /** + * If the config contains a filter that starts with a ( then believe + * them and don't modify it, otherwise wrap the filter. + */ + $filter_munge = ""; + if ( preg_match( '/^\(/', $ldapDriver->filterUsers ) ) { + $filter_munge = $ldapDriver->filterUsers; } + else { + $filter_munge = "($ldapDriver->filterUsers)"; + } + + $filter = "(&$filter_munge(".$mapping["username"]."=$username))"; + dbg_error_log( "LDAP", "checking user %s for password %s against LDAP",$username,$password ); + $valid = $ldapDriver->requestUser( $filter, $attributes, $password ); + + // is a valid user or not + if ( !$valid ) return false; + + $ldap_timestamp = $valid[$mapping["updated"]]; + + /** + * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S + */ + foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) + $$k = substr($ldap_timestamp,$v[0],$v[1]); + + // ok it is valid is already exist in db ? + $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; + if ( $usr = getUserByName($username) ) { + // should we update it ? + $db_timestamp = $usr->updated; + $db_timestamp = substr(strtr($db_timestamp, array(':' => '',' '=>'','-'=>'')),0,14); + if($ldap_timestamp <= $db_timestamp) { + return $usr; // no need to update + } + // we will need to update the user record + } + else { + $usr = (object) array( 'user_no' => 0 ); + } + + // The local cached user doesn't exist, or is older, so we create/update their details + sync_user_from_LDAP($usr, $mapping, $valid ); + + return $usr; + } + + /** * sync LDAP against the DB */ @@ -218,80 +241,75 @@ function sync_LDAP(){ $ldapDriver = getStaticLdap(); if($ldapDriver->valid){ $mapping = $c->authenticate_hook['config']['mapping_field']; - $attributs=array_values($mapping); - $ldap_users_tmp = $ldapDriver->getAllUsers($attributs); + $attributes = array_values($mapping); + $ldap_users_tmp = $ldapDriver->getAllUsers($attributes); foreach($ldap_users_tmp as $key => $ldap_user){ $ldap_users_info[$ldap_user[$mapping["username"]]] = $ldap_user; unset($ldap_users_tmp[$key]); } - $qry = new PgQuery( "SELECT username ,user_no, updated FROM usr "); + $qry = new PgQuery( "SELECT username, user_no, updated FROM usr "); $qry->Exec('sync_LDAP',__LINE__,__FILE__); while($db_user = $qry->Fetch(true)){ $db_users[] = $db_user['username']; $db_users_info[$db_user['username']] = array('user_no' => $db_user['user_no'], 'updated' => $db_user['updated']); } - require_once("RSCDSUser.php"); + include_once("RSCDSUser.php"); $ldap_users = array_keys($ldap_users_info); - //users only in ldap + // users only in ldap $users_to_create = array_diff($ldap_users,$db_users); - //users only in db - $users_to_desactivate = array_diff($db_users,$ldap_users); - //users present in ldap and in the db + // users only in db + $users_to_deactivate = array_diff($db_users,$ldap_users); + // users present in ldap and in the db $users_to_update = array_intersect($db_users,$ldap_users); - //creation of all users; - if(sizeof($users_to_create)) $c->messages[] = sprintf(i18n('- creating record for users : %s'),join(', ',$users_to_create)); - foreach($users_to_create as $username){ - $valid=$ldap_users_info[$username]; - $ldap_timestamp = $valid[$mapping["updated"]]; - foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) - $$k = substr($ldap_timestamp,$v[0],$v[1]); - $user = new RSCDSUser(0); - $validUserField = array_keys($user->Fields); - foreach($c->authenticate_hook['config']['default_value'] as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $value); - foreach($mapping as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]); - $user->Set("updated", "$Y-$m-$d $H:$M:$S"); - $messages = $c->messages; - $user->write(); - $c->messages = $messages; + // creation of all users; + if ( sizeof($users_to_create) ) + $c->messages[] = sprintf(i18n('- creating record for users : %s'),join(', ',$users_to_create)); + + foreach( $users_to_create as $username ) { + $user = (object) array( 'user_no' => 0, 'username' => $username ); + sync_user_from_LDAP( $user, $mapping, $ldap_users_info[$username] ); + } } - //desactivating all users - if(sizeof($users_to_desactivate)){ - foreach( $users_to_desactivate AS $v ) { + + // deactivating all users + if ( sizeof($users_to_deactivate) ) { + foreach( $users_to_deactivate AS $v ) { $usr_in .= ', ' . qpg($v); } $usr_in = substr($usr_in,1); - $c->messages[] = sprintf(i18n('- desactivating users : %s'),$usr_in); - $qry = new PgQuery( "UPDATE usr set active = FALSE WHERE lower(username) in ($usr_in)"); + $c->messages[] = sprintf(i18n('- deactivating users : %s'),$usr_in); + $qry = new PgQuery( "UPDATE usr SET active = FALSE WHERE lower(username) IN ($usr_in)"); $qry->Exec('sync_LDAP',__LINE__,__FILE__); } - //updating all users - foreach($users_to_update as $key=> $username){ - $valid=$ldap_users_info[$username]; - $ldap_timestamp = $valid[$mapping["updated"]]; - foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) - $$k = substr($ldap_timestamp,$v[0],$v[1]); - $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; - $db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14); - if($ldap_timestamp > $db_timestamp){ - $user = new RSCDSUser($db_users_info[$username]['user_no']); - $validUserField = array_keys($user->Fields); - foreach($c->authenticate_hook['config']['default_value'] as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $value); - foreach($mapping as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]); - $user->Set("updated", "$Y-$m-$d $H:$M:$S"); - $user->write(); - } else { - unset($users_to_update[$key]); - $users_nothing_done[] = $username; + + // updating all users + if ( sizeof($users_to_update) ) { + foreach ( $users_to_update as $key=> $username ) { + $valid=$ldap_users_info[$username]; + $ldap_timestamp = $valid[$mapping["updated"]]; + + /** + * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S + */ + foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) + $$k = substr($ldap_timestamp,$v[0],$v[1]); + $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; + + $db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14); + if ( $ldap_timestamp > $db_timestamp ) { + sync_user_from_LDAP($usr, $mapping, $valid ); + } + else { + unset($users_to_update[$key]); + $users_nothing_done[] = $username; + } } + $c->messages[] = sprintf(i18n('- updating user record %s'),join(', ',$users_to_update)); + if ( sizeof($users_nothing_done) ) + $c->messages[] = sprintf(i18n('- nothing done on %s'),join(', ', $users_nothing_done)); } - if(sizeof($users_to_update)) $c->messages[] = sprintf(i18n('- updating user record %s'),join(', ',$users_to_update)); - if(sizeof($users_nothing_done))$c->messages[] = sprintf(i18n('- nothing done on %s'),join(', ', $users_nothing_done)); } } -?> + From e34807cc1710e64916ec6abe5ebae78b1e2d6e38 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 1 Nov 2007 14:48:50 +1300 Subject: [PATCH 046/189] More consistently do the ldap timestamp munding. Probably this should really be done in a separate 'munge_ldap_timestamp()' function. --- inc/drivers_ldap.php | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index 0d94335d..580be59e 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -162,8 +162,6 @@ function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ); if ( in_array($field, $validUserFields) ) $usr->{$field} = $ldap_values[$value]; } - $user->updated = "$Y-$m-$d $H:$M:$S"; - UpdateUserFromExternal( $usr ); } @@ -210,8 +208,9 @@ function LDAP_check($username, $password ){ foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) $$k = substr($ldap_timestamp,$v[0],$v[1]); - // ok it is valid is already exist in db ? $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; + $valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S"; + if ( $usr = getUserByName($username) ) { // should we update it ? $db_timestamp = $usr->updated; @@ -269,7 +268,18 @@ function sync_LDAP(){ foreach( $users_to_create as $username ) { $user = (object) array( 'user_no' => 0, 'username' => $username ); - sync_user_from_LDAP( $user, $mapping, $ldap_users_info[$username] ); + $valid = $ldap_users_info[$username]; + $ldap_timestamp = $valid[$mapping["updated"]]; + + /** + * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S + */ + foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) + $$k = substr($ldap_timestamp,$v[0],$v[1]); + $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; + $valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S"; + + sync_user_from_LDAP( $user, $mapping, $valid ); } } @@ -296,6 +306,7 @@ function sync_LDAP(){ foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) $$k = substr($ldap_timestamp,$v[0],$v[1]); $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; + $valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S"; $db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14); if ( $ldap_timestamp > $db_timestamp ) { From 00fb075f22ae280f07bccd67a5df3ab076481d5c Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 1 Nov 2007 14:49:34 +1300 Subject: [PATCH 047/189] Some of the principal properties are available anywhere. --- inc/caldav-PROPFIND.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 6ce90b16..cf61d0c8 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -366,13 +366,10 @@ function item_to_xml( $item ) { $prop->NewElement("getetag", '"'.$item->dav_etag.'"' ); } - if ( isset($attribute_list['PRINCIPAL-URL'] ) ) { - $prop->NewElement("principal-url", $request->principal->url ); - } - - if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) { - $prop->NewElement("C:calendar-home-set", $request->principal->calendar_home_set ); - } + /** + * Then look at any properties related to the principal + */ + add_principal_properties( $prop ); if ( isset($attribute_list['ACL']) ) { /** From 39700005f4a39dd5a6bd194d2efae1487477edc5 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 1 Nov 2007 14:54:59 +1300 Subject: [PATCH 048/189] Some random renaming of RSCDS to DAViCal. --- htdocs/caldav.php | 3 +-- htdocs/help.php | 7 ++++--- htdocs/tools.php | 2 +- htdocs/users.php | 4 ++-- rscds.webprj | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/htdocs/caldav.php b/htdocs/caldav.php index 4d89ba1b..5a82cd0a 100644 --- a/htdocs/caldav.php +++ b/htdocs/caldav.php @@ -2,7 +2,7 @@ /** * CalDAV Server - main program * -* @package rscds +* @package davical * @subpackage caldav * @author Andrew McMillan * @copyright Catalyst .Net Ltd @@ -53,4 +53,3 @@ switch ( $request->method ) { $request->DoResponse( 500, translate("The application program does not understand that request.") ); -?> \ No newline at end of file diff --git a/htdocs/help.php b/htdocs/help.php index 1adba1f3..c7aa4d52 100644 --- a/htdocs/help.php +++ b/htdocs/help.php @@ -5,13 +5,14 @@ $session->LoginRequired(); require_once("interactive-page.php"); -$c->page_title = "Really Simple CalDAV Store - Configuration Help"; +$c->page_title = "DAViCal CalDAV Server - Configuration Help"; include("page-header.php"); ?>

Help

-

For initial help you should visit the RSCDS Home Page. If you can't -find the answers there, then you should post your problem in the RSCDS forums on Sourceforge itself.

+

For initial help you should visit the DAViCal Home Page. If you can't +find the answers there, visit the #davical IRC channel on irc.oftc.net, send a question to the mailing list or +post your problem in the DAViCal forums on Sourceforge itself.

* @copyright Maxime Delorme diff --git a/htdocs/users.php b/htdocs/users.php index 3ca41b60..a469b903 100644 --- a/htdocs/users.php +++ b/htdocs/users.php @@ -2,8 +2,8 @@ /** * Display a list of all users * -* @package rscds -* @subpackage RSCDSSession +* @package davical +* @subpackage Admin * @author Andrew McMillan * @copyright Catalyst .Net Ltd * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 diff --git a/rscds.webprj b/rscds.webprj index a32321e0..696fd70a 100644 --- a/rscds.webprj +++ b/rscds.webprj @@ -241,5 +241,6 @@ + From 9b72812be78f81044a00fd88c2bc25761a7c7258 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 1 Nov 2007 22:20:56 +1300 Subject: [PATCH 049/189] Updated language strings. --- po/de_DE.po | 14 +++++++++----- po/en_NZ.po | 9 ++++++--- po/es_AR.po | 14 +++++++++----- po/es_ES.po | 14 +++++++++----- po/es_MX.po | 14 +++++++++----- po/fr_FR.po | 14 +++++++++----- po/hu_HU.po | 14 +++++++++----- po/messages.po | 9 ++++++--- po/nl_NL.po | 14 +++++++++----- po/pl_PL.po | 14 +++++++++----- po/ru_RU.po | 14 +++++++++----- 11 files changed, 93 insertions(+), 51 deletions(-) diff --git a/po/de_DE.po b/po/de_DE.po index d4829e14..61dff7c4 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: 2006-11-06 17:24+1300\n" "Last-Translator: Cristina Radalescu \n" "MIME-Version: 1.0\n" @@ -19,9 +19,9 @@ msgstr "" msgid "- creating record for users : %s" msgstr "" -#, c-format -msgid "- desactivating users : %s" -msgstr "" +#, fuzzy, c-format +msgid "- deactivating users : %s" +msgstr "Benutzerdaten bearbeiten" #, c-format msgid "- nothing done on %s" @@ -161,6 +161,10 @@ msgstr "Datenbank Error" msgid "Date Style" msgstr "Datumsformat" +#, fuzzy +msgid "Default relationships added." +msgstr "Verhältnis hinzugefuegt" + msgid "Delete" msgstr "Löschen" @@ -196,7 +200,7 @@ msgid "Enter your username and password then click here to log in." msgstr "" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/en_NZ.po b/po/en_NZ.po index 38051ce2..e1cd9583 100644 --- a/po/en_NZ.po +++ b/po/en_NZ.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -21,7 +21,7 @@ msgid "- creating record for users : %s" msgstr "" #, c-format -msgid "- desactivating users : %s" +msgid "- deactivating users : %s" msgstr "" #, c-format @@ -153,6 +153,9 @@ msgstr "" msgid "Date Style" msgstr "" +msgid "Default relationships added." +msgstr "" + msgid "Delete" msgstr "" @@ -188,7 +191,7 @@ msgid "Enter your username and password then click here to log in." msgstr "" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/es_AR.po b/po/es_AR.po index 0556b8e6..ec718843 100644 --- a/po/es_AR.po +++ b/po/es_AR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti \n" "Language-Team: LANGUAGE \n" @@ -20,9 +20,9 @@ msgstr "" msgid "- creating record for users : %s" msgstr "" -#, c-format -msgid "- desactivating users : %s" -msgstr "" +#, fuzzy, c-format +msgid "- deactivating users : %s" +msgstr "Mostrar el registro de éste usuario" #, c-format msgid "- nothing done on %s" @@ -162,6 +162,10 @@ msgstr "Error en la Base de Datos." msgid "Date Style" msgstr "Formato de Fecha" +#, fuzzy +msgid "Default relationships added." +msgstr "Relación incorporada." + msgid "Delete" msgstr "Borrar" @@ -197,7 +201,7 @@ msgid "Enter your username and password then click here to log in." msgstr "" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/es_ES.po b/po/es_ES.po index 0556b8e6..ec718843 100644 --- a/po/es_ES.po +++ b/po/es_ES.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti \n" "Language-Team: LANGUAGE \n" @@ -20,9 +20,9 @@ msgstr "" msgid "- creating record for users : %s" msgstr "" -#, c-format -msgid "- desactivating users : %s" -msgstr "" +#, fuzzy, c-format +msgid "- deactivating users : %s" +msgstr "Mostrar el registro de éste usuario" #, c-format msgid "- nothing done on %s" @@ -162,6 +162,10 @@ msgstr "Error en la Base de Datos." msgid "Date Style" msgstr "Formato de Fecha" +#, fuzzy +msgid "Default relationships added." +msgstr "Relación incorporada." + msgid "Delete" msgstr "Borrar" @@ -197,7 +201,7 @@ msgid "Enter your username and password then click here to log in." msgstr "" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/es_MX.po b/po/es_MX.po index 0556b8e6..ec718843 100644 --- a/po/es_MX.po +++ b/po/es_MX.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti \n" "Language-Team: LANGUAGE \n" @@ -20,9 +20,9 @@ msgstr "" msgid "- creating record for users : %s" msgstr "" -#, c-format -msgid "- desactivating users : %s" -msgstr "" +#, fuzzy, c-format +msgid "- deactivating users : %s" +msgstr "Mostrar el registro de éste usuario" #, c-format msgid "- nothing done on %s" @@ -162,6 +162,10 @@ msgstr "Error en la Base de Datos." msgid "Date Style" msgstr "Formato de Fecha" +#, fuzzy +msgid "Default relationships added." +msgstr "Relación incorporada." + msgid "Delete" msgstr "Borrar" @@ -197,7 +201,7 @@ msgid "Enter your username and password then click here to log in." msgstr "" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/fr_FR.po b/po/fr_FR.po index 9140ee7a..d9f1f5a6 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.3.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: 2006-11-13 13:03+1300\n" "Last-Translator: maxime delorme \n" "Language-Team: LANGUAGE \n" @@ -20,8 +20,8 @@ msgstr "" msgid "- creating record for users : %s" msgstr "- création des utilisateurs : %s" -#, c-format -msgid "- desactivating users : %s" +#, fuzzy, c-format +msgid "- deactivating users : %s" msgstr "- desactivation des utilisateurs : %s" #, c-format @@ -165,6 +165,10 @@ msgstr "Erreur base de données" msgid "Date Style" msgstr "Format des dates" +#, fuzzy +msgid "Default relationships added." +msgstr "Relation ajoutée" + msgid "Delete" msgstr "Supprimer" @@ -203,8 +207,8 @@ msgstr "Tapez un nom pour ce type de ressource" msgid "Enter your username and password then click here to log in." msgstr "Tapez votre nom d'utilisateur et votre mot de passe puis cliquez ici pour vous connecter" -#, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +#, fuzzy, c-format +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "Erreur NoUserFound avec le filtre >%s<, attributs >%s<, dn >%s<" msgid "Error querying database." diff --git a/po/hu_HU.po b/po/hu_HU.po index 55766b9a..f793b82e 100644 --- a/po/hu_HU.po +++ b/po/hu_HU.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: 2007-05-03 15:00+0001\n" "Last-Translator: David Takacs \n" "Language-Team: \n" @@ -20,9 +20,9 @@ msgstr "" msgid "- creating record for users : %s" msgstr "" -#, c-format -msgid "- desactivating users : %s" -msgstr "" +#, fuzzy, c-format +msgid "- deactivating users : %s" +msgstr "Felhasználó szerkesztése" #, c-format msgid "- nothing done on %s" @@ -155,6 +155,10 @@ msgstr "Adatbázis-hiba" msgid "Date Style" msgstr "Dátumformátum" +#, fuzzy +msgid "Default relationships added." +msgstr "Kapcsolat hozzáadva." + msgid "Delete" msgstr "Törlés" @@ -190,7 +194,7 @@ msgid "Enter your username and password then click here to log in." msgstr "Írja be a felhasználónevét és jelszavát a belépéshez" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/messages.po b/po/messages.po index 23f4ba48..d8b1102a 100644 --- a/po/messages.po +++ b/po/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -21,7 +21,7 @@ msgid "- creating record for users : %s" msgstr "" #, c-format -msgid "- desactivating users : %s" +msgid "- deactivating users : %s" msgstr "" #, c-format @@ -158,6 +158,9 @@ msgstr "" msgid "Date Style" msgstr "" +msgid "Default relationships added." +msgstr "" + msgid "Delete" msgstr "" @@ -195,7 +198,7 @@ msgid "Enter your username and password then click here to log in." msgstr "" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/nl_NL.po b/po/nl_NL.po index 499929ad..266ccb03 100644 --- a/po/nl_NL.po +++ b/po/nl_NL.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Eelco Maljaars \n" "Language-Team: nl_NL \n" @@ -20,9 +20,9 @@ msgstr "" msgid "- creating record for users : %s" msgstr "" -#, c-format -msgid "- desactivating users : %s" -msgstr "" +#, fuzzy, c-format +msgid "- deactivating users : %s" +msgstr "Verander deze gebruiker" #, c-format msgid "- nothing done on %s" @@ -158,6 +158,10 @@ msgstr "Database fout" msgid "Date Style" msgstr "Datum stijl" +#, fuzzy +msgid "Default relationships added." +msgstr "Relatie toegevoegd" + msgid "Delete" msgstr "Verwijder" @@ -194,7 +198,7 @@ msgid "Enter your username and password then click here to log in." msgstr "Voer je gebruikersnaam en wachtwoord in en klik hier om in te loggen" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/pl_PL.po b/po/pl_PL.po index f73394a0..ea0b25d8 100644 --- a/po/pl_PL.po +++ b/po/pl_PL.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds-messages\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: 2007-03-31 00:24+0200\n" "Last-Translator: Rafal Slubowski \n" "Language-Team: polski \n" @@ -22,9 +22,9 @@ msgstr "" msgid "- creating record for users : %s" msgstr "" -#, c-format -msgid "- desactivating users : %s" -msgstr "" +#, fuzzy, c-format +msgid "- deactivating users : %s" +msgstr "Zmień dane tego użytkownika " #, c-format msgid "- nothing done on %s" @@ -157,6 +157,10 @@ msgstr "Błąd bazy danych" msgid "Date Style" msgstr "Format daty" +#, fuzzy +msgid "Default relationships added." +msgstr "Zależność została dodana." + msgid "Delete" msgstr "Usuń" @@ -192,7 +196,7 @@ msgid "Enter your username and password then click here to log in." msgstr "Wpisz nazwę użytkownika oraz hasło i naciśnij tutaj aby się zalogować." #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." diff --git a/po/ru_RU.po b/po/ru_RU.po index 4f54c80c..0a6cb030 100644 --- a/po/ru_RU.po +++ b/po/ru_RU.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.3.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-16 13:28+1300\n" +"POT-Creation-Date: 2007-11-01 22:19+1300\n" "PO-Revision-Date: 2006-11-13 23:07+0500\n" "Last-Translator: Nick Khazov \n" "Language-Team: LANGUAGE \n" @@ -19,9 +19,9 @@ msgstr "" msgid "- creating record for users : %s" msgstr "" -#, c-format -msgid "- desactivating users : %s" -msgstr "" +#, fuzzy, c-format +msgid "- deactivating users : %s" +msgstr "Посмотреть мою учетную запись" #, c-format msgid "- nothing done on %s" @@ -160,6 +160,10 @@ msgstr "" msgid "Date Style" msgstr "" +#, fuzzy +msgid "Default relationships added." +msgstr "Связь добавлена." + msgid "Delete" msgstr "Удалить" @@ -197,7 +201,7 @@ msgid "Enter your username and password then click here to log in." msgstr "" #, c-format -msgid "Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<" +msgid "Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<" msgstr "" msgid "Error querying database." From b373f73ca1b1763822b715da5b61af4d56559927 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 1 Nov 2007 22:21:33 +1300 Subject: [PATCH 050/189] Add a 'where' clause to the auth_other_awl method. --- inc/auth-functions.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/inc/auth-functions.php b/inc/auth-functions.php index 2d952e35..ece64513 100644 --- a/inc/auth-functions.php +++ b/inc/auth-functions.php @@ -145,7 +145,12 @@ EOERRMSG; else $cols = "*"; - $qry = new PgQuery("SELECT $cols FROM usr WHERE lower(username) = ? ", strtolower($username) ); + if ( isset($c->authenticate_hook['config']['where']) ) + $andwhere = " AND ".$c->authenticate_hook['config']['where']; + else + $andwhere = ""; + + $qry = new PgQuery("SELECT $cols FROM usr WHERE lower(username) = ? $andwhere", strtolower($username) ); $qry->SetConnection($authconn); if ( $qry->Exec('Login',__LINE,__FILE__) && $qry->rows == 1 ) { $usr = $qry->Fetch(); From 5e47b74ccf0de6e08f9ffa20a87021e83623e6f9 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 1 Nov 2007 22:29:08 +1300 Subject: [PATCH 051/189] Provide example config snippet for docs. --- inc/auth-functions.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/inc/auth-functions.php b/inc/auth-functions.php index ece64513..ccbd590a 100644 --- a/inc/auth-functions.php +++ b/inc/auth-functions.php @@ -123,7 +123,21 @@ function UpdateUserFromExternal( &$usr ) { * Authenticate against a different PostgreSQL database which contains a usr table in * the AWL format. * -* @package davical +* Use this as in the following example config snippet: +* +* require_once('auth-functions.php'); +* $c->authenticate_hook = array( +* 'call' => 'AuthExternalAwl', +* 'config' => array( +* // A PgSQL database connection string for the database containing user records +* 'connection' => 'dbname=wrms host=otherhost port=5433 user=general', +* // Which columns should be fetched from the database +* 'columns' => "user_no, active, email_ok, joined, last_update AS updated, last_used, username, password, fullname, email", +* // a WHERE clause to limit the records returned. +* 'where' => "active AND org_code=7" +* ) +* ); +* */ function AuthExternalAWL( $username, $password ) { global $c; From 8df33654e3954f199cc57c9544ba9218a9dee21c Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 1 Nov 2007 22:30:46 +1300 Subject: [PATCH 052/189] Change the example of auth against an external awl to use the new way. --- config/example-config.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/config/example-config.php b/config/example-config.php index 9195fb73..8942b67c 100644 --- a/config/example-config.php +++ b/config/example-config.php @@ -149,19 +149,20 @@ $c->admin_email ='calendar-admin@example.com'; /********************************/ /******* Other AWL hook *********/ /********************************/ -//require_once('AuthPlugins.php'); +// require_once('auth-functions.php'); // $c->authenticate_hook = array( -// 'call' => 'auth_other_awl', +// 'call' => 'AuthExternalAwl', // 'config' => array( - /** A PgSQL database connection string for the database containing user records */ -// 'connection' => 'dbname=wrms host=otherhose port=5433 user=general', - /** Which columns should be fetched from the database */ -// 'columns' => "user_no, active, email_ok, joined, last_update AS updated, last_used, username, password, fullname, email" +// // A PgSQL database connection string for the database containing user records +// 'connection' => 'dbname=wrms host=otherhost port=5433 user=general', +// // Which columns should be fetched from the database +// 'columns' => "user_no, active, email_ok, joined, last_update AS updated, last_used, username, password, fullname, email", +// // a WHERE clause to limit the records returned. +// 'where' => "active AND org_code=7" // ) // ); - /********************************/ /*********** LDAP hook **********/ /********************************/ From b876c2ef54ab97f1980e95ac0da4c046b06e602d Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Thu, 1 Nov 2007 23:09:43 +1300 Subject: [PATCH 053/189] Only warn when we fail to build the docs. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24f02d21..3c3d9e10 100755 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ version=$(shell cat VERSION) all: inc/always.php built-docs built-docs: docs/api/phpdoc.ini htdocs/*.php inc/*.php - phpdoc -c docs/api/phpdoc.ini + phpdoc -c docs/api/phpdoc.ini || echo "WARNING: failed to build docs" touch built-docs # From c370e3dc5f682ff1f755fa994cd4f110b2a7cf7c Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 2 Nov 2007 22:12:45 +1300 Subject: [PATCH 054/189] Change the dbname/dbport/dbhost parameters into one dsn parameter. --- testing/dav_test | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/testing/dav_test b/testing/dav_test index 50096424..7ea78abf 100755 --- a/testing/dav_test +++ b/testing/dav_test @@ -10,11 +10,9 @@ use Getopt::Long qw(:config permute); # allow mixed args. # Options variables my $debug = 0; -my $dbname = "rscds"; -my $dbport = 5432; +my $dsn = "davical"; my $dbuser = ""; my $dbpass = ""; -my $dbhost = ""; my $suite; my $test; my $helpmeplease = 0; @@ -25,11 +23,9 @@ my $patchdir = $dbadir . "/patches"; GetOptions ('debug!' => \$debug, - 'dbname=s' => \$dbname, + 'dsn=s' => \$dsn, 'dbuser=s' => \$dbuser, 'dbpass=s' => \$dbpass, - 'dbport=s' => \$dbport, - 'dbhost=s' => \$dbhost, 'suite=s' => \$suite, 'case=s' => \$test, 'help' => \$helpmeplease ); @@ -40,10 +36,8 @@ usage() if ( $helpmeplease || !defined($suite) || !defined($test)); # Open database connection. Note that the standard PostgreSQL # environment variables will also work with DBD::Pg. ############################################################ -my $dsn = "dbi:Pg:dbname=$dbname"; -$dsn .= ";host=$dbhost" if ( "$dbhost" ne "" ); -$dsn .= ";port=$dbport" if ( $dbport != 5432 ); -my $dbh = DBI->connect($dsn, $dbuser, $dbpass, { AutoCommit => 0 } ) or die "Can't connect to database $dbname"; +$dsn = "dbi:Pg:dbname=$dsn"; +my $dbh = DBI->connect($dsn, $dbuser, $dbpass, { AutoCommit => 0 } ) or die "Can't connect to database $dsn"; my @arguments = ( "--basic", "--proxy", "", "--silent" ); @@ -242,11 +236,9 @@ and follow the instructions there. The following options are available for controlling the database, for those test cases which might require it: - --dbname + --dsn [;port=NNNN][;host=example.com] --dbuser --dbpass - --dbport - --dbhost The test instructions will include lines defining the test like: From 9fa7ef661ac7df33e00b1fa1c7ec21a63b2d306b Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 2 Nov 2007 22:13:51 +1300 Subject: [PATCH 055/189] Sprinkle a little more configurability in there. --- testing/run_regressions.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/testing/run_regressions.sh b/testing/run_regressions.sh index 389a97aa..71183764 100755 --- a/testing/run_regressions.sh +++ b/testing/run_regressions.sh @@ -2,7 +2,15 @@ # # Run the regression tests and display differences # -DBNAME=caldav +DBNAME=regression +PGPOOL=inactive +HOSTNAME=regression + +. regression.conf + +[ -z "${DSN}" ] && DSN="${DBNAME}" + + UNTIL=${1:-"99999"} ACCEPT_ALL=${2:-""} @@ -40,7 +48,7 @@ drop_database() { # Restart PGPool to ensure we can drop and recreate the database # FIXME: We should really drop everything *from* the database and create it # from that, so we don't need to do this. - sudo /etc/init.d/pgpool restart + [ "${PGPOOL}" = "inactive" ] || sudo /etc/init.d/pgpool restart dropdb $1 if psql -ltA | cut -f1 -d'|' | grep "^$1$" >/dev/null ; then echo "Failed to drop $1 database" @@ -69,7 +77,7 @@ for T in ${REGRESSION}/*.test ; do if [ "${TESTNUM}" -gt "${UNTIL}" ] ; then break; fi - ./dav_test --dbname caldav --suite regression-suite --case "${TEST}" | ./normalise_result > "${RESULTS}/${TEST}" + ./dav_test --dsn "${DSN}" --suite regression-suite --case "${TEST}" | ./normalise_result > "${RESULTS}/${TEST}" check_result "${TEST}" From a07b8e31eb8870b533986a0caff533853d7f7466 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 2 Nov 2007 22:15:08 +1300 Subject: [PATCH 056/189] An example configuration file for the regression testing. --- testing/regression.conf.example | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 testing/regression.conf.example diff --git a/testing/regression.conf.example b/testing/regression.conf.example new file mode 100644 index 00000000..909fcc93 --- /dev/null +++ b/testing/regression.conf.example @@ -0,0 +1,7 @@ +# +# A configuration file for the regression testing. +# +DBNAME=regression +PGPOOL=inactive +HOSTNAME=mycaldav +DSN="regression;port=5432" From ee1ea4c9502b36af7cb1da4493d8be3781b09d5e Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 10:14:05 +1300 Subject: [PATCH 057/189] Refactoring of the principal into an object class. --- inc/CalDAVPrincipal.php | 153 ++++++++++++++++++++++++++++++++ inc/CalDAVRequest.php | 22 ++--- inc/caldav-PROPFIND.php | 4 +- inc/caldav-REPORT-principal.php | 3 - rscds.webprj | 1 + 5 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 inc/CalDAVPrincipal.php diff --git a/inc/CalDAVPrincipal.php b/inc/CalDAVPrincipal.php new file mode 100644 index 00000000..3764d205 --- /dev/null +++ b/inc/CalDAVPrincipal.php @@ -0,0 +1,153 @@ + +* @copyright Catalyst .Net Ltd +* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 +*/ + +/** +* @var $_CalDAVPrincipalCache +* A global variable holding a cache of any DAV Principals which are +* read from the DB. +*/ +$_CalDAVPrincipalCache = (object) array( 'p' => array(), 'u' => array() ); + + +/** +* A class for things to do with a DAV Principal +* +* @package davical +*/ +class CalDAVPrincipal +{ + /** + * @var The home URL of the principal + */ + var $url; + + /** + * @var RFC4791: Identifies the URL(s) of any WebDAV collections that contain + * calendar collections owned by the associated principal resource. + */ + var $calendar_home_set; + + /** + * @var draft-desruisseaux-caldav-sched-03: Identify the URL of the scheduling + * Inbox collection owned by the associated principal resource. + */ + var $schedule_inbox_url; + + /** + * @var draft-desruisseaux-caldav-sched-03: Identify the URL of the scheduling + * Outbox collection owned by the associated principal resource. + */ + var $schedule_outbox_url; + + /** + * Constructor + * @param mixed $parameters If null, an empty Principal is created. If it + * is an integer then that ID is read (if possible). If it is + * an array then the Principal matching the supplied elements is read. + * + * @return boolean Whether we actually read data from the DB to initialise the record. + */ + function CalDAVPrincipal( $parameters = null ) { + global $session, $c; + + if ( $parameters == null ) return false; + if ( is_int($parameters) ) { + dbg_error_log( "principal", "Principal: %d", $parameters ); + $usr = getUserByID($parameters); + } + else if ( is_array($parameters) ) { + if ( isset($parameters['username']) ) { + $usr = getUserByName($parameters['username']); + } + else if ( isset($parameters['user_no']) ) { + $usr = getUserByID($parameters['user_no']); + } + else if ( isset($parameters['path']) ) { + dbg_error_log( "principal", "Finding Principal from path: '%s'", $parameters['path'] ); + if ( $username = $this->UsernameFromPath($parameters['path'],$parameters['options']) ) { + $usr = getUserByName($username); + if ( isset($parameters['options']['allow_by_email']) && is_object($usr) && preg_match( '#/(\S+@\S+[.]\S+)$#', $parameters['path']) ) { + $this->by_email = true; + } + } + } + else if ( isset($parameters['principal-property-search']) ) { + $usr = $this->PropertySearch($parameters['principal-property-search']); + } + } + if ( !isset($usr) || !is_object($usr) ) return false; + + $this->InitialiseRecord($usr); + } + + + /** + * Initialise the Principal object from a $usr record from the DB. + * @param object $usr The usr record from the DB. + */ + function InitialiseRecord($usr) { + global $c; + foreach( $usr AS $k => $v ) { + $this->{$k} = $v; + } + + $this->url = sprintf( "%s/~%d/", $c->protocol_server_port_script, $this->user_no); + $this->calendar_home_set = sprintf( "%s/%s/", $c->protocol_server_port_script, $this->username); + $this->schedule_inbox_url = sprintf( "%s.inbox/", $this->url); + $this->schedule_outbox_url = sprintf( "%s.outbox/", $this->url); + + dbg_error_log( "principal", "User: %s (%d) URL: %s, Home: %s", $this->username, $this->user_no, $this->url, $this->calendar_home_set ); + } + + + /** + * Work out the username, based on elements of the path. + * @param string $path The path to be used. + * @param array $options The request options, controlling whether e-mail paths are allowed. + */ + function UsernameFromPath( $path, $options = null ) { + global $session, $c; + + if ( $path == '/' || $path == '' ) { + dbg_error_log( "principal", "No useful path split possible" ); + return false; + } + + $path_split = explode('/', $path ); + @dbg_error_log( "principal", "Path split into at least /// %s /// %s /// %s", $path_split[1], $path_split[2], $path_split[3] ); + + if ( substr($path,0,1) == '~' ) { + // URL is for a principal, by ID + $user_no = intval(substr($path,1)); + $user = getUserByID($user_no); + $username = $user->username; + } + else { + $username = $path_split[1]; + + if ( isset($options['allow_by_email']) && preg_match( '#/(\S+@\S+[.]\S+)$#', $path, $matches) ) { + $email = $matches[1]; + $qry = new PgQuery("SELECT user_no FROM usr WHERE email = ?;", $email ); + if ( $qry->Exec("principal") && $user = $qry->Fetch() ) { + $user_no = $user->user_no; + $username = $user->username; + } + } + elseif( $user = getUserByName( $username, 'caldav') ) { + $user_no = $user->user_no; + } + } + return $username; + } + + + +} \ No newline at end of file diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index 749bd2f7..f858ac5d 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -7,21 +7,22 @@ * - Utility functions which we can use to decide whether this * is a permitted activity for this user. * -* @package rscds -* @subpackage CalDAVRequest +* @package davical +* @subpackage Request * @author Andrew McMillan * @copyright Catalyst .Net Ltd * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ require_once("XMLElement.php"); +require_once("CalDAVPrincipal.php"); define('DEPTH_INFINITY', 9999); /** * A class for collecting things to do with this request. * -* @package rscds +* @package davical */ class CalDAVRequest { @@ -150,15 +151,17 @@ class CalDAVRequest } } + $this->user_no = $session->user_no; + $this->username = $session->username; + /** * Extract the user whom we are accessing - * TODO: Replace this by something which properly sets up the DAV 'principal' */ - $this->UserFromPath(); - $this->principal->url = sprintf( "%s/%s/", $c->protocol_server_port_script, $this->principal->username); - $this->principal->calendar_home_set = sprintf( "%s", $this->principal->url); - $this->principal->schedule_inbox_url = sprintf( "%s.inbox/", $this->principal->url); - $this->principal->schedule_outbox_url = sprintf( "%s.outbox/", $this->principal->url); + $this->principal = new CalDAVPrincipal( array( "path" => $this->path, "options" => $this->options ) ); + if ( isset($this->principal->user_no) ) $this->user_no = $this->principal->user_no; + if ( isset($this->principal->username)) $this->username = $this->principal->username; + if ( isset($this->principal->by_email)) $this->by_email = true; + /** * Evaluate our permissions for accessing the target @@ -584,4 +587,3 @@ class CalDAVRequest } } -?> \ No newline at end of file diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index cf61d0c8..da760631 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -77,8 +77,8 @@ foreach( $request->xml_tags AS $k => $v ) { * Handled calendar-schedule properties */ case 'CALENDAR-USER-ADDRESS-SET': /** CalDAV+s: slightly supported */ - case 'SCHEDULE-INBOX-URL': /** CalDAV+s: not supported */ - case 'SCHEDULE-OUTBOX-URL': /** CalDAV+s: not supported */ +// case 'SCHEDULE-INBOX-URL': /** CalDAV+s: not supported */ +// case 'SCHEDULE-OUTBOX-URL': /** CalDAV+s: not supported */ $attribute_list[$tag] = 1; dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag ); break; diff --git a/inc/caldav-REPORT-principal.php b/inc/caldav-REPORT-principal.php index 0f9f11cb..4cbf9d6f 100644 --- a/inc/caldav-REPORT-principal.php +++ b/inc/caldav-REPORT-principal.php @@ -22,9 +22,6 @@ function principal_to_xml( $properties, $item ) { $denied = array(); foreach( $properties AS $k => $v ) { switch( $v ) { -// case 'DAV::GETCONTENTTYPE': -// $prop->NewElement("getcontenttype", "text/x-vcard" ); -// break; case 'DAV::RESOURCETYPE': $prop->NewElement("resourcetype", new XMLElement("principal") ); break; diff --git a/rscds.webprj b/rscds.webprj index 696fd70a..96261753 100644 --- a/rscds.webprj +++ b/rscds.webprj @@ -242,5 +242,6 @@ + From 6e125d5de7c54d59bd5e7c40913d4244d4c648c8 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 10:19:37 +1300 Subject: [PATCH 058/189] Ignore a bunch of random crap in the testing directory. --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 6066d8fb..4108ca55 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,8 @@ locale built-docs .settings *~ +testing/*.stream +testing/*.cap +testing/*.pcap +testing/*.dump +testing/regression.conf From f02a8e3ebc654f9ee31f9850ce2e9cd44be91ded Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 11:50:12 +1300 Subject: [PATCH 059/189] Fix UsernameFromPath when the path is an e-mail address. --- inc/CalDAVPrincipal.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/inc/CalDAVPrincipal.php b/inc/CalDAVPrincipal.php index 3764d205..0c98cc4c 100644 --- a/inc/CalDAVPrincipal.php +++ b/inc/CalDAVPrincipal.php @@ -71,8 +71,8 @@ class CalDAVPrincipal $usr = getUserByID($parameters['user_no']); } else if ( isset($parameters['path']) ) { - dbg_error_log( "principal", "Finding Principal from path: '%s'", $parameters['path'] ); - if ( $username = $this->UsernameFromPath($parameters['path'],$parameters['options']) ) { + dbg_error_log( "principal", "Finding Principal from path: '%s', options.allow_by_email: '%s'", $parameters['path'], $parameters['options']['allow_by_email'] ); + if ( $username = $this->UsernameFromPath($parameters['path'], $parameters['options']) ) { $usr = getUserByName($username); if ( isset($parameters['options']['allow_by_email']) && is_object($usr) && preg_match( '#/(\S+@\S+[.]\S+)$#', $parameters['path']) ) { $this->by_email = true; @@ -104,7 +104,7 @@ class CalDAVPrincipal $this->schedule_inbox_url = sprintf( "%s.inbox/", $this->url); $this->schedule_outbox_url = sprintf( "%s.outbox/", $this->url); - dbg_error_log( "principal", "User: %s (%d) URL: %s, Home: %s", $this->username, $this->user_no, $this->url, $this->calendar_home_set ); + dbg_error_log( "principal", "User: %s (%d) URL: %s, Home: %s, By Email: %d", $this->username, $this->user_no, $this->url, $this->calendar_home_set, $this->by_email ); } @@ -135,7 +135,7 @@ class CalDAVPrincipal if ( isset($options['allow_by_email']) && preg_match( '#/(\S+@\S+[.]\S+)$#', $path, $matches) ) { $email = $matches[1]; - $qry = new PgQuery("SELECT user_no FROM usr WHERE email = ?;", $email ); + $qry = new PgQuery("SELECT user_no, username FROM usr WHERE email = ?;", $email ); if ( $qry->Exec("principal") && $user = $qry->Fetch() ) { $user_no = $user->user_no; $username = $user->username; From ad712e9c258d6644b3761318d3b7b2aaeb7cec07 Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Sat, 3 Nov 2007 12:11:29 +1300 Subject: [PATCH 060/189] Fix PHP syntax. --- inc/drivers_ldap.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index 580be59e..87da7d97 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -151,7 +151,7 @@ function getStaticLdap() { * Synchronise a cached user with one from LDAP * @param object $usr A user record to be updated (or created) */ -function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ); +function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { $validUserFields = get_fields('usr'); foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { @@ -263,7 +263,7 @@ function sync_LDAP(){ $users_to_update = array_intersect($db_users,$ldap_users); // creation of all users; - if ( sizeof($users_to_create) ) + if ( sizeof($users_to_create) ) { $c->messages[] = sprintf(i18n('- creating record for users : %s'),join(', ',$users_to_create)); foreach( $users_to_create as $username ) { @@ -323,4 +323,3 @@ function sync_LDAP(){ } } } - From 5ee58e34b3b2489119c4170169e0d211fde02fbf Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Sat, 3 Nov 2007 12:17:21 +1300 Subject: [PATCH 061/189] Rename one more occurance on attributs to attributes, I can login with LDAP now. --- inc/drivers_ldap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index 87da7d97..48fec9a1 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -111,7 +111,7 @@ class ldapDrivers $entry=NULL; // We get the DN of the USER - $entry = ldap_search($this->connect, $this->baseDNUsers, $filter,$attributs); + $entry = ldap_search($this->connect, $this->baseDNUsers, $filter,$attributes); if ( !ldap_first_entry($this->connect, $entry) ){ dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter ); return false; From 0920c1ef312b7e20f6b26a3cb1078ed57d961bdd Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 18:07:32 +1300 Subject: [PATCH 062/189] Remove dependence on database. --- scripts/po/rebuild-translations.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/po/rebuild-translations.sh b/scripts/po/rebuild-translations.sh index 12c220fa..d28b1cb5 100755 --- a/scripts/po/rebuild-translations.sh +++ b/scripts/po/rebuild-translations.sh @@ -18,14 +18,14 @@ sed -e 's/CHARSET/UTF-8/' <${PODIR}/messages.tmp >${PODIR}/messages.po rm ${PODIR}/messages.tmp -for LOCALE in `psql -qAt -c 'SELECT locale FROM supported_locales;' caldav` ; do +for LOCALE in `grep VALUES dba/supported_locales.sql | cut -f2 -d"'"` ; do if [ ! -f ${PODIR}/${LOCALE}.po ] ; then cp ${PODIR}/messages.po ${PODIR}/${LOCALE}.po fi msgmerge --quiet --width 105 --update ${PODIR}/${LOCALE}.po ${PODIR}/messages.po done -for LOCALE in `psql -qAt -c 'SELECT locale FROM supported_locales;' caldav` ; do +for LOCALE in `grep VALUES dba/supported_locales.sql | cut -f2 -d"'"` ; do mkdir -p ${LOCALEDIR}/${LOCALE}/LC_MESSAGES msgfmt ${PODIR}/${LOCALE}.po -o ${LOCALEDIR}/${LOCALE}/LC_MESSAGES/${APPLICATION}.mo done From 63930a85e62ac75095ce24a2ea2b15c764a788eb Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 18:09:23 +1300 Subject: [PATCH 063/189] Add the translation building process into the Makefile --- Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3c3d9e10..15e58fdf 100755 --- a/Makefile +++ b/Makefile @@ -4,12 +4,16 @@ package=rscds version=$(shell cat VERSION) -all: inc/always.php built-docs +all: inc/always.php built-docs built-po built-docs: docs/api/phpdoc.ini htdocs/*.php inc/*.php phpdoc -c docs/api/phpdoc.ini || echo "WARNING: failed to build docs" touch built-docs +built-po: inc/always.php scripts/po/rebuild-translations.sh scripts/po/extract.pl + scripts/po/rebuild-translations.sh + touch built-po + # # Insert the current version number into always.php # @@ -28,7 +32,7 @@ release: built-docs rm $(package)-$(version) clean: - rm -f built-docs + rm -f built-docs built-po -find docs/api/* ! -name "phpdoc.ini" ! -name ".gitignore" -delete -find . -name "*~" -delete From 78465c2be1dbaf253aafe2a34d9046bde46b633c Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Sat, 3 Nov 2007 20:24:29 +1300 Subject: [PATCH 064/189] Allow easily removing a user using SQL by adding some cascades. I've tested the patch this time! --- dba/patches/1.1.11.sql | 16 ++++++++++++++++ dba/rscds.sql | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 dba/patches/1.1.11.sql diff --git a/dba/patches/1.1.11.sql b/dba/patches/1.1.11.sql new file mode 100644 index 00000000..60a55e55 --- /dev/null +++ b/dba/patches/1.1.11.sql @@ -0,0 +1,16 @@ + +-- Sort out accessing calendar entries. + +BEGIN; +SELECT check_db_revision(1,1,10); + +ALTER TABLE calendar_item DROP CONSTRAINT "$1"; +ALTER TABLE calendar_item ADD CONSTRAINT "$1" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; + +ALTER TABLE collection DROP CONSTRAINT "$1"; +ALTER TABLE collection ADD CONSTRAINT "$1" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; + +SELECT new_db_revision(1,1,11, 'November' ); +COMMIT; +ROLLBACK; + diff --git a/dba/rscds.sql b/dba/rscds.sql index 33382bfa..ce52431a 100644 --- a/dba/rscds.sql +++ b/dba/rscds.sql @@ -7,7 +7,7 @@ -- The main event. Where we store the things the calendar throws at us. CREATE TABLE caldav_data ( - user_no INT references usr(user_no), + user_no INT references usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE, dav_name TEXT, dav_etag TEXT, created TIMESTAMP WITH TIME ZONE, @@ -69,7 +69,7 @@ GRANT SELECT,INSERT,UPDATE,DELETE ON calendar_item TO general; -- Something that can look like a filesystem hierarchy where we store stuff CREATE TABLE collection ( - user_no INT references usr(user_no), + user_no INT references usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE, parent_container TEXT, dav_name TEXT, dav_etag TEXT, @@ -142,4 +142,4 @@ CREATE TABLE freebusy_ticket ( GRANT INSERT,SELECT,UPDATE,DELETE ON TABLE freebusy_ticket TO general; -SELECT new_db_revision(1,1,10, 'October' ); +SELECT new_db_revision(1,1,11, 'November' ); From 8b53f09baa62981263ee3d6f1e7fb338811efe07 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 20:37:44 +1300 Subject: [PATCH 065/189] Allow non GET/POST requests on index.php to actually call caldav.php which means that a request for / which becomes index.php, still works with a PROPFIND or similar. --- htdocs/index.php | 23 +- .../regression-suite/826-Spec-PROPFIND.result | 49 +++ .../regression-suite/826-Spec-PROPFIND.test | 31 ++ .../regression-suite/827-Spec-PROPFIND.result | 284 ++++++++++++++++++ .../regression-suite/827-Spec-PROPFIND.test | 31 ++ 5 files changed, 410 insertions(+), 8 deletions(-) create mode 100644 testing/tests/regression-suite/826-Spec-PROPFIND.result create mode 100644 testing/tests/regression-suite/826-Spec-PROPFIND.test create mode 100644 testing/tests/regression-suite/827-Spec-PROPFIND.result create mode 100644 testing/tests/regression-suite/827-Spec-PROPFIND.test diff --git a/htdocs/index.php b/htdocs/index.php index 82d5206a..cab00912 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -1,9 +1,17 @@ LoginRequired(); -require_once("interactive-page.php"); +include("interactive-page.php"); include("page-header.php"); echo <<Where a set of users link to a group, which then links to other users/resources, the access restrictions will apply as the lesser of their link to that group, or the link from the group. They will have no access to each other's calendars. -

Configuring Calendar Clients for RSCDS

-

The RSCDS client setup page on sourceforge have information on how +

Configuring Calendar Clients for DAViCal

+

The DAViCal client setup page on sourceforge have information on how to configure Evolution, Sunbird, Lightning and Mulberry to use remotely hosted calendars.

The administrative interface has no facility for viewing or modifying calendar data.

-

Configuring RSCDS

+

Configuring DAViCal

If you can read this then things must be mostly working already.

-

The RSCDS installation page on sourceforge has +

The DAViCal installation page on sourceforge has some further information on how to install and configure this application.

\ No newline at end of file diff --git a/testing/tests/regression-suite/826-Spec-PROPFIND.result b/testing/tests/regression-suite/826-Spec-PROPFIND.result new file mode 100644 index 00000000..98e41252 --- /dev/null +++ b/testing/tests/regression-suite/826-Spec-PROPFIND.result @@ -0,0 +1,49 @@ + + + + /caldav.php/ + + + httpd/unix-directory + + + 20071103T201818 + + + + DAViCal CalDAV Server + "38f09ba341cd927809b571496db6e4c3" + + + + + + + + + + en_NZ.UTF-8 + + + + + + + + + + + + HTTP/1.1 200 OK + + + + + + + + + HTTP/1.1 404 Not Found + + + diff --git a/testing/tests/regression-suite/826-Spec-PROPFIND.test b/testing/tests/regression-suite/826-Spec-PROPFIND.test new file mode 100644 index 00000000..2ed3d626 --- /dev/null +++ b/testing/tests/regression-suite/826-Spec-PROPFIND.test @@ -0,0 +1,31 @@ +# +# Testing for Spec compliance. PROPFIND on the root +# +TYPE=PROPFIND +URL=http://mycaldav/ +HEADER=User-Agent: RFC2518 Spec Tests +HEADER=Depth: 0 +HEADER=Content-Type: application/xml + + +BEGINDATA + + + + + + + + + + + + + + + + + + + +ENDDATA diff --git a/testing/tests/regression-suite/827-Spec-PROPFIND.result b/testing/tests/regression-suite/827-Spec-PROPFIND.result new file mode 100644 index 00000000..b1762b1c --- /dev/null +++ b/testing/tests/regression-suite/827-Spec-PROPFIND.result @@ -0,0 +1,284 @@ + + + + /caldav.php/ + + + httpd/unix-directory + + + 20071103T202330 + + + + DAViCal CalDAV Server + "38f09ba341cd927809b571496db6e4c3" + + + + + + + + + + en_NZ.UTF-8 + + + + + + + + + + + + HTTP/1.1 200 OK + + + + + + + + + HTTP/1.1 404 Not Found + + + + /caldav.php/user1/ + + + httpd/unix-directory + Dow, 01 Jan 2000 00:00:00 GMT + + Dow, 01 Jan 2000 00:00:00 GMT + + + + + User 1 + "7d0fd5137942261bee17da4287f71494" + + + + + + + + + + en_NZ.UTF-8 + + + + + + + + + + + + HTTP/1.1 200 OK + + + + + + + + + HTTP/1.1 404 Not Found + + + + /caldav.php/manager1/ + + + httpd/unix-directory + Dow, 01 Jan 2000 00:00:00 GMT + + Dow, 01 Jan 2000 00:00:00 GMT + + + + + Manager 1 + "ec5b8b282c4a9c7b73d1e5bf610f0648" + + + + + + + + + + en_NZ.UTF-8 + + + + + + + + + + + + HTTP/1.1 200 OK + + + + + + + + + HTTP/1.1 404 Not Found + + + + /caldav.php/assistant1/ + + + httpd/unix-directory + Dow, 01 Jan 2000 00:00:00 GMT + + Dow, 01 Jan 2000 00:00:00 GMT + + + + + Assistant 1 + "b1f51f4e0cee340892205b0d7d514134" + + + + + + + + + + en_NZ.UTF-8 + + + + + + + + + + + + HTTP/1.1 200 OK + + + + + + + + + HTTP/1.1 404 Not Found + + + + /caldav.php/resource1/ + + + httpd/unix-directory + Dow, 01 Jan 2000 00:00:00 GMT + + Dow, 01 Jan 2000 00:00:00 GMT + + + + + Resource 1 + "7877b4ffa943232dbc624c0249c27e55" + + + + + + + + + + en_NZ.UTF-8 + + + + + + + + + + + + HTTP/1.1 200 OK + + + + + + + + + HTTP/1.1 404 Not Found + + + + /caldav.php/resource2/ + + + httpd/unix-directory + Dow, 01 Jan 2000 00:00:00 GMT + + Dow, 01 Jan 2000 00:00:00 GMT + + + + + Resource 2 + "658fc7067081793e3c1e27b32f935020" + + + + + + + + + + en_NZ.UTF-8 + + + + + + + + + + + + HTTP/1.1 200 OK + + + + + + + + + HTTP/1.1 404 Not Found + + + diff --git a/testing/tests/regression-suite/827-Spec-PROPFIND.test b/testing/tests/regression-suite/827-Spec-PROPFIND.test new file mode 100644 index 00000000..8e78bf79 --- /dev/null +++ b/testing/tests/regression-suite/827-Spec-PROPFIND.test @@ -0,0 +1,31 @@ +# +# Testing for Spec compliance. PROPFIND on the root +# +TYPE=PROPFIND +URL=http://mycaldav/ +HEADER=User-Agent: RFC2518 Spec Tests +HEADER=Depth: 1 +HEADER=Content-Type: application/xml + + +BEGINDATA + + + + + + + + + + + + + + + + + + + +ENDDATA From 13e9f6f4b55d43491a66e85c3cc9207b4b442aae Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 20:43:56 +1300 Subject: [PATCH 066/189] Fix cut and paste error. currval => nextval --- inc/auth-functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/auth-functions.php b/inc/auth-functions.php index ccbd590a..09c12765 100644 --- a/inc/auth-functions.php +++ b/inc/auth-functions.php @@ -92,7 +92,7 @@ function UpdateUserFromExternal( &$usr ) { * When we're doing the create we will usually need to generate a user number */ if ( !isset($usr->user_no) || intval($usr->user_no) == 0 ) { - $qry = new PgQuery( "SELECT currval('usr_user_no_seq');" ); + $qry = new PgQuery( "SELECT nextval('usr_user_no_seq');" ); $qry->Exec('Login',__LINE,__FILE__); $sequence_value = $qry->Fetch(true); // Fetch as an array $usr->user_no = $sequence_value[0]; From ec7dcef813182bde856261f5bee61a76493048fd Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 20:44:22 +1300 Subject: [PATCH 067/189] If running in debug then don't call curl with --silent --- testing/dav_test | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testing/dav_test b/testing/dav_test index 7ea78abf..fab2025e 100755 --- a/testing/dav_test +++ b/testing/dav_test @@ -40,8 +40,9 @@ $dsn = "dbi:Pg:dbname=$dsn"; my $dbh = DBI->connect($dsn, $dbuser, $dbpass, { AutoCommit => 0 } ) or die "Can't connect to database $dsn"; -my @arguments = ( "--basic", "--proxy", "", "--silent" ); -push @arguments, "--verbose" if ( defined($ARGV[2]) ); +my @arguments = ( "--basic", "--proxy", "" ); +push @arguments, "--silent" unless ( $debug ); +push @arguments, "--verbose" if ( $debug ); my $url; my $is_head_request = 0; From 2d456cadd516ab50cc451716f2b9c0dac802615b Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 20:44:59 +1300 Subject: [PATCH 068/189] Handle the case where we are called with a null path. --- inc/caldav-PROPFIND.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index da760631..f955708e 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -198,7 +198,10 @@ function collection_to_xml( $collection ) { $arbitrary_results = get_arbitrary_properties($collection->dav_name); $collection->properties = $arbitrary_results->found; - $url = $_SERVER['SCRIPT_NAME'] . $collection->dav_name; + $url = $_SERVER['SCRIPT_NAME']; + if ( $url == '/index.php' ) $url = '/caldav.php'; + $url .= $collection->dav_name; + $resourcetypes = array( new XMLElement("collection") ); $contentlength = false; if ( $collection->is_calendar == 't' ) { @@ -461,7 +464,7 @@ function get_collection_contents( $depth, $user_no, $collection ) { $sql .= "to_char(last_modified at time zone 'GMT',?) AS modified, "; $sql .= "summary AS dav_displayname "; $sql .= "FROM caldav_data JOIN calendar_item USING( user_no, dav_name) WHERE dav_name ~ ".qpg('^'.$collection->dav_name.'[^/]+$'); - $sql .= "AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL OR get_permissions($session->user_no,caldav_data.user_no) ~ 'A') "; // Must have 'all' permissions to see confidential items + $sql .= " AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL OR get_permissions($session->user_no,caldav_data.user_no) ~ 'A') "; // Must have 'all' permissions to see confidential items $sql .= "ORDER BY caldav_data.dav_name "; $qry = new PgQuery($sql, PgQuery::Plain(iCalendar::HttpDateFormat()), PgQuery::Plain(iCalendar::HttpDateFormat())); if( $qry->Exec("PROPFIND",__LINE__,__FILE__) && $qry->rows > 0 ) { @@ -485,12 +488,13 @@ function get_collection( $depth, $user_no, $collection_path ) { dbg_error_log("PROPFIND","Getting collection: Depth %d, User: %d, Path: %s", $depth, $user_no, $collection_path ); - if ( $collection_path == '/' ) { + if ( $collection_path == null || $collection_path == '/' || $collection_path == '' ) { $collection->dav_name = $collection_path; $collection->dav_etag = md5($c->system_name . $collection_path); $collection->is_calendar = 'f'; + $collection->is_principal = 'f'; $collection->dav_displayname = $c->system_name; - $collection->created = date('Ymd"T"His'); + $collection->created = date('Ymd\THis'); $responses[] = collection_to_xml( $collection ); } else { @@ -515,6 +519,7 @@ function get_collection( $depth, $user_no, $collection_path ) { $collection->dav_name = $collection_path; $collection->dav_etag = md5($collection_path); $collection->is_calendar = 't'; // Everything is a calendar, if it always exists! + $collection->is_principal = 'f'; $collection->dav_displayname = $collection_path; $collection->created = date('Ymd"T"His'); $responses[] = collection_to_xml( $collection ); @@ -539,7 +544,7 @@ function get_item( $item_path ) { $sql .= "to_char(coalesce(calendar_item.created, caldav_data.created) at time zone 'GMT',?) AS created, "; $sql .= "to_char(last_modified at time zone 'GMT',?) AS modified, "; $sql .= "summary AS dav_displayname "; - $sql .= "FROM caldav_data JOIN calendar_item USING( user_no, dav_name) WHERE dav_name = ?"; + $sql .= "FROM caldav_data JOIN calendar_item USING( user_no, dav_name) WHERE dav_name = ? "; $sql .= "AND (calendar_item.class != 'PRIVATE' OR calendar_item.class IS NULL OR get_permissions($session->user_no,caldav_data.user_no) ~ 'A') "; // Must have 'all' permissions to see confidential items $qry = new PgQuery($sql, PgQuery::Plain(iCalendar::HttpDateFormat()), PgQuery::Plain(iCalendar::HttpDateFormat()), $item_path); if( $qry->Exec("PROPFIND",__LINE__,__FILE__) && $qry->rows > 0 ) { From 7736e01a0ae928238371bc783e0fa8472fa8df92 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 20:45:33 +1300 Subject: [PATCH 069/189] If we can't split the path then default the username from the session. --- inc/CalDAVPrincipal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/CalDAVPrincipal.php b/inc/CalDAVPrincipal.php index 0c98cc4c..3034e30a 100644 --- a/inc/CalDAVPrincipal.php +++ b/inc/CalDAVPrincipal.php @@ -118,7 +118,7 @@ class CalDAVPrincipal if ( $path == '/' || $path == '' ) { dbg_error_log( "principal", "No useful path split possible" ); - return false; + return $session->username; } $path_split = explode('/', $path ); From adc44b0e39c07e0b6bdaecfb1cced7157d805ca5 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 20:45:54 +1300 Subject: [PATCH 070/189] Handle the null path case. --- inc/CalDAVRequest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index f858ac5d..ae86d4c6 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -130,6 +130,7 @@ class CalDAVRequest * the minimum privileges returned from that analysis. */ $this->path = $_SERVER['PATH_INFO']; + if ( $this->path == null || $this->path == '' ) $this->path = '/'; // dbg_error_log( "caldav", "Sanitising path '%s'", $this->path ); $bad_chars_regex = '/[\\^\\[\\(\\\\]/'; if ( preg_match( $bad_chars_regex, $this->path ) ) { From 10e02c5e76e64a67c0494c0eeac982252f437e8c Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 20:52:54 +1300 Subject: [PATCH 071/189] Add getUserByID and caching by ID. --- inc/always.php | 54 ++++++++++++++++++++++++++++++++++++----------- inc/always.php.in | 52 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 83 insertions(+), 23 deletions(-) diff --git a/inc/always.php b/inc/always.php index ea88f309..ec84dc08 100644 --- a/inc/always.php +++ b/inc/always.php @@ -51,12 +51,6 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS ), $_SERVER['SCRIPT_NAME'] ); -if ( count($c->dbg) > 0 ) { - // Only log this if debugging of some sort is turned on, somewhere - @dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", - $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); -} - init_gettext( 'rscds', '../locale' ); if ( file_exists("/etc/davical/".$_SERVER['SERVER_NAME']."-conf.php") ) { @@ -74,6 +68,12 @@ else { } if ( !isset($c->page_title) ) $c->page_title = $c->system_name; +if ( count($c->dbg) > 0 ) { + // Only log this if debugging of some sort is turned on, somewhere + @dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", + $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); +} + /** * Now that we have loaded the configuration file we can switch to a * default site locale. This may be overridden by each user. @@ -85,7 +85,7 @@ awl_set_locale($c->default_locale); * */ $c->code_version = 0; -$c->version_string = '0.9.1'; // The actual version # is replaced into that during the build /release process +$c->version_string = '0.9.1+iCal2'; // The actual version # is replaced into that during the build /release process if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) { $c->code_major = $matches[1]; $c->code_minor = $matches[2]; @@ -111,15 +111,45 @@ if ( $qry->Exec("always") && $row = $qry->Fetch() ) { $c->schema_patch = $row->schema_patch; } -$_known_users = array(); -function getUserByName( $username ) { + +$_known_users_name = array(); +$_known_users_id = array(); +/** +* Return a user record identified by a username, caching it for any subsequent lookup +* @param string $username The username of the record to retrieve +* @param boolean $use_cache Whether or not to use the cache (default: yes) +*/ +function getUserByName( $username, $use_cache = true ) { // Provide some basic caching in case this ends up being overused. - if ( isset( $_known_users[$username] ) ) return $_known_users[$username]; + if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username]; $qry = new PgQuery( "SELECT * FROM usr WHERE lower(username) = lower(?) ", $username ); if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) { - $_known_users[$username] = $qry->Fetch(); - return $_known_users[$username]; + $_known_users_name[$username] = $qry->Fetch(); + $id = $_known_users_name[$username]->user_no; + $_known_users_id[$id] = $_known_users_name[$username]; + return $_known_users_name[$username]; + } + + return false; +} + + +/** +* Return a user record identified by a user_no, caching it for any subsequent lookup +* @param int $user_no The ID of the record to retrieve +* @param boolean $use_cache Whether or not to use the cache (default: yes) +*/ +function getUserByID( $user_no, $use_cache = true ) { + // Provide some basic caching in case this ends up being overused. + if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no]; + + $qry = new PgQuery( "SELECT * FROM usr WHERE user_no = ? ", intval($user_no) ); + if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) { + $_known_users_id[$user_no] = $qry->Fetch(); + $name = $_known_users_id[$user_no]->username; + $_known_users_name[$name] = $_known_users_id[$user_no]; + return $_known_users_id[$user_no]; } return false; diff --git a/inc/always.php.in b/inc/always.php.in index 1ae708fd..75d207fd 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -51,12 +51,6 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS ), $_SERVER['SCRIPT_NAME'] ); -if ( count($c->dbg) > 0 ) { - // Only log this if debugging of some sort is turned on, somewhere - @dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", - $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); -} - init_gettext( 'rscds', '../locale' ); if ( file_exists("/etc/davical/".$_SERVER['SERVER_NAME']."-conf.php") ) { @@ -74,6 +68,12 @@ else { } if ( !isset($c->page_title) ) $c->page_title = $c->system_name; +if ( count($c->dbg) > 0 ) { + // Only log this if debugging of some sort is turned on, somewhere + @dbg_error_log( "LOG", "==========> method =%s= =%s= =%s= =%s= =%s=", + $_SERVER['REQUEST_METHOD'], $c->protocol_server_port_script, $_SERVER['PATH_INFO'], $c->base_url, $c->base_directory ); +} + /** * Now that we have loaded the configuration file we can switch to a * default site locale. This may be overridden by each user. @@ -111,15 +111,45 @@ if ( $qry->Exec("always") && $row = $qry->Fetch() ) { $c->schema_patch = $row->schema_patch; } -$_known_users = array(); -function getUserByName( $username ) { + +$_known_users_name = array(); +$_known_users_id = array(); +/** +* Return a user record identified by a username, caching it for any subsequent lookup +* @param string $username The username of the record to retrieve +* @param boolean $use_cache Whether or not to use the cache (default: yes) +*/ +function getUserByName( $username, $use_cache = true ) { // Provide some basic caching in case this ends up being overused. - if ( isset( $_known_users[$username] ) ) return $_known_users[$username]; + if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username]; $qry = new PgQuery( "SELECT * FROM usr WHERE lower(username) = lower(?) ", $username ); if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) { - $_known_users[$username] = $qry->Fetch(); - return $_known_users[$username]; + $_known_users_name[$username] = $qry->Fetch(); + $id = $_known_users_name[$username]->user_no; + $_known_users_id[$id] = $_known_users_name[$username]; + return $_known_users_name[$username]; + } + + return false; +} + + +/** +* Return a user record identified by a user_no, caching it for any subsequent lookup +* @param int $user_no The ID of the record to retrieve +* @param boolean $use_cache Whether or not to use the cache (default: yes) +*/ +function getUserByID( $user_no, $use_cache = true ) { + // Provide some basic caching in case this ends up being overused. + if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no]; + + $qry = new PgQuery( "SELECT * FROM usr WHERE user_no = ? ", intval($user_no) ); + if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows == 1 ) { + $_known_users_id[$user_no] = $qry->Fetch(); + $name = $_known_users_id[$user_no]->username; + $_known_users_name[$name] = $_known_users_id[$user_no]; + return $_known_users_id[$user_no]; } return false; From 87bff21fc8b6edff17c87cbcf45a37a6d93b26db Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 21:06:04 +1300 Subject: [PATCH 072/189] Fix these so they don't change continuously. --- testing/tests/regression-suite/826-Spec-PROPFIND.result | 2 +- testing/tests/regression-suite/826-Spec-PROPFIND.test | 1 + testing/tests/regression-suite/827-Spec-PROPFIND.result | 2 +- testing/tests/regression-suite/827-Spec-PROPFIND.test | 2 ++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/testing/tests/regression-suite/826-Spec-PROPFIND.result b/testing/tests/regression-suite/826-Spec-PROPFIND.result index 98e41252..fdb61901 100644 --- a/testing/tests/regression-suite/826-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/826-Spec-PROPFIND.result @@ -7,7 +7,7 @@ httpd/unix-directory - 20071103T201818 + YYYYMMDDThhmmss diff --git a/testing/tests/regression-suite/826-Spec-PROPFIND.test b/testing/tests/regression-suite/826-Spec-PROPFIND.test index 2ed3d626..ceaeff35 100644 --- a/testing/tests/regression-suite/826-Spec-PROPFIND.test +++ b/testing/tests/regression-suite/826-Spec-PROPFIND.test @@ -7,6 +7,7 @@ HEADER=User-Agent: RFC2518 Spec Tests HEADER=Depth: 0 HEADER=Content-Type: application/xml +REPLACE=#\d{8}T\d{6}#YYYYMMDDThhmmss# BEGINDATA diff --git a/testing/tests/regression-suite/827-Spec-PROPFIND.result b/testing/tests/regression-suite/827-Spec-PROPFIND.result index b1762b1c..f7bf1e0c 100644 --- a/testing/tests/regression-suite/827-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/827-Spec-PROPFIND.result @@ -7,7 +7,7 @@ httpd/unix-directory - 20071103T202330 + YYYYMMDDThhmmss diff --git a/testing/tests/regression-suite/827-Spec-PROPFIND.test b/testing/tests/regression-suite/827-Spec-PROPFIND.test index 8e78bf79..b1e0a61f 100644 --- a/testing/tests/regression-suite/827-Spec-PROPFIND.test +++ b/testing/tests/regression-suite/827-Spec-PROPFIND.test @@ -7,6 +7,8 @@ HEADER=User-Agent: RFC2518 Spec Tests HEADER=Depth: 1 HEADER=Content-Type: application/xml +REPLACE=#\d{8}T\d{6}#YYYYMMDDThhmmss# + BEGINDATA From 26a95698419c9850fafdeff3387e91695c0457ac Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 21:06:25 +1300 Subject: [PATCH 073/189] Current result. --- .../regression-suite/510-iCal-PROPFIND.result | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/testing/tests/regression-suite/510-iCal-PROPFIND.result b/testing/tests/regression-suite/510-iCal-PROPFIND.result index 7a4c8f18..c4be8816 100644 --- a/testing/tests/regression-suite/510-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/510-iCal-PROPFIND.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "d48322f182f679c3bdcf47af918de025" -Content-Length: 1022 +ETag: "defc8282f8eeeeee761e7cfd7bc2d363" +Content-Length: 920 Content-Type: text/xml; charset="utf-8" @@ -11,25 +11,21 @@ Content-Type: text/xml; charset="utf-8" /caldav.php/user1/home/ + home http://mycaldav/caldav.php/user1/ - - http://mycaldav/caldav.php/user1/.inbox/ - - - http://mycaldav/caldav.php/user1/.outbox/ - http://mycaldav/caldav.php/user1/ mailto:user1@example.net - home HTTP/1.1 200 OK + + From 1f57165ef840d527a8900404de21e71a08820093 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sat, 3 Nov 2007 21:13:05 +1300 Subject: [PATCH 074/189] Ignore built-po flagfile. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4108ca55..0460cc58 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build rscds.bfproject locale built-docs +built-po .settings *~ testing/*.stream From 568bd47b9ba26f8238d4e2e27f1b6a7af7a0e990 Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Sat, 3 Nov 2007 21:17:20 +1300 Subject: [PATCH 075/189] Modify the correct table. --- dba/patches/1.1.11.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dba/patches/1.1.11.sql b/dba/patches/1.1.11.sql index 60a55e55..1a6ad905 100644 --- a/dba/patches/1.1.11.sql +++ b/dba/patches/1.1.11.sql @@ -4,8 +4,8 @@ BEGIN; SELECT check_db_revision(1,1,10); -ALTER TABLE calendar_item DROP CONSTRAINT "$1"; -ALTER TABLE calendar_item ADD CONSTRAINT "$1" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; +ALTER TABLE caldav_data DROP CONSTRAINT "$1"; +ALTER TABLE caldav_data ADD CONSTRAINT "$1" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; ALTER TABLE collection DROP CONSTRAINT "$1"; ALTER TABLE collection ADD CONSTRAINT "$1" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; From c3943f3687773d442318a46e07d652019f0d178e Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 11:25:45 +1300 Subject: [PATCH 076/189] Slightly tweak the protocol_server_port to account for / --- inc/always.php | 4 +++- inc/always.php.in | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/inc/always.php b/inc/always.php index ec84dc08..4225ac4e 100644 --- a/inc/always.php +++ b/inc/always.php @@ -49,7 +49,9 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS ? '' : ':'.$_SERVER['SERVER_PORT'] ), - $_SERVER['SCRIPT_NAME'] ); + ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']) ); + +$c->protocol_server_port_script = ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']); init_gettext( 'rscds', '../locale' ); diff --git a/inc/always.php.in b/inc/always.php.in index 75d207fd..588a5fa8 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -49,7 +49,9 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS ? '' : ':'.$_SERVER['SERVER_PORT'] ), - $_SERVER['SCRIPT_NAME'] ); + ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']) ); + +$c->protocol_server_port_script = ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']); init_gettext( 'rscds', '../locale' ); From f84045e9cd1bd54a0c4ad48d231c9475d2beb61f Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 11:29:28 +1300 Subject: [PATCH 077/189] Tweak DAV header to admit that / is not as functional. --- htdocs/caldav.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/caldav.php b/htdocs/caldav.php index 5a82cd0a..cfe665cd 100644 --- a/htdocs/caldav.php +++ b/htdocs/caldav.php @@ -23,6 +23,7 @@ dbg_log_array( "headers", '_SERVER', $_SERVER, true ); * in all (or even much of) it's glory really. */ $dav = "1, 2, access-control, calendar-access"; +if ( $_SERVER['PATH_INFO'] == '/' || $_SERVER['PATH_INFO'] == '' ) $dav = "1, access-control"; header( "DAV: $dav"); // header( "DAV: 1, 2, access-control, calendar-access, calendar-schedule"); From f7a3bf6f8d672b74256efbae4f269154210525e6 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 11:30:25 +1300 Subject: [PATCH 078/189] Revert some of that last change. --- inc/always.php | 2 -- inc/always.php.in | 2 -- 2 files changed, 4 deletions(-) diff --git a/inc/always.php b/inc/always.php index 4225ac4e..7f3e0073 100644 --- a/inc/always.php +++ b/inc/always.php @@ -51,8 +51,6 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS ), ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']) ); -$c->protocol_server_port_script = ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']); - init_gettext( 'rscds', '../locale' ); if ( file_exists("/etc/davical/".$_SERVER['SERVER_NAME']."-conf.php") ) { diff --git a/inc/always.php.in b/inc/always.php.in index 588a5fa8..edab94fc 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -51,8 +51,6 @@ $c->protocol_server_port_script = sprintf( "%s://%s%s%s", (isset($_SERVER['HTTPS ), ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']) ); -$c->protocol_server_port_script = ($_SERVER['SCRIPT_NAME'] == '/index.php' ? '' : $_SERVER['SCRIPT_NAME']); - init_gettext( 'rscds', '../locale' ); if ( file_exists("/etc/davical/".$_SERVER['SERVER_NAME']."-conf.php") ) { From 541de9650a0e86c5c62c3a090d9d9c9a13bea323 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 12:13:58 +1300 Subject: [PATCH 079/189] Handle '/' as script path. Some commented changes reflect future plans. --- inc/CalDAVPrincipal.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/inc/CalDAVPrincipal.php b/inc/CalDAVPrincipal.php index 3034e30a..c5780984 100644 --- a/inc/CalDAVPrincipal.php +++ b/inc/CalDAVPrincipal.php @@ -99,10 +99,21 @@ class CalDAVPrincipal $this->{$k} = $v; } - $this->url = sprintf( "%s/~%d/", $c->protocol_server_port_script, $this->user_no); - $this->calendar_home_set = sprintf( "%s/%s/", $c->protocol_server_port_script, $this->username); - $this->schedule_inbox_url = sprintf( "%s.inbox/", $this->url); - $this->schedule_outbox_url = sprintf( "%s.outbox/", $this->url); + $script = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : ''); + $this->url = sprintf( "%s%s/%s/", $c->protocol_server_port_script, $script, $this->username); +// $this->url = sprintf( "%s%s/__uuids__/%s/", $c->protocol_server_port_script, $script, $this->username); + + $this->calendar_home_set = sprintf( "%s%s/%s/", $c->protocol_server_port_script, $script, $this->username); + + $this->user_address_set = array( + sprintf( "%s%s/%s/", $c->protocol_server_port_script, $script, $this->username), +// sprintf( "%s%s/~%s/", $c->protocol_server_port_script, $script, $this->username), +// sprintf( "%s%s/__uuids__/%s/", $c->protocol_server_port_script, $script, $this->username), + ); + $this->schedule_inbox_url = sprintf( "%s.in/", $this->calendar_home_set); + $this->schedule_outbox_url = sprintf( "%s.out/", $this->calendar_home_set); + $this->dropbox_url = sprintf( "%s.drop/", $this->calendar_home_set); + $this->notifications_url = sprintf( "%s.notify/", $this->calendar_home_set); dbg_error_log( "principal", "User: %s (%d) URL: %s, Home: %s, By Email: %d", $this->username, $this->user_no, $this->url, $this->calendar_home_set, $this->by_email ); } @@ -125,10 +136,10 @@ class CalDAVPrincipal @dbg_error_log( "principal", "Path split into at least /// %s /// %s /// %s", $path_split[1], $path_split[2], $path_split[3] ); if ( substr($path,0,1) == '~' ) { - // URL is for a principal, by ID - $user_no = intval(substr($path,1)); - $user = getUserByID($user_no); - $username = $user->username; + // URL is for a principal, by name + $username = substr($path_split[1],1); + $user = getUserByID($username); + $user_no = $user->user_no; } else { $username = $path_split[1]; From 4d0dc4fe781721ef6f9d0e4b226412dabcb8f130 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 12:14:26 +1300 Subject: [PATCH 080/189] Add the user-agent string into the request object. --- inc/CalDAVRequest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index ae86d4c6..40707d87 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -28,6 +28,16 @@ class CalDAVRequest { var $options; + /** + * The raw data sent along with the request + */ + var $raw_post; + + /** + * The HTTP request method: PROPFIND, LOCK, REPORT, OPTIONS, etc... + */ + var $method; + /** * The depth parameter from the request headers, coerced into a valid integer: 0, 1 * or DEPTH_INFINITY which is defined above. The default is set per various RFCs. @@ -39,6 +49,11 @@ class CalDAVRequest */ var $principal; + /** + * The user agent making the request. + */ + var $user_agent; + /** * Create a new CalDAVRequest object. */ @@ -55,6 +70,8 @@ class CalDAVRequest } $this->method = $_SERVER['REQUEST_METHOD']; + $this->user_agent = ((isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "Probably Mulberry")); + /** * A variety of requests may set the "Depth" header to control recursion */ From 1436dbc88eac0b92280e4763d9c22a9ce92edad8 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 12:39:22 +1300 Subject: [PATCH 081/189] Now works with iCal 3.0. Most notably because we replace ' ' with '_' in the response to requests for the displayname property. --- inc/caldav-PROPFIND.php | 96 +++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 13 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index f955708e..027da6a3 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -22,6 +22,18 @@ $attribute_list = array(); $unsupported = array(); $arbitrary = array(); +$namespaces = array( "xmlns" => "DAV:" ); + +function add_namespace( $prefix, $namespace ) { + global $namespaces; + + $prefix = 'xmlns:'.$prefix; + if ( !isset($namespaces[$prefix]) || $namespaces[$prefix] != $namespace ) { + $namespaces[$prefix] = $namespace; + } +} + + foreach( $request->xml_tags AS $k => $v ) { $ns_tag = $v['tag']; @@ -65,6 +77,11 @@ foreach( $request->xml_tags AS $k => $v ) { case 'SUPPORTED-PRIVILEGE-SET': /** supported-privilege-set - should work fine */ case 'CURRENT-USER-PRIVILEGE-SET': /** current-user-privilege-set - only vaguely supported */ case 'ALLPROP': /** allprop - limited support */ + $attribute_list[$tag] = 1; + dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag ); + break; + + /** * Handled CalDAV properties @@ -79,8 +96,16 @@ foreach( $request->xml_tags AS $k => $v ) { case 'CALENDAR-USER-ADDRESS-SET': /** CalDAV+s: slightly supported */ // case 'SCHEDULE-INBOX-URL': /** CalDAV+s: not supported */ // case 'SCHEDULE-OUTBOX-URL': /** CalDAV+s: not supported */ - $attribute_list[$tag] = 1; - dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag ); +// case 'DROPBOX-HOME-URL': // HTTP://CALENDARSERVER.ORG/NS/ +// case 'NOTIFICATIONS-URL': // HTTP://CALENDARSERVER.ORG/NS/ + if ( $_SERVER['PATH_INFO'] == '/' || $_SERVER['PATH_INFO'] == '' ) { + $arbitrary[$ns_tag] = $ns_tag; + dbg_error_log( "PROPFIND", "Adding arbitrary DAV property '%s'", $ns_tag ); + } + else { + $attribute_list[$tag] = 1; + dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag ); + } break; @@ -96,8 +121,6 @@ foreach( $request->xml_tags AS $k => $v ) { // case 'SOURCE': // DAV: // case 'LOCKDISCOVERY': // DAV: // case 'EXECUTABLE': // HTTP://APACHE.ORG/DAV/PROPS/ -// case 'DROPBOX-HOME-URL': // HTTP://CALENDARSERVER.ORG/NS/ -// case 'NOTIFICATIONS-URL': // HTTP://CALENDARSERVER.ORG/NS/ /** These are ignored specifically */ break; @@ -162,7 +185,7 @@ function get_arbitrary_properties($dav_name) { /** * Handles any properties related to the DAV::PRINCIPAL in the request */ -function add_principal_properties( &$prop ) { +function add_principal_properties( &$prop, &$not_found, &$denied ) { global $attribute_list, $session, $c, $request; if ( isset($attribute_list['PRINCIPAL-URL'] ) ) { @@ -170,16 +193,29 @@ function add_principal_properties( &$prop ) { } if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) { + add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $prop->NewElement("C:calendar-home-set", new XMLElement('href', $request->principal->calendar_home_set ) ); } if ( isset($attribute_list['SCHEDULE-INBOX-URL'] ) ) { + add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $prop->NewElement("C:schedule-inbox-url", new XMLElement('href', $request->principal->schedule_inbox_url) ); } if ( isset($attribute_list['SCHEDULE-OUTBOX-URL'] ) ) { + add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $prop->NewElement("C:schedule-outbox-url", new XMLElement('href', $request->principal->schedule_outbox_url) ); } + if ( isset($attribute_list['DROPBOX-HOME-URL'] ) ) { + add_namespace("A", "http://calendarserver.org/ns/"); + $prop->NewElement("A:dropbox-home-url", new XMLElement('href', $request->principal->dropbox_url) ); + } + if ( isset($attribute_list['NOTIFICATIONS-URL'] ) ) { + add_namespace("A", "http://calendarserver.org/ns/"); + $prop->NewElement("A:notifications-url", new XMLElement('href', $request->principal->notifications_url) ); + } + if ( isset($attribute_list['CALENDAR-USER-ADDRESS-SET'] ) ) { + add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $email = new XMLElement('href', 'mailto:'.$request->principal->email ); $calendar = new XMLElement('href', $request->principal->calendar_home_set ); $prop->NewElement("C:calendar-user-address-set", array( $calendar, $email) ); @@ -198,13 +234,13 @@ function collection_to_xml( $collection ) { $arbitrary_results = get_arbitrary_properties($collection->dav_name); $collection->properties = $arbitrary_results->found; - $url = $_SERVER['SCRIPT_NAME']; - if ( $url == '/index.php' ) $url = '/caldav.php'; - $url .= $collection->dav_name; + $url = $c->protocol_server_port_script . $collection->dav_name; + $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' $resourcetypes = array( new XMLElement("collection") ); $contentlength = false; if ( $collection->is_calendar == 't' ) { + add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $resourcetypes[] = new XMLElement("C:calendar", false); $lqry = new PgQuery("SELECT sum(length(caldav_data)) FROM caldav_data WHERE user_no = ? AND dav_name ~ ?;", $collection->user_no, $collection->dav_name.'[^/]+$' ); if ( $lqry->Exec("PROPFIND",__LINE__,__FILE__) && $row = $lqry->Fetch() ) { @@ -215,17 +251,21 @@ function collection_to_xml( $collection ) { $resourcetypes[] = new XMLElement("principal"); } $prop = new XMLElement("prop"); + $not_found = new XMLElement("prop"); + $denied = new XMLElement("prop"); /** * First process any static values we do support */ if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-COLLATION-SET']) ) { + add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $collations = array(); $collations[] = new XMLElement("C:supported-collation", 'i;ascii-casemap'); $collations[] = new XMLElement("C:supported-collation", 'i;octet'); $prop->NewElement("C:supported-collation-set", $collations ); } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-CALENDAR-COMPONENT-SET']) ) { + add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $components = array(); $components[] = new XMLElement("C:comp", '', array("name" => "VEVENT")); $components[] = new XMLElement("C:comp", '', array("name" => "VTODO")); @@ -252,6 +292,10 @@ function collection_to_xml( $collection ) { } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['DISPLAYNAME']) ) { $displayname = ( $collection->dav_displayname == "" ? ucfirst(trim(str_replace("/"," ", $collection->dav_name))) : $collection->dav_displayname ); + if ( preg_match( '/ iCal 3\.0/', $request->user_agent ) ) { + /** FIXME: There is a bug in iCal 3 which disables calendars with a displayname containing spaces */ + $displayname = str_replace( ' ', '_', $displayname ); + } $prop->NewElement("displayname", $displayname ); } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETETAG']) ) { @@ -261,10 +305,28 @@ function collection_to_xml( $collection ) { $prop->NewElement("current-user-privilege-set", privileges($request->permissions) ); } + if ( isset($attribute_list['CALENDAR-FREE-BUSY-SET'] ) ) { + add_namespace("C", "urn:ietf:params:xml:ns:caldav"); + if ( isset($collection->is_inbox) && $collection->is_inbox && $session->user_no == $collection->user_no ) { + $fb_set = array(); + foreach( $collection->free_busy_set AS $k => $v ) { + $fb_set[] = new XMLElement('href', $v ); + } + $prop->NewElement("C:calendar-free-busy-set", $fb_set ); + } + else if ( $session->user_no == $collection->user_no ) { + $not_found->NewElement("C:calendar-free-busy-set" ); + } + else { + $denied->NewElement("C:calendar-free-busy-set" ); + } + } + + /** * Then look at any properties related to the principal */ - add_principal_properties( $prop ); + add_principal_properties( $prop, $not_found, $denied ); if ( count($collection->properties) > 0 ) { foreach( $collection->properties AS $k => $v ) { @@ -308,7 +370,6 @@ function collection_to_xml( $collection ) { $response = array($href,$propstat); if ( count($arbitrary_results->missing) > 0 ) { - $missing = new XMLElement("prop"); foreach( $arbitrary_results->missing AS $k => $v ) { if ( preg_match('/^(.*):([^:]+)$/', $k, $matches) ) { $namespace = $matches[1]; @@ -318,10 +379,19 @@ function collection_to_xml( $collection ) { $namespace = ""; $tag = $k; } - $missing->NewElement(strtolower($tag), '', array("xmlns" => strtolower($namespace)) ); + $not_found->NewElement(strtolower($tag), '', array("xmlns" => strtolower($namespace)) ); } + } + + if ( count($not_found->content) > 0 ) { $status = new XMLElement("status", "HTTP/1.1 404 Not Found" ); - $propstat = new XMLElement( "propstat", array( $missing, $status) ); + $propstat = new XMLElement( "propstat", array( $not_found, $status) ); + $response[] = $propstat; + } + + if ( count($denied->content) > 0 ) { + $status = new XMLElement("status", "HTTP/1.1 403 Forbidden" ); + $propstat = new XMLElement( "propstat", array( $denied, $status) ); $response[] = $propstat; } @@ -573,7 +643,7 @@ else { $request->DoResponse( 403, translate("You do not have appropriate rights to view that resource.") ); } -$multistatus = new XMLElement( "multistatus", $responses, array('xmlns'=>'DAV:', "xmlns:C" => "urn:ietf:params:xml:ns:caldav") ); +$multistatus = new XMLElement( "multistatus", $responses, $namespaces ); // dbg_log_array( "PROPFIND", "XML", $multistatus, true ); $xmldoc = $multistatus->Render(0,''); From ee43bf9b9b6f254752dcc3db3f6a20ea81414f24 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 13:28:13 +1300 Subject: [PATCH 082/189] Add not_found / denied to item response. --- inc/caldav-PROPFIND.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 027da6a3..8f0db966 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -413,6 +413,10 @@ function item_to_xml( $item ) { $url = $_SERVER['SCRIPT_NAME'] . $item->dav_name; $prop = new XMLElement("prop"); + $not_found = new XMLElement("prop"); + $denied = new XMLElement("prop"); + + if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETLASTMODIFIED']) ) { $prop->NewElement("getlastmodified", ( isset($item->modified)? $item->modified : false )); } @@ -442,7 +446,7 @@ function item_to_xml( $item ) { /** * Then look at any properties related to the principal */ - add_principal_properties( $prop ); + add_principal_properties( $prop, $not_found, $denied ); if ( isset($attribute_list['ACL']) ) { /** @@ -476,8 +480,21 @@ function item_to_xml( $item ) { $propstat = new XMLElement( "propstat", array( $prop, $status) ); $href = new XMLElement("href", $url ); + $response = array($href,$propstat); - $response = new XMLElement( "response", array($href,$propstat)); + if ( count($not_found->content) > 0 ) { + $status = new XMLElement("status", "HTTP/1.1 404 Not Found" ); + $propstat = new XMLElement( "propstat", array( $not_found, $status) ); + $response[] = $propstat; + } + + if ( count($denied->content) > 0 ) { + $status = new XMLElement("status", "HTTP/1.1 403 Forbidden" ); + $propstat = new XMLElement( "propstat", array( $denied, $status) ); + $response[] = $propstat; + } + + $response = new XMLElement( "response", $response ); return $response; } From bdc9c1a8751c58d018c900b9b7a543393bba904a Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 13:48:56 +1300 Subject: [PATCH 083/189] Restrict the OPTIONS response on the root. --- inc/caldav-OPTIONS.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/inc/caldav-OPTIONS.php b/inc/caldav-OPTIONS.php index 2f1197ea..3c136714 100644 --- a/inc/caldav-OPTIONS.php +++ b/inc/caldav-OPTIONS.php @@ -11,7 +11,7 @@ dbg_error_log("OPTIONS", "method handler"); if ( ! $request->AllowedTo('read') ) { - $request->DoResponse( 403, translate("You may not access that calendar") ); + $request->DoResponse( 403, translate("You may not access that collection") ); } $exists = false; @@ -55,6 +55,10 @@ if ( isset($c->override_allowed_methods) ) $allowed = $c->override_allowed_methods; else { $allowed = "OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH"; + if ( $request->path == '/' ) { + $exists = true; + $allowed = "OPTIONS, GET, HEAD, PROPFIND, REPORT"; + } } header( "Allow: $allowed"); From 2e64a4fc8e61398c3b901fdc3876ccf388de6496 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 13:49:22 +1300 Subject: [PATCH 084/189] Tidy up the response. --- inc/caldav-PROPFIND.php | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 8f0db966..cb86923e 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -383,16 +383,12 @@ function collection_to_xml( $collection ) { } } - if ( count($not_found->content) > 0 ) { - $status = new XMLElement("status", "HTTP/1.1 404 Not Found" ); - $propstat = new XMLElement( "propstat", array( $not_found, $status) ); - $response[] = $propstat; + if ( is_array($not_found->content) && count($not_found->content) > 0 ) { + $response[] = new XMLElement( "propstat", array( $not_found, new XMLElement("status", "HTTP/1.1 404 Not Found" )) ); } - if ( count($denied->content) > 0 ) { - $status = new XMLElement("status", "HTTP/1.1 403 Forbidden" ); - $propstat = new XMLElement( "propstat", array( $denied, $status) ); - $response[] = $propstat; + if ( is_array($denied->content) && count($denied->content) > 0 ) { + $response[] = new XMLElement( "propstat", array( $denied, new XMLElement("status", "HTTP/1.1 403 Forbidden" )) ); } $response = new XMLElement( "response", $response ); @@ -482,16 +478,12 @@ function item_to_xml( $item ) { $href = new XMLElement("href", $url ); $response = array($href,$propstat); - if ( count($not_found->content) > 0 ) { - $status = new XMLElement("status", "HTTP/1.1 404 Not Found" ); - $propstat = new XMLElement( "propstat", array( $not_found, $status) ); - $response[] = $propstat; + if ( is_array($not_found->content) && count($not_found->content) > 0 ) { + $response[] = new XMLElement( "propstat", array( $not_found, new XMLElement("status", "HTTP/1.1 404 Not Found" )) ); } - if ( count($denied->content) > 0 ) { - $status = new XMLElement("status", "HTTP/1.1 403 Forbidden" ); - $propstat = new XMLElement( "propstat", array( $denied, $status) ); - $response[] = $propstat; + if ( is_array($denied->content) && count($denied->content) > 0 ) { + $response[] = new XMLElement( "propstat", array( $denied, new XMLElement("status", "HTTP/1.1 403 Forbidden" )) ); } $response = new XMLElement( "response", $response ); From bfa9dd89431c6ed383d735ccd04539fed6c5adf0 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 13:52:40 +1300 Subject: [PATCH 085/189] Regression tests after cleanup. --- .../regression-suite/001-Mulberry-1.result | 4 +- .../regression-suite/002-Mulberry-1.result | 20 ++++---- .../regression-suite/003-Mulberry-1.result | 8 +-- .../regression-suite/005-Mulberry-1.result | 8 +-- .../regression-suite/006-Mulberry-1.result | 6 +-- .../013-Mulberry-PROPFIND-5.result | 6 +-- .../015-Mulberry-PROPFIND-6.result | 6 +-- .../205-Moz-PROPFIND-1.result | 6 +-- .../regression-suite/212-Moz-PROPFIND.result | 6 +-- .../303-Chandler-PROPFIND-1.result | 6 +-- .../304-Chandler-PROPFIND-2.result | 6 +-- .../309-Chandler-PROPFIND-3.result | 6 +-- .../309-Chandler-PROPFIND-4.result | 6 +-- .../401-Cadaver-PROPFIND-1.result | 2 +- .../regression-suite/510-iCal-PROPFIND.result | 6 +-- .../820-Spec-PROPFIND-1.result | 2 +- .../821-Spec-PROPFIND-2.result | 4 +- .../822-Spec-PROPFIND-3.result | 2 +- .../823-Spec-PROPFIND-4.result | 2 +- .../824-Spec-PROPFIND-5.result | 2 +- .../825-Spec-PROPFIND-6.result | 2 +- .../regression-suite/826-Spec-PROPFIND.result | 4 +- .../regression-suite/827-Spec-PROPFIND.result | 14 +++--- .../regression-suite/831-Spec-RRULE-1.result | 2 +- .../regression-suite/843-Spec-PROPFIND.result | 2 +- .../860-Spec-REPORT-principal.result | 2 +- .../861-Spec-REPORT-principal.result | 2 +- .../862-Spec-REPORT-principal.result | 2 +- .../863-Spec-REPORT-principal.result | 2 +- .../870-Principal-PROPFIND.result | 50 +++++++++++++++++++ 30 files changed, 123 insertions(+), 73 deletions(-) create mode 100644 testing/tests/regression-suite/870-Principal-PROPFIND.result diff --git a/testing/tests/regression-suite/001-Mulberry-1.result b/testing/tests/regression-suite/001-Mulberry-1.result index b8f2be75..1e55920e 100644 --- a/testing/tests/regression-suite/001-Mulberry-1.result +++ b/testing/tests/regression-suite/001-Mulberry-1.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, 2, access-control, calendar-access -Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH +DAV: 1, access-control +Allow: OPTIONS, GET, HEAD, PROPFIND, REPORT Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/002-Mulberry-1.result b/testing/tests/regression-suite/002-Mulberry-1.result index 4eed464e..e0186618 100644 --- a/testing/tests/regression-suite/002-Mulberry-1.result +++ b/testing/tests/regression-suite/002-Mulberry-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, 2, access-control, calendar-access -ETag: "e4c5d91096060db78286e699730987a1" -Content-Length: 1920 +DAV: 1, access-control +ETag: "4f1f49d6e908f8ccfab25f51d1e08658" +Content-Length: 1970 Content-Type: text/xml; charset="utf-8" - + - /caldav.php/ + http://mycaldav/caldav.php/ httpd/unix-directory @@ -21,7 +21,7 @@ Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/ + http://mycaldav/caldav.php/user1/ httpd/unix-directory @@ -35,7 +35,7 @@ Content-Type: text/xml; charset="utf-8" - /caldav.php/manager1/ + http://mycaldav/caldav.php/manager1/ httpd/unix-directory @@ -49,7 +49,7 @@ Content-Type: text/xml; charset="utf-8" - /caldav.php/assistant1/ + http://mycaldav/caldav.php/assistant1/ httpd/unix-directory @@ -63,7 +63,7 @@ Content-Type: text/xml; charset="utf-8" - /caldav.php/resource1/ + http://mycaldav/caldav.php/resource1/ httpd/unix-directory @@ -77,7 +77,7 @@ Content-Type: text/xml; charset="utf-8" - /caldav.php/resource2/ + http://mycaldav/caldav.php/resource2/ httpd/unix-directory diff --git a/testing/tests/regression-suite/003-Mulberry-1.result b/testing/tests/regression-suite/003-Mulberry-1.result index dbc49d44..d9b7bc67 100644 --- a/testing/tests/regression-suite/003-Mulberry-1.result +++ b/testing/tests/regression-suite/003-Mulberry-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "792db2309cf4d54e7c00bbe79633895f" -Content-Length: 423 +ETag: "030f42bd67ae4aa29812c0832f5b8dec" +Content-Length: 398 Content-Type: text/xml; charset="utf-8" - + - /caldav.php/user1/ + http://mycaldav/caldav.php/user1/ httpd/unix-directory diff --git a/testing/tests/regression-suite/005-Mulberry-1.result b/testing/tests/regression-suite/005-Mulberry-1.result index 09b6e087..14c6953c 100644 --- a/testing/tests/regression-suite/005-Mulberry-1.result +++ b/testing/tests/regression-suite/005-Mulberry-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "a30e9b8f2662cd1da17252d3b814ef04" -Content-Length: 730 +ETag: "91534cf7117a7c119621ca3478b3b5af" +Content-Length: 760 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/ + http://mycaldav/caldav.php/user1/ httpd/unix-directory @@ -22,7 +22,7 @@ Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ httpd/unix-directory diff --git a/testing/tests/regression-suite/006-Mulberry-1.result b/testing/tests/regression-suite/006-Mulberry-1.result index d8cee0d6..33fbacfb 100644 --- a/testing/tests/regression-suite/006-Mulberry-1.result +++ b/testing/tests/regression-suite/006-Mulberry-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "7364b32495feb0c9bbe89cdb10988762" -Content-Length: 487 +ETag: "b935ebb71cd3bdebd81cfd488af4e5b0" +Content-Length: 502 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ httpd/unix-directory diff --git a/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result b/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result index a3dd940f..a06a4254 100644 --- a/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result +++ b/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "4cd4df7d08592927b92bcd697c2cdde7" -Content-Length: 1055 +ETag: "68e726f3b90f86125c6db18f5c650c54" +Content-Length: 1070 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ httpd/unix-directory diff --git a/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result b/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result index 44ab7700..9f02d457 100644 --- a/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result +++ b/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "d880baf3102a9de9bcea4d5f71a6b500" -Content-Length: 1055 +ETag: "9ce94a065308bb6bc3773f42449e7d6e" +Content-Length: 1070 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ httpd/unix-directory diff --git a/testing/tests/regression-suite/205-Moz-PROPFIND-1.result b/testing/tests/regression-suite/205-Moz-PROPFIND-1.result index 61354633..a2dbda7e 100644 --- a/testing/tests/regression-suite/205-Moz-PROPFIND-1.result +++ b/testing/tests/regression-suite/205-Moz-PROPFIND-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "334c8abc0ac73261cdbf963fc7269d76" -Content-Length: 347 +ETag: "cbf8e26e7db5a736eceeb48a8f68d904" +Content-Length: 362 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ diff --git a/testing/tests/regression-suite/212-Moz-PROPFIND.result b/testing/tests/regression-suite/212-Moz-PROPFIND.result index 6b8b8031..f50fbc0b 100644 --- a/testing/tests/regression-suite/212-Moz-PROPFIND.result +++ b/testing/tests/regression-suite/212-Moz-PROPFIND.result @@ -2,14 +2,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access Content-Location: /user1/home/ -ETag: "334c8abc0ac73261cdbf963fc7269d76" -Content-Length: 347 +ETag: "cbf8e26e7db5a736eceeb48a8f68d904" +Content-Length: 362 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ diff --git a/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result b/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result index 0d775c90..70f468c2 100644 --- a/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result +++ b/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "de5751155d5d8961c7fc9d38a690dd49" -Content-Length: 441 +ETag: "0dbbced4495f8f4044dca46fa1f317c0" +Content-Length: 456 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ diff --git a/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result b/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result index 526427b6..b2edaab8 100644 --- a/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result +++ b/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "5c2a97317978ca314ada6490cbebcc81" -Content-Length: 556 +ETag: "013e6851fdb2514eeac2122003786bcf" +Content-Length: 571 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ diff --git a/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result b/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result index 97451c46..8a26ddb6 100644 --- a/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result +++ b/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "2d33f4ae017a778547da61069d95e18f" -Content-Length: 469 +ETag: "8a45ca8db6ae342a1d059fb36865acea" +Content-Length: 484 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/.chandler/ + http://mycaldav/caldav.php/user1/home/.chandler/ diff --git a/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result b/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result index c4513138..76f776bc 100644 --- a/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result +++ b/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "f678e2f00e4582d963162b293e1e8ecb" -Content-Length: 3609 +ETag: "430439801bf82c7330f37c63382a5294" +Content-Length: 3624 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ diff --git a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result index 1d5e2f8b..8a43ce96 100644 --- a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result +++ b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result @@ -1,7 +1,7 @@ - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ Dow, 01 Jan 2000 00:00:00 GMT diff --git a/testing/tests/regression-suite/510-iCal-PROPFIND.result b/testing/tests/regression-suite/510-iCal-PROPFIND.result index c4be8816..e20d86f1 100644 --- a/testing/tests/regression-suite/510-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/510-iCal-PROPFIND.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "defc8282f8eeeeee761e7cfd7bc2d363" -Content-Length: 920 +ETag: "33567ed4d798b9c5ea389d70ed845ae9" +Content-Length: 935 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ home diff --git a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result index 68fa8512..963cdd0e 100644 --- a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result +++ b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result @@ -1,7 +1,7 @@ - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ httpd/unix-directory diff --git a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result index 50032b87..92c49000 100644 --- a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result +++ b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result @@ -2,13 +2,13 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access ETag: "deadbeefcafefeeddeadbeefcafefeed" -Content-Length: 1204 +Content-Length: 1219 Content-Type: text/xml; charset="utf-8" - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ httpd/unix-directory diff --git a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result index a1acd006..1e021b20 100644 --- a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result +++ b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result @@ -1,7 +1,7 @@ - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ httpd/unix-directory diff --git a/testing/tests/regression-suite/823-Spec-PROPFIND-4.result b/testing/tests/regression-suite/823-Spec-PROPFIND-4.result index 013d78e8..7683f515 100644 --- a/testing/tests/regression-suite/823-Spec-PROPFIND-4.result +++ b/testing/tests/regression-suite/823-Spec-PROPFIND-4.result @@ -1,5 +1,5 @@ - + /caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics diff --git a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result index 010089e7..36d01e86 100644 --- a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result +++ b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result @@ -1,7 +1,7 @@ - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ diff --git a/testing/tests/regression-suite/825-Spec-PROPFIND-6.result b/testing/tests/regression-suite/825-Spec-PROPFIND-6.result index 6e2f02d6..2f2a7489 100644 --- a/testing/tests/regression-suite/825-Spec-PROPFIND-6.result +++ b/testing/tests/regression-suite/825-Spec-PROPFIND-6.result @@ -1,5 +1,5 @@ - + /caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics diff --git a/testing/tests/regression-suite/826-Spec-PROPFIND.result b/testing/tests/regression-suite/826-Spec-PROPFIND.result index fdb61901..b82c988d 100644 --- a/testing/tests/regression-suite/826-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/826-Spec-PROPFIND.result @@ -1,7 +1,7 @@ - + - /caldav.php/ + http://mycaldav/ httpd/unix-directory diff --git a/testing/tests/regression-suite/827-Spec-PROPFIND.result b/testing/tests/regression-suite/827-Spec-PROPFIND.result index f7bf1e0c..7bb50089 100644 --- a/testing/tests/regression-suite/827-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/827-Spec-PROPFIND.result @@ -1,7 +1,7 @@ - + - /caldav.php/ + http://mycaldav/ httpd/unix-directory @@ -47,7 +47,7 @@ - /caldav.php/user1/ + http://mycaldav/user1/ httpd/unix-directory @@ -94,7 +94,7 @@ - /caldav.php/manager1/ + http://mycaldav/manager1/ httpd/unix-directory @@ -141,7 +141,7 @@ - /caldav.php/assistant1/ + http://mycaldav/assistant1/ httpd/unix-directory @@ -188,7 +188,7 @@ - /caldav.php/resource1/ + http://mycaldav/resource1/ httpd/unix-directory @@ -235,7 +235,7 @@ - /caldav.php/resource2/ + http://mycaldav/resource2/ httpd/unix-directory diff --git a/testing/tests/regression-suite/831-Spec-RRULE-1.result b/testing/tests/regression-suite/831-Spec-RRULE-1.result index da710c29..9662ed55 100644 --- a/testing/tests/regression-suite/831-Spec-RRULE-1.result +++ b/testing/tests/regression-suite/831-Spec-RRULE-1.result @@ -1,6 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, 2, access-control, calendar-access +DAV: 1, access-control Content-Length: 5020 Content-Type: text/plain diff --git a/testing/tests/regression-suite/843-Spec-PROPFIND.result b/testing/tests/regression-suite/843-Spec-PROPFIND.result index c9a1dd68..881a0ca6 100644 --- a/testing/tests/regression-suite/843-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/843-Spec-PROPFIND.result @@ -1,7 +1,7 @@ - /caldav.php/user1/home/ + http://mycaldav/caldav.php/user1/home/ User One's Calendar diff --git a/testing/tests/regression-suite/860-Spec-REPORT-principal.result b/testing/tests/regression-suite/860-Spec-REPORT-principal.result index adb16f6d..a0de0bfb 100644 --- a/testing/tests/regression-suite/860-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/860-Spec-REPORT-principal.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, 2, access-control, calendar-access +DAV: 1, access-control ETag: "c345629a9689adce5411818c3c29aa43" Content-Length: 358 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/861-Spec-REPORT-principal.result b/testing/tests/regression-suite/861-Spec-REPORT-principal.result index 7b9526f7..7ba2e2f1 100644 --- a/testing/tests/regression-suite/861-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/861-Spec-REPORT-principal.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, 2, access-control, calendar-access +DAV: 1, access-control ETag: "8ee6bd9a1b7e15f40e6e24f149c6bf20" Content-Length: 3720 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/862-Spec-REPORT-principal.result b/testing/tests/regression-suite/862-Spec-REPORT-principal.result index c55a5655..de8c2367 100644 --- a/testing/tests/regression-suite/862-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/862-Spec-REPORT-principal.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, 2, access-control, calendar-access +DAV: 1, access-control ETag: "d8fe1f4720e6249cb2fb0711fbed9794" Content-Length: 688 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/863-Spec-REPORT-principal.result b/testing/tests/regression-suite/863-Spec-REPORT-principal.result index 7b38fea1..db2ad115 100644 --- a/testing/tests/regression-suite/863-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/863-Spec-REPORT-principal.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, 2, access-control, calendar-access +DAV: 1, access-control ETag: "f9a0b07b2c7b0347a9ae26a412baef6b" Content-Length: 743 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/870-Principal-PROPFIND.result b/testing/tests/regression-suite/870-Principal-PROPFIND.result new file mode 100644 index 00000000..68f6c38b --- /dev/null +++ b/testing/tests/regression-suite/870-Principal-PROPFIND.result @@ -0,0 +1,50 @@ + + + + http://mycaldav/user1/ + + + httpd/unix-directory + Dow, 01 Jan 2000 00:00:00 GMT + + Dow, 01 Jan 2000 00:00:00 GMT + + + + + User 1 + "7d0fd5137942261bee17da4287f71494" + + + + + + + + + + en_NZ.UTF-8 + + + + + + + + + + + + HTTP/1.1 200 OK + + + + + + + + + HTTP/1.1 404 Not Found + + + From d5de171ccd8bfdf0ebfb5b6e661b9171a67dc488 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 13:53:44 +1300 Subject: [PATCH 086/189] Utility for sniffing traffic and displaying it as a plain stream. --- testing/sniffstream | 131 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100755 testing/sniffstream diff --git a/testing/sniffstream b/testing/sniffstream new file mode 100755 index 00000000..247bbd58 --- /dev/null +++ b/testing/sniffstream @@ -0,0 +1,131 @@ +#!/usr/bin/perl -w +# +# Sniff traffic and format as a stream of packet contents +# +use strict; + +use Getopt::Long qw(:config permute); # allow mixed args. + +# Options variables +my $debug = 0; +my $saveto; +my $readfrom; +my $interface = 'any'; +my $dumpspec = 'tcp port 80'; +my $helpmeplease = 0; + +GetOptions ('debug!' => \$debug, + 'write=s' => \$saveto, + 'file=s' => \$readfrom, + 'interface=s' => \$interface, + 'dumpspec=s' => \$dumpspec, + 'help' => \$helpmeplease ); + +usage() if ( $helpmeplease ); + +if ( defined($saveto) ) { + open( SAVETO, '>>', $saveto ) or die "Couldn't save to '$saveto'"; +} + +if ( defined($readfrom) ) { + if ( $readfrom ne '-' ) { + open( STDIN, '<', $readfrom ) or die "Couldn't open '$readfrom'"; + } +} +else { + my @tcpdumpoptions = ('-i', $interface, '-s0', '-l', '-xx', '-n', '-q', $dumpspec ); + open( STDIN, '-|', "tcpdump", @tcpdumpoptions ) or die "Couldn't start tcpdump process"; +} + +my $timestamp; +my $source = ''; +my $dest = ''; +my $lastsource = ''; +my $lastdest = ''; +my $show; +my $packet; +my $stream; + +while( ) { + $show = 0; + if ( /^([012]\d:[0-5]\d:[0-5]\d\.\d{6})\sIP\s([0-9.:]+)\s>\s([0-9.:]+):\ tcp/ ) { + $timestamp = $1; + $source = $2; + $dest = $3; + } + elsif ( /^\s+(0x....):\s(( [0-9a-f]{4}){1,8})/ ) { + my $pos = hex($1); + my $hex = $2; + + if ( $pos == 64 ) { + $hex = substr( $hex, 10 ); + $pos += 4; + } + + if ( $pos >= 68 ) { + my @hex = split /\s+/, $hex; + my $ascii = ""; + foreach my $xch ( @hex ) { + next if ( $xch eq '' ); + $ascii .= chr(hex(substr($xch,0,2))); + $ascii .= chr(hex(substr($xch,2,2))); + } + $show = 1; + $_ = $ascii; + } + } + elsif ( /^\.\./ ) { + s/^\.\.......//; + $show = 1; + } + else { + $show = 1; + } + + if ( $show ) { + if ( $source ne $lastsource || $dest ne $lastdest ) { + putline( "\n\n=============== $timestamp $source ==> $dest\n" ); + $lastsource = $source; + $lastdest = $dest; + } + putline( $_ ); + } +} + + + + +########################################################### +sub putline { + my $line = shift; + print $line; + print SAVETO $line if ( defined($saveto) ); +} + + +########################################################### +sub usage { + print < Append the stream to the named file. + --file (-|) Format the input from the named file, or stdin. + --interface Run tcpdump against the specified interface. + --dumpspec Run tcpdump with that capture specification . + +The default interface is 'any' and the default dumpspec is 'tcp port 80'. + +EOERROR + exit 1; + +} From 2744a62c288b00fa7957b963ba02bc0b705ccece Mon Sep 17 00:00:00 2001 From: Andrew Ruthven Date: Sun, 4 Nov 2007 20:08:42 +1300 Subject: [PATCH 087/189] Slight code tidy up and add some debug statements. --- inc/drivers_ldap.php | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index 48fec9a1..d451be16 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -50,14 +50,19 @@ class ldapDrivers $this->valid=false; return ; } - if ($port) $this->connect=ldap_connect($host, $port); - else $this->connect=ldap_connect($host); + if ($port) + $this->connect=ldap_connect($host, $port); + else + $this->connect=ldap_connect($host); + if (! $this->connect){ $c->messages[] = sprintf(i18n( "drivers_ldap : Unable to connect to LDAP with port %s on host %s"), $port,$host ); $this->valid=false; return ; } + dbg_error_log( "LDAP", "drivers_ldap : Connected to LDAP server %s",$host ); + //Set LDAP protocol version if (isset($config['protocolVersion'])) ldap_set_option($this->connect,LDAP_OPT_PROTOCOL_VERSION, $config['protocolVersion']); @@ -115,10 +120,17 @@ class ldapDrivers if ( !ldap_first_entry($this->connect, $entry) ){ dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter ); return false; + } else { + dbg_error_log( "LDAP", "drivers_ldap : Found a user using filter %s",$filter ); } + $dnUser = ldap_get_dn($this->connect, ldap_first_entry($this->connect,$entry)); - if ( !@ldap_bind($this->connect, $dnUser, $passwd) ) + if ( !@ldap_bind($this->connect, $dnUser, $passwd) ) { + dbg_error_log( "LDAP", "drivers_ldap : Failed to bind to user %s using password %s", $dnUser, $passwd ); return false; + } + + dbg_error_log( "LDAP", "drivers_ldap : Bound to user %s using password %s", $dnUser, $passwd ); $i = ldap_first_entry($this->connect,$entry); $arr = ldap_get_attributes($this->connect,$i); @@ -152,6 +164,7 @@ function getStaticLdap() { * @param object $usr A user record to be updated (or created) */ function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { + dbg_error_log( "LDAP", "Going to sync the user from LDAP" ); $validUserFields = get_fields('usr'); foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { @@ -159,7 +172,11 @@ function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { } foreach ( $mapping as $field => $value ) { - if ( in_array($field, $validUserFields) ) $usr->{$field} = $ldap_values[$value]; + dbg_error_log( "LDAP", "Considering copying %s", $field ); + if ( in_array($field, $validUserFields) ) { + $usr->{$field} = $ldap_values[$value]; + dbg_error_log( "LDAP", "Setting usr value for field $s to %s", $field, $value ); + } } UpdateUserFromExternal( $usr ); @@ -198,7 +215,10 @@ function LDAP_check($username, $password ){ $valid = $ldapDriver->requestUser( $filter, $attributes, $password ); // is a valid user or not - if ( !$valid ) return false; + if ( !$valid ) { + dbg_error_log( "LDAP", "user %s is not a valid user",$username ); + return false; + } $ldap_timestamp = $valid[$mapping["updated"]]; @@ -221,6 +241,7 @@ function LDAP_check($username, $password ){ // we will need to update the user record } else { + dbg_error_log( "LDAP", "user %s doesn't exist in local DB, we need to create it",$username ); $usr = (object) array( 'user_no' => 0 ); } From acca66e4d8929cfb5b8b6e78a846eb60a513dfea Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 21:20:05 +1300 Subject: [PATCH 088/189] $c needs to be global. --- inc/drivers_ldap.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index d451be16..c68e4743 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -128,7 +128,7 @@ class ldapDrivers if ( !@ldap_bind($this->connect, $dnUser, $passwd) ) { dbg_error_log( "LDAP", "drivers_ldap : Failed to bind to user %s using password %s", $dnUser, $passwd ); return false; - } + } dbg_error_log( "LDAP", "drivers_ldap : Bound to user %s using password %s", $dnUser, $passwd ); @@ -164,6 +164,7 @@ function getStaticLdap() { * @param object $usr A user record to be updated (or created) */ function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { + global $c; dbg_error_log( "LDAP", "Going to sync the user from LDAP" ); $validUserFields = get_fields('usr'); From 99248f42dd6d0cb496e3857aa58b6c10afa7ae43 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 21:22:55 +1300 Subject: [PATCH 089/189] Fix debugging. --- inc/drivers_ldap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index c68e4743..eb62e100 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -176,7 +176,7 @@ function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { dbg_error_log( "LDAP", "Considering copying %s", $field ); if ( in_array($field, $validUserFields) ) { $usr->{$field} = $ldap_values[$value]; - dbg_error_log( "LDAP", "Setting usr value for field $s to %s", $field, $value ); + dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value ); } } From e7940eef3258de7629cc8da26ef2ea269ff76b48 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 21:35:22 +1300 Subject: [PATCH 090/189] Add a bit more debugging. --- inc/drivers_ldap.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index eb62e100..d3218013 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -165,11 +165,15 @@ function getStaticLdap() { */ function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { global $c; + dbg_error_log( "LDAP", "Going to sync the user from LDAP" ); $validUserFields = get_fields('usr'); foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { - if ( in_array($field, $validUserFields) ) $usr->{$field} = $value; + if ( in_array($field, $validUserFields) ) { + $usr->{$field} = $value; + dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value ); + } } foreach ( $mapping as $field => $value ) { From 718961733432d7df8f0c2891abc81f4186b09fe4 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 21:41:20 +1300 Subject: [PATCH 091/189] in_array looks for values, but we need to look in the keys now. --- inc/drivers_ldap.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index d3218013..ba7be4cc 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -170,7 +170,7 @@ function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { $validUserFields = get_fields('usr'); foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { - if ( in_array($field, $validUserFields) ) { + if ( isset($validUserFields[$field]) ) { $usr->{$field} = $value; dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value ); } @@ -178,7 +178,7 @@ function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { foreach ( $mapping as $field => $value ) { dbg_error_log( "LDAP", "Considering copying %s", $field ); - if ( in_array($field, $validUserFields) ) { + if ( isset($validUserFields[$field]) ) { $usr->{$field} = $ldap_values[$value]; dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value ); } From 3eaa0ab62719b4f6e57355559cd0685451cb2deb Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 21:51:14 +1300 Subject: [PATCH 092/189] New test for iCal like PROPFIND on / --- .../regression-suite/511-iCal-PROPFIND.result | 30 +++++++++++++++++++ .../regression-suite/511-iCal-PROPFIND.test | 25 ++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 testing/tests/regression-suite/511-iCal-PROPFIND.result create mode 100644 testing/tests/regression-suite/511-iCal-PROPFIND.test diff --git a/testing/tests/regression-suite/511-iCal-PROPFIND.result b/testing/tests/regression-suite/511-iCal-PROPFIND.result new file mode 100644 index 00000000..c3a28a18 --- /dev/null +++ b/testing/tests/regression-suite/511-iCal-PROPFIND.result @@ -0,0 +1,30 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, access-control +ETag: "d87ada45ea684066e06cb14779b80ea4" +Content-Length: 755 +Content-Type: text/xml; charset="utf-8" + + + + + http://mycaldav/ + + + DAViCal_CalDAV_Server + + HTTP/1.1 200 OK + + + + + + + + + + + HTTP/1.1 404 Not Found + + + diff --git a/testing/tests/regression-suite/511-iCal-PROPFIND.test b/testing/tests/regression-suite/511-iCal-PROPFIND.test new file mode 100644 index 00000000..f027cafe --- /dev/null +++ b/testing/tests/regression-suite/511-iCal-PROPFIND.test @@ -0,0 +1,25 @@ +# +# Testing with a process similar to iCal 10.5 +# +TYPE=PROPFIND +URL=http://mycaldav/ +HEAD + +HEADER=User-Agent: DAVKit/2.0 (10.5; wrbt) iCal 3.0 +HEADER=Content-Type: text/xml +HEADER=Depth: 0 + +BEGINDATA + + + + + + + + + + + + +ENDDATA From 1ed1f646f282b4f0428a0e738a4076fcef841d15 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 21:51:55 +1300 Subject: [PATCH 093/189] Test to produce that result I actually committed earlier by accident. --- .../870-Principal-PROPFIND.test | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 testing/tests/regression-suite/870-Principal-PROPFIND.test diff --git a/testing/tests/regression-suite/870-Principal-PROPFIND.test b/testing/tests/regression-suite/870-Principal-PROPFIND.test new file mode 100644 index 00000000..a98088fc --- /dev/null +++ b/testing/tests/regression-suite/870-Principal-PROPFIND.test @@ -0,0 +1,32 @@ +# +# Testing for Spec compliance. PROPFIND on the root +# +TYPE=PROPFIND +URL=http://mycaldav/~user1/ +HEADER=User-Agent: RFC2518 Spec Tests +HEADER=Depth: 0 +HEADER=Content-Type: application/xml + +REPLACE=#\d{8}T\d{6}#YYYYMMDDThhmmss# + +BEGINDATA + + + + + + + + + + + + + + + + + + + +ENDDATA From 6faae5361b4a2029e39f02b81392bbab159ecdc3 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 23:10:02 +1300 Subject: [PATCH 094/189] New client setup details for iCal. --- docs/website/clients/iCal-details.php | 23 +++++++++++++++++++++++ docs/website/clients/iCal-dialog.png | Bin 0 -> 60811 bytes docs/website/clients/iCal-icon.png | Bin 0 -> 13308 bytes docs/website/clients/iCal-screenshot.png | Bin 0 -> 206196 bytes 4 files changed, 23 insertions(+) create mode 100644 docs/website/clients/iCal-details.php create mode 100644 docs/website/clients/iCal-dialog.png create mode 100644 docs/website/clients/iCal-icon.png create mode 100644 docs/website/clients/iCal-screenshot.png diff --git a/docs/website/clients/iCal-details.php b/docs/website/clients/iCal-details.php new file mode 100644 index 00000000..e6290d6a --- /dev/null +++ b/docs/website/clients/iCal-details.php @@ -0,0 +1,23 @@ +

iCal

+

iCal, from version 3.0 (released with OS 10.5) is generally well-behaved + and will discover your own calendars when configured. It will not allow you to manipulate other calendars on + the same server, however, unless you use different credentials to access them.

+ +
    +
  1. Open the "Preferences" dialog.
  2. +
  3. Choose the "Accounts" tab
  4. +
  5. Click on the "+" and a new panel will appear.
  6. +
  7. Enter a "Description" for the account.
  8. +
  9. The "Username" and "Password" are the relevant ones for your CalDAV server.
  10. +
  11. Open the "Server Options" area and set your account URL to point to http://host.../caldav.php/username/.
     
  12. +
  13. Click "Add" to confirm the new account
  14. +
  15. Your own calendars will be automatically discovered.
  16. +
  17. If you don't already have a calendar for your own user, go to the calendar view and long-click on the "+" will display a menu letting you create a new one.
  18. +
+ +

Caveats

+

DAViCal does not support the draft scheduling extensions to CalDAV, so you will not see the full functionality + of iCal.

+

iCal does not let you browse the calendar hierarchy to find other calendars you could view, so you will not + see the full functionality of DAViCal either.

+ diff --git a/docs/website/clients/iCal-dialog.png b/docs/website/clients/iCal-dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..c77ba8cf149b133c4ead41d01c6fa590c94ef8e1 GIT binary patch literal 60811 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

!mw1f>@y4GQ{bTG@74nnvmA=~{aBsx>u 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 VO!s;ucHsd(5M>ReB1N;;{{v}Lvu*$Y literal 0 HcmV?d00001 diff --git a/docs/website/clients/iCal-icon.png b/docs/website/clients/iCal-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..acb18df04fd3abf385260af1c1a454e441cd4c2f GIT binary patch literal 13308 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%0AGS{T1zhb-*r;QD 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 literal 0 HcmV?d00001 diff --git a/docs/website/clients/iCal-screenshot.png b/docs/website/clients/iCal-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f0c96d4a7348648078e36328295f8b14356ad540 GIT binary patch literal 206196 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�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

v&K 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 Date: Sun, 4 Nov 2007 23:10:52 +1300 Subject: [PATCH 095/189] Final changes to really get iCal working. --- inc/CalDAVPrincipal.php | 11 ++++++++--- inc/caldav-PROPFIND.php | 12 +++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/inc/CalDAVPrincipal.php b/inc/CalDAVPrincipal.php index c5780984..9c863373 100644 --- a/inc/CalDAVPrincipal.php +++ b/inc/CalDAVPrincipal.php @@ -100,13 +100,18 @@ class CalDAVPrincipal } $script = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : ''); - $this->url = sprintf( "%s%s/%s/", $c->protocol_server_port_script, $script, $this->username); + $script = $c->protocol_server_port_script . $script; + if ( preg_match( '/ iCal 3\.0/', $_SERVER['HTTP_USER_AGENT'] ) ) { + $script = preg_replace('#^https?://[^/]+#', '', $script ); + } + + $this->url = sprintf( "%s/%s/", $script, $this->username); // $this->url = sprintf( "%s%s/__uuids__/%s/", $c->protocol_server_port_script, $script, $this->username); - $this->calendar_home_set = sprintf( "%s%s/%s/", $c->protocol_server_port_script, $script, $this->username); + $this->calendar_home_set = sprintf( "%s/%s/", $script, $this->username); $this->user_address_set = array( - sprintf( "%s%s/%s/", $c->protocol_server_port_script, $script, $this->username), + sprintf( "%s/%s/", $script, $this->username), // sprintf( "%s%s/~%s/", $c->protocol_server_port_script, $script, $this->username), // sprintf( "%s%s/__uuids__/%s/", $c->protocol_server_port_script, $script, $this->username), ); diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index cb86923e..c40ffb94 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -216,9 +216,11 @@ function add_principal_properties( &$prop, &$not_found, &$denied ) { if ( isset($attribute_list['CALENDAR-USER-ADDRESS-SET'] ) ) { add_namespace("C", "urn:ietf:params:xml:ns:caldav"); - $email = new XMLElement('href', 'mailto:'.$request->principal->email ); - $calendar = new XMLElement('href', $request->principal->calendar_home_set ); - $prop->NewElement("C:calendar-user-address-set", array( $calendar, $email) ); + $addr_set = array(); + foreach( $request->principal->user_address_set AS $k => $v ) { + $addr_set[] = new XMLElement('href', $v ); + } + $prop->NewElement("C:calendar-user-address-set", $addr_set ); } } @@ -236,6 +238,10 @@ function collection_to_xml( $collection ) { $url = $c->protocol_server_port_script . $collection->dav_name; $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' + if ( preg_match( '/ iCal 3\.0/', $_SERVER['HTTP_USER_AGENT'] ) ) { + $url = preg_replace('#^https?://[^/]+#', '', $url ); + } + $resourcetypes = array( new XMLElement("collection") ); $contentlength = false; From 87f67589c4e7f6754da7a110bf6b53a403c76720 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 23:12:33 +1300 Subject: [PATCH 096/189] New files. --- rscds.webprj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rscds.webprj b/rscds.webprj index 96261753..50c0f84d 100644 --- a/rscds.webprj +++ b/rscds.webprj @@ -242,6 +242,8 @@ - + + + From c1abc850268c1188d14bfd0d21a10df69e8ceff4 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 23:12:50 +1300 Subject: [PATCH 097/189] Line buffering of the result is better. --- testing/watch-port-80.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/watch-port-80.sh b/testing/watch-port-80.sh index 065a9405..a479496c 100755 --- a/testing/watch-port-80.sh +++ b/testing/watch-port-80.sh @@ -2,4 +2,4 @@ PORT=${1:-"80"} -sudo tcpdump -i lo -s0 -n -q -A "tcp port ${PORT} and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)" +sudo tcpdump -i any -s0 -l -n -q -A "tcp port ${PORT} and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)" From 601e7bc12fdf68a593177f46af43e0aa1c4a73a9 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 23:30:14 +1300 Subject: [PATCH 098/189] Actual working iCal responses. --- .../tests/regression-suite/510-iCal-PROPFIND.result | 11 +++++------ .../tests/regression-suite/511-iCal-PROPFIND.result | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/testing/tests/regression-suite/510-iCal-PROPFIND.result b/testing/tests/regression-suite/510-iCal-PROPFIND.result index e20d86f1..49c31771 100644 --- a/testing/tests/regression-suite/510-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/510-iCal-PROPFIND.result @@ -1,23 +1,22 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "33567ed4d798b9c5ea389d70ed845ae9" -Content-Length: 935 +ETag: "455c90fdc59860d7dfa851ad1f75b4ba" +Content-Length: 847 Content-Type: text/xml; charset="utf-8" - http://mycaldav/caldav.php/user1/home/ + /caldav.php/user1/home/ home - http://mycaldav/caldav.php/user1/ + /caldav.php/user1/ - http://mycaldav/caldav.php/user1/ - mailto:user1@example.net + /caldav.php/user1/ HTTP/1.1 200 OK diff --git a/testing/tests/regression-suite/511-iCal-PROPFIND.result b/testing/tests/regression-suite/511-iCal-PROPFIND.result index c3a28a18..4a044e58 100644 --- a/testing/tests/regression-suite/511-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/511-iCal-PROPFIND.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, access-control -ETag: "d87ada45ea684066e06cb14779b80ea4" -Content-Length: 755 +ETag: "af62dedcedd04f04e042beb9408793c2" +Content-Length: 740 Content-Type: text/xml; charset="utf-8" - http://mycaldav/ + / DAViCal_CalDAV_Server From 5f2a55bcf5bc779037328352e5008c35b4bdde01 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 23:30:51 +1300 Subject: [PATCH 099/189] Scrub confidential events more thoroughly. --- inc/caldav-GET.php | 11 +++++++---- inc/caldav-REPORT.php | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/inc/caldav-GET.php b/inc/caldav-GET.php index e2b1bb57..123f5834 100644 --- a/inc/caldav-GET.php +++ b/inc/caldav-GET.php @@ -61,9 +61,13 @@ else if ( $qry->rows > 1 ) { // the user is not admin / owner of this calendarlooking at his calendar and can not admin the other cal if ( $event->class == 'CONFIDENTIAL' ) { // if the event is confidential we fake one that just says "Busy" - $displayname = translate("Busy"); - $ical->Put( 'SUMMARY', $displayname ); - $response .= $ical->Render( false, $event->caldav_type, $ical->DefaultPropertyList() ); + $confidential = new iCalendar( array( + 'SUMMARY' => translate('Busy'), 'CLASS' => 'CONFIDENTIAL', + 'DTSTART' => $ical->Get('DTSTART'), + 'DURATION' => $ical->Get('DURATION'), + 'RRULE' => $ical->Get('RRULE') + ) ); + $response .= $confidential->Render( false, $event->caldav_type ); } elseif ( $c->hide_alarm ) { // Otherwise we hide the alarms (if configured to) @@ -89,4 +93,3 @@ else { $request->DoResponse( 500, translate("Database Error") ); } -?> \ No newline at end of file diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index 02c7abd1..7df75582 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -72,10 +72,13 @@ function calendar_to_xml( $properties, $item ) { // the user is not admin / owner of this calendarlooking at his calendar and can not admin the other cal if ( $item->class == 'CONFIDENTIAL' ) { // if the event is confidential we fake one that just says "Busy" - $displayname = translate("Busy"); - $ical = new iCalendar( array( "icalendar" => $caldav_data) ); - $ical->Put( 'SUMMARY', $displayname ); - $caldav_data = $ical->render(true, $caldav_type, $ical->DefaultPropertyList() ); + $confidential = new iCalendar( array( + 'SUMMARY' => translate('Busy'), 'CLASS' => 'CONFIDENTIAL', + 'DTSTART' => $ical->Get('DTSTART'), + 'DURATION' => $ical->Get('DURATION'), + 'RRULE' => $ical->Get('RRULE') + ) ); + $caldav_data = $confidential->Render( true, $caldav_type ); } elseif ( $c->hide_alarm ) { // Otherwise we hide the alarms (if configured to) From 6e6d5289115c9afcce55f62d2a389b4c33674a87 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 23:31:58 +1300 Subject: [PATCH 100/189] Updated strings for 0.9.2 --- po/de_DE.po | 6 +++++- po/en_NZ.po | 5 ++++- po/es_AR.po | 6 +++++- po/es_ES.po | 6 +++++- po/es_MX.po | 6 +++++- po/fr_FR.po | 6 +++++- po/hu_HU.po | 6 +++++- po/messages.po | 5 ++++- po/nl_NL.po | 6 +++++- po/pl_PL.po | 6 +++++- po/ru_RU.po | 6 +++++- 11 files changed, 53 insertions(+), 11 deletions(-) diff --git a/po/de_DE.po b/po/de_DE.po index 61dff7c4..dfd12865 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: 2006-11-06 17:24+1300\n" "Last-Translator: Cristina Radalescu \n" "MIME-Version: 1.0\n" @@ -566,6 +566,10 @@ msgstr "" msgid "You may not access that calendar" msgstr "" +#, fuzzy +msgid "You may not access that collection" +msgstr "Sie sind nicht berechtigt diese Funktion zu benutzen" + #, fuzzy msgid "You may not add entries to this calendar." msgstr "Sie sind nicht berechtigt diese Funktion zu benutzen" diff --git a/po/en_NZ.po b/po/en_NZ.po index e1cd9583..35e2521e 100644 --- a/po/en_NZ.po +++ b/po/en_NZ.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -552,6 +552,9 @@ msgstr "" msgid "You may not access that calendar" msgstr "" +msgid "You may not access that collection" +msgstr "" + msgid "You may not add entries to this calendar." msgstr "" diff --git a/po/es_AR.po b/po/es_AR.po index ec718843..d0cf5dbe 100644 --- a/po/es_AR.po +++ b/po/es_AR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti \n" "Language-Team: LANGUAGE \n" @@ -564,6 +564,10 @@ msgstr "" msgid "You may not access that calendar" msgstr "" +#, fuzzy +msgid "You may not access that collection" +msgstr "No está autorizado a utilizar ésta función." + #, fuzzy msgid "You may not add entries to this calendar." msgstr "No está autorizado a utilizar ésta función." diff --git a/po/es_ES.po b/po/es_ES.po index ec718843..d0cf5dbe 100644 --- a/po/es_ES.po +++ b/po/es_ES.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti \n" "Language-Team: LANGUAGE \n" @@ -564,6 +564,10 @@ msgstr "" msgid "You may not access that calendar" msgstr "" +#, fuzzy +msgid "You may not access that collection" +msgstr "No está autorizado a utilizar ésta función." + #, fuzzy msgid "You may not add entries to this calendar." msgstr "No está autorizado a utilizar ésta función." diff --git a/po/es_MX.po b/po/es_MX.po index ec718843..d0cf5dbe 100644 --- a/po/es_MX.po +++ b/po/es_MX.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti \n" "Language-Team: LANGUAGE \n" @@ -564,6 +564,10 @@ msgstr "" msgid "You may not access that calendar" msgstr "" +#, fuzzy +msgid "You may not access that collection" +msgstr "No está autorizado a utilizar ésta función." + #, fuzzy msgid "You may not add entries to this calendar." msgstr "No está autorizado a utilizar ésta función." diff --git a/po/fr_FR.po b/po/fr_FR.po index d9f1f5a6..56f0302b 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.3.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: 2006-11-13 13:03+1300\n" "Last-Translator: maxime delorme \n" "Language-Team: LANGUAGE \n" @@ -631,6 +631,10 @@ msgstr "Vous n'avez pas suffisamment d'accès pour verrouiller ça" msgid "You may not access that calendar" msgstr "Vous ne pouvez accéder à ce calendrier" +#, fuzzy +msgid "You may not access that collection" +msgstr "Vous ne pouvez accéder à ce calendrier" + msgid "You may not add entries to this calendar." msgstr "Vous n'êtes pas autorisé à utiliser cette fonction." diff --git a/po/hu_HU.po b/po/hu_HU.po index f793b82e..5df6f3cb 100644 --- a/po/hu_HU.po +++ b/po/hu_HU.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: 2007-05-03 15:00+0001\n" "Last-Translator: David Takacs \n" "Language-Team: \n" @@ -557,6 +557,10 @@ msgstr "Nincs jogosultsága zárolni" msgid "You may not access that calendar" msgstr "Nincs jogosultsága hozzáférni a naptárhoz" +#, fuzzy +msgid "You may not access that collection" +msgstr "Nincs jogosultsága hozzáférni a naptárhoz" + msgid "You may not add entries to this calendar." msgstr "Nincs jogosultsága új bejegyzéseket írni a naptárba." diff --git a/po/messages.po b/po/messages.po index d8b1102a..12976086 100644 --- a/po/messages.po +++ b/po/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -565,6 +565,9 @@ msgstr "" msgid "You may not access that calendar" msgstr "" +msgid "You may not access that collection" +msgstr "" + msgid "You may not add entries to this calendar." msgstr "" diff --git a/po/nl_NL.po b/po/nl_NL.po index 266ccb03..34ce9d34 100644 --- a/po/nl_NL.po +++ b/po/nl_NL.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Eelco Maljaars \n" "Language-Team: nl_NL \n" @@ -561,6 +561,10 @@ msgstr "" msgid "You may not access that calendar" msgstr "Je mag die agenda niet benaderen" +#, fuzzy +msgid "You may not access that collection" +msgstr "Je mag die agenda niet benaderen" + msgid "You may not add entries to this calendar." msgstr "Je mag geen items toevoegen aan deze agenda" diff --git a/po/pl_PL.po b/po/pl_PL.po index ea0b25d8..f9126f7f 100644 --- a/po/pl_PL.po +++ b/po/pl_PL.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds-messages\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: 2007-03-31 00:24+0200\n" "Last-Translator: Rafal Slubowski \n" "Language-Team: polski \n" @@ -559,6 +559,10 @@ msgstr "Nie masz wystarczających uprawnień aby zarezerwować ten" msgid "You may not access that calendar" msgstr "Nie masz dostępu do tego kalendarza" +#, fuzzy +msgid "You may not access that collection" +msgstr "Nie masz dostępu do tego kalendarza" + msgid "You may not add entries to this calendar." msgstr "Nie możesz dodawać zdarzeń do tego kalendarza." diff --git a/po/ru_RU.po b/po/ru_RU.po index 0a6cb030..eacf5932 100644 --- a/po/ru_RU.po +++ b/po/ru_RU.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.3.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-01 22:19+1300\n" +"POT-Creation-Date: 2007-11-04 23:31+1300\n" "PO-Revision-Date: 2006-11-13 23:07+0500\n" "Last-Translator: Nick Khazov \n" "Language-Team: LANGUAGE \n" @@ -574,6 +574,10 @@ msgstr "" msgid "You may not access that calendar" msgstr "" +#, fuzzy +msgid "You may not access that collection" +msgstr "Вы не авторизованы для использоования этой функции." + #, fuzzy msgid "You may not add entries to this calendar." msgstr "Вы не авторизованы для использоования этой функции." From 7712649e687c20c3c1647f0bbc4355279128f9b8 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 4 Nov 2007 23:32:22 +1300 Subject: [PATCH 101/189] New docs, saying DAViCal rather than RSCDS. --- docs/website/clients.php | 4 ++++ docs/website/clients/Chandler-details.php | 4 ++-- docs/website/clients/Evolution-details.php | 8 ++++---- docs/website/clients/Interoperability-details.php | 4 ++-- docs/website/clients/Mozilla-details.php | 2 +- docs/website/clients/Mulberry-details.php | 2 +- docs/website/clients/Other-details.php | 4 ++-- docs/website/inc/page-footer.php | 4 ++-- docs/website/inc/page-header.php | 10 +++++----- 9 files changed, 23 insertions(+), 19 deletions(-) diff --git a/docs/website/clients.php b/docs/website/clients.php index fcda89b3..44c1af00 100644 --- a/docs/website/clients.php +++ b/docs/website/clients.php @@ -43,6 +43,7 @@ sort($clients); foreach( $clients AS $k => $v ) { if ( $v == "Interoperability" ) continue; + if ( $v == "Other" ) continue; $style = (strcmp($client_page,$v) == 0 ? ' class="selected"' : '' ); printf( '', $style, $style, urlencode($v) ); if ( isset($icons[$v]) ) { @@ -51,6 +52,9 @@ echo "$v

\n"; } + $style = ($client_page == "Other" ? ' class="selected"' : '' ); + printf( 'Other

', $style, $style ); + include("inc/page-middle.php"); include("clients/".$details[$client_page]); diff --git a/docs/website/clients/Chandler-details.php b/docs/website/clients/Chandler-details.php index 9d98c63f..9f395937 100644 --- a/docs/website/clients/Chandler-details.php +++ b/docs/website/clients/Chandler-details.php @@ -23,5 +23,5 @@ button or with a default frequency of hourly. This is quite different to the ot have used which all aggressively push new and changed items to the server as soon as possible, but which may be lazy about fetching updates.

-

Operation with RSCDS is not yet perfect but basic operation is satisfactory. I will be -concentrating on making RSCDS interoperate with Chandler over coming releases.

+

Operation with DAViCal is not yet perfect but basic operation is satisfactory. I will be +concentrating on making DAViCal interoperate with Chandler over coming releases.

diff --git a/docs/website/clients/Evolution-details.php b/docs/website/clients/Evolution-details.php index 9381a94f..39691d1f 100644 --- a/docs/website/clients/Evolution-details.php +++ b/docs/website/clients/Evolution-details.php @@ -5,7 +5,7 @@ was little in the way of a repository available to test against until recently.<
  1. Select "File" then "New" then "Calendar" from the menus.
  2. -
  3. Choose a type of "CalDAV", enter a name, and a URL such as caldav://server.domain.name/caldav.php/username/home/, enter your user name for RSCDS and click "OK".
     
  4. +
  5. Choose a type of "CalDAV", enter a name, and a URL such as caldav://server.domain.name/caldav.php/username/home/, enter your user name for DAViCal and click "OK".
     
  6. You should now be prompted for a password for that username. Enter the password and your calendar should now show.
@@ -15,11 +15,11 @@ restart. If you still have problems try doing that, but killing evolution-data-

Sometimes Evolution writes error messages into the cache file, so if you have ongoing problems you may want to take a look inside that.

-

There are some quirks with Evolution's handling of CalDAV too, so perhaps take a look at the following -bugs:

+

There are some quirks with Evolution's handling of CalDAV too, prior to 2.12.0, so perhaps take a look at the following +bugs (fixed in 2.12.0):

There may also be bugs in Evolution's handling of SSL with CalDAV - I couldn't get it to work reliably.

-

Hopefully those will be fixed before too long...

+ diff --git a/docs/website/clients/Interoperability-details.php b/docs/website/clients/Interoperability-details.php index 96c9834a..0a226fba 100644 --- a/docs/website/clients/Interoperability-details.php +++ b/docs/website/clients/Interoperability-details.php @@ -1,5 +1,5 @@

Cross-client Interoperability Considerations

-

If you intend to have users accessing the Really Simple CalDAV Store with more than one client +

If you intend to have users accessing the DAViCal CalDAV Server with more than one client then you should attempt to structure the URLs which they use to access the system in the way that Mulberry does it.

Basically, Mulberry breaks the URL into three parts:

@@ -11,7 +11,7 @@ that Mulberry does it.

The host name is, of course, up to you. The 'root path' should be /caldav.php/ and anything following that is the calendar namespace.

-

Within the calendar namespace RSCDS uses the first element of the path as the user or resource name, so that a client connecting at the root path +

Within the calendar namespace DAViCal uses the first element of the path as the user or resource name, so that a client connecting at the root path can see all of the (accessible) users and resources available to them (Mulberry displays this hierarchy) with any calendars below that.

Effectively this means that in Evolution, Sunbird and Lightning you should really specify a calendar URL which is something like:

diff --git a/docs/website/clients/Mozilla-details.php b/docs/website/clients/Mozilla-details.php
index a3c35da0..915afd7e 100644
--- a/docs/website/clients/Mozilla-details.php
+++ b/docs/website/clients/Mozilla-details.php
@@ -2,7 +2,7 @@
 

The Mozilla Calendar project offers their calendar under two different names: Sunbird is a standalone calendar application, and Lightning is a Thunderbird extension. - The two are essentially the same, as far as RSCDS is + The two are essentially the same, as far as DAViCal is concerned, and these instructions should work for either of them.

    diff --git a/docs/website/clients/Mulberry-details.php b/docs/website/clients/Mulberry-details.php index 55a3a49e..af58256b 100644 --- a/docs/website/clients/Mulberry-details.php +++ b/docs/website/clients/Mulberry-details.php @@ -23,7 +23,7 @@ PROPFIND requests.

    Unfortunately Mulberry is not (yet) open-source, though it is free, so we must wait on the developer to fix the user interface niggles when he gets around to it.

    Note that Mulberry has a complex user interface. When I wrote this I went back into Mulberry and initially -thought that RSCDS had regressed somewhat and that these instructions didn't exactly work... :-) It turned out +thought that DAViCal had regressed somewhat and that these instructions didn't exactly work... :-) It turned out that these instructions worked just fine when I followed them to the letter the next day. Go figure. I think I need to record some screenshots of this one...

    diff --git a/docs/website/clients/Other-details.php b/docs/website/clients/Other-details.php index c4474d62..0ca4ca8e 100644 --- a/docs/website/clients/Other-details.php +++ b/docs/website/clients/Other-details.php @@ -1,8 +1,8 @@

    Other Client Software

    -

    I would love to have more client software available to test RSCDS +

    I would love to have more client software available to test DAViCal against, but so far these are the only ones I have access to.

    If you want to point me at more free software that supports CalDAV, or send me free copies of such proprietary software, then I will add it to -the list as well as make RSCDS work with it.

    +the list as well as make DAViCal work with it.

    diff --git a/docs/website/inc/page-footer.php b/docs/website/inc/page-footer.php index 74ef0a7e..20d95992 100644 --- a/docs/website/inc/page-footer.php +++ b/docs/website/inc/page-footer.php @@ -11,10 +11,10 @@ echo $tags_to_be_closed; XHTML | CSS

    -Copyright 2006 | Andrew McMillan +Copyright 2007 | Andrew McMillan

    - + SourceForge.net Logo

diff --git a/docs/website/inc/page-header.php b/docs/website/inc/page-header.php index 42aec5ea..a7aa10fa 100644 --- a/docs/website/inc/page-header.php +++ b/docs/website/inc/page-header.php @@ -2,7 +2,7 @@ -Really Simple CalDAV Store<?php +<title>DAViCal CalDAV Server<?php if ( isset($title) ) { echo " - ". $title; } @@ -17,18 +17,18 @@ if ( isset($title) ) { echo $title; } else { - echo "Really Simple CalDAV Store"; + echo "DAViCal CalDAV Store"; } ?></div> -<div id="subTitle">Really Simple CalDAV Store</div> +<div id="subTitle">DAViCal CalDAV Server</div> <div id="headerLinks"> <a href="index.php" class="hlink">Home</a> | <a href="installation.php" class="hlink">Installation</a> | <a href="clients.php" class="hlink">Client Config</a> | <a href="administration.php" class="hlink">Administration</a> | -<a href="/moin/FrontPage" class="hlink">RSCDS Wiki</a> | +<a href="/moin/FrontPage" class="hlink">DAViCal Wiki</a> | <a href="http://andrew.mcmillan.net.nz/" class="hlink">Blog</a> | -<a href="http://sourceforge.net/projects/rscds/" class="hlink">RSCDS on Sourceforge</a> +<a href="http://sourceforge.net/projects/rscds/" class="hlink">DAViCal on Sourceforge</a> </div> </div> <div id="pageContent"> From 5976c52650b52fc5002237897e223143bd121036 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 4 Nov 2007 23:32:54 +1300 Subject: [PATCH 102/189] Release 0.9.2 --- VERSION | 2 +- debian/changelog | 12 ++++++++++++ inc/always.php | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index f374f666..2003b639 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.9.1 +0.9.2 diff --git a/debian/changelog b/debian/changelog index d1a508fc..f55f08ed 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +rscds (0.9.2) unstable; urgency=low + + * Add support for principal-url and calendar-home-set properties. + * All events should be PUBLIC unless CLASS specifies otherwise. + * Calendars can now be set such that all events are PUBLIC. + * Add support for automatically added relationships. + * Make some use of the improvements to the iCalendar class. + * Working with iCal 3.0 from Mac OS 10.5. + * Refactoring of driver code for LDAP and external AWL DB. + + -- Andrew McMillan <debian@mcmillan.net.nz> Sun, 04 Nov 2007 23:31:10 +1300 + rscds (0.9.1) unstable; urgency=low * Reduce debug logging noise when debugging is iff diff --git a/inc/always.php b/inc/always.php index 7f3e0073..8ce1de8d 100644 --- a/inc/always.php +++ b/inc/always.php @@ -85,7 +85,7 @@ awl_set_locale($c->default_locale); * */ $c->code_version = 0; -$c->version_string = '0.9.1+iCal2'; // The actual version # is replaced into that during the build /release process +$c->version_string = '0.9.2'; // The actual version # is replaced into that during the build /release process if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) { $c->code_major = $matches[1]; $c->code_minor = $matches[2]; From e8c826524edc0d6453a0edc2895b80bc37657877 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 14:59:07 +1300 Subject: [PATCH 103/189] Minor sanity checking for enabling LDAP options. --- htdocs/tools.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/tools.php b/htdocs/tools.php index 18df1c44..b64c0eba 100644 --- a/htdocs/tools.php +++ b/htdocs/tools.php @@ -20,7 +20,7 @@ require_once("classBrowser.php"); if ( !$session->AllowedTo("Admin" ) ) exit; -if(isset($_POST['Sync_LDAP'])){ +if( function_exists("sync_LDAP") && isset($_POST['Sync_LDAP'])){ sync_LDAP(); } @@ -38,7 +38,7 @@ class Tools { function render(){ global $c; echo $this->renderImportFromDirectory(); - if($c->authenticate_hook['call'] == 'LDAP_check'){ + if ( $c->authenticate_hook['call'] == 'LDAP_check' && function_exists("sync_LDAP") ) { echo $this->renderSyncLDAP(); } } From b7eae51e77fad68deeffa87fe10a9535a205bb74 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 15:00:24 +1300 Subject: [PATCH 104/189] Fix handling of CONFIDENTIAL events. --- inc/caldav-GET.php | 8 +++++++- inc/caldav-REPORT.php | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/inc/caldav-GET.php b/inc/caldav-GET.php index 123f5834..de0ec28b 100644 --- a/inc/caldav-GET.php +++ b/inc/caldav-GET.php @@ -64,9 +64,15 @@ else if ( $qry->rows > 1 ) { $confidential = new iCalendar( array( 'SUMMARY' => translate('Busy'), 'CLASS' => 'CONFIDENTIAL', 'DTSTART' => $ical->Get('DTSTART'), - 'DURATION' => $ical->Get('DURATION'), 'RRULE' => $ical->Get('RRULE') ) ); + $duration = $ical->Get('DURATION'); + if ( isset($duration) && $duration != "" ) { + $confidential->Set('DURATION', $duration ); + } + else { + $confidential->Set('DTEND', $ical->Get('DTEND') ); + } $response .= $confidential->Render( false, $event->caldav_type ); } elseif ( $c->hide_alarm ) { diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index 7df75582..15635a4c 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -71,13 +71,20 @@ function calendar_to_xml( $properties, $item ) { if ( !is_numeric(strpos($item->permissions,'A')) && $session->user_no != $item->user_no ){ // the user is not admin / owner of this calendarlooking at his calendar and can not admin the other cal if ( $item->class == 'CONFIDENTIAL' ) { + $ical = new iCalendar( array( "icalendar" => $caldav_data) ); // if the event is confidential we fake one that just says "Busy" $confidential = new iCalendar( array( 'SUMMARY' => translate('Busy'), 'CLASS' => 'CONFIDENTIAL', 'DTSTART' => $ical->Get('DTSTART'), - 'DURATION' => $ical->Get('DURATION'), 'RRULE' => $ical->Get('RRULE') ) ); + $duration = $ical->Get('DURATION'); + if ( isset($duration) && $duration != "" ) { + $confidential->Set('DURATION', $duration ); + } + else { + $confidential->Set('DTEND', $ical->Get('DTEND') ); + } $caldav_data = $confidential->Render( true, $caldav_type ); } elseif ( $c->hide_alarm ) { From 9172e1a86c8eb2143665266c33e57ee3f6a006ba Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 15:00:47 +1300 Subject: [PATCH 105/189] More name changing to DAViCal. --- docs/website/inc/page-header.php | 2 +- docs/website/index.php | 17 +++++++++-------- docs/website/installation.php | 23 ++++++++++++----------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/docs/website/inc/page-header.php b/docs/website/inc/page-header.php index a7aa10fa..f2433937 100644 --- a/docs/website/inc/page-header.php +++ b/docs/website/inc/page-header.php @@ -17,7 +17,7 @@ if ( isset($title) ) { echo $title; } else { - echo "DAViCal CalDAV Store"; + echo "DAViCal CalDAV Server"; } ?></div> <div id="subTitle">DAViCal CalDAV Server</div> diff --git a/docs/website/index.php b/docs/website/index.php index d19bc67e..bbdae445 100644 --- a/docs/website/index.php +++ b/docs/website/index.php @@ -1,5 +1,5 @@ <?php - $title = "RSCDS Home"; + $title = "DAViCal Home"; include("inc/page-header.php"); ?> <h1>Background</h1> @@ -30,19 +30,19 @@ but no testing has been undertaken in other PHP environments to date.</p> operating environments, and which is <em>fully</em> ACID compliant.</p> <h2>Simplicity of Setup</h2> -<p>For the greatest ease use you should consider installing RSCDS on the <a href="http://www.debian.org/">Debian GNU/Linux</a> +<p>For the greatest ease use you should consider installing DAViCal on the <a href="http://www.debian.org/">Debian GNU/Linux</a> distribution from the readily available, signed packages.</p> <p>We expect to increase the level of automation and simplicity for the Debian target release in particular, although other distributions might also become easier at the same time. We do expect slightly greater installation complexity in the first few releases as we come to understand the particular problems people experience.</p> <h2>Simplicity of Operation</h2> -<p>In general RSCDS should not need significant maintenance to keep it operating.</p> +<p>In general DAViCal should not need significant maintenance to keep it operating.</p> <p>Administrative functionality will be kept as simple as possible, within the target of supporting organisations of up to several hundred staff.</p> -<p>This is called a <em>Store</em> rather than a <em>Server</em> because the server-side smarts are intended to be -minimised to support CalDAV only in a manner sufficient to inter-operate with clients, and with the focus primarily -on the storage of calendar resources.</p> +<p>The server-side smarts in DAViCal are intended to be fairly minimal in order to support CalDAV + only in a manner sufficient to inter-operate with clients, and with the focus primarily + on the storage of calendar resources.</p> <h2>Web-based Administration</h2> <p>General administration of the system should be through a web-based application.</p> @@ -51,7 +51,7 @@ maintainable through a web-based client, although the server should support the works using the CalDAV protocol.</p> <h1>Credits</h1> -<p>The Really Simple CalDAV Store was conceived and written by <a href="http://andrew.mcmillan.net.nz/">Andrew McMillan</a>.</p> +<p>DAViCal CalDAV Server was conceived and written by <a href="http://andrew.mcmillan.net.nz/">Andrew McMillan</a>.</p> <p>Translations of the administration interface have been done by:</p> <ul> <li>Lorena Paoletti (Spanish)</li> @@ -62,7 +62,8 @@ works using the CalDAV protocol.</p> </ul> <p>Other contributors:</p> <ul> -<li>Maxime Delorme (CSS for Administration Pages)</li> +<li>Maxime Delorme (CSS, LDAP, SyncML, French translations)</li> +<li>Andrew Ruthven (Various enhancements)</li> </ul> <h1>Your Name Here!</h1> diff --git a/docs/website/installation.php b/docs/website/installation.php index 03d40892..feebd8f8 100644 --- a/docs/website/installation.php +++ b/docs/website/installation.php @@ -29,8 +29,8 @@ sudo apt-key advanced --keyserver subkeys.pgp.net --recv-keys CCA377BD77494424B0 notes to pages somewhere under here: <a href="http://rscds.sourceforge.net/moin/InstallationStuff">http://rscds.sourceforge.net/moin/InstallationStuff</a></p> -<h3>RPM Packages of RSCDS</h3> -<p>We have created RPM packages of RSCDS and libawl-php from the .deb packages +<h3>RPM Packages of DAViCal</h3> +<p>We have created RPM packages of DAViCal and libawl-php from the .deb packages using "alien". I don't know how well these work, so would appreciate feedback about your success with them.</p> @@ -40,7 +40,7 @@ about your success with them.</p> <h3>Gentoo, Slackware, BSD and the rest</h3> <p>You will need to download the latest versions of the <code>rscds</code> and <code>awl</code> packages -from the <a href="http://sourceforge.net/project/showfiles.php?group_id=179845">sourceforge download page for rscds</a>.</p> +from the <a href="http://sourceforge.net/project/showfiles.php?group_id=179845">sourceforge download page for DAViCal</a>.</p> <p>You will need to untar these. Preferably you will untar them from within the "<code>/usr/share</code>" directory and everything will be in it's expected location (well, except the docs, but it will at least be tidy and everything will be in one place).</p> @@ -60,7 +60,7 @@ the database creation scripts are likely to need love.</p> <h1>Pre-requisites</h1> -<p>RSCDS depends on a number of things. Firstly, it depends +<p>DAViCal depends on a number of things. Firstly, it depends on Andrew's Web Libraries (AWL) which is a set of useful PHP functions and objects written by Andrew McMillan over a number of years.</p> @@ -68,8 +68,8 @@ a number of years.</p> <p>The following other software is also needed:</p> <ul> <li>Apache: 1.3.x or 2.x.x</li> - <li>PHP: 4.3 or greater, including PHP5</li> - <li>PostgreSQL: 7.4 or greater (8.1 or better recommended)</li> + <li>PHP: 5.0 or greater, PHP4 might work</li> + <li>PostgreSQL: 8.1 or greater</li> </ul> <p>The PostgreSQL database may be installed on a server other @@ -79,7 +79,7 @@ installation.</p> <p>Since the CalDAV store takes over a significant amount of path hierarchy, it is designed to be installed in it's own virtual -host. If you want it to operate within the web root of some +host. However if you want it to operate within the web root of some other application there are instructions on the Wiki about doing this, and other fancy tricks such as URL rewriting to shorten the path.</p> @@ -139,11 +139,11 @@ computer as the web server, the following line (near the top of the pg_hba.conf file) should be enough:</p> <pre> -local rscds general trust +local davical general trust </pre> <p>This means that anyone on the local computer (including the -web application) will have rights to connect to the RSCDS +web application) will have rights to connect to the DAViCal database as the 'general' user. It will not allow remote access, or access as any user other than 'general'.</p> @@ -152,7 +152,7 @@ unix sockets, the line in the pg_hba.conf file should look something like:</p> <pre> -host rscds general 127.0.0.1/32 trust +host davical general 127.0.0.1/32 trust </pre> <p>If the webserver is on a different machine to the database, that @@ -178,13 +178,14 @@ single virtual host.</p> <VirtualHost 123.4.56.78 > DocumentRoot /usr/share/rscds/htdocs DirectoryIndex index.php index.html - ServerName rscds.example.net + ServerName davical.example.net ServerAlias calendar.example.net Alias /images/ /usr/share/rscds/htdocs/images/ php_value include_path /usr/share/awl/inc php_value magic_quotes_gpc 0 php_value register_globals 0 php_value error_reporting "E_ALL & ~E_NOTICE" + php_value default_charset "utf-8" </VirtualHost> </pre> From eefdb7749f5945fcd6625b7d15dbd3236fb9db09 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 15:29:01 +1300 Subject: [PATCH 106/189] Change names to DAViCal. --- inc/rscds_configuration_missing.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/inc/rscds_configuration_missing.php b/inc/rscds_configuration_missing.php index 97fccd51..5371669e 100644 --- a/inc/rscds_configuration_missing.php +++ b/inc/rscds_configuration_missing.php @@ -2,12 +2,12 @@ include("page-header.php"); echo <<<EOBODY -<h1>RSCDS Not Configured</h1> +<h1>DAViCal Not Configured</h1> <h2>The Bad News</h2> -<p>There is no configuration file present in <b>/etc/rscds/$_SERVER[SERVER_NAME]-conf.php</b> so +<p>There is no configuration file present in <b>/etc/davical/$_SERVER[SERVER_NAME]-conf.php</b> so your installation is not fully set up.</p> <h2>The Good News</h2> -<p>Well, you're seeing this! At least you have RSCDS <i>installed</i> :-) You also have Apache and PHP working +<p>Well, you're seeing this! At least you have DAViCal <i>installed</i> :-) You also have Apache and PHP working and so really you are well on the road to success!</p> <h2>The Dubious News</h2> <p>You could try and <a href="http://$_SERVER[SERVER_NAME]/docs/rscds/configuring.html">click here</a> and @@ -17,18 +17,16 @@ include("page-header.php"); <p>The configuration file should look something like this:</p> <pre> <?php -// \$c->domain_name = 'rscds.example.com'; -// \$c->sysabbr = 'rscds'; -// \$c->system_name = 'Really Simple CalDAV Store'; +// \$c->domain_name = 'davical.example.com'; +// \$c->sysabbr = 'davical'; +// \$c->system_name = 'DAViCal CalDAV Server'; \$c->admin_email = 'admin@example.com'; - \$c->pg_connect[] = 'dbname=rscds port=5432 user=general'; + \$c->pg_connect[] = 'dbname=davical port=5432 user=general'; -?> </pre> <p>The only really <em>essential</em> thing there is that connect string for the database, although configuring someone for the admin e-mail is a really good idea.</p> EOBODY; include("page-footer.php"); -?> \ No newline at end of file From f5e1e9830622fe06d6216583c7671a7a68b1c74e Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 15:33:27 +1300 Subject: [PATCH 107/189] Rename rscds_configuration_missing.php to davical_... --- inc/always.php | 2 +- inc/always.php.in | 2 +- ...figuration_missing.php => davical_configuration_missing.php} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename inc/{rscds_configuration_missing.php => davical_configuration_missing.php} (100%) diff --git a/inc/always.php b/inc/always.php index 8ce1de8d..de07a081 100644 --- a/inc/always.php +++ b/inc/always.php @@ -63,7 +63,7 @@ else if ( file_exists("../config/config.php") ) { include_once("../config/config.php"); } else { - include_once("rscds_configuration_missing.php"); + include_once("davical_configuration_missing.php"); exit; } if ( !isset($c->page_title) ) $c->page_title = $c->system_name; diff --git a/inc/always.php.in b/inc/always.php.in index edab94fc..7e12936c 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -63,7 +63,7 @@ else if ( file_exists("../config/config.php") ) { include_once("../config/config.php"); } else { - include_once("rscds_configuration_missing.php"); + include_once("davical_configuration_missing.php"); exit; } if ( !isset($c->page_title) ) $c->page_title = $c->system_name; diff --git a/inc/rscds_configuration_missing.php b/inc/davical_configuration_missing.php similarity index 100% rename from inc/rscds_configuration_missing.php rename to inc/davical_configuration_missing.php From 5342039006f9309ae0af0368470b3e1b0e304957 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 15:58:48 +1300 Subject: [PATCH 108/189] More renaming of things. --- INSTALL | 33 +++++++++++++++++---------------- rscds.webprj | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/INSTALL b/INSTALL index fb764883..a60ee6b4 100644 --- a/INSTALL +++ b/INSTALL @@ -50,15 +50,15 @@ I'm available to answer questions, anyway :-) Pre-requisites ============== -RSCDS depends on a number of things. Firstly, it depends +DAViCal depends on a number of things. Firstly, it depends on Andrew's Web Libraries (AWL) which is a set of useful PHP functions and objects written by Andrew McMillan over a number of years. The following other software is also needed: Apache: 1.3.x or 2.x.x - PHP: 4.3 or greater, including PHP5 - PostgreSQL: 7.4 or greater + PHP: 5.0 or greater + PostgreSQL: 8.1 or greater The PostgreSQL database may be installed on a server other than the web server, and that kind of situation is recommended @@ -102,22 +102,24 @@ Apache VHost Configuration Your Apache instance needs to be configured for Virtual Hosts. If this is not already the case you may want to read some documentation about that, and you most likely will want to ensure that any existing -site becomes the **default** virtual host, with RSCDS only being a +site becomes the **default** virtual host, with DAViCal only being a single virtual host. I use a Virtual Host stanza like this: # -# Virtual Host def for Debian packaged RSCDS +# Virtual Host def for Debian packaged DAViCal <VirtualHost 123.4.56.78 > DocumentRoot /usr/share/rscds/htdocs DirectoryIndex index.php index.html - ServerName rscds.example.net + ServerName davical.example.net ServerAlias calendar.example.net Alias /images/ /usr/share/rscds/htdocs/images/ php_value include_path /usr/share/rscds/inc:/usr/share/awl/inc php_value magic_quotes_gpc 0 - php_value register_globals 1 + php_value register_globals 0 + php_value error_reporting "E_ALL & ~E_NOTICE" + php_value default_charset "utf-8" </VirtualHost> Replace 123.4.56.78 with your own IP address, of course (you can @@ -135,25 +137,24 @@ installed from a package. Once your VHost is installed an working correctly, you should be able to browse to that address and see a page telling you that -you need to configure RSCDS. +you need to configure DAViCal. -RSCDS Configuration -=================== +DAViCal Configuration +===================== -The RSCDS configuration generally resides in /etc/rscds/<domain>-conf.php +The DAViCal configuration generally resides in /etc/davical/<domain>-conf.php and is a regular PHP file which sets (or overrides) some specific variables. <?php // $c->domainname = "calendar.example.net"; -// $c->sysabbr = 'rscds'; +// $c->sysabbr = 'davical'; // $c->admin_email = 'admin@example.net'; -// $c->system_name = "Really Simple CalDAV Store"; +// $c->system_name = "DAViCal CalDAV Server"; // $c->collections_always_exist = false; - $c->pg_connect[] = 'dbname=caldav port=5433 user=general'; - $c->pg_connect[] = 'dbname=caldav port=5432 user=general'; + $c->pg_connect[] = 'dbname=davical port=5432 user=general'; ?> @@ -180,7 +181,7 @@ If all is going well you should now be able to browse to the admin pages and log in as 'admin' (the password is the bit after the '**' in the 'password' field of the 'usr' table so: -psql rscds -c 'select username, password from usr;' +psql davical -c 'select username, password from usr;' should show you a list. Note that once you change a password it won't be readable in this way - only the initial configuration diff --git a/rscds.webprj b/rscds.webprj index 50c0f84d..8cf6b11a 100644 --- a/rscds.webprj +++ b/rscds.webprj @@ -29,7 +29,6 @@ <item url="inc/RSCDSSession.php" uploadstatus="1" /> <item url="inc/page-header.php" uploadstatus="1" /> <item url="inc/page-footer.php" uploadstatus="1" /> - <item url="inc/rscds_configuration_missing.php" uploadstatus="1" /> <item url="htdocs/rscds.css" uploadstatus="1" /> <item url="inc/interactive-page.php" uploadstatus="1" /> <item url="htdocs/users.php" uploadstatus="1" /> @@ -245,5 +244,6 @@ <item url="inc/CalDAVPrincipal.php" uploadstatus="1" /> <item url="dba/patches/1.1.11.sql" uploadstatus="1" /> <item url="docs/website/clients/iCal-details.php" uploadstatus="1" /> + <item url="inc/davical_configuration_missing.php" uploadstatus="1" /> </project> </webproject> From 8f48c7c6337070ce0efd663bde925794894a0103 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 16:27:17 +1300 Subject: [PATCH 109/189] More renaming to DAViCal. Updated TODO. --- README | 10 +++++++++- TODO | 10 ++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README b/README index 556d882b..6593db96 100644 --- a/README +++ b/README @@ -1 +1,9 @@ -Really Simple CalDAV Store by Andrew McMillan. +DAViCal CalDAV Server by Andrew McMillan. + +For documentation you are best advised to visit the sourceforge pages +or to start searching from http://davical.org/ and see where you end +up. + +Good luck! + +Andrew McMillan \ No newline at end of file diff --git a/TODO b/TODO index 2b7655ea..0209dd55 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,12 @@ Desirable - - accept the free/busy information as a PUT + - accept the free/busy information as a POST - more translations of the administration interface - translations of the website. - - the ability to see a basic list of event data in the admin interface + - the ability to see a better list of event data in the admin interface - allow a specific CalDAV access permission to delegate free/busy viewability. + - rename everything to "DAViCal" Important - - allow for some sort of modular authentication methods - - + - Fix the relationships code so relationships are controlled by the person + affected (or the admin). + - Implement draft-desruisseaux-caldav-sched specifications. From b491ee17fd4bf5c04f82676d9e2a0b35180ce8aa Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 18:25:40 +1300 Subject: [PATCH 110/189] More careful construction of the database, using a DBA user to own it. --- dba/create-database.sh | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/dba/create-database.sh b/dba/create-database.sh index 96a9b82b..a5acb121 100755 --- a/dba/create-database.sh +++ b/dba/create-database.sh @@ -8,16 +8,38 @@ ADMINPW="${2}" DBADIR="`dirname \"$0\"`" +export AWL_DBAUSER=davical_dba +export AWL_APPUSER=davical_app + +# Get the major version for PostgreSQL +export DBVERSION="`psql -qAt template1 -c "SELECT version();" | cut -f2 -d' ' | cut -f1-2 -d'.'`" + +db_users() { + psql -qAt template1 -c "SELECT usename FROM pg_user;"; +} + +create_db_user() { + if ! db_users | grep "^${1}$" >/dev/null ; then + createuser --no-superuser --no-createdb --no-createrole "${1}" + fi +} + +create_plpgsql_language() { + if ! psql -qAt template1 -c "SELECT lanname FROM pg_language;" | grep "^plpgsql$" >/dev/null; then + createlang plpgsql "${DBNAME}" + fi +} + +create_db_user "${AWL_DBAUSER}" +create_db_user "${AWL_APPUSER}" + # FIXME: Need to check that the database was actually created. -if ! createdb -E UTF8 "${DBNAME}" -T template0 ; then +if ! createdb --encoding UTF8 "${DBNAME}" --template template0 --owner "${AWL_DBAUSER}"; then echo "Unable to create database" exit 1 fi -# -# This will fail if the language already exists, but it should not -# because we created from template0. -createlang plpgsql "${DBNAME}" +create_plpgsql_language # # FIXME: filter non-error output From 3f5b2ae67ad55d8d9575709ce3446197a7b75ac1 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 22:29:34 +1300 Subject: [PATCH 111/189] Another attempt at resolving the URI vs. path issue. See RFC4918, 8.3 --- inc/CalDAVRequest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index 40707d87..ecb93ed5 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -72,6 +72,15 @@ class CalDAVRequest $this->user_agent = ((isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "Probably Mulberry")); + /** + * In general we systematically return Absolute URI hrefs. Unfortunately some + * software doesn't expect this to happen (iCal, SOHO Organizer, ???) and so we + * need to hack around these programs. RFC4918 section 8.3 gives details. + */ + if ( preg_match( '/(iCal 3.0|SOHO Organizer|ChronosCalendarsService)/', $this->user_agent ) ) { + $c->protocol_server_port_script = preg_replace('#^(http|caldav)s?://[^/]+#', '', $c->protocol_server_port_script ); + } + /** * A variety of requests may set the "Depth" header to control recursion */ From 0b4e5b9cb5ee52f382f57a892799053b463d0265 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 22:49:59 +1300 Subject: [PATCH 112/189] Rename SQL definition of database. --- dba/create-database.sh | 2 +- dba/{rscds.sql => davical.sql} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename dba/{rscds.sql => davical.sql} (100%) diff --git a/dba/create-database.sh b/dba/create-database.sh index a5acb121..17b18667 100755 --- a/dba/create-database.sh +++ b/dba/create-database.sh @@ -43,7 +43,7 @@ create_plpgsql_language # # FIXME: filter non-error output -psql -q -f "${DBADIR}/rscds.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" +psql -q -f "${DBADIR}/davical.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" psql -q -f "${DBADIR}/caldav_functions.sql" "${DBNAME}" diff --git a/dba/rscds.sql b/dba/davical.sql similarity index 100% rename from dba/rscds.sql rename to dba/davical.sql From e12139c6368eb24466679efc0553439cf52fa52d Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 22:56:33 +1300 Subject: [PATCH 113/189] Move the inclusion of the AWL tables out of the database SQL. --- dba/create-database.sh | 9 +++++++-- dba/davical.sql | 4 ---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dba/create-database.sh b/dba/create-database.sh index 17b18667..1c888545 100755 --- a/dba/create-database.sh +++ b/dba/create-database.sh @@ -42,7 +42,12 @@ fi create_plpgsql_language # -# FIXME: filter non-error output +# Load the AWL base tables and schema management tables +psql -q -f "/usr/share/awl/dba/awl-tables.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" +psql -q -f "/usr/share/awl/dba/schema-management.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" + +# +# Load the DAViCal tables psql -q -f "${DBADIR}/davical.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" psql -q -f "${DBADIR}/caldav_functions.sql" "${DBNAME}" @@ -61,7 +66,7 @@ fi if [ "$ADMINPW" = "" ] ; then # OK. They didn't supply one, and pwgen didn't work, so we hack something # together from /dev/random ... - ADMINPW="`dd if=/dev/urandom bs=512 count=1 2>/dev/null | tr -c -d "a-zA-HJ-NP-Y0-9" | cut -c2-9`" + ADMINPW="`dd if=/dev/urandom bs=512 count=1 2>/dev/null | tr -c -d "a-km-zA-HJ-NP-Y0-9" | cut -c2-9`" fi if [ "$ADMINPW" = "" ] ; then diff --git a/dba/davical.sql b/dba/davical.sql index ce52431a..b8dc8a0a 100644 --- a/dba/davical.sql +++ b/dba/davical.sql @@ -1,10 +1,6 @@ -- Really Simple CalDAV Store - Database Schema -- --- Use the usr, group and schema management stufffrom libawl-php -\i /usr/share/awl/dba/awl-tables.sql -\i /usr/share/awl/dba/schema-management.sql - -- The main event. Where we store the things the calendar throws at us. CREATE TABLE caldav_data ( user_no INT references usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE, From 0732c60bb286c24dd3db567f80a4515ad0a0dcea Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 22:58:01 +1300 Subject: [PATCH 114/189] Allow the interface to be specified. --- testing/watch-port-80.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/watch-port-80.sh b/testing/watch-port-80.sh index a479496c..f57925f6 100755 --- a/testing/watch-port-80.sh +++ b/testing/watch-port-80.sh @@ -1,5 +1,6 @@ #!/bin/sh PORT=${1:-"80"} +IFACE=${2:-"any"} -sudo tcpdump -i any -s0 -l -n -q -A "tcp port ${PORT} and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)" +sudo tcpdump -i $IFACE -s0 -l -n -q -A "tcp port ${PORT} and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)" From 5895e99d72b801c0facbfa48a59bcc668d6b0996 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 23:34:00 +1300 Subject: [PATCH 115/189] Attempt to autodiscover the AWL code from reasonable locations. --- dba/create-database.sh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/dba/create-database.sh b/dba/create-database.sh index 1c888545..d7dde0fe 100755 --- a/dba/create-database.sh +++ b/dba/create-database.sh @@ -8,6 +8,24 @@ ADMINPW="${2}" DBADIR="`dirname \"$0\"`" +testawldir() { + [ -f "${1}/dba/awl-tables.sql" ] +} + +# +# Attempt to locate the AWL directory +AWLDIR="${DBADIR}/../../awl" +if ! testawldir ; then + AWLDIR="/usr/share/awl" + if ! testawldir ; then + AWLDIR="/usr/local/share/awl" + if ! testawldir ; then + echo "Unable to find AWL libraries" + exit 1 + fi + fi +fi + export AWL_DBAUSER=davical_dba export AWL_APPUSER=davical_app @@ -43,8 +61,8 @@ create_plpgsql_language # # Load the AWL base tables and schema management tables -psql -q -f "/usr/share/awl/dba/awl-tables.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" -psql -q -f "/usr/share/awl/dba/schema-management.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" +psql -q -f "${AWLDIR}/dba/awl-tables.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" +psql -q -f "${AWLDIR}/dba/schema-management.sql" "${DBNAME}" 2>&1 | egrep -v "(^CREATE |^GRANT|^BEGIN|^COMMIT| NOTICE: )" # # Load the DAViCal tables From 357fcc5cee166258e8232e90c08895240ad54724 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 23:39:29 +1300 Subject: [PATCH 116/189] Fix thinko. --- dba/create-database.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dba/create-database.sh b/dba/create-database.sh index d7dde0fe..a944cac6 100755 --- a/dba/create-database.sh +++ b/dba/create-database.sh @@ -15,11 +15,11 @@ testawldir() { # # Attempt to locate the AWL directory AWLDIR="${DBADIR}/../../awl" -if ! testawldir ; then +if ! testawldir "${AWLDIR}"; then AWLDIR="/usr/share/awl" - if ! testawldir ; then + if ! testawldir "${AWLDIR}"; then AWLDIR="/usr/local/share/awl" - if ! testawldir ; then + if ! testawldir "${AWLDIR}"; then echo "Unable to find AWL libraries" exit 1 fi From 21ad58449eeda76d633b8d14200eb59e10d6607f Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 23:40:00 +1300 Subject: [PATCH 117/189] Don't limit our visible functionality at / --- htdocs/caldav.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/caldav.php b/htdocs/caldav.php index cfe665cd..5a82cd0a 100644 --- a/htdocs/caldav.php +++ b/htdocs/caldav.php @@ -23,7 +23,6 @@ dbg_log_array( "headers", '_SERVER', $_SERVER, true ); * in all (or even much of) it's glory really. */ $dav = "1, 2, access-control, calendar-access"; -if ( $_SERVER['PATH_INFO'] == '/' || $_SERVER['PATH_INFO'] == '' ) $dav = "1, access-control"; header( "DAV: $dav"); // header( "DAV: 1, 2, access-control, calendar-access, calendar-schedule"); From 501a6e215c94795314b1a20a240d46d4240747ee Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 23:41:49 +1300 Subject: [PATCH 118/189] Return the session user's home-url when called on / --- inc/caldav-PROPFIND.php | 10 +++++----- .../tests/regression-suite/511-iCal-PROPFIND.result | 12 +++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index c40ffb94..4885aa48 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -77,16 +77,16 @@ foreach( $request->xml_tags AS $k => $v ) { case 'SUPPORTED-PRIVILEGE-SET': /** supported-privilege-set - should work fine */ case 'CURRENT-USER-PRIVILEGE-SET': /** current-user-privilege-set - only vaguely supported */ case 'ALLPROP': /** allprop - limited support */ - $attribute_list[$tag] = 1; - dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag ); - break; - - /** * Handled CalDAV properties */ case 'CALENDAR-HOME-SET': /** calendar-home-set is used by iCal in Leopard - should work fine */ + $attribute_list[$tag] = 1; + dbg_error_log( "PROPFIND", "Adding %s attribute '%s'", $namespace, $tag ); + break; + + case 'SUPPORTED-COLLATION-SET': /** fixed server definition - should work fine */ case 'SUPPORTED-CALENDAR-COMPONENT-SET': /** fixed server definition - should work fine */ diff --git a/testing/tests/regression-suite/511-iCal-PROPFIND.result b/testing/tests/regression-suite/511-iCal-PROPFIND.result index 4a044e58..35da6638 100644 --- a/testing/tests/regression-suite/511-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/511-iCal-PROPFIND.result @@ -1,23 +1,25 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, access-control -ETag: "af62dedcedd04f04e042beb9408793c2" -Content-Length: 740 +DAV: 1, 2, access-control, calendar-access +ETag: "3c6167921378348411a110b1db03b7d4" +Content-Length: 796 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> -<multistatus xmlns="DAV:"> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> <href>/</href> <propstat> <prop> <displayname>DAViCal_CalDAV_Server</displayname> + <C:calendar-home-set> + <href>/user1/</href> + </C:calendar-home-set> </prop> <status>HTTP/1.1 200 OK</status> </propstat> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav"/> <calendar-user-address-set xmlns="urn:ietf:params:xml:ns:caldav"/> <schedule-inbox-url xmlns="urn:ietf:params:xml:ns:caldav"/> <schedule-outbox-url xmlns="urn:ietf:params:xml:ns:caldav"/> From 3005cb4689f2c4e721a271dc6998415803ed2215 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 5 Nov 2007 23:44:42 +1300 Subject: [PATCH 119/189] Various test results change as a result of the DAV header change. --- testing/tests/regression-suite/001-Mulberry-1.result | 2 +- testing/tests/regression-suite/002-Mulberry-1.result | 2 +- testing/tests/regression-suite/831-Spec-RRULE-1.result | 2 +- testing/tests/regression-suite/860-Spec-REPORT-principal.result | 2 +- testing/tests/regression-suite/861-Spec-REPORT-principal.result | 2 +- testing/tests/regression-suite/862-Spec-REPORT-principal.result | 2 +- testing/tests/regression-suite/863-Spec-REPORT-principal.result | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/testing/tests/regression-suite/001-Mulberry-1.result b/testing/tests/regression-suite/001-Mulberry-1.result index 1e55920e..85ac1a87 100644 --- a/testing/tests/regression-suite/001-Mulberry-1.result +++ b/testing/tests/regression-suite/001-Mulberry-1.result @@ -1,6 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, access-control +DAV: 1, 2, access-control, calendar-access Allow: OPTIONS, GET, HEAD, PROPFIND, REPORT Content-Length: 0 Content-Type: text/plain; charset="utf-8" diff --git a/testing/tests/regression-suite/002-Mulberry-1.result b/testing/tests/regression-suite/002-Mulberry-1.result index e0186618..08ee7e7c 100644 --- a/testing/tests/regression-suite/002-Mulberry-1.result +++ b/testing/tests/regression-suite/002-Mulberry-1.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, access-control +DAV: 1, 2, access-control, calendar-access ETag: "4f1f49d6e908f8ccfab25f51d1e08658" Content-Length: 1970 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/831-Spec-RRULE-1.result b/testing/tests/regression-suite/831-Spec-RRULE-1.result index 9662ed55..da710c29 100644 --- a/testing/tests/regression-suite/831-Spec-RRULE-1.result +++ b/testing/tests/regression-suite/831-Spec-RRULE-1.result @@ -1,6 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, access-control +DAV: 1, 2, access-control, calendar-access Content-Length: 5020 Content-Type: text/plain diff --git a/testing/tests/regression-suite/860-Spec-REPORT-principal.result b/testing/tests/regression-suite/860-Spec-REPORT-principal.result index a0de0bfb..adb16f6d 100644 --- a/testing/tests/regression-suite/860-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/860-Spec-REPORT-principal.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, access-control +DAV: 1, 2, access-control, calendar-access ETag: "c345629a9689adce5411818c3c29aa43" Content-Length: 358 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/861-Spec-REPORT-principal.result b/testing/tests/regression-suite/861-Spec-REPORT-principal.result index 7ba2e2f1..7b9526f7 100644 --- a/testing/tests/regression-suite/861-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/861-Spec-REPORT-principal.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, access-control +DAV: 1, 2, access-control, calendar-access ETag: "8ee6bd9a1b7e15f40e6e24f149c6bf20" Content-Length: 3720 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/862-Spec-REPORT-principal.result b/testing/tests/regression-suite/862-Spec-REPORT-principal.result index de8c2367..c55a5655 100644 --- a/testing/tests/regression-suite/862-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/862-Spec-REPORT-principal.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, access-control +DAV: 1, 2, access-control, calendar-access ETag: "d8fe1f4720e6249cb2fb0711fbed9794" Content-Length: 688 Content-Type: text/xml; charset="utf-8" diff --git a/testing/tests/regression-suite/863-Spec-REPORT-principal.result b/testing/tests/regression-suite/863-Spec-REPORT-principal.result index db2ad115..7b38fea1 100644 --- a/testing/tests/regression-suite/863-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/863-Spec-REPORT-principal.result @@ -1,6 +1,6 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT -DAV: 1, access-control +DAV: 1, 2, access-control, calendar-access ETag: "f9a0b07b2c7b0347a9ae26a412baef6b" Content-Length: 743 Content-Type: text/xml; charset="utf-8" From 2108144edf5dbfe054dde362b33957f2d2e34203 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 00:28:49 +1300 Subject: [PATCH 120/189] Don't duplicate the collection response when we get Depth: infinity --- inc/caldav-PROPFIND.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 4885aa48..1034acb5 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -532,7 +532,7 @@ function get_collection_contents( $depth, $user_no, $collection ) { while( $subcollection = $qry->Fetch() ) { $responses[] = collection_to_xml( $subcollection ); if ( $depth > 0 ) { - $responses = array_merge( $responses, get_collection( $depth - 1, $user_no, $subcollection->dav_name ) ); + $responses = array_merge( $responses, get_collection_contents( $depth - 1, $user_no, $subcollection ) ); } } } @@ -616,6 +616,7 @@ function get_collection( $depth, $user_no, $collection_path ) { return $responses; } + /** * Get XML response for a single item. Depth is irrelevant for this. */ From 42521a798c22a7fe9a4c4cf8dfe7dc2fe6b8df06 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 00:30:19 +1300 Subject: [PATCH 121/189] Some tests emulating SOHO Organizer and similar approaches. --- .../regression-suite/600-Soho-OPTIONS.result | 7 + .../regression-suite/600-Soho-OPTIONS.test | 8 + .../regression-suite/601-Soho-OPTIONS.result | 7 + .../regression-suite/601-Soho-OPTIONS.test | 7 + .../regression-suite/602-Soho-PROPFIND.result | 220 ++++++++++++++++++ .../regression-suite/602-Soho-PROPFIND.test | 13 ++ .../regression-suite/603-Soho-PROPFIND.result | 52 +++++ .../regression-suite/603-Soho-PROPFIND.test | 16 ++ .../regression-suite/604-Soho-PROPFIND.result | 31 +++ .../regression-suite/604-Soho-PROPFIND.test | 16 ++ 10 files changed, 377 insertions(+) create mode 100644 testing/tests/regression-suite/600-Soho-OPTIONS.result create mode 100644 testing/tests/regression-suite/600-Soho-OPTIONS.test create mode 100644 testing/tests/regression-suite/601-Soho-OPTIONS.result create mode 100644 testing/tests/regression-suite/601-Soho-OPTIONS.test create mode 100644 testing/tests/regression-suite/602-Soho-PROPFIND.result create mode 100644 testing/tests/regression-suite/602-Soho-PROPFIND.test create mode 100644 testing/tests/regression-suite/603-Soho-PROPFIND.result create mode 100644 testing/tests/regression-suite/603-Soho-PROPFIND.test create mode 100644 testing/tests/regression-suite/604-Soho-PROPFIND.result create mode 100644 testing/tests/regression-suite/604-Soho-PROPFIND.test diff --git a/testing/tests/regression-suite/600-Soho-OPTIONS.result b/testing/tests/regression-suite/600-Soho-OPTIONS.result new file mode 100644 index 00000000..33fda4cd --- /dev/null +++ b/testing/tests/regression-suite/600-Soho-OPTIONS.result @@ -0,0 +1,7 @@ +HTTP/1.1 401 Unauthorized +Date: Dow, 01 Jan 2000 00:00:00 GMT +WWW-Authenticate: Basic realm="DAViCal CalDAV Server" +Content-Length: 40 +Content-Type: text/plain; ; charset="utf-8" + +Please log in for access to this system. \ No newline at end of file diff --git a/testing/tests/regression-suite/600-Soho-OPTIONS.test b/testing/tests/regression-suite/600-Soho-OPTIONS.test new file mode 100644 index 00000000..64bab6c1 --- /dev/null +++ b/testing/tests/regression-suite/600-Soho-OPTIONS.test @@ -0,0 +1,8 @@ +# +# Do an initial OPTIONS request (unauthenticated) +TYPE=OPTIONS +URL=http://mycaldav/caldav.php/user1/ +NOAUTH + +HEADER=User-Agent: SOHO Organizer/6.5.2 libcurl/7.17.0 OpenSSL/0.9.7l zlib/1.2.3 libssh2/0.17 +HEAD diff --git a/testing/tests/regression-suite/601-Soho-OPTIONS.result b/testing/tests/regression-suite/601-Soho-OPTIONS.result new file mode 100644 index 00000000..b8f2be75 --- /dev/null +++ b/testing/tests/regression-suite/601-Soho-OPTIONS.result @@ -0,0 +1,7 @@ +HTTP/1.1 200 OK +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +Allow: OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT, PROPPATCH +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + diff --git a/testing/tests/regression-suite/601-Soho-OPTIONS.test b/testing/tests/regression-suite/601-Soho-OPTIONS.test new file mode 100644 index 00000000..d2e5145a --- /dev/null +++ b/testing/tests/regression-suite/601-Soho-OPTIONS.test @@ -0,0 +1,7 @@ +# +# Do an initial OPTIONS request (authenticated) +TYPE=OPTIONS +URL=http://mycaldav/caldav.php/user1/ + +HEADER=User-Agent: SOHO Organizer/6.5.2 libcurl/7.17.0 OpenSSL/0.9.7l zlib/1.2.3 libssh2/0.17 +HEAD diff --git a/testing/tests/regression-suite/602-Soho-PROPFIND.result b/testing/tests/regression-suite/602-Soho-PROPFIND.result new file mode 100644 index 00000000..69528def --- /dev/null +++ b/testing/tests/regression-suite/602-Soho-PROPFIND.result @@ -0,0 +1,220 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "f501a70013d679ecd57dc0981fdb62e1" +Content-Length: 5847 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> + <response> + <href>/caldav.php/user1/</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> + <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> + <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/0575d895-a006-4ed8-9be6-0d1b6b6b1f96.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/1906b3ca-4890-468a-9b58-1de74bf2c716.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/20061101T073004Z.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/2178279a-aec2-471f-832d-1f6df6203f2f.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/71e2ae82-7870-11db-c6d6-f6927c144649.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/917b9e47-b748-4550-a566-657fbe672447.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/9d050be7-8a02-4355-8ed3-02a9fc5f473f.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/b1679f77-673d-4f46-b3eb-2420e1bba301.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/602-Soho-PROPFIND.test b/testing/tests/regression-suite/602-Soho-PROPFIND.test new file mode 100644 index 00000000..c81ff147 --- /dev/null +++ b/testing/tests/regression-suite/602-Soho-PROPFIND.test @@ -0,0 +1,13 @@ +# +# SOHO Organizer works best looking at the person +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/ +HEADER=User-Agent: SOHO Organizer/6.5.2 libcurl/7.17.0 OpenSSL/0.9.7l zlib/1.2.3 libssh2/0.17 +HEADER=Content-Type: text/xml; charset=utf-8 +HEAD + + +BEGINDATA +<?xml version="1.0" encoding="utf-8"?><r0:propfind xmlns:r0="DAV:" xmlns:r1="urn:ietf:params:xml:ns:caldav" xmlns:r2="http://apple.com/ns/calendarserver/"><r0:prop><r1:calendar-home-set/><r1:calendar-user-address-set/><r2:dropbox-home-URL/><r2:notifications-URL/></r0:prop></r0:propfind> +ENDDATA diff --git a/testing/tests/regression-suite/603-Soho-PROPFIND.result b/testing/tests/regression-suite/603-Soho-PROPFIND.result new file mode 100644 index 00000000..0aa867ef --- /dev/null +++ b/testing/tests/regression-suite/603-Soho-PROPFIND.result @@ -0,0 +1,52 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "82a2af4a319c7702f65e131574e63754" +Content-Length: 1261 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> + <response> + <href>/caldav.php/user1/</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> + <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> + <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/603-Soho-PROPFIND.test b/testing/tests/regression-suite/603-Soho-PROPFIND.test new file mode 100644 index 00000000..c9b73abf --- /dev/null +++ b/testing/tests/regression-suite/603-Soho-PROPFIND.test @@ -0,0 +1,16 @@ +# +# SOHO Organizer works best looking at the person +# +# Now imagine what would happen if they supplied a 'Depth: 1' header! +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/ +HEADER=User-Agent: SOHO Organizer/6.5.2 libcurl/7.17.0 OpenSSL/0.9.7l zlib/1.2.3 libssh2/0.17 +HEADER=Content-Type: text/xml; charset=utf-8 +HEADER=Depth: 1 +HEAD + + +BEGINDATA +<?xml version="1.0" encoding="utf-8"?><r0:propfind xmlns:r0="DAV:" xmlns:r1="urn:ietf:params:xml:ns:caldav" xmlns:r2="http://apple.com/ns/calendarserver/"><r0:prop><r1:calendar-home-set/><r1:calendar-user-address-set/><r2:dropbox-home-URL/><r2:notifications-URL/></r0:prop></r0:propfind> +ENDDATA diff --git a/testing/tests/regression-suite/604-Soho-PROPFIND.result b/testing/tests/regression-suite/604-Soho-PROPFIND.result new file mode 100644 index 00000000..17697d3c --- /dev/null +++ b/testing/tests/regression-suite/604-Soho-PROPFIND.result @@ -0,0 +1,31 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "c240d5bc59682fd96a47d4b802052879" +Content-Length: 689 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> + <response> + <href>/caldav.php/user1/</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> + <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/604-Soho-PROPFIND.test b/testing/tests/regression-suite/604-Soho-PROPFIND.test new file mode 100644 index 00000000..afb9af48 --- /dev/null +++ b/testing/tests/regression-suite/604-Soho-PROPFIND.test @@ -0,0 +1,16 @@ +# +# SOHO Organizer works best looking at the person +# +# Suppose there were a Depth: 0 header? +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/ +HEADER=User-Agent: SOHO Organizer/6.5.2 libcurl/7.17.0 OpenSSL/0.9.7l zlib/1.2.3 libssh2/0.17 +HEADER=Content-Type: text/xml; charset=utf-8 +HEADER=Depth: 0 +HEAD + + +BEGINDATA +<?xml version="1.0" encoding="utf-8"?><r0:propfind xmlns:r0="DAV:" xmlns:r1="urn:ietf:params:xml:ns:caldav" xmlns:r2="http://apple.com/ns/calendarserver/"><r0:prop><r1:calendar-home-set/><r1:calendar-user-address-set/><r2:dropbox-home-URL/><r2:notifications-URL/></r0:prop></r0:propfind> +ENDDATA From 786e73f56b28b3107dd4b63aa50933c6d50440bf Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 14:52:13 +1300 Subject: [PATCH 122/189] Authentication against PAM via Squid helper by Eric Seigne. --- config/example-config.php | 10 +++++ inc/drivers_squid_pam.php | 83 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 inc/drivers_squid_pam.php diff --git a/config/example-config.php b/config/example-config.php index 8942b67c..ef1cbd88 100644 --- a/config/example-config.php +++ b/config/example-config.php @@ -198,6 +198,16 @@ $c->admin_email ='calendar-admin@example.com'; //include('drivers_ldap.php'); +/** +* Authentication against PAM using the Squid helper script. +*/ +//$c->authenticate_hook = array( +// 'call' => 'SQUID_PAM_check', +// 'config' => array( 'script' => '/usr/bin/pam_auth', 'email_base' => 'example.com' ); +// ); +//include('drivers_squid_pam.php'); + + /** * The default locale will be "en_NZ"; * If you are in a non-English locale, you can set the default_locale diff --git a/inc/drivers_squid_pam.php b/inc/drivers_squid_pam.php new file mode 100644 index 00000000..39230ad6 --- /dev/null +++ b/inc/drivers_squid_pam.php @@ -0,0 +1,83 @@ +<?php +/** +* Manages PAM repository connection with SQUID help +* +* @package davical +* @category Technical +* @subpackage ldap +* @author Eric Seigne <eric.seigne@ryxeo.com> +* @copyright Eric Seigne +* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 +*/ + +require_once("auth-functions.php"); + +class squidPamDrivers +{ + /**#@+ + * @access private + */ + + /**#@-*/ + + + /** + * Constructor. + * @param string $config path where /usr/lib/squid/pam_auth is + */ + function squidPamDrivers($config){ + $this->__construct($config); + } + + + /** + * The constructor + * + * @param string $config path where /usr/lib/squid/pam_auth is + */ + function __construct($config) + { + global $c; + if (! file_exists($config)){ + $c->messages[] = sprintf(i18n( "drivers_squid_pam : Unable to find %s file"), $config ); + $this->valid=false; + return ; + } + } +} + + +/** +* Check the username / password against the PAM system +*/ +function SQUID_PAM_check($username, $password ){ + global $c; + + $cmd = "echo '" . $username . "' '" . $password . "' | " . $c->authenticate_hook['config']['script'] . " -n common-auth"; + $auth_result = exec($cmd); + if ( $auth_result == "OK") { + if ( $usr = getUserByName($username) ) { + return $usr; + } + else { + dbg_error_log( "PAM", "user %s doesn't exist in local DB, we need to create it",$username ); + $fullname = trim( exec("getent passwd | grep ^" . $username ." | cut -d \":\" -f5"), ' ,' ); + $usr = (object) array( + 'user_no' => 0, + 'username' => $username, + 'active' => 't', + 'email' => $username . "@" . $c->authenticate_hook['config']['email_base'], + 'updated' => date(), + 'fullname' => $fullname + ); + + UpdateUserFromExternal( $usr ); + return $usr; + } + } + else { + dbg_error_log( "PAM", "User %s is not a valid username (or password was wrong)", $username ); + return false; + } + +} From 175ba171469fc6813b7f8c2bdae6ff012b43ad13 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 16:15:02 +1300 Subject: [PATCH 123/189] Renaming of RSCDS to DAViCal. --- config/debug-config.php | 13 +++++++------ config/example-config.php | 8 ++++---- config/other-config.php | 1 - 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/config/debug-config.php b/config/debug-config.php index 1307c7c0..2c13d791 100644 --- a/config/debug-config.php +++ b/config/debug-config.php @@ -6,7 +6,7 @@ */ /** -* if this is set then any e-mail that would normally be sent by RSCDS will be +* if this is set then any e-mail that would normally be sent by DAViCal will be * sent to this e-mail address for debugging. */ //$c->debug_email @@ -29,21 +29,23 @@ // $c->dbg['querystring'] = 1; // $c->dbg['icalendar'] = 1; // $c->dbg['ics'] = 1; -// $c->dbg['Login'] = 1; +// $c->dbg['login'] = 1; // $c->dbg['options'] = 1; // $c->dbg['get'] = 1; // $c->dbg['put'] = 1; // $c->dbg['propfind'] = 1; +// $c->dbg['proppatch'] = 1; // $c->dbg['report'] = 1; +// $c->dbg['principal'] = 1; // $c->dbg['user'] = 1; // $c->dbg['vevent'] = 1; // $c->dbg['rrule'] = 1; /** -* default is 'rscds' used to prefix debugging messages but will only need to change -* if you are running multiple RSCDS servers logging into the same place. +* default is 'davical' used to prefix debugging messages but will only need to change +* if you are running multiple DAViCal servers logging into the same place. */ -// $c->sysabbr +// $c->sysabbr = 'davical'; /** * As yet we only support quite a limited range of options. When we see clients looking @@ -55,4 +57,3 @@ */ // $c->override_allowed_methods = "PROPPATCH, OPTIONS, GET, HEAD, PUT, DELETE, PROPFIND, MKCOL, MKCALENDAR, LOCK, UNLOCK, REPORT" -?> \ No newline at end of file diff --git a/config/example-config.php b/config/example-config.php index ef1cbd88..4b076568 100644 --- a/config/example-config.php +++ b/config/example-config.php @@ -10,14 +10,14 @@ *****************************/ /** -* Ex : $c->pg_connect[] = 'dbname=rscds port=5432 user=general' +* Ex : $c->pg_connect[] = 'dbname=davical port=5432 user=general' * The application will attempt to * connect to the database, successively applying connection parameters from * the array in $c->pg_connect. * used in the web interface but also the caldav Server */ -$c->pg_connect[] = "dbname=rscds user=general"; -// $c->pg_connect[] = "dbname=rscds user=general port=5433 host=somehost password=mypass"; +$c->pg_connect[] = "dbname=davical user=general"; +// $c->pg_connect[] = "dbname=davical user=general port=5433 host=somehost password=mypass"; /**************************** @@ -66,7 +66,7 @@ $c->admin_email ='calendar-admin@example.com'; * <p>The "enable_row_linking" option controls whether javascript is used * to make the entire row clickable in browse lists in the administration * pages. Since this doesn't work in Konqueror you may want to set this -* to false if you expect people to be using Konqueror with the RSCDS +* to false if you expect people to be using Konqueror with the DAViCal * administration pages.</p> */ // $c->enable_row_linking = true; diff --git a/config/other-config.php b/config/other-config.php index e58b7e84..1cc92414 100644 --- a/config/other-config.php +++ b/config/other-config.php @@ -84,4 +84,3 @@ // $c->schema_patch // $c->schema_version -?> \ No newline at end of file From c4e30158539d01e4f8b3e2080417903771dec50b Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 16:15:20 +1300 Subject: [PATCH 124/189] Renaming from RSCDS to DAViCal --- htdocs/css/browse.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/css/browse.css b/htdocs/css/browse.css index feeb1377..c0874b3f 100644 --- a/htdocs/css/browse.css +++ b/htdocs/css/browse.css @@ -1,4 +1,4 @@ -/* CSS for browse pages in RSCDS */ +/* CSS for browse pages in DAViCal */ tr.header th, td { padding: 1px 4px; From 8ade4ce1715ac30eefb8d107bd3c00b270464938 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 16:15:59 +1300 Subject: [PATCH 125/189] Added files. --- rscds.webprj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rscds.webprj b/rscds.webprj index 8cf6b11a..8eeed00d 100644 --- a/rscds.webprj +++ b/rscds.webprj @@ -23,7 +23,6 @@ <item url="htdocs/caldav.php" uploadstatus="1" /> <item url="debian/" uploadstatus="1" /> <item url="debian/rules" uploadstatus="1" /> - <item url="dba/rscds.sql" uploadstatus="1" /> <item url="htdocs/freebusy.php" uploadstatus="1" /> <item url="htdocs/index.php" uploadstatus="1" /> <item url="inc/RSCDSSession.php" uploadstatus="1" /> @@ -245,5 +244,7 @@ <item url="dba/patches/1.1.11.sql" uploadstatus="1" /> <item url="docs/website/clients/iCal-details.php" uploadstatus="1" /> <item url="inc/davical_configuration_missing.php" uploadstatus="1" /> + <item url="dba/davical.sql" uploadstatus="1" /> + <item url="inc/drivers_squid_pam.php" uploadstatus="1" /> </project> </webproject> From 4369479faff9bdd139a14080e175c53ddc59a8ed Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 16:18:05 +1300 Subject: [PATCH 126/189] Renamed Quantas project file. --- rscds.webprj => davical.webprj | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rscds.webprj => davical.webprj (100%) diff --git a/rscds.webprj b/davical.webprj similarity index 100% rename from rscds.webprj rename to davical.webprj From a37a68b8ca2054315f7e5c9a3d5b61c524b69ff5 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 16:18:19 +1300 Subject: [PATCH 127/189] Ignore Quanta droppings. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0460cc58..03a1e04b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ caldav.session rscds.session +davical.session build rscds.bfproject +davical.bfproject locale built-docs built-po From d99f8ccc35681aac0540b93763ad0028c4c31ec7 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 17:29:22 +1300 Subject: [PATCH 128/189] Enforce a trailling '/' on collections when they are created. --- inc/caldav-MKCALENDAR.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inc/caldav-MKCALENDAR.php b/inc/caldav-MKCALENDAR.php index 30c35270..4c77affb 100644 --- a/inc/caldav-MKCALENDAR.php +++ b/inc/caldav-MKCALENDAR.php @@ -15,6 +15,10 @@ if ( ! $request->AllowedTo('mkcalendar') ) { } $displayname = $request->path; + +// Enforce trailling '/' on collection name +if ( ! preg_match( '#/$#', $request->path ) ) $request->path .= '/'; + $parent_container = '/'; if ( preg_match( '#^(.*/)([^/]+)(/)?$#', $request->path, $matches ) ) { $parent_container = $matches[1]; From dfef442ee5d21b7c9b3d3e31b8c78b92cd136953 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 18:31:35 +1300 Subject: [PATCH 129/189] When a calendar is created with XML, then it's parent will be the target URL. --- inc/caldav-MKCALENDAR.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/inc/caldav-MKCALENDAR.php b/inc/caldav-MKCALENDAR.php index 4c77affb..458bd6bd 100644 --- a/inc/caldav-MKCALENDAR.php +++ b/inc/caldav-MKCALENDAR.php @@ -17,7 +17,10 @@ if ( ! $request->AllowedTo('mkcalendar') ) { $displayname = $request->path; // Enforce trailling '/' on collection name -if ( ! preg_match( '#/$#', $request->path ) ) $request->path .= '/'; +if ( ! preg_match( '#/$#', $request->path ) ) { + dbg_error_log( "MKCALENDAR", "Add trailling '/' to '%s'", $request->path); + $request->path .= '/'; +} $parent_container = '/'; if ( preg_match( '#^(.*/)([^/]+)(/)?$#', $request->path, $matches ) ) { @@ -46,6 +49,7 @@ if ( isset($request->xml_tags) ) { case 'DAV::DISPLAYNAME': $displayname = $content; + $request->path .= $content . '/'; $success[$tag] = 1; break; From 03d82193cca563803bc0e7c9eb48300038267ad3 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 18:46:54 +1300 Subject: [PATCH 130/189] Also put arbitrary properties along with the calendar. --- inc/caldav-MKCALENDAR.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/inc/caldav-MKCALENDAR.php b/inc/caldav-MKCALENDAR.php index 458bd6bd..def4adbe 100644 --- a/inc/caldav-MKCALENDAR.php +++ b/inc/caldav-MKCALENDAR.php @@ -49,6 +49,8 @@ if ( isset($request->xml_tags) ) { case 'DAV::DISPLAYNAME': $displayname = $content; + dbg_error_log( "MKCALENDAR", "Displayname is '/' to '%s'", $request->path); + $parent_container = $request->path; $request->path .= $content . '/'; $success[$tag] = 1; break; @@ -117,7 +119,7 @@ if ( $qry->rows != 0 ) { $request->DoResponse( 405, translate("A collection already exists at that location.") ); } -$sql = "INSERT INTO collection ( user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp );"; +$sql = "BEGIN; INSERT INTO collection ( user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, created, modified ) VALUES( ?, ?, ?, ?, ?, ?, current_timestamp, current_timestamp ); $propertysql; COMMIT;"; $qry = new PgQuery( $sql, $request->user_no, $parent_container, $request->path, md5($request->user_no. $request->path), $displayname, ($request->method == 'MKCALENDAR') ); if ( $qry->Exec("MKCALENDAR",__LINE__,__FILE__) ) { From 54946e1f6ad766e13819e92cd142ad197a4127dc Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 22:46:49 +1300 Subject: [PATCH 131/189] MKCALENDAR result issued from SOHO Organizer. --- .../605-Soho-MKCALENDAR.result | 7 ++++ .../regression-suite/605-Soho-MKCALENDAR.test | 39 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 testing/tests/regression-suite/605-Soho-MKCALENDAR.result create mode 100644 testing/tests/regression-suite/605-Soho-MKCALENDAR.test diff --git a/testing/tests/regression-suite/605-Soho-MKCALENDAR.result b/testing/tests/regression-suite/605-Soho-MKCALENDAR.result new file mode 100644 index 00000000..6b4bc2bf --- /dev/null +++ b/testing/tests/regression-suite/605-Soho-MKCALENDAR.result @@ -0,0 +1,7 @@ +HTTP/1.1 201 Created +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +Cache-Control: no-cache +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + diff --git a/testing/tests/regression-suite/605-Soho-MKCALENDAR.test b/testing/tests/regression-suite/605-Soho-MKCALENDAR.test new file mode 100644 index 00000000..0c30cc67 --- /dev/null +++ b/testing/tests/regression-suite/605-Soho-MKCALENDAR.test @@ -0,0 +1,39 @@ +# +# SOHO Organizer works best looking at the person +# +# Make a new calendar for the user +# +TYPE=MKCALENDAR +URL=http://mycaldav/caldav.php/user1/ + +HEADER=User-Agent: SOHO Organizer/6.5.2 libcurl/7.17.0 OpenSSL/0.9.7l zlib/1.2.3 libssh2/0.17 +HEADER=Content-Type: text/xml; charset=utf-8 +HEADER=Accept: */* +HEADER=Content-Type: application/xml; charset="utf-8" + +HEAD + + +# Reformatted for readability +BEGINDATA +<?xml version="1.0" encoding="utf-8" ?> +<C:mkcalendar xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="com.apple.ical:"> + <D:set> + <D:prop> + <D:displayname>SOHO+collection</D:displayname> + <I:calendarcolor>#0000FFFF</I:calendarcolor> + <C:supported-calendar-component-set> + <C:comp name="VEVENT"/> + <C:comp name="VTODO"/> + <C:comp name="VTIMEZONE"/> + <C:comp name="VJOURNAL"/> + <C:comp name="VFREEBUSY"/> + </C:supported-calendar-component-set> + </D:prop> + </D:set> +</C:mkcalendar> +ENDDATA + +QUERY +SELECT * FROM collection WHERE dav_name = '/user1/SOHO+collection'; +ENDQUERY From 74db580cb6aa15f67445d385f297bcc285ad56ff Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 22:47:20 +1300 Subject: [PATCH 132/189] PROPPATCH result from SOHO Organizer. --- .../606-Soho-PROPPATCH.result | 14 ++++++++++ .../regression-suite/606-Soho-PROPPATCH.test | 26 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 testing/tests/regression-suite/606-Soho-PROPPATCH.result create mode 100644 testing/tests/regression-suite/606-Soho-PROPPATCH.test diff --git a/testing/tests/regression-suite/606-Soho-PROPPATCH.result b/testing/tests/regression-suite/606-Soho-PROPPATCH.result new file mode 100644 index 00000000..b554a5ae --- /dev/null +++ b/testing/tests/regression-suite/606-Soho-PROPPATCH.result @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +Content-Location: /user1/SOHO+collection/ +Content-Length: 235 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:"> + <response> + <href>/caldav.php/user1/SOHO+collection/</href> + <responsedescription>All requested changes were made.</responsedescription> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/606-Soho-PROPPATCH.test b/testing/tests/regression-suite/606-Soho-PROPPATCH.test new file mode 100644 index 00000000..40065594 --- /dev/null +++ b/testing/tests/regression-suite/606-Soho-PROPPATCH.test @@ -0,0 +1,26 @@ +# +# SOHO Organizer works best looking at the person +# +# Make some changes to the calendar properties +# +TYPE=PROPPATCH + +# Note the URL doesn't have a trailling '/' +URL=http://mycaldav/caldav.php/user1/SOHO+collection + +HEADER=User-Agent: SOHO Organizer/6.5.2 libcurl/7.17.0 OpenSSL/0.9.7l zlib/1.2.3 libssh2/0.17 +HEADER=Content-Type: text/xml; charset=utf-8 +HEADER=Accept: */* +HEADER=Content-Type: application/xml; charset="utf-8" + +HEAD + + +BEGINDATA +<?xml version="1.0" encoding="utf-8" ?><D:propertyupdate xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="com.apple.ical:"><D:set><D:prop><D:displayname>home</D:displayname><C:calendar-description>Calendar description</C:calendar-description><I:calendarcolor>#FF8000FF</I:calendarcolor></D:prop></D:set></D:propertyupdate> +ENDDATA + +QUERY +SELECT * FROM collection JOIN property USING (dav_name) + WHERE collection.dav_name = '/user1/SOHO+collection'; +ENDQUERY From 68ccaed0c4b30406edc15d655a11471fb576b117 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 6 Nov 2007 22:48:36 +1300 Subject: [PATCH 133/189] Results change due to SOHO Organizer tests added. --- .../tests/regression-suite/840-Spec-PROPPATCH-1.result | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result index b39a61c1..09ae75ec 100644 --- a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result +++ b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result @@ -16,3 +16,12 @@ User One's Calendar --- faf25336de0e470a54075c14cbcf5272 --- 0 --- 1 <DAV::HREF>http://www.example.com/acl/users/jim</DAV::HREF> --- 10 --- 1 /user1/home/ --- URN:MCMILLAN:BOGUS:XML:NS:RSCDS:ARBITRARY --- A completely bogus property which should be saved. --- 10 --- 1 +/user1/SOHO+collection/ --- COM.APPLE.ICAL::CALENDARCOLOR --- #FF8000FF --- 10 --- 0 +/user1/SOHO+collection/ --- URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DESCRIPTION --- Calendar description --- 10 --- 0 +/user1/SOHO+collection/ --- URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET --- + <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VEVENT"/> + <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VTODO"/> + <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VTIMEZONE"/> + <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VJOURNAL"/> + <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VFREEBUSY"/> + --- 10 --- 0 From d327417aba55b0f3da9dc47c3f12b5903eaf9fb1 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Wed, 14 Nov 2007 15:34:55 +1300 Subject: [PATCH 134/189] Rationalise where all those dumps go. --- .gitignore | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 03a1e04b..0064ddf1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,5 @@ built-docs built-po .settings *~ -testing/*.stream -testing/*.cap -testing/*.pcap -testing/*.dump +testing/dumps testing/regression.conf From 00a7f64159c428c2389ba42fc6d6e887e7006acc Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Wed, 14 Nov 2007 15:35:21 +1300 Subject: [PATCH 135/189] Tweaks to both of these programs. --- testing/sniffstream | 3 ++- testing/watch-port-80.sh | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/testing/sniffstream b/testing/sniffstream index 247bbd58..7d1f9bfe 100755 --- a/testing/sniffstream +++ b/testing/sniffstream @@ -53,9 +53,10 @@ while( <STDIN> ) { $source = $2; $dest = $3; } - elsif ( /^\s+(0x....):\s(( [0-9a-f]{4}){1,8})/ ) { + elsif ( /^\s+(0x....):\s(( [0-9a-f]{4}){1,8})/i ) { my $pos = hex($1); my $hex = $2; + next unless defined($hex); if ( $pos == 64 ) { $hex = substr( $hex, 10 ); diff --git a/testing/watch-port-80.sh b/testing/watch-port-80.sh index f57925f6..60cddf29 100755 --- a/testing/watch-port-80.sh +++ b/testing/watch-port-80.sh @@ -3,4 +3,26 @@ PORT=${1:-"80"} IFACE=${2:-"any"} -sudo tcpdump -i $IFACE -s0 -l -n -q -A "tcp port ${PORT} and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)" +# Only include packets that contain data +NOTSYNFIN=" and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)" +DUMP="tcp port ${PORT}" + +IPCLAUSE="" +if [ "${IFACE}" != "any" ]; then + IP="`ip addr show dev wlan0 | grep ' inet ' | tr -s ' ' | cut -f3 -d' ' | cut -f1 -d'/'`" + IPCLAUSE=" and ((src host ${IP} and src port ${PORT}) or (dst host ${IP} and dst port ${PORT}))" +fi + +DUMPFILE="dumps/`date '+%FT%T'`.dump" + +# touch "${DUMPFILE}" +sudo tcpdump -i $IFACE -s0 -l -n -q -A "${DUMP}${NOTSYNFIN}${IPCLAUSE}" >"${DUMPFILE}" 2>&1 & +DUMPPID="$!" + +less "${DUMPFILE}" + +sudo kill "${DUMPPID}" + +if [ "`stat --format='%s' \"${DUMPFILE}\"`" -le 230 ] ; then + rm "${DUMPFILE}" +fi From 7b38707e969edd8d49e9a917221ae6d718906920 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Thu, 15 Nov 2007 16:31:33 +1300 Subject: [PATCH 136/189] Increase modification window to 30 seconds. --- testing/tests/regression-suite/840-Spec-PROPPATCH-1.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.test b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.test index 44d94c53..9d23e902 100644 --- a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.test +++ b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.test @@ -33,12 +33,12 @@ ENDDATA QUERY SELECT dav_displayname, dav_etag, is_calendar, - modified > (current_timestamp - '5 seconds'::interval) AS changed_last_5secs + modified > (current_timestamp - '30 seconds'::interval) AS changed_last_30secs FROM collection WHERE dav_name = '/user1/home/' ENDQUERY QUERY SELECT dav_name, property_name, property_value, changed_by, - changed_on > (current_timestamp - '5 seconds'::interval) AS changed_last_5secs + changed_on > (current_timestamp - '30 seconds'::interval) AS changed_last_30secs FROM property ORDER BY dav_name, property_name ENDQUERY From 1f5dad92f0ee5234f462374695debcf70dcfc4ed Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Thu, 15 Nov 2007 16:31:50 +1300 Subject: [PATCH 137/189] Extra result from SOHO tests. --- testing/tests/regression-suite/840-Spec-PROPPATCH-1.result | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result index 09ae75ec..2531e85e 100644 --- a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result +++ b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result @@ -16,12 +16,12 @@ User One's Calendar --- faf25336de0e470a54075c14cbcf5272 --- 0 --- 1 <DAV::HREF>http://www.example.com/acl/users/jim</DAV::HREF> --- 10 --- 1 /user1/home/ --- URN:MCMILLAN:BOGUS:XML:NS:RSCDS:ARBITRARY --- A completely bogus property which should be saved. --- 10 --- 1 -/user1/SOHO+collection/ --- COM.APPLE.ICAL::CALENDARCOLOR --- #FF8000FF --- 10 --- 0 -/user1/SOHO+collection/ --- URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DESCRIPTION --- Calendar description --- 10 --- 0 +/user1/SOHO+collection/ --- COM.APPLE.ICAL::CALENDARCOLOR --- #FF8000FF --- 10 --- 1 +/user1/SOHO+collection/ --- URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DESCRIPTION --- Calendar description --- 10 --- 1 /user1/SOHO+collection/ --- URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET --- <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VEVENT"/> <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VTODO"/> <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VTIMEZONE"/> <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VJOURNAL"/> <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VFREEBUSY"/> - --- 10 --- 0 + --- 10 --- 1 From 60383ef3c26960ac83ab02240dc13f18f94f15e1 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Thu, 15 Nov 2007 16:35:29 +1300 Subject: [PATCH 138/189] Improved formatting of namespace details for arbitrary properties. --- inc/caldav-PROPFIND.php | 10 +++++++++- .../tests/regression-suite/843-Spec-PROPFIND.result | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 1034acb5..0a00d29d 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -336,7 +336,15 @@ function collection_to_xml( $collection ) { if ( count($collection->properties) > 0 ) { foreach( $collection->properties AS $k => $v ) { - $prop->NewElement($k, $v ); + if ( preg_match('/^(.*):([^:]+)$/', $k, $matches) ) { + $namespace = $matches[1]; + $tag = $matches[2]; + } + else { + $namespace = ""; + $tag = $k; + } + $prop->NewElement(strtolower($tag), $v, array("xmlns" => strtolower($namespace)) ); } } diff --git a/testing/tests/regression-suite/843-Spec-PROPFIND.result b/testing/tests/regression-suite/843-Spec-PROPFIND.result index 881a0ca6..3825c211 100644 --- a/testing/tests/regression-suite/843-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/843-Spec-PROPFIND.result @@ -5,7 +5,7 @@ <propstat> <prop> <displayname>User One's Calendar</displayname> - <URN:MCMILLAN:BOGUS:XML:NS:RSCDS:ARBITRARY>A completely bogus property which should be saved.</URN:MCMILLAN:BOGUS:XML:NS:RSCDS:ARBITRARY> + <arbitrary xmlns="urn:mcmillan:bogus:xml:ns:rscds">A completely bogus property which should be saved.</arbitrary> </prop> <status>HTTP/1.1 200 OK</status> </propstat> From ec949297c3361610bfd875a986508152e42d6791 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Fri, 16 Nov 2007 08:50:24 +1300 Subject: [PATCH 139/189] Restructure the way that we handle namespaces. This will move to XMLElement in due course. --- inc/caldav-PROPFIND.php | 92 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 0a00d29d..25963d68 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -22,18 +22,98 @@ $attribute_list = array(); $unsupported = array(); $arbitrary = array(); -$namespaces = array( "xmlns" => "DAV:" ); - +$namespaces = array( "DAV:" => "" ); +$prefixes = array(); function add_namespace( $prefix, $namespace ) { global $namespaces; + global $prefixes; - $prefix = 'xmlns:'.$prefix; - if ( !isset($namespaces[$prefix]) || $namespaces[$prefix] != $namespace ) { - $namespaces[$prefix] = $namespace; + if ( !isset($namespaces[$namespace]) ) { + if ( $prefix == "" || isset($prefixes[$prefix]) ) { + dbg_error_log("ERROR", "Cannot assign the same prefix to two different namespaces"); + exit; + } + else { + $prefixes[$prefix] = $prefix; + $namespaces[$namespace] = $prefix; + } + } + else { + if ( $namespaces[$namespace] != $prefix ) { + dbg_error_log("ERROR", "Cannot use the same namespace with two different prefixes"); + exit; + } } } +function ns_tag( $in_tag, $namespace=null, $prefix=null ) { + global $namespaces; + + if ( $namespace == null ) { + // Attempt to split out from namespace:tag + if ( preg_match('/^(.*):([^:]+)$/', $in_tag, $matches) ) { + $namespace = $matches[1]; + $tag = $matches[2]; + } + else { + // There is nothing we can do here + return $in_tag; + } + } + else { + $tag = $in_tag; + } + + if ( $prefix == null ) { + // Attempt to assign one + if ( isset($namespaces[$namespace]) ) { + $prefix = $namespaces[$namespace]; + } + else { + // Try and build a prefix based on the first character of the last element of the namespace + if ( preg_match('/^(.*):([^:]+)$/', $namespace, $matches) ) { + $prefix = substr($matches[2],0,1); + } + else { + $prefix = 'x'; + } + $i = ""; + if ( isset($prefixes[$prefix]) ) { + for ( $i=1; $i<20 && isset($prefixes["$prefix$i"]); $i++ ) { + } + } + if ( isset($prefixes["$prefix$i"]) ) { + dbg_error_log("ERROR", "Cannot find a free prefix for this namespace"); + exit; + } + $prefix = "$prefix$i"; + $namespaces[$namespace] = $prefix; + $prefixes[$prefix] = 1; + } + } + + if ( !isset($namespaces[$namespace]) ) { + add_namespace( $prefix, $namespace ); + } + + return $prefix . ":" . $tag; +} + + +function namespace_array() { + global $namespaces; + + $ns = array(); + foreach( $namespaces AS $n => $p ) { + if ( $p == "" ) $ns["xmlns"] = $n; else $ns["xmlns:$p"] = $n; + } + + return $ns; +} + + + foreach( $request->xml_tags AS $k => $v ) { $ns_tag = $v['tag']; @@ -667,7 +747,7 @@ else { $request->DoResponse( 403, translate("You do not have appropriate rights to view that resource.") ); } -$multistatus = new XMLElement( "multistatus", $responses, $namespaces ); +$multistatus = new XMLElement( "multistatus", $responses, namespace_array() ); // dbg_log_array( "PROPFIND", "XML", $multistatus, true ); $xmldoc = $multistatus->Render(0,'<?xml version="1.0" encoding="utf-8" ?>'); From 73c00d5b78d95987746854dfd40d549a72c29c8b Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Fri, 16 Nov 2007 09:08:37 +1300 Subject: [PATCH 140/189] Migrate caldav namespace handling to new structure. --- inc/caldav-PROPFIND.php | 43 +++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 25963d68..a0b8128b 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -64,6 +64,7 @@ function ns_tag( $in_tag, $namespace=null, $prefix=null ) { else { $tag = $in_tag; } + $namespace = strtolower($namespace); if ( $prefix == null ) { // Attempt to assign one @@ -73,7 +74,7 @@ function ns_tag( $in_tag, $namespace=null, $prefix=null ) { else { // Try and build a prefix based on the first character of the last element of the namespace if ( preg_match('/^(.*):([^:]+)$/', $namespace, $matches) ) { - $prefix = substr($matches[2],0,1); + $prefix = strtoupper(substr($matches[2],0,1)); } else { $prefix = 'x'; @@ -113,6 +114,10 @@ function namespace_array() { } +function caldav_tag( $tag ) { + return ns_tag( $tag, 'urn:ietf:params:xml:ns:caldav' ); +} + foreach( $request->xml_tags AS $k => $v ) { @@ -273,16 +278,13 @@ function add_principal_properties( &$prop, &$not_found, &$denied ) { } if ( isset($attribute_list['CALENDAR-HOME-SET'] ) ) { - add_namespace("C", "urn:ietf:params:xml:ns:caldav"); - $prop->NewElement("C:calendar-home-set", new XMLElement('href', $request->principal->calendar_home_set ) ); + $prop->NewElement(caldav_tag("calendar-home-set"), new XMLElement('href', $request->principal->calendar_home_set ) ); } if ( isset($attribute_list['SCHEDULE-INBOX-URL'] ) ) { - add_namespace("C", "urn:ietf:params:xml:ns:caldav"); - $prop->NewElement("C:schedule-inbox-url", new XMLElement('href', $request->principal->schedule_inbox_url) ); + $prop->NewElement(caldav_tag("schedule-inbox-url"), new XMLElement('href', $request->principal->schedule_inbox_url) ); } if ( isset($attribute_list['SCHEDULE-OUTBOX-URL'] ) ) { - add_namespace("C", "urn:ietf:params:xml:ns:caldav"); - $prop->NewElement("C:schedule-outbox-url", new XMLElement('href', $request->principal->schedule_outbox_url) ); + $prop->NewElement(caldav_tag("schedule-outbox-url"), new XMLElement('href', $request->principal->schedule_outbox_url) ); } if ( isset($attribute_list['DROPBOX-HOME-URL'] ) ) { @@ -295,12 +297,11 @@ function add_principal_properties( &$prop, &$not_found, &$denied ) { } if ( isset($attribute_list['CALENDAR-USER-ADDRESS-SET'] ) ) { - add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $addr_set = array(); foreach( $request->principal->user_address_set AS $k => $v ) { $addr_set[] = new XMLElement('href', $v ); } - $prop->NewElement("C:calendar-user-address-set", $addr_set ); + $prop->NewElement(caldav_tag("calendar-user-address-set"), $addr_set ); } } @@ -326,8 +327,7 @@ function collection_to_xml( $collection ) { $resourcetypes = array( new XMLElement("collection") ); $contentlength = false; if ( $collection->is_calendar == 't' ) { - add_namespace("C", "urn:ietf:params:xml:ns:caldav"); - $resourcetypes[] = new XMLElement("C:calendar", false); + $resourcetypes[] = new XMLElement(caldav_tag("calendar"), false); $lqry = new PgQuery("SELECT sum(length(caldav_data)) FROM caldav_data WHERE user_no = ? AND dav_name ~ ?;", $collection->user_no, $collection->dav_name.'[^/]+$' ); if ( $lqry->Exec("PROPFIND",__LINE__,__FILE__) && $row = $lqry->Fetch() ) { $contentlength = $row->sum; @@ -344,18 +344,16 @@ function collection_to_xml( $collection ) { * First process any static values we do support */ if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-COLLATION-SET']) ) { - add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $collations = array(); - $collations[] = new XMLElement("C:supported-collation", 'i;ascii-casemap'); - $collations[] = new XMLElement("C:supported-collation", 'i;octet'); - $prop->NewElement("C:supported-collation-set", $collations ); + $collations[] = new XMLElement(caldav_tag("supported-collation"), 'i;ascii-casemap'); + $collations[] = new XMLElement(caldav_tag("supported-collation"), 'i;octet'); + $prop->NewElement(caldav_tag("supported-collation-set"), $collations ); } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['SUPPORTED-CALENDAR-COMPONENT-SET']) ) { - add_namespace("C", "urn:ietf:params:xml:ns:caldav"); $components = array(); - $components[] = new XMLElement("C:comp", '', array("name" => "VEVENT")); - $components[] = new XMLElement("C:comp", '', array("name" => "VTODO")); - $prop->NewElement("C:supported-calendar-component-set", $components ); + $components[] = new XMLElement(caldav_tag("comp"), '', array("name" => "VEVENT")); + $components[] = new XMLElement(caldav_tag("comp"), '', array("name" => "VTODO")); + $prop->NewElement(caldav_tag("supported-calendar-component-set"), $components ); } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETCONTENTTYPE']) ) { $prop->NewElement("getcontenttype", "httpd/unix-directory" ); @@ -392,19 +390,18 @@ function collection_to_xml( $collection ) { } if ( isset($attribute_list['CALENDAR-FREE-BUSY-SET'] ) ) { - add_namespace("C", "urn:ietf:params:xml:ns:caldav"); if ( isset($collection->is_inbox) && $collection->is_inbox && $session->user_no == $collection->user_no ) { $fb_set = array(); foreach( $collection->free_busy_set AS $k => $v ) { $fb_set[] = new XMLElement('href', $v ); } - $prop->NewElement("C:calendar-free-busy-set", $fb_set ); + $prop->NewElement(caldav_tag("calendar-free-busy-set"), $fb_set ); } else if ( $session->user_no == $collection->user_no ) { - $not_found->NewElement("C:calendar-free-busy-set" ); + $not_found->NewElement(caldav_tag("calendar-free-busy-set") ); } else { - $denied->NewElement("C:calendar-free-busy-set" ); + $denied->NewElement(caldav_tag("calendar-free-busy-set") ); } } From 655bb12d3d1bb9b23ddb4bcb06da3407ac4bd8ba Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Fri, 16 Nov 2007 10:46:51 +1300 Subject: [PATCH 141/189] Freebusy URL should be Start/Finish datetimes, not Start/Duration. --- inc/freebusy-GET.php | 12 +- .../regression-suite/832-freebusy.result | 112 +++++++++--------- .../regression-suite/833-freebusy.result | 112 +++++++++--------- .../regression-suite/835-freebusy.result | 110 ++++++++--------- .../regression-suite/836-freebusy.result | 110 ++++++++--------- 5 files changed, 230 insertions(+), 226 deletions(-) diff --git a/inc/freebusy-GET.php b/inc/freebusy-GET.php index 99fe5977..3dbcc392 100644 --- a/inc/freebusy-GET.php +++ b/inc/freebusy-GET.php @@ -73,11 +73,13 @@ foreach( $busy_tentative AS $k => $v ) { while ( $date = $rrule->GetNext() ) { if ( ! $date->GreaterThan($start) ) continue; if ( $date->GreaterThan($finish) ) break; - $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $duration ); + $todate = clone($date); + $todate->AddDuration($duration); + $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $todate->Render('Ymd\THis') ); } } else { - $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $start->Render('Ymd\THis'), $duration ); + $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $v->start, $v->finish ); } } @@ -89,11 +91,13 @@ foreach( $busy AS $k => $v ) { while ( $date = $rrule->GetNext() ) { if ( ! $date->GreaterThan($start) ) continue; if ( $date->GreaterThan($finish) ) break; - $freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $duration ); + $todate = clone($date); + $todate->AddDuration($duration); + $freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $todate->Render('Ymd\THis') ); } } else { - $freebusy .= sprintf("FREEBUSY:%s/%s\n", $start->Render('Ymd\THis'), $duration ); + $freebusy .= sprintf("FREEBUSY:%s/%s\n", $v->start, $v->finish ); } } diff --git a/testing/tests/regression-suite/832-freebusy.result b/testing/tests/regression-suite/832-freebusy.result index 0bc71443..565b1ab7 100644 --- a/testing/tests/regression-suite/832-freebusy.result +++ b/testing/tests/regression-suite/832-freebusy.result @@ -1,6 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Content-Length: 1922 +Content-Length: 2476 Content-Type: text/calendar BEGIN:VCALENDAR @@ -10,60 +10,60 @@ BEGIN:VFREEBUSY DTSTAMP:yyyymmddThhmmssZ DTSTART:yyyymmddThhmmss DTEND:yyyymmddThhmmss -FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/PT2H -FREEBUSY:20061031T210000/PT1H -FREEBUSY:20061102T210000/PT1H -FREEBUSY:20061109T210000/PT1H -FREEBUSY:20061116T210000/PT1H -FREEBUSY:20061123T210000/PT1H -FREEBUSY:20061130T210000/PT1H -FREEBUSY:20061207T210000/PT1H -FREEBUSY:20061214T210000/PT1H -FREEBUSY:20061221T210000/PT1H -FREEBUSY:20061228T210000/PT1H -FREEBUSY:20070104T210000/PT1H -FREEBUSY:20070111T210000/PT1H -FREEBUSY:20070118T210000/PT1H -FREEBUSY:20070125T210000/PT1H -FREEBUSY:20070201T210000/PT1H -FREEBUSY:20070208T210000/PT1H -FREEBUSY:20070215T210000/PT1H -FREEBUSY:20070222T210000/PT1H -FREEBUSY:20070301T210000/PT1H -FREEBUSY:20070308T210000/PT1H -FREEBUSY:20070315T210000/PT1H -FREEBUSY:20070322T210000/PT1H -FREEBUSY:20070329T210000/PT1H -FREEBUSY:20070405T210000/PT1H -FREEBUSY:20070412T210000/PT1H -FREEBUSY:20070419T210000/PT1H -FREEBUSY:20070426T210000/PT1H -FREEBUSY:20061101T233000/PT1H -FREEBUSY:20061202T183000/PT2H -FREEBUSY:20070102T183000/PT2H -FREEBUSY:20070202T183000/PT2H -FREEBUSY:20070302T183000/PT2H -FREEBUSY:20070402T183000/PT2H -FREEBUSY:20070502T183000/PT2H -FREEBUSY:20070602T183000/PT2H -FREEBUSY:20061117T030000/PT1H45M -FREEBUSY:20061201T030000/PT1H45M -FREEBUSY:20061215T030000/PT1H45M -FREEBUSY:20061229T030000/PT1H45M -FREEBUSY:20070112T030000/PT1H45M -FREEBUSY:20070126T030000/PT1H45M -FREEBUSY:20070209T030000/PT1H45M -FREEBUSY:20070223T030000/PT1H45M -FREEBUSY:20070309T030000/PT1H45M -FREEBUSY:20070323T030000/PT1H45M -FREEBUSY:20070406T030000/PT1H45M -FREEBUSY:20070420T030000/PT1H45M -FREEBUSY:20070504T030000/PT1H45M -FREEBUSY:20070518T030000/PT1H45M -FREEBUSY:20070601T030000/PT1H45M -FREEBUSY:20070615T030000/PT1H45M -FREEBUSY:20070629T030000/PT1H45M -FREEBUSY:20061223T000000/PT2H -FREEBUSY:20061223T030000/PT2H +FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/20061223T080000 +FREEBUSY:20061031T210000/20061031T220000 +FREEBUSY:20061102T210000/20061102T220000 +FREEBUSY:20061109T210000/20061109T220000 +FREEBUSY:20061116T210000/20061116T220000 +FREEBUSY:20061123T210000/20061123T220000 +FREEBUSY:20061130T210000/20061130T220000 +FREEBUSY:20061207T210000/20061207T220000 +FREEBUSY:20061214T210000/20061214T220000 +FREEBUSY:20061221T210000/20061221T220000 +FREEBUSY:20061228T210000/20061228T220000 +FREEBUSY:20070104T210000/20070104T220000 +FREEBUSY:20070111T210000/20070111T220000 +FREEBUSY:20070118T210000/20070118T220000 +FREEBUSY:20070125T210000/20070125T220000 +FREEBUSY:20070201T210000/20070201T220000 +FREEBUSY:20070208T210000/20070208T220000 +FREEBUSY:20070215T210000/20070215T220000 +FREEBUSY:20070222T210000/20070222T220000 +FREEBUSY:20070301T210000/20070301T220000 +FREEBUSY:20070308T210000/20070308T220000 +FREEBUSY:20070315T210000/20070315T220000 +FREEBUSY:20070322T210000/20070322T220000 +FREEBUSY:20070329T210000/20070329T220000 +FREEBUSY:20070405T210000/20070405T220000 +FREEBUSY:20070412T210000/20070412T220000 +FREEBUSY:20070419T210000/20070419T220000 +FREEBUSY:20070426T210000/20070426T220000 +FREEBUSY:20061101T233000/20061102T003000 +FREEBUSY:20061202T183000/20061202T203000 +FREEBUSY:20070102T183000/20070102T203000 +FREEBUSY:20070202T183000/20070202T203000 +FREEBUSY:20070302T183000/20070302T203000 +FREEBUSY:20070402T183000/20070402T203000 +FREEBUSY:20070502T183000/20070502T203000 +FREEBUSY:20070602T183000/20070602T203000 +FREEBUSY:20061117T030000/20061117T040500 +FREEBUSY:20061201T030000/20061201T040500 +FREEBUSY:20061215T030000/20061215T040500 +FREEBUSY:20061229T030000/20061229T040500 +FREEBUSY:20070112T030000/20070112T040500 +FREEBUSY:20070126T030000/20070126T040500 +FREEBUSY:20070209T030000/20070209T040500 +FREEBUSY:20070223T030000/20070223T040500 +FREEBUSY:20070309T030000/20070309T040500 +FREEBUSY:20070323T030000/20070323T040500 +FREEBUSY:20070406T030000/20070406T040500 +FREEBUSY:20070420T030000/20070420T040500 +FREEBUSY:20070504T030000/20070504T040500 +FREEBUSY:20070518T030000/20070518T040500 +FREEBUSY:20070601T030000/20070601T040500 +FREEBUSY:20070615T030000/20070615T040500 +FREEBUSY:20070629T030000/20070629T040500 +FREEBUSY:20061223T000000/20061223T020000 +FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY END:VCALENDAR diff --git a/testing/tests/regression-suite/833-freebusy.result b/testing/tests/regression-suite/833-freebusy.result index 0bc71443..565b1ab7 100644 --- a/testing/tests/regression-suite/833-freebusy.result +++ b/testing/tests/regression-suite/833-freebusy.result @@ -1,6 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Content-Length: 1922 +Content-Length: 2476 Content-Type: text/calendar BEGIN:VCALENDAR @@ -10,60 +10,60 @@ BEGIN:VFREEBUSY DTSTAMP:yyyymmddThhmmssZ DTSTART:yyyymmddThhmmss DTEND:yyyymmddThhmmss -FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/PT2H -FREEBUSY:20061031T210000/PT1H -FREEBUSY:20061102T210000/PT1H -FREEBUSY:20061109T210000/PT1H -FREEBUSY:20061116T210000/PT1H -FREEBUSY:20061123T210000/PT1H -FREEBUSY:20061130T210000/PT1H -FREEBUSY:20061207T210000/PT1H -FREEBUSY:20061214T210000/PT1H -FREEBUSY:20061221T210000/PT1H -FREEBUSY:20061228T210000/PT1H -FREEBUSY:20070104T210000/PT1H -FREEBUSY:20070111T210000/PT1H -FREEBUSY:20070118T210000/PT1H -FREEBUSY:20070125T210000/PT1H -FREEBUSY:20070201T210000/PT1H -FREEBUSY:20070208T210000/PT1H -FREEBUSY:20070215T210000/PT1H -FREEBUSY:20070222T210000/PT1H -FREEBUSY:20070301T210000/PT1H -FREEBUSY:20070308T210000/PT1H -FREEBUSY:20070315T210000/PT1H -FREEBUSY:20070322T210000/PT1H -FREEBUSY:20070329T210000/PT1H -FREEBUSY:20070405T210000/PT1H -FREEBUSY:20070412T210000/PT1H -FREEBUSY:20070419T210000/PT1H -FREEBUSY:20070426T210000/PT1H -FREEBUSY:20061101T233000/PT1H -FREEBUSY:20061202T183000/PT2H -FREEBUSY:20070102T183000/PT2H -FREEBUSY:20070202T183000/PT2H -FREEBUSY:20070302T183000/PT2H -FREEBUSY:20070402T183000/PT2H -FREEBUSY:20070502T183000/PT2H -FREEBUSY:20070602T183000/PT2H -FREEBUSY:20061117T030000/PT1H45M -FREEBUSY:20061201T030000/PT1H45M -FREEBUSY:20061215T030000/PT1H45M -FREEBUSY:20061229T030000/PT1H45M -FREEBUSY:20070112T030000/PT1H45M -FREEBUSY:20070126T030000/PT1H45M -FREEBUSY:20070209T030000/PT1H45M -FREEBUSY:20070223T030000/PT1H45M -FREEBUSY:20070309T030000/PT1H45M -FREEBUSY:20070323T030000/PT1H45M -FREEBUSY:20070406T030000/PT1H45M -FREEBUSY:20070420T030000/PT1H45M -FREEBUSY:20070504T030000/PT1H45M -FREEBUSY:20070518T030000/PT1H45M -FREEBUSY:20070601T030000/PT1H45M -FREEBUSY:20070615T030000/PT1H45M -FREEBUSY:20070629T030000/PT1H45M -FREEBUSY:20061223T000000/PT2H -FREEBUSY:20061223T030000/PT2H +FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/20061223T080000 +FREEBUSY:20061031T210000/20061031T220000 +FREEBUSY:20061102T210000/20061102T220000 +FREEBUSY:20061109T210000/20061109T220000 +FREEBUSY:20061116T210000/20061116T220000 +FREEBUSY:20061123T210000/20061123T220000 +FREEBUSY:20061130T210000/20061130T220000 +FREEBUSY:20061207T210000/20061207T220000 +FREEBUSY:20061214T210000/20061214T220000 +FREEBUSY:20061221T210000/20061221T220000 +FREEBUSY:20061228T210000/20061228T220000 +FREEBUSY:20070104T210000/20070104T220000 +FREEBUSY:20070111T210000/20070111T220000 +FREEBUSY:20070118T210000/20070118T220000 +FREEBUSY:20070125T210000/20070125T220000 +FREEBUSY:20070201T210000/20070201T220000 +FREEBUSY:20070208T210000/20070208T220000 +FREEBUSY:20070215T210000/20070215T220000 +FREEBUSY:20070222T210000/20070222T220000 +FREEBUSY:20070301T210000/20070301T220000 +FREEBUSY:20070308T210000/20070308T220000 +FREEBUSY:20070315T210000/20070315T220000 +FREEBUSY:20070322T210000/20070322T220000 +FREEBUSY:20070329T210000/20070329T220000 +FREEBUSY:20070405T210000/20070405T220000 +FREEBUSY:20070412T210000/20070412T220000 +FREEBUSY:20070419T210000/20070419T220000 +FREEBUSY:20070426T210000/20070426T220000 +FREEBUSY:20061101T233000/20061102T003000 +FREEBUSY:20061202T183000/20061202T203000 +FREEBUSY:20070102T183000/20070102T203000 +FREEBUSY:20070202T183000/20070202T203000 +FREEBUSY:20070302T183000/20070302T203000 +FREEBUSY:20070402T183000/20070402T203000 +FREEBUSY:20070502T183000/20070502T203000 +FREEBUSY:20070602T183000/20070602T203000 +FREEBUSY:20061117T030000/20061117T040500 +FREEBUSY:20061201T030000/20061201T040500 +FREEBUSY:20061215T030000/20061215T040500 +FREEBUSY:20061229T030000/20061229T040500 +FREEBUSY:20070112T030000/20070112T040500 +FREEBUSY:20070126T030000/20070126T040500 +FREEBUSY:20070209T030000/20070209T040500 +FREEBUSY:20070223T030000/20070223T040500 +FREEBUSY:20070309T030000/20070309T040500 +FREEBUSY:20070323T030000/20070323T040500 +FREEBUSY:20070406T030000/20070406T040500 +FREEBUSY:20070420T030000/20070420T040500 +FREEBUSY:20070504T030000/20070504T040500 +FREEBUSY:20070518T030000/20070518T040500 +FREEBUSY:20070601T030000/20070601T040500 +FREEBUSY:20070615T030000/20070615T040500 +FREEBUSY:20070629T030000/20070629T040500 +FREEBUSY:20061223T000000/20061223T020000 +FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY END:VCALENDAR diff --git a/testing/tests/regression-suite/835-freebusy.result b/testing/tests/regression-suite/835-freebusy.result index cd5fca33..9763b5f7 100644 --- a/testing/tests/regression-suite/835-freebusy.result +++ b/testing/tests/regression-suite/835-freebusy.result @@ -1,6 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Content-Length: 1892 +Content-Length: 2435 Content-Type: text/calendar BEGIN:VCALENDAR @@ -10,59 +10,59 @@ BEGIN:VFREEBUSY DTSTAMP:yyyymmddThhmmssZ DTSTART:yyyymmddThhmmss DTEND:yyyymmddThhmmss -FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/PT2H -FREEBUSY:20061031T210000/PT1H -FREEBUSY:20061102T210000/PT1H -FREEBUSY:20061109T210000/PT1H -FREEBUSY:20061116T210000/PT1H -FREEBUSY:20061123T210000/PT1H -FREEBUSY:20061130T210000/PT1H -FREEBUSY:20061207T210000/PT1H -FREEBUSY:20061214T210000/PT1H -FREEBUSY:20061221T210000/PT1H -FREEBUSY:20061228T210000/PT1H -FREEBUSY:20070104T210000/PT1H -FREEBUSY:20070111T210000/PT1H -FREEBUSY:20070118T210000/PT1H -FREEBUSY:20070125T210000/PT1H -FREEBUSY:20070201T210000/PT1H -FREEBUSY:20070208T210000/PT1H -FREEBUSY:20070215T210000/PT1H -FREEBUSY:20070222T210000/PT1H -FREEBUSY:20070301T210000/PT1H -FREEBUSY:20070308T210000/PT1H -FREEBUSY:20070315T210000/PT1H -FREEBUSY:20070322T210000/PT1H -FREEBUSY:20070329T210000/PT1H -FREEBUSY:20070405T210000/PT1H -FREEBUSY:20070412T210000/PT1H -FREEBUSY:20070419T210000/PT1H -FREEBUSY:20070426T210000/PT1H -FREEBUSY:20061101T233000/PT1H -FREEBUSY:20061202T183000/PT2H -FREEBUSY:20070102T183000/PT2H -FREEBUSY:20070202T183000/PT2H -FREEBUSY:20070302T183000/PT2H -FREEBUSY:20070402T183000/PT2H -FREEBUSY:20070502T183000/PT2H -FREEBUSY:20070602T183000/PT2H -FREEBUSY:20061117T030000/PT1H45M -FREEBUSY:20061201T030000/PT1H45M -FREEBUSY:20061215T030000/PT1H45M -FREEBUSY:20061229T030000/PT1H45M -FREEBUSY:20070112T030000/PT1H45M -FREEBUSY:20070126T030000/PT1H45M -FREEBUSY:20070209T030000/PT1H45M -FREEBUSY:20070223T030000/PT1H45M -FREEBUSY:20070309T030000/PT1H45M -FREEBUSY:20070323T030000/PT1H45M -FREEBUSY:20070406T030000/PT1H45M -FREEBUSY:20070420T030000/PT1H45M -FREEBUSY:20070504T030000/PT1H45M -FREEBUSY:20070518T030000/PT1H45M -FREEBUSY:20070601T030000/PT1H45M -FREEBUSY:20070615T030000/PT1H45M -FREEBUSY:20070629T030000/PT1H45M -FREEBUSY:20061223T030000/PT2H +FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/20061223T080000 +FREEBUSY:20061031T210000/20061031T220000 +FREEBUSY:20061102T210000/20061102T220000 +FREEBUSY:20061109T210000/20061109T220000 +FREEBUSY:20061116T210000/20061116T220000 +FREEBUSY:20061123T210000/20061123T220000 +FREEBUSY:20061130T210000/20061130T220000 +FREEBUSY:20061207T210000/20061207T220000 +FREEBUSY:20061214T210000/20061214T220000 +FREEBUSY:20061221T210000/20061221T220000 +FREEBUSY:20061228T210000/20061228T220000 +FREEBUSY:20070104T210000/20070104T220000 +FREEBUSY:20070111T210000/20070111T220000 +FREEBUSY:20070118T210000/20070118T220000 +FREEBUSY:20070125T210000/20070125T220000 +FREEBUSY:20070201T210000/20070201T220000 +FREEBUSY:20070208T210000/20070208T220000 +FREEBUSY:20070215T210000/20070215T220000 +FREEBUSY:20070222T210000/20070222T220000 +FREEBUSY:20070301T210000/20070301T220000 +FREEBUSY:20070308T210000/20070308T220000 +FREEBUSY:20070315T210000/20070315T220000 +FREEBUSY:20070322T210000/20070322T220000 +FREEBUSY:20070329T210000/20070329T220000 +FREEBUSY:20070405T210000/20070405T220000 +FREEBUSY:20070412T210000/20070412T220000 +FREEBUSY:20070419T210000/20070419T220000 +FREEBUSY:20070426T210000/20070426T220000 +FREEBUSY:20061101T233000/20061102T003000 +FREEBUSY:20061202T183000/20061202T203000 +FREEBUSY:20070102T183000/20070102T203000 +FREEBUSY:20070202T183000/20070202T203000 +FREEBUSY:20070302T183000/20070302T203000 +FREEBUSY:20070402T183000/20070402T203000 +FREEBUSY:20070502T183000/20070502T203000 +FREEBUSY:20070602T183000/20070602T203000 +FREEBUSY:20061117T030000/20061117T040500 +FREEBUSY:20061201T030000/20061201T040500 +FREEBUSY:20061215T030000/20061215T040500 +FREEBUSY:20061229T030000/20061229T040500 +FREEBUSY:20070112T030000/20070112T040500 +FREEBUSY:20070126T030000/20070126T040500 +FREEBUSY:20070209T030000/20070209T040500 +FREEBUSY:20070223T030000/20070223T040500 +FREEBUSY:20070309T030000/20070309T040500 +FREEBUSY:20070323T030000/20070323T040500 +FREEBUSY:20070406T030000/20070406T040500 +FREEBUSY:20070420T030000/20070420T040500 +FREEBUSY:20070504T030000/20070504T040500 +FREEBUSY:20070518T030000/20070518T040500 +FREEBUSY:20070601T030000/20070601T040500 +FREEBUSY:20070615T030000/20070615T040500 +FREEBUSY:20070629T030000/20070629T040500 +FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY END:VCALENDAR diff --git a/testing/tests/regression-suite/836-freebusy.result b/testing/tests/regression-suite/836-freebusy.result index cd5fca33..9763b5f7 100644 --- a/testing/tests/regression-suite/836-freebusy.result +++ b/testing/tests/regression-suite/836-freebusy.result @@ -1,6 +1,6 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT -Content-Length: 1892 +Content-Length: 2435 Content-Type: text/calendar BEGIN:VCALENDAR @@ -10,59 +10,59 @@ BEGIN:VFREEBUSY DTSTAMP:yyyymmddThhmmssZ DTSTART:yyyymmddThhmmss DTEND:yyyymmddThhmmss -FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/PT2H -FREEBUSY:20061031T210000/PT1H -FREEBUSY:20061102T210000/PT1H -FREEBUSY:20061109T210000/PT1H -FREEBUSY:20061116T210000/PT1H -FREEBUSY:20061123T210000/PT1H -FREEBUSY:20061130T210000/PT1H -FREEBUSY:20061207T210000/PT1H -FREEBUSY:20061214T210000/PT1H -FREEBUSY:20061221T210000/PT1H -FREEBUSY:20061228T210000/PT1H -FREEBUSY:20070104T210000/PT1H -FREEBUSY:20070111T210000/PT1H -FREEBUSY:20070118T210000/PT1H -FREEBUSY:20070125T210000/PT1H -FREEBUSY:20070201T210000/PT1H -FREEBUSY:20070208T210000/PT1H -FREEBUSY:20070215T210000/PT1H -FREEBUSY:20070222T210000/PT1H -FREEBUSY:20070301T210000/PT1H -FREEBUSY:20070308T210000/PT1H -FREEBUSY:20070315T210000/PT1H -FREEBUSY:20070322T210000/PT1H -FREEBUSY:20070329T210000/PT1H -FREEBUSY:20070405T210000/PT1H -FREEBUSY:20070412T210000/PT1H -FREEBUSY:20070419T210000/PT1H -FREEBUSY:20070426T210000/PT1H -FREEBUSY:20061101T233000/PT1H -FREEBUSY:20061202T183000/PT2H -FREEBUSY:20070102T183000/PT2H -FREEBUSY:20070202T183000/PT2H -FREEBUSY:20070302T183000/PT2H -FREEBUSY:20070402T183000/PT2H -FREEBUSY:20070502T183000/PT2H -FREEBUSY:20070602T183000/PT2H -FREEBUSY:20061117T030000/PT1H45M -FREEBUSY:20061201T030000/PT1H45M -FREEBUSY:20061215T030000/PT1H45M -FREEBUSY:20061229T030000/PT1H45M -FREEBUSY:20070112T030000/PT1H45M -FREEBUSY:20070126T030000/PT1H45M -FREEBUSY:20070209T030000/PT1H45M -FREEBUSY:20070223T030000/PT1H45M -FREEBUSY:20070309T030000/PT1H45M -FREEBUSY:20070323T030000/PT1H45M -FREEBUSY:20070406T030000/PT1H45M -FREEBUSY:20070420T030000/PT1H45M -FREEBUSY:20070504T030000/PT1H45M -FREEBUSY:20070518T030000/PT1H45M -FREEBUSY:20070601T030000/PT1H45M -FREEBUSY:20070615T030000/PT1H45M -FREEBUSY:20070629T030000/PT1H45M -FREEBUSY:20061223T030000/PT2H +FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/20061223T080000 +FREEBUSY:20061031T210000/20061031T220000 +FREEBUSY:20061102T210000/20061102T220000 +FREEBUSY:20061109T210000/20061109T220000 +FREEBUSY:20061116T210000/20061116T220000 +FREEBUSY:20061123T210000/20061123T220000 +FREEBUSY:20061130T210000/20061130T220000 +FREEBUSY:20061207T210000/20061207T220000 +FREEBUSY:20061214T210000/20061214T220000 +FREEBUSY:20061221T210000/20061221T220000 +FREEBUSY:20061228T210000/20061228T220000 +FREEBUSY:20070104T210000/20070104T220000 +FREEBUSY:20070111T210000/20070111T220000 +FREEBUSY:20070118T210000/20070118T220000 +FREEBUSY:20070125T210000/20070125T220000 +FREEBUSY:20070201T210000/20070201T220000 +FREEBUSY:20070208T210000/20070208T220000 +FREEBUSY:20070215T210000/20070215T220000 +FREEBUSY:20070222T210000/20070222T220000 +FREEBUSY:20070301T210000/20070301T220000 +FREEBUSY:20070308T210000/20070308T220000 +FREEBUSY:20070315T210000/20070315T220000 +FREEBUSY:20070322T210000/20070322T220000 +FREEBUSY:20070329T210000/20070329T220000 +FREEBUSY:20070405T210000/20070405T220000 +FREEBUSY:20070412T210000/20070412T220000 +FREEBUSY:20070419T210000/20070419T220000 +FREEBUSY:20070426T210000/20070426T220000 +FREEBUSY:20061101T233000/20061102T003000 +FREEBUSY:20061202T183000/20061202T203000 +FREEBUSY:20070102T183000/20070102T203000 +FREEBUSY:20070202T183000/20070202T203000 +FREEBUSY:20070302T183000/20070302T203000 +FREEBUSY:20070402T183000/20070402T203000 +FREEBUSY:20070502T183000/20070502T203000 +FREEBUSY:20070602T183000/20070602T203000 +FREEBUSY:20061117T030000/20061117T040500 +FREEBUSY:20061201T030000/20061201T040500 +FREEBUSY:20061215T030000/20061215T040500 +FREEBUSY:20061229T030000/20061229T040500 +FREEBUSY:20070112T030000/20070112T040500 +FREEBUSY:20070126T030000/20070126T040500 +FREEBUSY:20070209T030000/20070209T040500 +FREEBUSY:20070223T030000/20070223T040500 +FREEBUSY:20070309T030000/20070309T040500 +FREEBUSY:20070323T030000/20070323T040500 +FREEBUSY:20070406T030000/20070406T040500 +FREEBUSY:20070420T030000/20070420T040500 +FREEBUSY:20070504T030000/20070504T040500 +FREEBUSY:20070518T030000/20070518T040500 +FREEBUSY:20070601T030000/20070601T040500 +FREEBUSY:20070615T030000/20070615T040500 +FREEBUSY:20070629T030000/20070629T040500 +FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY END:VCALENDAR From 8fb6bcd1e7c3cc0601f59c2852f2f1e0df555548 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 17 Nov 2007 22:07:30 +1300 Subject: [PATCH 142/189] Don't deault the admin e-mail address to a real one! --- inc/always.php | 2 +- inc/always.php.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/always.php b/inc/always.php index de07a081..0cfbeb48 100644 --- a/inc/always.php +++ b/inc/always.php @@ -11,7 +11,7 @@ unset($c); // Default some of the configurable values $c->sysabbr = 'davical'; -$c->admin_email = 'andrew@catalyst.net.nz'; +$c->admin_email = 'admin@davical.example.com'; $c->system_name = "DAViCal CalDAV Server"; $c->domain_name = $_SERVER['SERVER_NAME']; $c->save_time_zone_defs = true; diff --git a/inc/always.php.in b/inc/always.php.in index 7e12936c..4b5f011e 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -11,7 +11,7 @@ unset($c); // Default some of the configurable values $c->sysabbr = 'davical'; -$c->admin_email = 'andrew@catalyst.net.nz'; +$c->admin_email = 'admin@davical.example.com'; $c->system_name = "DAViCal CalDAV Server"; $c->domain_name = $_SERVER['SERVER_NAME']; $c->save_time_zone_defs = true; From 35839c062bd6806c184b704786e60aecf4845ae4 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 17 Nov 2007 22:07:38 +1300 Subject: [PATCH 143/189] Strings changed. --- po/de_DE.po | 6 +++++- po/en_NZ.po | 6 +++++- po/es_AR.po | 6 +++++- po/es_ES.po | 6 +++++- po/es_MX.po | 6 +++++- po/fr_FR.po | 6 +++++- po/hu_HU.po | 6 +++++- po/messages.po | 6 +++++- po/nl_NL.po | 6 +++++- po/pl_PL.po | 6 +++++- po/ru_RU.po | 6 +++++- 11 files changed, 55 insertions(+), 11 deletions(-) diff --git a/po/de_DE.po b/po/de_DE.po index dfd12865..10743336 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: 2006-11-06 17:24+1300\n" "Last-Translator: Cristina Radalescu <andrew@mcmillan.net.nz>\n" "MIME-Version: 1.0\n" @@ -610,6 +610,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/en_NZ.po b/po/en_NZ.po index 35e2521e..32f6d3df 100644 --- a/po/en_NZ.po +++ b/po/en_NZ.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -594,6 +594,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/es_AR.po b/po/es_AR.po index d0cf5dbe..53e616f5 100644 --- a/po/es_AR.po +++ b/po/es_AR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti <andrew@mcmillan.net.nz>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -608,6 +608,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/es_ES.po b/po/es_ES.po index d0cf5dbe..53e616f5 100644 --- a/po/es_ES.po +++ b/po/es_ES.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti <andrew@mcmillan.net.nz>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -608,6 +608,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/es_MX.po b/po/es_MX.po index d0cf5dbe..53e616f5 100644 --- a/po/es_MX.po +++ b/po/es_MX.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: RSCDS 0.2.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: 2006-11-06 17:12+1300\n" "Last-Translator: Lorena Paoletti <andrew@mcmillan.net.nz>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -608,6 +608,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/fr_FR.po b/po/fr_FR.po index 56f0302b..c5a2e614 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.3.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: 2006-11-13 13:03+1300\n" "Last-Translator: maxime delorme <mdelorme@tennaxia.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -678,6 +678,10 @@ msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap mod msgstr "" "drivers_ldap : la fonction ldap_connect n'est pas définie, vérifier que vous avez l'extension php_ldap" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/hu_HU.po b/po/hu_HU.po index 5df6f3cb..83499af3 100644 --- a/po/hu_HU.po +++ b/po/hu_HU.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: 2007-05-03 15:00+0001\n" "Last-Translator: David Takacs <david.takacs@cafeopen.eu>\n" "Language-Team: \n" @@ -601,6 +601,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/messages.po b/po/messages.po index 12976086..50fd8ac8 100644 --- a/po/messages.po +++ b/po/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -608,6 +608,10 @@ msgid "" "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a " "flower) and is an option allowing people to log in automatically in future --" diff --git a/po/nl_NL.po b/po/nl_NL.po index 34ce9d34..1f95aece 100644 --- a/po/nl_NL.po +++ b/po/nl_NL.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Eelco Maljaars <http://eelco.maljaars.net/>\n" "Language-Team: nl_NL <LL@li.org>\n" @@ -605,6 +605,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/pl_PL.po b/po/pl_PL.po index f9126f7f..1ea50733 100644 --- a/po/pl_PL.po +++ b/po/pl_PL.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds-messages\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: 2007-03-31 00:24+0200\n" "Last-Translator: Rafal Slubowski <rafalslubowski@gmail.com>\n" "Language-Team: polski <pl@li.org>\n" @@ -603,6 +603,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" diff --git a/po/ru_RU.po b/po/ru_RU.po index eacf5932..2a9bbdda 100644 --- a/po/ru_RU.po +++ b/po/ru_RU.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: rscds 0.3.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-11-04 23:31+1300\n" +"POT-Creation-Date: 2007-11-17 22:06+1300\n" "PO-Revision-Date: 2006-11-13 23:07+0500\n" "Last-Translator: Nick Khazov <m2k3d0n@users.sourceforge.net>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -618,6 +618,10 @@ msgstr "" msgid "drivers_ldap : function ldap_connect not defined, check your php_ldap module" msgstr "" +#, c-format +msgid "drivers_squid_pam : Unable to find %s file" +msgstr "" + msgid "" "forget me not <!-- this is a colloquial phrase in english (the name of a flower) and is an option " "allowing people to log in automatically in future -->" From 67801057d1adb7168fdf47771d669692533aa707 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 18 Nov 2007 09:38:09 +1300 Subject: [PATCH 144/189] Note that PostgreSQL needs a reload after modifying pg_hba.conf --- docs/website/installation.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/website/installation.php b/docs/website/installation.php index feebd8f8..e477f4e5 100644 --- a/docs/website/installation.php +++ b/docs/website/installation.php @@ -163,6 +163,10 @@ database on a different server, you should read the <a href="http://www.postgresql.org/docs/8.1/interactive/client-authentication.html">PostgreSQL documentation on pg_hba.conf</a> for the version you are using.</p> +<p>Once you have changed the pg_hba.conf file you will need to +reload or restart the PostgreSQL process for the change to come +into effect.</p> + <h1>Apache VHost Configuration</h1> <p>Your Apache instance needs to be configured for Virtual Hosts. If From 4d3f233756862cedecf04a96bf6910ed89ce00d2 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 18 Nov 2007 10:16:54 +1300 Subject: [PATCH 145/189] Switch freebusy style to match GET url response. --- inc/caldav-REPORT-freebusy.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/inc/caldav-REPORT-freebusy.php b/inc/caldav-REPORT-freebusy.php index 5edfd2b5..30037914 100644 --- a/inc/caldav-REPORT-freebusy.php +++ b/inc/caldav-REPORT-freebusy.php @@ -6,8 +6,8 @@ include_once("iCalendar.php"); include_once("RRule.php"); $fbq_content = $xmltree->GetContent('URN:IETF:PARAMS:XML:NS:CALDAV:FREE-BUSY-QUERY'); -$fbq_start = $fbq_content[0]->GetAttribute('START'); -$fbq_end = $fbq_content[0]->GetAttribute('END'); +$fbq_start = $fbq_content[0]->GetAttribute('START'); +$fbq_end = $fbq_content[0]->GetAttribute('END'); if ( ! ( isset($fbq_start) || isset($fbq_end) ) ) { $request->DoResponse( 400, 'All valid freebusy requests MUST contain a time-range filter' ); @@ -64,11 +64,13 @@ foreach( $busy_tentative AS $k => $v ) { while ( $date = $rrule->GetNext() ) { if ( ! $date->GreaterThan($fbq_start) ) continue; if ( $date->GreaterThan($fbq_end) ) break; - $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $duration ); + $todate = clone($date); + $todate->AddDuration($duration); + $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $date->Render('Ymd\THis'), $todate->Render('Ymd\THis') ); } } else { - $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $start->Render('Ymd\THis'), $duration ); + $freebusy .= sprintf("FREEBUSY;FBTYPE=BUSY-TENTATIVE:%s/%s\n", $start->Render('Ymd\THis'), $v->finish ); } } @@ -80,11 +82,13 @@ foreach( $busy AS $k => $v ) { while ( $date = $rrule->GetNext() ) { if ( ! $date->GreaterThan($fbq_start) ) continue; if ( $date->GreaterThan($fbq_end) ) break; - $freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $duration ); + $todate = clone($date); + $todate->AddDuration($duration); + $freebusy .= sprintf("FREEBUSY:%s/%s\n", $date->Render('Ymd\THis'), $todate->Render('Ymd\THis') ); } } else { - $freebusy .= sprintf("FREEBUSY:%s/%s\n", $start->Render('Ymd\THis'), $duration ); + $freebusy .= sprintf("FREEBUSY:%s/%s\n", $start->Render('Ymd\THis'), $v->finish ); } } From ad17ee8a2b56467717cb732dd464398448ec5215 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Fri, 23 Nov 2007 23:01:47 +1300 Subject: [PATCH 146/189] Use wrapper functions to construct tag namespaces. --- inc/caldav-PROPFIND.php | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index a0b8128b..e3588714 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -65,6 +65,7 @@ function ns_tag( $in_tag, $namespace=null, $prefix=null ) { $tag = $in_tag; } $namespace = strtolower($namespace); + $tag = strtolower($tag); if ( $prefix == null ) { // Attempt to assign one @@ -72,9 +73,10 @@ function ns_tag( $in_tag, $namespace=null, $prefix=null ) { $prefix = $namespaces[$namespace]; } else { - // Try and build a prefix based on the first character of the last element of the namespace + // Try and build a prefix based on the first alphabetic character of the last element of the namespace if ( preg_match('/^(.*):([^:]+)$/', $namespace, $matches) ) { - $prefix = strtoupper(substr($matches[2],0,1)); + $alpha = preg_replace( '/[^a-z]/i', '', $matches[2] ); + $prefix = strtoupper(substr($alpha,0,1)); } else { $prefix = 'x'; @@ -413,15 +415,7 @@ function collection_to_xml( $collection ) { if ( count($collection->properties) > 0 ) { foreach( $collection->properties AS $k => $v ) { - if ( preg_match('/^(.*):([^:]+)$/', $k, $matches) ) { - $namespace = $matches[1]; - $tag = $matches[2]; - } - else { - $namespace = ""; - $tag = $k; - } - $prop->NewElement(strtolower($tag), $v, array("xmlns" => strtolower($namespace)) ); + $prop->NewElement(ns_tag($k), $v); } } @@ -462,15 +456,7 @@ function collection_to_xml( $collection ) { if ( count($arbitrary_results->missing) > 0 ) { foreach( $arbitrary_results->missing AS $k => $v ) { - if ( preg_match('/^(.*):([^:]+)$/', $k, $matches) ) { - $namespace = $matches[1]; - $tag = $matches[2]; - } - else { - $namespace = ""; - $tag = $k; - } - $not_found->NewElement(strtolower($tag), '', array("xmlns" => strtolower($namespace)) ); + $not_found->NewElement(ns_tag($k), ''); } } From 552bb6f0e8f47f0e5a6d4b56f991221b6b566b3e Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Fri, 23 Nov 2007 23:32:05 +1300 Subject: [PATCH 147/189] Debugging namespace change, with updated regression results. --- inc/caldav-PROPFIND.php | 7 +-- .../401-Cadaver-PROPFIND-1.result | 8 ++-- .../regression-suite/510-iCal-PROPFIND.result | 14 +++--- .../regression-suite/511-iCal-PROPFIND.result | 16 +++---- .../regression-suite/602-Soho-PROPFIND.result | 14 +++--- .../regression-suite/603-Soho-PROPFIND.result | 14 +++--- .../regression-suite/604-Soho-PROPFIND.result | 10 ++-- .../820-Spec-PROPFIND-1.result | 8 ++-- .../821-Spec-PROPFIND-2.result | 14 +++--- .../822-Spec-PROPFIND-3.result | 8 ++-- .../regression-suite/826-Spec-PROPFIND.result | 8 ++-- .../regression-suite/827-Spec-PROPFIND.result | 48 +++++++++---------- .../regression-suite/843-Spec-PROPFIND.result | 6 +-- .../870-Principal-PROPFIND.result | 8 ++-- 14 files changed, 92 insertions(+), 91 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index e3588714..a366abc5 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -48,7 +48,7 @@ function add_namespace( $prefix, $namespace ) { function ns_tag( $in_tag, $namespace=null, $prefix=null ) { - global $namespaces; + global $namespaces, $prefixes; if ( $namespace == null ) { // Attempt to split out from namespace:tag @@ -65,6 +65,7 @@ function ns_tag( $in_tag, $namespace=null, $prefix=null ) { $tag = $in_tag; } $namespace = strtolower($namespace); + if ( $namespace == 'dav:' ) $namespace = 'DAV:'; // Special case for conventional naming $tag = strtolower($tag); if ( $prefix == null ) { @@ -83,7 +84,7 @@ function ns_tag( $in_tag, $namespace=null, $prefix=null ) { } $i = ""; if ( isset($prefixes[$prefix]) ) { - for ( $i=1; $i<20 && isset($prefixes["$prefix$i"]); $i++ ) { + for ( $i=1; $i<10 && isset($prefixes["$prefix$i"]); $i++ ) { } } if ( isset($prefixes["$prefix$i"]) ) { @@ -100,7 +101,7 @@ function ns_tag( $in_tag, $namespace=null, $prefix=null ) { add_namespace( $prefix, $namespace ); } - return $prefix . ":" . $tag; + return $prefix . ($prefix == "" ? "" : ":") . $tag; } diff --git a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result index 8a43ce96..c20d0286 100644 --- a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result +++ b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" ?> -<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:A="http://apache.org/dav/props/"> <response> <href>http://mycaldav/caldav.php/user1/home/</href> <propstat> @@ -15,9 +15,9 @@ </propstat> <propstat> <prop> - <executable xmlns="http://apache.org/dav/props/"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <A:executable/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/510-iCal-PROPFIND.result b/testing/tests/regression-suite/510-iCal-PROPFIND.result index 49c31771..2ff57364 100644 --- a/testing/tests/regression-suite/510-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/510-iCal-PROPFIND.result @@ -1,12 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "455c90fdc59860d7dfa851ad1f75b4ba" -Content-Length: 847 +ETag: "58323b4af2f8d17c9fd4412652c18a5c" +Content-Length: 746 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> -<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:C1="http://calendarserver.org/ns/"> <response> <href>/caldav.php/user1/home/</href> <propstat> @@ -23,10 +23,10 @@ Content-Type: text/xml; charset="utf-8" </propstat> <propstat> <prop> - <schedule-inbox-url xmlns="urn:ietf:params:xml:ns:caldav"/> - <schedule-outbox-url xmlns="urn:ietf:params:xml:ns:caldav"/> - <dropbox-home-url xmlns="http://calendarserver.org/ns/"/> - <notifications-url xmlns="http://calendarserver.org/ns/"/> + <C:schedule-inbox-url/> + <C:schedule-outbox-url/> + <C1:dropbox-home-url/> + <C1:notifications-url/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/511-iCal-PROPFIND.result b/testing/tests/regression-suite/511-iCal-PROPFIND.result index 35da6638..ef9a43e0 100644 --- a/testing/tests/regression-suite/511-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/511-iCal-PROPFIND.result @@ -1,12 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "3c6167921378348411a110b1db03b7d4" -Content-Length: 796 +ETag: "d595bef8c261fd561df6bb7eec2f3734" +Content-Length: 659 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> -<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:C1="http://calendarserver.org/ns/"> <response> <href>/</href> <propstat> @@ -20,11 +20,11 @@ Content-Type: text/xml; charset="utf-8" </propstat> <propstat> <prop> - <calendar-user-address-set xmlns="urn:ietf:params:xml:ns:caldav"/> - <schedule-inbox-url xmlns="urn:ietf:params:xml:ns:caldav"/> - <schedule-outbox-url xmlns="urn:ietf:params:xml:ns:caldav"/> - <dropbox-home-url xmlns="http://calendarserver.org/ns/"/> - <notifications-url xmlns="http://calendarserver.org/ns/"/> + <C:calendar-user-address-set/> + <C:schedule-inbox-url/> + <C:schedule-outbox-url/> + <C1:dropbox-home-url/> + <C1:notifications-url/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/602-Soho-PROPFIND.result b/testing/tests/regression-suite/602-Soho-PROPFIND.result index 69528def..877fc9c1 100644 --- a/testing/tests/regression-suite/602-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/602-Soho-PROPFIND.result @@ -1,12 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "f501a70013d679ecd57dc0981fdb62e1" -Content-Length: 5847 +ETag: "abe3054a40d9f860fe9ccabef5e558db" +Content-Length: 5725 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> -<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:A="http://apple.com/ns/calendarserver/"> <response> <href>/caldav.php/user1/</href> <propstat> @@ -22,8 +22,8 @@ Content-Type: text/xml; charset="utf-8" </propstat> <propstat> <prop> - <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> - <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + <A:dropbox-home-url/> + <A:notifications-url/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> @@ -43,8 +43,8 @@ Content-Type: text/xml; charset="utf-8" </propstat> <propstat> <prop> - <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> - <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + <A:dropbox-home-url/> + <A:notifications-url/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/603-Soho-PROPFIND.result b/testing/tests/regression-suite/603-Soho-PROPFIND.result index 0aa867ef..3edfc407 100644 --- a/testing/tests/regression-suite/603-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/603-Soho-PROPFIND.result @@ -1,12 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "82a2af4a319c7702f65e131574e63754" -Content-Length: 1261 +ETag: "461b0f96e42a2b69d256b99bc8d2ea1e" +Content-Length: 1139 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> -<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:A="http://apple.com/ns/calendarserver/"> <response> <href>/caldav.php/user1/</href> <propstat> @@ -22,8 +22,8 @@ Content-Type: text/xml; charset="utf-8" </propstat> <propstat> <prop> - <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> - <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + <A:dropbox-home-url/> + <A:notifications-url/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> @@ -43,8 +43,8 @@ Content-Type: text/xml; charset="utf-8" </propstat> <propstat> <prop> - <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> - <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + <A:dropbox-home-url/> + <A:notifications-url/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/604-Soho-PROPFIND.result b/testing/tests/regression-suite/604-Soho-PROPFIND.result index 17697d3c..25576b7a 100644 --- a/testing/tests/regression-suite/604-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/604-Soho-PROPFIND.result @@ -1,12 +1,12 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "c240d5bc59682fd96a47d4b802052879" -Content-Length: 689 +ETag: "f90fce514cd7d7155fcb48f704e9f171" +Content-Length: 651 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> -<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:A="http://apple.com/ns/calendarserver/"> <response> <href>/caldav.php/user1/</href> <propstat> @@ -22,8 +22,8 @@ Content-Type: text/xml; charset="utf-8" </propstat> <propstat> <prop> - <dropbox-home-url xmlns="http://apple.com/ns/calendarserver/"/> - <notifications-url xmlns="http://apple.com/ns/calendarserver/"/> + <A:dropbox-home-url/> + <A:notifications-url/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result index 963cdd0e..00252749 100644 --- a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result +++ b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result @@ -39,10 +39,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result index 92c49000..1b3fb3c5 100644 --- a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result +++ b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result @@ -2,7 +2,7 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access ETag: "deadbeefcafefeeddeadbeefcafefeed" -Content-Length: 1219 +Content-Length: 1141 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -37,12 +37,12 @@ Content-Type: text/xml; charset="utf-8" </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> - <bogus-property xmlns="dav:"/> - <contentbogosity xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> + <bogus-property/> + <contentbogosity/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result index 1e021b20..8176541b 100644 --- a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result +++ b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result @@ -30,10 +30,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/826-Spec-PROPFIND.result b/testing/tests/regression-suite/826-Spec-PROPFIND.result index b82c988d..a0aaa047 100644 --- a/testing/tests/regression-suite/826-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/826-Spec-PROPFIND.result @@ -38,10 +38,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/827-Spec-PROPFIND.result b/testing/tests/regression-suite/827-Spec-PROPFIND.result index 7bb50089..9fe8cf78 100644 --- a/testing/tests/regression-suite/827-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/827-Spec-PROPFIND.result @@ -38,10 +38,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> @@ -85,10 +85,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> @@ -132,10 +132,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> @@ -179,10 +179,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> @@ -226,10 +226,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> @@ -273,10 +273,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/843-Spec-PROPFIND.result b/testing/tests/regression-suite/843-Spec-PROPFIND.result index 3825c211..844a2f62 100644 --- a/testing/tests/regression-suite/843-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/843-Spec-PROPFIND.result @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="utf-8" ?> -<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:R="urn:mcmillan:bogus:xml:ns:rscds"> <response> <href>http://mycaldav/caldav.php/user1/home/</href> <propstat> <prop> <displayname>User One's Calendar</displayname> - <arbitrary xmlns="urn:mcmillan:bogus:xml:ns:rscds">A completely bogus property which should be saved.</arbitrary> + <R:arbitrary>A completely bogus property which should be saved.</R:arbitrary> </prop> <status>HTTP/1.1 200 OK</status> </propstat> <propstat> <prop> - <owner xmlns="dav:"/> + <owner/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> diff --git a/testing/tests/regression-suite/870-Principal-PROPFIND.result b/testing/tests/regression-suite/870-Principal-PROPFIND.result index 68f6c38b..6072e362 100644 --- a/testing/tests/regression-suite/870-Principal-PROPFIND.result +++ b/testing/tests/regression-suite/870-Principal-PROPFIND.result @@ -39,10 +39,10 @@ </propstat> <propstat> <prop> - <lockdiscovery xmlns="dav:"/> - <source xmlns="dav:"/> - <checked-in xmlns="dav:"/> - <checked-out xmlns="dav:"/> + <lockdiscovery/> + <source/> + <checked-in/> + <checked-out/> </prop> <status>HTTP/1.1 404 Not Found</status> </propstat> From a293bac9bb7941a86569baae2d7af316de9234ee Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 24 Nov 2007 00:01:04 +1300 Subject: [PATCH 148/189] Adding a bunch of more thorough regression tests to match iCal behaviour. --- .../regression-suite/502-iCal-PROPFIND.result | 50 ++++++ .../regression-suite/502-iCal-PROPFIND.test | 22 +++ .../regression-suite/503-iCal-PROPFIND.result | 31 ++++ .../regression-suite/503-iCal-PROPFIND.test | 23 +++ .../regression-suite/504-iCal-PROPFIND.result | 143 ++++++++++++++++++ .../regression-suite/504-iCal-PROPFIND.test | 20 +++ .../regression-suite/505-iCal-PUT.result | 8 + .../tests/regression-suite/505-iCal-PUT.test | 68 +++++++++ .../regression-suite/506-iCal-PUT.result | 8 + .../tests/regression-suite/506-iCal-PUT.test | 69 +++++++++ .../regression-suite/602-Soho-PROPFIND.result | 18 ++- .../820-Spec-PROPFIND-1.result | 2 +- .../821-Spec-PROPFIND-2.result | 4 +- .../822-Spec-PROPFIND-3.result | 28 +++- .../824-Spec-PROPFIND-5.result | 2 +- .../regression-suite/900-Moz-REPORT.result | 59 +++++++- .../901-GET-Collection.result | 38 ++++- 17 files changed, 577 insertions(+), 16 deletions(-) create mode 100644 testing/tests/regression-suite/502-iCal-PROPFIND.result create mode 100644 testing/tests/regression-suite/502-iCal-PROPFIND.test create mode 100644 testing/tests/regression-suite/503-iCal-PROPFIND.result create mode 100644 testing/tests/regression-suite/503-iCal-PROPFIND.test create mode 100644 testing/tests/regression-suite/504-iCal-PROPFIND.result create mode 100644 testing/tests/regression-suite/504-iCal-PROPFIND.test create mode 100644 testing/tests/regression-suite/505-iCal-PUT.result create mode 100644 testing/tests/regression-suite/505-iCal-PUT.test create mode 100644 testing/tests/regression-suite/506-iCal-PUT.result create mode 100644 testing/tests/regression-suite/506-iCal-PUT.test diff --git a/testing/tests/regression-suite/502-iCal-PROPFIND.result b/testing/tests/regression-suite/502-iCal-PROPFIND.result new file mode 100644 index 00000000..21dd3ab5 --- /dev/null +++ b/testing/tests/regression-suite/502-iCal-PROPFIND.result @@ -0,0 +1,50 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "fd1ab8da7166728112e8028466b371d4" +Content-Length: 966 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:A="http://apple.com/ns/ical/"> + <response> + <href>/caldav.php/user1/</href> + <propstat> + <prop> + <resourcetype> + <collection/> + <principal/> + </resourcetype> + <displayname>User_1</displayname> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <C:calendar-description/> + <A:calendar-color/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/</href> + <propstat> + <prop> + <resourcetype> + <collection/> + <C:calendar/> + </resourcetype> + <displayname>home</displayname> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <C:calendar-description/> + <A:calendar-color/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/502-iCal-PROPFIND.test b/testing/tests/regression-suite/502-iCal-PROPFIND.test new file mode 100644 index 00000000..98ba7a33 --- /dev/null +++ b/testing/tests/regression-suite/502-iCal-PROPFIND.test @@ -0,0 +1,22 @@ +# +# Testing with a process similar to iCal 10.5 +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/ +HEAD + +HEADER=User-Agent: DAVKit/2.0 (10.5; wrbt) iCal 3.0 +HEADER=Content-Type: text/xml +HEADER=Depth: 1 + +BEGINDATA +<?xml version="1.0" encoding="utf-8"?> +<x0:propfind xmlns:x1="urn:ietf:params:xml:ns:caldav" xmlns:x0="DAV:" xmlns:x2="http://apple.com/ns/ical/"> + <x0:prop> + <x0:displayname/> + <x1:calendar-description/> + <x2:calendar-color/> + <x0:resourcetype/> + </x0:prop> +</x0:propfind> +ENDDATA diff --git a/testing/tests/regression-suite/503-iCal-PROPFIND.result b/testing/tests/regression-suite/503-iCal-PROPFIND.result new file mode 100644 index 00000000..3cc4b197 --- /dev/null +++ b/testing/tests/regression-suite/503-iCal-PROPFIND.result @@ -0,0 +1,31 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "45e62f9b3b6b55ac40673d4ef35948b9" +Content-Length: 623 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:C1="http://calendarserver.org/ns/" xmlns:A="http://apple.com/ns/ical/"> + <response> + <href>/caldav.php/user1/home/</href> + <propstat> + <prop> + <resourcetype> + <collection/> + <C:calendar/> + </resourcetype> + <displayname>home</displayname> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <C1:getctag/> + <A:calendar-color/> + <C:calendar-description/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/503-iCal-PROPFIND.test b/testing/tests/regression-suite/503-iCal-PROPFIND.test new file mode 100644 index 00000000..8c0acb34 --- /dev/null +++ b/testing/tests/regression-suite/503-iCal-PROPFIND.test @@ -0,0 +1,23 @@ +# +# Testing with a process similar to iCal 10.5 +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/home/ +HEAD + +HEADER=User-Agent: DAVKit/2.0 (10.5; wrbt) iCal 3.0 +HEADER=Content-Type: text/xml +HEADER=Depth: 0 + +BEGINDATA +<?xml version="1.0" encoding="utf-8"?> +<x0:propfind xmlns:x1="http://calendarserver.org/ns/" xmlns:x0="DAV:" xmlns:x2="http://apple.com/ns/ical/" xmlns:x3="urn:ietf:params:xml:ns:caldav"> + <x0:prop> + <x0:displayname/> + <x1:getctag/> + <x2:calendar-color/> + <x3:calendar-description/> + <x0:resourcetype/> + </x0:prop> +</x0:propfind> +ENDDATA diff --git a/testing/tests/regression-suite/504-iCal-PROPFIND.result b/testing/tests/regression-suite/504-iCal-PROPFIND.result new file mode 100644 index 00000000..79aaf950 --- /dev/null +++ b/testing/tests/regression-suite/504-iCal-PROPFIND.result @@ -0,0 +1,143 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "47e34444ff36653135bc516cd861b019" +Content-Length: 3575 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> + <response> + <href>/caldav.php/user1/home/</href> + <propstat> + <prop> + <resourcetype> + <collection/> + <C:calendar/> + </resourcetype> + <getetag>"faf25336de0e470a54075c14cbcf5272"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/0575d895-a006-4ed8-9be6-0d1b6b6b1f96.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"00ad5eb1eb5507884710b0b66aa5d5c4"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/1906b3ca-4890-468a-9b58-1de74bf2c716.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"5def8ae2b20893a1c7f4dbaeb008f2f1"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/20061101T073004Z.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"c3658901fd4689d4a1e1d6f08601ef4f"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/2178279a-aec2-471f-832d-1f6df6203f2f.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"509b0f0d8a3363379f9f5727f5dd74a0"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"a1c6404d61190f9574e2bfd69383f144"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/71e2ae82-7870-11db-c6d6-f6927c144649.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"0d7a68984bf525342d22b8924a57e8e2"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/917b9e47-b748-4550-a566-657fbe672447.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"cb3d9dc3e8c157f53eba3ea0e1e0f146"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/9d050be7-8a02-4355-8ed3-02a9fc5f473f.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"08a435c2abaf38f4a50a997343c098a7"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/b1679f77-673d-4f46-b3eb-2420e1bba301.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"a2990674708634a311bb98a59865ca50"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"421abf7e4848d2fecbf64217ed205d4b"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"ac90acd649c25070b1a2a17fb31a105a"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/504-iCal-PROPFIND.test b/testing/tests/regression-suite/504-iCal-PROPFIND.test new file mode 100644 index 00000000..8e5ddaf3 --- /dev/null +++ b/testing/tests/regression-suite/504-iCal-PROPFIND.test @@ -0,0 +1,20 @@ +# +# Testing with a process similar to iCal 10.5 +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/home/ +HEAD + +HEADER=User-Agent: DAVKit/2.0 (10.5; wrbt) iCal 3.0 +HEADER=Content-Type: text/xml +HEADER=Depth: 1 + +BEGINDATA +<?xml version="1.0" encoding="utf-8"?> +<x0:propfind xmlns:x0="DAV:"> + <x0:prop> + <x0:getetag/> + <x0:resourcetype/> + </x0:prop> +</x0:propfind> +ENDDATA diff --git a/testing/tests/regression-suite/505-iCal-PUT.result b/testing/tests/regression-suite/505-iCal-PUT.result new file mode 100644 index 00000000..e0d76fe2 --- /dev/null +++ b/testing/tests/regression-suite/505-iCal-PUT.result @@ -0,0 +1,8 @@ +HTTP/1.1 201 Created +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "b3e66a461ef178bd4791b2b6509bbb9d" +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +10 --- VEVENT --- 10 --- AAA9318E-37D9-4319-8626-95ECD3D3B243 --- 2007-11-23 09:30:48 --- 2007-11-25 23:00:00+13 --- 2007-11-26 00:00:00+13 --- --- New Event --- --- --- --- PUBLIC --- OPAQUE --- --- --- --- --- diff --git a/testing/tests/regression-suite/505-iCal-PUT.test b/testing/tests/regression-suite/505-iCal-PUT.test new file mode 100644 index 00000000..fe3d2466 --- /dev/null +++ b/testing/tests/regression-suite/505-iCal-PUT.test @@ -0,0 +1,68 @@ +# +# PUT another event into the resource2 calendar so we can DELETE it +# +TYPE=PUT +URL=http://mycaldav/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics +HEADER=Content-Type: text/calendar +HEAD + + +BEGINDATA +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 3.0//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Pacific/Auckland +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+1200 +TZOFFSETTO:+1300 +DTSTART:20070930T020000 +RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU +TZNAME:NZDT +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:20080406T030000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +TZNAME:NZST +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:1 +TRANSP:OPAQUE +UID:AAA9318E-37D9-4319-8626-95ECD3D3B243 +DTSTART;TZID=Pacific/Auckland:20071125T230000 +DTSTAMP:20071123T093048Z +SUMMARY:New Event +CREATED:20071123T093048Z +DTEND;TZID=Pacific/Auckland:20071126T000000 +BEGIN:VALARM +X-WR-ALARMUID:2927836F-DF85-4688-901A-9ABE442BFB62 +ACTION:AUDIO +TRIGGER:-PT15M +ATTACH;VALUE=URI:Basso +END:VALARM +END:VEVENT +END:VCALENDAR +ENDDATA + + +QUERY +SELECT caldav_data.user_no, caldav_type, logged_user, + uid, dtstamp, dtstart, dtend, due, summary, location, + description, priority, class, transp, rrule, url, + percent_complete, tz_id, status +FROM caldav_data JOIN calendar_item USING(dav_name) +WHERE caldav_data.dav_etag = +'b3e66a461ef178bd4791b2b6509bbb9d'; +ENDQUERY + diff --git a/testing/tests/regression-suite/506-iCal-PUT.result b/testing/tests/regression-suite/506-iCal-PUT.result new file mode 100644 index 00000000..47298e25 --- /dev/null +++ b/testing/tests/regression-suite/506-iCal-PUT.result @@ -0,0 +1,8 @@ +HTTP/1.1 204 No Content +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "5f050eca5480bbebbe9428222570913d" +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +10 --- VEVENT --- 10 --- AAA9318E-37D9-4319-8626-95ECD3D3B243 --- 2007-11-23 09:32:23 --- 2007-11-25 13:00:00+13 --- 2007-11-25 19:00:00+13 --- --- BBQ @ ML's --- ML's House --- --- --- PUBLIC --- OPAQUE --- --- --- --- --- diff --git a/testing/tests/regression-suite/506-iCal-PUT.test b/testing/tests/regression-suite/506-iCal-PUT.test new file mode 100644 index 00000000..1079d608 --- /dev/null +++ b/testing/tests/regression-suite/506-iCal-PUT.test @@ -0,0 +1,69 @@ +# +# PUT a newer version of the event into the calendar. +# +TYPE=PUT +URL=http://mycaldav/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics +HEADER=Content-Type: text/calendar +HEADER=If-Match: "b3e66a461ef178bd4791b2b6509bbb9d" +HEAD + + +BEGINDATA +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 3.0//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Pacific/Auckland +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+1200 +TZOFFSETTO:+1300 +DTSTART:20070930T020000 +RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU +TZNAME:NZDT +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:20080406T030000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +TZNAME:NZST +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:6 +TRANSP:OPAQUE +UID:AAA9318E-37D9-4319-8626-95ECD3D3B243 +DTSTART;TZID=Pacific/Auckland:20071125T130000 +DTSTAMP:20071123T093223Z +SUMMARY:BBQ @ ML's +CREATED:20071123T093048Z +DTEND;TZID=Pacific/Auckland:20071125T190000 +LOCATION:ML's House +BEGIN:VALARM +X-WR-ALARMUID:2927836F-DF85-4688-901A-9ABE442BFB62 +ACTION:AUDIO +TRIGGER:-PT15M +ATTACH;VALUE=URI:Basso +END:VALARM +END:VEVENT +END:VCALENDAR +ENDDATA + + +QUERY +SELECT caldav_data.user_no, caldav_type, logged_user, + uid, dtstamp, dtstart, dtend, due, summary, location, + description, priority, class, transp, rrule, url, + percent_complete, tz_id, status +FROM caldav_data JOIN calendar_item USING(dav_name) +WHERE caldav_data.dav_etag = +'5f050eca5480bbebbe9428222570913d'; +ENDQUERY diff --git a/testing/tests/regression-suite/602-Soho-PROPFIND.result b/testing/tests/regression-suite/602-Soho-PROPFIND.result index 877fc9c1..07ec4d6b 100644 --- a/testing/tests/regression-suite/602-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/602-Soho-PROPFIND.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "abe3054a40d9f860fe9ccabef5e558db" -Content-Length: 5725 +ETag: "0f77e8fc1531888183e35da896c95287" +Content-Length: 6109 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -175,6 +175,20 @@ Content-Type: text/xml; charset="utf-8" <status>HTTP/1.1 200 OK</status> </propstat> </response> + <response> + <href>/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> <response> <href>/caldav.php/user1/home/b1679f77-673d-4f46-b3eb-2420e1bba301.ics</href> <propstat> diff --git a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result index 00252749..5ef3242f 100644 --- a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result +++ b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result @@ -6,7 +6,7 @@ <prop> <getcontenttype>httpd/unix-directory</getcontenttype> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>9531</getcontentlength> + <getcontentlength>10512</getcontentlength> <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> <resourcetype> <collection/> diff --git a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result index 1b3fb3c5..dcf27031 100644 --- a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result +++ b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result @@ -2,7 +2,7 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access ETag: "deadbeefcafefeeddeadbeefcafefeed" -Content-Length: 1141 +Content-Length: 1142 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -13,7 +13,7 @@ Content-Type: text/xml; charset="utf-8" <prop> <getcontenttype>httpd/unix-directory</getcontenttype> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>9531</getcontentlength> + <getcontentlength>10512</getcontentlength> <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> <resourcetype> <collection/> diff --git a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result index 8176541b..767ebeaf 100644 --- a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result +++ b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result @@ -6,7 +6,7 @@ <prop> <getcontenttype>httpd/unix-directory</getcontenttype> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>9531</getcontentlength> + <getcontentlength>10512</getcontentlength> <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> <resourcetype> <collection/> @@ -272,6 +272,32 @@ <status>HTTP/1.1 200 OK</status> </propstat> </response> + <response> + <href>/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href> + <propstat> + <prop> + <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> + <getcontentlength>981</getcontentlength> + <getcontenttype>text/calendar</getcontenttype> + <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> + <resourcetype/> + <displayname>BBQ @ ML's</displayname> + <getetag>"5f050eca5480bbebbe9428222570913d"</getetag> + <getcontentlanguage>en_NZ.UTF-8</getcontentlanguage> + <supportedlock> + <lockentry> + <lockscope> + <exclusive/> + </lockscope> + <locktype> + <write/> + </locktype> + </lockentry> + </supportedlock> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> <response> <href>/caldav.php/user1/home/b1679f77-673d-4f46-b3eb-2420e1bba301.ics</href> <propstat> diff --git a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result index 36d01e86..6cdbfe77 100644 --- a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result +++ b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result @@ -14,7 +14,7 @@ </C:supported-calendar-component-set> <getcontenttype>httpd/unix-directory</getcontenttype> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>9531</getcontentlength> + <getcontentlength>10512</getcontentlength> <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> <resourcetype> <collection/> diff --git a/testing/tests/regression-suite/900-Moz-REPORT.result b/testing/tests/regression-suite/900-Moz-REPORT.result index 793501b2..166138ab 100644 --- a/testing/tests/regression-suite/900-Moz-REPORT.result +++ b/testing/tests/regression-suite/900-Moz-REPORT.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "d19579c20ab7e6349b50af9e16ef5abd" -Content-Length: 6643 +ETag: "78f60a204e7deae626d7a11a8f7f8d8e" +Content-Length: 7901 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/xml; charset="utf-8" @@ -180,6 +180,61 @@ RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=10 END:DAYLIGHT END:VTIMEZONE END:VCALENDAR +</calendar-data> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>http://mycaldav/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href> + <propstat> + <prop> + <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 3.0//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Pacific/Auckland +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+1200 +TZOFFSETTO:+1300 +DTSTART:20070930T020000 +RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU +TZNAME:NZDT +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:20080406T030000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +TZNAME:NZST +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:6 +TRANSP:OPAQUE +UID:AAA9318E-37D9-4319-8626-95ECD3D3B243 +DTSTART;TZID=Pacific/Auckland:20071125T130000 +DTSTAMP:20071123T093223Z +SUMMARY:BBQ @ ML's +CREATED:20071123T093048Z +DTEND;TZID=Pacific/Auckland:20071125T190000 +LOCATION:ML's House +BEGIN:VALARM +X-WR-ALARMUID:2927836F-DF85-4688-901A-9ABE442BFB62 +ACTION:AUDIO +TRIGGER:-PT15M +ATTACH;VALUE=URI:Basso +END:VALARM +END:VEVENT +END:VCALENDAR </calendar-data> </prop> <status>HTTP/1.1 200 OK</status> diff --git a/testing/tests/regression-suite/901-GET-Collection.result b/testing/tests/regression-suite/901-GET-Collection.result index db60777d..d7d11678 100644 --- a/testing/tests/regression-suite/901-GET-Collection.result +++ b/testing/tests/regression-suite/901-GET-Collection.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -Content-Length: 5784 +Content-Length: 6340 Content-Type: text/calendar BEGIN:VCALENDAR @@ -120,6 +120,23 @@ DTEND;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T180000 X-MOZ-LOCATIONPATH:9d050be7-8a02-4355-8ed3-02a9fc5f473f.ics LOCATION:In a confidential place END:VEVENT +BEGIN:VEVENT +SEQUENCE:6 +TRANSP:OPAQUE +UID:AAA9318E-37D9-4319-8626-95ECD3D3B243 +DTSTART;TZID=Pacific/Auckland:20071125T130000 +DTSTAMP:20071123T093223Z +SUMMARY:BBQ @ ML's +CREATED:20071123T093048Z +DTEND;TZID=Pacific/Auckland:20071125T190000 +LOCATION:ML's House +BEGIN:VALARM +X-WR-ALARMUID:2927836F-DF85-4688-901A-9ABE442BFB62 +ACTION:AUDIO +TRIGGER:-PT15M +ATTACH;VALUE=URI:Basso +END:VALARM +END:VEVENT BEGIN:VTODO CREATED:20070806T223244Z LAST-MODIFIED:20070806T223411Z @@ -177,18 +194,25 @@ END:VTIMEZONE BEGIN:VTIMEZONE TZID:Pacific/Auckland BEGIN:STANDARD -DTSTART:20000319T030000 -RRULE:FREQ=YEARLY;BYDAY=3SU;BYMONTH=3 -TZNAME:Pacific/Auckland TZOFFSETFROM:+1300 TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST END:STANDARD BEGIN:DAYLIGHT -DTSTART:20001001T020000 -RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=10 -TZNAME:Pacific/Auckland TZOFFSETFROM:+1200 TZOFFSETTO:+1300 +DTSTART:20070930T020000 +RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU +TZNAME:NZDT END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:20080406T030000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +TZNAME:NZST +END:STANDARD END:VTIMEZONE END:VCALENDAR From 114b4a1f266c98096af6dd17336dce68d8128a80 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 24 Nov 2007 21:34:29 +1300 Subject: [PATCH 149/189] Tweaks to MKCALENDAR to make it work with iCal. --- inc/caldav-MKCALENDAR.php | 24 ++++++++++----- .../507-iCal-MKCALENDAR.result | 8 +++++ .../regression-suite/507-iCal-MKCALENDAR.test | 29 +++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 testing/tests/regression-suite/507-iCal-MKCALENDAR.result create mode 100644 testing/tests/regression-suite/507-iCal-MKCALENDAR.test diff --git a/inc/caldav-MKCALENDAR.php b/inc/caldav-MKCALENDAR.php index def4adbe..d22730ba 100644 --- a/inc/caldav-MKCALENDAR.php +++ b/inc/caldav-MKCALENDAR.php @@ -49,16 +49,26 @@ if ( isset($request->xml_tags) ) { case 'DAV::DISPLAYNAME': $displayname = $content; - dbg_error_log( "MKCALENDAR", "Displayname is '/' to '%s'", $request->path); - $parent_container = $request->path; - $request->path .= $content . '/'; + /** + * TODO: This is definitely a bug in SOHO Organizer and we probably should respond + * with an error, rather than silently doing what they *seem* to want us to do. + */ + if ( preg_match( '/ SOHO Organizer\/6\./', $_SERVER['HTTP_USER_AGENT'] ) ) { + dbg_error_log( "MKCALENDAR", "Displayname is '/' to '%s'", $request->path); + $parent_container = $request->path; + $request->path .= $content . '/'; + } $success[$tag] = 1; break; - case 'DAV::RESOURCETYPE': - /** - * Any value for resourcetype is ignored - */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET': /** Ignored, since we will support all component types */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-DATA': /** Ignored, since we will support iCalendar 2.0 */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DATA': /** Ignored, since we will support iCalendar 2.0 */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-RESOURCE-SIZE': /** Ignored, since we will support arbitrary size */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:MIN-DATE-TIME': /** Ignored, since we will support arbitrary time */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-DATE-TIME': /** Ignored, since we will support arbitrary time */ + case 'URN:IETF:PARAMS:XML:NS:CALDAV:MAX-INSTANCES': /** Ignored, since we will support arbitrary instances */ + case 'DAV::RESOURCETYPE': /** Any value for resourcetype is ignored */ $success[$tag] = 1; break; diff --git a/testing/tests/regression-suite/507-iCal-MKCALENDAR.result b/testing/tests/regression-suite/507-iCal-MKCALENDAR.result new file mode 100644 index 00000000..f5aeff6b --- /dev/null +++ b/testing/tests/regression-suite/507-iCal-MKCALENDAR.result @@ -0,0 +1,8 @@ +HTTP/1.1 201 Created +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +Cache-Control: no-cache +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +10 --- /user1/ --- Untitled --- 1 --- 0 diff --git a/testing/tests/regression-suite/507-iCal-MKCALENDAR.test b/testing/tests/regression-suite/507-iCal-MKCALENDAR.test new file mode 100644 index 00000000..27057e36 --- /dev/null +++ b/testing/tests/regression-suite/507-iCal-MKCALENDAR.test @@ -0,0 +1,29 @@ +# +# MKCALENDAR test for iCal +# +TYPE=MKCALENDAR +URL=http://mycaldav/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/ +HEADER=Content-Type: text/xml +HEAD + + +BEGINDATA +<?xml version="1.0" encoding="UTF-8" ?> +<x0:mkcalendar xmlns:x0="urn:ietf:params:xml:ns:caldav" xmlns:x1="DAV:" xmlns:x2="http://apple.com/ns/ical/"> + <x1:set> + <x1:prop> + <x1:displayname>Untitled</x1:displayname> + <x2:calendar-color>#492BA1FF</x2:calendar-color> + </x1:prop> + </x1:set> +</x0:mkcalendar> +ENDDATA + + +QUERY +SELECT user_no, parent_container, dav_displayname, + is_calendar, public_events_only +FROM collection +WHERE dav_name = '/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/'; +ENDQUERY + From 9a32c2c806ee580b3da262d30859062363e57857 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 24 Nov 2007 23:06:36 +1300 Subject: [PATCH 150/189] Fix a bug in addition of durations. --- inc/RRule.php | 16 +-- .../830-Spec-FREEBUSY-1.result | 48 ++++---- .../regression-suite/832-freebusy.result | 34 +++--- .../regression-suite/833-freebusy.result | 34 +++--- .../834-Spec-FREEBUSY-1.result | 114 +++++++++--------- .../regression-suite/835-freebusy.result | 34 +++--- .../regression-suite/836-freebusy.result | 34 +++--- 7 files changed, 158 insertions(+), 156 deletions(-) diff --git a/inc/RRule.php b/inc/RRule.php index ef526f88..b1a50648 100644 --- a/inc/RRule.php +++ b/inc/RRule.php @@ -282,23 +282,25 @@ class iCalDate { function AddDuration( $duration ) { list( $sign, $days, $time ) = preg_split( '/[PT]/', $duration ); $sign = ( $sign == "-" ? -1 : 1); + dbg_error_log( "RRule", " Adding duration to '%s' of sign: %d, days: %s, time: %s", $this->_text, $sign, $days, $time ); if ( preg_match( '/(\d)+(D|W)/', $days, $matches ) ) { $days = intval($matches[1]); if ( $matches[2] == 'W' ) $days *= 7; $this->AddDays( $days * $sign ); } - if ( preg_match( '/(\d)+(H)/', $time, $matches ) ) $hh = $matches[1]; - if ( preg_match( '/(\d)+(M)/', $time, $matches ) ) $mi = $matches[1]; - if ( preg_match( '/(\d)+(S)/', $time, $matches ) ) $ss = $matches[1]; + if ( preg_match( '/(\d+)(H)/', $time, $matches ) ) $hh = $matches[1]; + if ( preg_match( '/(\d+)(M)/', $time, $matches ) ) $mi = $matches[1]; + if ( preg_match( '/(\d+)(S)/', $time, $matches ) ) $ss = $matches[1]; + dbg_error_log( "RRule", " Adding %02d:%02d:%02d * %d to %02d:%02d:%02d", $hh, $mi, $ss, $sign, $this->_hh, $this->_mi, $this->_ss ); $this->_hh += ($hh * $sign); $this->_mi += ($mi * $sign); $this->_ss += ($ss * $sign); - if ( $this->_ss < 0 ) { $this->_mi -= (intval(abs($this->ss/60))+1); $this->_ss += ((intval(abs($this->mi/60))+1) * 60); } - if ( $this->_ss > 59) { $this->_mi += (intval(abs($this->ss/60))+1); $this->_ss -= ((intval(abs($this->mi/60))+1) * 60); } - if ( $this->_mi < 0 ) { $this->_hh -= (intval(abs($this->mi/60))+1); $this->_mi += ((intval(abs($this->mi/60))+1) * 60); } - if ( $this->_mi > 59) { $this->_hh += (intval(abs($this->mi/60))+1); $this->_mi -= ((intval(abs($this->mi/60))+1) * 60); } + if ( $this->_ss < 0 ) { $this->_mi -= (intval(abs($this->_ss/60))+1); $this->_ss += ((intval(abs($this->_mi/60))+1) * 60); } + if ( $this->_ss > 59) { $this->_mi += (intval(abs($this->_ss/60))+1); $this->_ss -= ((intval(abs($this->_mi/60))+1) * 60); } + if ( $this->_mi < 0 ) { $this->_hh -= (intval(abs($this->_mi/60))+1); $this->_mi += ((intval(abs($this->_mi/60))+1) * 60); } + if ( $this->_mi > 59) { $this->_hh += (intval(abs($this->_mi/60))+1); $this->_mi -= ((intval(abs($this->_mi/60))+1) * 60); } if ( $this->_hh < 0 ) { $this->AddDays( -1 * (intval(abs($this->_hh/24))+1) ); $this->_hh += ((intval(abs($this->_hh/24))+1)*24); } if ( $this->_hh > 23) { $this->AddDays( (intval(abs($this->_hh/24))+1) ); $this->_hh -= ((intval(abs($this->_hh/24))+1)*24); } diff --git a/testing/tests/regression-suite/830-Spec-FREEBUSY-1.result b/testing/tests/regression-suite/830-Spec-FREEBUSY-1.result index 99cf07e0..a50257e9 100644 --- a/testing/tests/regression-suite/830-Spec-FREEBUSY-1.result +++ b/testing/tests/regression-suite/830-Spec-FREEBUSY-1.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -Content-Length: 928 +Content-Length: 1166 Content-Type: text/calendar BEGIN:VCALENDAR @@ -11,28 +11,28 @@ BEGIN:VFREEBUSY DTSTAMP:yyyymmddThhmmssZ DTSTART:20061004T140000Z DTEND:20070105T220000Z -FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/PT2H -FREEBUSY:20061031T210000/PT1H -FREEBUSY:20061102T210000/PT1H -FREEBUSY:20061109T210000/PT1H -FREEBUSY:20061116T210000/PT1H -FREEBUSY:20061123T210000/PT1H -FREEBUSY:20061130T210000/PT1H -FREEBUSY:20061207T210000/PT1H -FREEBUSY:20061214T210000/PT1H -FREEBUSY:20061221T210000/PT1H -FREEBUSY:20061228T210000/PT1H -FREEBUSY:20070104T210000/PT1H -FREEBUSY:20061101T233000/PT1H -FREEBUSY:20061102T183000/PT2H -FREEBUSY:20061202T183000/PT2H -FREEBUSY:20070102T183000/PT2H -FREEBUSY:20061103T030000/PT1H45M -FREEBUSY:20061117T030000/PT1H45M -FREEBUSY:20061201T030000/PT1H45M -FREEBUSY:20061215T030000/PT1H45M -FREEBUSY:20061229T030000/PT1H45M -FREEBUSY:20061223T000000/PT2H -FREEBUSY:20061223T030000/PT2H +FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/20061223T080000 +FREEBUSY:20061031T210000/20061031T220000 +FREEBUSY:20061102T210000/20061102T220000 +FREEBUSY:20061109T210000/20061109T220000 +FREEBUSY:20061116T210000/20061116T220000 +FREEBUSY:20061123T210000/20061123T220000 +FREEBUSY:20061130T210000/20061130T220000 +FREEBUSY:20061207T210000/20061207T220000 +FREEBUSY:20061214T210000/20061214T220000 +FREEBUSY:20061221T210000/20061221T220000 +FREEBUSY:20061228T210000/20061228T220000 +FREEBUSY:20070104T210000/20070104T220000 +FREEBUSY:20061101T233000/20061102T003000 +FREEBUSY:20061102T183000/20061102T203000 +FREEBUSY:20061202T183000/20061202T203000 +FREEBUSY:20070102T183000/20070102T203000 +FREEBUSY:20061103T030000/20061103T044500 +FREEBUSY:20061117T030000/20061117T044500 +FREEBUSY:20061201T030000/20061201T044500 +FREEBUSY:20061215T030000/20061215T044500 +FREEBUSY:20061229T030000/20061229T044500 +FREEBUSY:20061223T000000/20061223T020000 +FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY END:VCALENDAR diff --git a/testing/tests/regression-suite/832-freebusy.result b/testing/tests/regression-suite/832-freebusy.result index 565b1ab7..efd7e369 100644 --- a/testing/tests/regression-suite/832-freebusy.result +++ b/testing/tests/regression-suite/832-freebusy.result @@ -46,23 +46,23 @@ FREEBUSY:20070302T183000/20070302T203000 FREEBUSY:20070402T183000/20070402T203000 FREEBUSY:20070502T183000/20070502T203000 FREEBUSY:20070602T183000/20070602T203000 -FREEBUSY:20061117T030000/20061117T040500 -FREEBUSY:20061201T030000/20061201T040500 -FREEBUSY:20061215T030000/20061215T040500 -FREEBUSY:20061229T030000/20061229T040500 -FREEBUSY:20070112T030000/20070112T040500 -FREEBUSY:20070126T030000/20070126T040500 -FREEBUSY:20070209T030000/20070209T040500 -FREEBUSY:20070223T030000/20070223T040500 -FREEBUSY:20070309T030000/20070309T040500 -FREEBUSY:20070323T030000/20070323T040500 -FREEBUSY:20070406T030000/20070406T040500 -FREEBUSY:20070420T030000/20070420T040500 -FREEBUSY:20070504T030000/20070504T040500 -FREEBUSY:20070518T030000/20070518T040500 -FREEBUSY:20070601T030000/20070601T040500 -FREEBUSY:20070615T030000/20070615T040500 -FREEBUSY:20070629T030000/20070629T040500 +FREEBUSY:20061117T030000/20061117T044500 +FREEBUSY:20061201T030000/20061201T044500 +FREEBUSY:20061215T030000/20061215T044500 +FREEBUSY:20061229T030000/20061229T044500 +FREEBUSY:20070112T030000/20070112T044500 +FREEBUSY:20070126T030000/20070126T044500 +FREEBUSY:20070209T030000/20070209T044500 +FREEBUSY:20070223T030000/20070223T044500 +FREEBUSY:20070309T030000/20070309T044500 +FREEBUSY:20070323T030000/20070323T044500 +FREEBUSY:20070406T030000/20070406T044500 +FREEBUSY:20070420T030000/20070420T044500 +FREEBUSY:20070504T030000/20070504T044500 +FREEBUSY:20070518T030000/20070518T044500 +FREEBUSY:20070601T030000/20070601T044500 +FREEBUSY:20070615T030000/20070615T044500 +FREEBUSY:20070629T030000/20070629T044500 FREEBUSY:20061223T000000/20061223T020000 FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY diff --git a/testing/tests/regression-suite/833-freebusy.result b/testing/tests/regression-suite/833-freebusy.result index 565b1ab7..efd7e369 100644 --- a/testing/tests/regression-suite/833-freebusy.result +++ b/testing/tests/regression-suite/833-freebusy.result @@ -46,23 +46,23 @@ FREEBUSY:20070302T183000/20070302T203000 FREEBUSY:20070402T183000/20070402T203000 FREEBUSY:20070502T183000/20070502T203000 FREEBUSY:20070602T183000/20070602T203000 -FREEBUSY:20061117T030000/20061117T040500 -FREEBUSY:20061201T030000/20061201T040500 -FREEBUSY:20061215T030000/20061215T040500 -FREEBUSY:20061229T030000/20061229T040500 -FREEBUSY:20070112T030000/20070112T040500 -FREEBUSY:20070126T030000/20070126T040500 -FREEBUSY:20070209T030000/20070209T040500 -FREEBUSY:20070223T030000/20070223T040500 -FREEBUSY:20070309T030000/20070309T040500 -FREEBUSY:20070323T030000/20070323T040500 -FREEBUSY:20070406T030000/20070406T040500 -FREEBUSY:20070420T030000/20070420T040500 -FREEBUSY:20070504T030000/20070504T040500 -FREEBUSY:20070518T030000/20070518T040500 -FREEBUSY:20070601T030000/20070601T040500 -FREEBUSY:20070615T030000/20070615T040500 -FREEBUSY:20070629T030000/20070629T040500 +FREEBUSY:20061117T030000/20061117T044500 +FREEBUSY:20061201T030000/20061201T044500 +FREEBUSY:20061215T030000/20061215T044500 +FREEBUSY:20061229T030000/20061229T044500 +FREEBUSY:20070112T030000/20070112T044500 +FREEBUSY:20070126T030000/20070126T044500 +FREEBUSY:20070209T030000/20070209T044500 +FREEBUSY:20070223T030000/20070223T044500 +FREEBUSY:20070309T030000/20070309T044500 +FREEBUSY:20070323T030000/20070323T044500 +FREEBUSY:20070406T030000/20070406T044500 +FREEBUSY:20070420T030000/20070420T044500 +FREEBUSY:20070504T030000/20070504T044500 +FREEBUSY:20070518T030000/20070518T044500 +FREEBUSY:20070601T030000/20070601T044500 +FREEBUSY:20070615T030000/20070615T044500 +FREEBUSY:20070629T030000/20070629T044500 FREEBUSY:20061223T000000/20061223T020000 FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY diff --git a/testing/tests/regression-suite/834-Spec-FREEBUSY-1.result b/testing/tests/regression-suite/834-Spec-FREEBUSY-1.result index 4b60fca8..6995ea54 100644 --- a/testing/tests/regression-suite/834-Spec-FREEBUSY-1.result +++ b/testing/tests/regression-suite/834-Spec-FREEBUSY-1.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -Content-Length: 1957 +Content-Length: 2519 Content-Type: text/calendar BEGIN:VCALENDAR @@ -11,61 +11,61 @@ BEGIN:VFREEBUSY DTSTAMP:yyyymmddThhmmssZ DTSTART:20061001T000000Z DTEND:20070630T235959Z -FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/PT2H -FREEBUSY:20061031T210000/PT1H -FREEBUSY:20061102T210000/PT1H -FREEBUSY:20061109T210000/PT1H -FREEBUSY:20061116T210000/PT1H -FREEBUSY:20061123T210000/PT1H -FREEBUSY:20061130T210000/PT1H -FREEBUSY:20061207T210000/PT1H -FREEBUSY:20061214T210000/PT1H -FREEBUSY:20061221T210000/PT1H -FREEBUSY:20061228T210000/PT1H -FREEBUSY:20070104T210000/PT1H -FREEBUSY:20070111T210000/PT1H -FREEBUSY:20070118T210000/PT1H -FREEBUSY:20070125T210000/PT1H -FREEBUSY:20070201T210000/PT1H -FREEBUSY:20070208T210000/PT1H -FREEBUSY:20070215T210000/PT1H -FREEBUSY:20070222T210000/PT1H -FREEBUSY:20070301T210000/PT1H -FREEBUSY:20070308T210000/PT1H -FREEBUSY:20070315T210000/PT1H -FREEBUSY:20070322T210000/PT1H -FREEBUSY:20070329T210000/PT1H -FREEBUSY:20070405T210000/PT1H -FREEBUSY:20070412T210000/PT1H -FREEBUSY:20070419T210000/PT1H -FREEBUSY:20070426T210000/PT1H -FREEBUSY:20061101T233000/PT1H -FREEBUSY:20061102T183000/PT2H -FREEBUSY:20061202T183000/PT2H -FREEBUSY:20070102T183000/PT2H -FREEBUSY:20070202T183000/PT2H -FREEBUSY:20070302T183000/PT2H -FREEBUSY:20070402T183000/PT2H -FREEBUSY:20070502T183000/PT2H -FREEBUSY:20070602T183000/PT2H -FREEBUSY:20061103T030000/PT1H45M -FREEBUSY:20061117T030000/PT1H45M -FREEBUSY:20061201T030000/PT1H45M -FREEBUSY:20061215T030000/PT1H45M -FREEBUSY:20061229T030000/PT1H45M -FREEBUSY:20070112T030000/PT1H45M -FREEBUSY:20070126T030000/PT1H45M -FREEBUSY:20070209T030000/PT1H45M -FREEBUSY:20070223T030000/PT1H45M -FREEBUSY:20070309T030000/PT1H45M -FREEBUSY:20070323T030000/PT1H45M -FREEBUSY:20070406T030000/PT1H45M -FREEBUSY:20070420T030000/PT1H45M -FREEBUSY:20070504T030000/PT1H45M -FREEBUSY:20070518T030000/PT1H45M -FREEBUSY:20070601T030000/PT1H45M -FREEBUSY:20070615T030000/PT1H45M -FREEBUSY:20070629T030000/PT1H45M -FREEBUSY:20061223T030000/PT2H +FREEBUSY;FBTYPE=BUSY-TENTATIVE:20061223T060000/20061223T080000 +FREEBUSY:20061031T210000/20061031T220000 +FREEBUSY:20061102T210000/20061102T220000 +FREEBUSY:20061109T210000/20061109T220000 +FREEBUSY:20061116T210000/20061116T220000 +FREEBUSY:20061123T210000/20061123T220000 +FREEBUSY:20061130T210000/20061130T220000 +FREEBUSY:20061207T210000/20061207T220000 +FREEBUSY:20061214T210000/20061214T220000 +FREEBUSY:20061221T210000/20061221T220000 +FREEBUSY:20061228T210000/20061228T220000 +FREEBUSY:20070104T210000/20070104T220000 +FREEBUSY:20070111T210000/20070111T220000 +FREEBUSY:20070118T210000/20070118T220000 +FREEBUSY:20070125T210000/20070125T220000 +FREEBUSY:20070201T210000/20070201T220000 +FREEBUSY:20070208T210000/20070208T220000 +FREEBUSY:20070215T210000/20070215T220000 +FREEBUSY:20070222T210000/20070222T220000 +FREEBUSY:20070301T210000/20070301T220000 +FREEBUSY:20070308T210000/20070308T220000 +FREEBUSY:20070315T210000/20070315T220000 +FREEBUSY:20070322T210000/20070322T220000 +FREEBUSY:20070329T210000/20070329T220000 +FREEBUSY:20070405T210000/20070405T220000 +FREEBUSY:20070412T210000/20070412T220000 +FREEBUSY:20070419T210000/20070419T220000 +FREEBUSY:20070426T210000/20070426T220000 +FREEBUSY:20061101T233000/20061102T003000 +FREEBUSY:20061102T183000/20061102T203000 +FREEBUSY:20061202T183000/20061202T203000 +FREEBUSY:20070102T183000/20070102T203000 +FREEBUSY:20070202T183000/20070202T203000 +FREEBUSY:20070302T183000/20070302T203000 +FREEBUSY:20070402T183000/20070402T203000 +FREEBUSY:20070502T183000/20070502T203000 +FREEBUSY:20070602T183000/20070602T203000 +FREEBUSY:20061103T030000/20061103T044500 +FREEBUSY:20061117T030000/20061117T044500 +FREEBUSY:20061201T030000/20061201T044500 +FREEBUSY:20061215T030000/20061215T044500 +FREEBUSY:20061229T030000/20061229T044500 +FREEBUSY:20070112T030000/20070112T044500 +FREEBUSY:20070126T030000/20070126T044500 +FREEBUSY:20070209T030000/20070209T044500 +FREEBUSY:20070223T030000/20070223T044500 +FREEBUSY:20070309T030000/20070309T044500 +FREEBUSY:20070323T030000/20070323T044500 +FREEBUSY:20070406T030000/20070406T044500 +FREEBUSY:20070420T030000/20070420T044500 +FREEBUSY:20070504T030000/20070504T044500 +FREEBUSY:20070518T030000/20070518T044500 +FREEBUSY:20070601T030000/20070601T044500 +FREEBUSY:20070615T030000/20070615T044500 +FREEBUSY:20070629T030000/20070629T044500 +FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY END:VCALENDAR diff --git a/testing/tests/regression-suite/835-freebusy.result b/testing/tests/regression-suite/835-freebusy.result index 9763b5f7..4f1a8472 100644 --- a/testing/tests/regression-suite/835-freebusy.result +++ b/testing/tests/regression-suite/835-freebusy.result @@ -46,23 +46,23 @@ FREEBUSY:20070302T183000/20070302T203000 FREEBUSY:20070402T183000/20070402T203000 FREEBUSY:20070502T183000/20070502T203000 FREEBUSY:20070602T183000/20070602T203000 -FREEBUSY:20061117T030000/20061117T040500 -FREEBUSY:20061201T030000/20061201T040500 -FREEBUSY:20061215T030000/20061215T040500 -FREEBUSY:20061229T030000/20061229T040500 -FREEBUSY:20070112T030000/20070112T040500 -FREEBUSY:20070126T030000/20070126T040500 -FREEBUSY:20070209T030000/20070209T040500 -FREEBUSY:20070223T030000/20070223T040500 -FREEBUSY:20070309T030000/20070309T040500 -FREEBUSY:20070323T030000/20070323T040500 -FREEBUSY:20070406T030000/20070406T040500 -FREEBUSY:20070420T030000/20070420T040500 -FREEBUSY:20070504T030000/20070504T040500 -FREEBUSY:20070518T030000/20070518T040500 -FREEBUSY:20070601T030000/20070601T040500 -FREEBUSY:20070615T030000/20070615T040500 -FREEBUSY:20070629T030000/20070629T040500 +FREEBUSY:20061117T030000/20061117T044500 +FREEBUSY:20061201T030000/20061201T044500 +FREEBUSY:20061215T030000/20061215T044500 +FREEBUSY:20061229T030000/20061229T044500 +FREEBUSY:20070112T030000/20070112T044500 +FREEBUSY:20070126T030000/20070126T044500 +FREEBUSY:20070209T030000/20070209T044500 +FREEBUSY:20070223T030000/20070223T044500 +FREEBUSY:20070309T030000/20070309T044500 +FREEBUSY:20070323T030000/20070323T044500 +FREEBUSY:20070406T030000/20070406T044500 +FREEBUSY:20070420T030000/20070420T044500 +FREEBUSY:20070504T030000/20070504T044500 +FREEBUSY:20070518T030000/20070518T044500 +FREEBUSY:20070601T030000/20070601T044500 +FREEBUSY:20070615T030000/20070615T044500 +FREEBUSY:20070629T030000/20070629T044500 FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY END:VCALENDAR diff --git a/testing/tests/regression-suite/836-freebusy.result b/testing/tests/regression-suite/836-freebusy.result index 9763b5f7..4f1a8472 100644 --- a/testing/tests/regression-suite/836-freebusy.result +++ b/testing/tests/regression-suite/836-freebusy.result @@ -46,23 +46,23 @@ FREEBUSY:20070302T183000/20070302T203000 FREEBUSY:20070402T183000/20070402T203000 FREEBUSY:20070502T183000/20070502T203000 FREEBUSY:20070602T183000/20070602T203000 -FREEBUSY:20061117T030000/20061117T040500 -FREEBUSY:20061201T030000/20061201T040500 -FREEBUSY:20061215T030000/20061215T040500 -FREEBUSY:20061229T030000/20061229T040500 -FREEBUSY:20070112T030000/20070112T040500 -FREEBUSY:20070126T030000/20070126T040500 -FREEBUSY:20070209T030000/20070209T040500 -FREEBUSY:20070223T030000/20070223T040500 -FREEBUSY:20070309T030000/20070309T040500 -FREEBUSY:20070323T030000/20070323T040500 -FREEBUSY:20070406T030000/20070406T040500 -FREEBUSY:20070420T030000/20070420T040500 -FREEBUSY:20070504T030000/20070504T040500 -FREEBUSY:20070518T030000/20070518T040500 -FREEBUSY:20070601T030000/20070601T040500 -FREEBUSY:20070615T030000/20070615T040500 -FREEBUSY:20070629T030000/20070629T040500 +FREEBUSY:20061117T030000/20061117T044500 +FREEBUSY:20061201T030000/20061201T044500 +FREEBUSY:20061215T030000/20061215T044500 +FREEBUSY:20061229T030000/20061229T044500 +FREEBUSY:20070112T030000/20070112T044500 +FREEBUSY:20070126T030000/20070126T044500 +FREEBUSY:20070209T030000/20070209T044500 +FREEBUSY:20070223T030000/20070223T044500 +FREEBUSY:20070309T030000/20070309T044500 +FREEBUSY:20070323T030000/20070323T044500 +FREEBUSY:20070406T030000/20070406T044500 +FREEBUSY:20070420T030000/20070420T044500 +FREEBUSY:20070504T030000/20070504T044500 +FREEBUSY:20070518T030000/20070518T044500 +FREEBUSY:20070601T030000/20070601T044500 +FREEBUSY:20070615T030000/20070615T044500 +FREEBUSY:20070629T030000/20070629T044500 FREEBUSY:20061223T030000/20061223T050000 END:VFREEBUSY END:VCALENDAR From b66460a34d69c6562554de4536d4d902d1772f9b Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 24 Nov 2007 23:07:54 +1300 Subject: [PATCH 151/189] Display NULL for null fields. --- testing/dav_test | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/dav_test b/testing/dav_test index fab2025e..4d57ad5c 100755 --- a/testing/dav_test +++ b/testing/dav_test @@ -199,6 +199,7 @@ if ( defined(@{$queries}) && @{$queries} ) { print STDERR "Processing results row\n" if ( $debug ); my $sep = ""; foreach my $column ( @$row ) { + $column = 'NULL' unless ( defined($column) ); print $sep, $column; $sep = " --- "; } From 522852d4f5ff02293803fa25f8ee764df7c54804 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 24 Nov 2007 23:39:56 +1300 Subject: [PATCH 152/189] Ensure that mkcalendar will fail at / or /username/ locations. --- inc/CalDAVRequest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index ecb93ed5..317f6109 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -529,9 +529,14 @@ class CalDAVRequest break; case 'create': + return isset($this->permissions['write']) || isset($this->permissions['bind']); + break; + case 'mkcalendar': case 'mkcol': - return isset($this->permissions['write']) || isset($this->permissions['bind']); + if ( !isset($this->permissions['write']) || !isset($this->permissions['bind']) ) return false; + if ( $this->is_principal ) return false; + if ( $this->path == '/' ) return false; break; case 'read': From 2667580a2508519baebeb2afd5a92195f9109c38 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 24 Nov 2007 23:40:42 +1300 Subject: [PATCH 153/189] Better regex to match SOHO Organizer . --- inc/caldav-MKCALENDAR.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/caldav-MKCALENDAR.php b/inc/caldav-MKCALENDAR.php index d22730ba..9f48bf18 100644 --- a/inc/caldav-MKCALENDAR.php +++ b/inc/caldav-MKCALENDAR.php @@ -53,7 +53,7 @@ if ( isset($request->xml_tags) ) { * TODO: This is definitely a bug in SOHO Organizer and we probably should respond * with an error, rather than silently doing what they *seem* to want us to do. */ - if ( preg_match( '/ SOHO Organizer\/6\./', $_SERVER['HTTP_USER_AGENT'] ) ) { + if ( preg_match( '/^SOHO.Organizer.6\./', $_SERVER['HTTP_USER_AGENT'] ) ) { dbg_error_log( "MKCALENDAR", "Displayname is '/' to '%s'", $request->path); $parent_container = $request->path; $request->path .= $content . '/'; From eb738ab0eadf64183e5b28d0f349ccda9defc7e1 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 24 Nov 2007 23:44:38 +1300 Subject: [PATCH 154/189] Showing NULL now due to improved dav_test. --- testing/tests/regression-suite/505-iCal-PUT.result | 2 +- testing/tests/regression-suite/506-iCal-PUT.result | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/tests/regression-suite/505-iCal-PUT.result b/testing/tests/regression-suite/505-iCal-PUT.result index e0d76fe2..a77ca2be 100644 --- a/testing/tests/regression-suite/505-iCal-PUT.result +++ b/testing/tests/regression-suite/505-iCal-PUT.result @@ -5,4 +5,4 @@ ETag: "b3e66a461ef178bd4791b2b6509bbb9d" Content-Length: 0 Content-Type: text/plain; charset="utf-8" -10 --- VEVENT --- 10 --- AAA9318E-37D9-4319-8626-95ECD3D3B243 --- 2007-11-23 09:30:48 --- 2007-11-25 23:00:00+13 --- 2007-11-26 00:00:00+13 --- --- New Event --- --- --- --- PUBLIC --- OPAQUE --- --- --- --- --- +10 --- VEVENT --- 10 --- AAA9318E-37D9-4319-8626-95ECD3D3B243 --- 2007-11-23 09:30:48 --- 2007-11-25 23:00:00+13 --- 2007-11-26 00:00:00+13 --- NULL --- New Event --- NULL --- NULL --- NULL --- PUBLIC --- OPAQUE --- NULL --- NULL --- NULL --- NULL --- NULL diff --git a/testing/tests/regression-suite/506-iCal-PUT.result b/testing/tests/regression-suite/506-iCal-PUT.result index 47298e25..4e35e396 100644 --- a/testing/tests/regression-suite/506-iCal-PUT.result +++ b/testing/tests/regression-suite/506-iCal-PUT.result @@ -5,4 +5,4 @@ ETag: "5f050eca5480bbebbe9428222570913d" Content-Length: 0 Content-Type: text/plain; charset="utf-8" -10 --- VEVENT --- 10 --- AAA9318E-37D9-4319-8626-95ECD3D3B243 --- 2007-11-23 09:32:23 --- 2007-11-25 13:00:00+13 --- 2007-11-25 19:00:00+13 --- --- BBQ @ ML's --- ML's House --- --- --- PUBLIC --- OPAQUE --- --- --- --- --- +10 --- VEVENT --- 10 --- AAA9318E-37D9-4319-8626-95ECD3D3B243 --- 2007-11-23 09:32:23 --- 2007-11-25 13:00:00+13 --- 2007-11-25 19:00:00+13 --- NULL --- BBQ @ ML's --- ML's House --- NULL --- NULL --- PUBLIC --- OPAQUE --- NULL --- NULL --- NULL --- NULL --- NULL From 43606cf173af1a7a0283ae2e3385f1f3c7910547 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sat, 24 Nov 2007 23:45:40 +1300 Subject: [PATCH 155/189] New results due to additional data. --- .../regression-suite/602-Soho-PROPFIND.result | 25 +++++++++++++++++-- .../regression-suite/603-Soho-PROPFIND.result | 25 +++++++++++++++++-- .../840-Spec-PROPPATCH-1.result | 8 +----- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/testing/tests/regression-suite/602-Soho-PROPFIND.result b/testing/tests/regression-suite/602-Soho-PROPFIND.result index 07ec4d6b..db8cf79f 100644 --- a/testing/tests/regression-suite/602-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/602-Soho-PROPFIND.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "0f77e8fc1531888183e35da896c95287" -Content-Length: 6109 +ETag: "11569a6789ed65497bd05e27e9657a27" +Content-Length: 6629 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -231,4 +231,25 @@ Content-Type: text/xml; charset="utf-8" <status>HTTP/1.1 200 OK</status> </propstat> </response> + <response> + <href>/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <A:dropbox-home-url/> + <A:notifications-url/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> </multistatus> diff --git a/testing/tests/regression-suite/603-Soho-PROPFIND.result b/testing/tests/regression-suite/603-Soho-PROPFIND.result index 3edfc407..29bbc6bd 100644 --- a/testing/tests/regression-suite/603-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/603-Soho-PROPFIND.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "461b0f96e42a2b69d256b99bc8d2ea1e" -Content-Length: 1139 +ETag: "f404adc5be7a3e1a0b8eb755a91fcf4a" +Content-Length: 1659 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -49,4 +49,25 @@ Content-Type: text/xml; charset="utf-8" <status>HTTP/1.1 404 Not Found</status> </propstat> </response> + <response> + <href>/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <A:dropbox-home-url/> + <A:notifications-url/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> </multistatus> diff --git a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result index 2531e85e..c2cfcdd2 100644 --- a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result +++ b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result @@ -12,16 +12,10 @@ Content-Type: text/xml; charset="utf-8" </response> </multistatus> User One's Calendar --- faf25336de0e470a54075c14cbcf5272 --- 0 --- 1 +/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/ --- HTTP://APPLE.COM/NS/ICAL/:CALENDAR-COLOR --- #492BA1FF --- 10 --- 1 /user1/home/ --- DAV::OWNER --- <DAV::HREF>http://www.example.com/acl/users/jim</DAV::HREF> --- 10 --- 1 /user1/home/ --- URN:MCMILLAN:BOGUS:XML:NS:RSCDS:ARBITRARY --- A completely bogus property which should be saved. --- 10 --- 1 /user1/SOHO+collection/ --- COM.APPLE.ICAL::CALENDARCOLOR --- #FF8000FF --- 10 --- 1 /user1/SOHO+collection/ --- URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DESCRIPTION --- Calendar description --- 10 --- 1 -/user1/SOHO+collection/ --- URN:IETF:PARAMS:XML:NS:CALDAV:SUPPORTED-CALENDAR-COMPONENT-SET --- - <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VEVENT"/> - <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VTODO"/> - <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VTIMEZONE"/> - <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VJOURNAL"/> - <URN:IETF:PARAMS:XML:NS:CALDAV:COMP NAME="VFREEBUSY"/> - --- 10 --- 1 From 10f0e300abc0c6e1a9f398b4fa12c5c7a1f52518 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 00:37:31 +1300 Subject: [PATCH 156/189] Test calendar-multiget report as used by iCal. --- .../regression-suite/508-iCal-REPORT.result | 66 +++++++++++++++++++ .../regression-suite/508-iCal-REPORT.test | 23 +++++++ 2 files changed, 89 insertions(+) create mode 100644 testing/tests/regression-suite/508-iCal-REPORT.result create mode 100644 testing/tests/regression-suite/508-iCal-REPORT.test diff --git a/testing/tests/regression-suite/508-iCal-REPORT.result b/testing/tests/regression-suite/508-iCal-REPORT.result new file mode 100644 index 00000000..a7c40cc0 --- /dev/null +++ b/testing/tests/regression-suite/508-iCal-REPORT.result @@ -0,0 +1,66 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "cffcf7a710204d19f988b512720549cd" +Content-Length: 1383 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:"> + <response> + <href>/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href> + <propstat> + <prop> + <getetag>"5f050eca5480bbebbe9428222570913d"</getetag> + <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 3.0//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Pacific/Auckland +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+1200 +TZOFFSETTO:+1300 +DTSTART:20070930T020000 +RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU +TZNAME:NZDT +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:20080406T030000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +TZNAME:NZST +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:6 +TRANSP:OPAQUE +UID:AAA9318E-37D9-4319-8626-95ECD3D3B243 +DTSTART;TZID=Pacific/Auckland:20071125T130000 +DTSTAMP:20071123T093223Z +SUMMARY:BBQ @ ML's +CREATED:20071123T093048Z +DTEND;TZID=Pacific/Auckland:20071125T190000 +LOCATION:ML's House +BEGIN:VALARM +X-WR-ALARMUID:2927836F-DF85-4688-901A-9ABE442BFB62 +ACTION:AUDIO +TRIGGER:-PT15M +ATTACH;VALUE=URI:Basso +END:VALARM +END:VEVENT +END:VCALENDAR +</calendar-data> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/508-iCal-REPORT.test b/testing/tests/regression-suite/508-iCal-REPORT.test new file mode 100644 index 00000000..58f20699 --- /dev/null +++ b/testing/tests/regression-suite/508-iCal-REPORT.test @@ -0,0 +1,23 @@ +# +# iCal does a calendar-multiget REPORT to fetch new events +# +TYPE=REPORT +URL=http://mycaldav/caldav.php/user1/home/ +HEADER=Content-Type: text/xml +HEADER=User-Agent: DAVKit/2.0 (10.5.1; wrbt) iCal 3.0.1 +HEAD + + +# Reformatted for readability +BEGINDATA +<?xml version="1.0" encoding="UTF-8" ?> +<x0:calendar-multiget xmlns:x0="urn:ietf:params:xml:ns:caldav" xmlns:x1="DAV:"> + <x1:prop> + <x1:getetag/> + <x0:calendar-data/> + </x1:prop> + <x1:href>/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</x1:href> +</x0:calendar-multiget> +ENDDATA + + From 96ebfb59d07f0281aa022ecff73dd54b6c2a1879 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 00:37:58 +1300 Subject: [PATCH 157/189] Test PROPPATCH to change the name of a calendar. --- .../509-iCal-PROPPATCH.result | 14 +++++++++ .../regression-suite/509-iCal-PROPPATCH.test | 29 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 testing/tests/regression-suite/509-iCal-PROPPATCH.result create mode 100644 testing/tests/regression-suite/509-iCal-PROPPATCH.test diff --git a/testing/tests/regression-suite/509-iCal-PROPPATCH.result b/testing/tests/regression-suite/509-iCal-PROPPATCH.result new file mode 100644 index 00000000..1c1ddd3c --- /dev/null +++ b/testing/tests/regression-suite/509-iCal-PROPPATCH.result @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +Content-Length: 256 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:"> + <response> + <href>/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/</href> + <responsedescription>All requested changes were made.</responsedescription> + </response> +</multistatus> +iCal Calendar --- 1 diff --git a/testing/tests/regression-suite/509-iCal-PROPPATCH.test b/testing/tests/regression-suite/509-iCal-PROPPATCH.test new file mode 100644 index 00000000..3685698c --- /dev/null +++ b/testing/tests/regression-suite/509-iCal-PROPPATCH.test @@ -0,0 +1,29 @@ +# +# iCal does a PROPPATCH to change the name of a calendar +# +TYPE=PROPPATCH +URL=http://mycaldav/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/ +HEADER=Content-Type: text/xml +HEADER=User-Agent: DAVKit/2.0 (10.5.1; wrbt) iCal 3.0.1 +HEAD + + +# Reformatted for readability +BEGINDATA +<?xml version="1.0" encoding="UTF-8" ?> +<x0:propertyupdate xmlns:x0="DAV:"> + <x0:set> + <x0:prop> + <x0:displayname>iCal Calendar</x0:displayname> + </x0:prop> + </x0:set> +</x0:propertyupdate> +ENDDATA + + +QUERY +SELECT dav_displayname, is_calendar + FROM collection + WHERE dav_name = '/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/'; +ENDQUERY + From 8b470ad78c84b71ee530e87e4ea4a0f535cbc245 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 00:38:37 +1300 Subject: [PATCH 158/189] Testing with an event which has many repeats. --- .../regression-suite/512-iCal-PUT.result | 8 ++ .../tests/regression-suite/512-iCal-PUT.test | 69 +++++++++++++++++ .../regression-suite/513-iCal-PUT.result | 8 ++ .../tests/regression-suite/513-iCal-PUT.test | 74 +++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 testing/tests/regression-suite/512-iCal-PUT.result create mode 100644 testing/tests/regression-suite/512-iCal-PUT.test create mode 100644 testing/tests/regression-suite/513-iCal-PUT.result create mode 100644 testing/tests/regression-suite/513-iCal-PUT.test diff --git a/testing/tests/regression-suite/512-iCal-PUT.result b/testing/tests/regression-suite/512-iCal-PUT.result new file mode 100644 index 00000000..6d916570 --- /dev/null +++ b/testing/tests/regression-suite/512-iCal-PUT.result @@ -0,0 +1,8 @@ +HTTP/1.1 201 Created +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "b7cfb403232dc83f936c15a179901d50" +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +10 --- b7cfb403232dc83f936c15a179901d50 --- VEVENT --- 10 --- 6C8A0D88-E1F9-4FC1-9EDD-DA258ABF2CFA --- 2007-11-24 08:37:09 --- 2007-11-26 22:00:00+13 --- 2007-11-26 23:00:00+13 --- NULL --- New Event --- NULL --- NULL --- NULL --- PUBLIC --- OPAQUE --- NULL --- NULL --- NULL --- NULL --- NULL diff --git a/testing/tests/regression-suite/512-iCal-PUT.test b/testing/tests/regression-suite/512-iCal-PUT.test new file mode 100644 index 00000000..b1fb8b56 --- /dev/null +++ b/testing/tests/regression-suite/512-iCal-PUT.test @@ -0,0 +1,69 @@ +# +# PUT an iCal style event into the database +# +TYPE=PUT +URL=http://mycaldav/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/6C8A0D88-E1F9-4FC1-9EDD-DA258ABF2CFA.ics +HEADER=Content-Type: text/calendar +HEADER=User-Agent: DAVKit/2.0 (10.5.1; wrbt) iCal 3.0.1 +HEAD + + +BEGINDATA +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 3.0//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Pacific/Auckland +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+1200 +TZOFFSETTO:+1300 +DTSTART:20070930T020000 +RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU +TZNAME:NZDT +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:20080406T030000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +TZNAME:NZST +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:1 +TRANSP:OPAQUE +UID:6C8A0D88-E1F9-4FC1-9EDD-DA258ABF2CFA +DTSTART;TZID=Pacific/Auckland:20071126T220000 +DTSTAMP:20071124T083709Z +SUMMARY:New Event +CREATED:20071124T083709Z +DTEND;TZID=Pacific/Auckland:20071126T230000 +BEGIN:VALARM +X-WR-ALARMUID:F33877C6-563B-4F20-B129-77A5B6C6944E +ACTION:AUDIO +TRIGGER:-PT15M +ATTACH;VALUE=URI:Basso +END:VALARM +END:VEVENT +END:VCALENDAR +ENDDATA + + +QUERY +SELECT caldav_data.user_no, caldav_data.dav_etag, caldav_type, logged_user, + uid, dtstamp, dtstart, dtend, due, summary, location, + description, priority, class, transp, rrule, url, + percent_complete, tz_id, status +FROM caldav_data JOIN calendar_item USING(dav_name) +WHERE caldav_data.dav_name = +'/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/6C8A0D88-E1F9-4FC1-9EDD-DA258ABF2CFA.ics'; +ENDQUERY + diff --git a/testing/tests/regression-suite/513-iCal-PUT.result b/testing/tests/regression-suite/513-iCal-PUT.result new file mode 100644 index 00000000..04fdd494 --- /dev/null +++ b/testing/tests/regression-suite/513-iCal-PUT.result @@ -0,0 +1,8 @@ +HTTP/1.1 204 No Content +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "087d1ea4915719b8a904ca18a9abbbe1" +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +10 --- 087d1ea4915719b8a904ca18a9abbbe1 --- VEVENT --- 10 --- 6C8A0D88-E1F9-4FC1-9EDD-DA258ABF2CFA --- 2007-11-24 08:38:10 --- 2007-11-26 07:00:00+13 --- 2007-11-26 17:00:00+13 --- NULL --- Go to work --- NULL --- NULL --- NULL --- PUBLIC --- OPAQUE --- FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;WKST=SU --- NULL --- NULL --- NULL --- NULL diff --git a/testing/tests/regression-suite/513-iCal-PUT.test b/testing/tests/regression-suite/513-iCal-PUT.test new file mode 100644 index 00000000..718d6310 --- /dev/null +++ b/testing/tests/regression-suite/513-iCal-PUT.test @@ -0,0 +1,74 @@ +# +# Overwrite iCal event with another one +# +TYPE=PUT +URL=http://mycaldav/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/6C8A0D88-E1F9-4FC1-9EDD-DA258ABF2CFA.ics +HEADER=Content-Type: text/calendar +HEADER=User-Agent: DAVKit/2.0 (10.5.1; wrbt) iCal 3.0.1 +HEADER=If-Match: "b7cfb403232dc83f936c15a179901d50" +HEAD + + +# +# This event is a repeat Mo,Tu,We,Th,Fr forever +# +BEGINDATA +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 3.0//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Pacific/Auckland +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+1200 +TZOFFSETTO:+1300 +DTSTART:20070930T020000 +RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU +TZNAME:NZDT +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:20080406T030000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +TZNAME:NZST +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:5 +TRANSP:OPAQUE +UID:6C8A0D88-E1F9-4FC1-9EDD-DA258ABF2CFA +DTSTART;TZID=Pacific/Auckland:20071126T070000 +DTSTAMP:20071124T083810Z +SUMMARY:Go to work +CREATED:20071124T083709Z +DTEND;TZID=Pacific/Auckland:20071126T170000 +RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;WKST=SU +BEGIN:VALARM +X-WR-ALARMUID:F33877C6-563B-4F20-B129-77A5B6C6944E +ACTION:AUDIO +TRIGGER:-PT15M +ATTACH;VALUE=URI:Basso +END:VALARM +END:VEVENT +END:VCALENDAR +ENDDATA + + +QUERY +SELECT caldav_data.user_no, caldav_data.dav_etag, caldav_type, logged_user, + uid, dtstamp, dtstart, dtend, due, summary, location, + description, priority, class, transp, rrule, url, + percent_complete, tz_id, status +FROM caldav_data JOIN calendar_item USING(dav_name) +WHERE caldav_data.dav_etag = +'087d1ea4915719b8a904ca18a9abbbe1'; +ENDQUERY + From 75ef6cc10515e526d22c319bfc329e0c800ead14 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 00:41:28 +1300 Subject: [PATCH 159/189] Remove iCal hack to escape displaynames with spaces. iCal 3.0.1 doesn't need this. --- inc/caldav-PROPFIND.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index a366abc5..4efca8b6 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -379,10 +379,6 @@ function collection_to_xml( $collection ) { } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['DISPLAYNAME']) ) { $displayname = ( $collection->dav_displayname == "" ? ucfirst(trim(str_replace("/"," ", $collection->dav_name))) : $collection->dav_displayname ); - if ( preg_match( '/ iCal 3\.0/', $request->user_agent ) ) { - /** FIXME: There is a bug in iCal 3 which disables calendars with a displayname containing spaces */ - $displayname = str_replace( ' ', '_', $displayname ); - } $prop->NewElement("displayname", $displayname ); } if ( isset($attribute_list['ALLPROP']) || isset($attribute_list['GETETAG']) ) { From 401375642b1e329ee5e36588db2c0a56c3ae7eac Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 00:44:34 +1300 Subject: [PATCH 160/189] Additional data. --- .../regression-suite/602-Soho-PROPFIND.result | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/testing/tests/regression-suite/602-Soho-PROPFIND.result b/testing/tests/regression-suite/602-Soho-PROPFIND.result index db8cf79f..77757a2f 100644 --- a/testing/tests/regression-suite/602-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/602-Soho-PROPFIND.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "11569a6789ed65497bd05e27e9657a27" -Content-Length: 6629 +ETag: "86a8139e523f058ede9c0298e408d8b3" +Content-Length: 7045 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -252,4 +252,18 @@ Content-Type: text/xml; charset="utf-8" <status>HTTP/1.1 404 Not Found</status> </propstat> </response> + <response> + <href>/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/6C8A0D88-E1F9-4FC1-9EDD-DA258ABF2CFA.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> </multistatus> From e636f17c671175c2197857c1e70e231bed0e9f05 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 00:44:52 +1300 Subject: [PATCH 161/189] Send user agent header. --- testing/tests/regression-suite/505-iCal-PUT.test | 3 ++- testing/tests/regression-suite/506-iCal-PUT.test | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/testing/tests/regression-suite/505-iCal-PUT.test b/testing/tests/regression-suite/505-iCal-PUT.test index fe3d2466..8f7c866e 100644 --- a/testing/tests/regression-suite/505-iCal-PUT.test +++ b/testing/tests/regression-suite/505-iCal-PUT.test @@ -1,9 +1,10 @@ # -# PUT another event into the resource2 calendar so we can DELETE it +# PUT an iCal style event into the database # TYPE=PUT URL=http://mycaldav/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics HEADER=Content-Type: text/calendar +HEADER=User-Agent: DAVKit/2.0 (10.5.1; wrbt) iCal 3.0.1 HEAD diff --git a/testing/tests/regression-suite/506-iCal-PUT.test b/testing/tests/regression-suite/506-iCal-PUT.test index 1079d608..95971624 100644 --- a/testing/tests/regression-suite/506-iCal-PUT.test +++ b/testing/tests/regression-suite/506-iCal-PUT.test @@ -4,6 +4,7 @@ TYPE=PUT URL=http://mycaldav/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics HEADER=Content-Type: text/calendar +HEADER=User-Agent: DAVKit/2.0 (10.5.1; wrbt) iCal 3.0.1 HEADER=If-Match: "b3e66a461ef178bd4791b2b6509bbb9d" HEAD From 6f2ee67ea342ec87080a1674bca1086aa04a94bb Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 00:45:46 +1300 Subject: [PATCH 162/189] Response for iCal now spaces are allowed with iCal 3.0.1 --- testing/tests/regression-suite/502-iCal-PROPFIND.result | 4 ++-- testing/tests/regression-suite/511-iCal-PROPFIND.result | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/tests/regression-suite/502-iCal-PROPFIND.result b/testing/tests/regression-suite/502-iCal-PROPFIND.result index 21dd3ab5..db111ab8 100644 --- a/testing/tests/regression-suite/502-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/502-iCal-PROPFIND.result @@ -1,7 +1,7 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "fd1ab8da7166728112e8028466b371d4" +ETag: "39225b2248c1ac30ff58662ca692650c" Content-Length: 966 Content-Type: text/xml; charset="utf-8" @@ -15,7 +15,7 @@ Content-Type: text/xml; charset="utf-8" <collection/> <principal/> </resourcetype> - <displayname>User_1</displayname> + <displayname>User 1</displayname> </prop> <status>HTTP/1.1 200 OK</status> </propstat> diff --git a/testing/tests/regression-suite/511-iCal-PROPFIND.result b/testing/tests/regression-suite/511-iCal-PROPFIND.result index ef9a43e0..f2129d8f 100644 --- a/testing/tests/regression-suite/511-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/511-iCal-PROPFIND.result @@ -1,7 +1,7 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "d595bef8c261fd561df6bb7eec2f3734" +ETag: "56a84b1b0c3881d98a25fd43c01ad94e" Content-Length: 659 Content-Type: text/xml; charset="utf-8" @@ -11,7 +11,7 @@ Content-Type: text/xml; charset="utf-8" <href>/</href> <propstat> <prop> - <displayname>DAViCal_CalDAV_Server</displayname> + <displayname>DAViCal CalDAV Server</displayname> <C:calendar-home-set> <href>/user1/</href> </C:calendar-home-set> From 78ce98b8de8a889fb44515abe6b1085d5aff47db Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 12:42:40 +1300 Subject: [PATCH 163/189] Consistently use URL without protocol://host:port prefix. --- inc/caldav-PROPFIND.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 4efca8b6..94289283 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -322,9 +322,7 @@ function collection_to_xml( $collection ) { $url = $c->protocol_server_port_script . $collection->dav_name; $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' - if ( preg_match( '/ iCal 3\.0/', $_SERVER['HTTP_USER_AGENT'] ) ) { - $url = preg_replace('#^https?://[^/]+#', '', $url ); - } + $url = preg_replace('#^https?://[^/]+#', '', $url ); $resourcetypes = array( new XMLElement("collection") ); @@ -481,7 +479,10 @@ function item_to_xml( $item ) { $item->properties = get_arbitrary_properties($item->dav_name); - $url = $_SERVER['SCRIPT_NAME'] . $item->dav_name; + $url = $c->protocol_server_port_script . $item->dav_name; + $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' + $url = preg_replace('#^https?://[^/]+#', '', $url ); + $prop = new XMLElement("prop"); $not_found = new XMLElement("prop"); $denied = new XMLElement("prop"); From 6980fafede105d55f183e5eb8244d580a52124f9 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 12:43:09 +1300 Subject: [PATCH 164/189] Test results changed with relative URL. --- .../tests/regression-suite/002-Mulberry-1.result | 16 ++++++++-------- .../tests/regression-suite/003-Mulberry-1.result | 6 +++--- .../tests/regression-suite/005-Mulberry-1.result | 8 ++++---- .../tests/regression-suite/006-Mulberry-1.result | 6 +++--- .../013-Mulberry-PROPFIND-5.result | 6 +++--- .../015-Mulberry-PROPFIND-6.result | 6 +++--- .../regression-suite/205-Moz-PROPFIND-1.result | 6 +++--- .../regression-suite/212-Moz-PROPFIND.result | 6 +++--- .../303-Chandler-PROPFIND-1.result | 6 +++--- .../304-Chandler-PROPFIND-2.result | 6 +++--- .../309-Chandler-PROPFIND-3.result | 6 +++--- .../309-Chandler-PROPFIND-4.result | 6 +++--- .../401-Cadaver-PROPFIND-1.result | 2 +- .../regression-suite/507-iCal-MKCALENDAR.test | 2 +- .../regression-suite/820-Spec-PROPFIND-1.result | 2 +- .../regression-suite/821-Spec-PROPFIND-2.result | 4 ++-- .../regression-suite/822-Spec-PROPFIND-3.result | 2 +- .../regression-suite/824-Spec-PROPFIND-5.result | 2 +- .../regression-suite/826-Spec-PROPFIND.result | 2 +- .../regression-suite/827-Spec-PROPFIND.result | 12 ++++++------ .../regression-suite/843-Spec-PROPFIND.result | 2 +- .../870-Principal-PROPFIND.result | 2 +- 22 files changed, 58 insertions(+), 58 deletions(-) diff --git a/testing/tests/regression-suite/002-Mulberry-1.result b/testing/tests/regression-suite/002-Mulberry-1.result index 08ee7e7c..bf29b546 100644 --- a/testing/tests/regression-suite/002-Mulberry-1.result +++ b/testing/tests/regression-suite/002-Mulberry-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "4f1f49d6e908f8ccfab25f51d1e08658" -Content-Length: 1970 +ETag: "373430133d9c51260783bc61177aa1d3" +Content-Length: 1880 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/</href> + <href>/caldav.php/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -21,7 +21,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/</href> + <href>/caldav.php/user1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -35,7 +35,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://mycaldav/caldav.php/manager1/</href> + <href>/caldav.php/manager1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -49,7 +49,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://mycaldav/caldav.php/assistant1/</href> + <href>/caldav.php/assistant1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -63,7 +63,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://mycaldav/caldav.php/resource1/</href> + <href>/caldav.php/resource1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -77,7 +77,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://mycaldav/caldav.php/resource2/</href> + <href>/caldav.php/resource2/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/003-Mulberry-1.result b/testing/tests/regression-suite/003-Mulberry-1.result index d9b7bc67..1309ae91 100644 --- a/testing/tests/regression-suite/003-Mulberry-1.result +++ b/testing/tests/regression-suite/003-Mulberry-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "030f42bd67ae4aa29812c0832f5b8dec" -Content-Length: 398 +ETag: "cc0f368288b5b8373d00e28f842190e6" +Content-Length: 383 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/</href> + <href>/caldav.php/user1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/005-Mulberry-1.result b/testing/tests/regression-suite/005-Mulberry-1.result index 14c6953c..09b6e087 100644 --- a/testing/tests/regression-suite/005-Mulberry-1.result +++ b/testing/tests/regression-suite/005-Mulberry-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "91534cf7117a7c119621ca3478b3b5af" -Content-Length: 760 +ETag: "a30e9b8f2662cd1da17252d3b814ef04" +Content-Length: 730 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/</href> + <href>/caldav.php/user1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -22,7 +22,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/006-Mulberry-1.result b/testing/tests/regression-suite/006-Mulberry-1.result index 33fbacfb..d8cee0d6 100644 --- a/testing/tests/regression-suite/006-Mulberry-1.result +++ b/testing/tests/regression-suite/006-Mulberry-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "b935ebb71cd3bdebd81cfd488af4e5b0" -Content-Length: 502 +ETag: "7364b32495feb0c9bbe89cdb10988762" +Content-Length: 487 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result b/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result index a06a4254..a3dd940f 100644 --- a/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result +++ b/testing/tests/regression-suite/013-Mulberry-PROPFIND-5.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "68e726f3b90f86125c6db18f5c650c54" -Content-Length: 1070 +ETag: "4cd4df7d08592927b92bcd697c2cdde7" +Content-Length: 1055 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result b/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result index 9f02d457..44ab7700 100644 --- a/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result +++ b/testing/tests/regression-suite/015-Mulberry-PROPFIND-6.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "9ce94a065308bb6bc3773f42449e7d6e" -Content-Length: 1070 +ETag: "d880baf3102a9de9bcea4d5f71a6b500" +Content-Length: 1055 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/205-Moz-PROPFIND-1.result b/testing/tests/regression-suite/205-Moz-PROPFIND-1.result index a2dbda7e..61354633 100644 --- a/testing/tests/regression-suite/205-Moz-PROPFIND-1.result +++ b/testing/tests/regression-suite/205-Moz-PROPFIND-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "cbf8e26e7db5a736eceeb48a8f68d904" -Content-Length: 362 +ETag: "334c8abc0ac73261cdbf963fc7269d76" +Content-Length: 347 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <resourcetype> diff --git a/testing/tests/regression-suite/212-Moz-PROPFIND.result b/testing/tests/regression-suite/212-Moz-PROPFIND.result index f50fbc0b..6b8b8031 100644 --- a/testing/tests/regression-suite/212-Moz-PROPFIND.result +++ b/testing/tests/regression-suite/212-Moz-PROPFIND.result @@ -2,14 +2,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access Content-Location: /user1/home/ -ETag: "cbf8e26e7db5a736eceeb48a8f68d904" -Content-Length: 362 +ETag: "334c8abc0ac73261cdbf963fc7269d76" +Content-Length: 347 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <resourcetype> diff --git a/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result b/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result index 70f468c2..0d775c90 100644 --- a/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result +++ b/testing/tests/regression-suite/303-Chandler-PROPFIND-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "0dbbced4495f8f4044dca46fa1f317c0" -Content-Length: 456 +ETag: "de5751155d5d8961c7fc9d38a690dd49" +Content-Length: 441 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <resourcetype> diff --git a/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result b/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result index b2edaab8..526427b6 100644 --- a/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result +++ b/testing/tests/regression-suite/304-Chandler-PROPFIND-2.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "013e6851fdb2514eeac2122003786bcf" -Content-Length: 571 +ETag: "5c2a97317978ca314ada6490cbebcc81" +Content-Length: 556 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <resourcetype> diff --git a/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result b/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result index 8a26ddb6..97451c46 100644 --- a/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result +++ b/testing/tests/regression-suite/309-Chandler-PROPFIND-3.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "8a45ca8db6ae342a1d059fb36865acea" -Content-Length: 484 +ETag: "2d33f4ae017a778547da61069d95e18f" +Content-Length: 469 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/.chandler/</href> + <href>/caldav.php/user1/home/.chandler/</href> <propstat> <prop> <resourcetype> diff --git a/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result b/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result index 76f776bc..c4513138 100644 --- a/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result +++ b/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "430439801bf82c7330f37c63382a5294" -Content-Length: 3624 +ETag: "f678e2f00e4582d963162b293e1e8ecb" +Content-Length: 3609 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <resourcetype> diff --git a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result index c20d0286..35a07746 100644 --- a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result +++ b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:A="http://apache.org/dav/props/"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> diff --git a/testing/tests/regression-suite/507-iCal-MKCALENDAR.test b/testing/tests/regression-suite/507-iCal-MKCALENDAR.test index 27057e36..70331d77 100644 --- a/testing/tests/regression-suite/507-iCal-MKCALENDAR.test +++ b/testing/tests/regression-suite/507-iCal-MKCALENDAR.test @@ -13,7 +13,7 @@ BEGINDATA <x1:set> <x1:prop> <x1:displayname>Untitled</x1:displayname> - <x2:calendar-color>#492BA1FF</x2:calendar-color> + <x2:calendar-color>#391B71A0</x2:calendar-color> </x1:prop> </x1:set> </x0:mkcalendar> diff --git a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result index 5ef3242f..7c8ff01a 100644 --- a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result +++ b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result index dcf27031..64403a0c 100644 --- a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result +++ b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result @@ -2,13 +2,13 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access ETag: "deadbeefcafefeeddeadbeefcafefeed" -Content-Length: 1142 +Content-Length: 1127 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result index 767ebeaf..92c56d24 100644 --- a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result +++ b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result index 6cdbfe77..9a033ee7 100644 --- a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result +++ b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <C:supported-collation-set> diff --git a/testing/tests/regression-suite/826-Spec-PROPFIND.result b/testing/tests/regression-suite/826-Spec-PROPFIND.result index a0aaa047..1caabeb0 100644 --- a/testing/tests/regression-suite/826-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/826-Spec-PROPFIND.result @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/</href> + <href>/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/827-Spec-PROPFIND.result b/testing/tests/regression-suite/827-Spec-PROPFIND.result index 9fe8cf78..b72f5341 100644 --- a/testing/tests/regression-suite/827-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/827-Spec-PROPFIND.result @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/</href> + <href>/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -47,7 +47,7 @@ </propstat> </response> <response> - <href>http://mycaldav/user1/</href> + <href>/user1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -94,7 +94,7 @@ </propstat> </response> <response> - <href>http://mycaldav/manager1/</href> + <href>/manager1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -141,7 +141,7 @@ </propstat> </response> <response> - <href>http://mycaldav/assistant1/</href> + <href>/assistant1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -188,7 +188,7 @@ </propstat> </response> <response> - <href>http://mycaldav/resource1/</href> + <href>/resource1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> @@ -235,7 +235,7 @@ </propstat> </response> <response> - <href>http://mycaldav/resource2/</href> + <href>/resource2/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> diff --git a/testing/tests/regression-suite/843-Spec-PROPFIND.result b/testing/tests/regression-suite/843-Spec-PROPFIND.result index 844a2f62..6993c1bf 100644 --- a/testing/tests/regression-suite/843-Spec-PROPFIND.result +++ b/testing/tests/regression-suite/843-Spec-PROPFIND.result @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:R="urn:mcmillan:bogus:xml:ns:rscds"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <displayname>User One's Calendar</displayname> diff --git a/testing/tests/regression-suite/870-Principal-PROPFIND.result b/testing/tests/regression-suite/870-Principal-PROPFIND.result index 6072e362..f035f4cb 100644 --- a/testing/tests/regression-suite/870-Principal-PROPFIND.result +++ b/testing/tests/regression-suite/870-Principal-PROPFIND.result @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/user1/</href> + <href>/user1/</href> <propstat> <prop> <getcontenttype>httpd/unix-directory</getcontenttype> From 89c7a336944e1e5d822584ffa9ea542ff5c33730 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 12:47:41 +1300 Subject: [PATCH 165/189] Change REPORT to omit protocol://host:port from URLs also. --- inc/caldav-REPORT.php | 3 +++ .../regression-suite/102-Evo-REPORT-1.result | 6 +++--- .../regression-suite/105-Evo-REPORT-1.result | 8 ++++---- .../regression-suite/107-Evo-REPORT-1.result | 8 ++++---- .../regression-suite/108-Evo-REPORT-1.result | 8 ++++---- .../regression-suite/203-Moz-REPORT-2.result | 8 ++++---- .../regression-suite/204-Moz-REPORT-3.result | 6 +++--- .../regression-suite/207-Moz-REPORT-4.result | 6 +++--- .../230-Moz-REPORT-Tasks-Completed.result | 8 ++++---- .../231-Moz-REPORT-All-Tasks.result | 12 ++++++------ .../regression-suite/850-Spec-REPORT-1.result | 6 +++--- .../regression-suite/851-Spec-REPORT-1.result | 12 ++++++------ .../regression-suite/900-Moz-REPORT.result | 18 +++++++++--------- 13 files changed, 56 insertions(+), 53 deletions(-) diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index 15635a4c..1f7f9bfe 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -97,6 +97,9 @@ function calendar_to_xml( $properties, $item ) { } $url = $c->protocol_server_port_script . $item->dav_name; + $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' + $url = preg_replace('#^https?://[^/]+#', '', $url ); + $prop = new XMLElement("prop"); foreach( $properties AS $k => $v ) { switch( $k ) { diff --git a/testing/tests/regression-suite/102-Evo-REPORT-1.result b/testing/tests/regression-suite/102-Evo-REPORT-1.result index d45bdd9f..455549c8 100644 --- a/testing/tests/regression-suite/102-Evo-REPORT-1.result +++ b/testing/tests/regression-suite/102-Evo-REPORT-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "7dd087918d1ab4ba7e7861307b57c6dd" -Content-Length: 341 +ETag: "5d903e7367fc5fd8975cd2a2f12c94ef" +Content-Length: 326 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> + <href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> <propstat> <prop> <getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag> diff --git a/testing/tests/regression-suite/105-Evo-REPORT-1.result b/testing/tests/regression-suite/105-Evo-REPORT-1.result index 911c06d3..71e5b574 100644 --- a/testing/tests/regression-suite/105-Evo-REPORT-1.result +++ b/testing/tests/regression-suite/105-Evo-REPORT-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "4b08329b0bd43cb3a95a0e4f8286c423" -Content-Length: 582 +ETag: "278939915085a441aa95fa319fc3bb3a" +Content-Length: 552 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/20061101T073004Z.ics</href> + <href>/caldav.php/user1/home/20061101T073004Z.ics</href> <propstat> <prop> <getetag>"c3658901fd4689d4a1e1d6f08601ef4f"</getetag> @@ -17,7 +17,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> + <href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> <propstat> <prop> <getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag> diff --git a/testing/tests/regression-suite/107-Evo-REPORT-1.result b/testing/tests/regression-suite/107-Evo-REPORT-1.result index f0d5e883..e7f99b77 100644 --- a/testing/tests/regression-suite/107-Evo-REPORT-1.result +++ b/testing/tests/regression-suite/107-Evo-REPORT-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "709206be6ed57942c30d98aa629efc6f" -Content-Length: 560 +ETag: "83ce5baee07017b4b40318062103c2ce" +Content-Length: 530 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/user1/home/20061101T073004Z.ics</href> + <href>/user1/home/20061101T073004Z.ics</href> <propstat> <prop> <getetag>"c3658901fd4689d4a1e1d6f08601ef4f"</getetag> @@ -17,7 +17,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://mycaldav/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> + <href>/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> <propstat> <prop> <getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag> diff --git a/testing/tests/regression-suite/108-Evo-REPORT-1.result b/testing/tests/regression-suite/108-Evo-REPORT-1.result index 32b5acc4..9038e8bc 100644 --- a/testing/tests/regression-suite/108-Evo-REPORT-1.result +++ b/testing/tests/regression-suite/108-Evo-REPORT-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "5a05dff964308972a179d2e7f44bf751" -Content-Length: 596 +ETag: "9f89b851745eccbc4d1da3bf3f0bb9c7" +Content-Length: 570 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://myapms/calendar/caldav.php/user1/home/20061101T073004Z.ics</href> + <href>/calendar/caldav.php/user1/home/20061101T073004Z.ics</href> <propstat> <prop> <getetag>"c3658901fd4689d4a1e1d6f08601ef4f"</getetag> @@ -17,7 +17,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href>http://myapms/calendar/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> + <href>/calendar/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> <propstat> <prop> <getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag> diff --git a/testing/tests/regression-suite/203-Moz-REPORT-2.result b/testing/tests/regression-suite/203-Moz-REPORT-2.result index 607ee9da..c1f39df6 100644 --- a/testing/tests/regression-suite/203-Moz-REPORT-2.result +++ b/testing/tests/regression-suite/203-Moz-REPORT-2.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "a57a6c930b230c67301c4295254a3521" -Content-Length: 2420 +ETag: "6df625ac708940d88e7e400fa0cd2092" +Content-Length: 2390 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/20061101T073004Z.ics</href> + <href>/caldav.php/user1/home/20061101T073004Z.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR @@ -57,7 +57,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> + <href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR diff --git a/testing/tests/regression-suite/204-Moz-REPORT-3.result b/testing/tests/regression-suite/204-Moz-REPORT-3.result index f9b61fc8..2339c01e 100644 --- a/testing/tests/regression-suite/204-Moz-REPORT-3.result +++ b/testing/tests/regression-suite/204-Moz-REPORT-3.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "46061ea7ac75102dbb315b82c666c24d" -Content-Length: 1110 +ETag: "62d5362cafb71b92c39ff83bfec5f16d" +Content-Length: 1095 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/resource2/home/0A5EA1F0F2691A03E917E85F9F255448-0.ics</href> + <href>/caldav.php/resource2/home/0A5EA1F0F2691A03E917E85F9F255448-0.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR diff --git a/testing/tests/regression-suite/207-Moz-REPORT-4.result b/testing/tests/regression-suite/207-Moz-REPORT-4.result index 33886f34..f7009e58 100644 --- a/testing/tests/regression-suite/207-Moz-REPORT-4.result +++ b/testing/tests/regression-suite/207-Moz-REPORT-4.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "5ea083d59cfcd77e3baf11ef74297e6e" -Content-Length: 1358 +ETag: "5acea2c1bc8250bf55a3a32f155c0872" +Content-Length: 1343 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href> + <href>/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR diff --git a/testing/tests/regression-suite/230-Moz-REPORT-Tasks-Completed.result b/testing/tests/regression-suite/230-Moz-REPORT-Tasks-Completed.result index fc880a82..42d86bec 100644 --- a/testing/tests/regression-suite/230-Moz-REPORT-Tasks-Completed.result +++ b/testing/tests/regression-suite/230-Moz-REPORT-Tasks-Completed.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "8f48e613721a5ccb5e44c277f7a1a909" -Content-Length: 1630 +ETag: "cf7647a0d4c17b2c0c8dcf418574fe09" +Content-Length: 1604 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://myapms/calendar/caldav.php/user1/home/2178279a-aec2-471f-832d-1f6df6203f2f.ics</href> + <href>/calendar/caldav.php/user1/home/2178279a-aec2-471f-832d-1f6df6203f2f.ics</href> <propstat> <prop> <getetag>"509b0f0d8a3363379f9f5727f5dd74a0"</getetag> @@ -32,7 +32,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://myapms/calendar/caldav.php/user1/home/917b9e47-b748-4550-a566-657fbe672447.ics</href> + <href>/calendar/caldav.php/user1/home/917b9e47-b748-4550-a566-657fbe672447.ics</href> <propstat> <prop> <getetag>"cb3d9dc3e8c157f53eba3ea0e1e0f146"</getetag> diff --git a/testing/tests/regression-suite/231-Moz-REPORT-All-Tasks.result b/testing/tests/regression-suite/231-Moz-REPORT-All-Tasks.result index 225ff38b..ce3399e9 100644 --- a/testing/tests/regression-suite/231-Moz-REPORT-All-Tasks.result +++ b/testing/tests/regression-suite/231-Moz-REPORT-All-Tasks.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "2d56ad662a3857cbba346a51e2287e22" -Content-Length: 4276 +ETag: "4a177807973966b4873ffa2f0080b4a1" +Content-Length: 4224 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://myapms/calendar/caldav.php/user1/home/0575d895-a006-4ed8-9be6-0d1b6b6b1f96.ics</href> + <href>/calendar/caldav.php/user1/home/0575d895-a006-4ed8-9be6-0d1b6b6b1f96.ics</href> <propstat> <prop> <getetag>"00ad5eb1eb5507884710b0b66aa5d5c4"</getetag> @@ -54,7 +54,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://myapms/calendar/caldav.php/user1/home/2178279a-aec2-471f-832d-1f6df6203f2f.ics</href> + <href>/calendar/caldav.php/user1/home/2178279a-aec2-471f-832d-1f6df6203f2f.ics</href> <propstat> <prop> <getetag>"509b0f0d8a3363379f9f5727f5dd74a0"</getetag> @@ -78,7 +78,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://myapms/calendar/caldav.php/user1/home/917b9e47-b748-4550-a566-657fbe672447.ics</href> + <href>/calendar/caldav.php/user1/home/917b9e47-b748-4550-a566-657fbe672447.ics</href> <propstat> <prop> <getetag>"cb3d9dc3e8c157f53eba3ea0e1e0f146"</getetag> @@ -104,7 +104,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://myapms/calendar/caldav.php/user1/home/b1679f77-673d-4f46-b3eb-2420e1bba301.ics</href> + <href>/calendar/caldav.php/user1/home/b1679f77-673d-4f46-b3eb-2420e1bba301.ics</href> <propstat> <prop> <getetag>"a2990674708634a311bb98a59865ca50"</getetag> diff --git a/testing/tests/regression-suite/850-Spec-REPORT-1.result b/testing/tests/regression-suite/850-Spec-REPORT-1.result index 8a783df5..d7b3ba86 100644 --- a/testing/tests/regression-suite/850-Spec-REPORT-1.result +++ b/testing/tests/regression-suite/850-Spec-REPORT-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "3140e532d35ae4918005eb9bf5fcc26b" -Content-Length: 1456 +ETag: "ed933141b8d662fd7a79e37399302fa4" +Content-Length: 1441 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/20061101T073004Z.ics</href> + <href>/caldav.php/user1/home/20061101T073004Z.ics</href> <propstat> <prop> <getetag>"c3658901fd4689d4a1e1d6f08601ef4f"</getetag> diff --git a/testing/tests/regression-suite/851-Spec-REPORT-1.result b/testing/tests/regression-suite/851-Spec-REPORT-1.result index 33c243fb..d92fc1ac 100644 --- a/testing/tests/regression-suite/851-Spec-REPORT-1.result +++ b/testing/tests/regression-suite/851-Spec-REPORT-1.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "8bb1ae7c599f81130860154adb77364b" -Content-Length: 5175 +ETag: "3902e726b3e12b996ddf533065b131ab" +Content-Length: 5115 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> + <href>/caldav.php/user1/home/3F4CF6227300FD062D9EF3CDFB30D32D-0.ics</href> <propstat> <prop> <getetag>"2c32a2f8aba853654eb17fe037a4db4d"</getetag> @@ -51,7 +51,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/20061101T073004Z.ics</href> + <href>/caldav.php/user1/home/20061101T073004Z.ics</href> <propstat> <prop> <getetag>"c3658901fd4689d4a1e1d6f08601ef4f"</getetag> @@ -101,7 +101,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href> + <href>/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href> <propstat> <prop> <getetag>"a1c6404d61190f9574e2bfd69383f144"</getetag> @@ -147,7 +147,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/1906b3ca-4890-468a-9b58-1de74bf2c716.ics</href> + <href>/caldav.php/user1/home/1906b3ca-4890-468a-9b58-1de74bf2c716.ics</href> <propstat> <prop> <getetag>"5def8ae2b20893a1c7f4dbaeb008f2f1"</getetag> diff --git a/testing/tests/regression-suite/900-Moz-REPORT.result b/testing/tests/regression-suite/900-Moz-REPORT.result index 166138ab..3bb0dede 100644 --- a/testing/tests/regression-suite/900-Moz-REPORT.result +++ b/testing/tests/regression-suite/900-Moz-REPORT.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "78f60a204e7deae626d7a11a8f7f8d8e" -Content-Length: 7901 +ETag: "add7fd32d70e4f7378b7aff4cf4e32e1" +Content-Length: 7796 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/xml; charset="utf-8" @@ -10,7 +10,7 @@ Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/1906b3ca-4890-468a-9b58-1de74bf2c716.ics</href> + <href>/caldav.php/user1/home/1906b3ca-4890-468a-9b58-1de74bf2c716.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR @@ -56,7 +56,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href> + <href>/caldav.php/user1/home/4aaf8f37-f232-4c8e-a72e-e171d4c4fe54.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR @@ -101,7 +101,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/71e2ae82-7870-11db-c6d6-f6927c144649.ics</href> + <href>/caldav.php/user1/home/71e2ae82-7870-11db-c6d6-f6927c144649.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR @@ -141,7 +141,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/9d050be7-8a02-4355-8ed3-02a9fc5f473f.ics</href> + <href>/caldav.php/user1/home/9d050be7-8a02-4355-8ed3-02a9fc5f473f.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR @@ -186,7 +186,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href> + <href>/caldav.php/user1/home/AAA9318E-37D9-4319-8626-95ECD3D3B243.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR @@ -241,7 +241,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics</href> + <href>/caldav.php/user1/home/da81c0ee-7871-11db-c6d6-f6927c144649.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR @@ -264,7 +264,7 @@ END:VCALENDAR </propstat> </response> <response> - <href>http://mycaldav/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href> + <href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href> <propstat> <prop> <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR From 6d3a0abd4ccae3f230ffbe91a23dd2484caed639 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 12:57:54 +1300 Subject: [PATCH 166/189] Write & use utility function for URL construction. --- inc/CalDAVRequest.php | 14 ++++++++++++++ inc/caldav-PROPFIND.php | 9 ++------- inc/caldav-REPORT.php | 4 +--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index 317f6109..0906ce57 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -254,6 +254,20 @@ class CalDAVRequest } + /** + * Construct a URL from the supplied dav_name + * @param string $partial_path The part of the path after the script name + */ + function ConstructURL( $partial_path ) { + global $c; + + $url = $c->protocol_server_port_script . $partial_path; + $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' + $url = preg_replace('#^https?://[^/]+#', '', $url ); + return $url; + } + + /** * Permissions are controlled as follows: * 1. if the path is '/', the request has read privileges diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index 94289283..d6ec5f23 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -320,10 +320,7 @@ function collection_to_xml( $collection ) { $arbitrary_results = get_arbitrary_properties($collection->dav_name); $collection->properties = $arbitrary_results->found; - $url = $c->protocol_server_port_script . $collection->dav_name; - $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' - $url = preg_replace('#^https?://[^/]+#', '', $url ); - + $url = $request->ConstructURL($collection->dav_name); $resourcetypes = array( new XMLElement("collection") ); $contentlength = false; @@ -479,9 +476,7 @@ function item_to_xml( $item ) { $item->properties = get_arbitrary_properties($item->dav_name); - $url = $c->protocol_server_port_script . $item->dav_name; - $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' - $url = preg_replace('#^https?://[^/]+#', '', $url ); + $url = $request->ConstructURL($item->dav_name); $prop = new XMLElement("prop"); $not_found = new XMLElement("prop"); diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index 1f7f9bfe..4aee6056 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -96,9 +96,7 @@ function calendar_to_xml( $properties, $item ) { } } - $url = $c->protocol_server_port_script . $item->dav_name; - $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' - $url = preg_replace('#^https?://[^/]+#', '', $url ); + $url = $request->ConstructURL($item->dav_name); $prop = new XMLElement("prop"); foreach( $properties AS $k => $v ) { From 0a5b95be5217eb7e88faaa5a24cb2413d59b5769 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 12:58:50 +1300 Subject: [PATCH 167/189] Data changes. --- .../regression-suite/602-Soho-PROPFIND.result | 18 ++++++++++++++++-- .../840-Spec-PROPPATCH-1.result | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/testing/tests/regression-suite/602-Soho-PROPFIND.result b/testing/tests/regression-suite/602-Soho-PROPFIND.result index 77757a2f..76a93114 100644 --- a/testing/tests/regression-suite/602-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/602-Soho-PROPFIND.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "86a8139e523f058ede9c0298e408d8b3" -Content-Length: 7045 +ETag: "a8b240ec9481626730de7fffbc8cc5f8" +Content-Length: 7461 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -266,4 +266,18 @@ Content-Type: text/xml; charset="utf-8" <status>HTTP/1.1 200 OK</status> </propstat> </response> + <response> + <href>/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/E6BC62F3-77C6-4FB7-BDD3-6882E2F1BE74.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> </multistatus> diff --git a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result index c2cfcdd2..20fdb480 100644 --- a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result +++ b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result @@ -12,7 +12,7 @@ Content-Type: text/xml; charset="utf-8" </response> </multistatus> User One's Calendar --- faf25336de0e470a54075c14cbcf5272 --- 0 --- 1 -/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/ --- HTTP://APPLE.COM/NS/ICAL/:CALENDAR-COLOR --- #492BA1FF --- 10 --- 1 +/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/ --- HTTP://APPLE.COM/NS/ICAL/:CALENDAR-COLOR --- #391B71A0 --- 10 --- 1 /user1/home/ --- DAV::OWNER --- <DAV::HREF>http://www.example.com/acl/users/jim</DAV::HREF> --- 10 --- 1 From b474b5dbe78aa7ced3f656686fdb7bf3fcd5b7c2 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 12:59:29 +1300 Subject: [PATCH 168/189] Include an iCal VTODO in the regression testing. --- .../514-iCal-PUT-VTODO.result | 8 +++ .../regression-suite/514-iCal-PUT-VTODO.test | 58 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 testing/tests/regression-suite/514-iCal-PUT-VTODO.result create mode 100644 testing/tests/regression-suite/514-iCal-PUT-VTODO.test diff --git a/testing/tests/regression-suite/514-iCal-PUT-VTODO.result b/testing/tests/regression-suite/514-iCal-PUT-VTODO.result new file mode 100644 index 00000000..67f6e5c4 --- /dev/null +++ b/testing/tests/regression-suite/514-iCal-PUT-VTODO.result @@ -0,0 +1,8 @@ +HTTP/1.1 201 Created +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "18134bbb51c8e25919c92a0d6265f789" +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +10 --- 18134bbb51c8e25919c92a0d6265f789 --- VTODO --- 10 --- E6BC62F3-77C6-4FB7-BDD3-6882E2F1BE74 --- 2007-11-24 22:09:25 --- 2004-01-01 12:00:00+13 --- NULL --- 2010-02-17 00:00:00+13 --- Celebrate a significant birthday --- NULL --- Organise a party --- 5 --- PUBLIC --- NULL --- NULL --- NULL --- NULL --- NULL --- NULL diff --git a/testing/tests/regression-suite/514-iCal-PUT-VTODO.test b/testing/tests/regression-suite/514-iCal-PUT-VTODO.test new file mode 100644 index 00000000..d6953fd1 --- /dev/null +++ b/testing/tests/regression-suite/514-iCal-PUT-VTODO.test @@ -0,0 +1,58 @@ +# +# PUT an iCal style event into the database +# +TYPE=PUT +URL=http://mycaldav/caldav.php/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/E6BC62F3-77C6-4FB7-BDD3-6882E2F1BE74.ics +HEADER=Content-Type: text/calendar +HEADER=User-Agent: DAVKit/2.0 (10.5.1; wrbt) iCal 3.0.1 +HEAD + + +BEGINDATA +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 3.0//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Pacific/Auckland +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+1200 +TZOFFSETTO:+1300 +DTSTART:19901007T020000 +RRULE:FREQ=YEARLY;UNTIL=20060930T140000Z;BYMONTH=10;BYDAY=1SU +TZNAME:NZDT +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VTODO +PRIORITY:5 +SEQUENCE:7 +DESCRIPTION:Organise a party +UID:E6BC62F3-77C6-4FB7-BDD3-6882E2F1BE74 +DTSTART;TZID=Pacific/Auckland:20040101T120000 +DTSTAMP:20071124T220925Z +SUMMARY:Celebrate a significant birthday +CREATED:20071124T220749Z +X-APPLE-SORT-ORDER:2147483647 +DUE;VALUE=DATE:20100217 +END:VTODO +END:VCALENDAR +ENDDATA + + +QUERY +SELECT caldav_data.user_no, caldav_data.dav_etag, caldav_type, logged_user, + uid, dtstamp, dtstart, dtend, due, summary, location, + description, priority, class, transp, rrule, url, + percent_complete, tz_id, status +FROM caldav_data JOIN calendar_item USING(dav_name) +WHERE caldav_data.dav_name = +'/user1/6E20BB7C-EFD9-4F0F-9BDC-5335E04D47E0/E6BC62F3-77C6-4FB7-BDD3-6882E2F1BE74.ics'; +ENDQUERY + From c0c8d2d19f941d1dc841fcebc02303e05bc7d750 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 12:59:59 +1300 Subject: [PATCH 169/189] Include another repeating event, with multiple alarms. --- .../515-iCal-PUT-VEVENT.result | 10 +++ .../regression-suite/515-iCal-PUT-VEVENT.test | 79 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 testing/tests/regression-suite/515-iCal-PUT-VEVENT.result create mode 100644 testing/tests/regression-suite/515-iCal-PUT-VEVENT.test diff --git a/testing/tests/regression-suite/515-iCal-PUT-VEVENT.result b/testing/tests/regression-suite/515-iCal-PUT-VEVENT.result new file mode 100644 index 00000000..8675a639 --- /dev/null +++ b/testing/tests/regression-suite/515-iCal-PUT-VEVENT.result @@ -0,0 +1,10 @@ +HTTP/1.1 100 Continue + +HTTP/1.1 201 Created +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "c057c3eb789b944e76f4d77fccf36ea1" +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +101 --- c057c3eb789b944e76f4d77fccf36ea1 --- VEVENT --- 10 --- 3C1BF85D-3F28-413F-844F-80EBD33B8EE6 --- 2007-11-24 22:19:00 --- 2007-11-23 12:00:00+13 --- 2007-11-23 14:00:00+13 --- NULL --- Beard Meeting --- NULL --- Lunch will be needed --- NULL --- PUBLIC --- OPAQUE --- FREQ=MONTHLY;INTERVAL=1;BYDAY=4FR --- NULL --- NULL --- NULL --- NULL diff --git a/testing/tests/regression-suite/515-iCal-PUT-VEVENT.test b/testing/tests/regression-suite/515-iCal-PUT-VEVENT.test new file mode 100644 index 00000000..fd012383 --- /dev/null +++ b/testing/tests/regression-suite/515-iCal-PUT-VEVENT.test @@ -0,0 +1,79 @@ +# +# PUT an iCal style event with repeats and alarms +# +TYPE=PUT +URL=http://mycaldav/caldav.php/resource2/home/3C1BF85D-3F28-413F-844F-80EBD33B8EE6.ics +HEADER=Content-Type: text/calendar +HEADER=User-Agent: DAVKit/2.0 (10.5.1; wrbt) iCal 3.0.1 +HEAD + + +BEGINDATA +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 3.0//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Pacific/Auckland +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:19900318T030000 +RRULE:FREQ=YEARLY;UNTIL=20070317T140000Z;BYMONTH=3;BYDAY=3SU +TZNAME:NZST +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:+1200 +TZOFFSETTO:+1300 +DTSTART:20070930T020000 +RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU +TZNAME:NZDT +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1300 +TZOFFSETTO:+1200 +DTSTART:20080406T030000 +RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU +TZNAME:NZST +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +SEQUENCE:7 +DESCRIPTION:Lunch will be needed +UID:3C1BF85D-3F28-413F-844F-80EBD33B8EE6 +TRANSP:OPAQUE +DTSTART;TZID=Pacific/Auckland:20071123T120000 +DTSTAMP:20071124T221900Z +SUMMARY:Beard Meeting +CREATED:20071124T221521Z +DTEND;TZID=Pacific/Auckland:20071123T140000 +RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=4FR +BEGIN:VALARM +X-WR-ALARMUID:F5B2B4CF-E7F2-47B3-8243-8CB829E81122 +ACTION:EMAIL +DESCRIPTION:This is an event reminder +SUMMARY:Alarm notification +ATTENDEE:mailto:andrew@mcmillan.net.nz +TRIGGER:-P8D +END:VALARM +BEGIN:VALARM +X-WR-ALARMUID:3A336F1D-550D-412F-9BDE-EBE8B03E8A53 +ACTION:AUDIO +TRIGGER:-PT15M +ATTACH;VALUE=URI:Basso +END:VALARM +END:VEVENT +END:VCALENDAR +ENDDATA + + +QUERY +SELECT caldav_data.user_no, caldav_data.dav_etag, caldav_type, logged_user, + uid, dtstamp, dtstart, dtend, due, summary, location, + description, priority, class, transp, rrule, url, + percent_complete, tz_id, status +FROM caldav_data JOIN calendar_item USING(dav_name) +WHERE caldav_data.dav_name = +'/resource2/home/3C1BF85D-3F28-413F-844F-80EBD33B8EE6.ics'; +ENDQUERY + From 96e579910b6a2818344f6ecb53f8d8791013acc4 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 13:03:41 +1300 Subject: [PATCH 170/189] Use URL construction in PROPPATCH handling. --- inc/caldav-PROPPATCH.php | 6 ++++-- testing/tests/regression-suite/841-Spec-PROPPATCH-2.result | 4 ++-- testing/tests/regression-suite/842-Spec-PROPPATCH-3.result | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/inc/caldav-PROPPATCH.php b/inc/caldav-PROPPATCH.php index e3978d4d..3e9a21ca 100644 --- a/inc/caldav-PROPPATCH.php +++ b/inc/caldav-PROPPATCH.php @@ -195,7 +195,8 @@ if ( count($failure) > 0 ) { )); } - array_unshift( $failure, new XMLElement('href', $c->protocol_server_port_script . $request->path ) ); + $url = $request->ConstructURL($request->path); + array_unshift( $failure, new XMLElement('href', $url ) ); $failure[] = new XMLElement('responsedescription', translate("Some properties were not able to be changed.") ); $multistatus = new XMLElement( "multistatus", new XMLElement( 'response', $failure ), array('xmlns'=>'DAV:') ); @@ -209,7 +210,8 @@ if ( count($failure) > 0 ) { $sql .= "COMMIT;"; $qry = new PgQuery( $sql ); if ( $qry->Exec() ) { - $href = new XMLElement('href', $c->protocol_server_port_script . $request->path ); + $url = $request->ConstructURL($request->path); + $href = new XMLElement('href', $url ); $desc = new XMLElement('responsedescription', translate("All requested changes were made.") ); $multistatus = new XMLElement( "multistatus", new XMLElement( 'response', array( $href, $desc ) ), array('xmlns'=>'DAV:') ); diff --git a/testing/tests/regression-suite/841-Spec-PROPPATCH-2.result b/testing/tests/regression-suite/841-Spec-PROPPATCH-2.result index 30ce8085..154d20ed 100644 --- a/testing/tests/regression-suite/841-Spec-PROPPATCH-2.result +++ b/testing/tests/regression-suite/841-Spec-PROPPATCH-2.result @@ -1,13 +1,13 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -Content-Length: 239 +Content-Length: 224 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <responsedescription>All requested changes were made.</responsedescription> </response> </multistatus> diff --git a/testing/tests/regression-suite/842-Spec-PROPPATCH-3.result b/testing/tests/regression-suite/842-Spec-PROPPATCH-3.result index 2c138f46..b604a362 100644 --- a/testing/tests/regression-suite/842-Spec-PROPPATCH-3.result +++ b/testing/tests/regression-suite/842-Spec-PROPPATCH-3.result @@ -1,13 +1,13 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -Content-Length: 464 +Content-Length: 449 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <propstat> <prop> <DAV::RESOURCETYPE/> From 2cacc8aa1cc3fb0632a48698dde4469b318662d3 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 13:31:35 +1300 Subject: [PATCH 171/189] Almost entirely switched to root-relative URLs now. --- inc/CalDAVPrincipal.php | 18 +++++---------- inc/CalDAVRequest.php | 23 ------------------- inc/always.php | 20 ++++++++++++++++ inc/always.php.in | 19 ++++++++++++++- inc/caldav-PROPFIND.php | 4 ++-- inc/caldav-PROPPATCH.php | 4 ++-- inc/caldav-REPORT.php | 2 +- .../840-Spec-PROPPATCH-1.result | 4 ++-- 8 files changed, 51 insertions(+), 43 deletions(-) diff --git a/inc/CalDAVPrincipal.php b/inc/CalDAVPrincipal.php index 9c863373..5e6a1af9 100644 --- a/inc/CalDAVPrincipal.php +++ b/inc/CalDAVPrincipal.php @@ -99,21 +99,15 @@ class CalDAVPrincipal $this->{$k} = $v; } - $script = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : ''); - $script = $c->protocol_server_port_script . $script; - if ( preg_match( '/ iCal 3\.0/', $_SERVER['HTTP_USER_AGENT'] ) ) { - $script = preg_replace('#^https?://[^/]+#', '', $script ); - } + $this->url = ConstructURL( "/".$this->username."/" ); +// $this->url = ConstructURL( "/__uuids__/" . $this->username . "/" ); - $this->url = sprintf( "%s/%s/", $script, $this->username); -// $this->url = sprintf( "%s%s/__uuids__/%s/", $c->protocol_server_port_script, $script, $this->username); - - $this->calendar_home_set = sprintf( "%s/%s/", $script, $this->username); + $this->calendar_home_set = ConstructURL( "/".$this->username."/" ); $this->user_address_set = array( - sprintf( "%s/%s/", $script, $this->username), -// sprintf( "%s%s/~%s/", $c->protocol_server_port_script, $script, $this->username), -// sprintf( "%s%s/__uuids__/%s/", $c->protocol_server_port_script, $script, $this->username), + ConstructURL( "/".$this->username."/" ), +// ConstructURL( "/~".$this->username."/" ), +// ConstructURL( "/__uuids__/".$this->username."/" ), ); $this->schedule_inbox_url = sprintf( "%s.in/", $this->calendar_home_set); $this->schedule_outbox_url = sprintf( "%s.out/", $this->calendar_home_set); diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php index 0906ce57..2385c81d 100644 --- a/inc/CalDAVRequest.php +++ b/inc/CalDAVRequest.php @@ -72,15 +72,6 @@ class CalDAVRequest $this->user_agent = ((isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : "Probably Mulberry")); - /** - * In general we systematically return Absolute URI hrefs. Unfortunately some - * software doesn't expect this to happen (iCal, SOHO Organizer, ???) and so we - * need to hack around these programs. RFC4918 section 8.3 gives details. - */ - if ( preg_match( '/(iCal 3.0|SOHO Organizer|ChronosCalendarsService)/', $this->user_agent ) ) { - $c->protocol_server_port_script = preg_replace('#^(http|caldav)s?://[^/]+#', '', $c->protocol_server_port_script ); - } - /** * A variety of requests may set the "Depth" header to control recursion */ @@ -254,20 +245,6 @@ class CalDAVRequest } - /** - * Construct a URL from the supplied dav_name - * @param string $partial_path The part of the path after the script name - */ - function ConstructURL( $partial_path ) { - global $c; - - $url = $c->protocol_server_port_script . $partial_path; - $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' - $url = preg_replace('#^https?://[^/]+#', '', $url ); - return $url; - } - - /** * Permissions are controlled as follows: * 1. if the path is '/', the request has read privileges diff --git a/inc/always.php b/inc/always.php index 0cfbeb48..20057428 100644 --- a/inc/always.php +++ b/inc/always.php @@ -213,4 +213,24 @@ function getStatusMessage($status) { } +/** +* Construct a URL from the supplied dav_name +* @param string $partial_path The part of the path after the script name +*/ +function ConstructURL( $partial_path ) { + global $c; + + if ( ! isset($c->_url_script_path) ) { + $c->_url_script_path = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : ''); + $c->_url_script_path = $c->protocol_server_port_script . $c->_url_script_path; + } + + $url = $c->_url_script_path . $partial_path; + $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' + $url = preg_replace('#^https?://[^/]+#', '', $url ); + return $url; +} + + + ?> \ No newline at end of file diff --git a/inc/always.php.in b/inc/always.php.in index 4b5f011e..85e7dbbd 100644 --- a/inc/always.php.in +++ b/inc/always.php.in @@ -213,4 +213,21 @@ function getStatusMessage($status) { } -?> \ No newline at end of file +/** +* Construct a URL from the supplied dav_name +* @param string $partial_path The part of the path after the script name +*/ +function ConstructURL( $partial_path ) { + global $c; + + if ( ! isset($c->_url_script_path) ) { + $c->_url_script_path = (preg_match('#/$#', $c->protocol_server_port_script) ? 'caldav.php' : ''); + $c->_url_script_path = $c->protocol_server_port_script . $c->_url_script_path; + } + + $url = $c->_url_script_path . $partial_path; + $url = preg_replace( '#^(https?://.+)//#', '$1/', $url ); // Ensure we don't double any '/' + $url = preg_replace('#^https?://[^/]+#', '', $url ); + return $url; +} + diff --git a/inc/caldav-PROPFIND.php b/inc/caldav-PROPFIND.php index d6ec5f23..6fa2a19a 100644 --- a/inc/caldav-PROPFIND.php +++ b/inc/caldav-PROPFIND.php @@ -320,7 +320,7 @@ function collection_to_xml( $collection ) { $arbitrary_results = get_arbitrary_properties($collection->dav_name); $collection->properties = $arbitrary_results->found; - $url = $request->ConstructURL($collection->dav_name); + $url = ConstructURL($collection->dav_name); $resourcetypes = array( new XMLElement("collection") ); $contentlength = false; @@ -476,7 +476,7 @@ function item_to_xml( $item ) { $item->properties = get_arbitrary_properties($item->dav_name); - $url = $request->ConstructURL($item->dav_name); + $url = ConstructURL($item->dav_name); $prop = new XMLElement("prop"); $not_found = new XMLElement("prop"); diff --git a/inc/caldav-PROPPATCH.php b/inc/caldav-PROPPATCH.php index 3e9a21ca..b4a2c57c 100644 --- a/inc/caldav-PROPPATCH.php +++ b/inc/caldav-PROPPATCH.php @@ -195,7 +195,7 @@ if ( count($failure) > 0 ) { )); } - $url = $request->ConstructURL($request->path); + $url = ConstructURL($request->path); array_unshift( $failure, new XMLElement('href', $url ) ); $failure[] = new XMLElement('responsedescription', translate("Some properties were not able to be changed.") ); @@ -210,7 +210,7 @@ if ( count($failure) > 0 ) { $sql .= "COMMIT;"; $qry = new PgQuery( $sql ); if ( $qry->Exec() ) { - $url = $request->ConstructURL($request->path); + $url = ConstructURL($request->path); $href = new XMLElement('href', $url ); $desc = new XMLElement('responsedescription', translate("All requested changes were made.") ); diff --git a/inc/caldav-REPORT.php b/inc/caldav-REPORT.php index 4aee6056..e3c4c34a 100644 --- a/inc/caldav-REPORT.php +++ b/inc/caldav-REPORT.php @@ -96,7 +96,7 @@ function calendar_to_xml( $properties, $item ) { } } - $url = $request->ConstructURL($item->dav_name); + $url = ConstructURL($item->dav_name); $prop = new XMLElement("prop"); foreach( $properties AS $k => $v ) { diff --git a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result index 20fdb480..24d760df 100644 --- a/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result +++ b/testing/tests/regression-suite/840-Spec-PROPPATCH-1.result @@ -1,13 +1,13 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -Content-Length: 239 +Content-Length: 224 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href>http://mycaldav/caldav.php/user1/home/</href> + <href>/caldav.php/user1/home/</href> <responsedescription>All requested changes were made.</responsedescription> </response> </multistatus> From e589d2ed5c8c9f101f969e58cde0c965748966c7 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 13:43:25 +1300 Subject: [PATCH 172/189] Remove protocol://host:port from principal report and be consistent with calendar-home-set response in other places also. --- inc/caldav-REPORT-principal.php | 6 ++-- .../860-Spec-REPORT-principal.result | 6 ++-- .../861-Spec-REPORT-principal.result | 30 +++++++++---------- .../862-Spec-REPORT-principal.result | 8 ++--- .../863-Spec-REPORT-principal.result | 8 ++--- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/inc/caldav-REPORT-principal.php b/inc/caldav-REPORT-principal.php index 4cbf9d6f..9ebc2067 100644 --- a/inc/caldav-REPORT-principal.php +++ b/inc/caldav-REPORT-principal.php @@ -15,9 +15,9 @@ function principal_to_xml( $properties, $item ) { dbg_error_log("REPORT","Building XML Response for principal '%s'", $item->username ); - $this_url = $c->protocol_server_port_script . $request->dav_name; - $principal_url = sprintf( "%s/%s/", $c->protocol_server_port_script, $item->username); - $home_calendar = sprintf( "%s/%s/%s/", $c->protocol_server_port_script, $item->username, $c->home_calendar_name); + $this_url = ConstructURL( $request->dav_name ); + $principal_url = ConstructURL( "/".$item->username."/"); + $home_calendar = ConstructURL( "/".$item->username."/"); $prop = new XMLElement("prop"); $denied = array(); foreach( $properties AS $k => $v ) { diff --git a/testing/tests/regression-suite/860-Spec-REPORT-principal.result b/testing/tests/regression-suite/860-Spec-REPORT-principal.result index adb16f6d..b7fe7f32 100644 --- a/testing/tests/regression-suite/860-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/860-Spec-REPORT-principal.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "c345629a9689adce5411818c3c29aa43" -Content-Length: 358 +ETag: "a608df84660135cffaa4e0c8e3000df5" +Content-Length: 338 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -11,7 +11,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/user1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user1/</calendar-home-set> <displayname>user1</displayname> </prop> <status>HTTP/1.1 200 OK</status> diff --git a/testing/tests/regression-suite/861-Spec-REPORT-principal.result b/testing/tests/regression-suite/861-Spec-REPORT-principal.result index 7b9526f7..7fb68ba9 100644 --- a/testing/tests/regression-suite/861-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/861-Spec-REPORT-principal.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "8ee6bd9a1b7e15f40e6e24f149c6bf20" -Content-Length: 3720 +ETag: "858ddca3788c4d78126a68ae1ecc123d" +Content-Length: 3460 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -11,7 +11,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/admin/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/admin/</calendar-home-set> <displayname>admin</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -21,7 +21,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/andrew/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/andrew/</calendar-home-set> <displayname>andrew</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -31,7 +31,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/user1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user1/</calendar-home-set> <displayname>user1</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -41,7 +41,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/user2/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user2/</calendar-home-set> <displayname>user2</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -51,7 +51,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/user3/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user3/</calendar-home-set> <displayname>user3</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -61,7 +61,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/user4/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user4/</calendar-home-set> <displayname>user4</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -71,7 +71,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/user5/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user5/</calendar-home-set> <displayname>user5</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -81,7 +81,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/manager1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/manager1/</calendar-home-set> <displayname>manager1</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -91,7 +91,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/assistant1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/assistant1/</calendar-home-set> <displayname>assistant1</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -101,7 +101,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/resource1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/resource1/</calendar-home-set> <displayname>resource1</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -111,7 +111,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/resource2/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/resource2/</calendar-home-set> <displayname>resource2</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -121,7 +121,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/resmgr1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/resmgr1/</calendar-home-set> <displayname>resmgr1</displayname> </prop> <status>HTTP/1.1 200 OK</status> @@ -131,7 +131,7 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/teamclient1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/teamclient1/</calendar-home-set> <displayname>teamclient1</displayname> </prop> <status>HTTP/1.1 200 OK</status> diff --git a/testing/tests/regression-suite/862-Spec-REPORT-principal.result b/testing/tests/regression-suite/862-Spec-REPORT-principal.result index c55a5655..d106c4c2 100644 --- a/testing/tests/regression-suite/862-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/862-Spec-REPORT-principal.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "d8fe1f4720e6249cb2fb0711fbed9794" -Content-Length: 688 +ETag: "48570cfdc80325e01292f9a6d0db7289" +Content-Length: 653 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -11,12 +11,12 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/user1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user1/</calendar-home-set> <displayname>user1</displayname> <resourcetype> <principal/> </resourcetype> - <principal-url>http://mycaldav/caldav.php/user1/</principal-url> + <principal-url>/caldav.php/user1/</principal-url> <alternate-uri/> <group-member-set/> <group-membership> diff --git a/testing/tests/regression-suite/863-Spec-REPORT-principal.result b/testing/tests/regression-suite/863-Spec-REPORT-principal.result index 7b38fea1..bc689a6b 100644 --- a/testing/tests/regression-suite/863-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/863-Spec-REPORT-principal.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "f9a0b07b2c7b0347a9ae26a412baef6b" -Content-Length: 743 +ETag: "d73acd2ac03f8c93b5c7197558e2314b" +Content-Length: 708 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -11,12 +11,12 @@ Content-Type: text/xml; charset="utf-8" <href/> <propstat> <prop> - <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">http://mycaldav/caldav.php/resmgr1/home/</calendar-home-set> + <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/resmgr1/</calendar-home-set> <displayname>resmgr1</displayname> <resourcetype> <principal/> </resourcetype> - <principal-url>http://mycaldav/caldav.php/resmgr1/</principal-url> + <principal-url>/caldav.php/resmgr1/</principal-url> <alternate-uri/> <group-member-set> <href>http://mycaldav/caldav.php/user1/</href> From 139062644939063fadf4ba3cd4dfc711378d6b17 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Sun, 25 Nov 2007 23:08:17 +1300 Subject: [PATCH 173/189] Get rid of the last URLs containing protocol://host:port part. --- inc/caldav-REPORT-principal.php | 6 ++-- .../860-Spec-REPORT-principal.result | 6 ++-- .../861-Spec-REPORT-principal.result | 30 +++++++++---------- .../862-Spec-REPORT-principal.result | 10 +++---- .../863-Spec-REPORT-principal.result | 12 ++++---- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/inc/caldav-REPORT-principal.php b/inc/caldav-REPORT-principal.php index 9ebc2067..549f2f0d 100644 --- a/inc/caldav-REPORT-principal.php +++ b/inc/caldav-REPORT-principal.php @@ -39,7 +39,7 @@ function principal_to_xml( $properties, $item ) { $group = array(); if ( $qry->Exec("REPORT-principal") && $qry->rows > 0 ) { while( $membership = $qry->Fetch() ) { - $group[] = new XMLElement("href", sprintf( "%s/%s/", $c->protocol_server_port_script, $membership->username) ); + $group[] = new XMLElement("href", ConstructURL( "/". $membership->username . "/") ); } } $prop->NewElement("group-member-set", $group ); @@ -49,7 +49,7 @@ function principal_to_xml( $properties, $item ) { $group = array(); if ( $qry->Exec("REPORT-principal") && $qry->rows > 0 ) { while( $membership = $qry->Fetch() ) { - $group[] = new XMLElement("href", sprintf( "%s/%s/", $c->protocol_server_port_script, $membership->username) ); + $group[] = new XMLElement("href", ConstructURL( "/". $membership->username . "/") ); } } $prop->NewElement("group-membership", $group ); @@ -68,7 +68,7 @@ function principal_to_xml( $properties, $item ) { $status = new XMLElement("status", "HTTP/1.1 200 OK" ); $propstat = new XMLElement( "propstat", array( $prop, $status) ); - $href = new XMLElement("href", $url ); + $href = new XMLElement("href", $principal_url ); $elements = array($href,$propstat); diff --git a/testing/tests/regression-suite/860-Spec-REPORT-principal.result b/testing/tests/regression-suite/860-Spec-REPORT-principal.result index b7fe7f32..57bf54bb 100644 --- a/testing/tests/regression-suite/860-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/860-Spec-REPORT-principal.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "a608df84660135cffaa4e0c8e3000df5" -Content-Length: 338 +ETag: "325db06f30c85ce69b1aab60837300f7" +Content-Length: 362 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href/> + <href>/caldav.php/user1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user1/</calendar-home-set> diff --git a/testing/tests/regression-suite/861-Spec-REPORT-principal.result b/testing/tests/regression-suite/861-Spec-REPORT-principal.result index 7fb68ba9..96f5d967 100644 --- a/testing/tests/regression-suite/861-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/861-Spec-REPORT-principal.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "858ddca3788c4d78126a68ae1ecc123d" -Content-Length: 3460 +ETag: "c1552b9c365c15b3e3e6ca730e56e2be" +Content-Length: 3797 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href/> + <href>/caldav.php/admin/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/admin/</calendar-home-set> @@ -18,7 +18,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/andrew/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/andrew/</calendar-home-set> @@ -28,7 +28,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/user1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user1/</calendar-home-set> @@ -38,7 +38,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/user2/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user2/</calendar-home-set> @@ -48,7 +48,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/user3/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user3/</calendar-home-set> @@ -58,7 +58,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/user4/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user4/</calendar-home-set> @@ -68,7 +68,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/user5/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user5/</calendar-home-set> @@ -78,7 +78,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/manager1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/manager1/</calendar-home-set> @@ -88,7 +88,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/assistant1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/assistant1/</calendar-home-set> @@ -98,7 +98,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/resource1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/resource1/</calendar-home-set> @@ -108,7 +108,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/resource2/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/resource2/</calendar-home-set> @@ -118,7 +118,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/resmgr1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/resmgr1/</calendar-home-set> @@ -128,7 +128,7 @@ Content-Type: text/xml; charset="utf-8" </propstat> </response> <response> - <href/> + <href>/caldav.php/teamclient1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/teamclient1/</calendar-home-set> diff --git a/testing/tests/regression-suite/862-Spec-REPORT-principal.result b/testing/tests/regression-suite/862-Spec-REPORT-principal.result index d106c4c2..fe17579e 100644 --- a/testing/tests/regression-suite/862-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/862-Spec-REPORT-principal.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "48570cfdc80325e01292f9a6d0db7289" -Content-Length: 653 +ETag: "5870b1abbdaf891cb5b5891c150305cd" +Content-Length: 647 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href/> + <href>/caldav.php/user1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/user1/</calendar-home-set> @@ -20,8 +20,8 @@ Content-Type: text/xml; charset="utf-8" <alternate-uri/> <group-member-set/> <group-membership> - <href>http://mycaldav/caldav.php/resmgr1/</href> - <href>http://mycaldav/caldav.php/teamclient1/</href> + <href>/caldav.php/resmgr1/</href> + <href>/caldav.php/teamclient1/</href> </group-membership> </prop> <status>HTTP/1.1 200 OK</status> diff --git a/testing/tests/regression-suite/863-Spec-REPORT-principal.result b/testing/tests/regression-suite/863-Spec-REPORT-principal.result index bc689a6b..19356a18 100644 --- a/testing/tests/regression-suite/863-Spec-REPORT-principal.result +++ b/testing/tests/regression-suite/863-Spec-REPORT-principal.result @@ -1,14 +1,14 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "d73acd2ac03f8c93b5c7197558e2314b" -Content-Length: 708 +ETag: "c48188f2dc50ffba44c958e04f237d69" +Content-Length: 689 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> - <href/> + <href>/caldav.php/resmgr1/</href> <propstat> <prop> <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">/caldav.php/resmgr1/</calendar-home-set> @@ -19,9 +19,9 @@ Content-Type: text/xml; charset="utf-8" <principal-url>/caldav.php/resmgr1/</principal-url> <alternate-uri/> <group-member-set> - <href>http://mycaldav/caldav.php/user1/</href> - <href>http://mycaldav/caldav.php/user2/</href> - <href>http://mycaldav/caldav.php/assistant1/</href> + <href>/caldav.php/user1/</href> + <href>/caldav.php/user2/</href> + <href>/caldav.php/assistant1/</href> </group-member-set> <group-membership/> </prop> From 045b369c69cb0df264b4ae715a6770b7572a0d4f Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 27 Nov 2007 18:03:47 +1300 Subject: [PATCH 174/189] Note TODO item regarding refactoring this into CalDAVPrincipal --- inc/caldav-REPORT-principal.php | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/caldav-REPORT-principal.php b/inc/caldav-REPORT-principal.php index 549f2f0d..57241be3 100644 --- a/inc/caldav-REPORT-principal.php +++ b/inc/caldav-REPORT-principal.php @@ -4,6 +4,7 @@ $responses = array(); /** * Return XML for a single Principal (user) from the DB +* TODO: Refactor this functionality into the CalDAVPrincipal object * * @param array $properties The requested properties for this principal * @param string $item The user data for this calendar From aa928076f3e368a3659d3b6049c1e54fe619a39e Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 27 Nov 2007 18:05:22 +1300 Subject: [PATCH 175/189] If we specify the interface that's the one we should grep for the address of! --- testing/watch-port-80.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/watch-port-80.sh b/testing/watch-port-80.sh index 60cddf29..df492878 100755 --- a/testing/watch-port-80.sh +++ b/testing/watch-port-80.sh @@ -9,7 +9,7 @@ DUMP="tcp port ${PORT}" IPCLAUSE="" if [ "${IFACE}" != "any" ]; then - IP="`ip addr show dev wlan0 | grep ' inet ' | tr -s ' ' | cut -f3 -d' ' | cut -f1 -d'/'`" + IP="`ip addr show dev ${IFACE} | grep ' inet ' | tr -s ' ' | cut -f3 -d' ' | cut -f1 -d'/'`" IPCLAUSE=" and ((src host ${IP} and src port ${PORT}) or (dst host ${IP} and dst port ${PORT}))" fi From adc1166ff6ee9af90078a516e1d5d07cbc89364f Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 27 Nov 2007 18:05:51 +1300 Subject: [PATCH 176/189] iCal does an initial look for calendar-home-set when we create the account. --- .../regression-suite/501-iCal-PROPFIND.result | 34 +++++++++++++++++++ .../regression-suite/501-iCal-PROPFIND.test | 31 +++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 testing/tests/regression-suite/501-iCal-PROPFIND.result create mode 100644 testing/tests/regression-suite/501-iCal-PROPFIND.test diff --git a/testing/tests/regression-suite/501-iCal-PROPFIND.result b/testing/tests/regression-suite/501-iCal-PROPFIND.result new file mode 100644 index 00000000..c0a19c0d --- /dev/null +++ b/testing/tests/regression-suite/501-iCal-PROPFIND.result @@ -0,0 +1,34 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "840f74443f877d300a546ff6a4e8dd1c" +Content-Length: 743 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:C1="http://calendarserver.org/ns/"> + <response> + <href>/caldav.php/user1/</href> + <propstat> + <prop> + <displayname>User 1</displayname> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + <propstat> + <prop> + <C:schedule-inbox-url/> + <C:schedule-outbox-url/> + <C1:dropbox-home-url/> + <C1:notifications-url/> + </prop> + <status>HTTP/1.1 404 Not Found</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/501-iCal-PROPFIND.test b/testing/tests/regression-suite/501-iCal-PROPFIND.test new file mode 100644 index 00000000..761dadea --- /dev/null +++ b/testing/tests/regression-suite/501-iCal-PROPFIND.test @@ -0,0 +1,31 @@ +# +# Testing with a process similar to iCal 3 (preferably 3.0.1+) +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/ +HEAD + +HEADER=User-Agent: DAVKit/2.0 (10.5; wrbt) iCal 3.0 +HEADER=Content-Type: text/xml +HEADER=Depth: 0 + +# +# This query from iCal seems to discover several things. Firstly they +# get the calendar-home-set URL for this path. Secondly, they ascertain +# whether the calendar supports scheduling, and finally, whether it +# handles some Apple-specific extensions. +# +BEGINDATA +<?xml version="1.0" encoding="utf-8"?> +<x0:propfind xmlns:x2="http://calendarserver.org/ns/" xmlns:x1="urn:ietf:params:xml:ns:caldav" xmlns:x0="DAV:"> + <x0:prop> + <x1:calendar-home-set/> + <x1:calendar-user-address-set/> + <x1:schedule-inbox-URL/> + <x1:schedule-outbox-URL/> + <x2:dropbox-home-URL/> + <x2:notifications-URL/> + <x0:displayname/> + </x0:prop> +</x0:propfind> +ENDDATA From 5b4071f8e408ce186e6e713360f7147cdc1d60c6 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 27 Nov 2007 18:07:18 +1300 Subject: [PATCH 177/189] Added a version of patch 1.1.11 which works for PostgreSQL 8.x --- dba/patches/1.1.11a.sql | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 dba/patches/1.1.11a.sql diff --git a/dba/patches/1.1.11a.sql b/dba/patches/1.1.11a.sql new file mode 100644 index 00000000..55c6f52e --- /dev/null +++ b/dba/patches/1.1.11a.sql @@ -0,0 +1,17 @@ + +-- Sort out accessing calendar entries. +-- This patch file is the same in/out revision as 1.1.11 but it works with newer databases (8.x) + +BEGIN; +SELECT check_db_revision(1,1,10); + +ALTER TABLE caldav_data DROP CONSTRAINT "caldav_data_user_no_fkey"; +ALTER TABLE caldav_data ADD CONSTRAINT "caldav_data_user_no_fkey" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; + +ALTER TABLE collection DROP CONSTRAINT "collection_user_no_fkey"; +ALTER TABLE collection ADD CONSTRAINT "collection_user_no_fkey" FOREIGN KEY (user_no) REFERENCES usr(user_no) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; + +SELECT new_db_revision(1,1,11, 'November' ); +COMMIT; +ROLLBACK; + From 2031ba23a33ebb3b562e868d0fc67a1a6fef224e Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Wed, 28 Nov 2007 23:08:26 +1300 Subject: [PATCH 178/189] Patch to apply a numeric primary key to caldav_data / calendar_item in order to attempt to resolve performance issues in non-POSIX collation. --- dba/patches/1.1.12.sql | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 dba/patches/1.1.12.sql diff --git a/dba/patches/1.1.12.sql b/dba/patches/1.1.12.sql new file mode 100644 index 00000000..1995be0d --- /dev/null +++ b/dba/patches/1.1.12.sql @@ -0,0 +1,68 @@ + +-- Add a numeric primary key link between caldav_data and calendar_item to +-- provide more efficient linking when the db has been initialised with a +-- non POSIX collation. + + +BEGIN; +SELECT check_db_revision(1,1,11); + +-- Add a column to the collection table to allow us to mark collections +-- as publicly readable +ALTER TABLE collection ADD COLUMN publicly_readable BOOLEAN DEFAULT FALSE; + +-- Add a numeric dav_id to link the caldav_data and calendar_item tables +ALTER TABLE caldav_data ADD COLUMN dav_id INT8; +ALTER TABLE calendar_item ADD COLUMN dav_id INT8; +CREATE SEQUENCE caldav_data_dav_id_seq; + +CREATE or REPLACE FUNCTION sync_dav_id ( ) RETURNS TRIGGER AS ' + DECLARE + BEGIN + + IF TG_OP = ''DELETE'' THEN + -- Just let the ON DELETE CASCADE handle this case + RETURN OLD; + END IF; + + IF NEW.dav_id IS NULL THEN + NEW.dav_id = nextval(''caldav_data_dav_id_seq''); + END IF; + + IF OLD.dav_id = NEW.dav_id THEN + -- Nothing to do + RETURN NEW; + END IF; + + IF TG_RELNAME = ''caldav_data'' THEN + UPDATE calendar_item SET dav_id = NEW.dav_id WHERE user_no = NEW.user_no AND dav_name = NEW.dav_name; + ELSE + UPDATE caldav_data SET dav_id = NEW.dav_id WHERE user_no = NEW.user_no AND dav_name = NEW.dav_name; + END IF; + + RETURN NEW; + + END +' LANGUAGE 'plpgsql'; + +CREATE TRIGGER caldav_data_sync_dav_id AFTER INSERT OR UPDATE ON caldav_data + FOR EACH ROW EXECUTE PROCEDURE sync_dav_id(); + +CREATE TRIGGER calendar_item_sync_dav_id AFTER INSERT OR UPDATE ON calendar_item + FOR EACH ROW EXECUTE PROCEDURE sync_dav_id(); + +-- Now, using the trigger, magically assign dav_id to all rows in caldav_data and calendar_item +UPDATE caldav_data SET dav_id = dav_id; + +-- Finally, what we are really after, create the foreign key constraints +ALTER TABLE caldav_data DROP CONSTRAINT caldav_data_pkey CASCADE; +ALTER TABLE caldav_data ADD PRIMARY KEY ( dav_id ); +ALTER TABLE calendar_item DROP CONSTRAINT calendar_item_pkey CASCADE; +ALTER TABLE calendar_item ADD PRIMARY KEY ( dav_id ); +ALTER TABLE calendar_item ADD CONSTRAINT "calendar_item_dav_id_fkey" FOREIGN KEY (dav_id) REFERENCES caldav_data(dav_id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; + +SELECT new_db_revision(1,1,12, 'December' ); + +COMMIT; +ROLLBACK; + From 91f1d2324c3aca88432689deeacbe46d6d23c4df Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Mon, 3 Dec 2007 22:28:44 +1300 Subject: [PATCH 179/189] Enhance the database patch script to allow for alternative patches. --- dba/update-rscds-database | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/dba/update-rscds-database b/dba/update-rscds-database index ee192ca6..ec73cd78 100755 --- a/dba/update-rscds-database +++ b/dba/update-rscds-database @@ -12,7 +12,7 @@ use Getopt::Long qw(:config permute); # allow mixed args. # Options variables my $debug = 0; -my $dbname = "rscds"; +my $dbname = "davical"; my $dbport = 5432; my $dbuser = ""; my $dbpass = ""; @@ -46,10 +46,10 @@ my $current_revision = get_current_revision(); printf( "The database is currently at revision %d.%d.%d.\n", $current_revision->{'schema_major'}, $current_revision->{'schema_minor'}, $current_revision->{'schema_patch'} ); opendir( PATCHDIR, $patchdir ) or die "Can't open patch directory $patchdir"; -my @patches = grep { /^([0-9]+)\.([0-9]+)\.([0-9]+)\.sql$/ } readdir(PATCHDIR); +my @patches = grep { /^([0-9]+)\.([0-9]+)\.([0-9]+)([a-z]?)\.sql$/ } readdir(PATCHDIR); closedir(PATCHDIR); -@patches = sort { compare_revisions(revision_hash($a),revision_hash($b)); } @patches; +@patches = sort { compare_revisions(revision_hash($a),revision_hash($b), 1); } @patches; my $applied = 0; @@ -57,7 +57,14 @@ for ( my $i=0; $i <= $#patches; $i++ ) { printf( "Looking at patches[%d] (%s)\n", $i, $patches[$i]) if ( $debug ); if ( compare_revisions(revision_hash($patches[$i]),$current_revision) > 0 ) { print "Applying patch $patches[$i]\n"; - last unless( apply_patch( $patches[$i] ) ); + if ( !apply_patch( $patches[$i] ) ) { + # Skip to the end unless the next patch is an alternate for the same version. + last unless ( compare_revisions(revision_hash($patches[$i]),revision_hash($patches[$i+1])) == 0 ); + print "Patch failed, but alternatives exist. Attempting next alternative.\n"; + } + else { + print "Patch succeeded.\n"; + } $applied++; } else { @@ -91,17 +98,20 @@ exit 0; # which is of the form "1.2.3" or we have three parameters. ############################################################ sub revision_hash { - my $rev = +{}; + my $rev = +{ 'schema_major', => 0, 'schema_minor' => 0, 'schema_patch' => 0, 'alternative' => '0' }; my $first = shift; - if ( $first =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)([^0-9]|$)/ ) { + return $rev unless ( defined($first) ); + if ( $first =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)([a-z]?)([^0-9]|$)/ ) { $rev->{'schema_major'} = $1; $rev->{'schema_minor'} = $2; $rev->{'schema_patch'} = $3; + $rev->{'alternative'} = $4; } else { $rev->{'schema_major'} = $first; $rev->{'schema_minor'} = shift; $rev->{'schema_patch'} = shift; + $rev->{'alternative'} = '0'; } return $rev; } @@ -113,6 +123,7 @@ sub revision_hash { sub compare_revisions { my $a = shift; my $b = shift; + my $test_alt = shift; return -1 if ( $a->{'schema_major'} < $b->{'schema_major'} ); return 1 if ( $a->{'schema_major'} > $b->{'schema_major'} ); @@ -123,6 +134,11 @@ sub compare_revisions { return -1 if ( $a->{'schema_patch'} < $b->{'schema_patch'} ); return 1 if ( $a->{'schema_patch'} > $b->{'schema_patch'} ); + if ( defined($test_alt) ) { + return -1 if ( $a->{'alternative'} lt $b->{'alternative'} ); + return 1 if ( $a->{'alternative'} gt $b->{'alternative'} ); + } + return 0; } From c2115a22d8f44ff2bcd84401ab1557125f76a624 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 4 Dec 2007 08:46:47 +1300 Subject: [PATCH 180/189] Minimise output on patch failure where alternatives exist. --- dba/update-rscds-database | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/dba/update-rscds-database b/dba/update-rscds-database index ec73cd78..1ab046a3 100755 --- a/dba/update-rscds-database +++ b/dba/update-rscds-database @@ -12,7 +12,7 @@ use Getopt::Long qw(:config permute); # allow mixed args. # Options variables my $debug = 0; -my $dbname = "davical"; +my $dbname = "rscds"; my $dbport = 5432; my $dbuser = ""; my $dbpass = ""; @@ -52,18 +52,24 @@ closedir(PATCHDIR); @patches = sort { compare_revisions(revision_hash($a),revision_hash($b), 1); } @patches; my $applied = 0; +my $last_results = ''; # Will hold the last SQL result from applying a patch for ( my $i=0; $i <= $#patches; $i++ ) { printf( "Looking at patches[%d] (%s)\n", $i, $patches[$i]) if ( $debug ); if ( compare_revisions(revision_hash($patches[$i]),$current_revision) > 0 ) { - print "Applying patch $patches[$i]\n"; + print "Applying patch $patches[$i] ... "; if ( !apply_patch( $patches[$i] ) ) { # Skip to the end unless the next patch is an alternate for the same version. - last unless ( compare_revisions(revision_hash($patches[$i]),revision_hash($patches[$i+1])) == 0 ); - print "Patch failed, but alternatives exist. Attempting next alternative.\n"; + if ( defined($patches[$i+1]) && compare_revisions(revision_hash($patches[$i]),revision_hash($patches[$i+1])) == 0 ) { + print "failed. Attempting next alternative.\n"; + $applied--; + } + else { + print "failed!\n$last_results \n ==> No further patches will be attempted!\n"; + } } else { - print "Patch succeeded.\n"; + print "succeeded.\n"; } $applied++; } @@ -181,7 +187,7 @@ sub apply_patch { $current_revision = get_current_revision(); if ( compare_revisions($current_revision,revision_hash($patch)) != 0 ) { - printf( "Failed to apply revision %s to the database!\n", $patch ); + printf( "Failed to apply revision %s to the database!\n", $patch ) if ( $debug ); return 0; } return 1; # Success @@ -204,11 +210,10 @@ sub apply_sql_file { $ENV{'PGPASS'} = $dbpass if ( $dbpass ne "" ); my $command = join ' ', @psql_opts; - my $results = `$command 2>&1 1>/dev/null`; + $last_results = `$command 2>&1 1>/dev/null`; - $results =~ s/^.*WARNING: there is no transaction in progress\s$//m; - - print $results; + $last_results =~ s/^.*WARNING: there is no transaction in progress\s$//m; + $last_results =~ s/^.*NOTICE: //m; } From 6658b923391776b7e0bc5a6b2e94cc6312477af7 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 4 Dec 2007 12:13:49 +1300 Subject: [PATCH 181/189] Changes to regression testing from reviewing current Mozilla 0.7 operation. --- .../regression-suite/232-Moz-PROPFIND.result | 22 ++++++ .../regression-suite/232-Moz-PROPFIND.test | 18 +++++ .../tests/regression-suite/233-Moz-PUT.result | 10 +++ .../tests/regression-suite/233-Moz-PUT.test | 69 +++++++++++++++++++ .../tests/regression-suite/234-Moz-PUT.result | 8 +++ .../tests/regression-suite/234-Moz-PUT.test | 67 ++++++++++++++++++ .../regression-suite/235-Moz-REPORT.result | 61 ++++++++++++++++ .../regression-suite/235-Moz-REPORT.test | 30 ++++++++ .../regression-suite/236-Moz-REPORT.result | 59 ++++++++++++++++ .../regression-suite/236-Moz-REPORT.test | 30 ++++++++ .../309-Chandler-PROPFIND-4.result | 26 ++++++- .../401-Cadaver-PROPFIND-1.result | 2 +- .../regression-suite/504-iCal-PROPFIND.result | 24 ++++++- .../regression-suite/602-Soho-PROPFIND.result | 32 ++++++++- .../820-Spec-PROPFIND-1.result | 2 +- .../821-Spec-PROPFIND-2.result | 2 +- .../822-Spec-PROPFIND-3.result | 54 ++++++++++++++- .../824-Spec-PROPFIND-5.result | 2 +- .../regression-suite/900-Moz-REPORT.result | 54 ++++++++++++++- .../901-GET-Collection.result | 38 +++++++++- 20 files changed, 596 insertions(+), 14 deletions(-) create mode 100644 testing/tests/regression-suite/232-Moz-PROPFIND.result create mode 100644 testing/tests/regression-suite/232-Moz-PROPFIND.test create mode 100644 testing/tests/regression-suite/233-Moz-PUT.result create mode 100644 testing/tests/regression-suite/233-Moz-PUT.test create mode 100644 testing/tests/regression-suite/234-Moz-PUT.result create mode 100644 testing/tests/regression-suite/234-Moz-PUT.test create mode 100644 testing/tests/regression-suite/235-Moz-REPORT.result create mode 100644 testing/tests/regression-suite/235-Moz-REPORT.test create mode 100644 testing/tests/regression-suite/236-Moz-REPORT.result create mode 100644 testing/tests/regression-suite/236-Moz-REPORT.test diff --git a/testing/tests/regression-suite/232-Moz-PROPFIND.result b/testing/tests/regression-suite/232-Moz-PROPFIND.result new file mode 100644 index 00000000..61354633 --- /dev/null +++ b/testing/tests/regression-suite/232-Moz-PROPFIND.result @@ -0,0 +1,22 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "334c8abc0ac73261cdbf963fc7269d76" +Content-Length: 347 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> + <response> + <href>/caldav.php/user1/home/</href> + <propstat> + <prop> + <resourcetype> + <collection/> + <C:calendar/> + </resourcetype> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/232-Moz-PROPFIND.test b/testing/tests/regression-suite/232-Moz-PROPFIND.test new file mode 100644 index 00000000..9c88891d --- /dev/null +++ b/testing/tests/regression-suite/232-Moz-PROPFIND.test @@ -0,0 +1,18 @@ +# +# Testing with a process similar to Mozilla Sunbird 0.7 +# +TYPE=PROPFIND +URL=http://mycaldav/caldav.php/user1/home/ +HEAD + +HEADER=User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8pre) Gecko/20071023 Sunbird/0.7 +HEADER=Content-Type: text/xml; charset=utf-8 +HEADER=Depth: 0 + +# +# The first query just gets the resourcetype +# +BEGINDATA +<?xml version="1.0"?> +<D:propfind xmlns:D="DAV:"><D:prop><D:resourcetype/></D:prop></D:propfind> +ENDDATA diff --git a/testing/tests/regression-suite/233-Moz-PUT.result b/testing/tests/regression-suite/233-Moz-PUT.result new file mode 100644 index 00000000..f96231e5 --- /dev/null +++ b/testing/tests/regression-suite/233-Moz-PUT.result @@ -0,0 +1,10 @@ +HTTP/1.1 100 Continue + +HTTP/1.1 201 Created +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "e8060931f30c1798ac58ffbe4ec0bffc" +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +10 --- e8060931f30c1798ac58ffbe4ec0bffc --- VEVENT --- 10 --- e70576e9-c1e0-431e-a507-0386fd82f223 --- 2007-12-03 20:26:30 --- 2007-12-11 07:45:00+13 --- 2007-12-11 08:30:00+13 --- NULL --- Morning Meeting --- Suzies Coffee Lounge --- Twice-weekly breakfast meeting --- NULL --- PUBLIC --- NULL --- FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH --- NULL --- NULL --- NULL --- NULL diff --git a/testing/tests/regression-suite/233-Moz-PUT.test b/testing/tests/regression-suite/233-Moz-PUT.test new file mode 100644 index 00000000..4b983a04 --- /dev/null +++ b/testing/tests/regression-suite/233-Moz-PUT.test @@ -0,0 +1,69 @@ +# +# PUT a Mozilla style event into the database +# +TYPE=PUT +URL=http://mycaldav/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics +HEADER=User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8pre) Gecko/20071023 Sunbird/0.7 +HEADER=Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 +HEADER=Accept-Language: en-us,en;q=0.5 +HEADER=Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 +HEADER=Content-Type: text/calendar; charset=utf-8 + +HEAD + + +BEGINDATA +BEGIN:VCALENDAR +PRODID:-//Mozilla Calendar//NONSGML Sunbird//EN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:/mozilla.org/20070129_1/Antarctica/McMurdo +X-LIC-LOCATION:Antarctica/McMurdo +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 +BEGIN:VEVENT +CREATED:20071203T202630Z +LAST-MODIFIED:20071203T202834Z +DTSTAMP:20071203T202630Z +UID:e70576e9-c1e0-431e-a507-0386fd82f223 +SUMMARY:Morning Meeting +RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH +DTSTART;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071211T074500 +DTEND;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071211T083000 +X-MOZ-LOCATIONPATH:e70576e9-c1e0-431e-a507-0386fd82f223.ics +LOCATION:Suzies Coffee Lounge +DESCRIPTION:Twice-weekly breakfast meeting +CATEGORIES:Business +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-PT10M +DESCRIPTION:Mozilla Alarm: Morning Meeting +ACTION:DISPLAY +END:VALARM +END:VEVENT +END:VCALENDAR +ENDDATA + + +QUERY +SELECT caldav_data.user_no, caldav_data.dav_etag, caldav_type, logged_user, + uid, dtstamp, dtstart, dtend, due, summary, location, + description, priority, class, transp, rrule, url, + percent_complete, tz_id, status +FROM caldav_data JOIN calendar_item USING(dav_name) +WHERE caldav_data.dav_name = +'/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics'; +ENDQUERY + diff --git a/testing/tests/regression-suite/234-Moz-PUT.result b/testing/tests/regression-suite/234-Moz-PUT.result new file mode 100644 index 00000000..6f1061c4 --- /dev/null +++ b/testing/tests/regression-suite/234-Moz-PUT.result @@ -0,0 +1,8 @@ +HTTP/1.1 201 Created +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "8f581a053df6d833254756dfd7553d37" +Content-Length: 0 +Content-Type: text/plain; charset="utf-8" + +10 --- 8f581a053df6d833254756dfd7553d37 --- VTODO --- 10 --- e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08 --- 2007-12-03 20:29:15 --- 2007-12-09 13:30:00+13 --- NULL --- 2007-12-09 13:30:00+13 --- Release 0.9.3 --- NULL --- NULL --- NULL --- PUBLIC --- NULL --- NULL --- NULL --- 95.00 --- NULL --- IN-PROCESS diff --git a/testing/tests/regression-suite/234-Moz-PUT.test b/testing/tests/regression-suite/234-Moz-PUT.test new file mode 100644 index 00000000..919cfa19 --- /dev/null +++ b/testing/tests/regression-suite/234-Moz-PUT.test @@ -0,0 +1,67 @@ +# +# PUT a Mozilla style event into the database +# +TYPE=PUT +URL=http://mycaldav/caldav.php/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics +HEADER=User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8pre) Gecko/20071023 Sunbird/0.7 +HEADER=Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 +HEADER=Accept-Language: en-us,en;q=0.5 +HEADER=Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 +HEADER=Content-Type: text/calendar; charset=utf-8 + +HEAD + + +BEGINDATA +BEGIN:VCALENDAR +PRODID:-//Mozilla Calendar//NONSGML Sunbird//EN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:/mozilla.org/20070129_1/Antarctica/McMurdo +X-LIC-LOCATION:Antarctica/McMurdo +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 +BEGIN:VTODO +CREATED:20071203T202915Z +LAST-MODIFIED:20071203T203021Z +DTSTAMP:20071203T202915Z +UID:e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08 +SUMMARY:Release 0.9.3 +STATUS:IN-PROCESS +DTSTART;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071209T133000 +DUE;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071209T133000 +PERCENT-COMPLETE:95 +X-MOZ-LOCATIONPATH:e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-P2D +DESCRIPTION:Mozilla Alarm: Release 0.9.3 +ACTION:DISPLAY +END:VALARM +END:VTODO +END:VCALENDAR +ENDDATA + + +QUERY +SELECT caldav_data.user_no, caldav_data.dav_etag, caldav_type, logged_user, + uid, dtstamp, dtstart, dtend, due, summary, location, + description, priority, class, transp, rrule, url, + percent_complete, tz_id, status +FROM caldav_data JOIN calendar_item USING(dav_name) +WHERE caldav_data.dav_name = +'/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics'; +ENDQUERY + diff --git a/testing/tests/regression-suite/235-Moz-REPORT.result b/testing/tests/regression-suite/235-Moz-REPORT.result new file mode 100644 index 00000000..e0531007 --- /dev/null +++ b/testing/tests/regression-suite/235-Moz-REPORT.result @@ -0,0 +1,61 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "c4532eec08793ee4b4f24deb4588f9be" +Content-Length: 1521 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:"> + <response> + <href>/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics</href> + <propstat> + <prop> + <getetag>"e8060931f30c1798ac58ffbe4ec0bffc"</getetag> + <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR +PRODID:-//Mozilla Calendar//NONSGML Sunbird//EN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:/mozilla.org/20070129_1/Antarctica/McMurdo +X-LIC-LOCATION:Antarctica/McMurdo +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 +BEGIN:VEVENT +CREATED:20071203T202630Z +LAST-MODIFIED:20071203T202834Z +DTSTAMP:20071203T202630Z +UID:e70576e9-c1e0-431e-a507-0386fd82f223 +SUMMARY:Morning Meeting +RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH +DTSTART;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071211T074500 +DTEND;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071211T083000 +X-MOZ-LOCATIONPATH:e70576e9-c1e0-431e-a507-0386fd82f223.ics +LOCATION:Suzies Coffee Lounge +DESCRIPTION:Twice-weekly breakfast meeting +CATEGORIES:Business +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-PT10M +DESCRIPTION:Mozilla Alarm: Morning Meeting +ACTION:DISPLAY +END:VALARM +END:VEVENT +END:VCALENDAR +</calendar-data> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/235-Moz-REPORT.test b/testing/tests/regression-suite/235-Moz-REPORT.test new file mode 100644 index 00000000..5add10f5 --- /dev/null +++ b/testing/tests/regression-suite/235-Moz-REPORT.test @@ -0,0 +1,30 @@ +# +# Check for REPORT calendar-query of VEVENT within time range +# +TYPE=REPORT +URL=http://mycaldav/caldav.php/user1/home/ +HEADER=User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8pre) Gecko/20071023 Sunbird/0.7 +HEADER=Accept: text/xml +HEADER=Accept-Language: en-us,en;q=0.5 +HEADER=Accept-Encoding: gzip,deflate +HEADER=Accept-Charset: utf-8,*;q=0.1 +HEADER=Content-Type: text/xml; charset=utf-8 +HEADER=Depth: 1 +HEAD + +BEGINDATA +<?xml version="1.0" encoding="UTF-8"?> +<calendar-query xmlns:D="DAV:" xmlns="urn:ietf:params:xml:ns:caldav"> + <D:prop> + <D:getetag/> + <calendar-data/> + </D:prop> + <filter> + <comp-filter name="VCALENDAR"> + <comp-filter name="VEVENT"> + <time-range start="20071101T110000Z" end="20080104T110000Z"/> + </comp-filter> + </comp-filter> + </filter> +</calendar-query> +ENDDATA diff --git a/testing/tests/regression-suite/236-Moz-REPORT.result b/testing/tests/regression-suite/236-Moz-REPORT.result new file mode 100644 index 00000000..7dbe1231 --- /dev/null +++ b/testing/tests/regression-suite/236-Moz-REPORT.result @@ -0,0 +1,59 @@ +HTTP/1.1 207 Multi-Status +Date: Dow, 01 Jan 2000 00:00:00 GMT +DAV: 1, 2, access-control, calendar-access +ETag: "55e79b5b5836290d5b3344ef8a16d10b" +Content-Length: 1415 +Content-Type: text/xml; charset="utf-8" + +<?xml version="1.0" encoding="utf-8" ?> +<multistatus xmlns="DAV:"> + <response> + <href>/caldav.php/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics</href> + <propstat> + <prop> + <getetag>"8f581a053df6d833254756dfd7553d37"</getetag> + <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR +PRODID:-//Mozilla Calendar//NONSGML Sunbird//EN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:/mozilla.org/20070129_1/Antarctica/McMurdo +X-LIC-LOCATION:Antarctica/McMurdo +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 +BEGIN:VTODO +CREATED:20071203T202915Z +LAST-MODIFIED:20071203T203021Z +DTSTAMP:20071203T202915Z +UID:e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08 +SUMMARY:Release 0.9.3 +STATUS:IN-PROCESS +DTSTART;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071209T133000 +DUE;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071209T133000 +PERCENT-COMPLETE:95 +X-MOZ-LOCATIONPATH:e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-P2D +DESCRIPTION:Mozilla Alarm: Release 0.9.3 +ACTION:DISPLAY +END:VALARM +END:VTODO +END:VCALENDAR +</calendar-data> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> +</multistatus> diff --git a/testing/tests/regression-suite/236-Moz-REPORT.test b/testing/tests/regression-suite/236-Moz-REPORT.test new file mode 100644 index 00000000..5b1a6a8b --- /dev/null +++ b/testing/tests/regression-suite/236-Moz-REPORT.test @@ -0,0 +1,30 @@ +# +# Check for REPORT calendar-query of VTODO within time range +# +TYPE=REPORT +URL=http://mycaldav/caldav.php/user1/home/ +HEADER=User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8pre) Gecko/20071023 Sunbird/0.7 +HEADER=Accept: text/xml +HEADER=Accept-Language: en-us,en;q=0.5 +HEADER=Accept-Encoding: gzip,deflate +HEADER=Accept-Charset: utf-8,*;q=0.1 +HEADER=Content-Type: text/xml; charset=utf-8 +HEADER=Depth: 1 +HEAD + +BEGINDATA +<?xml version="1.0" encoding="UTF-8"?> +<calendar-query xmlns:D="DAV:" xmlns="urn:ietf:params:xml:ns:caldav"> + <D:prop> + <D:getetag/> + <calendar-data/> + </D:prop> + <filter> + <comp-filter name="VCALENDAR"> + <comp-filter name="VTODO"> + <time-range start="20071101T110000Z" end="20080104T110000Z"/> + </comp-filter> + </comp-filter> + </filter> +</calendar-query> +ENDDATA diff --git a/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result b/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result index c4513138..4cfe0a50 100644 --- a/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result +++ b/testing/tests/regression-suite/309-Chandler-PROPFIND-4.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "f678e2f00e4582d963162b293e1e8ecb" -Content-Length: 3609 +ETag: "307a9592c8e442356bbeb566b87f3de1" +Content-Length: 4233 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -120,6 +120,28 @@ Content-Type: text/xml; charset="utf-8" <status>HTTP/1.1 200 OK</status> </propstat> </response> + <response> + <href>/caldav.php/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics</href> + <propstat> + <prop> + <resourcetype/> + <displayname>Release 0.9.3</displayname> + <getetag>"8f581a053df6d833254756dfd7553d37"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics</href> + <propstat> + <prop> + <resourcetype/> + <displayname>Morning Meeting</displayname> + <getetag>"e8060931f30c1798ac58ffbe4ec0bffc"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> <response> <href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href> <propstat> diff --git a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result index 35a07746..a36eab0a 100644 --- a/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result +++ b/testing/tests/regression-suite/401-Cadaver-PROPFIND-1.result @@ -5,7 +5,7 @@ <propstat> <prop> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>9531</getcontentlength> + <getcontentlength>11663</getcontentlength> <resourcetype> <collection/> <C:calendar/> diff --git a/testing/tests/regression-suite/504-iCal-PROPFIND.result b/testing/tests/regression-suite/504-iCal-PROPFIND.result index 79aaf950..9da477a3 100644 --- a/testing/tests/regression-suite/504-iCal-PROPFIND.result +++ b/testing/tests/regression-suite/504-iCal-PROPFIND.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "47e34444ff36653135bc516cd861b019" -Content-Length: 3575 +ETag: "c6c4b54709e3dac67c5c7dd1d8bf30ea" +Content-Length: 4107 Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -130,6 +130,26 @@ Content-Type: text/xml; charset="utf-8" <status>HTTP/1.1 200 OK</status> </propstat> </response> + <response> + <href>/caldav.php/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"8f581a053df6d833254756dfd7553d37"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics</href> + <propstat> + <prop> + <resourcetype/> + <getetag>"e8060931f30c1798ac58ffbe4ec0bffc"</getetag> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> <response> <href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href> <propstat> diff --git a/testing/tests/regression-suite/602-Soho-PROPFIND.result b/testing/tests/regression-suite/602-Soho-PROPFIND.result index 76a93114..05ed9f72 100644 --- a/testing/tests/regression-suite/602-Soho-PROPFIND.result +++ b/testing/tests/regression-suite/602-Soho-PROPFIND.result @@ -1,8 +1,8 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "a8b240ec9481626730de7fffbc8cc5f8" -Content-Length: 7461 +ETag: "9cd5b2172bdaa7cc59b004100c6fea86" +Transfer-Encoding: chunked Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -217,6 +217,34 @@ Content-Type: text/xml; charset="utf-8" <status>HTTP/1.1 200 OK</status> </propstat> </response> + <response> + <href>/caldav.php/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics</href> + <propstat> + <prop> + <C:calendar-home-set> + <href>/caldav.php/user1/</href> + </C:calendar-home-set> + <C:calendar-user-address-set> + <href>/caldav.php/user1/</href> + </C:calendar-user-address-set> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> <response> <href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href> <propstat> diff --git a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result index 7c8ff01a..3aae92d9 100644 --- a/testing/tests/regression-suite/820-Spec-PROPFIND-1.result +++ b/testing/tests/regression-suite/820-Spec-PROPFIND-1.result @@ -6,7 +6,7 @@ <prop> <getcontenttype>httpd/unix-directory</getcontenttype> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>10512</getcontentlength> + <getcontentlength>12644</getcontentlength> <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> <resourcetype> <collection/> diff --git a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result index 64403a0c..ddf9bea7 100644 --- a/testing/tests/regression-suite/821-Spec-PROPFIND-2.result +++ b/testing/tests/regression-suite/821-Spec-PROPFIND-2.result @@ -13,7 +13,7 @@ Content-Type: text/xml; charset="utf-8" <prop> <getcontenttype>httpd/unix-directory</getcontenttype> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>10512</getcontentlength> + <getcontentlength>12644</getcontentlength> <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> <resourcetype> <collection/> diff --git a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result index 92c56d24..cbe7811e 100644 --- a/testing/tests/regression-suite/822-Spec-PROPFIND-3.result +++ b/testing/tests/regression-suite/822-Spec-PROPFIND-3.result @@ -6,7 +6,7 @@ <prop> <getcontenttype>httpd/unix-directory</getcontenttype> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>10512</getcontentlength> + <getcontentlength>12644</getcontentlength> <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> <resourcetype> <collection/> @@ -350,6 +350,58 @@ <status>HTTP/1.1 200 OK</status> </propstat> </response> + <response> + <href>/caldav.php/user1/home/e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics</href> + <propstat> + <prop> + <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> + <getcontentlength>1013</getcontentlength> + <getcontenttype>text/calendar</getcontenttype> + <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> + <resourcetype/> + <displayname>Release 0.9.3</displayname> + <getetag>"8f581a053df6d833254756dfd7553d37"</getetag> + <getcontentlanguage>en_NZ.UTF-8</getcontentlanguage> + <supportedlock> + <lockentry> + <lockscope> + <exclusive/> + </lockscope> + <locktype> + <write/> + </locktype> + </lockentry> + </supportedlock> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics</href> + <propstat> + <prop> + <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> + <getcontentlength>1119</getcontentlength> + <getcontenttype>text/calendar</getcontenttype> + <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> + <resourcetype/> + <displayname>Morning Meeting</displayname> + <getetag>"e8060931f30c1798ac58ffbe4ec0bffc"</getetag> + <getcontentlanguage>en_NZ.UTF-8</getcontentlanguage> + <supportedlock> + <lockentry> + <lockscope> + <exclusive/> + </lockscope> + <locktype> + <write/> + </locktype> + </lockentry> + </supportedlock> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> <response> <href>/caldav.php/user1/home/fbd57454-d966-4a14-8341-abe1edb1ae66.ics</href> <propstat> diff --git a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result index 9a033ee7..a623c299 100644 --- a/testing/tests/regression-suite/824-Spec-PROPFIND-5.result +++ b/testing/tests/regression-suite/824-Spec-PROPFIND-5.result @@ -14,7 +14,7 @@ </C:supported-calendar-component-set> <getcontenttype>httpd/unix-directory</getcontenttype> <getlastmodified>Dow, 01 Jan 2000 00:00:00 GMT</getlastmodified> - <getcontentlength>10512</getcontentlength> + <getcontentlength>12644</getcontentlength> <creationdate>Dow, 01 Jan 2000 00:00:00 GMT</creationdate> <resourcetype> <collection/> diff --git a/testing/tests/regression-suite/900-Moz-REPORT.result b/testing/tests/regression-suite/900-Moz-REPORT.result index 3bb0dede..60c82457 100644 --- a/testing/tests/regression-suite/900-Moz-REPORT.result +++ b/testing/tests/regression-suite/900-Moz-REPORT.result @@ -1,10 +1,10 @@ HTTP/1.1 207 Multi-Status Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -ETag: "add7fd32d70e4f7378b7aff4cf4e32e1" -Content-Length: 7796 +ETag: "fea25d8795124283031b5cb5ecb29b04" Keep-Alive: timeout=15, max=100 Connection: Keep-Alive +Transfer-Encoding: chunked Content-Type: text/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> @@ -258,6 +258,56 @@ STATUS:CONFIRMED SUMMARY:Morning Mgmt Mtg END:VEVENT END:VCALENDAR +</calendar-data> + </prop> + <status>HTTP/1.1 200 OK</status> + </propstat> + </response> + <response> + <href>/caldav.php/user1/home/e70576e9-c1e0-431e-a507-0386fd82f223.ics</href> + <propstat> + <prop> + <calendar-data xmlns="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR +PRODID:-//Mozilla Calendar//NONSGML Sunbird//EN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:/mozilla.org/20070129_1/Antarctica/McMurdo +X-LIC-LOCATION:Antarctica/McMurdo +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 +BEGIN:VEVENT +CREATED:20071203T202630Z +LAST-MODIFIED:20071203T202834Z +DTSTAMP:20071203T202630Z +UID:e70576e9-c1e0-431e-a507-0386fd82f223 +SUMMARY:Morning Meeting +RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH +DTSTART;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071211T074500 +DTEND;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071211T083000 +X-MOZ-LOCATIONPATH:e70576e9-c1e0-431e-a507-0386fd82f223.ics +LOCATION:Suzies Coffee Lounge +DESCRIPTION:Twice-weekly breakfast meeting +CATEGORIES:Business +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-PT10M +DESCRIPTION:Mozilla Alarm: Morning Meeting +ACTION:DISPLAY +END:VALARM +END:VEVENT +END:VCALENDAR </calendar-data> </prop> <status>HTTP/1.1 200 OK</status> diff --git a/testing/tests/regression-suite/901-GET-Collection.result b/testing/tests/regression-suite/901-GET-Collection.result index d7d11678..408d4d2e 100644 --- a/testing/tests/regression-suite/901-GET-Collection.result +++ b/testing/tests/regression-suite/901-GET-Collection.result @@ -1,7 +1,7 @@ HTTP/1.1 200 OK Date: Dow, 01 Jan 2000 00:00:00 GMT DAV: 1, 2, access-control, calendar-access -Content-Length: 6340 +Content-Length: 7506 Content-Type: text/calendar BEGIN:VCALENDAR @@ -160,6 +160,42 @@ RRULE:FREQ=MONTHLY STATUS:CONFIRMED SUMMARY:Morning Mgmt Mtg END:VEVENT +BEGIN:VTODO +CREATED:20071203T202915Z +LAST-MODIFIED:20071203T203021Z +DTSTAMP:20071203T202915Z +UID:e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08 +SUMMARY:Release 0.9.3 +STATUS:IN-PROCESS +DTSTART;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071209T133000 +DUE;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071209T133000 +PERCENT-COMPLETE:95 +X-MOZ-LOCATIONPATH:e6eb5bc9-f7f9-4a0a-94e8-8e90eefc7d08.ics +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-P2D +DESCRIPTION:Mozilla Alarm: Release 0.9.3 +ACTION:DISPLAY +END:VALARM +END:VTODO +BEGIN:VEVENT +CREATED:20071203T202630Z +LAST-MODIFIED:20071203T202834Z +DTSTAMP:20071203T202630Z +UID:e70576e9-c1e0-431e-a507-0386fd82f223 +SUMMARY:Morning Meeting +RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH +DTSTART;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071211T074500 +DTEND;TZID=/mozilla.org/20070129_1/Antarctica/McMurdo:20071211T083000 +X-MOZ-LOCATIONPATH:e70576e9-c1e0-431e-a507-0386fd82f223.ics +LOCATION:Suzies Coffee Lounge +DESCRIPTION:Twice-weekly breakfast meeting +CATEGORIES:Business +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-PT10M +DESCRIPTION:Mozilla Alarm: Morning Meeting +ACTION:DISPLAY +END:VALARM +END:VEVENT BEGIN:VEVENT CREATED:20061223T051646Z LAST-MODIFIED:20061223T051713Z From 186734fea943d04c8eb2f30019915e49e2088db4 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 4 Dec 2007 12:16:17 +1300 Subject: [PATCH 182/189] Remove unnecessary newline. --- dba/update-rscds-database | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dba/update-rscds-database b/dba/update-rscds-database index 1ab046a3..d00cf691 100755 --- a/dba/update-rscds-database +++ b/dba/update-rscds-database @@ -65,7 +65,8 @@ for ( my $i=0; $i <= $#patches; $i++ ) { $applied--; } else { - print "failed!\n$last_results \n ==> No further patches will be attempted!\n"; + print "failed!\n$last_results ==> No further patches will be attempted!\n"; + last; } } else { From bdb1e60cd12dc3bd58943ea66b17a45efcf71be3 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 4 Dec 2007 12:16:52 +1300 Subject: [PATCH 183/189] Note that this is an alternate. --- dba/patches/1.1.11a.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dba/patches/1.1.11a.sql b/dba/patches/1.1.11a.sql index 55c6f52e..2f22a7d7 100644 --- a/dba/patches/1.1.11a.sql +++ b/dba/patches/1.1.11a.sql @@ -1,6 +1,6 @@ -- Sort out accessing calendar entries. --- This patch file is the same in/out revision as 1.1.11 but it works with newer databases (8.x) +-- This alternative patch file is the same in/out revision as 1.1.11 but it works with newer databases (8.x) BEGIN; SELECT check_db_revision(1,1,10); From bbca4ba75f5ff88d8288832589d7ab1159ffe5c7 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 4 Dec 2007 12:17:59 +1300 Subject: [PATCH 184/189] We'll need to let this settle for a version before we make it the primary key. Too many programming changes are needed to accept the risk of rolling it straight out. --- dba/patches/1.1.12.sql | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/dba/patches/1.1.12.sql b/dba/patches/1.1.12.sql index 1995be0d..ef37c884 100644 --- a/dba/patches/1.1.12.sql +++ b/dba/patches/1.1.12.sql @@ -1,5 +1,5 @@ --- Add a numeric primary key link between caldav_data and calendar_item to +-- Add a numeric foreign key link between caldav_data and calendar_item to -- provide more efficient linking when the db has been initialised with a -- non POSIX collation. @@ -15,6 +15,7 @@ ALTER TABLE collection ADD COLUMN publicly_readable BOOLEAN DEFAULT FALSE; ALTER TABLE caldav_data ADD COLUMN dav_id INT8; ALTER TABLE calendar_item ADD COLUMN dav_id INT8; CREATE SEQUENCE caldav_data_dav_id_seq; +GRANT SELECT,UPDATE ON caldav_data_dav_id_seq TO general; CREATE or REPLACE FUNCTION sync_dav_id ( ) RETURNS TRIGGER AS ' DECLARE @@ -29,9 +30,11 @@ CREATE or REPLACE FUNCTION sync_dav_id ( ) RETURNS TRIGGER AS ' NEW.dav_id = nextval(''caldav_data_dav_id_seq''); END IF; - IF OLD.dav_id = NEW.dav_id THEN - -- Nothing to do - RETURN NEW; + IF TG_OP = ''UPDATE'' THEN + IF OLD.dav_id = NEW.dav_id THEN + -- Nothing to do + RETURN NEW; + END IF; END IF; IF TG_RELNAME = ''caldav_data'' THEN @@ -54,12 +57,19 @@ CREATE TRIGGER calendar_item_sync_dav_id AFTER INSERT OR UPDATE ON calendar_item -- Now, using the trigger, magically assign dav_id to all rows in caldav_data and calendar_item UPDATE caldav_data SET dav_id = dav_id; +ALTER TABLE caldav_data ALTER COLUMN dav_id SET DEFAULT nextval('caldav_data_dav_id_seq'); +ALTER TABLE caldav_data ALTER COLUMN dav_id SET NOT NULL; +ALTER TABLE caldav_data ADD CONSTRAINT caldav_data_dav_id_key UNIQUE (dav_id); + +-- ALTER TABLE calendar_item ALTER COLUMN dav_id SET NOT NULL; +ALTER TABLE calendar_item ADD CONSTRAINT calendar_item_dav_id_key UNIQUE (dav_id); + -- Finally, what we are really after, create the foreign key constraints -ALTER TABLE caldav_data DROP CONSTRAINT caldav_data_pkey CASCADE; -ALTER TABLE caldav_data ADD PRIMARY KEY ( dav_id ); -ALTER TABLE calendar_item DROP CONSTRAINT calendar_item_pkey CASCADE; -ALTER TABLE calendar_item ADD PRIMARY KEY ( dav_id ); -ALTER TABLE calendar_item ADD CONSTRAINT "calendar_item_dav_id_fkey" FOREIGN KEY (dav_id) REFERENCES caldav_data(dav_id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; +-- ALTER TABLE caldav_data DROP CONSTRAINT caldav_data_pkey CASCADE; +-- ALTER TABLE caldav_data ADD PRIMARY KEY ( dav_id ); +-- ALTER TABLE calendar_item DROP CONSTRAINT calendar_item_pkey CASCADE; +-- ALTER TABLE calendar_item ADD PRIMARY KEY ( dav_id ); +-- ALTER TABLE calendar_item ADD CONSTRAINT "calendar_item_dav_id_fkey" FOREIGN KEY (dav_id) REFERENCES caldav_data(dav_id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; SELECT new_db_revision(1,1,12, 'December' ); From 193ada1ef54fd06ff636c09c0cf1773bb8f1735d Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 4 Dec 2007 12:19:05 +1300 Subject: [PATCH 185/189] Remove that commented code now it's in Git. --- dba/patches/1.1.12.sql | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dba/patches/1.1.12.sql b/dba/patches/1.1.12.sql index ef37c884..b50a6da1 100644 --- a/dba/patches/1.1.12.sql +++ b/dba/patches/1.1.12.sql @@ -61,16 +61,8 @@ ALTER TABLE caldav_data ALTER COLUMN dav_id SET DEFAULT nextval('caldav_data_dav ALTER TABLE caldav_data ALTER COLUMN dav_id SET NOT NULL; ALTER TABLE caldav_data ADD CONSTRAINT caldav_data_dav_id_key UNIQUE (dav_id); --- ALTER TABLE calendar_item ALTER COLUMN dav_id SET NOT NULL; ALTER TABLE calendar_item ADD CONSTRAINT calendar_item_dav_id_key UNIQUE (dav_id); --- Finally, what we are really after, create the foreign key constraints --- ALTER TABLE caldav_data DROP CONSTRAINT caldav_data_pkey CASCADE; --- ALTER TABLE caldav_data ADD PRIMARY KEY ( dav_id ); --- ALTER TABLE calendar_item DROP CONSTRAINT calendar_item_pkey CASCADE; --- ALTER TABLE calendar_item ADD PRIMARY KEY ( dav_id ); --- ALTER TABLE calendar_item ADD CONSTRAINT "calendar_item_dav_id_fkey" FOREIGN KEY (dav_id) REFERENCES caldav_data(dav_id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE; - SELECT new_db_revision(1,1,12, 'December' ); COMMIT; From 8568524fa304e101124245d1534ddd812af88985 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Tue, 4 Dec 2007 13:43:15 +1300 Subject: [PATCH 186/189] Quanta droppings. --- davical.webprj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/davical.webprj b/davical.webprj index 8eeed00d..2eec6308 100644 --- a/davical.webprj +++ b/davical.webprj @@ -246,5 +246,7 @@ <item url="inc/davical_configuration_missing.php" uploadstatus="1" /> <item url="dba/davical.sql" uploadstatus="1" /> <item url="inc/drivers_squid_pam.php" uploadstatus="1" /> + <item url="dba/patches/1.1.11a.sql" uploadstatus="1" /> + <item url="dba/patches/1.1.12.sql" uploadstatus="1" /> </project> </webproject> From cf7eaa11bcd946fe6f451ed19e3c9268b85adb8d Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Wed, 17 Oct 2007 10:17:14 +1300 Subject: [PATCH 187/189] Rename to DAViCal in the documentation. --- docs/website/administration.php | 8 ++-- docs/website/inc/page-header.php | 6 ++- docs/website/index.php | 3 +- docs/website/installation.php | 66 ++++++++++++++++++++------------ 4 files changed, 52 insertions(+), 31 deletions(-) diff --git a/docs/website/administration.php b/docs/website/administration.php index 4702f861..d9078546 100644 --- a/docs/website/administration.php +++ b/docs/website/administration.php @@ -98,14 +98,14 @@ P4 ==>> Administers Group ==> G </pre> -<h1>Configuring Calendar Clients for RSCDS</h1> -<p>The <a href="http://rscds.sourceforge.net/clients.php">RSCDS client setup page on sourceforge</a> has information on how +<h1>Configuring Calendar Clients for DAViCal</h1> +<p>The <a href="http://rscds.sourceforge.net/clients.php">DAViCal client setup page on sourceforge</a> has information on how to configure Evolution, Mozilla Calendar (Sunbird & Lightning) and Mulberry to use remotely hosted calendars.</p> <p>The administrative interface has no facility for viewing or modifying calendar data.</p> -<h1>Configuring RSCDS</h1> +<h1>Configuring DAViCal</h1> <p>If you can read this then things must be mostly working already.</p> -<p>The <a href="http://rscds.sourceforge.net/installation.php">RSCDS installation page</a> on sourceforge has +<p>The <a href="http://rscds.sourceforge.net/installation.php">DAViCal installation page</a> on sourceforge has some further information on how to install and configure this application.</p> diff --git a/docs/website/inc/page-header.php b/docs/website/inc/page-header.php index f2433937..6fa74c3b 100644 --- a/docs/website/inc/page-header.php +++ b/docs/website/inc/page-header.php @@ -17,10 +17,14 @@ if ( isset($title) ) { echo $title; } else { +<<<<<<< HEAD:docs/website/inc/page-header.php echo "DAViCal CalDAV Server"; +======= + echo "DAViCal"; +>>>>>>> Rename to DAViCal in the documentation.:docs/website/inc/page-header.php } ?></div> -<div id="subTitle">DAViCal CalDAV Server</div> +<div id="subTitle">A CalDAV Store</div> <div id="headerLinks"> <a href="index.php" class="hlink">Home</a> | <a href="installation.php" class="hlink">Installation</a> | diff --git a/docs/website/index.php b/docs/website/index.php index bbdae445..c4c6e1cc 100644 --- a/docs/website/index.php +++ b/docs/website/index.php @@ -56,7 +56,7 @@ works using the CalDAV protocol.</p> <ul> <li>Lorena Paoletti (Spanish)</li> <li>Cristina Radalescu (German)</li> -<li>Guillaume Rosquin (French)</li> +<li>Guillaume Rosquin & Maxime Delorme (French)</li> <li>Nick Khazov (Russian)</li> <li>Eelco Maljaars (Dutch)</li> </ul> @@ -69,7 +69,6 @@ works using the CalDAV protocol.</p> <h1>Your Name Here!</h1> <p>If you are interested in helping, there are several areas where I need help at the moment:</p> <i> -<li>The project needs a better name - feel free to suggest one!</li> <li>We need more documentation</li> <li>We need to find more CalDAV-capable calendar clients to interoperate with</li> <li>We would love you to write about your experiences in the project Wiki.</li> diff --git a/docs/website/installation.php b/docs/website/installation.php index e477f4e5..262a98c6 100644 --- a/docs/website/installation.php +++ b/docs/website/installation.php @@ -12,7 +12,7 @@ deb http://debian.mcmillan.net.nz/debian unstable awm </pre> <p>to your <code>/etc/apt/sources.list</code>. Once you have done that you can use <code>apt-get</code> or <code>synaptic</code> or some other equivalent package -manager to fetch and install <code>rscds</code> and all the dependencies.</p> +manager to fetch and install <code>DAViCal</code> and all the dependencies.</p> <p>This repository is signed by Andrew McMillan's public key, which you can install so that you don't get asked for confirmation all the time:</p> @@ -31,15 +31,15 @@ notes to pages somewhere under here: <h3>RPM Packages of DAViCal</h3> <p>We have created RPM packages of DAViCal and libawl-php from the .deb packages -using "alien". I don't know how well these work, so would appreciate feedback -about your success with them.</p> +using "alien". These are reported to work fine, so use them and then proceed to the +Pre-requisites section below.</p> <h3>SuSE Linux</h3> <p>On SuSE Linux you may need to look in /var/lib/pgsql/data/ for the pg_hba.conf file.</p> <h3>Gentoo, Slackware, BSD and the rest</h3> -<p>You will need to download the latest versions of the <code>rscds</code> and <code>awl</code> packages +<p>You will need to download the latest versions of the <code>DAViCal</code> and <code>awl</code> packages from the <a href="http://sourceforge.net/project/showfiles.php?group_id=179845">sourceforge download page for DAViCal</a>.</p> <p>You will need to untar these. Preferably you will untar them from within the "<code>/usr/share</code>" directory and everything will be in it's expected location (well, except the docs, but it will at least be tidy and everything will be in one place).</p> @@ -68,7 +68,7 @@ a number of years.</p> <p>The following other software is also needed:</p> <ul> <li>Apache: 1.3.x or 2.x.x</li> - <li>PHP: 5.0 or greater, PHP4 might work</li> + <li>PHP: 5.0 or greater</li> <li>PostgreSQL: 8.1 or greater</li> </ul> @@ -78,10 +78,11 @@ if you want to increase the security or scalability of your installation.</p> <p>Since the CalDAV store takes over a significant amount of path -hierarchy, it is designed to be installed in it's own virtual -host. However if you want it to operate within the web root of some +hierarchy, it can be easier in it's own virtual +host. If you want it to operate within the web root of some other application there are instructions on the Wiki about doing this, -and other fancy tricks such as URL rewriting to shorten the path.</p> +as well as other fancy tricks such as configuring URL rewriting in +order to shorten the path.</p> <h1>Database Setup</h1> @@ -124,7 +125,7 @@ have put them.</p> running as a user who has rights to create a new database, so you may need to do this as the "postgres" user, for example:</p> <pre> -su postgres -c /usr/share/rscds/dba/create-database.sh +su postgres -c /usr/share/davical/dba/create-database.sh </pre> <h2>Connecting to the Database</h2> @@ -168,23 +169,40 @@ reload or restart the PostgreSQL process for the change to come into effect.</p> <h1>Apache VHost Configuration</h1> +<h2>Relative to an existing DocumentRoot</h2> + +<p>You can create a symlink from an existing web root directory to the +/usr/share/rscds/htdocs directory, such as:</p> + +<pre> +cd /my/apache/docroot +ln -s /usr/share/davical/htdocs davical +</pre> + +You will need to change your global PHP configuration to include the +directory '/usr/share/awl/inc' in the 'include_path' setting, along with +any other directories already needed by other applications. + +You will also need to ensure that 'magic_quotes_gpc' is off. + +<h2>Using a Virtual Host</h2> <p>Your Apache instance needs to be configured for Virtual Hosts. If this is not already the case you may want to read some documentation about that, and you most likely will want to ensure that any existing -site becomes the **default** virtual host, with RSCDS only being a +site becomes the **default** virtual host, with DAViCal only being a single virtual host.</p> <p>I use a Virtual Host stanza like this:</p> <pre> # -# Virtual Host def for Debian packaged RSCDS +# Virtual Host def for Debian packaged DAViCal <VirtualHost 123.4.56.78 > - DocumentRoot /usr/share/rscds/htdocs + DocumentRoot /usr/share/davical/htdocs DirectoryIndex index.php index.html ServerName davical.example.net ServerAlias calendar.example.net - Alias /images/ /usr/share/rscds/htdocs/images/ + Alias /images/ /usr/share/davical/htdocs/images/ php_value include_path /usr/share/awl/inc php_value magic_quotes_gpc 0 php_value register_globals 0 @@ -204,30 +222,30 @@ installed from a package.</p> <p>Once your VHost is installed an working correctly, you should be able to browse to that address and see a page telling you that -you need to configure RSCDS.</p> +you need to configure DAViCal.</p> <p>On Debian systems (or derivatives such as Ubuntu), when you are using Apache 2, you should put this definition in the /etc/apache2/sites-available directory and you can use the 'a2ensite' command to enable it.</p> -<h1>RSCDS Configuration</h1> +<h1>DAViCal Configuration</h1> -<p>The RSCDS configuration generally resides in /etc/rscds/<domain>-conf.php +<p>The DAViCal configuration generally resides in /etc/davical/<domain>-conf.php and is a regular PHP file which sets (or overrides) some specific variables.</p> <pre> <?php // $c->domain_name = "calendar.example.net"; -// $c->sysabbr = 'rscds'; +// $c->sysabbr = 'DAViCal'; // $c->admin_email = 'admin@example.net'; -// $c->system_name = "Really Simple CalDAV Store"; +// $c->system_name = "DAViCal Server Administration"; // $c->collections_always_exist = true; // $c->enable_row_linking = true; // $c->default_locale = en_NZ.UTF-8; -// $c->pg_connect[] = 'dbname=rscds port=5433 user=general'; - $c->pg_connect[] = 'dbname=rscds port=5432 user=general'; + $c->pg_connect[] = 'dbname=davical port=5433 user=general'; + $c->pg_connect[] = 'dbname=davical port=5432 user=general'; ?> </pre> @@ -246,7 +264,7 @@ creation of calendar collections.</p> <p>The "enable_row_linking" option controls whether javascript is used to make the entire row clickable in browse lists in the administration pages. Since this doesn't work in Konqueror you may want to set this -to false if you expect people to be using Konqueror with the RSCDS +to false if you expect people to be using Konqueror with the DAViCal administration pages.</p> <p>You should set the 'domain_name' and 'admin_email' as they are used @@ -283,7 +301,7 @@ are supported on your system.</p> pages and log in as 'admin' (the password is the bit after the '**' in the 'password' field of the 'usr' table so:</p> <pre> -psql rscds -c 'select username, password from usr;' +psql davical -c 'select username, password from usr;' </pre> <p>should show you a list. Note that once you change a password it @@ -301,8 +319,8 @@ about your experiences in the Wiki, including distribution specific notes, to pa <h1>Upgrades</h1> -<p>Whenever you upgrade the RSCDS application to a new version you will need to -run dba/update-rscds-database which will apply any pending database patches, as well as +<p>Whenever you upgrade the DAViCal application to a new version you will need to +run dba/update-davical-database which will apply any pending database patches, as well as enabling any new translations.</p> <p>In due course the running of this script will be able to be handled by From e7a919eca60299ad2126852e5c26db3a8204d4a3 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Wed, 17 Oct 2007 10:17:14 +1300 Subject: [PATCH 188/189] Rename to DAViCal in the documentation. --- docs/website/administration.php | 8 ++-- docs/website/inc/page-header.php | 6 ++- docs/website/index.php | 3 +- docs/website/installation.php | 66 ++++++++++++++++++++------------ 4 files changed, 52 insertions(+), 31 deletions(-) diff --git a/docs/website/administration.php b/docs/website/administration.php index 4702f861..d9078546 100644 --- a/docs/website/administration.php +++ b/docs/website/administration.php @@ -98,14 +98,14 @@ P4 ==>> Administers Group ==> G </pre> -<h1>Configuring Calendar Clients for RSCDS</h1> -<p>The <a href="http://rscds.sourceforge.net/clients.php">RSCDS client setup page on sourceforge</a> has information on how +<h1>Configuring Calendar Clients for DAViCal</h1> +<p>The <a href="http://rscds.sourceforge.net/clients.php">DAViCal client setup page on sourceforge</a> has information on how to configure Evolution, Mozilla Calendar (Sunbird & Lightning) and Mulberry to use remotely hosted calendars.</p> <p>The administrative interface has no facility for viewing or modifying calendar data.</p> -<h1>Configuring RSCDS</h1> +<h1>Configuring DAViCal</h1> <p>If you can read this then things must be mostly working already.</p> -<p>The <a href="http://rscds.sourceforge.net/installation.php">RSCDS installation page</a> on sourceforge has +<p>The <a href="http://rscds.sourceforge.net/installation.php">DAViCal installation page</a> on sourceforge has some further information on how to install and configure this application.</p> diff --git a/docs/website/inc/page-header.php b/docs/website/inc/page-header.php index f2433937..6fa74c3b 100644 --- a/docs/website/inc/page-header.php +++ b/docs/website/inc/page-header.php @@ -17,10 +17,14 @@ if ( isset($title) ) { echo $title; } else { +<<<<<<< HEAD:docs/website/inc/page-header.php echo "DAViCal CalDAV Server"; +======= + echo "DAViCal"; +>>>>>>> Rename to DAViCal in the documentation.:docs/website/inc/page-header.php } ?></div> -<div id="subTitle">DAViCal CalDAV Server</div> +<div id="subTitle">A CalDAV Store</div> <div id="headerLinks"> <a href="index.php" class="hlink">Home</a> | <a href="installation.php" class="hlink">Installation</a> | diff --git a/docs/website/index.php b/docs/website/index.php index bbdae445..c4c6e1cc 100644 --- a/docs/website/index.php +++ b/docs/website/index.php @@ -56,7 +56,7 @@ works using the CalDAV protocol.</p> <ul> <li>Lorena Paoletti (Spanish)</li> <li>Cristina Radalescu (German)</li> -<li>Guillaume Rosquin (French)</li> +<li>Guillaume Rosquin & Maxime Delorme (French)</li> <li>Nick Khazov (Russian)</li> <li>Eelco Maljaars (Dutch)</li> </ul> @@ -69,7 +69,6 @@ works using the CalDAV protocol.</p> <h1>Your Name Here!</h1> <p>If you are interested in helping, there are several areas where I need help at the moment:</p> <i> -<li>The project needs a better name - feel free to suggest one!</li> <li>We need more documentation</li> <li>We need to find more CalDAV-capable calendar clients to interoperate with</li> <li>We would love you to write about your experiences in the project Wiki.</li> diff --git a/docs/website/installation.php b/docs/website/installation.php index e477f4e5..262a98c6 100644 --- a/docs/website/installation.php +++ b/docs/website/installation.php @@ -12,7 +12,7 @@ deb http://debian.mcmillan.net.nz/debian unstable awm </pre> <p>to your <code>/etc/apt/sources.list</code>. Once you have done that you can use <code>apt-get</code> or <code>synaptic</code> or some other equivalent package -manager to fetch and install <code>rscds</code> and all the dependencies.</p> +manager to fetch and install <code>DAViCal</code> and all the dependencies.</p> <p>This repository is signed by Andrew McMillan's public key, which you can install so that you don't get asked for confirmation all the time:</p> @@ -31,15 +31,15 @@ notes to pages somewhere under here: <h3>RPM Packages of DAViCal</h3> <p>We have created RPM packages of DAViCal and libawl-php from the .deb packages -using "alien". I don't know how well these work, so would appreciate feedback -about your success with them.</p> +using "alien". These are reported to work fine, so use them and then proceed to the +Pre-requisites section below.</p> <h3>SuSE Linux</h3> <p>On SuSE Linux you may need to look in /var/lib/pgsql/data/ for the pg_hba.conf file.</p> <h3>Gentoo, Slackware, BSD and the rest</h3> -<p>You will need to download the latest versions of the <code>rscds</code> and <code>awl</code> packages +<p>You will need to download the latest versions of the <code>DAViCal</code> and <code>awl</code> packages from the <a href="http://sourceforge.net/project/showfiles.php?group_id=179845">sourceforge download page for DAViCal</a>.</p> <p>You will need to untar these. Preferably you will untar them from within the "<code>/usr/share</code>" directory and everything will be in it's expected location (well, except the docs, but it will at least be tidy and everything will be in one place).</p> @@ -68,7 +68,7 @@ a number of years.</p> <p>The following other software is also needed:</p> <ul> <li>Apache: 1.3.x or 2.x.x</li> - <li>PHP: 5.0 or greater, PHP4 might work</li> + <li>PHP: 5.0 or greater</li> <li>PostgreSQL: 8.1 or greater</li> </ul> @@ -78,10 +78,11 @@ if you want to increase the security or scalability of your installation.</p> <p>Since the CalDAV store takes over a significant amount of path -hierarchy, it is designed to be installed in it's own virtual -host. However if you want it to operate within the web root of some +hierarchy, it can be easier in it's own virtual +host. If you want it to operate within the web root of some other application there are instructions on the Wiki about doing this, -and other fancy tricks such as URL rewriting to shorten the path.</p> +as well as other fancy tricks such as configuring URL rewriting in +order to shorten the path.</p> <h1>Database Setup</h1> @@ -124,7 +125,7 @@ have put them.</p> running as a user who has rights to create a new database, so you may need to do this as the "postgres" user, for example:</p> <pre> -su postgres -c /usr/share/rscds/dba/create-database.sh +su postgres -c /usr/share/davical/dba/create-database.sh </pre> <h2>Connecting to the Database</h2> @@ -168,23 +169,40 @@ reload or restart the PostgreSQL process for the change to come into effect.</p> <h1>Apache VHost Configuration</h1> +<h2>Relative to an existing DocumentRoot</h2> + +<p>You can create a symlink from an existing web root directory to the +/usr/share/rscds/htdocs directory, such as:</p> + +<pre> +cd /my/apache/docroot +ln -s /usr/share/davical/htdocs davical +</pre> + +You will need to change your global PHP configuration to include the +directory '/usr/share/awl/inc' in the 'include_path' setting, along with +any other directories already needed by other applications. + +You will also need to ensure that 'magic_quotes_gpc' is off. + +<h2>Using a Virtual Host</h2> <p>Your Apache instance needs to be configured for Virtual Hosts. If this is not already the case you may want to read some documentation about that, and you most likely will want to ensure that any existing -site becomes the **default** virtual host, with RSCDS only being a +site becomes the **default** virtual host, with DAViCal only being a single virtual host.</p> <p>I use a Virtual Host stanza like this:</p> <pre> # -# Virtual Host def for Debian packaged RSCDS +# Virtual Host def for Debian packaged DAViCal <VirtualHost 123.4.56.78 > - DocumentRoot /usr/share/rscds/htdocs + DocumentRoot /usr/share/davical/htdocs DirectoryIndex index.php index.html ServerName davical.example.net ServerAlias calendar.example.net - Alias /images/ /usr/share/rscds/htdocs/images/ + Alias /images/ /usr/share/davical/htdocs/images/ php_value include_path /usr/share/awl/inc php_value magic_quotes_gpc 0 php_value register_globals 0 @@ -204,30 +222,30 @@ installed from a package.</p> <p>Once your VHost is installed an working correctly, you should be able to browse to that address and see a page telling you that -you need to configure RSCDS.</p> +you need to configure DAViCal.</p> <p>On Debian systems (or derivatives such as Ubuntu), when you are using Apache 2, you should put this definition in the /etc/apache2/sites-available directory and you can use the 'a2ensite' command to enable it.</p> -<h1>RSCDS Configuration</h1> +<h1>DAViCal Configuration</h1> -<p>The RSCDS configuration generally resides in /etc/rscds/<domain>-conf.php +<p>The DAViCal configuration generally resides in /etc/davical/<domain>-conf.php and is a regular PHP file which sets (or overrides) some specific variables.</p> <pre> <?php // $c->domain_name = "calendar.example.net"; -// $c->sysabbr = 'rscds'; +// $c->sysabbr = 'DAViCal'; // $c->admin_email = 'admin@example.net'; -// $c->system_name = "Really Simple CalDAV Store"; +// $c->system_name = "DAViCal Server Administration"; // $c->collections_always_exist = true; // $c->enable_row_linking = true; // $c->default_locale = en_NZ.UTF-8; -// $c->pg_connect[] = 'dbname=rscds port=5433 user=general'; - $c->pg_connect[] = 'dbname=rscds port=5432 user=general'; + $c->pg_connect[] = 'dbname=davical port=5433 user=general'; + $c->pg_connect[] = 'dbname=davical port=5432 user=general'; ?> </pre> @@ -246,7 +264,7 @@ creation of calendar collections.</p> <p>The "enable_row_linking" option controls whether javascript is used to make the entire row clickable in browse lists in the administration pages. Since this doesn't work in Konqueror you may want to set this -to false if you expect people to be using Konqueror with the RSCDS +to false if you expect people to be using Konqueror with the DAViCal administration pages.</p> <p>You should set the 'domain_name' and 'admin_email' as they are used @@ -283,7 +301,7 @@ are supported on your system.</p> pages and log in as 'admin' (the password is the bit after the '**' in the 'password' field of the 'usr' table so:</p> <pre> -psql rscds -c 'select username, password from usr;' +psql davical -c 'select username, password from usr;' </pre> <p>should show you a list. Note that once you change a password it @@ -301,8 +319,8 @@ about your experiences in the Wiki, including distribution specific notes, to pa <h1>Upgrades</h1> -<p>Whenever you upgrade the RSCDS application to a new version you will need to -run dba/update-rscds-database which will apply any pending database patches, as well as +<p>Whenever you upgrade the DAViCal application to a new version you will need to +run dba/update-davical-database which will apply any pending database patches, as well as enabling any new translations.</p> <p>In due course the running of this script will be able to be handled by From 27be6f55f361ecc28163da2c92dc188f71b1b194 Mon Sep 17 00:00:00 2001 From: Andrew McMillan <debian@mcmillan.net.nz> Date: Fri, 7 Dec 2007 09:16:52 +1300 Subject: [PATCH 189/189] Fix busted merge. --- docs/website/inc/page-header.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/website/inc/page-header.php b/docs/website/inc/page-header.php index 6fa74c3b..0bb3ef61 100644 --- a/docs/website/inc/page-header.php +++ b/docs/website/inc/page-header.php @@ -17,11 +17,7 @@ if ( isset($title) ) { echo $title; } else { -<<<<<<< HEAD:docs/website/inc/page-header.php echo "DAViCal CalDAV Server"; -======= - echo "DAViCal"; ->>>>>>> Rename to DAViCal in the documentation.:docs/website/inc/page-header.php } ?></div> <div id="subTitle">A CalDAV Store</div>