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 STORE_DIR = "/var/lib/imip-agent/store" 9 PUBLISH_DIR = "/var/www/imip-agent" 10 11 def check_dir(base, dir): 12 return commonprefix([base, abspath(dir)]) == base 13 14 def make_calendar(fragment, method=None): 15 return ("VCALENDAR", {}, 16 (method and [("METHOD", {}, method)] or []) + 17 [("VERSION", {}, "2.0")] + 18 fragment 19 ) 20 21 def to_stream(out, fragment, encoding="utf-8"): 22 iterwrite(out, encoding=encoding).append(fragment) 23 24 class FileBase: 25 26 "Basic filesystem operations." 27 28 def __init__(self, store_dir=STORE_DIR): 29 self.store_dir = store_dir 30 if not exists(self.store_dir): 31 makedirs(self.store_dir) 32 33 def get_file_object(self, base, *parts): 34 pathname = join(base, *parts) 35 return check_dir(base, pathname) and pathname or None 36 37 def get_object_for_user(self, user, uid): 38 dir = self.get_file_object(self.store_dir, user) 39 if not dir: 40 return False 41 42 filename = self.get_file_object(dir, uid) 43 if not filename: 44 return False 45 46 if not exists(dir): 47 makedirs(dir) 48 49 return filename 50 51 class FileStore(FileBase): 52 53 "A file store of tabular free/busy data and objects." 54 55 def get_event(self, user, uid): 56 57 "Get the event for the given 'user' with the given 'uid'." 58 59 filename = self.get_object_for_user(user, uid) 60 if not filename or not exists(filename): 61 return None 62 63 return exists(filename) and open(filename) or None 64 65 def set_event(self, user, uid, node): 66 67 "Set an event for 'user' having the given 'uid' and 'node'." 68 69 filename = self.get_object_for_user(user, uid) 70 if not filename: 71 return False 72 73 f = open(filename, "w") 74 try: 75 to_stream(f, node) 76 finally: 77 f.close() 78 79 return True 80 81 def get_freebusy(self, user): 82 83 "Get free/busy details for the given 'user'." 84 85 filename = self.get_object_for_user(user, "freebusy") 86 if not filename or not exists(filename): 87 return None 88 89 f = open(filename) 90 try: 91 l = [] 92 for line in f.readlines(): 93 l.append(tuple(line.strip().split("\t"))) 94 return l 95 finally: 96 f.close() 97 98 def set_freebusy(self, user, freebusy): 99 100 "For the given 'user', set 'freebusy' details." 101 102 filename = self.get_object_for_user(user, "freebusy") 103 if not filename: 104 return False 105 106 f = open(filename, "w") 107 try: 108 for item in freebusy: 109 f.write("\t".join(item) + "\n") 110 finally: 111 f.close() 112 113 return True 114 115 class FilePublisher(FileBase): 116 117 "A publisher of objects." 118 119 def __init__(self, store_dir=PUBLISH_DIR): 120 FileBase.__init__(self, store_dir) 121 122 def set_freebusy(self, user, freebusy): 123 124 "For the given 'user', set 'freebusy' details." 125 126 filename = self.get_object_for_user(user, "freebusy") 127 if not filename: 128 return False 129 130 record = [] 131 rwrite = record.append 132 133 rwrite(("ORGANIZER", {}, user)) 134 rwrite(("UID", {}, user)) 135 rwrite(("DTSTAMP", {}, datetime.utcnow().strftime("%Y%m%dT%H%M%SZ"))) 136 137 for start, end, uid in freebusy: 138 rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end]))) 139 140 f = open(filename, "w") 141 try: 142 to_stream(f, make_calendar([("VFREEBUSY", {}, record)], "PUBLISH")) 143 finally: 144 f.close() 145 146 return True 147 148 # vim: tabstop=4 expandtab shiftwidth=4