imip-agent

imiptools/client.py

560:ade19f50b58e
2015-05-18 Paul Boddie Produce recurring periods employing dates if they are involved. Handle missing DTSTART when encountering CANCEL messages.
     1 #!/usr/bin/env python     2      3 """     4 Common calendar client utilities.     5      6 Copyright (C) 2014, 2015 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_uri, get_window_end, uri_dict, uri_items, uri_values    23 from imiptools.dates import get_default_timezone    24 from imiptools.profile import Preferences    25     26 def update_attendees(obj, attendees, removed):    27     28     """    29     Update the attendees in 'obj' with the given 'attendees' and 'removed'    30     attendee lists. A list is returned containing the attendees whose    31     attendance should be cancelled.    32     """    33     34     to_cancel = []    35     36     existing_attendees = uri_values(obj.get_values("ATTENDEE") or [])    37     added = set(attendees).difference(existing_attendees)    38     39     if added or removed:    40         attendees = uri_items(obj.get_items("ATTENDEE") or [])    41         sequence = obj.get_value("SEQUENCE")    42     43         if removed:    44             remaining = []    45     46             for attendee, attendee_attr in attendees:    47                 if attendee in removed:    48     49                     # Without a sequence number, assume that the event has not    50                     # been published and that attendees can be silently removed.    51     52                     if sequence is not None:    53                         to_cancel.append((attendee, attendee_attr))    54                 else:    55                     remaining.append((attendee, attendee_attr))    56     57             attendees = remaining    58     59         if added:    60             for attendee in added:    61                 attendee = attendee.strip()    62                 if attendee:    63                     attendees.append((get_uri(attendee), {"PARTSTAT" : "NEEDS-ACTION", "RSVP" : "TRUE"}))    64     65         obj["ATTENDEE"] = attendees    66     67     return to_cancel    68     69 def update_participation(obj, user, partstat):    70     71     "Update the participation in 'obj' of 'user' with the given 'partstat'."    72     73     existing_attendees = uri_dict(obj.get_value_map("ATTENDEE"))    74     75     if partstat:    76         if existing_attendees.has_key(user):    77             existing_attendees[user]["PARTSTAT"] = partstat    78             if existing_attendees[user].has_key("RSVP"):    79                 del existing_attendees[user]["RSVP"]    80     81 class Client:    82     83     "Common handler and manager methods."    84     85     default_window_size = 100    86     87     def __init__(self, user):    88         self.user = user    89         self.preferences = None    90     91     def get_preferences(self):    92         if not self.preferences and self.user:    93             self.preferences = Preferences(self.user)    94         return self.preferences    95     96     def get_tzid(self):    97         prefs = self.get_preferences()    98         return prefs and prefs.get("TZID") or get_default_timezone()    99    100     def get_window_size(self):   101         prefs = self.get_preferences()   102         try:   103             return prefs and int(prefs.get("window_size")) or self.default_window_size   104         except (TypeError, ValueError):   105             return self.default_window_size   106    107     def get_window_end(self):   108         return get_window_end(self.get_tzid(), self.get_window_size())   109    110     def is_sharing(self):   111         prefs = self.get_preferences()   112         return prefs and prefs.get("freebusy_sharing") == "share" or False   113    114     def is_bundling(self):   115         prefs = self.get_preferences()   116         return prefs and prefs.get("freebusy_bundling") == "always" or False   117    118     def is_notifying(self):   119         prefs = self.get_preferences()   120         return prefs and prefs.get("freebusy_messages") == "notify" or False   121    122 # vim: tabstop=4 expandtab shiftwidth=4