dav
dav copied to clipboard
Scheduling with external organizer
We are using SabreDAV 3.2.2 and recently activated scheduling, i.e. added
$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
$server->addPlugin(new \Sabre\CalDAV\Schedule\IMipPlugin('[email protected]'));
to our server.php.
Case 1: An internal organizer O creates a calendar entry with an internal attendee A. SabreDAV will then create two calendarobjects in the calendars of O and A and the partstat of A will be tentative in both of them. SabreDAV also sends an email to A. If A accepts the invitation (either from within the email-application or from the calendar-application) a confirmation email is be sent to O.
Case 2: An external orgainzer E creates a calendar entry and invites A. In this case no calendarobjects will be created until A accepts the invitation. At this point I would expect SabreDAV to sent a confirmation email to E. But SabreDAV does not send such an email, neither does the calendar app of A since auto-scheduling prevents this to happen in the client.
I tried to analyse the problem and here's what I found out so far:
- Sabre\CalDAV\Schedule\Plugin::calendarObjectChange() is called after A accepts the invitation. In case 1 parameter $isNew is false, since the calendar of A already contains the event with partstat=tentative. In case 2 $isNew is true.
- calendarObjectChange() calls processICalendarChange() with either $oldObject==NULL or $oldObject!=NULL
- processICalendarChange() then calls Sabre\VObject\ITip\Broker::parseEvent() with either $oldCalendar==NULL or $oldCalendar!=NULL
- parseEvent() has the following lines:
...
} elseif ($oldCalendar) {
// We need to figure out if the user is an attendee, but we're only
// doing so if there's an oldCalendar, because we only want to
// process updates, not creation of new events.
foreach ($eventInfo['attendees'] as $attendee) {
if (in_array($attendee['href'], $userHref)) {
return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
}
}
}
...
- so parseEvent() returns an empty array in case 2 since then $oldCalendar==null
So here are my questions:
- Why is parseEvent() only processing updates of existing events?
It seems to me that this is causing the problem in case 2. I will try to fix this and let you know what happens.
Any other ideas how to fix this?
Peter
It seems like the above problem is caused by three minor SabreDAV bugs, namely:
- Sabre\VObject\ITip\Broker::parseEvent() does not create scheduling events for new events.
- Email addresses are compared case sensitive. I have created a separate issue for that (#1250)
- the schedule-agent property of organizers is handeled in such a way, that no messages are sent when I believe they should. This might be caused by a misunderstanding of RFC6638. I have created another issue for this problem a well (#1252)
Here's what I did so far to make SabreDAV handle new vevents: When Sabre\CalDAV\Schedule\Plugin::calendarObjectChange() is called with $isNew==true, processICalendarChange() was called with $oldObj==null. I changed that such that processICalendarChange() is called with a fake old vevent that I create by cloning the new vevent and removing all attendees.
Here's the old code from vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php:
if (!$isNew) {
$node = $this->server->tree->getNodeForPath($request->getPath());
$oldObj = Reader::read($node->get());
} else {
$oldObj = null;
}
and here's the new one:
if (!$isNew) {
$node = $this->server->tree->getNodeForPath($request->getPath());
$oldObj = Reader::read($node->get());
} else {
$oldObj = null;
if($vCal->VEVENT){
$oldObj=clone $vCal;
unset($oldObj->VEVENT->ATTENDEE);
}
}
I have no idea wether this has unwanted side-effects. With our setup this worked (when #1250 and #1252 are fixed as well)
Peter
@pk1234 Do you get valid ics files with your replies? See also my comments in #1168.
Thanks a lot for your other suggestions.
The solution with the fake $oldObj seems quite hacky.
@evert I know it is sometimes difficult to remember commits that are years old. But could you shed some light on the subject? What I have seen is that creation of new events are not processed (tested with sabre/dav 4.1.0).
because we only want to process updates, not creation of new events.
See changes in (Broker.php): https://github.com/sabre-io/vobject/commit/18c86bcbf8c962b5f1b10b25bd03148aa596f664
The question is when an external organzier sends an event. Which would be the correct method to send a reply for the initial invitation? If I change the else if
into an else
path then a reply is sent to the organzier using the IMipPlugin. I dont't know if this would have any side effects.
https://github.com/sabre-io/vobject/blob/18c86bcbf8c962b5f1b10b25bd03148aa596f664/lib/Sabre/VObject/ITip/Broker.php#L191
Just looking at that line you sent:
My best guess is that, when an event is changed by an attendee of an event, the initial event creation is always triggered by the organizer.
When the event is first created, no attendee action has taken place. Only after the attendee performs an action (update RSVP, delete instance, etc) this would result in a message.
But I'm not sure. I don't really have the time to dig into this or the original issues. I'm no longer involved with this project
OK. Thank you very much for your reply and your great work you've done.
I think this is a bug. If an external organzier creates an event (REQUEST) then no action is taken by the attendee since $oldObj
is null
. The initial action for an event (e.g. ACCEPT) should also create a reply in my point of view.
Under what condition / what clients will create events like this? Just curious, your reasoning seems sound
I've only tested it with an external organizer (Google Calendar and Outlook 365) and the attendee is using eM Client in conjunction with sabre/dav. The external organzier creates an event and sends the invitation to the client (eM Client). In the client software I then accept the event.
Is this going to be fixed officially? I tried changing the else if
to an else
but RSVP emails are still not being sent. My use case is simple: I routinely get invited to events by people using Google Calendar. I RSVP in my client (Thunderbird), but the person who sent me the event invite never gets my RSVP email.
Emails are properly sent to attendees when I create and edit events, they only don't work for RSVPs.
The solution with the fake $oldObj seems quite hacky.
@evert I know it is sometimes difficult to remember commits that are years old. But could you shed some light on the subject? What I have seen is that creation of new events are not processed (tested with sabre/dav 4.1.0).
because we only want to process updates, not creation of new events.
See changes in (Broker.php): sabre-io/vobject@18c86bc
The question is when an external organzier sends an event. Which would be the correct method to send a reply for the initial invitation? If I change the
else if
into anelse
path then a reply is sent to the organzier using the IMipPlugin. I dont't know if this would have any side effects.https://github.com/sabre-io/vobject/blob/18c86bcbf8c962b5f1b10b25bd03148aa596f664/lib/Sabre/VObject/ITip/Broker.php#L191
Update: changing the elseif
to an else
and also doing the fixes outlined in #1250 and #1252 has everything working. I'm still curious why this wouldn't just work out of the box, the use case is common.
If I knew more PHP I would submit PRs w/ tests!
I'm no longer active on this project, so it's up to others to submit a PR and release it.
I tried to find examples regarding Scheduling but I couldn't so far.
I got CalDAV working on my localhost environment (php8 + apache 2.4, dockerized), added to Mac OS Calendar.
If on Mac OS' Calendar app I add some invitees and right click Mail Event
it goes as .ics
file but there's no option natively on the email clients I tested to reply
that (Accept, Decline, Tentative, Propose New Time).
I initially did a small iCal library to handle events (mostly meetings) from one software that I develop/maintain, and it was being handled as a subscribed calendar (not CalDAV, just plain iCalendar format), with REST API and a simple frontend to change invitee's statuses but it was getting big responses, taking longer to update, etc.
Then I decided to find a native solution and I came to sabre/dav and a few other libraries, but I couldn't find enough reading material in any library (or RFCs) to describe the process of Scheduling an event and how "replying" to that would work.
Closest to what I got was just displaying the event, but the user has no option to Confirm presence
.
Any suggestions on how to implement that?
@icaroscherma please don't hijack this bug report. This is off-topic.
You need IMIP: https://tools.ietf.org/html/rfc6047
Hi everybody,
an external organizer does not get a reply if an attendee accepts his invitation. I temporarily fixed that in our 3.2.2 SabreDAV installation (see above) and the 2020-plan was to fix it in version 4 as well.
Now its 2022, we migrated to SabreDAV 4.3.1 and the problem is still there.
It seems obvious to me that an external organizer should receive a reply if an attendee accepts his invitation. In that case processICalendarChange() is called with $oldObject===null (unless my dirty hack is used)
Do we agree, that this is a BUG? Or should I do some RFC-reading first to find out whether this is a bug or not?
Peter