1.1 --- a/imip_store.py Tue Sep 01 15:59:42 2015 +0200
1.2 +++ b/imip_store.py Tue Sep 01 19:43:40 2015 +0200
1.3 @@ -351,6 +351,30 @@
1.4
1.5 # Free/busy period providers, upon extension of the free/busy records.
1.6
1.7 + def _get_freebusy_providers(self, user):
1.8 +
1.9 + """
1.10 + Return the free/busy providers for the given 'user'.
1.11 +
1.12 + This function returns any stored datetime and a list of providers as a
1.13 + 2-tuple. Each provider is itself a (uid, recurrenceid) tuple.
1.14 + """
1.15 +
1.16 + filename = self.get_object_in_store(user, "freebusy-providers")
1.17 + if not filename or not exists(filename):
1.18 + return None
1.19 +
1.20 + # Attempt to read providers, with a declaration of the datetime
1.21 + # from which such providers are considered as still being active.
1.22 +
1.23 + t = self._get_table(user, filename, [(1, None)])
1.24 + try:
1.25 + dt_string = t[0][0]
1.26 + except IndexError:
1.27 + return None
1.28 +
1.29 + return dt_string, t[1:]
1.30 +
1.31 def get_freebusy_providers(self, user, dt=None):
1.32
1.33 """
1.34 @@ -361,32 +385,39 @@
1.35 details will be returned. Otherwise, if 'dt' is earlier than the
1.36 datetime recorded for the known providers, None is returned, indicating
1.37 that the list of providers must be recomputed.
1.38 +
1.39 + This function returns a list of (uid, recurrenceid) tuples upon success.
1.40 """
1.41
1.42 + t = self._get_freebusy_providers(user)
1.43 + if not t:
1.44 + return None
1.45 +
1.46 + dt_string, t = t
1.47 +
1.48 + # If the requested datetime is earlier than the stated datetime, the
1.49 + # providers will need to be recomputed.
1.50 +
1.51 + if dt:
1.52 + providers_dt = get_datetime(dt_string)
1.53 + if not providers_dt or providers_dt > dt:
1.54 + return None
1.55 +
1.56 + # Otherwise, return the providers.
1.57 +
1.58 + return t[1:]
1.59 +
1.60 + def _set_freebusy_providers(self, user, dt_string, t):
1.61 +
1.62 + "Set the given provider timestamp 'dt_string' and table 't'."
1.63 +
1.64 filename = self.get_object_in_store(user, "freebusy-providers")
1.65 - if not filename or not exists(filename):
1.66 - return None
1.67 - else:
1.68 - # Attempt to read providers, with a declaration of the datetime
1.69 - # from which such providers are considered as still being active.
1.70 -
1.71 - t = self._get_table(user, filename, [(1, None)])
1.72 - try:
1.73 - dt_string = t[0][0]
1.74 - except IndexError:
1.75 - return None
1.76 + if not filename:
1.77 + return False
1.78
1.79 - # If the requested datetime is earlier than the stated datetime, the
1.80 - # providers will need to be recomputed.
1.81 -
1.82 - if dt:
1.83 - providers_dt = get_datetime(dt_string)
1.84 - if not providers_dt or providers_dt > dt:
1.85 - return None
1.86 -
1.87 - # Otherwise, return the providers.
1.88 -
1.89 - return t[1:]
1.90 + t.insert(0, (dt_string,))
1.91 + self._set_table(user, filename, t, [(1, "")])
1.92 + return True
1.93
1.94 def set_freebusy_providers(self, user, dt, providers):
1.95
1.96 @@ -395,17 +426,41 @@
1.97 given datetime 'dt'.
1.98 """
1.99
1.100 - t = [(format_datetime(dt),)]
1.101 + t = []
1.102
1.103 for obj in providers:
1.104 - t.append((obj.get_uid(), obj.get_recurrenceid() or ""))
1.105 + t.append((obj.get_uid(), obj.get_recurrenceid()))
1.106 +
1.107 + return self._set_freebusy_providers(user, format_datetime(dt), t)
1.108
1.109 - filename = self.get_object_in_store(user, "freebusy-providers")
1.110 - if not filename:
1.111 + def append_freebusy_provider(self, user, provider):
1.112 +
1.113 + "For the given 'user', append the free/busy 'provider'."
1.114 +
1.115 + t = self._get_freebusy_providers(user)
1.116 + if not t:
1.117 return False
1.118
1.119 - self._set_table(user, filename, t)
1.120 - return True
1.121 + dt_string, t = t
1.122 + t.append((provider.get_uid(), provider.get_recurrenceid()))
1.123 +
1.124 + return self._set_freebusy_providers(user, dt_string, t)
1.125 +
1.126 + def remove_freebusy_provider(self, user, provider):
1.127 +
1.128 + "For the given 'user', remove the free/busy 'provider'."
1.129 +
1.130 + t = self._get_freebusy_providers(user)
1.131 + if not t:
1.132 + return False
1.133 +
1.134 + dt_string, t = t
1.135 + try:
1.136 + t.remove((provider.get_uid(), provider.get_recurrenceid()))
1.137 + except ValueError:
1.138 + return False
1.139 +
1.140 + return self._set_freebusy_providers(user, dt_string, t)
1.141
1.142 # Free/busy period access.
1.143
2.1 --- a/imiptools/client.py Tue Sep 01 15:59:42 2015 +0200
2.2 +++ b/imiptools/client.py Tue Sep 01 19:43:40 2015 +0200
2.3 @@ -418,6 +418,18 @@
2.4
2.5 return False
2.6
2.7 + def possibly_recurring_indefinitely(self):
2.8 +
2.9 + "Return whether the object recurs indefinitely."
2.10 +
2.11 + # Obtain the stored object to make sure that recurrence information
2.12 + # is not being ignored. This might happen if a client sends a
2.13 + # cancellation without the complete set of properties, for instance.
2.14 +
2.15 + return self.obj.possibly_recurring_indefinitely() or \
2.16 + self.get_stored_object_version() and \
2.17 + self.get_stored_object_version().possibly_recurring_indefinitely()
2.18 +
2.19 # Constraint application on event periods.
2.20
2.21 def check_object(self):
3.1 --- a/imiptools/data.py Tue Sep 01 15:59:42 2015 +0200
3.2 +++ b/imiptools/data.py Tue Sep 01 19:43:40 2015 +0200
3.3 @@ -330,18 +330,23 @@
3.4 if p.get_end_point() > dt:
3.5 return True
3.6
3.7 + return self.possibly_recurring_indefinitely()
3.8 +
3.9 + def possibly_recurring_indefinitely(self):
3.10 +
3.11 + "Return whether this object may recur indefinitely."
3.12 +
3.13 rrule = self.get_value("RRULE")
3.14 parameters = rrule and get_parameters(rrule)
3.15 until = parameters and parameters.get("UNTIL")
3.16 count = parameters and parameters.get("COUNT")
3.17
3.18 - # Non-recurring periods or constrained recurrences that are not found to
3.19 - # lie beyond the specified datetime.
3.20 + # Non-recurring periods or constrained recurrences.
3.21
3.22 if not rrule or until or count:
3.23 return False
3.24
3.25 - # Unconstrained recurring periods will always lie beyond the specified
3.26 + # Unconstrained recurring periods will always lie beyond any specified
3.27 # datetime.
3.28
3.29 else:
4.1 --- a/imiptools/handlers/common.py Tue Sep 01 15:59:42 2015 +0200
4.2 +++ b/imiptools/handlers/common.py Tue Sep 01 19:43:40 2015 +0200
4.3 @@ -89,6 +89,12 @@
4.4 if self.publisher and self.is_sharing():
4.5 self.publisher.set_freebusy(self.user, freebusy)
4.6
4.7 + # Update free/busy provider information if the event may recur
4.8 + # indefinitely.
4.9 +
4.10 + if self.possibly_recurring_indefinitely():
4.11 + self.store.append_freebusy_provider(self.user, self.obj)
4.12 +
4.13 return True
4.14
4.15 def remove_event_from_freebusy(self):
4.16 @@ -103,4 +109,10 @@
4.17 if self.publisher and self.is_sharing():
4.18 self.publisher.set_freebusy(self.user, freebusy)
4.19
4.20 + # Update free/busy provider information if the event may recur
4.21 + # indefinitely.
4.22 +
4.23 + if self.possibly_recurring_indefinitely():
4.24 + self.store.remove_freebusy_provider(self.user, self.obj)
4.25 +
4.26 # vim: tabstop=4 expandtab shiftwidth=4
5.1 --- a/imiptools/handlers/person.py Tue Sep 01 15:59:42 2015 +0200
5.2 +++ b/imiptools/handlers/person.py Tue Sep 01 19:43:40 2015 +0200
5.3 @@ -62,10 +62,6 @@
5.4 if obj_attendees.has_key(organiser):
5.5 obj_attendees[organiser]["PARTSTAT"] = "DECLINED"
5.6
5.7 - # Set the complete event or an additional occurrence.
5.8 -
5.9 - self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node())
5.10 -
5.11 # Remove additional recurrences if handling a complete event.
5.12
5.13 if not self.recurrenceid:
5.14 @@ -96,6 +92,10 @@
5.15
5.16 self.update_freebusy_from_organiser(organiser)
5.17
5.18 + # Set the complete event or an additional occurrence.
5.19 +
5.20 + self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node())
5.21 +
5.22 # As organiser, update attendance from valid attendees.
5.23
5.24 else:
6.1 --- a/imiptools/handlers/person_outgoing.py Tue Sep 01 15:59:42 2015 +0200
6.2 +++ b/imiptools/handlers/person_outgoing.py Tue Sep 01 19:43:40 2015 +0200
6.3 @@ -131,6 +131,11 @@
6.4 obj["SEQUENCE"] = self.obj.get_items("SEQUENCE") or []
6.5 obj["DTSTAMP"] = self.obj.get_items("DTSTAMP") or []
6.6
6.7 + # Update free/busy information.
6.8 +
6.9 + if cancel_entire_event or self.user in given_attendees:
6.10 + self.remove_event_from_freebusy()
6.11 +
6.12 # Set the complete event if not an additional occurrence. For any newly-
6.13 # indicated occurrence, use the received event details.
6.14
6.15 @@ -140,11 +145,6 @@
6.16
6.17 self.store.dequeue_request(self.user, self.uid, self.recurrenceid)
6.18
6.19 - # Update free/busy information.
6.20 -
6.21 - if cancel_entire_event or self.user in given_attendees:
6.22 - self.remove_event_from_freebusy()
6.23 -
6.24 return True
6.25
6.26 class Event(PersonHandler):
7.1 --- a/imiptools/handlers/resource.py Tue Sep 01 15:59:42 2015 +0200
7.2 +++ b/imiptools/handlers/resource.py Tue Sep 01 19:43:40 2015 +0200
7.3 @@ -142,13 +142,15 @@
7.4 the current object.
7.5 """
7.6
7.7 - self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node())
7.8 - self.store.cancel_event(self.user, self.uid, self.recurrenceid)
7.9 -
7.10 # Update free/busy information.
7.11
7.12 self.remove_event_from_freebusy()
7.13
7.14 + # Update the stored event and cancel it.
7.15 +
7.16 + self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node())
7.17 + self.store.cancel_event(self.user, self.uid, self.recurrenceid)
7.18 +
7.19 class Event(ResourceHandler):
7.20
7.21 "An event handler."
8.1 --- a/imipweb/resource.py Tue Sep 01 15:59:42 2015 +0200
8.2 +++ b/imipweb/resource.py Tue Sep 01 19:43:40 2015 +0200
8.3 @@ -213,12 +213,24 @@
8.4 self.store.set_freebusy(self.user, freebusy)
8.5 self.publish_freebusy(freebusy)
8.6
8.7 + # Update free/busy provider information if the event may recur
8.8 + # indefinitely.
8.9 +
8.10 + if obj.possibly_recurring_indefinitely():
8.11 + self.store.append_freebusy_provider(self.user, obj)
8.12 +
8.13 def remove_from_freebusy(self, uid, recurrenceid=None):
8.14 freebusy = self.store.get_freebusy(self.user)
8.15 remove_period(freebusy, uid, recurrenceid)
8.16 self.store.set_freebusy(self.user, freebusy)
8.17 self.publish_freebusy(freebusy)
8.18
8.19 + # Update free/busy provider information if the event may recur
8.20 + # indefinitely.
8.21 +
8.22 + if obj.possibly_recurring_indefinitely():
8.23 + self.store.remove_freebusy_provider(self.user, obj)
8.24 +
8.25 def publish_freebusy(self, freebusy):
8.26
8.27 "Publish the details if configured to share them."
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/tests/templates/event-cancel-recurring-indefinitely.txt Tue Sep 01 19:43:40 2015 +0200
9.3 @@ -0,0 +1,34 @@
9.4 +Content-Type: multipart/alternative; boundary="===============0047278175=="
9.5 +MIME-Version: 1.0
9.6 +From: paul.boddie@example.com
9.7 +To: resource-room-confroom@example.com
9.8 +Subject: Cancellation!
9.9 +
9.10 +Cancel the event for resource-room-confroom and paul.boddie.
9.11 +
9.12 +--===============0047278175==
9.13 +Content-Type: text/plain; charset="us-ascii"
9.14 +MIME-Version: 1.0
9.15 +Content-Transfer-Encoding: 7bit
9.16 +
9.17 +This message contains an event.
9.18 +--===============0047278175==
9.19 +MIME-Version: 1.0
9.20 +Content-Transfer-Encoding: 7bit
9.21 +Content-Type: text/calendar; charset="us-ascii"; method="CANCEL"
9.22 +
9.23 +BEGIN:VCALENDAR
9.24 +PRODID:-//imip-agent/test//EN
9.25 +METHOD:CANCEL
9.26 +VERSION:2.0
9.27 +BEGIN:VEVENT
9.28 +ORGANIZER:mailto:paul.boddie@example.com
9.29 +ATTENDEE;RSVP=TRUE:mailto:resource-room-confroom@example.com
9.30 +ATTENDEE;RSVP=TRUE:mailto:paul.boddie@example.com
9.31 +DTSTAMP:20141009T182400Z
9.32 +SUMMARY:Recurring event indefinitely
9.33 +UID:event14@example.com
9.34 +END:VEVENT
9.35 +END:VCALENDAR
9.36 +
9.37 +--===============0047278175==--
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/tests/templates/event-request-recurring-indefinitely.txt Tue Sep 01 19:43:40 2015 +0200
10.3 @@ -0,0 +1,34 @@
10.4 +Content-Type: multipart/alternative; boundary="===============0047278175=="
10.5 +MIME-Version: 1.0
10.6 +From: paul.boddie@example.com
10.7 +To: resource-room-confroom@example.com
10.8 +Subject: Invitation!
10.9 +
10.10 +--===============0047278175==
10.11 +Content-Type: text/plain; charset="us-ascii"
10.12 +MIME-Version: 1.0
10.13 +Content-Transfer-Encoding: 7bit
10.14 +
10.15 +This message contains an event.
10.16 +--===============0047278175==
10.17 +MIME-Version: 1.0
10.18 +Content-Transfer-Encoding: 7bit
10.19 +Content-Type: text/calendar; charset="us-ascii"; method="REQUEST"
10.20 +
10.21 +BEGIN:VCALENDAR
10.22 +PRODID:-//imip-agent/test//EN
10.23 +METHOD:REQUEST
10.24 +VERSION:2.0
10.25 +BEGIN:VEVENT
10.26 +ORGANIZER:mailto:paul.boddie@example.com
10.27 +ATTENDEE;RSVP=TRUE:mailto:resource-room-confroom@example.com
10.28 +DTSTAMP:20141009T182400Z
10.29 +DTSTART;TZID=Europe/Oslo:20141010T100000
10.30 +DTEND;TZID=Europe/Oslo:20141010T110000
10.31 +RRULE:FREQ=MONTHLY;BYDAY=2FR
10.32 +SUMMARY:Recurring event indefinitely
10.33 +UID:event14@example.com
10.34 +END:VEVENT
10.35 +END:VCALENDAR
10.36 +
10.37 +--===============0047278175==--
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/tests/test_resource_invitation_recurring_indefinitely.sh Tue Sep 01 19:43:40 2015 +0200
11.3 @@ -0,0 +1,105 @@
11.4 +#!/bin/sh
11.5 +
11.6 +THIS_DIR=`dirname $0`
11.7 +BASE_DIR="$THIS_DIR/.."
11.8 +
11.9 +TEMPLATES="$THIS_DIR/templates"
11.10 +RESOURCE_SCRIPT="$BASE_DIR/imip_resource.py"
11.11 +FREEBUSY_SCRIPT="$BASE_DIR/tools/make_freebusy.py"
11.12 +SHOWMAIL="$BASE_DIR/tools/showmail.py"
11.13 +STORE=/tmp/store
11.14 +STATIC=/tmp/static
11.15 +PREFS=/tmp/prefs
11.16 +ARGS="-S $STORE -P $STATIC -p $PREFS -d"
11.17 +FBARGS="-s -n"
11.18 +USER="mailto:resource-room-confroom@example.com"
11.19 +ERROR=err.tmp
11.20 +
11.21 +rm -r $STORE
11.22 +rm -r $STATIC
11.23 +rm -r $PREFS
11.24 +rm $ERROR
11.25 +rm out*.tmp
11.26 +
11.27 +mkdir -p "$PREFS/$USER"
11.28 +echo 'Europe/Oslo' > "$PREFS/$USER/TZID"
11.29 +echo 'share' > "$PREFS/$USER/freebusy_sharing"
11.30 +
11.31 + "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/fb-request-all.txt" 2>> $ERROR \
11.32 +| "$SHOWMAIL" \
11.33 +> out0.tmp
11.34 +
11.35 + grep -q 'METHOD:REPLY' out0.tmp \
11.36 +&& ! grep -q '^FREEBUSY' out0.tmp \
11.37 +&& echo "Success" \
11.38 +|| echo "Failed"
11.39 +
11.40 + "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/event-request-recurring-indefinitely.txt" 2>> $ERROR \
11.41 +| "$SHOWMAIL" \
11.42 +> out2.tmp
11.43 +
11.44 + grep -q 'METHOD:REPLY' out2.tmp \
11.45 +&& grep -q 'ATTENDEE;PARTSTAT=ACCEPTED' out2.tmp \
11.46 +&& echo "Success" \
11.47 +|| echo "Failed"
11.48 +
11.49 + "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/fb-request-all.txt" 2>> $ERROR \
11.50 +| "$SHOWMAIL" \
11.51 +> out3.tmp
11.52 +
11.53 + grep -q 'METHOD:REPLY' out3.tmp \
11.54 +&& grep -q 'FREEBUSY;FBTYPE=BUSY:20141114T090000Z/20141114T100000Z' out3.tmp \
11.55 +&& grep -q 'FREEBUSY;FBTYPE=BUSY:20141212T090000Z/20141212T100000Z' out3.tmp \
11.56 +&& grep -q 'FREEBUSY;FBTYPE=BUSY:20150109T090000Z/20150109T100000Z' out3.tmp \
11.57 +&& echo "Success" \
11.58 +|| echo "Failed"
11.59 +
11.60 +PYTHONPATH="$BASE_DIR" "$FREEBUSY_SCRIPT" "$USER" $FBARGS $ARGS 2>> $ERROR
11.61 +
11.62 + grep -q 'event14@example.com' "$STORE/$USER/freebusy-providers" \
11.63 +&& echo "Success" \
11.64 +|| echo "Failed"
11.65 +
11.66 + "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-recurring-indefinitely.txt" 2>> $ERROR
11.67 +echo "Cancel..."
11.68 +
11.69 + "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/fb-request-all.txt" 2>> $ERROR \
11.70 +| "$SHOWMAIL" \
11.71 +> out4.tmp
11.72 +
11.73 + grep -q 'METHOD:REPLY' out4.tmp \
11.74 +&& ! grep -q 'FREEBUSY;FBTYPE=BUSY:20141114T090000Z/20141114T100000Z' out4.tmp \
11.75 +&& ! grep -q 'FREEBUSY;FBTYPE=BUSY:20141212T090000Z/20141212T100000Z' out4.tmp \
11.76 +&& ! grep -q 'FREEBUSY;FBTYPE=BUSY:20150109T090000Z/20150109T100000Z' out4.tmp \
11.77 +&& echo "Success" \
11.78 +|| echo "Failed"
11.79 +
11.80 + ! grep -q 'event14@example.com' "$STORE/$USER/freebusy-providers" \
11.81 +&& echo "Success" \
11.82 +|| echo "Failed"
11.83 +
11.84 +# Re-add event to test scheduling and presence in the freebusy-providers file.
11.85 +
11.86 + "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/event-request-recurring-indefinitely.txt" 2>> $ERROR \
11.87 +| "$SHOWMAIL" \
11.88 +> out5.tmp
11.89 +
11.90 + grep -q 'METHOD:REPLY' out5.tmp \
11.91 +&& grep -q 'ATTENDEE;PARTSTAT=ACCEPTED' out5.tmp \
11.92 +&& echo "Success" \
11.93 +|| echo "Failed"
11.94 +
11.95 + "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/fb-request-all.txt" 2>> $ERROR \
11.96 +| "$SHOWMAIL" \
11.97 +> out6.tmp
11.98 +
11.99 + grep -q 'METHOD:REPLY' out6.tmp \
11.100 +&& grep -q 'FREEBUSY;FBTYPE=BUSY:20141114T090000Z/20141114T100000Z' out6.tmp \
11.101 +&& grep -q 'FREEBUSY;FBTYPE=BUSY:20141212T090000Z/20141212T100000Z' out6.tmp \
11.102 +&& grep -q 'FREEBUSY;FBTYPE=BUSY:20150109T090000Z/20150109T100000Z' out6.tmp \
11.103 +&& echo "Success" \
11.104 +|| echo "Failed"
11.105 +
11.106 + grep -q 'event14@example.com' "$STORE/$USER/freebusy-providers" \
11.107 +&& echo "Success" \
11.108 +|| echo "Failed"
12.1 --- a/tools/make_freebusy.py Tue Sep 01 15:59:42 2015 +0200
12.2 +++ b/tools/make_freebusy.py Tue Sep 01 19:43:40 2015 +0200
12.3 @@ -29,12 +29,14 @@
12.4 from imip_store import FileStore, FilePublisher
12.5 import sys
12.6
12.7 -def make_freebusy(user, participant, store_and_publish, include_needs_action, reset_updated_list, verbose):
12.8 +def make_freebusy(store, publisher, preferences, user, participant,
12.9 + store_and_publish, include_needs_action, reset_updated_list, verbose):
12.10
12.11 """
12.12 - Make free/busy details for the records of the given 'user', generating
12.13 - details for 'participant' if not indicated as None; otherwise, generating
12.14 - free/busy details concerning the given user.
12.15 + Using the given 'store', 'publisher' and 'preferences', make free/busy
12.16 + details for the records of the given 'user', generating details for
12.17 + 'participant' if not indicated as None; otherwise, generating free/busy
12.18 + details concerning the given user.
12.19
12.20 If 'store_and_publish' is set, the stored details will be updated;
12.21 otherwise, the details will be written to standard output.
12.22 @@ -51,8 +53,6 @@
12.23 """
12.24
12.25 participant = participant or user
12.26 -
12.27 - preferences = Preferences(user)
12.28 tzid = preferences.get("TZID") or get_default_timezone()
12.29
12.30 # Get the size of the free/busy window.
12.31 @@ -63,9 +63,6 @@
12.32 window_size = 100
12.33 window_end = get_window_end(tzid, window_size)
12.34
12.35 - store = FileStore()
12.36 - publisher = FilePublisher()
12.37 -
12.38 # Get identifiers for uncancelled events either from a list of events
12.39 # providing free/busy periods at the end of the given time window, or from
12.40 # a list of all events.
12.41 @@ -132,15 +129,33 @@
12.42
12.43 # Interpret the command line arguments.
12.44
12.45 + participants = []
12.46 + args = []
12.47 + store_dir = []
12.48 + publishing_dir = []
12.49 + preferences_dir = []
12.50 + ignored = []
12.51 +
12.52 + # Collect user details first, switching to other arguments when encountering
12.53 + # switches.
12.54 +
12.55 + l = participants
12.56 +
12.57 + for arg in sys.argv[1:]:
12.58 + if arg in ("-n", "-s", "-v", "-r"):
12.59 + args.append(arg)
12.60 + l = ignored
12.61 + elif arg == "-S":
12.62 + l = store_dir
12.63 + elif arg == "-P":
12.64 + l = publishing_dir
12.65 + elif arg == "-p":
12.66 + l = preferences_dir
12.67 + else:
12.68 + l.append(arg)
12.69 +
12.70 try:
12.71 - user = sys.argv[1]
12.72 - args = sys.argv[2:]
12.73 - participant = args and args[0] not in ("-n", "-s", "-v", "-r") and args[0] or None
12.74 - store_and_publish = "-s" in args
12.75 - include_needs_action = "-n" in args
12.76 - reset_updated_list = "-r" in args
12.77 - verbose = "-v" in args
12.78 -
12.79 + user = participants[0]
12.80 except IndexError:
12.81 print >>sys.stderr, """\
12.82 Need a user and an optional participant (if different from the user),
12.83 @@ -151,14 +166,39 @@
12.84 """
12.85 sys.exit(1)
12.86
12.87 + # Define any other participant of interest plus options.
12.88 +
12.89 + participant = participants[1:] and participants[1] or None
12.90 + store_and_publish = "-s" in args
12.91 + include_needs_action = "-n" in args
12.92 + reset_updated_list = "-r" in args
12.93 + verbose = "-v" in args
12.94 +
12.95 + # Override defaults if indicated.
12.96 +
12.97 + store_dir = store_dir and store_dir[0] or None
12.98 + publishing_dir = publishing_dir and publishing_dir[0] or None
12.99 + preferences_dir = preferences_dir and preferences_dir[0] or None
12.100 +
12.101 + # Obtain store-related objects.
12.102 +
12.103 + store = FileStore(store_dir)
12.104 + publisher = FilePublisher(publishing_dir)
12.105 + preferences = Preferences(user, preferences_dir)
12.106 +
12.107 + # Obtain a list of users for processing.
12.108 +
12.109 if user in ("*", "all"):
12.110 - users = FileStore().get_users()
12.111 + users = store.get_users()
12.112 else:
12.113 users = [user]
12.114
12.115 + # Process the given users.
12.116 +
12.117 for user in users:
12.118 if verbose:
12.119 print >>sys.stderr, user
12.120 - make_freebusy(user, participant, store_and_publish, include_needs_action, reset_updated_list, verbose)
12.121 + make_freebusy(store, publisher, preferences, user, participant,
12.122 + store_and_publish, include_needs_action, reset_updated_list, verbose)
12.123
12.124 # vim: tabstop=4 expandtab shiftwidth=4