1 #!/usr/bin/env python 2 3 """ 4 A handler to help with testing. 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.client import ClientForObject 23 from imiptools.data import Object, get_address, parse_object 24 from imiptools.dates import get_datetime, to_timezone 25 from imiptools.mail import Messenger 26 from imiptools.period import RecurringPeriod 27 import imip_store 28 import sys 29 30 class TestClient(ClientForObject): 31 32 """ 33 A content handler for use in testing, as opposed to operating within the 34 mail processing pipeline. 35 """ 36 37 # Action methods. 38 39 def handle_request(self, action, start=None, end=None): 40 41 """ 42 Process the current request for the current user. Return whether the 43 given 'action' was taken. 44 45 If 'start' and 'end' are specified, they will be used in any 46 counter-proposal. 47 """ 48 49 # Reply only on behalf of this user. 50 51 if action in ("accept", "decline"): 52 attendee_attr = self.update_participation(self.obj, action == "accept" and "ACCEPTED" or "DECLINED") 53 method = "REPLY" 54 55 # For counter-proposals, set a new main period for the event. 56 57 elif action == "counter": 58 attendee_attr = self.obj.get_value_map("ATTENDEE").get(self.user) 59 period = self.obj.get_main_period(self.get_tzid()) 60 61 # Use the existing or configured time zone for the specified 62 # datetimes. 63 64 start = to_timezone(get_datetime(start), period.tzid) 65 end = to_timezone(get_datetime(end), period.tzid) 66 period = RecurringPeriod(start, end, period.tzid, period.origin, period.get_start_attr(), period.get_end_attr()) 67 self.obj.set_period(period) 68 method = "COUNTER" 69 else: 70 return None 71 72 if not attendee_attr: 73 return None 74 75 # NOTE: This is a simpler form of the code in imipweb.client. 76 77 organiser = get_address(self.obj.get_value("ORGANIZER")) 78 79 self.obj["ATTENDEE"] = [(self.user, attendee_attr)] 80 self.update_dtstamp() 81 self.set_sequence(False) 82 83 message = self.messenger.make_outgoing_message( 84 [self.obj.to_part(method)], 85 [organiser], 86 outgoing_bcc=get_address(self.user) 87 ) 88 89 return message.as_string() 90 91 # A simple main program that attempts to handle a stored request, writing the 92 # response message to standard output. 93 94 if __name__ == "__main__": 95 try: 96 action, store_dir, user = sys.argv[1:4] 97 if action == "counter": 98 start, end = sys.argv[4:6] 99 i = 6 100 else: 101 start, end = None, None 102 i = 4 103 uid, recurrenceid = (sys.argv[i:i+2] + [None] * 2)[:2] 104 except ValueError: 105 print >>sys.stderr, """\ 106 Need 'accept', 'counter' or 'decline', a store directory, user URI, any 107 counter-proposal datetimes (see below), plus the appropriate event UID and 108 RECURRENCE-ID (if a recurrence is involved). 109 110 The RECURRENCE-ID must be in exactly the form employed by the store, not a 111 different but equivalent representation. 112 113 Alternatively, omit the UID and RECURRENCE-ID and provide event-only details on 114 standard input to force the script to handle an event not already present in the 115 store. 116 117 If 'counter' has been indicated, alternative start and end datetimes are also 118 required. 119 """ 120 sys.exit(1) 121 122 store = imip_store.FileStore(store_dir) 123 124 if uid is not None: 125 fragment = store.get_event(user, uid, recurrenceid) 126 127 if not fragment: 128 print >>sys.stderr, "No such event:", uid, recurrenceid 129 sys.exit(1) 130 else: 131 fragment = parse_object(sys.stdin, "utf-8") 132 133 obj = Object(fragment) 134 handler = TestClient(obj, user, Messenger(), store) 135 response = handler.handle_request(action, start, end) 136 137 if response: 138 if uid is not None: 139 store.dequeue_request(user, uid, recurrenceid) 140 print response 141 else: 142 sys.exit(1) 143 144 # vim: tabstop=4 expandtab shiftwidth=4