# HG changeset patch # User Paul Boddie # Date 1442105928 -7200 # Node ID 12f55f31c92ea13fdbe691d9b2932577c19a7728 # Parent 5fce86b01ca936499162833dbbeb571a03cb9c82 Added support to the person handler for responding with REFRESH messages when receiving ADD messages. Tidied up organiser replacement preferences access. diff -r 5fce86b01ca9 -r 12f55f31c92e docs/preferences.txt --- a/docs/preferences.txt Sun Sep 13 02:52:21 2015 +0200 +++ b/docs/preferences.txt Sun Sep 13 02:58:48 2015 +0200 @@ -17,6 +17,21 @@ The default time zone/regime for calendars, new events and local times. +add_method_response +------------------- + +Default: refresh +Alternatives (see below) + +Indicate how ADD methods shall be responded to when received by a recipient: + + add apply them to events as received + + ignore ignore attempts to add event occurrences + + refresh respond with a REFRESH message to obtain a proper + request will all event details + event_refreshing ---------------- diff -r 5fce86b01ca9 -r 12f55f31c92e imiptools/client.py --- a/imiptools/client.py Sun Sep 13 02:52:21 2015 +0200 +++ b/imiptools/client.py Sun Sep 13 02:58:48 2015 +0200 @@ -108,9 +108,16 @@ prefs = self.get_preferences() return prefs and prefs.get("event_refreshing") == "always" or False - def allow_organiser_replacement(self): + def allow_add(self): + return self.get_add_method_response() in ("add", "refresh") + + def get_add_method_response(self): prefs = self.get_preferences() - return prefs and prefs.get("organiser_replacement", "attendee") or False + return prefs and prefs.get("add_method_response", "refresh") or "refresh" + + def get_organiser_replacement(self): + prefs = self.get_preferences() + return prefs and prefs.get("organiser_replacement", "attendee") or "attendee" def have_manager(self): return MANAGER_INTERFACE diff -r 5fce86b01ca9 -r 12f55f31c92e imiptools/data.py --- a/imiptools/data.py Sun Sep 13 02:52:21 2015 +0200 +++ b/imiptools/data.py Sun Sep 13 02:58:48 2015 +0200 @@ -157,6 +157,9 @@ def get(self, name): return self.details.get(name) + def keys(self): + return self.details.keys() + def __getitem__(self, name): return self.details[name] @@ -176,6 +179,11 @@ for name in names: self.remove(name) + def preserve(self, names): + for name in self.keys(): + if not name in names: + self.remove(name) + # Computed results. def get_main_period_items(self, tzid): diff -r 5fce86b01ca9 -r 12f55f31c92e imiptools/handlers/__init__.py --- a/imiptools/handlers/__init__.py Sun Sep 13 02:52:21 2015 +0200 +++ b/imiptools/handlers/__init__.py Sun Sep 13 02:58:48 2015 +0200 @@ -158,7 +158,7 @@ # Test against any previously-received organiser details. if not self.is_recognised_organiser(organiser): - replacement = self.allow_organiser_replacement() + replacement = self.get_organiser_replacement() # Allow any organiser as a replacement where indicated. diff -r 5fce86b01ca9 -r 12f55f31c92e imiptools/handlers/person.py --- a/imiptools/handlers/person.py Sun Sep 13 02:52:21 2015 +0200 +++ b/imiptools/handlers/person.py Sun Sep 13 02:58:48 2015 +0200 @@ -30,7 +30,10 @@ def _add(self, queue=True): - "Add a recurrence for the current object." + """ + Add an event occurrence for the current object or produce a response + that requests the event details to be sent again. + """ # Obtain valid organiser and attendee details. @@ -40,29 +43,49 @@ (organiser, organiser_attr), attendees = oa - # Ignore unknown objects. - # NOTE: We could issue a REFRESH to get such objects. + # Request details where configured, doing so for unknown objects anyway. + + refreshing = not self.get_stored_object_version() or self.get_add_method_response() == "refresh" + + if refreshing: + + # Add SENT-BY details to the recipient's attributes. - if not self.get_stored_object_version(): - return + attendee_attr = attendees[self.user] + self.update_sender(attendee_attr) + + # Make a new object with a minimal property selection. + + obj = self.obj.copy() + obj.preserve(("ORGANIZER", "DTSTAMP", "UID", "RECURRENCE-ID")) + obj["ATTENDEE"] = [(self.user, attendee_attr)] + + # Send a REFRESH message in response. + + self.add_result("REFRESH", [get_address(organiser)], obj.to_part("REFRESH")) # Record the event as a recurrence of the parent object. self.update_recurrenceid() + # Update the recipient's record of the organiser's schedule. + + self.update_freebusy_from_organiser(organiser) + + # Stop if requesting the full event. + + if refreshing: + return + + # Set the additional occurrence. + + self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node()) + # Queue any request, if appropriate. if queue: self.store.queue_request(self.user, self.uid, self.recurrenceid) - # Update the recipient's record of the organiser's schedule. - - self.update_freebusy_from_organiser(organiser) - - # Set the additional occurrence. - - self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node()) - return True def _record(self, from_organiser=True, queue=False, cancel=False): @@ -205,7 +228,7 @@ "Queue a suggested additional recurrence for any active event." - if self._add(queue=True): + if self.allow_add() and self._add(queue=True): return self.wrap("An addition to an event has been received.") def cancel(self): diff -r 5fce86b01ca9 -r 12f55f31c92e tests/templates/event-request-person-recurring-add.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/templates/event-request-person-recurring-add.txt Sun Sep 13 02:58:48 2015 +0200 @@ -0,0 +1,35 @@ +Content-Type: multipart/alternative; boundary="===============0047278175==" +MIME-Version: 1.0 +From: paul.boddie@example.com +To: vincent.vole@example.com +Subject: Invitation! + +--===============0047278175== +Content-Type: text/plain; charset="us-ascii" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit + +This message contains an event. + +--===============0047278175== +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Content-Type: text/calendar; charset="us-ascii"; method="ADD" + +BEGIN:VCALENDAR +PRODID:-//imip-agent/test//EN +METHOD:ADD +VERSION:2.0 +BEGIN:VEVENT +ORGANIZER:mailto:paul.boddie@example.com +ATTENDEE;RSVP=TRUE:mailto:vincent.vole@example.com +ATTENDEE;RSVP=TRUE:mailto:paul.boddie@example.com +DTSTAMP:20141009T182400Z +DTSTART;TZID=Europe/Oslo:20150109T100000 +DTEND;TZID=Europe/Oslo:20150109T110000 +SUMMARY:Another event occurrence +UID:event8@example.com +END:VEVENT +END:VCALENDAR + +--===============0047278175==-- diff -r 5fce86b01ca9 -r 12f55f31c92e tests/test_person_invitation_add.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_person_invitation_add.sh Sun Sep 13 02:58:48 2015 +0200 @@ -0,0 +1,178 @@ +#!/bin/sh + +THIS_DIR=`dirname $0` + +TEMPLATES="$THIS_DIR/templates" +PERSON_SCRIPT="$THIS_DIR/../imip_person.py" +SHOWMAIL="$THIS_DIR/../tools/showmail.py" +STORE=/tmp/store +STATIC=/tmp/static +PREFS=/tmp/prefs +ARGS="-S $STORE -P $STATIC -p $PREFS -d" +USER="mailto:vincent.vole@example.com" +SENDER="mailto:paul.boddie@example.com" +FBFILE="$STORE/$USER/freebusy" +FBOTHERFILE="$STORE/$USER/freebusy-other/$SENDER" +FBSENDERFILE="$STORE/$SENDER/freebusy" +FBSENDEROTHERFILE="$STORE/$SENDER/freebusy-other/$USER" +TAB=`printf '\t'` + +OUTGOING_SCRIPT="$THIS_DIR/../imip_person_outgoing.py" + +PYTHONPATH="$THIS_DIR/.." +export PYTHONPATH + +ACCEPT_SCRIPT="$THIS_DIR/test_handle.py" +ACCEPT_ARGS="accept $STORE" + +DECLINE_SCRIPT="$THIS_DIR/test_handle.py" +DECLINE_ARGS="decline $STORE" + +ERROR=err.tmp + +rm -r $STORE +rm -r $STATIC +rm -r $PREFS +rm $ERROR +rm out*.tmp + +mkdir -p "$PREFS/$USER" +echo 'Europe/Oslo' > "$PREFS/$USER/TZID" +echo 'share' > "$PREFS/$USER/freebusy_sharing" + +mkdir -p "$PREFS/$SENDER" +echo 'Europe/Oslo' > "$PREFS/$USER/TZID" +echo 'always' > "$PREFS/$SENDER/event_refreshing" + +# Test event request registration in the outgoing handler. + +"$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring.txt" 2>> $ERROR + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDERFILE" \ +&& echo "Success" \ +|| echo "Failed" + +# Present the request to the recipient. + + "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring.txt" 2>> $ERROR \ +| "$SHOWMAIL" \ +> out2.tmp + + ! grep -q 'METHOD:REPLY' out2.tmp \ +&& echo "Success" \ +|| echo "Failed" + + ! [ -e "$FBFILE" ] \ +|| ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ +&& echo "Success" \ +|| echo "Failed" + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ +&& echo "Success" \ +|| echo "Failed" + +# Test acceptance and registration in the outgoing handler. + + "$ACCEPT_SCRIPT" $ACCEPT_ARGS "$USER" "event8@example.com" 2>> $ERROR \ +| tee out3.tmp \ +| "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR + + "$SHOWMAIL" < out3.tmp | grep -q 'METHOD:REPLY' \ +&& echo "Success" \ +|| echo "Failed" + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ +&& echo "Success" \ +|| echo "Failed" + +# Present the result to the recipient. + + "$PERSON_SCRIPT" $ARGS < out3.tmp 2>> $ERROR \ +| "$SHOWMAIL" \ +> out4.tmp + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDEROTHERFILE" \ +&& echo "Success" \ +|| echo "Failed" + +# Attempt to add an occurrence to the event. + +"$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring-add.txt" 2>> $ERROR + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDERFILE" \ +&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBSENDERFILE" \ +&& echo "Success" \ +|| echo "Failed" + +# Present the request to the recipient. + + "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring-add.txt" 2>> $ERROR \ +| "$SHOWMAIL" \ +> out5.tmp + + grep -q 'METHOD:REFRESH' out5.tmp \ +&& echo "Success" \ +|| echo "Failed" + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ +&& ! grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBFILE" \ +&& echo "Success" \ +|| echo "Failed" + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ +&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBOTHERFILE" \ +&& echo "Success" \ +|| echo "Failed" + +# Present the refresh message to the organiser. + + "$PERSON_SCRIPT" $ARGS < out5.tmp 2>> $ERROR \ +| "$SHOWMAIL" \ +> out6.tmp + + grep -q 'METHOD:REQUEST' out6.tmp \ +&& echo "Success" \ +|| echo "Failed" + +# Present the request to the recipient. + + "$PERSON_SCRIPT" $ARGS < out6.tmp 2>> $ERROR \ +| "$SHOWMAIL" \ +> out7.tmp + + ! grep -q 'METHOD:REPLY' out7.tmp \ +&& echo "Success" \ +|| echo "Failed" + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ +&& ! grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBFILE" \ +&& echo "Success" \ +|| echo "Failed" + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ +&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBOTHERFILE" \ +&& echo "Success" \ +|| echo "Failed" + +# Test acceptance and registration in the outgoing handler. + + "$ACCEPT_SCRIPT" $ACCEPT_ARGS "$USER" "event8@example.com" 2>> $ERROR \ +| tee out8.tmp \ +| "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR + + "$SHOWMAIL" < out8.tmp | grep -q 'METHOD:REPLY' \ +&& echo "Success" \ +|| echo "Failed" + + "$ACCEPT_SCRIPT" $ACCEPT_ARGS "$USER" "event8@example.com" "20150109T090000Z" 2>> $ERROR \ +| tee out9.tmp \ +| "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR + + "$SHOWMAIL" < out9.tmp | grep -q 'METHOD:REPLY' \ +&& echo "Success" \ +|| echo "Failed" + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ +&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBFILE" \ +&& echo "Success" \ +|| echo "Failed"