imip-agent

imiptools/handlers/common.py

1065:2175787d1896
2016-03-04 Paul Boddie Merged changes from the default branch. freebusy-collections
     1 #!/usr/bin/env python     2      3 """     4 Common handler functionality for different entities.     5      6 Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 from imiptools.data import get_address, get_uri, make_freebusy, to_part, \    23                            uri_dict    24 from imiptools.dates import format_datetime    25 from imiptools.period import FreeBusyPeriod, Period    26     27 class CommonFreebusy:    28     29     "Common free/busy mix-in."    30     31     def _record_freebusy(self, from_organiser=True):    32     33         """    34         Record free/busy information for a message originating from an organiser    35         if 'from_organiser' is set to a true value.    36         """    37     38         if from_organiser:    39             organiser_item = self.require_organiser(from_organiser)    40             if not organiser_item:    41                 return    42     43             senders = [organiser_item]    44         else:    45             oa = self.require_organiser_and_attendees(from_organiser)    46             if not oa:    47                 return    48     49             organiser_item, attendees = oa    50             senders = attendees.items()    51     52             if not senders:    53                 return    54     55         freebusy = [FreeBusyPeriod(p.get_start_point(), p.get_end_point()) for p in self.obj.get_period_values("FREEBUSY")]    56         dtstart = self.obj.get_datetime("DTSTART")    57         dtend = self.obj.get_datetime("DTEND")    58         period = Period(dtstart, dtend, self.get_tzid())    59     60         for sender, sender_attr in senders:    61             stored_freebusy = self.store.get_freebusy_for_other(self.user, sender)    62             stored_freebusy.replace_overlapping(period, freebusy)    63             self.store.set_freebusy_for_other(self.user, stored_freebusy, sender)    64     65     def request(self):    66     67         """    68         Respond to a request by preparing a reply containing free/busy    69         information for each indicated attendee.    70         """    71     72         oa = self.require_organiser_and_attendees()    73         if not oa:    74             return    75     76         (organiser, organiser_attr), attendees = oa    77     78         # Get the details for each attendee.    79     80         responses = []    81         rwrite = responses.append    82     83         # For replies, the organiser and attendee are preserved.    84     85         for attendee, attendee_attr in attendees.items():    86             freebusy = self.store.get_freebusy(attendee)    87     88             # Indicate the actual sender of the reply.    89     90             self.update_sender(attendee_attr)    91     92             dtstart = self.obj.get_datetime("DTSTART")    93             dtend = self.obj.get_datetime("DTEND")    94             period = dtstart and dtend and Period(dtstart, dtend, self.get_tzid()) or None    95     96             rwrite(make_freebusy(freebusy, self.uid, organiser, organiser_attr, attendee, attendee_attr, period))    97     98         # Return the reply.    99    100         self.add_result("REPLY", [get_address(organiser)], to_part("REPLY", responses))   101    102 class CommonEvent:   103    104     "Common outgoing message handling functionality mix-in."   105    106     def is_usable(self, method=None):   107    108         "Return whether the current object is usable with the given 'method'."   109    110         return self.obj and (   111             method in ("CANCEL", "REFRESH") or   112             self.obj.get_datetime("DTSTART") and   113                 (self.obj.get_datetime("DTEND") or self.obj.get_duration("DURATION")))   114    115     def will_refresh(self):   116    117         """   118         Indicate whether a REFRESH message should be used to respond to an ADD   119         message.   120         """   121    122         return not self.get_stored_object_version() or self.get_add_method_response() == "refresh"   123    124     def make_refresh(self):   125    126         "Make a REFRESH message."   127    128         organiser = get_uri(self.obj.get_value("ORGANIZER"))   129         attendees = uri_dict(self.obj.get_value_map("ATTENDEE"))   130    131         # Indicate the actual sender of the message.   132    133         attendee_attr = attendees[self.user]   134         self.update_sender(attendee_attr)   135    136         # Make a new object with a minimal property selection.   137    138         obj = self.obj.copy()   139         obj.preserve(("ORGANIZER", "DTSTAMP", "UID", "RECURRENCE-ID"))   140         obj["ATTENDEE"] = [(self.user, attendee_attr)]   141    142         # Send a REFRESH message in response.   143    144         self.add_result("REFRESH", [get_address(organiser)], obj.to_part("REFRESH"))   145    146 # vim: tabstop=4 expandtab shiftwidth=4