1 #!/usr/bin/env python 2 3 from datetime import datetime 4 from os.path import abspath, commonprefix, exists, join, split 5 from os import makedirs 6 from vCalendar import iterwrite 7 8 # The location of the stored calendar information. 9 10 STORE_DIR = "/var/lib/imip-agent/store" 11 12 # The location of published static free/busy information. 13 14 PUBLISH_DIR = "/var/www/imip-agent/static" 15 16 def check_dir(base, dir): 17 return commonprefix([base, abspath(dir)]) == base 18 19 def make_calendar(fragment, method=None): 20 return ("VCALENDAR", {}, 21 (method and [("METHOD", {}, method)] or []) + 22 [("VERSION", {}, "2.0")] + 23 fragment 24 ) 25 26 def to_stream(out, fragment, encoding="utf-8"): 27 iterwrite(out, encoding=encoding).append(fragment) 28 29 class FileBase: 30 31 "Basic filesystem operations." 32 33 def __init__(self, store_dir=STORE_DIR): 34 self.store_dir = store_dir 35 if not exists(self.store_dir): 36 makedirs(self.store_dir) 37 38 def get_file_object(self, base, *parts): 39 pathname = join(base, *parts) 40 return check_dir(base, pathname) and pathname or None 41 42 def get_object_in_store(self, *parts): 43 44 """ 45 Return the name of any valid object stored within a hierarchy specified 46 by the given 'parts'. 47 """ 48 49 parent = expected = self.store_dir 50 51 for part in parts: 52 filename = self.get_file_object(expected, part) 53 if not filename: 54 return False 55 parent = expected 56 expected = filename 57 58 if not exists(parent): 59 makedirs(parent) 60 61 return filename 62 63 class FileStore(FileBase): 64 65 "A file store of tabular free/busy data and objects." 66 67 def get_event(self, user, uid): 68 69 "Get the event for the given 'user' with the given 'uid'." 70 71 filename = self.get_object_in_store(user, uid) 72 if not filename or not exists(filename): 73 return None 74 75 return exists(filename) and open(filename) or None 76 77 def set_event(self, user, uid, node): 78 79 "Set an event for 'user' having the given 'uid' and 'node'." 80 81 filename = self.get_object_in_store(user, uid) 82 if not filename: 83 return False 84 85 f = open(filename, "w") 86 try: 87 to_stream(f, node) 88 finally: 89 f.close() 90 91 return True 92 93 def get_freebusy(self, user): 94 95 "Get free/busy details for the given 'user'." 96 97 filename = self.get_object_in_store(user, "freebusy") 98 if not filename or not exists(filename): 99 return None 100 101 f = open(filename) 102 try: 103 l = [] 104 for line in f.readlines(): 105 l.append(tuple(line.strip().split("\t"))) 106 return l 107 finally: 108 f.close() 109 110 def set_freebusy(self, user, freebusy): 111 112 "For the given 'user', set 'freebusy' details." 113 114 filename = self.get_object_in_store(user, "freebusy") 115 if not filename: 116 return False 117 118 f = open(filename, "w") 119 try: 120 for item in freebusy: 121 f.write("\t".join(item) + "\n") 122 finally: 123 f.close() 124 125 return True 126 127 def queue_request(self, user, uid): 128 129 "Queue a request for 'user' having the given 'uid'." 130 131 filename = self.get_object_in_store(user, "requests") 132 if not filename: 133 return False 134 135 f = open(filename, "a") 136 try: 137 print >>f, uid 138 finally: 139 f.close() 140 141 return True 142 143 class FilePublisher(FileBase): 144 145 "A publisher of objects." 146 147 def __init__(self, store_dir=PUBLISH_DIR): 148 FileBase.__init__(self, store_dir) 149 150 def set_freebusy(self, user, freebusy): 151 152 "For the given 'user', set 'freebusy' details." 153 154 filename = self.get_object_in_store(user, "freebusy") 155 if not filename: 156 return False 157 158 record = [] 159 rwrite = record.append 160 161 rwrite(("ORGANIZER", {}, user)) 162 rwrite(("UID", {}, user)) 163 rwrite(("DTSTAMP", {}, datetime.utcnow().strftime("%Y%m%dT%H%M%SZ"))) 164 165 for start, end, uid in freebusy: 166 rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end]))) 167 168 f = open(filename, "w") 169 try: 170 to_stream(f, make_calendar([("VFREEBUSY", {}, record)], "PUBLISH")) 171 finally: 172 f.close() 173 174 return True 175 176 # vim: tabstop=4 expandtab shiftwidth=4