# HG changeset patch # User Paul Boddie # Date 1411403336 -7200 # Node ID aa8c34d84ad2fc58eab8b2fbf2d9fa0c971a87be # Parent dddb17c1aa28dc25df93e3dc945f7d730c333f77 Convert to a more regular structure for calendar details. Added MIME part production for handler results. diff -r dddb17c1aa28 -r aa8c34d84ad2 imip_agent.py --- a/imip_agent.py Mon Sep 22 18:26:59 2014 +0200 +++ b/imip_agent.py Mon Sep 22 18:28:56 2014 +0200 @@ -1,7 +1,9 @@ #!/usr/bin/env python from email import message_from_file -from vCalendar import parse, iterwrite +from email.mime.text import MIMEText +from smtplib import SMTP +from vCalendar import parse, iterwrite, ParseError, SECTION_TYPES import imip_store import sys @@ -35,7 +37,21 @@ "text/x-vcalendar", "application/ics", # other possibilities ] +# Sending of outgoing messages. + +def sendmail(sender, recipients, data): + smtp = SMTP("localhost") + smtp.sendmail(sender, recipients, data) + smtp.quit() + +# Processing of incoming messages. + def process(f, args): + + "Process content from the stream 'f' accompanied by the given 'args'." + + recipient = args[0] + msg = message_from_file(f) print >>open("/tmp/imip.txt", "a"), "----" print >>open("/tmp/imip.txt", "a"), args @@ -49,25 +65,23 @@ if part.get_content_type() in itip_content_types and \ part.get_param("method"): - handle_itip_part(part) + handle_itip_part(part, recipient) def get_itip_elements(elements): d = {} for name, attr, value in elements: - if isinstance(value, list): - d[name] = attr, get_itip_elements(value) + if not d.has_key(name): + d[name] = [] + if name in SECTION_TYPES: + d[name].append((attr, get_itip_elements(value))) else: - if not d.has_key(name): - d[name] = [] d[name].append((attr, value)) return d def get_attr_value(d, name, single=True): if d.has_key(name): values = d[name] - if isinstance(values, tuple): - return values - elif single and len(values) == 1: + if single and len(values) == 1: return values[0] else: return values @@ -77,36 +91,51 @@ def get_value(d, name, single=True): if d.has_key(name): values = d[name] - if isinstance(values, tuple): - return values[1] - elif single and len(values) == 1: + if single and len(values) == 1: return values[0][1] else: return map(lambda x: x[1], values) else: return None -def handle_itip_part(part): +def handle_itip_part(part, recipient): method = part.get_param("method") + # Decode the data and parse it. + f = StringIO(part.get_payload(decode=True)) - doctype, attrs, elements = parse(f, encoding=part.get_content_charset()) + + try: + doctype, attrs, elements = parse(f, encoding=part.get_content_charset()) + except (ParseError, ValueError): + sys.exit(EX_DATAERR) + + # Only handle calendar information. if doctype == "VCALENDAR": itip = get_itip_elements(elements) + # Require consistency between declared and employed methods. + if get_value(itip, "METHOD") == method: + # Look for different kinds of sections. + for name, cls in handlers: - details = get_value(itip, name) + for details in get_value(itip, name, False) or []: + + # Dispatch to a handler and obtain any response. - if details: - print >>open("/tmp/imip.txt", "a"), details handler = cls(details) - print >>open("/tmp/imip.txt", "a"), "Handling", method, "with", handler, "->", methods[method](handler) - methods[method](handler)() + part = methods[method](handler)() + + if part: + print >>open("/tmp/imip.txt", "a"), part.as_string() class Handler: + + "General handler support." + def __init__(self, details): self.details = details self.uid = get_value(details, "UID") @@ -180,9 +209,9 @@ # Get the details for the attendee. - out = open("/tmp/imip.txt", "a") + out = StringIO() try: - w = iterwrite(out) + w = iterwrite(out, encoding="utf-8") calendar = [] cwrite = calendar.append @@ -207,6 +236,8 @@ w.write("VCALENDAR", {}, calendar) + return MIMEText(out.getvalue(), "calendar", "utf-8") + finally: out.close()