Cyrus CalDAV Scheduling Flowchart
caldav_put() - create/modify via HTTP PUT on a
resource or POST (add-member) on a calendar
- Check if the new resource is a scheduling resource (contains
ORGANIZER property). If not, skip to step 4.
- Check for (and load) any existing resource.
- Check if the authenticated user matches ORGANIZER:
- Store the new/modified resource.
caldav_delete_sched() - remove via HTTP
DELETE on a resource
- Check if the existing resource is a scheduling resource (has
Schedule-Tag). If not, we are done.
- Load the existing resource.
- Check if the authenticated user matches ORGANIZER. If yes,
goto sched_request(), otherwise
goto sched_reply().
caldav_post() - busytime query via HTTP POST on
Scheduling Outbox
- Check the ACL on the owner's Scheduling Outbox. If the
authenticated user doesn't have the DACL_SCHEDFB right, fail.
- sched_busytime_query().
sched_pollstatus - perform a voter
response update
sched_request() - perform an organizer
request / attendee status update
- Check the ACL on the owner's Scheduling Outbox. If the
authenticated user doesn't have the DACL_INVITE right, fail.
- If the request includes a resource, then set METHOD:REQUEST,
otherwise set METHOD:CANCEL.
- Create an iTIP message template, copying over any
CALSCALE property and VTIMEZONE components.
- If not an attendee status update and the existing resource is a
scheduling resource:
Foreach component in the existing resource, add it and
its SEQUENCE to our hash table keyed by RECURRENCE-ID (for
comparison against new/modified resource).
- Create a hash table of attendees. This will hold
attendee-specific iTIP messages.
- Foreach component in the new/modified resource:
- Lookup (by RECURRENCE-ID) and remove the component from the
hash table of existing components.
- If the component exists compare all of DTSTART, DTEND,
DURATION, RRULE, RDATE, EXDATE to those of the new
component.
- If the component is new or changed,
then process_attendees().
- Foreach remaining component in the hash table of existing
components do sched_cancel().
- Foreach iTIP message in our hash table of
ATTENDEES, sched_deliver() the iTIP
message.
- Foreach component in the new/modified resource update the
SCHEDULE-STATUS of each ATTENDEE.
process_attendees() - create a suitable
iTIP request message for each attendee
- Foreach ATTENDEE in the component, remove the SCHEDULE-STATUS
parameter, and set PROPSTAT=NEEDS-ACTION if required.
- Make a copy of the component and
clean_component().
- Foreach ATTENDEE in the cleaned component:
- Check the CalDAV Scheduling parameters. If SCHEDULE-AGENT
!= SERVER, skip to the next attendee.
- Lookup attendee in our hash table.
- If it doesn't exist, create a clone of our iTIP template and
insert it into our hash table of attendees.
- Add the component to the attendee's iTIP message.
- Add the component “number” to our mask of new components
appearing in the attendee's iTIP message.
- If the component is not the "master", foreach attendee do
sched_exclude().
sched_exclude() - exclude an attendee from a
recurrence instance
- If the component did not appear in the attendee's iTIP
message, add an EXDATE property (based on the RECURRENCE-ID of
the component) to the master component of the attendee's iTIP
message.
sched_cancel() - cancel an organizer event/task
- Set STATUS:CANCELLED on the component.
- process_attendees().
sched_reply() - perform an attendee reply
- Check the CalDAV Scheduling parameters on ORGANIZER. If
SCHEDULE-AGENT != SERVER, we are done.
- Check the ACL on the owner's Scheduling Outbox. If the
authenticated user doesn't have the DACL_REPLY right, fail.
- Create a new iTIP (METHOD:REPLY) message, copying over any
CALSCALE property and VTIMEZONE components.
- Foreach component in the existing resource:
- trim_attendees().
- Add the trimmed component and the attendee's PARTSTAT to our
hash table keyed by RECURRENCE-ID (for comparison against
new/modified resource).
- Foreach component in the new/modified resource:
- trim_attendees().
- Lookup (by RECURRENCE-ID) and remove the component from the
hash table of existing components.
- If the component exists:
- If component is VPOLL, add voter responses to REPLY
via sched_vpoll_reply().
- Otherwise, compare the PARTSTAT of the ATTENDEE to that of
the new component.
- If the component is new or the PARTSTAT has changed:
- clean_component().
- Add the component to our iTIP message.
- Add the component “number” to our mask of new components
appearing in our iTIP message.
- Foreach remaining component in the hash table of existing
components do sched_decline().
- sched_deliver() our iTIP
message.
- Foreach component in the new/modified resource that appeared
in our iTIP message, update the SCHEDULE-STATUS of the ORGANIZER.
trim_attendees() - remove all attendees
other than the one replying
- Clone the component and remove all ATTENDEE properties other
than the one corresponding to the owner of the calendar.
- Return the ATTENDEE property of owner, his/her PARTSTAT
parameter, and the RECURRENCE-ID of the component.
sched_vpoll_reply() - add voter
responses to VPOLL reply
sched_decline() - decline a recurrence
instance for an attendee
- Set PARTSTAT of ATTENDEE to DECLINED.
- clean_component().
- Add the component to our iTIP message.
clean_component() - sanitize a component
for use in an iTIP message
- Update DTSTAMP.
- Remove any VALARM components.
- For a reply/decline only, remove scheduling parameters from
ORGANIZER.
sched_deliver() - deliver an iTIP message to
a recipient
- Lookup the recipient.
- If local to our server goto
sched_deliver_local(),
otherwise goto
sched_deliver_remote().
sched_deliver_local() - deliver an
iTIP message to a local user
- Check the ACL on the owner's Scheduling Inbox. If the
sender doesn't have the proper right (DACL_INVITE for
request/cancel, DACL_REPLY for reply), fail.
- Search the recipient's calendars for a resource having the
specified UID.
- If the resource doesn't exist:
- If the iTIP method is REPLY, fail (we are done).
- If the iTIP method is CANCEL, ignore it (we are done).
- Otherwise, create a new (empty) attendee object and target
the recipient's Default calendar.
- Otherwise, load the existing resource.
- Update the new/existing resource:
- If the iTIP method is CANCEL, set STATUS:CANCELLED on all
existing components.
- If the iTIP method is REPLY, do
deliver_merge_reply().
- If the iTIP method is REQUEST, do
deliver_merge_request().
- If the iTIP method is POLLSTATUS, do
deliver_merge_pollstatus().
- Store the new/updated resource in the recipient's target
calendar.
- Record the delivery status (SCHEDULE-STATUS).
- If the iTIP message is something other than just a PARTSTAT
update from an attendee, store the iTIP message as a new
resource in the recipient's Inbox.
- If the iTIP method is REPLY, send an update other attendees
via sched_pollstatus() (VPOLL only)
or sched_request().
deliver_merge_reply() - update
an organizer resource with an attendee reply
- Foreach component in the existing resource, add it to our
hash table keyed by RECURRENCE-ID (for comparison against
iTIP message).
- Foreach component in the iTIP message:
- Lookup (by RECURRENCE-ID) the component from the
hash table of existing components.
- If the component doesn't exist (new recurrence overridden by
ATTENDEE) create a new recurring component:
- Clone the existing master component.
- Remove the RRULE property.
- Add the RECURRENCE-ID from the iTIP message.
- Replace the DTSTART, DTEND, SEQUENCE properties with those
from the iTIP message.
- Add the new component to our existing resource.
- Get the sending ATTENDEE from the iTIP message.
- Find the matching ATTENDEE in the existing component.
- If not found (ATTENDEE added themselves to this recurrence),
add new ATTENDEE to the component.
- Set the ATTENDEE PARTSTAT, RSVP, and SCHEDULE-STATUS
parameters in the existing component.
- If the component is VPOLL, update the voter responses in the
existing component via
deliver_merge_vpoll_reply().
- Return the sending ATTENDEE.
deliver_merge_vpoll_reply() - update
an organizer resource with voter responses
- Foreach sub-component in the existing resource, replace any
voter response(s) with those from the reply.
deliver_merge_request() -
create/update an attendee resource with an organizer request
- Foreach VTIMEZONE component in the existing resource, add it
to our hash table keyed by TZID (for comparison against iTIP
message).
- Foreach VTIMEZONE component in the iTIP message:
- Lookup (by TZID) the VTIMEZONE component from the hash table of
existing components.
- If the component exists, remove it from the existing
object.
- Add the VTIMEZONE from the iTIP message to our existing
object.
- Foreach component in the existing resource, add it to our
hash table keyed by RECURRENCE-ID (for comparison against
iTIP message).
- Foreach component in the iTIP message:
- Clone a new component from the iTIP component.
- Lookup (by RECURRENCE-ID) the component from the
hash table of existing components.
- If the component exists:
- Compare the SEQUENCE of the new component to the existing
component to see if it has changed.
- Copy any COMPLETED, PERCENT-COMPLETE, or TRANSP properties
from the existing component to the new component.
- Copy any ORGANIZER SCHEDULE-STATUS parameter
from the existing component to the new component.
- Remove the existing component from the existing object.
- Add the new component to the existing object.
deliver_merge_pollstatus() -
update voter responses on a voter resource
- Foreach sub-component in the existing resource, add it to our
hash table keyed by POLL-ITEM-ID (for comparison against
iTIP message). The sub-component entry includes a hash table
of VOTERs.
- Foreach sub-component in the iTIP message:
- Lookup (by POLL-ITEM-ID) the sub-component from the
hash table of existing sub-components.
- If the component exists, foreach VOTER in the sub-component
in the iTIP message:
- Lookup VOTER in the hash table of existing
sub-component.
- Add/update VOTER response.
sched_deliver_remote() - deliver an
iTIP message to a remote user
- If the recipient is local to our Murder, goto
isched_send(), otherwise
goto imip_send().
- Retrieve status of iTIP message delivery.
isched_send() - deliver an iTIP message to a
remote user via iSchedule (HTTP)
imip_send() - deliver an iTIP message to a
remote user via iMIP (SMTP)
sched_busytime_query() - perform a
busytime query
busytime_query_local() - perform a
busytime query on a local user
busytime_query_remote() - perform a
busytime query on a remote user