1.1 --- a/imip_text_client.py Fri Mar 23 15:46:51 2018 +0100
1.2 +++ b/imip_text_client.py Thu Mar 29 17:30:13 2018 +0200
1.3 @@ -64,6 +64,7 @@
1.4
1.5 CANCEL_COMMANDS = ("R", "remove", "cancel")
1.6 CANCEL_PUBLISH_COMMANDS = ("RP", "remove-publish", "cancel-publish")
1.7 +FREEBUSY_COMMANDS = ("F", "fb", "freebusy", "free/busy", "free-busy")
1.8 PUBLISH_COMMANDS = ("P", "publish")
1.9 SEND_COMMANDS = ("S", "send")
1.10 UPDATE_COMMANDS = ("U", "update")
1.11 @@ -781,6 +782,13 @@
1.12 if message:
1.13 self.show_message(message, plain, filename)
1.14
1.15 + def show_freebusy_message(self, plain=False, filename=None):
1.16 +
1.17 + "Show a free/busy request message for the main period."
1.18 +
1.19 + message = self.prepare_freebusy_message()
1.20 + self.show_message(message, plain, filename)
1.21 +
1.22 def show_cancel_publish_message(self, plain=False, filename=None):
1.23
1.24 "Show the cancel message for the current user."
1.25 @@ -1282,26 +1290,30 @@
1.26 print_title("Message inspection commands")
1.27 print
1.28 print """\
1.29 -P [ <filename> ]
1.30 +%(FREEBUSY_COMMANDS)s
1.31 + Show free/busy request message, writing to <filename> if specified
1.32 +
1.33 +%(PUBLISH_COMMANDS)s
1.34 publish [ <filename> ]
1.35 Show publishing message, writing to <filename> if specified
1.36
1.37 -R [ <filename> ]
1.38 -remove [ <filename> ]
1.39 -cancel [ <filename> ]
1.40 +%(CANCEL_COMMANDS)s
1.41 Show cancellation message sent to uninvited/removed recipients, writing to
1.42 <filename> if specified
1.43
1.44 -RP [ <filename> ]
1.45 -remove-publish [ <filename> ]
1.46 -cancel-publish [ <filename> ]
1.47 +%(CANCEL_PUBLISH_COMMANDS)s
1.48 Show cancellation message for use by the organiser, writing to <filename> if
1.49 specified
1.50
1.51 -U [ <filename> ]
1.52 -update [ <filename> ]
1.53 +%(UPDATE_COMMANDS)s
1.54 Show update message, writing to <filename> if specified
1.55 -"""
1.56 +""" % {
1.57 + "CANCEL_COMMANDS" : commandlist(CANCEL_COMMANDS, "[ <filename> ]"),
1.58 + "CANCEL_PUBLISH_COMMANDS" : commandlist(CANCEL_PUBLISH_COMMANDS, "[ <filename> ]"),
1.59 + "FREEBUSY_COMMANDS" : commandlist(FREEBUSY_COMMANDS, "[ <filename> ]"),
1.60 + "PUBLISH_COMMANDS" : commandlist(PUBLISH_COMMANDS, "[ <filename> ]"),
1.61 + "UPDATE_COMMANDS" : commandlist(UPDATE_COMMANDS, "[ <filename> ]"),
1.62 + }
1.63
1.64 def edit_object(cl, obj, handle_outgoing=False):
1.65
1.66 @@ -1409,6 +1421,10 @@
1.67 filename = get_text_arg(s)
1.68 cl.show_update_message(plain=not filename, filename=filename)
1.69
1.70 + elif cmd in FREEBUSY_COMMANDS:
1.71 + filename = get_text_arg(s)
1.72 + cl.show_freebusy_message(plain=not filename, filename=filename)
1.73 +
1.74 # Definitive finishing action.
1.75
1.76 elif cmd in SEND_COMMANDS:
2.1 --- a/imiptools/client.py Fri Mar 23 15:46:51 2018 +0100
2.2 +++ b/imiptools/client.py Thu Mar 29 17:30:13 2018 +0200
2.3 @@ -1047,6 +1047,24 @@
2.4 parts = [self.object_to_part("CANCEL", self.obj)]
2.5 return self.make_message_for_self(parts)
2.6
2.7 + def make_freebusy_message(self):
2.8 +
2.9 + "Prepare a free/busy request for the main period."
2.10 +
2.11 + user_attr = {}
2.12 + self.update_sender_attr(user_attr)
2.13 +
2.14 + attributes = self.obj.get_items("ATTENDEE")
2.15 + period = self.obj.get_main_period()
2.16 +
2.17 + recipients = self.get_recipients()
2.18 +
2.19 + # NOTE: Should choose a different UID to any event.
2.20 +
2.21 + fb = make_freebusy(None, self.uid, self.user, user_attr, attributes, period)
2.22 + parts = [self.to_part("REQUEST", [fb])]
2.23 + return self.make_message(parts, recipients)
2.24 +
2.25 # Action methods.
2.26
2.27 def send_declined_counter_to_attendee(self, attendee):
3.1 --- a/imiptools/data.py Fri Mar 23 15:46:51 2018 +0100
3.2 +++ b/imiptools/data.py Thu Mar 29 17:30:13 2018 +0200
3.3 @@ -770,14 +770,14 @@
3.4 nodes
3.5 )
3.6
3.7 -def make_freebusy(freebusy, uid, organiser, organiser_attr=None, attendee=None,
3.8 - attendee_attr=None, period=None):
3.9 +def make_freebusy(freebusy, uid, organiser, organiser_attr=None, attendees=None,
3.10 + period=None):
3.11
3.12 """
3.13 Return a calendar node defining the free/busy details described in the given
3.14 'freebusy' list, employing the given 'uid', for the given 'organiser' and
3.15 - optional 'organiser_attr', with the optional 'attendee' providing recipient
3.16 - details together with the optional 'attendee_attr'.
3.17 + optional 'organiser_attr', with the optional 'attendees' providing a
3.18 + collection of (address, attribute) items.
3.19
3.20 The result will be constrained to the 'period' if specified.
3.21 """
3.22 @@ -787,12 +787,17 @@
3.23
3.24 rwrite(("ORGANIZER", organiser_attr or {}, organiser))
3.25
3.26 - if attendee:
3.27 - rwrite(("ATTENDEE", attendee_attr or {}, attendee))
3.28 + # A request can have many attendees; a response will have just one.
3.29 +
3.30 + if attendees:
3.31 + for attendee, attendee_attr in attendees:
3.32 + rwrite(("ATTENDEE", attendee_attr or {}, attendee))
3.33
3.34 rwrite(("UID", {}, uid))
3.35
3.36 - if freebusy:
3.37 + # Obtain free/busy periods if publishing or replying.
3.38 +
3.39 + if freebusy is not None:
3.40
3.41 # Get a constrained view if start and end limits are specified.
3.42
3.43 @@ -801,20 +806,23 @@
3.44 else:
3.45 periods = freebusy
3.46
3.47 - # Write the limits of the resource.
3.48 + else:
3.49 + periods = []
3.50 +
3.51 + # Write the limits of the resource.
3.52
3.53 - if periods:
3.54 - rwrite(("DTSTART", {"VALUE" : "DATE-TIME"}, format_datetime(periods[0].get_start_point())))
3.55 - rwrite(("DTEND", {"VALUE" : "DATE-TIME"}, format_datetime(periods[-1].get_end_point())))
3.56 - else:
3.57 - rwrite(("DTSTART", {"VALUE" : "DATE-TIME"}, format_datetime(period.get_start_point())))
3.58 - rwrite(("DTEND", {"VALUE" : "DATE-TIME"}, format_datetime(period.get_end_point())))
3.59 + if periods:
3.60 + rwrite(("DTSTART", {"VALUE" : "DATE-TIME"}, format_datetime(periods[0].get_start_point())))
3.61 + rwrite(("DTEND", {"VALUE" : "DATE-TIME"}, format_datetime(periods[-1].get_end_point())))
3.62 + elif period:
3.63 + rwrite(("DTSTART", {"VALUE" : "DATE-TIME"}, format_datetime(period.get_start_point())))
3.64 + rwrite(("DTEND", {"VALUE" : "DATE-TIME"}, format_datetime(period.get_end_point())))
3.65
3.66 - for p in periods:
3.67 - if p.transp == "OPAQUE":
3.68 - rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join(
3.69 - map(format_datetime, [p.get_start_point(), p.get_end_point()])
3.70 - )))
3.71 + for p in periods:
3.72 + if p.transp == "OPAQUE":
3.73 + rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join(
3.74 + map(format_datetime, [p.get_start_point(), p.get_end_point()])
3.75 + )))
3.76
3.77 return ("VFREEBUSY", {}, record)
3.78
4.1 --- a/imiptools/editing.py Fri Mar 23 15:46:51 2018 +0100
4.2 +++ b/imiptools/editing.py Thu Mar 29 17:30:13 2018 +0200
4.3 @@ -521,6 +521,12 @@
4.4
4.5 return self.make_cancel_message_for_self()
4.6
4.7 + def prepare_freebusy_message(self):
4.8 +
4.9 + "Prepare a free/busy request message for the main period."
4.10 +
4.11 + return self.make_freebusy_message()
4.12 +
4.13 def prepare_publish_message(self):
4.14
4.15 "Prepare the publishing message for the updated event."
5.1 --- a/imiptools/handlers/common.py Fri Mar 23 15:46:51 2018 +0100
5.2 +++ b/imiptools/handlers/common.py Thu Mar 29 17:30:13 2018 +0200
5.3 @@ -75,6 +75,12 @@
5.4
5.5 (organiser, organiser_attr), attendees = oa
5.6
5.7 + # Get the period involved.
5.8 +
5.9 + dtstart = self.obj.get_datetime("DTSTART")
5.10 + dtend = self.obj.get_datetime("DTEND")
5.11 + period = dtstart and dtend and Period(dtstart, dtend, self.get_tzid()) or None
5.12 +
5.13 # Get the details for each attendee.
5.14
5.15 responses = []
5.16 @@ -89,11 +95,10 @@
5.17
5.18 self.update_sender_attr(attendee_attr)
5.19
5.20 - dtstart = self.obj.get_datetime("DTSTART")
5.21 - dtend = self.obj.get_datetime("DTEND")
5.22 - period = dtstart and dtend and Period(dtstart, dtend, self.get_tzid()) or None
5.23 + # Produce a free/busy reply.
5.24
5.25 - rwrite(make_freebusy(freebusy, self.uid, organiser, organiser_attr, attendee, attendee_attr, period))
5.26 + rwrite(make_freebusy(freebusy, self.uid, organiser, organiser_attr,
5.27 + [(attendee, attendee_attr)], period))
5.28
5.29 # Return the reply.
5.30