[CalendarServer-changes] [1839]
source_changes at macosforge.org
source_changes at macosforge.org
Tue Sep 4 09:59:40 PDT 2007
Revision: 1839
http://trac.macosforge.org/projects/calendarserver/changeset/1839
Author: cdaboo at apple.com
Date: 2007-09-04 09:59:39 -0700 (Tue, 04 Sep 2007)
Log Message:
-----------
Support for handling REQUEST and CANCEL on recurrence instances with tests. The old code for REQUEST is still present and will
be removed in a future commit once all testing is done. Tests only cover the CANCEL operation right now.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/better-itip-1835/twistedcaldav/ical.py
CalendarServer/branches/users/cdaboo/better-itip-1835/twistedcaldav/itip.py
Added Paths:
-----------
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/1.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/10.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/11.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/12.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/13.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/14.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/2.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/3.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/4.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/5.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/6.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/7.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/8.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/9.ics
CalDAVTester/branches/users/cdaboo/better-itip-1837/scripts/tests/schedulepostautorecur.xml
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/1.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/1.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/1.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,18 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:REQUEST
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/10.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/10.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/10.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,73 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060209T200000Z
+DTEND:20060209T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+RECURRENCE-ID:20060216T200000Z
+DTSTART:20060216T210000Z
+DTEND:20060216T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+RECURRENCE-ID:20060223T200000Z
+DTSTART:20060223T210000Z
+DTEND:20060223T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+RECURRENCE-ID:20060309T200000Z
+DTSTART:20060309T210000Z
+DTEND:20060309T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+RECURRENCE-ID:20060323T200000Z
+DTSTART:20060324T210000Z
+DTEND:20060324T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/11.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/11.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/11.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,20 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:CANCEL
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060216T210000Z
+DTEND:20060216T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060216T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:1
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/12.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/12.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/12.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,61 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060209T200000Z
+DTEND:20060209T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+EXDATE:20060216T200000Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:1
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+RECURRENCE-ID:20060223T200000Z
+DTSTART:20060223T210000Z
+DTEND:20060223T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+RECURRENCE-ID:20060309T200000Z
+DTSTART:20060309T210000Z
+DTEND:20060309T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+RECURRENCE-ID:20060323T200000Z
+DTSTART:20060324T210000Z
+DTEND:20060324T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/13.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/13.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/13.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,35 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:CANCEL
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060223T210000Z
+DTEND:20060223T220000Z
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060223T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:2
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060309T210000Z
+DTEND:20060309T220000Z
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060309T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:2
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/14.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/14.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/14.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,34 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060209T200000Z
+DTEND:20060209T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+EXDATE:20060216T200000Z
+EXDATE:20060223T200000Z,20060309T200000Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:2
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+RECURRENCE-ID:20060323T200000Z
+DTSTART:20060324T210000Z
+DTEND:20060324T220000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/2.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/2.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/2.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,17 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/3.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/3.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/3.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,20 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:CANCEL
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060215T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:1
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/4.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/4.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/4.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,19 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+EXDATE:20060215T200000Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:1
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/5.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/5.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/5.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,50 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:CANCEL
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060308T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:2
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060322T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:2
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060405T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:2
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/6.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/6.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/6.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,20 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+EXDATE:20060215T200000Z
+EXDATE:20060308T200000Z,20060322T200000Z,20060405T200000Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:2
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/7.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/7.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/7.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,20 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:CANCEL
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-1
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060419T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:1
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/8.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/8.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/8.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,20 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:CANCEL
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-2
+DTSTART:20060208T200000Z
+DTEND:20060208T210000Z
+ATTENDEE;PARTSTAT=ACCEPTED;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060419T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SEQUENCE:1
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/9.ics
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/9.ics (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/Resource/scheduleautorecur/9.ics 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,74 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:REQUEST
+PRODID:-//ORACLE//NONSGML Windows Desktop Calendar 10.1.2.0.5.278//EN
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060209T200000Z
+DTEND:20060209T210000Z
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060216T210000Z
+DTEND:20060216T220000Z
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060216T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060223T210000Z
+DTEND:20060223T220000Z
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060223T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060309T210000Z
+DTEND:20060309T220000Z
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060309T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:20060110T231240Z-4011c71-187-6f73-3
+DTSTART:20060324T210000Z
+DTEND:20060324T220000Z
+ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Resource 01:$rcuaddralt1:
+CREATED:20060110T231240Z
+DESCRIPTION:+1 605 990 0100\nAccess: 879307#
+DTSTAMP:20060309T185105Z
+ORGANIZER;CN=Cyrus Daboo:$cuaddralt1:
+RECURRENCE-ID:20060323T200000Z
+RRULE:FREQ=WEEKLY;COUNT=20
+SUMMARY:TC Realtime
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
Added: CalDAVTester/branches/users/cdaboo/better-itip-1837/scripts/tests/schedulepostautorecur.xml
===================================================================
--- CalDAVTester/branches/users/cdaboo/better-itip-1837/scripts/tests/schedulepostautorecur.xml (rev 0)
+++ CalDAVTester/branches/users/cdaboo/better-itip-1837/scripts/tests/schedulepostautorecur.xml 2007-09-04 16:59:39 UTC (rev 1839)
@@ -0,0 +1,640 @@
+<?xml version="1.0" standalone="no"?>
+
+<!DOCTYPE caldavtest SYSTEM "caldavtest.dtd">
+
+<!--
+ Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ DRI: Cyrus Daboo, cdaboo at apple.com
+ -->
+
+<caldavtest>
+ <description>Test iTIP with recurrence instances</description>
+
+ <start>
+ <request>
+ <method>DELETEALL</method>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ </request>
+ <request>
+ <method>DELETEALL</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ </request>
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$rpathprefix1:/$outbox:/</ruri>
+ </request>
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ </request>
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ </request>
+ </start>
+
+ <test-suite name='POST recurring' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Do POST</description>
+ <request>
+ <method>POST</method>
+ <header>
+ <name>Originator</name>
+ <value>$cuaddralt1:</value>
+ </header>
+ <header>
+ <name>Recipient</name>
+ <value>$rcuaddralt1:</value>
+ </header>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/scheduleautorecur/1.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELAY</method>
+ <ruri>6</ruri>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>No items in resource01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>0</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>One item in resource01 Calendar</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>GETNEW</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ <verify>
+ <callback>dataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/scheduleautorecur/2.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>One item in user01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>1</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='POST cancel one instance' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Do POST</description>
+ <request>
+ <method>POST</method>
+ <header>
+ <name>Originator</name>
+ <value>$cuaddralt1:</value>
+ </header>
+ <header>
+ <name>Recipient</name>
+ <value>$rcuaddralt1:</value>
+ </header>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/scheduleautorecur/3.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELAY</method>
+ <ruri>4</ruri>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>No items in resource01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>0</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>One item in resource01 Calendar</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>GETNEW</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ <verify>
+ <callback>dataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/scheduleautorecur/4.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>One item in user01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>1</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='POST cancel multiple instances' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Do POST</description>
+ <request>
+ <method>POST</method>
+ <header>
+ <name>Originator</name>
+ <value>$cuaddralt1:</value>
+ </header>
+ <header>
+ <name>Recipient</name>
+ <value>$rcuaddralt1:</value>
+ </header>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/scheduleautorecur/5.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELAY</method>
+ <ruri>4</ruri>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>No items in resource01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>0</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>One item in resource01 Calendar</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>GETNEW</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ <verify>
+ <callback>dataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/scheduleautorecur/6.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>One item in user01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>1</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='POST cancel wrong SEQUENCE' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Do POST</description>
+ <request>
+ <method>POST</method>
+ <header>
+ <name>Originator</name>
+ <value>$cuaddralt1:</value>
+ </header>
+ <header>
+ <name>Recipient</name>
+ <value>$rcuaddralt1:</value>
+ </header>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/scheduleautorecur/7.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELAY</method>
+ <ruri>4</ruri>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>No items in resource01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>0</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>One item in resource01 Calendar</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>GETNEW</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ <verify>
+ <callback>dataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/scheduleautorecur/6.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>One item in user01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>1</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='POST cancel no match UID' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Do POST</description>
+ <request>
+ <method>POST</method>
+ <header>
+ <name>Originator</name>
+ <value>$cuaddralt1:</value>
+ </header>
+ <header>
+ <name>Recipient</name>
+ <value>$rcuaddralt1:</value>
+ </header>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/scheduleautorecur/8.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELAY</method>
+ <ruri>4</ruri>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>No items in resource01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>0</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>One item in resource01 Calendar</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>1</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>One item in user01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>1</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='POST recurring with overridden instances' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Do POST</description>
+ <request>
+ <method>POST</method>
+ <header>
+ <name>Originator</name>
+ <value>$cuaddralt1:</value>
+ </header>
+ <header>
+ <name>Recipient</name>
+ <value>$rcuaddralt1:</value>
+ </header>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/scheduleautorecur/9.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELAY</method>
+ <ruri>6</ruri>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>No items in resource01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>0</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>One item in resource01 Calendar</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>GETNEW</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ <verify>
+ <callback>dataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/scheduleautorecur/10.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>One item in user01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>2</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='POST cancel one overridden instance' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Do POST</description>
+ <request>
+ <method>POST</method>
+ <header>
+ <name>Originator</name>
+ <value>$cuaddralt1:</value>
+ </header>
+ <header>
+ <name>Recipient</name>
+ <value>$rcuaddralt1:</value>
+ </header>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/scheduleautorecur/11.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELAY</method>
+ <ruri>4</ruri>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>No items in resource01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>0</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>One item in resource01 Calendar</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>GETNEW</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ <verify>
+ <callback>dataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/scheduleautorecur/12.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>One item in user01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>2</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <test-suite name='POST cancel multiple instances' ignore='no'>
+ <test name='1' ignore='no'>
+ <description>Do POST</description>
+ <request>
+ <method>POST</method>
+ <header>
+ <name>Originator</name>
+ <value>$cuaddralt1:</value>
+ </header>
+ <header>
+ <name>Recipient</name>
+ <value>$rcuaddralt1:</value>
+ </header>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ <data>
+ <content-type>text/calendar; charset=utf-8</content-type>
+ <filepath>Resource/scheduleautorecur/13.ics</filepath>
+ </data>
+ <verify>
+ <callback>statusCode</callback>
+ </verify>
+ </request>
+ <request>
+ <method>DELAY</method>
+ <ruri>4</ruri>
+ </request>
+ </test>
+ <test name='2' ignore='no'>
+ <description>No items in resource01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>0</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='3' ignore='no'>
+ <description>One item in resource01 Calendar</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>GETNEW</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ <verify>
+ <callback>dataMatch</callback>
+ <arg>
+ <name>filepath</name>
+ <value>Resource/scheduleautorecur/14.ics</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ <test name='4' ignore='no'>
+ <description>One item in user01 Inbox</description>
+ <request user="$useradmin:" pswd="$pswdadmin:" print-response="no">
+ <method>PROPFIND</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ <verify>
+ <callback>multistatusItems</callback>
+ <arg>
+ <name>count</name>
+ <value>2</value>
+ </arg>
+ </verify>
+ </request>
+ </test>
+ </test-suite>
+
+ <end>
+ <request>
+ <method>DELETEALL</method>
+ <ruri>$pathprefix:/$outbox:/</ruri>
+ </request>
+ <request>
+ <method>DELETEALL</method>
+ <ruri>$pathprefix:/$inbox:/</ruri>
+ </request>
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$rpathprefix1:/$outbox:/</ruri>
+ </request>
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$rpathprefix1:/$inbox:/</ruri>
+ </request>
+ <request user="$useradmin:" pswd="$pswdadmin:">
+ <method>DELETEALL</method>
+ <ruri>$rpathprefix1:/calendar/</ruri>
+ </request>
+ </end>
+
+</caldavtest>
Modified: CalendarServer/branches/users/cdaboo/better-itip-1835/twistedcaldav/ical.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-itip-1835/twistedcaldav/ical.py 2007-09-01 19:13:55 UTC (rev 1838)
+++ CalendarServer/branches/users/cdaboo/better-itip-1835/twistedcaldav/ical.py 2007-09-04 16:59:39 UTC (rev 1839)
@@ -46,7 +46,7 @@
from twisted.web2.stream import IStream
from twisted.web2.dav.util import allDataFromStream
-from twistedcaldav.dateops import normalizeToUTC, timeRangesOverlap
+from twistedcaldav.dateops import compareDateTime, normalizeToUTC, timeRangesOverlap
from twistedcaldav.instance import InstanceList
iCalendarProductID = "-//CALENDARSERVER.ORG//NONSGML Version 1//EN"
@@ -309,7 +309,7 @@
return type
- def mainComponent(self):
+ def mainComponent(self, allow_multiple=False):
"""
Return the primary iCal component in this calendar.
@return: the L{Component} of the primary type.
@@ -321,13 +321,51 @@
for component in self.subcomponents():
if component.name() == "VTIMEZONE":
continue
- elif (result is not None):
+ elif not allow_multiple and (result is not None):
raise ValueError("Calendar contains more than one primary component: %r" % (self,))
else:
result = component
+ if allow_multiple:
+ break
return result
+ def masterComponent(self):
+ """
+ Return the master iCal component in this calendar.
+ @return: the L{Component} for the master component,
+ or C{None} if there isn't one.
+ """
+ assert self.name() == "VCALENDAR", "Must be a VCALENDAR: %r" % (self,)
+
+ for component in self.subcomponents():
+ if component.name() == "VTIMEZONE":
+ continue
+ if not component.hasProperty("RECURRENCE-ID"):
+ return component
+
+ return None
+
+ def overriddenComponent(self, recurrence_id):
+ """
+ Return the overridden iCal component in this calendar matching the supplied RECURRENCE-ID property.
+
+ @param recurrence_id: The RECURRENCE-ID property value to match.
+ @type recurrence_id: L{datetime.datetime} or L{datetime.date}
+ @return: the L{Component} for the overridden component,
+ or C{None} if there isn't one.
+ """
+ assert self.name() == "VCALENDAR", "Must be a VCALENDAR: %r" % (self,)
+
+ for component in self.subcomponents():
+ if component.name() == "VTIMEZONE":
+ continue
+ rid = component.getRecurrenceIDUTC()
+ if rid and compareDateTime(rid, recurrence_id) == 0:
+ return component
+
+ return None
+
def duplicate(self):
"""
Duplicate this object and all its contents.
@@ -355,6 +393,13 @@
self._vobject.add(component._vobject)
component._parent = self
+ def removeComponent(self, component):
+ """
+ Removes a subcomponent from this component.
+ @param component: the L{Component} to remove.
+ """
+ self._vobject.remove(component._vobject)
+
def hasProperty(self, name):
"""
@param name: the name of the property whose existence is being tested.
@@ -982,6 +1027,37 @@
return None
+ def getAttendeeProperties(self, match):
+ """
+ Get all the attendees matching a value in each component. Works on a VCALENDAR component only.
+
+ @param match: a C{list} of calendar user address strings to try and match.
+ @return: the string value of the Organizer property, or None
+ """
+
+ assert self.name() == "VCALENDAR", "Not a calendar: %r" % (self,)
+
+ # FIXME: we should really have a URL class and have it manage comparisons
+ # in a sensible fashion.
+ def _normalizeCUAddress(addr):
+ if addr.startswith("/") or addr.startswith("http:") or addr.startswith("https:"):
+ return addr.rstrip("/")
+ else:
+ return addr
+
+ # Need to normalize http/https cu addresses
+ test = set()
+ for item in match:
+ test.add(_normalizeCUAddress(item))
+
+ # Extract appropriate sub-component if this is a VCALENDAR
+ results = []
+ for component in self.subcomponents():
+ if component.name() != "VTIMEZONE":
+ results.append(component.getAttendeeProperty(match))
+
+ return results
+
def getMaskUID(self):
"""
Get the X-CALENDARSEREVR-MASK-UID value. Works on either a VCALENDAR or on a component.
Modified: CalendarServer/branches/users/cdaboo/better-itip-1835/twistedcaldav/itip.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-itip-1835/twistedcaldav/itip.py 2007-09-01 19:13:55 UTC (rev 1838)
+++ CalendarServer/branches/users/cdaboo/better-itip-1835/twistedcaldav/itip.py 2007-09-04 16:59:39 UTC (rev 1839)
@@ -75,7 +75,7 @@
method = calendar.propertyValue("METHOD")
if method == "REQUEST":
- f = processRequest
+ f = processRequest2
elif method == "ADD":
f = processAdd
elif method == "CANCEL":
@@ -151,22 +151,22 @@
doreply, replycal, accepted = d.getResult()
if calmatch:
# See whether the current component is older than any existing ones and throw it away if so
- cal = updatecal.iCalendar(calmatch[0])
- info = getSyncInfo(calmatch[0], cal)
+ cal = updatecal.iCalendar(calmatch)
+ info = getSyncInfo(calmatch, cal)
if compareSyncInfo(info, newinfo) < 0:
# Re-write existing resource with new one, if accepted, otherwise delete existing as the
# update to it was not accepted.
try:
if accepted:
- newchild = waitForDeferred(writeResource(request, calURL, updatecal, calmatch[0], calendar))
+ newchild = waitForDeferred(writeResource(request, calURL, updatecal, calmatch, calendar))
yield newchild
newchild = newchild.getResult()
- logging.info("[ITIP]: replaced calendar component %s with new iTIP message in %s." % (calmatch[0], calURL))
+ logging.info("[ITIP]: replaced calendar component %s with new iTIP message in %s." % (calmatch, calURL))
else:
- d = waitForDeferred(deleteResource(updatecal, calmatch[0]))
+ d = waitForDeferred(deleteResource(updatecal, calmatch))
yield d
d.getResult()
- logging.info("[ITIP]: deleted calendar component %s in %s as update was not accepted." % (calmatch[0], calURL))
+ logging.info("[ITIP]: deleted calendar component %s in %s as update was not accepted." % (calmatch, calURL))
except:
log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
raise iTipException
@@ -177,7 +177,7 @@
d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
yield d
d.getResult()
- logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than %s in %s." % (child.fp.basename(), calmatch[0], calURL))
+ logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than %s in %s." % (child.fp.basename(), calmatch, calURL))
except:
log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
raise iTipException
@@ -224,6 +224,182 @@
processRequest = deferredGenerator(processRequest)
+def processRequest2(request, principal, inbox, calendar, child):
+ """
+ Process a METHOD=REQUEST.
+ This is a deferredGenerator function so use yield whenever we have a deferred.
+
+ Steps:
+
+ 1. See if this updates existing ones in Inbox.
+ 1. If so,
+ 1. Remove existing ones in Inbox.
+ 2. See if this updates existing ones in free-busy-set calendars.
+ 3. Remove existing ones in those calendars.
+ 4. See if this fits into a free slot:
+ 1. If not, send REPLY with failure status
+ 2. If so
+ 1. send REPLY with success
+ 2. add to f-b-s calendar
+ 2. If not,
+ 1. remove the one we got - its 'stale'
+ 3. Delete the request from the Inbox.
+
+ @param request: the L{twisted.web2.server.Request} for the current request.
+ @param principal: the L{CalendarPrincipalFile} principal resource for the principal we are dealing with.
+ @param inbox: the L{ScheduleInboxFile} for the principal's Inbox.
+ @param calendar: the L{Component} for the iTIP message we are processing.
+ @param child: the L{CalDAVFile} for the iTIP message resource already saved to the Inbox.
+ """
+
+ logging.info("[ITIP]: Auto-processing iTIP REQUEST for: %s" % (str(principal),))
+ processed = "ignored"
+
+ # First determine whether this is a full or partial update. A full update is one containing the master
+ # component in a recurrence set (or non-recurring event). Partial is one where overridden instances only are
+ # being changed.
+
+ new_master = calendar.masterComponent()
+
+ # Next we want to try and find a match to any components on existing calendars listed as contributing
+ # to free-busy as we will need to update those with the new one.
+ d = waitForDeferred(findCalendarMatch(request, principal, calendar))
+ yield d
+ calmatch, updatecal, calURL = d.getResult()
+
+ if new_master:
+ # So we have a full update. That means we need to delete any existing events completely and
+ # replace with the ones provided so long as the new one is newer.
+
+ # If we have a match then we need to check whether we are updating etc
+ check_reply = False
+ if calmatch:
+ # See whether the new component is older than any existing ones and throw it away if so
+ newinfo = (None,) + getComponentSyncInfo(new_master)
+ cal = updatecal.iCalendar(calmatch)
+ info = getSyncInfo(calmatch, cal)
+ if compareSyncInfo(info, newinfo) < 0:
+ # Existing resource is older and will be replaced
+ check_reply = True
+ else:
+ processed = "older"
+ else:
+ # We have a new request which we can reply to
+ check_reply = True
+
+ if check_reply:
+ # Process the reply by determining PARTSTAT and sending the reply and booking the event.
+ d = waitForDeferred(checkForReply2(request, principal, calendar))
+ yield d
+ doreply, replycal, accepted = d.getResult()
+
+ try:
+ if accepted:
+ if calmatch:
+ newchild = waitForDeferred(writeResource(request, calURL, updatecal, calmatch, calendar))
+ yield newchild
+ newchild = newchild.getResult()
+ logging.info("[ITIP]: replaced calendar component %s with new iTIP message in %s." % (calmatch, calURL))
+ else:
+ newchild = waitForDeferred(writeResource(request, calURL, updatecal, None, calendar))
+ yield newchild
+ newchild.getResult()
+ logging.info("[ITIP]: added new calendar component in %s." % (calURL,))
+ else:
+ if calmatch:
+ d = waitForDeferred(deleteResource(updatecal, calmatch))
+ yield d
+ d.getResult()
+ logging.info("[ITIP]: deleted calendar component %s in %s as update was not accepted." % (calmatch, calURL))
+
+ # If we get here we have a new iTIP message that we want to process. Any previous ones
+ # have been removed (so we won't run in to problems when we check that there is free time
+ # to book the new one).
+ if doreply:
+ logging.info("[ITIP]: sending iTIP REPLY %s" % (("declined","accepted")[accepted],))
+ newchild = waitForDeferred(writeReply(request, principal, replycal, inbox))
+ yield newchild
+ newchild = newchild.getResult()
+ newInboxResource(child, newchild)
+ processed = "processed"
+ except:
+ log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
+ raise iTipException
+
+ else:
+ # So we have a partial update. That means we have to do partial updates to instances in
+ # the existing calendar component.
+
+ # If we have a match then we need to check whether we are updating etc
+ check_reply = False
+ if calmatch:
+ # See whether the new component is older than any existing ones and throw it away if so
+ newinfo = getSyncInfo(calendar)
+ cal = updatecal.iCalendar(calmatch)
+ info = getSyncInfo(calmatch, cal)
+ if compareSyncInfo(info, newinfo) < 0:
+ # Existing resource is older and will be replaced
+ check_reply = True
+ else:
+ processed = "older"
+ else:
+ # We have a new request which we can reply to
+ check_reply = True
+
+ if check_reply:
+ # Process the reply by determining PARTSTAT and sending the reply and booking the event.
+ d = waitForDeferred(checkForReply2(request, principal, calendar))
+ yield d
+ doreply, replycal, accepted = d.getResult()
+
+ try:
+ if calmatch:
+ # Merge the new instances with the old ones
+ mergeComponents(calendar, cal)
+ newchild = waitForDeferred(writeResource(request, calURL, updatecal, calmatch, cal))
+ yield newchild
+ newchild = newchild.getResult()
+ logging.info("[ITIP]: merged calendar component %s with new iTIP message in %s." % (calmatch, calURL))
+ else:
+ if accepted:
+ newchild = waitForDeferred(writeResource(request, calURL, updatecal, None, calendar))
+ yield newchild
+ newchild.getResult()
+ logging.info("[ITIP]: added new calendar component in %s." % (calURL,))
+
+ # If we get here we have a new iTIP message that we want to process. Any previous ones
+ # have been removed (so we won't run in to problems when we check that there is free time
+ # to book the new one).
+ if doreply:
+ logging.info("[ITIP]: sending iTIP REPLY %s" % (("declined","accepted")[accepted],))
+ newchild = waitForDeferred(writeReply(request, principal, replycal, inbox))
+ yield newchild
+ newchild = newchild.getResult()
+ newInboxResource(child, newchild)
+
+ processed = "processed"
+ except:
+ log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
+ raise iTipException
+
+ # Remove the now processed incoming request.
+ try:
+ d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
+ yield d
+ d.getResult()
+ logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it has been %s." %
+ (child.fp.basename(),
+ {"processed":"processed",
+ "older": "ignored: older",
+ "ignored": "ignored: no match"}[processed],))
+ except:
+ log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
+ raise iTipException
+ yield None
+ return
+
+processRequest2 = deferredGenerator(processRequest2)
+
def processAdd(request, principal, inbox, calendar, child):
"""
Process a METHOD=ADD.
@@ -277,6 +453,7 @@
"""
logging.info("[ITIP]: Auto-processing iTIP CANCEL for: %s" % (str(principal),))
+ processed = "ignored"
# Get all component info for this iTIP message
newinfo = getSyncInfo(child.fp.basename(), calendar)
@@ -311,43 +488,99 @@
# If we have a match then we need to check whether we are updating etc
if calmatch:
# See whether the current component is older than any existing ones and throw it away if so
- cal = updatecal.iCalendar(calmatch[0])
- info = getSyncInfo(calmatch[0], cal)
+ cal = updatecal.iCalendar(calmatch)
+ info = getSyncInfo(calmatch, cal)
if compareSyncInfo(info, newinfo) < 0:
# Delete existing resource which has been cancelled
try:
- d = waitForDeferred(deleteResource(updatecal, calmatch[0],))
+ d = waitForDeferred(deleteResource(updatecal, calmatch,))
yield d
d.getResult()
- logging.info("[ITIP]: delete calendar component %s in %s as it was cancelled." % (calmatch[0], calURL))
+ logging.info("[ITIP]: delete calendar component %s in %s as it was cancelled." % (calmatch, calURL))
except:
log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
raise iTipException
+ processed = "processed"
else:
- # Delete new one in Inbox as it is old
- try:
- d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
- yield d
- d.getResult()
- logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than %s in %s." % (child.fp.basename(), calmatch[0], calURL))
- except:
- log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
- raise iTipException
- yield None
- return
+ processed = "older"
else:
- # Nothing to do
- pass
+ # Nothing to do except delete the inbox item as we have nothing to cancel.
+ processed = "ignored"
else:
- raise NotImplementedError
+ # Try and find a match to any components on existing calendars listed as contributing
+ # to free-busy as we will need to update those with the new one.
+ d = waitForDeferred(findCalendarMatch(request, principal, calendar))
+ yield d
+ calmatch, updatecal, calURL = d.getResult()
+
+ # If we have a match then we need to check whether we are updating etc
+ if calmatch:
+ # iTIP CANCEL can contain multiple components being cancelled in the RECURRENCE-ID case.
+ # So we need to iterate over each iTIP component.
-
+ # Get the existing calendar object
+ existing_calendar = updatecal.iCalendar(calmatch)
+ existing_master = existing_calendar.masterComponent()
+ exdates = []
+ max_sequence = existing_master.propertyValue("SEQUENCE")
+ if max_sequence is None:
+ max_sequence = 0
+
+ for component in calendar.subcomponents():
+ if component.name() == "VTIMEZONE":
+ continue
+
+ # Find matching component in existing calendar
+ old_component = findMatchingComponent(component, existing_calendar)
+
+ if old_component:
+ # We are cancelling an overridden component, so we need to check the
+ # SEQUENCE/DTSAMP with the master.
+ if compareComponents(old_component, component) < 0:
+ # Exclude the cancelled instance
+ exdates.append(component.getRecurrenceIDUTC())
+ max_sequence = max(max_sequence, component.propertyValue("SEQUENCE"))
+
+ # Remove the existing component.
+ existing_calendar.removeComponent(old_component)
+ else:
+ # We are trying to CANCEL a non-overridden instance, so we need to
+ # check SEQUENCE/DTSTAMP with the master.
+ if compareComponents(existing_master, component) < 0:
+ # Exclude the cancelled instance
+ exdates.append(component.getRecurrenceIDUTC())
+ max_sequence = max(max_sequence, component.propertyValue("SEQUENCE"))
+
+ # If we have any EXDATEs lets add them to the existing calendar object and write
+ # it back.
+ if exdates:
+ existing_master.addProperty(Property("EXDATE", exdates))
+ seq = existing_master.getProperty("SEQUENCE")
+ if seq:
+ seq.setValue(max_sequence)
+ else:
+ existing_master.addProperty(Property("SEQUENCE", max_sequence))
+ newchild = waitForDeferred(writeResource(request, calURL, updatecal, calmatch, existing_calendar))
+ yield newchild
+ newchild = newchild.getResult()
+ logging.info("[ITIP]: updated calendar component %s with cancellations from iTIP message in %s." % (calmatch, calURL))
+ processed = "processed"
+ else:
+ processed = "older"
+ else:
+ # Nothing to do except delete the inbox item as we have nothing to cancel.
+ processed = "ignored"
+
# Remove the now processed incoming request.
try:
d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
yield d
d.getResult()
- logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it has been processed." % (child.fp.basename(),))
+ logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it has been %s." %
+ (child.fp.basename(),
+ {"processed":"processed",
+ "older": "ignored: older",
+ "ignored": "ignored: no match"}[processed],))
except:
log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
raise iTipException
@@ -469,6 +702,129 @@
checkForReply = deferredGenerator(checkForReply)
+def checkForReply2(request, principal, calendar):
+ """
+ Check whether a reply to the given iTIP message is needed. A reply will be needed if the
+ RSVP=TRUE. A reply will either be positive (accepted
+ invitation) or negative (denied invitation). In addition we will modify calendar to reflect
+ any new state (e.g. remove RSVP, set PARTSTAT to ACCEPTED or DECLINED).
+
+ BTW The incoming iTIP message may contain multiple components so we need to iterate over all those.
+ At the moment we will treat a failure on one isntances as a DECLINE of the entire set.
+
+ @param request: the L{twisted.web2.server.Request} for the current request.
+ @param principal: the L{CalendarPrincipalFile} principal resource for the principal we are dealing with.
+ @param calendar: the L{Component} for the iTIP message we are processing.
+ @return: C{True} if a reply is needed, C{False} otherwise.
+ """
+
+ # We need to fugure out whether the specified component will clash with any others in the f-b-set calendars
+ accepted = True
+
+ # First expand current one to get instances (only go 1 year into the future)
+ default_future_expansion_duration = datetime.timedelta(days=356*1)
+ expand_max = datetime.date.today() + default_future_expansion_duration
+ instances = calendar.expandTimeRanges(expand_max)
+
+ # Extract UID from primary component as we want to ignore this one if we match it
+ # in any calendars.
+ comp = calendar.mainComponent(allow_multiple=True)
+ uid = comp.propertyValue("UID")
+
+ # Now compare each instance time-range with the index and see if there is an overlap
+ fbset = waitForDeferred(principal.calendarFreeBusyURIs(request))
+ yield fbset
+ fbset = fbset.getResult()
+
+ for calURL in fbset:
+ testcal = waitForDeferred(request.locateResource(calURL))
+ yield testcal
+ testcal = testcal.getResult()
+
+ # First list is BUSY, second BUSY-TENTATIVE, third BUSY-UNAVAILABLE
+ fbinfo = ([], [], [])
+
+ # Now do search for overlapping time-range
+ for instance in instances.instances.itervalues():
+ try:
+ tr = caldavxml.TimeRange(start="20000101", end="20000101")
+ tr.start = instance.start
+ tr.end = instance.end
+ d = waitForDeferred(report_common.generateFreeBusyInfo(request, testcal, fbinfo, tr, 0, uid))
+ yield d
+ d.getResult()
+
+ # If any fbinfo entries exist we have an overlap
+ if len(fbinfo[0]) or len(fbinfo[1]) or len(fbinfo[2]):
+ accepted = False
+ break
+ except NumberOfMatchesWithinLimits:
+ accepted = False
+ logging.info("[ITIP]: exceeded number of matches whilst trying to find free-time.")
+ break
+
+ if not accepted:
+ break
+
+ # Extract the ATTENDEE property matching current recipient from the calendar data
+ cuas = principal.calendarUserAddresses()
+ attendeeProps = calendar.getAttendeeProperties(cuas)
+ if not attendeeProps:
+ yield False, None, accepted
+ return
+
+ # Look for specific parameters
+ rsvp = False
+ for attendeeProp in attendeeProps:
+ if "RSVP" in attendeeProp.params():
+ if attendeeProp.params()["RSVP"][0] == "TRUE":
+ rsvp = True
+
+ # Now modify the original component
+ del attendeeProp.params()["RSVP"]
+
+ if accepted:
+ partstat = "ACCEPTED"
+ else:
+ partstat = "DECLINED"
+ for attendeeProp in attendeeProps:
+ if "PARTSTAT" in attendeeProp.params():
+ attendeeProp.params()["PARTSTAT"][0] = partstat
+ else:
+ attendeeProp.params()["PARTSTAT"] = [partstat]
+
+ # Now create a new calendar object for the reply
+
+ # First get useful props from the original
+ replycal = calendar.duplicate()
+
+ # Change METHOD
+ replycal.getProperty("METHOD").setValue("REPLY")
+
+ # Change PRODID to this server
+ replycal.getProperty("PRODID").setValue(iCalendarProductID)
+
+ # Add REQUEST-STATUS
+ for component in replycal.subcomponents():
+ if accepted:
+ component.addProperty(Property(name="REQUEST-STATUS", value="2.0; Success."))
+ else:
+ component.addProperty(Property(name="REQUEST-STATUS", value="4.0; Event conflict. Date/time is busy."))
+
+ # Remove all attendees other than ourselves
+ for component in replycal.subcomponents():
+ if component.name() == "VTIMEZONE":
+ continue
+ attendeeProp = component.getAttendeeProperty(cuas)
+ attendees = tuple(component.properties("ATTENDEE"))
+ for attendee in attendees:
+ if attendeeProp is None or (attendee.value() != attendeeProp.value()):
+ replycal.mainComponent().removeProperty(attendee)
+
+ yield rsvp, replycal, accepted
+
+checkForReply2 = deferredGenerator(checkForReply2)
+
def writeReply(request, principal, replycal, ainbox):
"""
Write an iTIP message reply into the specified Inbox.
@@ -535,7 +891,8 @@
itipper = True
if collection.isCalendarCollection():
method = calendar.getProperty("METHOD")
- calendar.removeProperty(method)
+ if method:
+ calendar.removeProperty(method)
itipper = False
# Now write it to the resource
@@ -679,47 +1036,91 @@
# We will ignore missing calendars. If the recipient has failed to
# properly manage the free busy set that should not prevent us from working.
continue
- calmatch = matchComponentInCalendar(updatecal, calendar, None)
+ calmatch = matchComponentInCalendar(updatecal, calendar)
if calmatch:
- logging.info("[ITIP]: found calendar component %s matching new iTIP message in %s." % (calmatch[0], calURL))
+ logging.info("[ITIP]: found calendar component %s matching new iTIP message in %s." % (calmatch, calURL))
break
- if not calmatch and len(fbset):
+ if calmatch is None and len(fbset):
calURL = fbset[0]
+ updatecal = waitForDeferred(request.locateResource(calURL))
+ yield updatecal
+ updatecal = updatecal.getResult()
yield calmatch, updatecal, calURL
findCalendarMatch = deferredGenerator(findCalendarMatch)
-def matchComponentInCalendar(collection, calendar, ignore):
+def matchComponentInCalendar(collection, calendar):
"""
See if the component in the provided iTIP calendar object matches any in the specified calendar
- collectrion, excluding the resource provided.
+ collection.
@param collection: L{CalDAVFile} for the calendar collection to examine.
@param calendar: L{Component} for calendar to examine.
- @param ignore: L{CalDAVFile} to ignore if found, or C{None} if none to ignore.
@return: C{list} of resource names found.
"""
- result = []
try:
- # Extract UID from primary component
- comp = calendar.mainComponent()
+ # Extract UID from primary component (note we allow multiple components to be present
+ # because CANCEL requests can have multiple components).
+ comp = calendar.mainComponent(allow_multiple=True)
uid = comp.propertyValue("UID")
# Now use calendar collection index to find all other resources with the same UID
index = collection.index()
result = index.resourceNamesForUID(uid)
- # Remove the one we want to ignore
- if ignore is not None:
- result = [name for name in result if name != ignore.fp.basename()]
+ # There can be only one
+ if len(result) > 0:
+ return result[0]
+ else:
+ return None
except ValueError:
- return []
+ return None
+
+def findMatchingComponent(component, calendar):
+ """
+ See if any overridden component in the provided iTIP calendar object matches the specified component.
- return result
+ @param component: the component to try and match.
+ @type component: L{Component}
+ @param calendar: the calendar to find a match in.
+ @type calendar: L{Component}
+ @return: L{Component} for matching component,
+ or C{None} if not found.
+ """
+ # Extract RECURRENCE-ID value from component
+ rid = component.getRecurrenceIDUTC()
+
+ # Return the one that matches in the calendar
+ return calendar.overriddenComponent(rid)
+
+def mergeComponents(newcal, oldcal):
+ """
+ Merge the overridden instance components in newcal into old cal replacing any
+ matching components there.
+
+ @param newcal: the new overridden instances to use.
+ @type newcal: L{Component}
+ @param oldcal: the component to merge into.
+ @type oldcal: L{Component}
+ """
+
+ # FIXME: going to ignore VTIMEZONE - i.e. will assume that the component being added
+ # use a TZID that is already specified in the old component set.
+
+ for component in newcal.subcomponents():
+ if component.name() == "VTIMEZONE":
+ continue
+
+ rid = component.getRecurrenceIDUTC()
+ old_component = oldcal.overriddenComponent(rid)
+ if old_component:
+ oldcal.removeComponent(old_component)
+ oldcal.addComponent(component)
+
def getAllInfo(collection, calendar, ignore):
"""
Find each component in the calendar collection that has a matching UID with
@@ -734,8 +1135,9 @@
"""
names = []
try:
- # Extract UID from primary component
- comp = calendar.mainComponent()
+ # Extract UID from primary component (note we allow multiple components to be present
+ # because CANCEL requests can have multiple components).
+ comp = calendar.mainComponent(allow_multiple=True)
uid = comp.propertyValue("UID")
# Now use calendar collection index to find all other resources with the same UID
@@ -764,18 +1166,50 @@
@return: C{tuple} of (uid, seq, dtstamp, r-id) some of which may be C{None} if property does not exist
"""
try:
- # Extract items from primary component
- comp = calendar.mainComponent()
- uid = comp.propertyValue("UID")
- seq = comp.propertyValue("SEQUENCE")
- dtstamp = comp.propertyValue("DTSTAMP")
- rid = comp.propertyValue("RECURRENCE-ID")
+ # Extract components from primary component (note we allow multiple components to be present
+ # because CANCEL requests can have multiple components).
+ comp = calendar.mainComponent(allow_multiple=True)
+ uid, seq, dtstamp, rid = getComponentSyncInfo(comp)
except ValueError:
return (name, None, None, None, None)
return (name, uid, seq, dtstamp, rid)
+def getComponentSyncInfo(component):
+ """
+ Get property value details needed to synchronize iTIP components.
+
+ @param component: L{Component} to check.
+ @return: C{tuple} of (uid, seq, dtstamp, r-id) some of which may be C{None} if property does not exist
+ """
+ try:
+ # Extract items from component
+ uid = component.propertyValue("UID")
+ seq = component.propertyValue("SEQUENCE")
+ dtstamp = component.propertyValue("DTSTAMP")
+ rid = component.propertyValue("RECURRENCE-ID")
+
+ except ValueError:
+ return (None, None, None, None)
+
+ return (uid, seq, dtstamp, rid)
+
+def compareComponents(component1, component2):
+ """
+ Compare synchronization information for two components to see if they match according to iTIP.
+
+ @param component1: first component to check.
+ @type component1: L{Component}
+ @param component2: second component to check.
+ @type component2: L{Component}
+
+ @return: 0, 1, -1 as per compareSyncInfo.
+ """
+ info1 = (None,) + getComponentSyncInfo(component1)
+ info2 = (None,) + getComponentSyncInfo(component2)
+ return compareSyncInfo(info1, info2)
+
def compareSyncInfo(info1, info2):
"""
Compare two synchronization information records.
@@ -810,50 +1244,3 @@
return -1
return 0
-
-def updating(collection, names, calendar):
- """
- Check whether the specified calendar object is an iTIP message that is "newer" than the
- others listed, or does not match the component type listed.
-
- @param collection: L{CalDAVFile} for the calendar collection to examine.
- @param names: C{list} of C{str} for names of resources in the collection to check against.
- @param calendar: L{Component} for calendar to check.
- @return: C{True} if new component is an update and valid, C{False} otherwise.
- """
-
- # First get useful sync-related info from existing component
- uid, seq, dtstamp, rid = getSyncInfo(calendar)
-
- # Now get info from each named component and compare
- for name in names:
- cal = collection.iCalendar(name)
- cuid, cseq, cdtstamp, crid = getSyncInfo(cal)
-
- # UIDs MUST match
- assert uid == cuid
-
- # Look for sequence
- if (cseq is not None) and (seq is not None):
- if cseq > seq:
- return False
- if cseq < seq:
- continue
- elif (cseq is not None) and (seq is None):
- return False
- elif (cseq is None) and (seq is not None):
- continue
-
- # Look for DTSTAMP
- if (cdtstamp is not None) and (dtstamp is not None):
- if cdtstamp > dtstamp:
- return False
- if cdtstamp < dtstamp:
- continue
- elif (cdtstamp is not None) and (dtstamp is None):
- return False
- elif (cdtstamp is None) and (dtstamp is not None):
- continue
-
- return True
-
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070904/0c0b0346/attachment.html
More information about the calendarserver-changes
mailing list