imip-agent

imiptools/handlers/__init__.py

1005:819a0a8a3ae5
2015-11-05 Paul Boddie Added initial message localisation support.
     1 #!/usr/bin/env python     2      3 """     4 General handler support for incoming calendar objects.     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 email.mime.text import MIMEText    23 from imiptools.client import ClientForObject    24 from imiptools.config import MANAGER_PATH, MANAGER_URL, MANAGER_URL_SCHEME    25 from imiptools.data import get_address, get_uri, get_sender_identities, \    26                            uri_dict, uri_item    27 from socket import gethostname    28     29 # References to the Web interface.    30     31 def get_manager_url():    32     url_base = MANAGER_URL or \    33                "%s%s/" % (MANAGER_URL_SCHEME or "https://", gethostname())    34     return "%s/%s" % (url_base.rstrip("/"), MANAGER_PATH.lstrip("/"))    35     36 def get_object_url(uid, recurrenceid=None):    37     return "%s/%s%s" % (    38         get_manager_url().rstrip("/"), uid,    39         recurrenceid and "/%s" % recurrenceid or ""    40         )    41     42 class Handler(ClientForObject):    43     44     "General handler support."    45     46     def __init__(self, senders=None, recipient=None, messenger=None, store=None,    47                  publisher=None, preferences_dir=None):    48     49         """    50         Initialise the handler with any specifically indicated 'senders' and    51         'recipient' of a calendar object. The object is initially undefined.    52     53         The optional 'messenger' provides a means of interacting with the mail    54         system.    55     56         The optional 'store' and 'publisher' can be specified to override the    57         default store and publisher objects.    58         """    59     60         ClientForObject.__init__(self, None, recipient and get_uri(recipient), messenger, store, publisher, preferences_dir)    61     62         self.senders = senders and set(map(get_address, senders))    63         self.recipient = recipient and get_address(recipient)    64     65         self.results = []    66         self.outgoing_methods = set()    67     68     def wrap(self, text, link=True):    69     70         "Wrap any valid message for passing to the recipient."    71     72         _ = self.get_translator()    73     74         texts = []    75         texts.append(text)    76         if link and self.have_manager():    77             texts.append(_("If your mail program cannot handle this "    78                            "message, you may view the details here:\n\n%s") %    79                          get_object_url(self.uid, self.recurrenceid))    80     81         return self.add_result(None, None, MIMEText("\n".join(texts)))    82     83     # Result registration.    84     85     def add_result(self, method, outgoing_recipients, part):    86     87         """    88         Record a result having the given 'method', 'outgoing_recipients' and    89         message 'part'.    90         """    91     92         if outgoing_recipients:    93             self.outgoing_methods.add(method)    94         self.results.append((outgoing_recipients, part))    95     96     def add_results(self, methods, outgoing_recipients, parts):    97     98         """    99         Record results having the given 'methods', 'outgoing_recipients' and   100         message 'parts'.   101         """   102    103         if outgoing_recipients:   104             self.outgoing_methods.update(methods)   105         for part in parts:   106             self.results.append((outgoing_recipients, part))   107    108     def get_results(self):   109         return self.results   110    111     def get_outgoing_methods(self):   112         return self.outgoing_methods   113    114     # Logic, filtering and access to calendar structures and other data.   115    116     def filter_by_senders(self, mapping):   117    118         """   119         Return a list of items from 'mapping' filtered using sender information.   120         """   121    122         if self.senders:   123    124             # Get a mapping from senders to identities.   125    126             identities = get_sender_identities(mapping)   127    128             # Find the senders that are valid.   129    130             senders = map(get_address, identities)   131             valid = self.senders.intersection(senders)   132    133             # Return the true identities.   134    135             return reduce(lambda a, b: a + b, [identities[get_uri(address)] for address in valid], [])   136         else:   137             return mapping   138    139     def filter_by_recipient(self, mapping):   140    141         """   142         Return a list of items from 'mapping' filtered using recipient   143         information.   144         """   145    146         if self.recipient:   147             addresses = set(map(get_address, mapping))   148             return map(get_uri, addresses.intersection([self.recipient]))   149         else:   150             return mapping   151    152     def require_organiser(self, from_organiser=True):   153    154         """   155         Return the organiser for the current object, filtered for the sender or   156         recipient of interest. Return None if no identities are eligible.   157    158         The organiser identity is normalized.   159         """   160    161         organiser, organiser_attr = organiser_item = uri_item(self.obj.get_item("ORGANIZER"))   162    163         if not organiser:   164             return None   165    166         # Only provide details for an organiser who sent/receives the message.   167    168         organiser_filter_fn = from_organiser and self.filter_by_senders or self.filter_by_recipient   169    170         if not organiser_filter_fn(dict([organiser_item])):   171             return None   172    173         # Test against any previously-received organiser details.   174    175         if not self.is_recognised_organiser(organiser):   176             replacement = self.get_organiser_replacement()   177    178             # Allow any organiser as a replacement where indicated.   179    180             if replacement == "any":   181                 pass   182    183             # Allow any recognised attendee as a replacement where indicated.   184    185             elif replacement != "attendee" or not self.is_recognised_attendee(organiser):   186                 return None   187    188         return organiser_item   189    190     def require_attendees(self, from_organiser=True):   191    192         """   193         Return the attendees for the current object, filtered for the sender or   194         recipient of interest. Return None if no identities are eligible.   195    196         The attendee identities are normalized.   197         """   198    199         attendee_map = uri_dict(self.obj.get_value_map("ATTENDEE"))   200    201         # Only provide details for attendees who sent/receive the message.   202    203         attendee_filter_fn = from_organiser and self.filter_by_recipient or self.filter_by_senders   204    205         attendees = {}   206         for attendee in attendee_filter_fn(attendee_map):   207             if attendee:   208                 attendees[attendee] = attendee_map[attendee]   209    210         return attendees   211    212     def require_organiser_and_attendees(self, from_organiser=True):   213    214         """   215         Return the organiser and attendees for the current object, filtered for   216         the recipient of interest. Return None if no identities are eligible.   217    218         Organiser and attendee identities are normalized.   219         """   220    221         organiser_item = self.require_organiser(from_organiser)   222         attendees = self.require_attendees(from_organiser)   223    224         if not attendees or not organiser_item:   225             return None   226    227         return organiser_item, attendees   228    229 # vim: tabstop=4 expandtab shiftwidth=4