1 #!/usr/bin/env python 2 3 from email import message_from_file 4 from vCalendar import parse 5 import imip_store 6 import sys 7 8 try: 9 from cStringIO import StringIO 10 except ImportError: 11 from StringIO import StringIO 12 13 # Postfix exit codes. 14 15 EX_USAGE = 64 16 EX_DATAERR = 65 17 EX_NOINPUT = 66 18 EX_NOUSER = 67 19 EX_NOHOST = 68 20 EX_UNAVAILABLE = 69 21 EX_SOFTWARE = 70 22 EX_OSERR = 71 23 EX_OSFILE = 72 24 EX_CANTCREAT = 73 25 EX_IOERR = 74 26 EX_TEMPFAIL = 75 27 EX_PROTOCOL = 76 28 EX_NOPERM = 77 29 EX_CONFIG = 78 30 31 # Permitted iTIP content types. 32 33 itip_content_types = [ 34 "text/calendar", # from RFC 6047 35 "text/x-vcalendar", "application/ics", # other possibilities 36 ] 37 38 def process(f, args): 39 msg = message_from_file(f) 40 print >>open("/tmp/imip.txt", "a"), "----" 41 print >>open("/tmp/imip.txt", "a"), args 42 print >>open("/tmp/imip.txt", "a"), "----" 43 print >>open("/tmp/imip.txt", "a"), msg.as_string() 44 print >>open("/tmp/imip.txt", "a") 45 46 # Handle messages with iTIP parts. 47 48 for part in msg.walk(): 49 if part.get_content_type() in itip_content_types and \ 50 part.get_param("method"): 51 52 handle_itip_part(part) 53 54 def get_itip_elements(elements): 55 d = {} 56 for name, attr, value in elements: 57 if isinstance(value, list): 58 d[name] = attr, get_itip_elements(value) 59 else: 60 if not d.has_key(name): 61 d[name] = [] 62 d[name].append((attr, value)) 63 return d 64 65 def get_value(d, name, single=True): 66 if d.has_key(name): 67 values = d[name] 68 if isinstance(values, tuple): 69 return values[1] 70 elif single and len(values) == 1: 71 return values[0][1] 72 else: 73 return map(lambda x: x[1], values) 74 else: 75 return None 76 77 def handle_itip_part(part): 78 method = part.get_param("method") 79 80 f = StringIO(part.get_payload(decode=True)) 81 doctype, attrs, elements = parse(f, encoding=part.get_content_charset()) 82 83 if doctype == "VCALENDAR": 84 itip = get_itip_elements(elements) 85 86 if get_value(itip, "METHOD") == method: 87 88 for name, cls in handlers: 89 details = get_value(itip, name) 90 91 if details: 92 print >>open("/tmp/imip.txt", "a"), details 93 handler = cls(details) 94 print >>open("/tmp/imip.txt", "a"), "Handling", method, "with", handler, "->", methods[method](handler) 95 methods[method](handler)() 96 97 class Handler: 98 def __init__(self, details): 99 self.details = details 100 self.uid = get_value(details, "UID") 101 self.sequence = get_value(details, "SEQUENCE") 102 self.store = imip_store.FileStore() 103 104 def publish(self): 105 pass 106 107 def get_value(self, name, single=False): 108 return get_value(self.details, name, single) 109 110 class Event(Handler): 111 def add(self): 112 pass 113 114 def cancel(self): 115 pass 116 117 def counter(self): 118 pass 119 120 def declinecounter(self): 121 pass 122 123 def refresh(self): 124 pass 125 126 def reply(self): 127 pass 128 129 def request(self): 130 pass 131 132 class Freebusy(Handler): 133 def reply(self): 134 attendees = self.get_value("ATTENDEE", False) 135 organiser = self.get_value("ORGANIZER") 136 if not attendees and not organiser: 137 return 138 139 # Store the reply details for the attendee. 140 141 def request(self): 142 attendees = self.get_value("ATTENDEE", False) 143 organiser = self.get_value("ORGANIZER") 144 print >>open("/tmp/imip.txt", "a"), attendees, organiser 145 if not attendees and not organiser: 146 return 147 148 # Get the details for the attendee. 149 150 for attendee in attendees: 151 freebusy = self.store.get_freebusy(attendee) 152 print >>open("/tmp/imip.txt", "a"), freebusy 153 154 # Send a reply with the information. 155 156 class Journal(Handler): 157 def add(self): 158 pass 159 160 def cancel(self): 161 pass 162 163 class Todo(Handler): 164 def add(self): 165 pass 166 167 def cancel(self): 168 pass 169 170 def counter(self): 171 pass 172 173 def declinecounter(self): 174 pass 175 176 def refresh(self): 177 pass 178 179 def reply(self): 180 pass 181 182 def request(self): 183 pass 184 185 # Handler registry. 186 187 handlers = [ 188 ("VFREEBUSY", Freebusy), 189 ("VEVENT", Event), 190 ("VTODO", Todo), 191 ("VJOURNAL", Journal), 192 ] 193 194 methods = { 195 "ADD" : lambda handler: handler.add, 196 "CANCEL" : lambda handler: handler.cancel, 197 "COUNTER" : lambda handler: handler.counter, 198 "DECLINECOUNTER" : lambda handler: handler.declinecounter, 199 "PUBLISH" : lambda handler: handler.publish, 200 "REFRESH" : lambda handler: handler.refresh, 201 "REPLY" : lambda handler: handler.reply, 202 "REQUEST" : lambda handler: handler.request, 203 } 204 205 if __name__ == "__main__": 206 process(sys.stdin, sys.argv[1:]) 207 208 # vim: tabstop=4 expandtab shiftwidth=4