1 #!/usr/bin/env python 2 3 """ 4 Handlers for a person for whom scheduling is performed. 5 """ 6 7 from email.mime.text import MIMEText 8 from imiptools.content import Handler, to_part 9 from vCalendar import to_node 10 11 class Event(Handler): 12 13 "An event handler." 14 15 def _record_and_deliver(self, queue=False): 16 17 oa = self.require_organiser_and_attendees() 18 if not oa: 19 return False 20 21 (organiser, organiser_attr), attendees = oa 22 23 # Process each attendee separately. 24 25 for attendee, attendee_attr in attendees.items(): 26 27 if not self.have_new_object(attendee, "VEVENT"): 28 continue 29 30 # Store the event and queue any request. 31 32 self.store.set_event(attendee, self.uid, to_node( 33 {"VEVENT" : [(self.details, {})]} 34 )) 35 36 if queue: 37 self.store.queue_request(attendee, self.uid) 38 39 return True 40 41 def add(self): 42 43 # NOTE: Queue a suggested modification to any active event. 44 45 # The message is now wrapped and passed on to the recipient. 46 47 return "ADD", MIMEText("An addition to an event has been received.") 48 49 def cancel(self): 50 51 # NOTE: Queue a suggested modification to any active event. 52 53 # The message is now wrapped and passed on to the recipient. 54 55 return "CANCEL", MIMEText("A cancellation has been received.") 56 57 def counter(self): 58 59 # NOTE: Queue a suggested modification to any active event. 60 61 # The message is now wrapped and passed on to the recipient. 62 63 return "COUNTER", MIMEText("A counter proposal has been received.") 64 65 def declinecounter(self): 66 67 # NOTE: Queue a suggested modification to any active event. 68 69 # The message is now wrapped and passed on to the recipient. 70 71 return "DECLINECOUNTER", MIMEText("A declining counter proposal has been received.") 72 73 def publish(self): 74 75 # NOTE: Register details of any relevant event. 76 77 # The message is now wrapped and passed on to the recipient. 78 79 return "PUBLISH", MIMEText("Details of an event have been received.") 80 81 def refresh(self): 82 83 # NOTE: Update details of any active event. 84 85 # The message is now wrapped and passed on to the recipient. 86 87 return "REFRESH", MIMEText("An event update has been received.") 88 89 def reply(self): 90 91 "Record replies and notify the recipient." 92 93 self._record_and_deliver(False) 94 95 # The message is now wrapped and passed on to the recipient. 96 97 return "REPLY", MIMEText("A reply has been received.") 98 99 def request(self): 100 101 "Hold requests and notify the recipient." 102 103 self._record_and_deliver(True) 104 105 # The message is now wrapped and passed on to the recipient. 106 107 return "REQUEST", MIMEText("A request has been queued.") 108 109 class Freebusy(Handler): 110 111 "A free/busy handler." 112 113 def publish(self): 114 115 # NOTE: Register free/busy information. 116 117 # The message is now wrapped and passed on to the recipient. 118 119 return "PUBLISH", MIMEText("Details of a contact's availability have been received.") 120 121 def reply(self): 122 123 "Record replies and notify the recipient." 124 125 self._record_and_deliver(False) 126 127 # The message is now wrapped and passed on to the recipient. 128 129 return "REPLY", MIMEText("A reply has been received.") 130 131 def request(self): 132 133 """ 134 Respond to a request by preparing a reply containing free/busy 135 information for each indicated attendee. 136 """ 137 138 # NOTE: This is currently the same as the resource handler but should be 139 # NOTE: subject to policy/preferences. 140 141 oa = self.require_organiser_and_attendees() 142 if not oa: 143 return None 144 145 (organiser, organiser_attr), attendees = oa 146 147 # Construct an appropriate fragment. 148 149 calendar = [] 150 cwrite = calendar.append 151 152 # Get the details for each attendee. 153 154 for attendee, attendee_attr in attendees.items(): 155 freebusy = self.store.get_freebusy(attendee) 156 157 record = [] 158 rwrite = record.append 159 160 rwrite(("ORGANIZER", organiser_attr, organiser)) 161 rwrite(("ATTENDEE", attendee_attr, attendee)) 162 rwrite(("UID", {}, self.uid)) 163 164 if freebusy: 165 for start, end, uid in freebusy: 166 rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, [start, end])) 167 168 cwrite(("VFREEBUSY", {}, record)) 169 170 # Return the reply. 171 172 return "REPLY", to_part("REPLY", calendar) 173 174 class Journal(Handler): 175 176 "A journal entry handler." 177 178 def add(self): 179 180 # NOTE: Queue a suggested modification to any active entry. 181 182 # The message is now wrapped and passed on to the recipient. 183 184 return "ADD", MIMEText("An addition to a journal entry has been received.") 185 186 def cancel(self): 187 188 # NOTE: Queue a suggested modification to any active entry. 189 190 # The message is now wrapped and passed on to the recipient. 191 192 return "CANCEL", MIMEText("A cancellation has been received.") 193 194 def publish(self): 195 196 # NOTE: Register details of any relevant entry. 197 198 # The message is now wrapped and passed on to the recipient. 199 200 return "PUBLISH", MIMEText("Details of a journal entry have been received.") 201 202 class Todo(Handler): 203 204 "A to-do item handler." 205 206 def add(self): 207 208 # NOTE: Queue a suggested modification to any active item. 209 210 # The message is now wrapped and passed on to the recipient. 211 212 return "ADD", MIMEText("An addition to an item has been received.") 213 214 def cancel(self): 215 216 # NOTE: Queue a suggested modification to any active item. 217 218 # The message is now wrapped and passed on to the recipient. 219 220 return "CANCEL", MIMEText("A cancellation has been received.") 221 222 def counter(self): 223 224 # NOTE: Queue a suggested modification to any active item. 225 226 # The message is now wrapped and passed on to the recipient. 227 228 return "COUNTER", MIMEText("A counter proposal has been received.") 229 230 def declinecounter(self): 231 232 # NOTE: Queue a suggested modification to any active item. 233 234 # The message is now wrapped and passed on to the recipient. 235 236 return "DECLINECOUNTER", MIMEText("A declining counter proposal has been received.") 237 238 def publish(self): 239 240 # NOTE: Register details of any relevant item. 241 242 # The message is now wrapped and passed on to the recipient. 243 244 return "PUBLISH", MIMEText("Details of an item have been received.") 245 246 def refresh(self): 247 248 # NOTE: Update details of any active item. 249 250 # The message is now wrapped and passed on to the recipient. 251 252 return "REFRESH", MIMEText("An item update has been received.") 253 254 def reply(self): 255 256 "Record replies and notify the recipient." 257 258 self._record_and_deliver(False) 259 260 # The message is now wrapped and passed on to the recipient. 261 262 return "REPLY", MIMEText("A reply has been received.") 263 264 def request(self): 265 266 "Hold requests and notify the recipient." 267 268 self._record_and_deliver(True) 269 270 # The message is now wrapped and passed on to the recipient. 271 272 return "REQUEST", MIMEText("A request has been queued.") 273 274 # Handler registry. 275 276 handlers = [ 277 ("VFREEBUSY", Freebusy), 278 ("VEVENT", Event), 279 ("VTODO", Todo), 280 ("VJOURNAL", Journal), 281 ] 282 283 # vim: tabstop=4 expandtab shiftwidth=4