Merge remote branch 'origin/master' into sched

This commit is contained in:
Rob Ostensen 2011-11-07 16:22:59 -06:00
commit f4e561412f
49 changed files with 1908 additions and 609 deletions

View File

@ -7,7 +7,7 @@ written in Python.</p>
<ol>
<li>Select "Subscribe" from the "Share" menu (or in older builds it was in the "Collection" menu).</li>
<li>Enter a URL like: "http://calendar.example.net/caldav.php/username/home/" (click "Subscribe") <img src="clients/Chandler-dialog1.png" /> <br /> &nbsp;</li>
<li>Enter a URL like: "http://calendar.example.net/caldav.php/username/calendar/" (click "Subscribe") <img src="clients/Chandler-dialog1.png" /> <br /> &nbsp;</li>
<li>You will then be prompted for a username/password with in an expanded dialog. Enter these and click "Subscribe" again. <img src="clients/Chandler-dialog2.png" /> <br /> &nbsp;</li>
<li>You should now have a new calendar showing.</li>
</ol>

View File

@ -5,7 +5,7 @@ was little in the way of a repository available to test against until recently.<
<ol>
<li>Select "File" then "New" then "Calendar" from the menus.</li>
<li>Choose a type of "CalDAV", enter a name, and a URL such as <code>caldav://server.domain.name/caldav.php/username/home/</code>, enter your user name for DAViCal and click "OK".<img src="clients/Evolution-dialog1.png" /> <br />&nbsp;</li>
<li>Choose a type of "CalDAV", enter a name, and a URL such as <code>caldav://server.domain.name/caldav.php/username/calendar/</code>, enter your user name for DAViCal and click "OK".<img src="clients/Evolution-dialog1.png" /> <br />&nbsp;</li>
<li>You should now be prompted for a password for that username. Enter the password and your calendar should now show.</li>
</ol>

View File

@ -10,13 +10,25 @@ that Mulberry does it.</p>
<li>Calendar namespace</li>
</ul>
<p>The host name is, of course, up to you. The 'root path' should be <code>/caldav.php/</code> and anything following that is the calendar namespace.</p>
<p>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.</p>
<p>Effectively this means that in Evolution, Sunbird and Lightning you should really specify a calendar URL which is something like:</p>
<p>The host name is, of course, up to you. The 'root path' should be
<code>/caldav.php/</code> and anything following that is the calendar
namespace.</p>
<p>Within the calendar namespace DAViCal uses the first element of the
path as the user or 'princpal' 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.</p>
<p>This means that in Evolution, Lightning and other software wanting a
'calendar' URL you should specify a URL which is something like:</p>
<pre>
http://calendar.example.net/caldav.php/username/home/
http://calendar.example.net/caldav.php/username/calendar/
</pre>
<p>Then, when more calendar client software sees it as useful to be able to browse that hierarchy, you won't be up for any heavy database manipulation.</p>
<p>I may well enforce this standard in some way before release 1.0, as well as auto-creating the <code>collection</code> records when Evolution, Lightning
or Sunbird attempt to store to a non-existent collection.</p>
<p>DAViCal creates two collections automatically when a user is created. In
recent versions these are called 'calendar' and 'addressbook'. Some software
also makes it easy to create more calendars and addressbooks, or you can create
more through DAViCal's web interface, also.</p>
<p>In older versions of DAViCal (pre 0.9.9.5) the default calendar was named 'home'
and there was no default addressbook.</p>

View File

@ -8,7 +8,7 @@
<ol>
<li>Select "New Calendar" from the "File" menu.</li>
<li>Choose "On the Network" (click "Next")<img src="clients/Mozilla-dialog1.png" /> <br /> &nbsp;</li>
<li>Choose a format of "CalDAV" and enter a URL like: "http://calendar.example.net/caldav.php/username/home/" (click "Next")<img src="clients/Mozilla-dialog2.png" /> <br /> &nbsp;</li>
<li>Choose a format of "CalDAV" and enter a URL like: "http://calendar.example.net/caldav.php/username/calendar/" (click "Next")<img src="clients/Mozilla-dialog2.png" /> <br /> &nbsp;</li>
<li>Give the calendar an appropriate display name, and choose a colour for events on this calendar. (click "Next")<img src="clients/Mozilla-dialog3.png" /> <br /> &nbsp;</li>
<li>click "Finish"</li>
</ol>

View File

@ -6,3 +6,24 @@ against, but so far these are the only ones I have access to.</p>
<p>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 DAViCal work with it.</p>
<p>In the general CalDAV terminology, client software will want to know
several facts about the CalDAV server. Some (like iCal and iOS) will try
and discover these facts for themselves, and others (like Lightning and
Evolution) will require you to enter some information. When they ask for
that information they will be asking for the following things:</p>
<ol>
<li>Where is the user's "home" collection?</li>
<li>Where is the user's "calendar" collection?</li>
<li>What is the server's domain name</li>
</ol>
<p>Typically the answers, in DAViCal's case, are:</p>
<ol>
<li>.../caldav.php/username/</li>
<li>.../caldav.php/username/calendar/ (although in older versions the default calendar was called 'home' rather than 'calendar')</li>
<li>I can't help here - whatever you called it, I guess!</li>
</ol>
<p>There could well be a wider range of information about many and varied client
software on the <a href="http://wiki.davical.org/" title="The DAViCal CalDAV Server Wiki">DAViCal Wiki</a> as well.

View File

@ -24,7 +24,7 @@ if ( ! @include_once( $code_file ) ) {
$c->messages[] = sprintf('No page found to %s %s%s%s', $action, ($action == 'browse' ? '' : 'a '), $component, ($action == 'browse' ? 's' : ''));
include('page-header.php');
include('page-footer.php');
exit(0);
@ob_flush(); exit(0);
}
include('page-header.php');

View File

@ -26,6 +26,7 @@ function early_exception_handler($e) {
foreach( $trace AS $k => $v ) {
printf( "%s[%d] %s%s%s()\n", $v['file'], $v['line'], (isset($v['class'])?$v['class']:''), (isset($v['type'])?$v['type']:''), (isset($v['function'])?$v['function']:'') );
}
@ob_flush();
}
set_exception_handler('early_exception_handler');
@ -89,7 +90,7 @@ if ( ! @include_once('AWLUtilities.php') ) {
}
if ( ! @include_once('AWLUtilities.php') ) {
echo "Could not find the AWL libraries. Are they installed? Check your include_path in php.ini!\n";
exit;
@ob_flush(); exit(0);
}
}
@ -145,7 +146,7 @@ else if ( @file_exists('config/config.php') ) {
}
else {
include('davical_configuration_missing.php');
exit;
@ob_flush(); exit(0);
}
$config_warnings = trim(ob_get_contents());
ob_end_clean();

View File

@ -17,17 +17,17 @@ if ( isset($_SERVER['PATH_INFO']) && preg_match( '{^(/favicon.ico|davical.css|(i
else {
fpassthru($fh);
}
exit(0);
@ob_flush(); exit(0);
}
require_once('./always.php');
if ( isset($_SERVER['PATH_INFO']) && preg_match( '{^/\.well-known/(.+)$}', $_SERVER['PATH_INFO'], $matches ) ) {
require ('well-known.php');
exit(0);
@ob_flush(); exit(0);
}
elseif ( isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] == '/autodiscover/autodiscover.xml' ) {
require ('autodiscover-handler.php');
exit(0);
@ob_flush(); exit(0);
}
function logRequestHeaders() {
@ -102,7 +102,7 @@ if ( ! ($request->IsPrincipal() || isset($request->collection) || $request->meth
$redirect_url = ConstructURL('/caldav.php'.$matches[1]);
dbg_error_log( 'LOG WARNING', 'Redirecting %s for "%s" to "%s"', $request->method, $request->path, $redirect_url );
header('Location: '.$redirect_url );
exit(0);
@ob_flush(); exit(0);
}
}

View File

@ -4,7 +4,7 @@ if ( $_SERVER['REQUEST_METHOD'] != "GET" && $_SERVER['REQUEST_METHOD'] != "POST"
* If the request is not a GET or POST then they must really want caldav.php!
*/
include("./caldav.php");
exit; // Not that it should return from that!
@ob_flush(); exit(0); // Not that it should return from that!
}
include("./always.php");

View File

@ -21,7 +21,7 @@ require_once("caldav-PUT-functions.php");
include_once('check_UTF8.php');
if ( !$session->AllowedTo("Admin" ) )
exit;
@ob_flush(); exit(0);
if( function_exists("sync_LDAP") && isset($_POST['Sync_LDAP'])){
sync_LDAP();

View File

@ -1201,8 +1201,7 @@ EOSQL;
@dbg_error_log("statistics", "Method: %s, Status: %d, Script: %5.3lfs, Queries: %5.3lfs, URL: %s",
$this->method, $status, $script_time, $c->total_query_time, $this->path);
}
exit(0);
@ob_flush(); exit(0);
}
}

View File

@ -283,6 +283,17 @@ class DAVResource
$this->resource->location = null;
$this->resource->url = null;
}
else if ( isset($c->hide_alarm) && $c->hide_alarm && !$this->HavePrivilegeTo('write') ) {
$vcal1 = new iCalComponent($this->resource->caldav_data);
$comps = $vcal1->GetComponents();
$vcal2 = new iCalComponent();
$vcal2->VCalendar();
foreach( $comps AS $comp ) {
$comp->ClearComponents('VALARM');
$vcal2->AddComponent($comp);
}
$this->resource->caldav_data = $vcal2->Render();
}
}
else if ( strtoupper(substr($this->resource->caldav_data,0,11)) == 'BEGIN:VCARD' ) {
$this->contenttype = 'text/vcard';
@ -1048,8 +1059,8 @@ EOQRY;
/**
* Checks whether this resource is a calendar
* @param string $type The type of scheduling collection, 'read', 'write' or 'any'
* Checks whether this resource is a scheduling inbox/outbox collection
* @param string $type The type of scheduling collection, 'inbox', 'outbox' or 'any'
*/
function IsSchedulingCollection( $type = 'any' ) {
if ( $this->_is_collection && preg_match( '{schedule-(inbox|outbox)}', $this->collection->type, $matches ) ) {
@ -1059,6 +1070,18 @@ EOQRY;
}
/**
* Checks whether this resource is IN a scheduling inbox/outbox collection
* @param string $type The type of scheduling collection, 'inbox', 'outbox' or 'any'
*/
function IsInSchedulingCollection( $type = 'any' ) {
if ( !$this->_is_collection && preg_match( '{schedule-(inbox|outbox)}', $this->collection->type, $matches ) ) {
return ($type == 'any' || $type == $matches[1]);
}
return false;
}
/**
* Checks whether this resource is an addressbook
*/
@ -1245,6 +1268,14 @@ EOQRY;
}
/**
* Checks whether the target collection is for public events only
*/
function IsPublicOnly() {
return ( isset($this->collection->publicly_events_only) && $this->collection->publicly_events_only == 't' );
}
/**
* Return the type of whatever contains this resource, or would if it existed.
*/
@ -1371,6 +1402,11 @@ EOQRY;
return clone($this->resource);
break;
case 'dav-data':
if ( !isset($this->resource) ) $this->FetchResource();
return $this->resource->caldav_data;
break;
case 'principal':
if ( !isset($this->principal) ) $this->FetchPrincipal();
return clone($this->principal);

View File

@ -113,7 +113,7 @@ class DAViCalSession extends Session
|| (isset($c->restrict_admin_port) && $c->restrict_admin_port != $_SERVER['SERVER_PORT'] ) ) {
header('Location: caldav.php');
dbg_error_log( 'LOG WARNING', 'Access to "%s" via "%s:%d" rejected.', $_SERVER['REQUEST_URI'], $current_domain, $_SERVER['SERVER_PORT'] );
exit(0);
@ob_flush(); exit(0);
}
if ( isset($c->restrict_admin_roles) && $roles == '' ) $roles = $c->restrict_admin_roles;
if ( $this->logged_in && $roles == '' ) return;
@ -156,7 +156,7 @@ class DAViCalSession extends Session
}
include('page-footer.php');
exit;
@ob_flush(); exit(0);
}
}

View File

@ -88,7 +88,7 @@ class HTTPAuthSession {
header( $auth_header );
echo 'Please log in for access to this system.';
dbg_error_log( "HTTPAuth", ":Session: User is not authorised: %s ", $_SERVER['REMOTE_ADDR'] );
exit;
@ob_flush(); exit(0);
}
@ -139,6 +139,11 @@ class HTTPAuthSession {
*/
if ( isset($_SERVER['PHP_AUTH_USER']) ) {
if ( $p = $this->CheckPassword( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) ) {
if ( isset($p->active) && !isset($p->user_active) ) {
trace_bug('Some authentication failed to return a dav_principal record and needs fixing.');
$p->user_active = $p->active;
}
/**
* Maybe some external authentication didn't return false for an inactive
* user, so we'll be pedantic here.
@ -300,7 +305,11 @@ class HTTPAuthSession {
* It can expect that:
* - Configuration data will be in $c->authenticate_hook['config'], which might be an array, or whatever is needed.
*/
return call_user_func( $c->authenticate_hook['call'], $username, $password );
$principal = call_user_func( $c->authenticate_hook['call'], $username, $password );
if ( $principal !== false && !($principal instanceof Principal) ) {
$principal = new Principal('username', $username);
}
return $principal;
}
return false;

View File

@ -17,7 +17,7 @@ class WritableCollection extends DAVResource {
return $p->GetParameterValue('TZID');
}
/**
/**
* Writes the data to a member in the collection and returns the segment_name of the
* resource in our internal namespace.
*
@ -36,7 +36,7 @@ class WritableCollection extends DAVResource {
return false;
}
global $tz_regex, $session, $caldav_context;
global $session, $caldav_context;
$resources = $vcal->GetComponents('VTIMEZONE',false); // Not matching VTIMEZONE
$user_no = $this->user_no();
@ -179,18 +179,11 @@ class WritableCollection extends DAVResource {
$calitem_params[':dtstamp'] = $dtstamp;
$class = $first->GetPValue('CLASS');
/* Check and see if we should over ride the class. */
/** @todo is there some way we can move this out of this function? Or at least get rid of the need for the SQL query here. */
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
* RFC2445, 4.8.1.3: Default is PUBLIC
*/
if ( !isset($class) || $class == '' ) {
if ( $this->IsPublicOnly() || !isset($class) || $class == '' ) {
$class = 'PUBLIC';
}
$calitem_params[':class'] = $class;
@ -202,19 +195,11 @@ class WritableCollection extends DAVResource {
$tz = $vcal->GetTimeZone($tzid);
$olson = $vcal->GetOlsonName($tz);
dbg_error_log( 'PUT', ' Using TZID[%s] and location of [%s]', $tzid, (isset($olson) ? $olson : '') );
if ( !empty($olson) && ($olson != $last_olson) && preg_match( $tz_regex, $olson ) ) {
if ( !empty($olson) && ($olson != $last_olson) ) {
dbg_error_log( 'PUT', ' Setting timezone to %s', $olson );
$qry->QDo('SET TIMEZONE TO \''.$olson."'" );
$last_olson = $olson;
}
$params = array( ':tzid' => $tzid);
$qry = new AwlQuery('SELECT 1 FROM timezones WHERE tzid = :tzid', $params );
if ( $qry->Exec('PUT',__LINE__,__FILE__) && $qry->rows() == 0 ) {
$params[':olson_name'] = $olson;
$params[':vtimezone'] = (isset($tz) ? $tz->Render() : null );
$qry->QDo('INSERT INTO timezones (tzid, olson_name, active, vtimezone) VALUES(:tzid,:olson_name,false,:vtimezone)', $params );
}
}
$created = $first->GetPValue('CREATED');
@ -258,8 +243,8 @@ EOSQL;
}
if ( !$this->IsSchedulingCollection() ) {
write_alarms($dav_id, $first);
write_attendees($dav_id, $vcal);
$this->WriteCalendarAlarms($dav_id, $vcal);
$this->WriteCalendarAttendees($dav_id, $vcal);
if ( $log_action && function_exists('log_caldav_action') ) {
log_caldav_action( $put_action_type, $first->GetPValue('UID'), $user_no, $collection_id, $path );
}
@ -317,4 +302,144 @@ EOSQL;
return $segment_name;
}
/**
* Given a dav_id and an original vCalendar, pull out each of the VALARMs
* and write the values into the calendar_alarm table.
*
* @return null
*/
function WriteCalendarAlarms( $dav_id, vCalendar $vcal ) {
$qry = new AwlQuery('DELETE FROM calendar_alarm WHERE dav_id = '.$dav_id );
$qry->Exec('PUT',__LINE__,__FILE__);
$components = $vcal->GetComponents();
$qry->SetSql('INSERT INTO calendar_alarm ( dav_id, action, trigger, summary, description, component, next_trigger )
VALUES( '.$dav_id.', :action, :trigger, :summary, :description, :component,
:related::timestamp with time zone + :related_trigger::interval )' );
$qry->Prepare();
foreach( $components AS $component ) {
if ( $component->GetType() == 'VTIMEZONE' ) continue;
$alarms = $component->GetComponents('VALARM');
if ( count($alarms) < 1 ) return;
foreach( $alarms AS $v ) {
$trigger = array_merge($v->GetProperties('TRIGGER'));
if ( $trigger == null ) continue; // Bogus data.
$trigger = $trigger[0];
$related = null;
$related_trigger = '0M';
$trigger_type = $trigger->GetParameterValue('VALUE');
if ( !isset($trigger_type) || $trigger_type == 'DURATION' ) {
switch ( $trigger->GetParameterValue('RELATED') ) {
case 'DTEND': $related = $component->GetPValue('DTEND'); break;
case 'DUE': $related = $component->GetPValue('DUE'); break;
default: $related = $component->GetPValue('DTSTART');
}
$duration = $trigger->Value();
if ( !preg_match('{^-?P(:?\d+W)?(:?\d+D)?(:?T(:?\d+H)?(:?\d+M)?(:?\d+S)?)?$}', $duration ) ) continue;
$minus = (substr($duration,0,1) == '-');
$related_trigger = trim(preg_replace( '#[PT-]#', ' ', $duration ));
if ( $minus ) {
$related_trigger = preg_replace( '{(\d+[WDHMS])}', '-$1 ', $related_trigger );
}
else {
$related_trigger = preg_replace( '{(\d+[WDHMS])}', '$1 ', $related_trigger );
}
}
else {
if ( false === strtotime($trigger->Value()) ) continue; // Invalid date.
}
$qry->Bind(':action', $v->GetPValue('ACTION'));
$qry->Bind(':trigger', $trigger->Render());
$qry->Bind(':summary', $v->GetPValue('SUMMARY'));
$qry->Bind(':description', $v->GetPValue('DESCRIPTION'));
$qry->Bind(':component', $v->Render());
$qry->Bind(':related', $related );
$qry->Bind(':related_trigger', $related_trigger );
$qry->Exec('PUT',__LINE__,__FILE__);
}
}
}
/**
* Parse out the attendee property and write a row to the
* calendar_attendee table for each one.
* @param int $dav_id The dav_id of the caldav_data we're processing
* @param vComponent The VEVENT or VTODO containing the ATTENDEEs
* @return null
*/
function WriteCalendarAttendees( $dav_id, vCalendar $vcal ) {
$qry = new AwlQuery('DELETE FROM calendar_attendee WHERE dav_id = '.$dav_id );
$qry->Exec('PUT',__LINE__,__FILE__);
$attendees = $vcal->GetAttendees();
if ( count($attendees) < 1 ) return;
$qry->SetSql('INSERT INTO calendar_attendee ( dav_id, status, partstat, cn, attendee, role, rsvp, property )
VALUES( '.$dav_id.', :status, :partstat, :cn, :attendee, :role, :rsvp, :property )' );
$qry->Prepare();
$processed = array();
foreach( $attendees AS $v ) {
$attendee = $v->Value();
if ( isset($processed[$attendee]) ) {
dbg_error_log( 'LOG', 'Duplicate attendee "%s" in resource "%d"', $attendee, $dav_id );
dbg_error_log( 'LOG', 'Original: "%s"', $processed[$attendee] );
dbg_error_log( 'LOG', 'Duplicate: "%s"', $v->Render() );
continue; /** @todo work out why we get duplicate ATTENDEE on one VEVENT */
}
$qry->Bind(':attendee', $attendee );
$qry->Bind(':status', $v->GetParameterValue('STATUS') );
$qry->Bind(':partstat', $v->GetParameterValue('PARTSTAT') );
$qry->Bind(':cn', $v->GetParameterValue('CN') );
$qry->Bind(':role', $v->GetParameterValue('ROLE') );
$qry->Bind(':rsvp', $v->GetParameterValue('RSVP') );
$qry->Bind(':property', $v->Render() );
$qry->Exec('PUT',__LINE__,__FILE__);
$processed[$attendee] = $v->Render();
}
}
/**
* Writes the data to a member in the collection and returns the segment_name of the
* resource in our internal namespace.
*
* @param vCalendar $member_dav_name The path to the resource to be deleted.
* @return boolean Success is true, or false on failure.
*/
function actualDeleteCalendarMember( $member_dav_name ) {
global $session, $caldav_context;
// A quick sanity check...
$segment_name = str_replace( $this->dav_name(), '', $member_dav_name );
if ( strstr($segment_name, '/') !== false ) {
@dbg_error_log( "DELETE", "DELETE: Refused to delete member '%s' from calendar '%s'!", $member_dav_name, $this->dav_name() );
return false;
}
// We need to serialise access to this process just for this collection
$cache = getCacheInstance();
$myLock = $cache->acquireLock('collection-'.$this->dav_name());
$qry = new AwlQuery();
$params = array( ':dav_name' => $member_dav_name );
if ( $qry->QDo("SELECT write_sync_change(collection_id, 404, caldav_data.dav_name) FROM caldav_data WHERE dav_name = :dav_name", $params )
&& $qry->QDo("DELETE FROM property WHERE dav_name = :dav_name", $params )
&& $qry->QDo("DELETE FROM locks WHERE dav_name = :dav_name", $params )
&& $qry->QDo("DELETE FROM caldav_data WHERE dav_name = :dav_name", $params ) ) {
@dbg_error_log( "DELETE", "DELETE: Calendar member %s deleted from calendar '%s'", $member_dav_name, $this->dav_name() );
$cache->releaseLock($myLock);
return true;
}
$cache->releaseLock($myLock);
return false;
}
}

View File

@ -26,6 +26,7 @@ function early_exception_handler($e) {
foreach( $trace AS $k => $v ) {
printf( "%s[%d] %s%s%s()\n", $v['file'], $v['line'], (isset($v['class'])?$v['class']:''), (isset($v['type'])?$v['type']:''), (isset($v['function'])?$v['function']:'') );
}
@ob_flush();
}
set_exception_handler('early_exception_handler');
@ -89,7 +90,7 @@ if ( ! @include_once('AWLUtilities.php') ) {
}
if ( ! @include_once('AWLUtilities.php') ) {
echo "Could not find the AWL libraries. Are they installed? Check your include_path in php.ini!\n";
exit;
@ob_flush(); exit(0);
}
}
@ -145,7 +146,7 @@ else if ( @file_exists('config/config.php') ) {
}
else {
include('davical_configuration_missing.php');
exit;
@ob_flush(); exit(0);
}
$config_warnings = trim(ob_get_contents());
ob_end_clean();

View File

@ -299,7 +299,7 @@ function AuthExternalAWL( $username, $password ) {
</body>
</html>
EOERRMSG;
exit(1);
@ob_flush(); exit(1);
}
if ( $qry->Exec('Login',__LINE__,__FILE__) && $qry->rows() == 1 ) {

View File

@ -14,7 +14,7 @@ $request = new CalDAVRequest();
if ( !isset($c->enable_autodiscover) || ! $c->enable_autodiscover ) {
$request->DoResponse( 404 );
exit(0);
exit(0); // unneccessary
}
$ns_outlook_req_2006 = "http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006";
@ -40,7 +40,7 @@ function errorResponse( $code, $message, $debugdata = '' ) {
ERROR;
$request->DoResponse( $code, $response, 'text/xml; charset="utf-8"' );
exit(0);
exit(0); // unneccessary
}

View File

@ -17,6 +17,7 @@ $container->NeedPrivilege('DAV::unbind');
$lock_opener = $request->FailIfLocked();
require_once('schedule-functions.php');
function delete_collection( $id ) {
$params = array( ':collection_id' => $id );
@ -72,12 +73,14 @@ else {
$request->DoResponse( 412, translate("Resource has changed on server - not deleted") );
}
$params = array( ':dav_id' => $dav_resource->resource_id() );
// Check to see if we need to do any scheduling transactions for this one.
do_scheduling_for_delete($dav_resource);
// We need to serialise access to this process just for this collection
$cache = getCacheInstance();
$myLock = $cache->acquireLock('collection-'.$dav_resource->parent_path());
$params = array( ':dav_id' => $dav_resource->resource_id() );
if ( $qry->QDo("SELECT write_sync_change(collection_id, 404, caldav_data.dav_name) FROM caldav_data WHERE dav_id = :dav_id", $params )
&& $qry->QDo("DELETE FROM property WHERE dav_name = (SELECT dav_name FROM caldav_data WHERE dav_id = :dav_id)", $params )
&& $qry->QDo("DELETE FROM locks WHERE dav_name = (SELECT dav_name FROM caldav_data WHERE dav_id = :dav_id)", $params )
@ -92,7 +95,6 @@ else {
$request->DoResponse( 204 );
}
$cache->releaseLock($myLock);
}
$request->DoResponse( 500 );

View File

@ -353,6 +353,5 @@ if ( $qry->Commit() ) {
* Or it was all crap.
*/
$request->DoResponse( 500 );
exit(0);
exit(0); // unneccessary

View File

@ -334,25 +334,25 @@ $sql = 'SELECT caldav_data.*,calendar_item.* FROM collection INNER JOIN caldav_
if ( isset($c->strict_result_ordering) && $c->strict_result_ordering ) $sql .= " ORDER BY caldav_data.dav_id";
$qry = new AwlQuery( $sql, $params );
if ( $qry->Exec("calquery",__LINE__,__FILE__) && $qry->rows() > 0 ) {
while( $calendar_object = $qry->Fetch() ) {
if ( !$need_post_filter || apply_filter( $qry_filters, $calendar_object ) ) {
while( $dav_object = $qry->Fetch() ) {
if ( !$need_post_filter || apply_filter( $qry_filters, $dav_object ) ) {
if ( $bound_from != $target_collection->dav_name() ) {
$calendar_object->dav_name = str_replace( $bound_from, $target_collection->dav_name(), $calendar_object->dav_name);
$dav_object->dav_name = str_replace( $bound_from, $target_collection->dav_name(), $dav_object->dav_name);
}
if ( $need_expansion ) {
$vResource = new vComponent($calendar_object->caldav_data);
$vResource = new vComponent($dav_object->caldav_data);
$expanded = expand_event_instances($vResource, $expand_range_start, $expand_range_end, $expand_as_floating );
if ( $expanded->ComponentCount() == 0 ) continue;
if ( $need_expansion ) $calendar_object->caldav_data = $expanded->Render();
if ( $need_expansion ) $dav_object->caldav_data = $expanded->Render();
}
else if ( isset($range_filter) ) {
$vResource = new vComponent($calendar_object->caldav_data);
$vResource = new vComponent($dav_object->caldav_data);
$expanded = getVCalendarRange($vResource);
dbg_error_log('calquery', 'Expanded to %s:%s which might overlap %s:%s',
$expanded->from, $expanded->until, $range_filter->from, $range_filter->until );
if ( !$expanded->overlaps($range_filter) ) continue;
}
$responses[] = calendar_to_xml( $properties, $calendar_object );
$responses[] = component_to_xml( $properties, $dav_object );
}
}
}

View File

@ -7,7 +7,8 @@ function get_address_properties( $address_data_xml ) {
global $address_data_properties;
$expansion = $address_data_xml->GetElements();
foreach( $expansion AS $k => $v ) {
$address_data_properties[strtoupper($v->GetAttribute('name'))] = true;
if ( $v instanceof XMLElement )
$address_data_properties[strtoupper($v->GetAttribute('name'))] = true;
}
}

View File

@ -39,7 +39,7 @@ if ( $xmltree->GetTag() != 'DAV::principal-property-search'
$target->NeedPrivilege( array('DAV::read', 'urn:ietf:params:xml:ns:caldav:read-free-busy'), true ); // They may have either
}
require_once("iCalendar.php");
require_once("vCalendar.php");
$reportnum = -1;
$report = array();
@ -80,110 +80,6 @@ switch( $xmltree->GetTag() ) {
}
/**
* Return XML for a single calendar (or todo) entry from the DB
*
* @param array $properties The properties for this calendar
* @param string $item The calendar data for this calendar
*
* @return string An XML document which is the response for the calendar
*/
function calendar_to_xml( $properties, $item ) {
global $session, $c, $request, $reply;
dbg_error_log("REPORT","Building XML Response for item '%s'", $item->dav_name );
$denied = array();
$caldav_data = $item->caldav_data;
$displayname = $item->summary;
if ( isset($properties['calendar-data']) || isset($properties['displayname']) ) {
if ( !$request->AllowedTo('all') && $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
/** @todo We should examine the ORGANIZER and ATTENDEE fields in the event. If this person is there then they should see this */
if ( $item->class == 'CONFIDENTIAL' || !$request->AllowedTo('read') ) {
$ical = new iCalComponent( $caldav_data );
$resources = $ical->GetComponents('VTIMEZONE',false);
$first = $resources[0];
// if the event is confidential we fake one that just says "Busy"
$confidential = new iCalComponent();
$confidential->SetType($first->GetType());
$confidential->AddProperty( 'SUMMARY', translate('Busy') );
$confidential->AddProperty( 'CLASS', 'CONFIDENTIAL' );
$confidential->SetProperties( $first->GetProperties('DTSTART'), 'DTSTART' );
$confidential->SetProperties( $first->GetProperties('RRULE'), 'RRULE' );
$confidential->SetProperties( $first->GetProperties('DURATION'), 'DURATION' );
$confidential->SetProperties( $first->GetProperties('DTEND'), 'DTEND' );
$confidential->SetProperties( $first->GetProperties('UID'), 'UID' );
$ical->SetComponents(array($confidential),$confidential->GetType());
$caldav_data = $ical->Render();
$displayname = translate('Busy');
}
}
}
$url = ConstructURL($item->dav_name);
$prop = new XMLElement("prop");
foreach( $properties AS $k => $v ) {
switch( $k ) {
case 'getcontentlength':
$contentlength = strlen($caldav_data);
$prop->NewElement($k, $contentlength );
break;
case 'getlastmodified':
$prop->NewElement($k, ISODateToHTTPDate($item->modified) );
break;
case 'calendar-data':
$reply->CalDAVElement($prop, $k, $caldav_data );
break;
case 'getcontenttype':
$prop->NewElement($k, "text/calendar" );
break;
case 'current-user-principal':
$prop->NewElement("current-user-principal", $request->current_user_principal_xml);
break;
case 'displayname':
$prop->NewElement($k, $displayname );
break;
case 'resourcetype':
$prop->NewElement($k); // Just an empty resourcetype for a non-collection.
break;
case 'getetag':
$prop->NewElement($k, '"'.$item->dav_etag.'"' );
break;
case '"current-user-privilege-set"':
$prop->NewElement($k, privileges($request->permissions) );
break;
case 'SOME-DENIED-PROPERTY': /** indicating the style for future expansion */
$denied[] = $v;
break;
default:
dbg_error_log( 'REPORT', "Request for unsupported property '%s' of calendar item.", $v );
$unsupported[] = $v;
}
}
$status = new XMLElement("status", "HTTP/1.1 200 OK" );
$propstat = new XMLElement( "propstat", array( $prop, $status) );
$href = new XMLElement("href", $url );
$elements = array($href,$propstat);
if ( count($denied) > 0 ) {
$status = new XMLElement("status", "HTTP/1.1 403 Forbidden" );
$noprop = new XMLElement("prop");
foreach( $denied AS $k => $v ) {
$noprop->NewElement( strtolower($v) );
}
$elements[] = new XMLElement( "propstat", array( $noprop, $status) );
}
$response = new XMLElement( "response", $elements );
return $response;
}
/**
* Return XML for a single component from the DB
@ -219,33 +115,27 @@ function component_to_xml( $properties, $item ) {
$contenttype = 'text/vcard';
break;
}
if ( isset($properties['calendar-data']) || isset($properties['displayname']) ) {
if ( !$request->AllowedTo('all') && $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
/** @todo We should examine the ORGANIZER and ATTENDEE fields in the event. If this person is there then they should see this */
if ( $type == 'calendar' && $item->class == 'CONFIDENTIAL' || !$request->AllowedTo('read') ) {
$ical = new iCalComponent( $caldav_data );
$resources = $ical->GetComponents('VTIMEZONE',false);
$first = $resources[0];
// if the event is confidential we fake one that just says "Busy"
$confidential = new iCalComponent();
$confidential->SetType($first->GetType());
$confidential->AddProperty( 'SUMMARY', translate('Busy') );
$confidential->AddProperty( 'CLASS', 'CONFIDENTIAL' );
$confidential->SetProperties( $first->GetProperties('DTSTART'), 'DTSTART' );
$confidential->SetProperties( $first->GetProperties('RRULE'), 'RRULE' );
$confidential->SetProperties( $first->GetProperties('DURATION'), 'DURATION' );
$confidential->SetProperties( $first->GetProperties('DTEND'), 'DTEND' );
$confidential->SetProperties( $first->GetProperties('UID'), 'UID' );
$ical->SetComponents(array($confidential),$confidential->GetType());
$caldav_data = $ical->Render();
$displayname = translate('Busy');
if ( $type == 'calendar' ) {
if ( isset($properties['calendar-data']) || isset($properties['displayname']) ) {
if ( !$request->AllowedTo('all') && $session->user_no != $item->user_no ) {
// the user is not admin / owner of this calendar looking at his calendar and can not admin the other cal
if ( $item->class == 'CONFIDENTIAL' || !$request->AllowedTo('read') ) {
dbg_error_log("REPORT","Anonymising confidential event for: %s", $item->dav_name );
$vcal = new vCalendar( $caldav_data );
$caldav_data = $vcal->Confidential()->Render();
$displayname = translate('Busy');
}
}
}
if ( isset($properties['calendar-data']) && isset($c->hide_alarm) && $c->hide_alarm && !$request->HavePrivilegeTo('write') ) {
dbg_error_log("REPORT","Stripping event alarms for: %s", $item->dav_name );
$vcal = new vCalendar($caldav_data);
$vcal->ClearComponents('VALARM');
$caldav_data = $vcal->Render();
}
}
$url = ConstructURL($item->dav_name);
$prop = new XMLElement("prop");

315
inc/schedule-functions.php Normal file
View File

@ -0,0 +1,315 @@
<?php
/**
* Functions for handling CalDAV Scheduling.
*
* @package davical
* @subpackage caldav
* @author Andrew McMillan <andrew@morphoss.com>
* @copyright Morphoss Ltd - http://www.morphoss.com/
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later version
*/
require_once('vCalendar.php');
require_once('WritableCollection.php');
require_once('RRule-v2.php');
/**
* Entry point for scheduling on DELETE, for which there are thee outcomes:
* - We don't do scheduling (disabled, no organizer, ...)
* - We are an ATTENDEE declining the meeting.
* - We are the ORGANIZER canceling the meeting.
*
* @param DAVResource $deleted_resource The resource which has already been deleted
*/
function do_scheduling_for_delete(DAVResource $deleted_resource ) {
// By the time we arrive here the resource *has* actually been deleted from disk
// we can only fail to (de-)schedule the activity...
global $request, $c;
if ( !isset($request) || (isset($c->enable_auto_schedule) && !$c->enable_auto_schedule) ) return true;
if ( $deleted_resource->IsInSchedulingCollection() ) return true;
$caldav_data = $deleted_resource->GetProperty('dav-data');
if ( empty($caldav_data) ) return true;
$vcal = new vCalendar($caldav_data);
$organizer = $vcal->GetOrganizer();
if ( $organizer === false || empty($organizer) ) {
dbg_error_log( 'schedule', 'Event has no organizer - no scheduling required.' );
return true;
}
if ( $vcal->GetScheduleAgent() != 'SERVER' ) {
dbg_error_log( 'schedule', 'SCHEDULE-AGENT=%s - no scheduling required.', $vcal->GetScheduleAgent() );
return true;
}
$organizer_email = preg_replace( '/^mailto:/i', '', $organizer->Value() );
if ( $request->principal->email() == $organizer_email ) {
return doItipOrganizerCancel( $vcal );
}
else {
if ( isset($_SERVER['HTTP_SCHEDULE_REPLY']) && $_SERVER['HTTP_SCHEDULE_REPLY'] == 'F') {
dbg_error_log( 'schedule', 'Schedule-Request header set to "F" - no scheduling required.' );
return true;
}
return doItipAttendeeReply( $vcal, 'DECLINED', $request->principal->email());
}
}
/**
* Do the scheduling adjustments for a REPLY when an ATTENDEE updates their status.
* @param vCalendar $vcal The resource that the ATTENDEE is writing to their calendar
* @param string $organizer The property which is the event ORGANIZER.
*/
//function do_scheduling_reply( vCalendar $vcal, vProperty $organizer ) {
function doItipAttendeeReply( vCalendar $resource, $partstat ) {
global $request;
$organizer = $resource->GetOrganizer();
$organizer_email = preg_replace( '/^mailto:/i', '', $organizer->Value() );
$organizer_principal = new Principal('email',$organizer_email );
if ( !$organizer_principal->Exists() ) {
dbg_error_log( 'schedule', 'Unknown ORGANIZER "%s" - unable to notify.', $organizer->Value() );
return true;
}
$sql = 'SELECT caldav_data.dav_name, caldav_data.caldav_data FROM caldav_data JOIN calendar_item USING(dav_id) ';
$sql .= 'WHERE caldav_data.collection_id IN (SELECT collection_id FROM collection WHERE is_calendar AND user_no =?) ';
$sql .= 'AND uid=? LIMIT 1';
$uids = $resource->GetPropertiesByPath('/VCALENDAR/*/UID');
if ( count($uids) == 0 ) {
dbg_error_log( 'schedule', 'No UID in VCALENDAR - giving up on REPLY.' );
return true;
}
$uid = $uids[0]->Value();
$qry = new AwlQuery($sql, $organizer_principal->user_no(), $uid);
if ( !$qry->Exec('schedule',__LINE__,__FILE__) || $qry->rows() < 1 ) {
dbg_error_log( 'schedule', 'Could not find original event from organizer - giving up on REPLY.' );
return true;
}
$row = $qry->Fetch();
$collection_path = preg_replace('{/[^/]+$}', '/', $row->dav_name );
$segment_name = str_replace($collection_path, '', $row->dav_name );
$vcal = new vCalendar($row->caldav_data);
$attendees = $vcal->GetAttendees();
foreach( $attendees AS $v ) {
$email = preg_replace( '/^mailto:/i', '', $v->Value() );
if ( $email == $request->principal->email() ) {
$attendee = $v;
break;
}
}
if ( empty($attendee) ) {
dbg_error_log( 'schedule', 'Could not find ATTENDEE in VEVENT - giving up on REPLY.' );
return true;
}
$attendee->SetParameterValue('PARTSTAT', $partstat);
$attendee->SetParameterValue('SCHEDULE-STATUS', '2.0');
$vcal->UpdateAttendeeStatus($request->principal->email(), clone($attendee) );
$organizer_calendar = new WritableCollection(array('path' => $collection_path));
$organizer_inbox = new WritableCollection(array('path' => $organizer_principal->internal_url('schedule-inbox')));
$schedule_reply = GetItip(new vCalendar($row->caldav_data),'REPLY',$attendee->Value());
$schedule_request = GetItip(new vCalendar($row->caldav_data),'REQUEST',null);
dbg_error_log( 'schedule', 'Writing ATTENDEE scheduling REPLY from %s to %s', $request->principal->email(), $organizer_principal->email() );
$response = '3.7'; // Organizer was not found on server.
if ( !$organizer_calendar->Exists() ) {
dbg_error_log('ERROR','Default calendar at "%s" does not exist for user "%s"',
$organizer_calendar->dav_name(), $schedule_target->username());
$response = '5.2'; // No scheduling support for user
}
else {
if ( ! $organizer_inbox->HavePrivilegeTo('schedule-deliver-reply') ) {
$response = '3.8'; // No authority to deliver replies to organizer.
}
$response = '1.2'; // Scheduling reply delivered successfully
if ( $organizer_calendar->WriteCalendarMember($vcal, false, false, $segment_name) === false ) {
dbg_error_log('ERROR','Could not write updated calendar member to %s', $attendee_calendar->dav_name() );
trace_bug('Failed to write scheduling resource.');
}
$organizer_inbox->WriteCalendarMember($schedule_reply, false, false, $request->principal->username().$segment_name);
}
dbg_error_log( 'schedule', 'Status for organizer <%s> set to "%s"', $organizer->Value(), $response );
$organizer->SetParameterValue( 'SCHEDULE-STATUS', $response );
$resource->UpdateOrganizerStatus($organizer); // Which was passed in by reference, and we're updating it here.
// Now we loop through the *other* ATTENDEEs, updating them on the status of the ATTENDEE DECLINE/ACCEPT
foreach( $attendees AS $attendee ) {
$email = preg_replace( '/^mailto:/i', '', $attendee->Value() );
if ( $email == $request->principal->email() || $email == $organizer_principal->email() ) continue;
$agent = $attendee->GetParameterValue('SCHEDULE-AGENT');
if ( !empty($agent) && $agent != 'SERVER' ) continue;
$schedule_target = new Principal('email',$email);
if ( $schedule_target->Exists() ) {
$attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar')));
if ( !$attendee_calendar->Exists() ) {
dbg_error_log('ERROR','Default calendar at "%s" does not exist for user "%s"',
$attendee_calendar->dav_name(), $schedule_target->username());
continue;
}
else {
$attendee_inbox = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-inbox')));
if ( ! $attendee_inbox->HavePrivilegeTo('schedule-deliver-invite') ) continue;
if ( $attendee_calendar->WriteCalendarMember($vcal, false) === false ) {
dbg_error_log('ERROR','Could not write updated calendar member to %s', $attendee_calendar->dav_name());
trace_bug('Failed to write scheduling resource.');
}
$attendee_inbox->WriteCalendarMember($schedule_request, false);
}
}
}
return true;
}
function GetItip( VCalendar $vcal, $method, $attendee_value ) {
$iTIP = $vcal->GetItip($method, $attendee_value );
$iTIP->AddProperty('REQUEST-STATUS','2.0');
$components = $iTIP->GetComponents();
foreach( $components AS $comp ) {
$properties = array();
foreach( $comp->GetProperties() AS $k=> $property ) {
switch( $property->Name() ) {
case 'DTSTART':
case 'DTEND':
case 'DUE':
$when = new RepeatRuleDateTime($property);
$properties[] = new vProperty( $property->Name() . ":" . $when->UTC() );
break;
default:
$properties[] = $property;
}
}
$comp->SetProperties($properties);
}
return $iTIP;
}
/**
* Handles sending the iTIP CANCEL messages to each ATTENDEE by the ORGANIZER.
* @param vCalendar $vcal What's being cancelled.
*/
function doItipOrganizerCancel( vCalendar $vcal ) {
global $request;
$attendees = $vcal->GetAttendees();
if ( count($attendees) == 0 && count($old_attendees) == 0 ) {
dbg_error_log( 'schedule', 'Event has no attendees - no scheduling required.', count($attendees) );
return true;
}
dbg_error_log( 'schedule', 'Writing scheduling resources for %d attendees', count($attendees) );
$scheduling_actions = false;
$iTIP = GetItip($vcal, 'CANCEL', null);
foreach( $attendees AS $attendee ) {
$email = preg_replace( '/^mailto:/i', '', $attendee->Value() );
if ( $email == $request->principal->email() ) {
dbg_error_log( 'schedule', "not delivering to owner '%s'", $request->principal->email() );
continue;
}
$agent = $attendee->GetParameterValue('SCHEDULE-AGENT');
if ( $agent && $agent != 'SERVER' ) {
dbg_error_log( 'schedule', "not delivering to %s, schedule agent set to value other than server", $email );
continue;
}
$schedule_target = new Principal('email',$email);
if ( !$schedule_target->Exists() ) {
$response = '3.7';
}
else {
$attendee_inbox = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-inbox')));
if ( ! $attendee_inbox->HavePrivilegeTo('schedule-deliver-invite') ) {
dbg_error_log( 'schedule', "No authority to deliver invite to %s", $schedule_target->internal_url('schedule-inbox') );
$response = '3.8';
}
else {
$attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar')));
$response = processItipCancel( $vcal, $attendee, $attendee_calendar, $schedule_target );
deliverItipCancel( $iTIP, $attendee, $attendee_inbox );
}
}
dbg_error_log( 'schedule', 'Status for attendee <%s> set to "%s"', $attendee->Value(), $response );
$attendee->SetParameterValue( 'SCHEDULE-STATUS', $response );
$scheduling_actions = true;
}
return true;
}
/**
* Does the actual processing of the iTIP CANCEL message on behalf of an ATTENDEE,
* which generally means writing it into the ATTENDEE's default calendar.
*
* @param vCalendar $vcal The message.
* @param vProperty $attendee
* @param WritableCollection $attendee_calendar
*/
function processItipCancel( vCalendar $vcal, vProperty $attendee, WritableCollection $attendee_calendar, Principal $attendee_principal ) {
dbg_error_log( 'schedule', 'Processing iTIP CANCEL to %s', $attendee->Value());
if ( !$attendee_calendar->Exists() ) {
dbg_error_log('ERROR', 'Default calendar at "%s" does not exist for attendee "%s"',
$attendee_calendar->dav_name(), $attendee->Value());
return '5.2'; // No scheduling support for user
}
$sql = 'SELECT caldav_data.dav_name FROM caldav_data JOIN calendar_item USING(dav_id) ';
$sql .= 'WHERE caldav_data.collection_id IN (SELECT collection_id FROM collection WHERE is_calendar AND user_no =?) ';
$sql .= 'AND uid=? LIMIT 1';
$uids = $vcal->GetPropertiesByPath('/VCALENDAR/*/UID');
if ( count($uids) == 0 ) {
dbg_error_log( 'schedule', 'No UID in VCALENDAR - giving up on CANCEL processing.' );
return '3.8';
}
$uid = $uids[0]->Value();
$qry = new AwlQuery($sql, $attendee_principal->user_no(), $uid);
if ( !$qry->Exec('schedule',__LINE__,__FILE__) || $qry->rows() < 1 ) {
dbg_error_log( 'schedule', 'Could not find ATTENDEE copy of original event - not trying to DELETE it!' );
return '1.2';
}
$row = $qry->Fetch();
if ( $attendee_calendar->actualDeleteCalendarMember($row->dav_name) === false ) {
dbg_error_log('ERROR', 'Could not delete calendar member %s for %s',
$row->dav_name(), $attendee->Value());
trace_bug('Failed to write scheduling resource.');
return '5.2';
}
return '1.2'; // Scheduling invitation delivered successfully
}
/**
* Delivers the iTIP CANCEL message to an ATTENDEE's Scheduling Inbox Collection.
*
* This is pretty simple at present, but could be extended in the future to do the sending
* of e-mail to a remote attendee.
*
* @param vCalendar $iTIP
* @param vProperty $attendee
* @param WritableCollection $attendee_inbox
*/
function deliverItipCancel( vCalendar $iTIP, vProperty $attendee, WritableCollection $attendee_inbox ) {
$attendee_inbox->WriteCalendarMember($iTIP, false);
}

View File

@ -34,7 +34,7 @@ switch ( $request->path ) {
if ( $c->enable_scheduling != true )
{
$request->DoResponse( 404, translate('The application program does not understand that request.') );
exit ();
// Does not return
}
header ( 'iSchedule-Version: 1.0' );
@ -103,5 +103,6 @@ RESPONSE;
</capability-set>
</query-result>
RESPONSE;
exit ( 0 );
@ob_flush(); exit(0);
}

View File

@ -10,8 +10,8 @@ msgstr ""
"Project-Id-Version: DAViCal\n"
"Report-Msgid-Bugs-To: http://repo.or.cz/w/davical.git/tree/HEAD:/issues\n"
"POT-Creation-Date: 2011-10-24 21:19+1300\n"
"PO-Revision-Date: 2011-10-24 08:21+0000\n"
"Last-Translator: karora <andrew@mcmillan.net.nz>\n"
"PO-Revision-Date: 2011-10-26 18:54+0000\n"
"Last-Translator: aleksand <daniel@aleksand.no>\n"
"Language-Team: Norwegian Bokmål (Norway) (http://www.transifex.net/projects/p/davical/team/nb_NO/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -30,7 +30,7 @@ msgid "%T"
msgstr "%T"
msgid "*** Default Locale ***"
msgstr "*** Standard Locale ***"
msgstr "*** Forvalgt Nasjonalitet ***"
msgid "*** Unknown ***"
msgstr "*** Ukjent ***"
@ -153,7 +153,7 @@ msgstr "Alle data til samlingen vil ugjenopprettelig bli slettet"
#, php-format
msgid "All events of user \"%s\" were deleted and replaced by those from file %s"
msgstr ""
msgstr "Alle \"%s\" sine hendelser ble slettet og erstattet med de fra filen %s"
msgid ""
"All of the principal's calendars and events will be unrecoverably deleted."
@ -205,7 +205,7 @@ msgid "Bindings to this Principal's Collections"
msgstr "Forbindelse til denne kontoens samlinger"
msgid "Body contains no XML data!"
msgstr ""
msgstr "Meldingskroppen inneholder ingen XML data!"
msgid "Bound As"
msgstr "Forbundet som"
@ -395,10 +395,10 @@ msgid "Date Style"
msgstr "Datoformat"
msgid "Default Privileges"
msgstr "Standard privilegier"
msgstr "Forvalgte privilegier"
msgid "Default relationships added."
msgstr ""
msgstr "La til forvalgte relasjoner."
msgid "Delete"
msgstr "Slett"
@ -525,10 +525,10 @@ msgid "Expires"
msgstr "Løper ut"
msgid "External Calendars"
msgstr ""
msgstr "Eksterne kalendere"
msgid "External Url"
msgstr ""
msgstr "Ekstern URL"
msgid "Fail"
msgstr "Feil"
@ -680,7 +680,7 @@ msgid "Last used"
msgstr "Sist brukt"
msgid "List External Calendars"
msgstr ""
msgstr "List opp eksterne kalendere"
msgid "List Groups"
msgstr "Liste grupper"
@ -788,7 +788,7 @@ msgid "PHP PostgreSQL available"
msgstr "PHP PostgreSQL tilgjengelig"
msgid "PHP calendar extension available"
msgstr ""
msgstr "PHP kalenderutvidelse er tilgjengelig."
msgid "PHP iconv support"
msgstr "Støtte for PHP iconv"
@ -804,6 +804,8 @@ msgid ""
"PUT on a collection is only allowed for text/vcard content against an "
"addressbook collection"
msgstr ""
"En PUT anmodning er kun tillatt for text/vcard innhold i en "
"adresseboksamling."
msgid "Passed"
msgstr "Godkjent"
@ -901,7 +903,7 @@ msgid "Read/Write"
msgstr "Les/Skriv"
msgid "References"
msgstr ""
msgstr "Referanser"
msgid "Remove"
msgstr "Fjern"
@ -910,7 +912,7 @@ msgid "Remove a lock"
msgstr "Fjern en lås"
msgid "Remove dangling external calendars"
msgstr ""
msgstr "Fjern haltende eksterne kalendere"
msgid "Report Bug"
msgstr "Rapporter feil"
@ -1006,6 +1008,8 @@ msgid ""
"Set the path to store your ics e.g. 'calendar' will be referenced as "
"/caldav.php/username/calendar/"
msgstr ""
"Angi en sti for lagring av ics. For eksempel kalender vil bli referert som"
" /caldav.php/brukernavn/kalender/"
msgid "Setup"
msgstr "Oppsett"
@ -1053,7 +1057,7 @@ msgid "Suhosin \"server.strip\" disabled"
msgstr "Suhosin \"server.strip\" disabled"
msgid "Sync LDAP Groups with DAViCal"
msgstr ""
msgstr "Synkroniser LDAP grupper med DAViCal"
msgid "Sync LDAP with DAViCal"
msgstr "Synk LDAP med DAViCal"
@ -1091,7 +1095,7 @@ msgid ""
msgstr "Adressebok-forespørselsrapport må kjøres mot en adressebok-samling"
msgid "The application failed to understand that request."
msgstr ""
msgstr "Programmet kunne ikke forstå den anmodningen."
msgid "The application program does not understand that request."
msgstr "Programmet forstår ikke forespørselen"
@ -1132,6 +1136,8 @@ msgstr "Epostadressen skulle absolutt ikke være tom"
#, php-format
msgid "The file \"%s\" is not UTF-8 encoded, please check error for more details"
msgstr ""
"Filen \"%s\" er ikke inkodet i UTF-8 encoded. Kontroller feilen for flere "
"detaljer."
msgid ""
"The file is not UTF-8 encoded, please check the error for more details."
@ -1154,7 +1160,7 @@ msgstr "Foretrukket språk for denne personen"
#, php-format
msgid "The principal \"%s\" does not exist"
msgstr ""
msgstr "Kontoen \"%s\" finnes ikke."
msgid "The style of dates used for this person."
msgstr "Datoformat brukt for denne personen"
@ -1219,6 +1225,8 @@ msgid ""
"This process will import each file in a directory named \"username.ics\" and"
" create a user and calendar for each file to import."
msgstr ""
"Prosesen vil hente inn hver fil i mappen med navnet \"brukernavn.ics\" og "
"opprette en bruker og kalender for hver bruker og kalender som hentes inn."
msgid "This server only supports the text/calendar format for freebusy URLs"
msgstr ""

670
po/pl.po

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,8 @@ msgstr ""
"Project-Id-Version: DAViCal\n"
"Report-Msgid-Bugs-To: http://repo.or.cz/w/davical.git/tree/HEAD:/issues\n"
"POT-Creation-Date: 2011-10-24 21:19+1300\n"
"PO-Revision-Date: 2011-10-24 08:21+0000\n"
"Last-Translator: karora <andrew@mcmillan.net.nz>\n"
"PO-Revision-Date: 2011-10-26 19:34+0000\n"
"Last-Translator: m42 <p.m42.ribeiro@gmail.com>\n"
"Language-Team: Portuguese (Portugal) (http://www.transifex.net/projects/p/davical/team/pt_PT/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -157,6 +157,8 @@ msgstr "Todos os dados da colecção serão irremediavelmente apagados"
#, php-format
msgid "All events of user \"%s\" were deleted and replaced by those from file %s"
msgstr ""
"Todos os eventos do utilizador \"%s\" foram apagados e substituídos pelos do"
" ficheiro %s"
msgid ""
"All of the principal's calendars and events will be unrecoverably deleted."
@ -210,7 +212,7 @@ msgid "Bindings to this Principal's Collections"
msgstr "Ligações às colecções deste Principal"
msgid "Body contains no XML data!"
msgstr ""
msgstr "O corpo não contém dados XML!"
msgid "Bound As"
msgstr "Ligado Como"
@ -407,7 +409,7 @@ msgid "Default Privileges"
msgstr "Privilégios predefinidos"
msgid "Default relationships added."
msgstr ""
msgstr "Acrescentados relacionamentos predefinidos"
msgid "Delete"
msgstr "Eliminar"
@ -541,10 +543,10 @@ msgid "Expires"
msgstr "Expira"
msgid "External Calendars"
msgstr ""
msgstr "Calendários Externos"
msgid "External Url"
msgstr ""
msgstr "Url Externo"
msgid "Fail"
msgstr "Falha"
@ -696,7 +698,7 @@ msgid "Last used"
msgstr "Último usado"
msgid "List External Calendars"
msgstr ""
msgstr "Listar Calendários Externos"
msgid "List Groups"
msgstr "Listar Grupos"
@ -762,7 +764,7 @@ msgstr "Sem sumário"
#. Translators: short for 'Number'
msgid "No."
msgstr "Não."
msgstr "Núm."
msgid "No. of Collections"
msgstr "Núm. de colecções"
@ -804,7 +806,7 @@ msgid "PHP PostgreSQL available"
msgstr "PHP PostgreSQL disponível"
msgid "PHP calendar extension available"
msgstr ""
msgstr "Extensão PHP para calendários disponível"
msgid "PHP iconv support"
msgstr "Suporte iconv do PHP"
@ -813,13 +815,15 @@ msgid ""
"PUT on a collection is only allowed for text/calendar content against a "
"calendar collection"
msgstr ""
"PUT numa colecção é apenas permitido para conteúdo de texto/calendário em "
"face de uma colecção de calendário"
"PUT de conteúdo text/calendar apenas é permitido numa colecção do tipo "
"calendário"
msgid ""
"PUT on a collection is only allowed for text/vcard content against an "
"addressbook collection"
msgstr ""
"PUT de conteúdo text/vcard apenas é permitido numa colecção do tipo livro de"
" endereços"
msgid "Passed"
msgstr "Passou"
@ -918,7 +922,7 @@ msgid "Read/Write"
msgstr "Ler/Escrever"
msgid "References"
msgstr ""
msgstr "Referências"
msgid "Remove"
msgstr "Remover"
@ -927,7 +931,7 @@ msgid "Remove a lock"
msgstr "Remover um lock"
msgid "Remove dangling external calendars"
msgstr ""
msgstr "Remover calendários externos com problemas"
msgid "Report Bug"
msgstr "Relatar um bug"
@ -1027,6 +1031,8 @@ msgid ""
"Set the path to store your ics e.g. 'calendar' will be referenced as "
"/caldav.php/username/calendar/"
msgstr ""
"Definir o caminho para guardar o seu ficheiro ics - e.g. 'calendar' será "
"referido como /caldav.php/nome_de_utilizador/calendar/"
msgid "Setup"
msgstr "Configurar"
@ -1075,7 +1081,7 @@ msgid "Suhosin \"server.strip\" disabled"
msgstr "\"server.strip\" do suhosin desabilitado"
msgid "Sync LDAP Groups with DAViCal"
msgstr ""
msgstr "Sincronizar Grupos LDAP com o DAViCal"
msgid "Sync LDAP with DAViCal"
msgstr "Sincronizar LDAP com o DAViCal"
@ -1117,7 +1123,7 @@ msgstr ""
"livros de endereços"
msgid "The application failed to understand that request."
msgstr ""
msgstr "A aplicação não conseguiu entender esse pedido."
msgid "The application program does not understand that request."
msgstr "O programa não entende esse pedido."
@ -1159,6 +1165,8 @@ msgstr "O endereço de email não devia, de facto, ficar em branco."
#, php-format
msgid "The file \"%s\" is not UTF-8 encoded, please check error for more details"
msgstr ""
"O ficheiro \"%s\" não está codificado como UTF-8, por favor verifique a "
"mensagem de erro para mais promenores"
msgid ""
"The file is not UTF-8 encoded, please check the error for more details."
@ -1183,7 +1191,7 @@ msgstr "O idioma preferido para esta pessoa."
#, php-format
msgid "The principal \"%s\" does not exist"
msgstr ""
msgstr "O principal \"%s\" não existe"
msgid "The style of dates used for this person."
msgstr "O estilo de datas em uso para esta pessoa."
@ -1251,6 +1259,8 @@ msgid ""
"This process will import each file in a directory named \"username.ics\" and"
" create a user and calendar for each file to import."
msgstr ""
"Este processo irá importar cada ficheiro chamado \"nome_de_utilizador.ics\" "
"ecriar um utilizador e calendário para cada ficheiro."
msgid "This server only supports the text/calendar format for freebusy URLs"
msgstr ""

54
scripts/refresh-alarms.php Normal file → Executable file
View File

@ -1,29 +1,18 @@
#!/usr/bin/php
#!/usr/bin/env php
<?php
/**
* Script to refresh the pending alarm times for the next alarm instance.
*
* @package davical
* @subpackage alarms
* @author Andrew McMillan <andrew@morphoss.com>
* @copyright Morphoss Ltd
* @license http://gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$script_file = __FILE__;
set_include_path('.');
function add_path_for( $include, $paths ) {
foreach( $paths AS $test_path ) {
if ( @file_exists($test_path.'/'.$include) ) {
set_include_path( $test_path. PATH_SEPARATOR. get_include_path());
return;
}
}
}
add_path_for('AWLUtilities.php', array( '../../awl/inc' , '../awl/inc'
, '../../../awl/inc' , '/usr/share/awl/inc' , '/usr/local/share/awl/inc') );
add_path_for('caldav-client-v2.php', array( '../../davical/inc' , '../davical/inc'
, '../../../davical/inc' , '/usr/share/davical/inc' , '/usr/local/share/davical/inc') );
add_path_for('always.php', array( 'scripts' ) );
add_path_for('sync-config.php', array( 'config' ) );
require('always.php');
require_once('AwlQuery.php');
require_once('RRule-v2.php');
require_once('vComponent.php');
chdir(str_replace('/scripts/refresh-alarms.php','/htdocs',$script_file));
$_SERVER['SERVER_NAME'] = 'localhost';
/**
* Call with something like e.g.:
@ -41,15 +30,17 @@ $args->near_past = 'P1D';
$args->far_past = 'P1200D';
$debugging = null;
function parse_arguments() {
global $args;
$opts = getopt( 'f:p:n:d:lh' );
$opts = getopt( 'f:p:s:n:d:lh' );
foreach( $opts AS $k => $v ) {
switch( $k ) {
case 'f': $args->future = $v; break;
case 'n': $args->near_past = $v; break;
case 'p': $args->far_past = $v; break;
case 's': $_SERVER['SERVER_NAME'] = $v; break;
case 'd': $args->debug = true; $debugging = explode(',',$v); break;
case 'l': $args->set_last = true; break;
case 'h': usage(); break;
@ -59,9 +50,10 @@ function parse_arguments() {
}
function usage() {
echo <<<EOUSAGE
echo <<<USAGE
Usage:
refresh-alarms.php [-d]
refresh-alarms.php [-s server.domain.tld] [-d] [other options]
-n <duration> Near past period to skip for finding last instances: default 1 days ('P1D')
-p <duration> Far past period to examine for finding last instances: default ~3 years ('P1200D')
@ -71,8 +63,7 @@ Usage:
-d Enable debugging
EOUSAGE;
USAGE;
exit(0);
}
@ -86,6 +77,11 @@ if ( $args->debug && is_array($debugging )) {
$args->near_past = '-' . $args->near_past;
$args->far_past = '-' . $args->far_past;
require_once("./always.php");
require_once('AwlQuery.php');
require_once('RRule-v2.php');
require_once('vComponent.php');
/**
* Essentially what we are doing is:

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8" ?>
<multistatus xmlns="DAV:" xmlns:VC="urn:ietf:params:xml:ns:carddav">
<response>
<href>/caldav.php/user1/addressbook/andrew_mcmillan.vcf</href>
<propstat>
<prop>
<VC:address-data>BEGIN:VCARD
VERSION:3.0
REV:2010-03-29T09:23:34Z
UID:pas-id-4BB0719600000000
X-SKYPE;X-EVOLUTION-UI-SLOT=1;TYPE=HOME:karora__
X-JABBER;X-EVOLUTION-UI-SLOT=3;TYPE=HOME:karora@irc.oftc.net
TEL;X-EVOLUTION-UI-SLOT=3;TYPE=CELL:+64 22 123 4567
TEL;X-EVOLUTION-UI-SLOT=2;TYPE=HOME,VOICE:+64 4 123 4567
TEL;X-EVOLUTION-UI-SLOT=1;TYPE=WORK,VOICE:+64 22 123 4567
EMAIL;X-EVOLUTION-UI-SLOT=2;TYPE=HOME:andrew@mcmillan.net.nz
EMAIL;X-EVOLUTION-UI-SLOT=1;TYPE=WORK:andrew@morphoss.com
LABEL;TYPE=HOME:16 Kaka Place\nPorikana\n4173\nNew Zealand
ADR;TYPE=HOME:;;16 Kaka Place;Porikana;;4173;New Zealand
X-MOZILLA-HTML:FALSE
X-EVOLUTION-VIDEO-URL:
FBURL:https://davical.morphoss.com/freebusy.php/andrew@morphoss.com
CALADRURI:mailto:andrew@morphoss.com
CALURI:https://dotcal.com/karora
X-EVOLUTION-BLOG-URL:http://andrew.mcmillan.net.nz/
CATEGORIES:Developer,Personal,Debian,
X-EVOLUTION-FILE-AS:McMillan\, Andrew
N:McMillan;Andrew;Watson;;
FN:Andrew Watson McMillan
NOTE:Primary author of DAViCal CalDAV Server.
X-EVOLUTION-SPOUSE:Heather Buchanan
X-EVOLUTION-ANNIVERSARY:1989-04-22
BDAY:1958-07-26
NICKNAME:karora
X-EVOLUTION-ASSISTANT:
X-EVOLUTION-MANAGER:
ROLE:Geek
ORG:dotCal;;Porirua
TITLE:Chief Technology Officer
URL:http://andrew.mcmillan.net.nz/
END:VCARD
</VC:address-data>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>

View File

@ -0,0 +1,28 @@
#
# Request a REPORT
#
TYPE=REPORT
URL=http://mycaldav/caldav.php/user1/addressbook/
HEADER=Accept: text/xml,application/xml
HEADER=Content-Type: text/xml
HEADER=Depth: 1
# HEAD
BEGINDATA
<?xml version="1.0" encoding="utf-8" ?>
<C:addressbook-query xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:carddav">
<D:prop>
<C:address-data/>
</D:prop>
<C:filter>
<C:prop-filter name="NICKNAME">
<C:text-match collation="i;unicode-casemap"
match-type="equals"
>karora</C:text-match>
</C:prop-filter>
</C:filter>
</C:addressbook-query>
ENDDATA

View File

@ -2,8 +2,8 @@ HTTP/1.1 207 Multi-Status
Date: Dow, 01 Jan 2000 00:00:00 GMT
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule
ETag: "452f45250e12e66d9f6db823b4615a48"
Content-Length: 3503
ETag: "987fc68a44b7bc99bdf6fe3ab2d0b0ad"
Content-Length: 3587
Content-Type: text/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
@ -60,6 +60,16 @@ END:VCALENDAR
<C:calendar-data>BEGIN:VCALENDAR
PRODID:-//Mozilla Calendar//NONSGML Sunbird//EN
VERSION:2.0
BEGIN:VEVENT
CREATED:20061223T032350Z
LAST-MODIFIED:20061223T033144Z
DTSTAMP:20061223T033144Z
UID:9d050be7-8a02-4355-8ed3-02a9fc5f473f
CLASS:CONFIDENTIAL
DTSTART;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T160000
DTEND;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T180000
SUMMARY:Busy
END:VEVENT
BEGIN:VTIMEZONE
TZID:/mozilla.org/20050126_1/Antarctica/McMurdo
X-LIC-LOCATION:Antarctica/McMurdo
@ -78,13 +88,6 @@ DTSTART:19701004T020000
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=10
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:Busy
CLASS:CONFIDENTIAL
DTSTART;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T160000
DTEND;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T180000
UID:9d050be7-8a02-4355-8ed3-02a9fc5f473f
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</prop>

View File

@ -2,8 +2,8 @@ HTTP/1.1 207 Multi-Status
Date: Dow, 01 Jan 2000 00:00:00 GMT
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, calendar-proxy, bind, addressbook
ETag: "452f45250e12e66d9f6db823b4615a48"
Content-Length: 3503
ETag: "987fc68a44b7bc99bdf6fe3ab2d0b0ad"
Content-Length: 3587
Content-Type: text/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
@ -60,6 +60,16 @@ END:VCALENDAR
<C:calendar-data>BEGIN:VCALENDAR
PRODID:-//Mozilla Calendar//NONSGML Sunbird//EN
VERSION:2.0
BEGIN:VEVENT
CREATED:20061223T032350Z
LAST-MODIFIED:20061223T033144Z
DTSTAMP:20061223T033144Z
UID:9d050be7-8a02-4355-8ed3-02a9fc5f473f
CLASS:CONFIDENTIAL
DTSTART;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T160000
DTEND;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T180000
SUMMARY:Busy
END:VEVENT
BEGIN:VTIMEZONE
TZID:/mozilla.org/20050126_1/Antarctica/McMurdo
X-LIC-LOCATION:Antarctica/McMurdo
@ -78,13 +88,6 @@ DTSTART:19701004T020000
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=10
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:Busy
CLASS:CONFIDENTIAL
DTSTART;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T160000
DTEND;TZID=/mozilla.org/20050126_1/Antarctica/McMurdo:20061223T180000
UID:9d050be7-8a02-4355-8ed3-02a9fc5f473f
END:VEVENT
END:VCALENDAR
</C:calendar-data>
</prop>

View File

@ -29,16 +29,16 @@ BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T110000
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:user1@example.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T100000
DTSTAMP:20111018T200107Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:5
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:user1@example.net
END:VEVENT
END:VCALENDAR
<
@ -118,16 +118,16 @@ BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T110000
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:user1@example.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T100000
DTSTAMP:20111018T200107Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:5
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:user1@example.net
END:VEVENT
END:VCALENDAR
<

View File

@ -127,16 +127,16 @@ BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T110000
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:user1@example.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T100000
DTSTAMP:20111018T200107Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:5
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:user1@example.net
END:VEVENT
END:VCALENDAR
<

View File

@ -5,7 +5,7 @@ TYPE=PUT
URL=http://regression.host/caldav.php/manager1/home/E1A13F04-iCal-schedule.ics
HEADER=Content-Type: text/calendar
HEADER=DAVKit/4.0.3 (732.2); CalendarStore/4.0.4 (997.7); iCal/4.0.4 (1395.7); Mac OS X/10.6.8 (10K549)
HEADER=If-Match: "87421a4ff0b84a95a31db428ee6d11d9"
HEADER=If-Match: "d60f8959edc5eee6e949a2e5b81dd746"
HEAD
AUTH=manager1:manager1

View File

@ -0,0 +1,14 @@
HTTP/1.1 204 No Content
Date: Dow, 01 Jan 2000 00:00:00 GMT
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule
Content-Length: 0
Content-Type: text/plain; charset="utf-8"
dav_name: >/manager1/home/E1A13F04-iCal-schedule.ics<
dav_name: >/user1/home/E1A13F04-iCal-schedule.ics<
dav_name: >/manager1/.in/user1E1A13F04-iCal-schedule.ics<

View File

@ -0,0 +1,18 @@
#
# iCal DELETE's the invitation in the .in
#
TYPE=DELETE
URL=http://regression.host/user1/.in/E1A13F04-iCal-schedule.ics
HEADER=User-Agent: DAVKit/4.0.3 (732.2); CalendarStore/4.0.4 (997.7); iCal/4.0.4 (1395.7); Mac OS X/10.6.8 (10K549)
HEAD
#
# Query to confirm we got rid of it. There should be two now.
QUERY
SELECT dav_name
FROM calendar_item
WHERE uid = 'E1A13F04-iCal-schedule'
ORDER BY dav_id
ENDQUERY

View File

@ -0,0 +1,12 @@
HTTP/1.1 204 No Content
Date: Dow, 01 Jan 2000 00:00:00 GMT
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule
Content-Length: 0
Content-Type: text/plain; charset="utf-8"
dav_name: >/manager1/home/E1A13F04-iCal-schedule.ics<
dav_name: >/user1/home/E1A13F04-iCal-schedule.ics<

View File

@ -0,0 +1,20 @@
#
# iCal DELETE's the invitation in the .in
#
TYPE=DELETE
URL=http://regression.host/manager1/.in/user1E1A13F04-iCal-schedule.ics
HEADER=User-Agent: DAVKit/4.0.3 (732.2); CalendarStore/4.0.4 (997.7); iCal/4.0.4 (1395.7); Mac OS X/10.6.8 (10K549)
HEAD
AUTH=manager1:manager1
#
# Query to confirm we got rid of it. There should be two now.
QUERY
SELECT dav_name
FROM calendar_item
WHERE uid = 'E1A13F04-iCal-schedule'
ORDER BY dav_id
ENDQUERY

View File

@ -0,0 +1,70 @@
HTTP/1.1 204 No Content
Date: Dow, 01 Jan 2000 00:00:00 GMT
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule
Content-Length: 0
Content-Type: text/plain; charset="utf-8"
dav_name: >/manager1/home/E1A13F04-iCal-schedule.ics<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:looks good
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:6
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=DECLINED;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=2.0:mai
lto:user1@example.net
END:VEVENT
END:VCALENDAR
<
dav_name: >/manager1/.in/user1E1A13F04-iCal-schedule.ics<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
METHOD:REPLY
REQUEST-STATUS:2.0
BEGIN:VEVENT
UID:E1A13F04-iCal-schedule
DTEND:20111019T010000Z
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user1@example.net
DTSTART:20111019T000000Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
DTSTAMP:looks good
END:VEVENT
END:VCALENDAR
<

View File

@ -0,0 +1,23 @@
#
# We now DELETE the ATTENDEE's copy of the actual event.
# - This should send a CANCEL reply and update the manager's
# event copy with the PARTSTAT=DECLINED
#
TYPE=DELETE
URL=http://regression.host/user1/home/E1A13F04-iCal-schedule.ics
HEADER=User-Agent: DAVKit/4.0.3 (732.2); CalendarStore/4.0.4 (997.7); iCal/4.0.4 (1395.7); Mac OS X/10.6.8 (10K549)
HEAD
#
# Query to confirm we got rid of it. There should be two now:
# - An event in the manager's calendar, with a PARTSTART=DECLINED for user 1
# - An iTIP message in the managers's inbox.
QUERY
SELECT calendar_item.dav_name,
regexp_replace(caldav_data,'DTSTAMP:[0-9T]{15}Z','DTSTAMP:looks good') AS vcalendar
FROM calendar_item JOIN caldav_data USING(dav_id, dav_name)
WHERE uid = 'E1A13F04-iCal-schedule'
ORDER BY dav_id
ENDQUERY

View File

@ -0,0 +1,10 @@
HTTP/1.1 204 No Content
Date: Dow, 01 Jan 2000 00:00:00 GMT
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule
Content-Length: 0
Content-Type: text/plain; charset="utf-8"
dav_name: >/manager1/home/E1A13F04-iCal-schedule.ics<

View File

@ -0,0 +1,21 @@
#
# Now DELETE's the cancelation reply in the Manager's .in
#
TYPE=DELETE
URL=http://regression.host/manager1/.in/user1E1A13F04-iCal-schedule.ics
HEADER=User-Agent: DAVKit/4.0.3 (732.2); CalendarStore/4.0.4 (997.7); iCal/4.0.4 (1395.7); Mac OS X/10.6.8 (10K549)
HEAD
AUTH=manager1:manager1
#
# Query to confirm we got rid of it. There should only be one
# lonely meeting in the manager's calendar (which has been declined).
QUERY
SELECT dav_name
FROM calendar_item
WHERE uid = 'E1A13F04-iCal-schedule'
ORDER BY dav_id
ENDQUERY

View File

@ -0,0 +1,370 @@
HTTP/1.1 100 Continue
HTTP/1.1 204 No Content
Date: Dow, 01 Jan 2000 00:00:00 GMT
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule
Content-Length: 0
Content-Type: text/plain; charset="utf-8"
caldav_type: >VEVENT<
dav_name: >/manager1/home/E1A13F04-iCal-schedule.ics<
logged_user: >20<
summary: >Meeting with User1<
user_no: >20<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user1@example.net
ATTENDEE;CN=user2@example.net;CUTYPE=INDIVIDUAL;EMAIL=user2@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user2@example.net
ATTENDEE;CN=user3@example.net;CUTYPE=INDIVIDUAL;EMAIL=user3@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user3@example.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:20111024T035702Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
caldav_type: >VEVENT<
dav_name: >/user1/.in/E1A13F04-iCal-schedule.ics<
logged_user: >20<
summary: >Meeting with User1<
user_no: >10<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
ATTENDEE;CN="Manager 1";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:manag
er1@example.net
ATTENDEE;CN="user1@example.net";CUTYPE=INDIVIDUAL;EMAIL="user1@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user1@ex
ample.net
ATTENDEE;CN="user2@example.net";CUTYPE=INDIVIDUAL;EMAIL="user2@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user2@ex
ample.net
ATTENDEE;CN="user3@example.net";CUTYPE=INDIVIDUAL;EMAIL="user3@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user3@ex
ample.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:20111024T035702Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
caldav_type: >VEVENT<
dav_name: >/user1/home/E1A13F04-iCal-schedule.ics<
logged_user: >20<
summary: >Meeting with User1<
user_no: >10<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
ATTENDEE;CN="Manager 1";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:manag
er1@example.net
ATTENDEE;CN="user1@example.net";CUTYPE=INDIVIDUAL;EMAIL="user1@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user1@ex
ample.net
ATTENDEE;CN="user2@example.net";CUTYPE=INDIVIDUAL;EMAIL="user2@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user2@ex
ample.net
ATTENDEE;CN="user3@example.net";CUTYPE=INDIVIDUAL;EMAIL="user3@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user3@ex
ample.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:20111024T035702Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
caldav_type: >VEVENT<
dav_name: >/user2/.in/E1A13F04-iCal-schedule.ics<
logged_user: >20<
summary: >Meeting with User1<
user_no: >11<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
ATTENDEE;CN="Manager 1";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:manag
er1@example.net
ATTENDEE;CN="user1@example.net";CUTYPE=INDIVIDUAL;EMAIL="user1@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user1@ex
ample.net
ATTENDEE;CN="user2@example.net";CUTYPE=INDIVIDUAL;EMAIL="user2@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user2@ex
ample.net
ATTENDEE;CN="user3@example.net";CUTYPE=INDIVIDUAL;EMAIL="user3@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user3@ex
ample.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:20111024T035702Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
caldav_type: >VEVENT<
dav_name: >/user2/home/E1A13F04-iCal-schedule.ics<
logged_user: >20<
summary: >Meeting with User1<
user_no: >11<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
ATTENDEE;CN="Manager 1";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:manag
er1@example.net
ATTENDEE;CN="user1@example.net";CUTYPE=INDIVIDUAL;EMAIL="user1@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user1@ex
ample.net
ATTENDEE;CN="user2@example.net";CUTYPE=INDIVIDUAL;EMAIL="user2@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user2@ex
ample.net
ATTENDEE;CN="user3@example.net";CUTYPE=INDIVIDUAL;EMAIL="user3@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user3@ex
ample.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:20111024T035702Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
caldav_type: >VEVENT<
dav_name: >/user3/.in/E1A13F04-iCal-schedule.ics<
logged_user: >20<
summary: >Meeting with User1<
user_no: >12<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
ATTENDEE;CN="Manager 1";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:manag
er1@example.net
ATTENDEE;CN="user1@example.net";CUTYPE=INDIVIDUAL;EMAIL="user1@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user1@ex
ample.net
ATTENDEE;CN="user2@example.net";CUTYPE=INDIVIDUAL;EMAIL="user2@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user2@ex
ample.net
ATTENDEE;CN="user3@example.net";CUTYPE=INDIVIDUAL;EMAIL="user3@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user3@ex
ample.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:20111024T035702Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
caldav_type: >VEVENT<
dav_name: >/user3/home/E1A13F04-iCal-schedule.ics<
logged_user: >20<
summary: >Meeting with User1<
user_no: >12<
vcalendar: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
ATTENDEE;CN="Manager 1";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:manag
er1@example.net
ATTENDEE;CN="user1@example.net";CUTYPE=INDIVIDUAL;EMAIL="user1@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user1@ex
ample.net
ATTENDEE;CN="user2@example.net";CUTYPE=INDIVIDUAL;EMAIL="user2@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user2@ex
ample.net
ATTENDEE;CN="user3@example.net";CUTYPE=INDIVIDUAL;EMAIL="user3@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user3@ex
ample.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:20111024T035702Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<

View File

@ -0,0 +1,72 @@
#
# PUT an event with several attendees - so we can delete the organizer
# copy in the next request.
#
# After this we should see 7 events: 1 manager, 3 attendees, 3 attendee iTIP
#
TYPE=PUT
URL=http://regression.host/caldav.php/manager1/home/E1A13F04-iCal-schedule.ics
HEADER=Content-Type: text/calendar
HEADER=DAVKit/4.0.3 (732.2); CalendarStore/4.0.4 (997.7); iCal/4.0.4 (1395.7); Mac OS X/10.6.8 (10K549)
HEAD
AUTH=manager1:manager1
BEGINDATA
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Pacific/Auckland
BEGIN:DAYLIGHT
TZOFFSETFROM:+1200
RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU
DTSTART:20070930T020000
TZNAME:GMT+13:00
TZOFFSETTO:+1300
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+1300
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
DTSTART:20080406T030000
TZNAME:GMT+12:00
TZOFFSETTO:+1200
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20111018T195845Z
UID:E1A13F04-iCal-schedule
DTEND;TZID=Pacific/Auckland:20111019T140000
ATTENDEE;CN="Manager 1";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:manag
er1@example.net
ATTENDEE;CN="user1@example.net";CUTYPE=INDIVIDUAL;EMAIL="user1@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user1@ex
ample.net
ATTENDEE;CN="user2@example.net";CUTYPE=INDIVIDUAL;EMAIL="user2@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user2@ex
ample.net
ATTENDEE;CN="user3@example.net";CUTYPE=INDIVIDUAL;EMAIL="user3@example.n
et";PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:user3@ex
ample.net
TRANSP:OPAQUE
SUMMARY:Meeting with User1
DTSTART;TZID=Pacific/Auckland:20111019T130000
DTSTAMP:20111024T035702Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
ENDDATA
QUERY
SELECT caldav_data.user_no, caldav_data.dav_name,
caldav_type, logged_user, caldav_data.caldav_data AS "vcalendar",
summary
FROM caldav_data JOIN calendar_item USING(dav_name) LEFT JOIN timezones ON (tz_id=tzid)
WHERE calendar_item.uid = 'E1A13F04-iCal-schedule'
ORDER BY caldav_data.dav_id
ENDQUERY

View File

@ -0,0 +1,95 @@
SQL executed successfully.
DELETE FROM caldav_data WHERE dav_name ~ E'/\\.in/.*E1A13F04-iCal-schedule\\.ics'
HTTP/1.1 204 No Content
Date: Dow, 01 Jan 2000 00:00:00 GMT
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, calendar-proxy, bind, addressbook, calendar-auto-schedule
Content-Length: 0
Content-Type: text/plain; charset="utf-8"
caldav_data: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
METHOD:CANCEL
REQUEST-STATUS:2.0
BEGIN:VEVENT
UID:E1A13F04-iCal-schedule
DTEND:20111019T010000Z
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user1@example.net
ATTENDEE;CN=user2@example.net;CUTYPE=INDIVIDUAL;EMAIL=user2@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user2@example.net
ATTENDEE;CN=user3@example.net;CUTYPE=INDIVIDUAL;EMAIL=user3@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user3@example.net
DTSTART:20111019T000000Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
dav_name: >/user1/.in/E1A13F04-iCal-schedule.ics<
caldav_data: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
METHOD:CANCEL
REQUEST-STATUS:2.0
BEGIN:VEVENT
UID:E1A13F04-iCal-schedule
DTEND:20111019T010000Z
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user1@example.net
ATTENDEE;CN=user2@example.net;CUTYPE=INDIVIDUAL;EMAIL=user2@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user2@example.net
ATTENDEE;CN=user3@example.net;CUTYPE=INDIVIDUAL;EMAIL=user3@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user3@example.net
DTSTART:20111019T000000Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
dav_name: >/user2/.in/E1A13F04-iCal-schedule.ics<
caldav_data: >BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
METHOD:CANCEL
REQUEST-STATUS:2.0
BEGIN:VEVENT
UID:E1A13F04-iCal-schedule
DTEND:20111019T010000Z
ATTENDEE;CN=Manager 1;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:
mailto:manager1@example.net
ATTENDEE;CN=user1@example.net;CUTYPE=INDIVIDUAL;EMAIL=user1@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user1@example.net
ATTENDEE;CN=user2@example.net;CUTYPE=INDIVIDUAL;EMAIL=user2@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user2@example.net
ATTENDEE;CN=user3@example.net;CUTYPE=INDIVIDUAL;EMAIL=user3@example.net;
PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2
:mailto:user3@example.net
DTSTART:20111019T000000Z
ORGANIZER;CN="Manager 1":mailto:manager1@example.net
SEQUENCE:7
END:VEVENT
END:VCALENDAR
<
dav_name: >/user3/.in/E1A13F04-iCal-schedule.ics<

View File

@ -0,0 +1,31 @@
#
# We now DELETE the ORGANIZER's copy of the actual event.
# - This should send a CANCEL reply and remove each attendee's
# copy of the event
#
TYPE=DELETE
URL=http://regression.host/manager1/home/E1A13F04-iCal-schedule.ics
HEADER=User-Agent: DAVKit/4.0.3 (732.2); CalendarStore/4.0.4 (997.7); iCal/4.0.4 (1395.7); Mac OS X/10.6.8 (10K549)
HEAD
AUTH=manager1:manager1
# Before we run, this time we'll assume everyone has read their inbox
# and all existing iTIP messages are deleted.
DOSQL
DELETE FROM caldav_data WHERE dav_name ~ E'/\\.in/.*E1A13F04-iCal-schedule\\.ics'
ENDDOSQL
#
# Query to confirm we got rid of it. There should be two now:
# - An event in the manager's calendar, with a PARTSTART=DECLINED for user 1
# - An iTIP message in the managers's inbox.
QUERY
SELECT calendar_item.dav_name,
caldav_data.caldav_data
FROM calendar_item JOIN caldav_data USING(dav_id, dav_name)
WHERE uid = 'E1A13F04-iCal-schedule'
ORDER BY dav_id
ENDQUERY

View File

@ -1,6 +1,6 @@
setval
--------
1657
1667
(1 row)
setval