# HG changeset patch # User Paul Boddie # Date 1441406191 -7200 # Node ID 95a18b7a097cd94ad814ed11bbd473a072a0c28b # Parent 58d06d81028ffd3eec4e646effdb4093f37def84 Added initial support for automatic responses to REFRESH messages. diff -r 58d06d81028f -r 95a18b7a097c docs/preferences.txt --- a/docs/preferences.txt Sat Sep 05 00:36:05 2015 +0200 +++ b/docs/preferences.txt Sat Sep 05 00:36:31 2015 +0200 @@ -17,6 +17,16 @@ The default time zone/regime for calendars, new events and local times. +event_refreshing +---------------- + +Default: never +Alternative: always + +Indicate whether messages requesting a refresh of event details shall be +handled automatically. If not, such messages will be passed on to the +recipient for their mail program to handle. + freebusy_bundling ----------------- diff -r 58d06d81028f -r 95a18b7a097c imiptools/client.py --- a/imiptools/client.py Sat Sep 05 00:36:05 2015 +0200 +++ b/imiptools/client.py Sat Sep 05 00:36:31 2015 +0200 @@ -86,6 +86,10 @@ prefs = self.get_preferences() return prefs and prefs.get("freebusy_messages") == "notify" or False + def is_refreshing(self): + prefs = self.get_preferences() + return prefs and prefs.get("event_refreshing") == "always" or False + def have_manager(self): return MANAGER_INTERFACE diff -r 58d06d81028f -r 95a18b7a097c imiptools/handlers/person.py --- a/imiptools/handlers/person.py Sat Sep 05 00:36:05 2015 +0200 +++ b/imiptools/handlers/person.py Sat Sep 05 00:36:31 2015 +0200 @@ -19,7 +19,7 @@ this program. If not, see . """ -from imiptools.data import uri_dict +from imiptools.data import get_address, to_part, uri_dict, uri_item from imiptools.handlers import Handler from imiptools.handlers.common import CommonFreebusy, CommonEvent from imiptools.period import FreeBusyPeriod, Period, replace_overlapping @@ -175,6 +175,62 @@ replace_overlapping(stored_freebusy, period, freebusy) self.store.set_freebusy_for_other(self.user, stored_freebusy, sender) + def _refresh(self): + + """ + Respond to a refresh message by providing complete event details to + attendees. + """ + + # Obtain valid organiser and attendee details. + + oa = self.require_organiser_and_attendees(False) + if not oa: + return False + + (organiser, organiser_attr), attendees = oa + + # Filter by stored attendees. + + obj = self.get_stored_object_version() + stored_attendees = set(obj.get_values("ATTENDEE")) + attendees = stored_attendees.intersection(attendees) + + if not attendees: + return False + + # Assume that the outcome will be a request. It would not seem + # completely bizarre to produce a publishing message instead if a + # refresh message was unprovoked. + + method = "REQUEST" + + # Get the parent event, add SENT-BY details to the organiser. + + obj = self.get_stored_object_version() + organiser, organiser_attr = uri_item(obj.get_item("ORGANIZER")) + self.update_sender(organiser_attr) + responses = [obj.to_node()] + + # Get recurrences. + + cancelled = self.store.get_cancellations(self.user) + + if not self.recurrenceid: + for recurrenceid in self.store.get_recurrences(self.user, self.uid): + if (self.uid, recurrenceid) not in cancelled: + + # Get the recurrence, add SENT-BY details to the organiser. + + obj = self.get_stored_object(self.uid, recurrenceid) + organiser, organiser_attr = uri_item(obj.get_item("ORGANIZER")) + self.update_sender(organiser_attr) + responses.append(obj.to_node()) + + self.add_result(method, map(get_address, attendees), to_part(method, responses)) + + return True + class Event(PersonHandler): "An event handler." @@ -214,11 +270,12 @@ def refresh(self): - "Generate details of any active event." + "Requests to refresh events are handled either here or by the client." - # NOTE: Return event details if configured to do so. - - return self.wrap("A request for updated event details has been received.") + if self.is_refreshing(): + return self._refresh() + else: + return self.wrap("A request for updated event details has been received.") def reply(self): diff -r 58d06d81028f -r 95a18b7a097c tests/templates/event-refresh-person-recurring-non-attendee.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/templates/event-refresh-person-recurring-non-attendee.txt Sat Sep 05 00:36:31 2015 +0200 @@ -0,0 +1,30 @@ +Content-Type: multipart/alternative; boundary="===============0047278175==" +MIME-Version: 1.0 +From: oliver.otter@example.com +To: paul.boddie@example.com +Subject: Refresh! + +--===============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="REFRESH" + +BEGIN:VCALENDAR +PRODID:-//imip-agent/test//EN +METHOD:REFRESH +VERSION:2.0 +BEGIN:VEVENT +ORGANIZER:mailto:paul.boddie@example.com +ATTENDEE;RSVP=TRUE:mailto:oliver.otter@example.com +DTSTAMP:20141009T182400Z +UID:event8@example.com +END:VEVENT +END:VCALENDAR + +--===============0047278175==-- diff -r 58d06d81028f -r 95a18b7a097c tests/templates/event-refresh-person-recurring.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/templates/event-refresh-person-recurring.txt Sat Sep 05 00:36:31 2015 +0200 @@ -0,0 +1,30 @@ +Content-Type: multipart/alternative; boundary="===============0047278175==" +MIME-Version: 1.0 +From: vincent.vole@example.com +To: paul.boddie@example.com +Subject: Refresh! + +--===============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="REFRESH" + +BEGIN:VCALENDAR +PRODID:-//imip-agent/test//EN +METHOD:REFRESH +VERSION:2.0 +BEGIN:VEVENT +ORGANIZER:mailto:paul.boddie@example.com +ATTENDEE;RSVP=TRUE:mailto:vincent.vole@example.com +DTSTAMP:20141009T182400Z +UID:event8@example.com +END:VEVENT +END:VCALENDAR + +--===============0047278175==-- diff -r 58d06d81028f -r 95a18b7a097c tests/test_person_invitation_refresh.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_person_invitation_refresh.sh Sat Sep 05 00:36:31 2015 +0200 @@ -0,0 +1,100 @@ +#!/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" +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" + +# Publish an event, testing 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" + +# Test a request from an attendee for the event details to be refreshed. + + "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/event-refresh-person-recurring.txt" 2>> $ERROR \ +| "$SHOWMAIL" \ +> out2.tmp + + grep -q 'METHOD:REQUEST' out2.tmp \ +&& echo "Success" \ +|| echo "Failed" + +# Present the result to the recipient. + + "$PERSON_SCRIPT" $ARGS < out2.tmp 2>> $ERROR \ +| "$SHOWMAIL" \ +> out3.tmp + + ! grep -q 'METHOD:REPLY' out3.tmp \ +&& echo "Success" \ +|| echo "Failed" + + ! 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 out4.tmp \ +| "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR + + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ +&& echo "Success" \ +|| echo "Failed" + +# Test a request from a non-attendee for the event details to be refreshed. + + "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/event-refresh-person-recurring-non-attendee.txt" 2>> $ERROR \ +| "$SHOWMAIL" \ +> out5.tmp + + ! grep -q 'METHOD:REQUEST' out5.tmp \ +&& echo "Success" \ +|| echo "Failed"