CalDAV Scheduling - part 3

This commit is contained in:
mdecimus
2025-06-17 15:04:01 +02:00
parent 55e62a6830
commit 20cb114715
28 changed files with 4091 additions and 1069 deletions

View File

@@ -29,7 +29,7 @@ imap = { path = "../crates/imap", features = ["test_mode"] }
imap_proto = { path = "../crates/imap-proto" }
dav = { path = "../crates/dav", features = ["test_mode"] }
dav-proto = { path = "../crates/dav-proto", features = ["test_mode"] }
calcard = { version = "0.1.2", features = ["rkyv"] }
calcard = { version = "0.1.3", features = ["rkyv"] }
groupware = { path = "../crates/groupware", features = ["test_mode"] }
http = { path = "../crates/http", features = ["test_mode", "enterprise"] }
http_proto = { path = "../crates/http-proto" }

View File

@@ -0,0 +1,265 @@
# Send initial request
> put a@gmail.com 1qnf39p0m9h6n1cm9qa9d8mocv@google.com
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
X-LIC-LOCATION:America/Los_Angeles
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
TZNAME:PDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
TZNAME:PST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=America/Los_Angeles:20250619T060000
DTEND;TZID=America/Los_Angeles:20250619T064500
RRULE:FREQ=WEEKLY;WKST=SU;COUNT=2;BYDAY=TH
DTSTAMP:20250616T182403Z
ORGANIZER;CN=John Doe:mailto:a@gmail.com
UID:1qnf39p0m9h6n1cm9qa9d8mocv@google.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
TRUE;CN=b@gmail.com;X-NUM-GUESTS=0:mailto:b@gmail.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
;CN=John Doe;X-NUM-GUESTS=0:mailto:a@gmail.com
X-MICROSOFT-CDO-OWNERAPPTID:299828133
CREATED:20250616T182358Z
LAST-MODIFIED:20250616T182358Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Meet me maybe
DESCRIPTION:This is the event description
TRANSP:OPAQUE
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:This is an event reminder
TRIGGER:-P0DT0H10M0S
END:VALARM
END:VEVENT
END:VCALENDAR
> expect
from: a@gmail.com
to: b@gmail.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DESCRIPTION:This is the event description
LOCATION:
STATUS:CONFIRMED
SUMMARY:Meet me maybe
DTEND;TZID=America/Los_Angeles:20250619T064500
DTSTART;TZID=America/Los_Angeles:20250619T060000
TRANSP:OPAQUE
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
TRUE;CN=b@gmail.com;X-NUM-GUESTS=0:mailto:b@gmail.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE;
CN="John Doe";X-NUM-GUESTS=0:mailto:a@gmail.com
ORGANIZER;CN="John Doe":mailto:a@gmail.com
UID:1qnf39p0m9h6n1cm9qa9d8mocv@google.com
RRULE:FREQ=WEEKLY;COUNT=2;BYDAY=TH;WKST=SU
CREATED:20250616T182358Z
DTSTAMP:0
LAST-MODIFIED:20250616T182358Z
SEQUENCE:1
X-MICROSOFT-CDO-OWNERAPPTID:299828133
BEGIN:VALARM
DESCRIPTION:This is an event reminder
ACTION:DISPLAY
TRIGGER:-PT10M
END:VALARM
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
X-LIC-LOCATION:America/Los_Angeles
BEGIN:DAYLIGHT
DTSTART:19700308T020000
TZNAME:PDT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19701101T020000
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
END:VTIMEZONE
END:VCALENDAR
# Send iTIP
> send
# Update the event, expect no changes
> put a@gmail.com 1qnf39p0m9h6n1cm9qa9d8mocv@google.com
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
X-LIC-LOCATION:America/Los_Angeles
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
TZNAME:PDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
TZNAME:PST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=America/Los_Angeles:20250619T060000
DTEND;TZID=America/Los_Angeles:20250619T064500
RRULE:FREQ=WEEKLY;WKST=SU;COUNT=2;BYDAY=TH
DTSTAMP:20250616T182416Z
ORGANIZER;CN=John Doe:mailto:a@gmail.com
UID:1qnf39p0m9h6n1cm9qa9d8mocv@google.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
TRUE;CN=b@gmail.com;X-NUM-GUESTS=0:mailto:b@gmail.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
;CN=John Doe;X-NUM-GUESTS=0:mailto:a@gmail.com
X-MICROSOFT-CDO-OWNERAPPTID:299828133
CREATED:20250616T182358Z
LAST-MODIFIED:20250616T182415Z
LOCATION:
SEQUENCE:1
STATUS:CONFIRMED
SUMMARY:Meet me maybe
DESCRIPTION:This is the updated event description
TRANSP:OPAQUE
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:This is an event reminder
TRIGGER:-P0DT0H10M0S
END:VALARM
END:VEVENT
END:VCALENDAR
> expect
from: a@gmail.com
to: b@gmail.com
changes: DESCRIPTION
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DESCRIPTION:This is the updated event description
LOCATION:
STATUS:CONFIRMED
SUMMARY:Meet me maybe
DTEND;TZID=America/Los_Angeles:20250619T064500
DTSTART;TZID=America/Los_Angeles:20250619T060000
TRANSP:OPAQUE
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
TRUE;CN=b@gmail.com;X-NUM-GUESTS=0:mailto:b@gmail.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE;
CN="John Doe";X-NUM-GUESTS=0:mailto:a@gmail.com
ORGANIZER;CN="John Doe":mailto:a@gmail.com
UID:1qnf39p0m9h6n1cm9qa9d8mocv@google.com
RRULE:FREQ=WEEKLY;COUNT=2;BYDAY=TH;WKST=SU
CREATED:20250616T182358Z
DTSTAMP:0
LAST-MODIFIED:20250616T182415Z
SEQUENCE:1
X-MICROSOFT-CDO-OWNERAPPTID:299828133
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
X-LIC-LOCATION:America/Los_Angeles
BEGIN:DAYLIGHT
DTSTART:19700308T020000
TZNAME:PDT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19701101T020000
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
END:VTIMEZONE
END:VCALENDAR
> send
# Make sure the original alarms are preserved
> get b@gmail.com 1qnf39p0m9h6n1cm9qa9d8mocv@google.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DESCRIPTION:This is the updated event description
LOCATION:
STATUS:CONFIRMED
SUMMARY:Meet me maybe
DTEND;TZID=America/Los_Angeles:20250619T064500
DTSTART;TZID=America/Los_Angeles:20250619T060000
TRANSP:OPAQUE
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
TRUE;CN=b@gmail.com;X-NUM-GUESTS=0:mailto:b@gmail.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE;
CN="John Doe";X-NUM-GUESTS=0:mailto:a@gmail.com
ORGANIZER;CN="John Doe":mailto:a@gmail.com
UID:1qnf39p0m9h6n1cm9qa9d8mocv@google.com
RRULE:FREQ=WEEKLY;COUNT=2;BYDAY=TH;WKST=SU
CREATED:20250616T182358Z
DTSTAMP:0
LAST-MODIFIED:20250616T182358Z
SEQUENCE:1
X-MICROSOFT-CDO-OWNERAPPTID:299828133
BEGIN:VALARM
DESCRIPTION:This is an event reminder
ACTION:DISPLAY
TRIGGER:-PT10M
END:VALARM
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
X-LIC-LOCATION:America/Los_Angeles
BEGIN:DAYLIGHT
DTSTART:19700308T020000
TZNAME:PDT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19701101T020000
TZNAME:PST
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
END:VTIMEZONE
END:VCALENDAR

View File

@@ -0,0 +1,130 @@
# iTIP tests
# Recipient is not organizer or attendee
> itip x@example.com y@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=C:mailto:c@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;RSVP=FALSE;CUTYPE=ROOM:conf_big@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> send
NotOrganizerNorAttendee
> reset
# Refreshing an event (1)
> put a@example.com 123456789@example.com
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:0
RDATE:19980304T180000Z
RDATE:19980311T180000Z
RDATE:19980318T180000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980304T180000Z
DTEND:19980304T200000Z
DTSTAMP:19980303T193000Z
LOCATION:Conference Room A
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
# Refreshing an event (2)
> expect
from: a@example.com
to: b@example.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
LOCATION:Conference Room A
STATUS:CONFIRMED
SUMMARY:Review Accounts
DTEND:19980304T200000Z
DTSTART:19980304T180000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:123456789@example.com
RDATE:19980304T180000Z
RDATE:19980311T180000Z
RDATE:19980318T180000Z
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR
# Refreshing an event (3)
> send
# Refreshing an event (4)
> itip b@example.com a@example.com
BEGIN:VCALENDAR
METHOD:REFRESH
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:0
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
DTSTART:19980304T180000Z
END:VEVENT
END:VCALENDAR
# Refreshing an event (5)
> send
from: a@example.com
to: b@example.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
LOCATION:Conference Room A
STATUS:CONFIRMED
SUMMARY:Review Accounts
DTEND:19980304T200000Z
DTSTART:19980304T180000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:123456789@example.com
RDATE:19980304T180000Z
RDATE:19980311T180000Z
RDATE:19980318T180000Z
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR

View File

@@ -0,0 +1,322 @@
# Scheduling invalid actions
# Event has no scheduling information
> put x@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
NoSchedulingInfo
> reset
# X is not the organizer
> put x@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
NotOrganizerNorAttendee
> reset
# No attendees
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
NothingToSend
> reset
# Organizer with client scheduling agent
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER;SCHEDULE-AGENT=CLIENT:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
OtherSchedulingAgent
> reset
# Single participant with client scheduling agent
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;SCHEDULE-AGENT=CLIENT;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
NothingToSend
> reset
# Only send updates to clients with server scheduling agent
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:d@example.com
ATTENDEE;SCHEDULE-AGENT=CLIENT;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: d@example.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Conference
DTEND:19970701T2100000Z
DTSTART:19970701T200000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B;PARTSTAT=NEEDS-ACTION:mailto:b@exa
mple.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B;PARTSTAT=NEEDS-ACTION:mailto:d@exa
mple.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR
> reset
# Multiple object types should be rejected
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VTODO
END:VCALENDAR
> expect
MultipleObjectTypes
> reset
# Multiple organizers should be rejected
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
ORGANIZER:mailto:d@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=D:mailto:d@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
MultipleOrganizer
> reset
# Different UIDs should be rejected
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:other-uid@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
MultipleUid
> reset
# Multiple object instances should be rejected
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
RECURRENCE-ID:19970701T200000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
RECURRENCE-ID:19970701T200000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
MultipleObjectInstances

View File

@@ -0,0 +1,833 @@
# RFC5546 - Group Event Request
# A sample meeting request is sent from "A" to "B", "C", and "D".
> put a@example.com guid-1@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
SEQUENCE:0
RRULE:FREQ=MONTHLY;BYMONTHDAY=1;UNTIL=19980901T210000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970601T210000Z
DTEND:19970601T220000Z
LOCATION:Conference Call
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com, c@example.com, d@example.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Conference Call
LOCATION:Conference Call
STATUS:CONFIRMED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970601T220000Z
DTSTART:19970601T210000Z
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ORGANIZER:mailto:a@example.com
UID:guid-1@example.com
RRULE:FREQ=MONTHLY;UNTIL=19980901T210000Z;BYMONTHDAY=1
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR
# Send iTIP request to attendees
> send
# Change a recurrence instance
> put a@example.com guid-1@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
SEQUENCE:2
RRULE:FREQ=MONTHLY;BYMONTHDAY=1;UNTIL=19980901T210000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970601T210000Z
DTEND:19970601T220000Z
LOCATION:Conference Call
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID:19970701T210000Z
SEQUENCE:1
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970703T210000Z
DTEND:19970703T220000Z
LOCATION:Conference Call
DTSTAMP:19970626T093000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com, c@example.com, d@example.com
changes:
BEGIN:VCALENDAR
METHOD:ADD
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Conference Call
LOCATION:Conference Call
STATUS:CONFIRMED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970703T220000Z
DTSTART:19970703T210000Z
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19970701T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# Send iTIP update to attendees
> send
# Cancel a recurrence instance only for B
> put a@example.com guid-1@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
SEQUENCE:3
RRULE:FREQ=MONTHLY;BYMONTHDAY=1;UNTIL=19980901T210000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970601T210000Z
DTEND:19970601T220000Z
LOCATION:Conference Call
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID:19970701T210000Z
SEQUENCE:2
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970703T210000Z
DTEND:19970703T220000Z
LOCATION:Conference Call
DTSTAMP:19970626T093000Z
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
RECURRENCE-ID:19970801T210000Z
SEQUENCE:2
STATUS:CANCELLED
DTSTAMP:19970721T093000Z
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com
changes:
BEGIN:VCALENDAR
METHOD:CANCEL
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CANCELLED
ATTENDEE:mailto:b@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19970801T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:3
END:VEVENT
END:VCALENDAR
# Send iTIP cancellation to B
> send
# Make sure B has the cancelled event
> get b@example.com guid-1@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Conference Call
LOCATION:Conference Call
STATUS:CONFIRMED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970601T220000Z
DTSTART:19970601T210000Z
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ORGANIZER:mailto:a@example.com
UID:guid-1@example.com
RRULE:FREQ=MONTHLY;UNTIL=19980901T210000Z;BYMONTHDAY=1
DTSTAMP:0
SEQUENCE:1
END:VEVENT
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Conference Call
LOCATION:Conference Call
STATUS:CONFIRMED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970703T220000Z
DTSTART:19970703T210000Z
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19970701T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:2
END:VEVENT
BEGIN:VEVENT
STATUS:CANCELLED
ATTENDEE:mailto:b@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19970801T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:3
END:VEVENT
END:VCALENDAR
# Change all future instances
> put a@example.com guid-1@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
SEQUENCE:4
RRULE:FREQ=MONTHLY;BYMONTHDAY=1;UNTIL=19980901T210000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970601T210000Z
DTEND:19970601T220000Z
LOCATION:Conference Call
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID:19970701T210000Z
SEQUENCE:3
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970703T210000Z
DTEND:19970703T220000Z
LOCATION:Conference Call
DTSTAMP:19970626T093000Z
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
RECURRENCE-ID:19970801T210000Z
SEQUENCE:3
STATUS:CANCELLED
DTSTAMP:19970721T093000Z
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
SEQUENCE:3
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
DESCRIPTION:IETF-C&S Discussion
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970901T210000Z
DTEND:19970901T220000Z
LOCATION:Building 32, Microsoft, Seattle, WA
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com, c@example.com, d@example.com
changes:
BEGIN:VCALENDAR
METHOD:ADD
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Discussion
LOCATION:Building 32\, Microsoft\, Seattle\, WA
STATUS:CONFIRMED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970901T220000Z
DTSTART:19970901T210000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:4
END:VEVENT
END:VCALENDAR
# Send iTIP update to attendees
> send
# Make sure B has the complete event including all updates
> get b@example.com guid-1@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Conference Call
LOCATION:Conference Call
STATUS:CONFIRMED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970601T220000Z
DTSTART:19970601T210000Z
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ORGANIZER:mailto:a@example.com
UID:guid-1@example.com
RRULE:FREQ=MONTHLY;UNTIL=19980901T210000Z;BYMONTHDAY=1
DTSTAMP:0
SEQUENCE:1
END:VEVENT
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Conference Call
LOCATION:Conference Call
STATUS:CONFIRMED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970703T220000Z
DTSTART:19970703T210000Z
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19970701T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:2
END:VEVENT
BEGIN:VEVENT
STATUS:CANCELLED
ATTENDEE:mailto:b@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19970801T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:3
END:VEVENT
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Discussion
LOCATION:Building 32\, Microsoft\, Seattle\, WA
STATUS:CONFIRMED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970901T220000Z
DTSTART:19970901T210000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:4
END:VEVENT
END:VCALENDAR
# Cancel the recurring event
> put a@example.com guid-1@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:guid-1@example.com
SEQUENCE:4
RRULE:FREQ=MONTHLY;BYMONTHDAY=1;UNTIL=19980901T210000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970601T210000Z
DTEND:19970601T220000Z
LOCATION:Conference Call
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID:19970701T210000Z
SEQUENCE:3
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
DESCRIPTION:IETF-C&S Conference Call
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970703T210000Z
DTEND:19970703T220000Z
LOCATION:Conference Call
DTSTAMP:19970626T093000Z
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE:mailto:b@example.com
RECURRENCE-ID:19970801T210000Z
SEQUENCE:3
STATUS:CANCELLED
DTSTAMP:19970721T093000Z
END:VEVENT
BEGIN:VEVENT
UID:guid-1@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
SEQUENCE:3
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
DESCRIPTION:IETF-C&S Discussion
CLASS:PUBLIC
SUMMARY:IETF Calendaring Working Group Meeting
DTSTART:19970901T210000Z
DTEND:19970901T220000Z
LOCATION:Building 32, Microsoft, Seattle, WA
DTSTAMP:19970526T083000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
# Cancel a recurring event
> delete a@example.com guid-1@example.com
> expect
from: a@example.com
to: b@example.com, c@example.com, d@example.com
changes:
BEGIN:VCALENDAR
METHOD:CANCEL
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CANCELLED
ATTENDEE:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:5
END:VEVENT
END:VCALENDAR
# Send iTIP cancellation to attendees
> send
# Make sure all instances in B were deleted
> get b@example.com guid-1@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Conference Call
LOCATION:Conference Call
STATUS:CANCELLED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970601T220000Z
DTSTART:19970601T210000Z
ATTENDEE:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:guid-1@example.com
RRULE:FREQ=MONTHLY;UNTIL=19980901T210000Z;BYMONTHDAY=1
DTSTAMP:0
END:VEVENT
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Conference Call
LOCATION:Conference Call
STATUS:CANCELLED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970703T220000Z
DTSTART:19970703T210000Z
ATTENDEE:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19970701T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:2
END:VEVENT
BEGIN:VEVENT
STATUS:CANCELLED
ATTENDEE:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19970801T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:3
END:VEVENT
BEGIN:VEVENT
CLASS:PUBLIC
DESCRIPTION:IETF-C&S Discussion
LOCATION:Building 32\, Microsoft\, Seattle\, WA
STATUS:CANCELLED
SUMMARY:IETF Calendaring Working Group Meeting
DTEND:19970901T220000Z
DTSTART:19970901T210000Z
ATTENDEE:mailto:a@example.com
ATTENDEE:mailto:b@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:d@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
UID:guid-1@example.com
DTSTAMP:0
SEQUENCE:4
END:VEVENT
END:VCALENDAR
# Add a new series of instances to the recurring event
> put a@example.com 123456789@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:0
RRULE:WKST=SU;BYDAY=TU;FREQ=WEEKLY
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980303T210000Z
DTEND:19980303T220000Z
LOCATION:The White Room
DTSTAMP:19980301T093000Z
STATUS:CONFIRMED
END:VEVENT
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:2
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
SUMMARY:Review Accounts
DTSTAMP:19980303T193000Z
LOCATION:The Red Room
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com, c@example.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
LOCATION:The White Room
STATUS:CONFIRMED
SUMMARY:Review Accounts
DTEND:19980303T220000Z
DTSTART:19980303T210000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:123456789@example.com
RRULE:FREQ=WEEKLY;BYDAY=TU;WKST=SU
DTSTAMP:0
SEQUENCE:1
END:VEVENT
BEGIN:VEVENT
LOCATION:The Red Room
STATUS:CONFIRMED
SUMMARY:Review Accounts
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
UID:123456789@example.com
DTSTAMP:0
SEQUENCE:3
END:VEVENT
END:VCALENDAR
# Send iTIP request to B and C
> send
# Add a new series of instances to the recurring event (update)
> put a@example.com 123456789@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
UID:123456789@example.com
SEQUENCE:2
RRULE:WKST=SU;BYDAY=TU,TH;FREQ=WEEKLY
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
SUMMARY:Review Accounts
DTSTART:19980303T210000Z
DTEND:19980303T220000Z
DTSTAMP:19980303T193000Z
LOCATION:The White Room
STATUS:CONFIRMED
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com
changes: EXDATE, RRULE
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
LOCATION:The White Room
STATUS:CONFIRMED
SUMMARY:Review Accounts
DTEND:19980303T220000Z
DTSTART:19980303T210000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:123456789@example.com
RRULE:FREQ=WEEKLY;BYDAY=TU,TH;WKST=SU
DTSTAMP:0
SEQUENCE:3
END:VEVENT
END:VCALENDAR
================================
from: a@example.com
to: c@example.com
changes:
BEGIN:VCALENDAR
METHOD:CANCEL
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CANCELLED
ATTENDEE:mailto:c@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
UID:123456789@example.com
DTSTAMP:0
SEQUENCE:4
END:VEVENT
END:VCALENDAR
# Send iTIP request to B and cancellation to C
> send
# Make sure B has the updated event
> get b@example.com 123456789@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
LOCATION:The White Room
STATUS:CONFIRMED
SUMMARY:Review Accounts
DTEND:19980303T220000Z
DTSTART:19980303T210000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:123456789@example.com
RRULE:FREQ=WEEKLY;BYDAY=TU,TH;WKST=SU
DTSTAMP:0
SEQUENCE:3
END:VEVENT
END:VCALENDAR
# Make sure C has the updated event
> get c@example.com 123456789@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
LOCATION:The Red Room
STATUS:CANCELLED
SUMMARY:Review Accounts
ATTENDEE:mailto:c@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID;THISANDFUTURE:19970901T210000Z
UID:123456789@example.com
DTSTAMP:0
END:VEVENT
BEGIN:VEVENT
LOCATION:The White Room
STATUS:CONFIRMED
SUMMARY:Review Accounts
DTEND:19980303T220000Z
DTSTART:19980303T210000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:123456789@example.com
RRULE:FREQ=WEEKLY;BYDAY=TU;WKST=SU
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR
# Delete the event from B
> delete b@example.com 123456789@example.com
> expect
from: b@example.com
to: a@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
ATTENDEE;PARTSTAT=DECLINED:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:123456789@example.com
DTSTAMP:0
SEQUENCE:3
END:VEVENT
END:VCALENDAR
> send
# Make sure A has the cancellation from B
> get a@example.com 123456789@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
LOCATION:The White Room
STATUS:CONFIRMED
SUMMARY:Review Accounts
DTEND:19980303T220000Z
DTSTART:19980303T210000Z
ATTENDEE;PARTSTAT=DECLINED:mailto:b@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ORGANIZER:mailto:a@example.com
UID:123456789@example.com
RRULE:FREQ=WEEKLY;BYDAY=TU,TH;WKST=SU
DTSTAMP:1
SEQUENCE:3
END:VEVENT
END:VCALENDAR

View File

@@ -0,0 +1,683 @@
# RFC5546 - Group Event Request
# A sample meeting request is sent from "A" to "B", "C", and "D".
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=C:mailto:c@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;RSVP=FALSE;CUTYPE=ROOM:conf_big@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
DTSTAMP:19970611T190000Z
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:0
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com, c@example.com, d@example.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Conference
DTEND:19970701T2100000Z
DTSTART:19970701T200000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
ATTENDEE;RSVP=FALSE;CUTYPE=ROOM:conf_big@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B;PARTSTAT=NEEDS-ACTION:mailto:b@exa
mple.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=C;PARTSTAT=NEEDS-ACTION:mailto:c@exa
mple.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR
# Send iTIP request to B, C, and D
> send
# Make sure B receives the request
> get b@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Conference
DTEND:19970701T2100000Z
DTSTART:19970701T200000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
ATTENDEE;RSVP=FALSE;CUTYPE=ROOM:conf_big@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B;PARTSTAT=NEEDS-ACTION:mailto:b@exa
mple.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=C;PARTSTAT=NEEDS-ACTION:mailto:c@exa
mple.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR
# B accepts the request
> put b@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
BEGIN:VEVENT
DTSTAMP:19970701T200000Z
SEQUENCE:1
UID:calsrv.example.com-873970198738777@example.com
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B;PARTSTAT=ACCEPTED:mailto:b@exa
mple.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=C;PARTSTAT=NEEDS-ACTION:mailto:c@exa
mple.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;RSVP=FALSE;CUTYPE=ROOM:conf_big@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
DTSTART:19970701T200000Z
DTEND:19970701T2100000Z
SUMMARY:Conference
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: b@example.com
to: a@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B;PARTSTAT=ACCEPTED:mailto:b@example
.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:1
REQUEST-STATUS:2.0;Success
END:VEVENT
END:VCALENDAR
# Send iTIP reply to A
> send
# Make sure A receives the reply
> get a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Conference
DTEND:19970701T2100000Z
DTSTART:19970701T200000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN=A:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
ATTENDEE;RSVP=FALSE;CUTYPE=ROOM:conf_big@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=B;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=
2.0:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=C:mailto:c@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:1
SEQUENCE:1
END:VEVENT
END:VCALENDAR
# A moved the event to a new time
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:c@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
DTSTART:19970701T180000Z
DTEND:19970701T190000Z
SUMMARY:Phone Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:1
DTSTAMP:19970613T190000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com, c@example.com, d@example.com
changes: ATTENDEE, DTEND, DTSTART, SUMMARY
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:c@example.
com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# Send iTIP request to B, C, and D
> send
# Make sure C receives the request
> get c@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE:mailto:e@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:c@example.
com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# "C" delegates presence at the meeting to "E".
> put c@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
BEGIN:VEVENT
DTSTAMP:19970701T180000Z
UID:calsrv.example.com-873970198738777@example.com
ORGANIZER:mailto:a@example.com
STATUS:CONFIRMED
SEQUENCE:2
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@example.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com":mailto:e@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
DTSTART:19970701T180000Z
DTEND:19970701T190000Z
SUMMARY:Phone Conference
END:VEVENT
END:VCALENDAR
> expect
from: c@example.com
to: a@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com":mailto:e@example.c
om
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:2
REQUEST-STATUS:2.0;Success
END:VEVENT
END:VCALENDAR
================================
from: c@example.com
to: e@example.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=NEEDS-AC
TION:mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:2
END:VEVENT
END:VCALENDAR
> send
# Make sure E receives the request
> get e@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=NEEDS-AC
TION:mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# Make sure A receives the request
> get a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@exam
ple.com";SCHEDULE-STATUS=2.0:mailto:c@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com":mailto:e@example.c
om
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:2
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# Delegate E accepts the request
> put e@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
BEGIN:VEVENT
DTSTAMP:19970701T180000Z
SEQUENCE:2
UID:calsrv.example.com-873970198738777@example.com
ORGANIZER:mailto:a@example.com
STATUS:CONFIRMED
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=ACCEPTED:mailto:e@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
DTSTART:19970701T180000Z
DTEND:19970701T190000Z
SUMMARY:Phone Conference
END:VEVENT
END:VCALENDAR
> expect
from: e@example.com
to: a@example.com, c@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=ACCEPTED:
mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:2
REQUEST-STATUS:2.0;Success
END:VEVENT
END:VCALENDAR
> send
# Make sure A receives the reply
> get a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@exam
ple.com";SCHEDULE-STATUS=2.0:mailto:c@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=ACCEPTED;
SCHEDULE-STATUS=2.0:mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:2
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# Make sure C receives the reply
> get c@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=ACCEPTED;
SCHEDULE-STATUS=2.0:mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:3
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# Delegate E declines the request
> put e@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
BEGIN:VEVENT
DTSTAMP:19970701T180000Z
SEQUENCE:2
UID:calsrv.example.com-873970198738777@example.com
ORGANIZER:mailto:a@example.com
STATUS:CONFIRMED
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=DECLINED:mailto:e@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
DTSTART:19970701T180000Z
DTEND:19970701T190000Z
SUMMARY:Phone Conference
END:VEVENT
END:VCALENDAR
> expect
from: e@example.com
to: a@example.com, c@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=DECLINED:
mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:2
REQUEST-STATUS:2.0;Success
END:VEVENT
END:VCALENDAR
# Send iTIP reply to A and C
> send
# Make sure C receives the reply
> get c@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c@ex
ample.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=DECLINED;
SCHEDULE-STATUS=2.0:mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:3
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# Make sure A receives the reply
> get a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@exam
ple.com";SCHEDULE-STATUS=2.0:mailto:c@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=DECLINED;
SCHEDULE-STATUS=2.0:mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:2
SEQUENCE:2
END:VEVENT
END:VCALENDAR
# Remove B and expect an iTIP cancelation
> put a@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@exam
ple.com";SCHEDULE-STATUS=2.0:mailto:c@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal:mailto:d@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=DECLINED;
SCHEDULE-STATUS=2.0:mailto:e@example.com
DTSTART:19970701T180000Z
DTEND:19970701T190000Z
SUMMARY:Phone Conference
UID:calsrv.example.com-873970198738777@example.com
SEQUENCE:2
DTSTAMP:19970701T180000Z
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
> expect
from: a@example.com
to: c@example.com, d@example.com
changes: ATTENDEE
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CONFIRMED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@exam
ple.com":mailto:c@example.com
ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:a@example.com
ATTENDEE;ROLE=NON-PARTICIPANT;RSVP=FALSE;CUTYPE=ROOM:mailto:conf@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;CN=Hal;PARTSTAT=NEEDS-ACTION:mailto:d@e
xample.com
ATTENDEE;RSVP=TRUE;DELEGATED-FROM="mailto:c@example.com";PARTSTAT=DECLINED:
mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:3
END:VEVENT
END:VCALENDAR
================================
from: a@example.com
to: b@example.com
changes:
BEGIN:VCALENDAR
METHOD:CANCEL
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CANCELLED
ATTENDEE:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:3
END:VEVENT
END:VCALENDAR
# Send iTIP cancelation
> send
# Make sure B receives the cancelation
> get b@example.com calsrv.example.com-873970198738777@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CANCELLED
SUMMARY:Phone Conference
DTEND:19970701T190000Z
DTSTART:19970701T180000Z
ATTENDEE:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
END:VEVENT
END:VCALENDAR
# Delete the event from A's calendar and expect an iTIP cancelation
> delete a@example.com calsrv.example.com-873970198738777@example.com
> expect
from: a@example.com
to: c@example.com, d@example.com
changes:
BEGIN:VCALENDAR
METHOD:CANCEL
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
STATUS:CANCELLED
ATTENDEE:mailto:a@example.com
ATTENDEE:mailto:c@example.com
ATTENDEE:mailto:conf@example.com
ATTENDEE:mailto:d@example.com
ATTENDEE:mailto:e@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777@example.com
DTSTAMP:0
SEQUENCE:4
END:VEVENT
END:VCALENDAR

View File

@@ -0,0 +1,468 @@
# RFC5546 - Todo Request
# A sample todo is sent from "A" to "B", "C", and "D".
> put a@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
METHOD:REQUEST
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:b@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
DTSTART:19970701T170000Z
DUE:19970722T170000Z
PRIORITY:1
SUMMARY:Create the requirements document
UID:calsrv.example.com-873970198738777-00@example.com
SEQUENCE:0
DTSTAMP:19970717T200000Z
STATUS:NEEDS-ACTION
END:VTODO
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com, c@example.com, d@example.com
changes:
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
PRIORITY:1
STATUS:NEEDS-ACTION
SUMMARY:Create the requirements document
DUE:19970722T170000Z
DTSTART:19970701T170000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=NEEDS-ACTION:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
SEQUENCE:1
END:VTODO
END:VCALENDAR
# Send iTIP request to the attendees
> send
# Make sure B received the todo
> get b@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
PRIORITY:1
STATUS:NEEDS-ACTION
SUMMARY:Create the requirements document
DUE:19970722T170000Z
DTSTART:19970701T170000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=NEEDS-ACTION:mailto:a@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:b@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:c@example.com
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
SEQUENCE:1
END:VTODO
END:VCALENDAR
# "B" accepts the to-do.
> put b@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=ACCEPTED:mailto:b@example.com
UID:calsrv.example.com-873970198738777-00@example.com
COMMENT:I'll send you my input by email
SEQUENCE:1
PRIORITY:1
STATUS:IN-PROCESS
DTSTART:19970701T170000Z
DUE:19970722T170000Z
DTSTAMP:19970717T203000Z
END:VTODO
END:VCALENDAR
> expect
from: b@example.com
to: a@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
STATUS:IN-PROCESS
ATTENDEE;PARTSTAT=ACCEPTED:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
SEQUENCE:1
REQUEST-STATUS:2.0;Success
END:VTODO
END:VCALENDAR
# Send iTIP reply to the organizer
> send
# Make sure "A" received the reply
> get a@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
PRIORITY:1
STATUS:IN-PROCESS
SUMMARY:Create the requirements document
DUE:19970722T170000Z
DTSTART:19970701T170000Z
ATTENDEE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:mailto:b@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:1
SEQUENCE:1
END:VTODO
END:VCALENDAR
# "B" updates percent completion of the to-do.
> put b@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
PERCENT-COMPLETE:75
ATTENDEE;PARTSTAT=IN-PROCESS:mailto:b@example.com
UID:calsrv.example.com-873970198738777-00@example.com
COMMENT:I'll send you my input by email
SEQUENCE:1
PRIORITY:1
STATUS:IN-PROCESS
DTSTART:19970701T170000Z
DUE:19970722T170000Z
DTSTAMP:19970717T203000Z
END:VTODO
END:VCALENDAR
> expect
from: b@example.com
to: a@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
PERCENT-COMPLETE:75
STATUS:IN-PROCESS
ATTENDEE;PARTSTAT=IN-PROCESS:mailto:b@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
SEQUENCE:1
REQUEST-STATUS:2.0;Success
END:VTODO
END:VCALENDAR
# Send iTIP reply to the organizer
> send
# Make sure "A" received the reply
> get a@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
PERCENT-COMPLETE:75
PRIORITY:1
STATUS:IN-PROCESS
SUMMARY:Create the requirements document
DUE:19970722T170000Z
DTSTART:19970701T170000Z
ATTENDEE;PARTSTAT=IN-PROCESS;SCHEDULE-STATUS=2.0:mailto:b@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ATTENDEE;RSVP=TRUE:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:1
SEQUENCE:1
END:VTODO
END:VCALENDAR
# "D" completed the to-do.
> put d@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=COMPLETED:mailto:d@example.com
UID:calsrv.example.com-873970198738777-00@example.com
COMMENT:I'll send you my input by email
SEQUENCE:1
PRIORITY:1
DTSTART:19970701T170000Z
DUE:19970722T170000Z
DTSTAMP:19970717T203000Z
END:VTODO
END:VCALENDAR
> expect
from: d@example.com
to: a@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
ATTENDEE;PARTSTAT=COMPLETED:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
SEQUENCE:1
REQUEST-STATUS:2.0;Success
END:VTODO
END:VCALENDAR
# Send iTIP reply to the organizer
> send
# Make sure "A" received the reply
> get a@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
PERCENT-COMPLETE:75
PRIORITY:1
STATUS:IN-PROCESS
SUMMARY:Create the requirements document
DUE:19970722T170000Z
DTSTART:19970701T170000Z
ATTENDEE;PARTSTAT=COMPLETED;SCHEDULE-STATUS=2.0:mailto:d@example.com
ATTENDEE;PARTSTAT=IN-PROCESS;SCHEDULE-STATUS=2.0:mailto:b@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE:mailto:c@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:1
SEQUENCE:1
END:VTODO
END:VCALENDAR
# Recurring to-do request
> put a@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:d@example.com
RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
DTSTART:19980101T100000Z
DUE:19980103T100000Z
SUMMARY:Send Status Reports to Area Managers
UID:calsrv.example.com-873970198738777-00@example.com
SEQUENCE:0
DTSTAMP:19970717T200000Z
STATUS:NEEDS-ACTION
PRIORITY:1
END:VTODO
END:VCALENDAR
> expect
from: a@example.com
to: b@example.com, d@example.com
changes: ATTENDEE, DTSTART, DUE, PERCENT-COMPLETE, RRULE, STATUS, SUMMARY
BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
PRIORITY:1
STATUS:NEEDS-ACTION
SUMMARY:Send Status Reports to Area Managers
DUE:19980103T100000Z
DTSTART:19980101T100000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=NEEDS-ACTION:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:d@example.
com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
DTSTAMP:0
SEQUENCE:1
END:VTODO
END:VCALENDAR
================================
from: a@example.com
to: c@example.com
changes:
BEGIN:VCALENDAR
METHOD:CANCEL
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
STATUS:CANCELLED
ATTENDEE:mailto:c@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
SEQUENCE:2
END:VTODO
END:VCALENDAR
> send
# Make sure "C" received the cancel request
> get c@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
PRIORITY:1
STATUS:CANCELLED
SUMMARY:Create the requirements document
DUE:19970722T170000Z
DTSTART:19970701T170000Z
ATTENDEE:mailto:c@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
END:VTODO
END:VCALENDAR
# Make sure "B" received the updated to-do
> get b@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
COMMENT:I'll send you my input by email
PRIORITY:1
STATUS:NEEDS-ACTION
SUMMARY:Send Status Reports to Area Managers
DUE:19980103T100000Z
DTSTART:19980101T100000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=NEEDS-ACTION:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:d@example.
com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
DTSTAMP:0
SEQUENCE:1
END:VTODO
END:VCALENDAR
# Reply to an instance of a recurring to-do
> put b@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
COMMENT:I'll send you my input by email
PRIORITY:1
STATUS:NEEDS-ACTION
SUMMARY:Send Status Reports to Area Managers
DUE:19980103T100000Z
DTSTART:19980101T100000Z
ATTENDEE;ROLE=CHAIR;PARTSTAT=NEEDS-ACTION:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:b@example.
com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION:mailto:d@example.
com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
DTSTAMP:19970717T233000Z
SEQUENCE:1
END:VTODO
BEGIN:VTODO
ORGANIZER:mailto:a@example.com
ATTENDEE;PARTSTAT=IN-PROCESS:mailto:b@example.com
PERCENT-COMPLETE:75
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:19970717T233000Z
RECURRENCE-ID:19980101T170000Z
SEQUENCE:1
END:VTODO
END:VCALENDAR
> expect
from: b@example.com
to: a@example.com
changes:
BEGIN:VCALENDAR
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VTODO
PERCENT-COMPLETE:75
ATTENDEE;PARTSTAT=IN-PROCESS:mailto:b@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19980101T170000Z
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
SEQUENCE:1
REQUEST-STATUS:2.0;Success
END:VTODO
END:VCALENDAR
> send
# Make sure "A" received the reply
> get a@example.com calsrv.example.com-873970198738777-00@example.com
BEGIN:VCALENDAR
PRODID:-//Example/ExampleCalendarClient//EN
VERSION:2.0
BEGIN:VTODO
PRIORITY:1
STATUS:NEEDS-ACTION
SUMMARY:Send Status Reports to Area Managers
DUE:19980103T100000Z
DTSTART:19980101T100000Z
ATTENDEE;ROLE=CHAIR:mailto:a@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:b@example.com
ATTENDEE;RSVP=TRUE;CUTYPE=INDIVIDUAL:mailto:d@example.com
ORGANIZER:mailto:a@example.com
UID:calsrv.example.com-873970198738777-00@example.com
RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
DTSTAMP:1
SEQUENCE:1
END:VTODO
BEGIN:VTODO
PERCENT-COMPLETE:75
ATTENDEE;PARTSTAT=IN-PROCESS:mailto:b@example.com
ORGANIZER:mailto:a@example.com
RECURRENCE-ID:19980101T170000Z
UID:calsrv.example.com-873970198738777-00@example.com
DTSTAMP:0
SEQUENCE:1
END:VTODO
END:VCALENDAR

View File

@@ -42,39 +42,39 @@ from: cyrus@example.com
to: bernard@example.net
changes:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:1
UID:9263504FD3AD
DTSTART;TZID=America/Montreal:20090601T150000
DTEND;TZID=America/Montreal:20090601T160000
RRULE:FREQ=DAILY;COUNT=5;INTERVAL=1
TRANSP:OPAQUE
SUMMARY:Review Internet-Draft
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
DTEND;TZID=America/Montreal:20090601T160000
DTSTART;TZID=America/Montreal:20090601T150000
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;RSVP=
TRUE;PARTSTAT=NEEDS-ACTION:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
RRULE:FREQ=DAILY;COUNT=5;INTERVAL=1
DTSTAMP:0
SEQUENCE:1
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Montreal
BEGIN:STANDARD
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20070311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
@@ -85,38 +85,38 @@ END:VCALENDAR
# Make sure the participant receives the event
> get bernard@example.net 9263504FD3AD
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:1
UID:9263504FD3AD
DTSTART;TZID=America/Montreal:20090601T150000
DTEND;TZID=America/Montreal:20090601T160000
RRULE:FREQ=DAILY;COUNT=5;INTERVAL=1
TRANSP:OPAQUE
SUMMARY:Review Internet-Draft
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
DTEND;TZID=America/Montreal:20090601T160000
DTSTART;TZID=America/Montreal:20090601T150000
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;RSVP=
TRUE;PARTSTAT=NEEDS-ACTION:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
RRULE:FREQ=DAILY;COUNT=5;INTERVAL=1
DTSTAMP:0
SEQUENCE:1
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Montreal
BEGIN:STANDARD
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20070311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
@@ -176,43 +176,43 @@ from: bernard@example.net
to: cyrus@example.com
changes:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:1
UID:9263504FD3AD
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;ROLE=
REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:1
REQUEST-STATUS:2.0;Success
END:VEVENT
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:1
UID:9263504FD3AD
RECURRENCE-ID;TZID=America/Montreal:20090602T150000
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=DECLINED;ROLE=
REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
RECURRENCE-ID;TZID=America/Montreal:20090602T150000
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:1
REQUEST-STATUS:2.0;Success
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Montreal
BEGIN:STANDARD
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20070311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
@@ -223,47 +223,47 @@ END:VCALENDAR
# Organizer receives the response
> get cyrus@example.com 9263504FD3AD
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
BEGIN:VEVENT
UID:9263504FD3AD
SEQUENCE:1
DTSTAMP:1
DTSTART;TZID=America/Montreal:20090601T150000
DTEND;TZID=America/Montreal:20090601T160000
RRULE:FREQ=DAILY;COUNT=5;INTERVAL=1
TRANSP:OPAQUE
SUMMARY:Review Internet-Draft
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
DTEND;TZID=America/Montreal:20090601T160000
DTSTART;TZID=America/Montreal:20090601T150000
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;RSVP=
TRUE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
RRULE:FREQ=DAILY;COUNT=5;INTERVAL=1
DTSTAMP:1
SEQUENCE:1
END:VEVENT
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:1
UID:9263504FD3AD
RECURRENCE-ID;TZID=America/Montreal:20090602T150000
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=DECLINED;ROLE=
REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
RECURRENCE-ID;TZID=America/Montreal:20090602T150000
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:1
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Montreal
BEGIN:STANDARD
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20070311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
@@ -324,32 +324,32 @@ from: bernard@example.net
to: cyrus@example.com
changes:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=DECLINED:mailto:bernard@example.net
ORGANIZER:mailto:cyrus@example.com
RECURRENCE-ID;TZID=America/Montreal:20090603T150000
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:1
RECURRENCE-ID;TZID=America/Montreal:20090603T150000
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Montreal
BEGIN:STANDARD
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20070311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR
@@ -360,55 +360,55 @@ END:VCALENDAR
# Organizer receives the response
> get cyrus@example.com 9263504FD3AD
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
BEGIN:VEVENT
ORGANIZER:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=DECLINED:mailto:bernard@example.net
ORGANIZER:mailto:cyrus@example.com
RECURRENCE-ID;TZID=America/Montreal:20090603T150000
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:1
RECURRENCE-ID;TZID=America/Montreal:20090603T150000
END:VEVENT
BEGIN:VEVENT
UID:9263504FD3AD
SEQUENCE:1
DTSTAMP:1
DTSTART;TZID=America/Montreal:20090601T150000
DTEND;TZID=America/Montreal:20090601T160000
RRULE:FREQ=DAILY;COUNT=5;INTERVAL=1
TRANSP:OPAQUE
SUMMARY:Review Internet-Draft
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
DTEND;TZID=America/Montreal:20090601T160000
DTSTART;TZID=America/Montreal:20090601T150000
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;RSVP=
TRUE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
RRULE:FREQ=DAILY;COUNT=5;INTERVAL=1
DTSTAMP:1
SEQUENCE:1
END:VEVENT
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:1
UID:9263504FD3AD
RECURRENCE-ID;TZID=America/Montreal:20090602T150000
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=DECLINED;ROLE=
REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
RECURRENCE-ID;TZID=America/Montreal:20090602T150000
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:1
END:VEVENT
BEGIN:VTIMEZONE
TZID:America/Montreal
BEGIN:STANDARD
DTSTART:20071104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20070311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
END:VTIMEZONE
END:VCALENDAR

View File

@@ -26,51 +26,51 @@ from: cyrus@example.com
to: bernard@example.net, mike@example.org, wilfredo@example.com
changes:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
METHOD:REQUEST
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:1
UID:9263504FD3AD
DTSTART:20090602T160000Z
DTEND:20090602T170000Z
TRANSP:OPAQUE
SUMMARY:Lunch
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
DTEND:20090602T170000Z
DTSTART:20090602T160000Z
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Mike Douglass";CUTYPE=INDIVIDUAL;RSVP=TRUE;PARTSTAT=NEEDS-ACTI
ON:mailto:mike@example.org
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR
# Make sure the sequence number is updated
> get cyrus@example.com 9263504FD3AD
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
BEGIN:VEVENT
UID:9263504FD3AD
SEQUENCE:1
DTSTAMP:1
DTSTART:20090602T160000Z
DTEND:20090602T170000Z
TRANSP:OPAQUE
SUMMARY:Lunch
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
DTEND:20090602T170000Z
DTSTART:20090602T160000Z
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Mike Douglass";CUTYPE=INDIVIDUAL;RSVP=TRUE:mailto:mike@example.
org
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
DTSTAMP:1
SEQUENCE:1
END:VEVENT
END:VCALENDAR
@@ -80,25 +80,25 @@ END:VCALENDAR
# Make sure the message was received by the attendees
> get wilfredo@example.com 9263504FD3AD
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:1
UID:9263504FD3AD
DTSTART:20090602T160000Z
DTEND:20090602T170000Z
TRANSP:OPAQUE
SUMMARY:Lunch
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
DTEND:20090602T170000Z
DTSTART:20090602T160000Z
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Mike Douglass";CUTYPE=INDIVIDUAL;RSVP=TRUE;PARTSTAT=NEEDS-ACTI
ON:mailto:mike@example.org
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:1
END:VEVENT
END:VCALENDAR
@@ -131,29 +131,29 @@ END:VCALENDAR
# Make sure the sequence number is not updated
> get wilfredo@example.com 9263504FD3AD
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
BEGIN:VEVENT
UID:9263504FD3AD
SEQUENCE:0
DTSTAMP:1
DTSTART:20090602T160000Z
DTEND:20090602T170000Z
TRANSP:OPAQUE
SUMMARY:Lunch
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;ROLE=
REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
DTEND:20090602T170000Z
DTSTART:20090602T160000Z
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Mike Douglass";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;RSVP=TR
UE:mailto:mike@example.org
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;ROLE=
REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
DTSTAMP:1
SEQUENCE:0
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Reminder
ACTION:DISPLAY
TRIGGER:-PT15M
END:VALARM
END:VEVENT
END:VCALENDAR
@@ -163,16 +163,16 @@ from: wilfredo@example.com
to: cyrus@example.com
changes:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
METHOD:REPLY
PRODID:-//Stalwart Labs LLC//Stalwart Server//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:0
SEQUENCE:0
UID:9263504FD3AD
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;ROLE=
REQ-PARTICIPANT;RSVP=TRUE:mailto:wilfredo@example.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
DTSTAMP:0
SEQUENCE:0
REQUEST-STATUS:2.0;Success
END:VEVENT
END:VCALENDAR
@@ -183,25 +183,25 @@ END:VCALENDAR
# Make sure the message was received by the organizer
> get cyrus@example.com 9263504FD3AD
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
BEGIN:VEVENT
UID:9263504FD3AD
SEQUENCE:1
DTSTAMP:1
DTSTART:20090602T160000Z
DTEND:20090602T170000Z
TRANSP:OPAQUE
SUMMARY:Lunch
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;
RSVP=TRUE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:mailto:wilfredo@example.com
DTEND:20090602T170000Z
DTSTART:20090602T160000Z
TRANSP:OPAQUE
ATTENDEE;CN="Bernard Desruisseaux";CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;
ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:bernard@example.net
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cyrus@e
xample.com
ATTENDEE;CN="Mike Douglass";CUTYPE=INDIVIDUAL;RSVP=TRUE:mailto:mike@example.
org
ATTENDEE;CN="Wilfredo Sanchez Vega";CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;
RSVP=TRUE;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:mailto:wilfredo@example.com
ORGANIZER;CN="Cyrus Daboo":mailto:cyrus@example.com
UID:9263504FD3AD
DTSTAMP:1
SEQUENCE:1
END:VEVENT
END:VCALENDAR

View File

@@ -0,0 +1,413 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use ahash::AHashMap;
use calcard::{
common::PartialDateTime,
icalendar::{ICalendar, ICalendarMethod, ICalendarProperty, ICalendarValue},
};
use groupware::scheduling::{
ItipMessage,
event_cancel::itip_cancel,
event_create::itip_create,
event_update::itip_update,
inbound::{MergeResult, itip_import_message, itip_merge_changes, itip_process_message},
snapshot::itip_snapshot,
};
use std::{collections::hash_map::Entry, path::PathBuf};
struct Test {
test_name: String,
command: Command,
line_num: usize,
parameters: Vec<String>,
payload: String,
}
#[derive(Debug, PartialEq, Eq)]
enum Command {
Put,
Get,
Delete,
Expect,
Send,
Reset,
Itip,
}
pub fn test() {
for entry in std::fs::read_dir(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("resources")
.join("itip"),
)
.unwrap()
{
let entry = entry.unwrap();
let path = entry.path();
if path.extension().is_none_or(|ext| ext != "txt") {
continue;
}
let file_name = path.file_name().unwrap().to_str().unwrap();
let rules = std::fs::read_to_string(&path).unwrap();
let mut last_comment = "";
let mut last_command = "";
let mut last_line_num = 0;
let mut payload = String::new();
let mut commands = Vec::new();
for (line_num, line) in rules.lines().enumerate() {
if line.starts_with('#') {
last_comment = line.trim_start_matches('#').trim();
} else if let Some(command) = line.strip_prefix("> ") {
last_command = command.trim();
last_line_num = line_num;
} else if !line.is_empty() {
payload.push_str(line);
payload.push('\n');
} else {
if last_command.is_empty() && payload.is_empty() {
continue;
}
let mut command_and_args = last_command.split_whitespace();
let command = match command_and_args
.next()
.expect("Command should not be empty")
{
"put" => Command::Put,
"get" => Command::Get,
"expect" => Command::Expect,
"send" => Command::Send,
"delete" => Command::Delete,
"reset" => Command::Reset,
"itip" => Command::Itip,
_ => panic!("Unknown command: {}", last_command),
};
commands.push(Test {
command,
test_name: last_comment.to_string(),
line_num: last_line_num,
parameters: command_and_args.map(String::from).collect(),
payload: payload.trim().to_string(),
});
last_command = "";
last_line_num = 0;
payload.clear();
}
}
if commands.is_empty() {
panic!("No commands found in file: {}", file_name);
} else if !last_command.is_empty() {
panic!(
"File ended with command '{}' at line {} without payload",
last_command, last_line_num
);
}
println!("====== Running test: {} ======", file_name);
let mut store: AHashMap<String, AHashMap<String, ICalendar>> = AHashMap::new();
let mut dtstamp_map: AHashMap<PartialDateTime, usize> = AHashMap::new();
let mut last_itip = None;
for command in &commands {
if command.command != Command::Put {
println!("{} (line {})", command.test_name, command.line_num);
}
match command.command {
Command::Put => {
let account = command
.parameters
.first()
.expect("Account parameter is required");
let name = command
.parameters
.get(1)
.expect("Name parameter is required");
let mut ical = ICalendar::parse(&command.payload)
.expect("Failed to parse iCalendar payload");
match store
.entry(account.to_string())
.or_default()
.entry(name.to_string())
{
Entry::Occupied(mut entry) => {
last_itip = Some(itip_update(&mut ical, entry.get_mut(), &[account]));
entry.insert(ical);
}
Entry::Vacant(entry) => {
last_itip = Some(
itip_create(&mut ical, &[account]).map(|message| vec![message]),
);
entry.insert(ical);
}
}
}
Command::Get => {
let account = command
.parameters
.first()
.expect("Account parameter is required")
.as_str();
let name = command
.parameters
.get(1)
.expect("Name parameter is required")
.as_str();
let ical = ICalendar::parse(&command.payload)
.expect("Failed to parse iCalendar payload")
.to_string()
.replace("\r\n", "\n");
store
.get(account)
.and_then(|account_store| account_store.get(name))
.map(|stored_ical| {
let stored_ical = normalize_ical(stored_ical.clone(), &mut dtstamp_map);
if stored_ical != ical {
panic!(
"ICalendar mismatch for {}: expected {}, got {}",
command.test_name, ical, stored_ical
);
}
})
.unwrap_or_else(|| {
panic!(
"ICalendar not found for account: {}, name: {}",
account, name
);
});
}
Command::Delete => {
let account = command
.parameters
.first()
.expect("Account parameter is required")
.as_str();
let name = command
.parameters
.get(1)
.expect("Name parameter is required")
.as_str();
let store = store.get_mut(account).expect("Account not found in store");
if let Some(mut ical) = store.remove(name) {
last_itip =
Some(itip_cancel(&mut ical, &[account]).map(|message| vec![message]));
} else {
panic!(
"ICalendar not found for account: {}, name: {}",
account, name
);
}
}
Command::Expect => {
let last_itip_str = match last_itip
.as_ref()
.expect("No last iTIP message to compare against")
{
Ok(m) => {
let mut result = String::new();
for (i, m) in m.iter().enumerate() {
if i > 0 {
result.push_str("================================\n");
}
result.push_str(&m.to_string(&mut dtstamp_map));
}
result
}
Err(e) => format!("{e:?}"),
};
assert_eq!(
command.payload.trim(),
last_itip_str.trim(),
"iTIP message mismatch for {} at line {}: expected {}, got {}",
command.test_name,
command.line_num,
command.payload,
last_itip_str
);
}
Command::Send => {
let mut results = String::new();
match last_itip {
Some(Ok(messages)) => {
for message in messages {
for rcpt in &message.to {
let result = match itip_snapshot(
&message.message,
&[rcpt.as_str()],
false,
) {
Ok(itip_snapshots) => {
match store
.entry(rcpt.to_string())
.or_default()
.entry(itip_snapshots.uid.to_string())
{
Entry::Occupied(mut entry) => {
let ical = entry.get_mut();
let snapshots = itip_snapshot(
ical,
&[rcpt.as_str()],
false,
)
.expect("Failed to create iTIP snapshot");
match itip_process_message(
ical,
snapshots,
&message.message,
itip_snapshots,
message.from.clone(),
) {
Ok(result) => match result {
MergeResult::Actions(changes) => {
itip_merge_changes(ical, changes);
Ok(None)
}
MergeResult::Message(message) => {
Ok(Some(message))
}
MergeResult::None => Ok(None),
},
Err(err) => Err(err),
}
}
Entry::Vacant(entry) => {
let mut message = message.message.clone();
itip_import_message(&mut message)
.expect("Failed to import iTIP message");
entry.insert(message);
Ok(None)
}
}
}
Err(err) => Err(err),
};
match result {
Ok(Some(itip_message)) => {
results.push_str(
&itip_message.to_string(&mut dtstamp_map),
);
}
Ok(None) => {}
Err(e) => {
results.push_str(&format!("{e:?}"));
}
}
}
}
assert_eq!(
results.trim(),
command.payload.trim(),
"iTIP send result mismatch for {} at line {}: expected {}, got {}",
command.test_name,
command.line_num,
command.payload,
results
);
}
Some(Err(e)) => {
panic!(
"Failed to create iTIP message for {} at line {}: {:?}",
command.test_name, command.line_num, e
);
}
None => {
panic!(
"No iTIP message to send for {} at line {}",
command.test_name, command.line_num
);
}
}
last_itip = None;
}
Command::Itip => {
let mut commands = command.parameters.iter();
last_itip = Some(Ok(vec![ItipMessage {
method: ICalendarMethod::Request,
from: commands
.next()
.expect("From parameter is required")
.to_string(),
to: commands.map(|s| s.to_string()).collect::<Vec<_>>(),
changed_properties: vec![],
message: ICalendar::parse(&command.payload)
.expect("Failed to parse iCalendar payload"),
}]))
}
Command::Reset => {
store.clear();
dtstamp_map.clear();
last_itip = None;
}
}
}
}
}
trait ItipMessageExt {
fn to_string(&self, map: &mut AHashMap<PartialDateTime, usize>) -> String;
}
impl ItipMessageExt for ItipMessage {
fn to_string(&self, map: &mut AHashMap<PartialDateTime, usize>) -> String {
use std::fmt::Write;
let mut f = String::new();
let mut to = self.to.iter().map(|t| t.as_str()).collect::<Vec<_>>();
to.sort_unstable();
let mut changed = self
.changed_properties
.iter()
.map(|p| p.as_str())
.collect::<Vec<_>>();
changed.sort_unstable();
writeln!(&mut f, "from: {}", self.from).unwrap();
writeln!(&mut f, "to: {}", to.join(", ")).unwrap();
writeln!(&mut f, "changes: {}", changed.join(", ")).unwrap();
write!(&mut f, "{}", normalize_ical(self.message.clone(), map)).unwrap();
f
}
}
fn normalize_ical(mut ical: ICalendar, map: &mut AHashMap<PartialDateTime, usize>) -> String {
let mut comps = ical
.components
.iter()
.enumerate()
.filter(|(comp_id, _)| {
ical.components[0]
.component_ids
.contains(&(*comp_id as u16))
})
.collect::<Vec<_>>();
comps.sort_unstable_by_key(|(_, comp)| *comp);
ical.components[0].component_ids = comps.iter().map(|(comp_id, _)| *comp_id as u16).collect();
for comp in &mut ical.components {
for entry in &mut comp.entries {
if let (ICalendarProperty::Dtstamp, Some(ICalendarValue::PartialDateTime(dt))) =
(&entry.name, entry.values.first())
{
if let Some(index) = map.get(dt) {
entry.values = vec![ICalendarValue::Integer(*index as i64)];
} else {
let index = map.len();
map.insert(dt.as_ref().clone(), index);
entry.values = vec![ICalendarValue::Integer(index as i64)];
}
}
}
comp.entries.sort_unstable();
}
ical.to_string().replace("\r\n", "\n")
}

View File

@@ -48,6 +48,7 @@ use utils::config::Config;
pub mod acl;
pub mod basic;
pub mod cal_alarm;
pub mod cal_itip;
pub mod cal_query;
pub mod card_query;
pub mod copy_move;
@@ -71,7 +72,7 @@ pub async fn webdav_tests() {
)
.await;
basic::test(&handle).await;
/*basic::test(&handle).await;
put_get::test(&handle).await;
mkcol::test(&handle).await;
copy_move::test(&handle).await;
@@ -83,7 +84,8 @@ pub async fn webdav_tests() {
acl::test(&handle).await;
card_query::test(&handle).await;
cal_query::test(&handle).await;
cal_alarm::test(&handle).await;
cal_alarm::test(&handle).await;*/
cal_itip::test();
// Print elapsed time
let elapsed = start_time.elapsed();