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 class FileStore(FileBase): 38 39 "A file store of tabular free/busy data and objects." 40 41 def get_event(self, user, uid): 42 43 "Get the event for the given 'user' with the given 'uid'." 44 45 filename = self.get_file_object(self.store_dir, user, uid) 46 if not filename: 47 return None 48 49 return exists(filename) and open(filename) or None 50 51 def set_event(self, user, uid, node): 52 53 "Set an event for 'user' having the given 'uid' and 'node'." 54 55 dir = self.get_file_object(self.store_dir, user) 56 if not dir: 57 return False 58 59 filename = self.get_file_object(dir, uid) 60 if not filename: 61 return False 62 63 if not exists(dir): 64 makedirs(dir) 65 66 f = open(filename, "w") 67 try: 68 to_stream(f, node) 69 finally: 70 f.close() 71 72 return True 73 74 def get_freebusy(self, user): 75 76 "Get free/busy details for the given 'user'." 77 78 filename = self.get_file_object(self.store_dir, user, "freebusy") 79 if not filename or not exists(filename): 80 return None 81 82 f = open(filename) 83 try: 84 l = [] 85 for line in f.readlines(): 86 l.append(tuple(line.strip().split("\t"))) 87 return l 88 finally: 89 f.close() 90 91 def set_freebusy(self, user, freebusy): 92 93 "For the given 'user', set 'freebusy' details." 94 95 filename = self.get_file_object(self.store_dir, user, "freebusy") 96 if not filename: 97 return False 98 99 dir = split(filename)[0] 100 101 if not exists(dir): 102 makedirs(dir) 103 104 f = open(filename, "w") 105 try: 106 for item in freebusy: 107 f.write("\t".join(item) + "\n") 108 finally: 109 f.close() 110 111 return True 112 113 class FilePublisher(FileBase): 114 115 "A publisher of objects." 116 117 def __init__(self, store_dir=PUBLISH_DIR): 118 FileBase.__init__(self, store_dir) 119 120 def set_freebusy(self, user, freebusy): 121 122 "For the given 'user', set 'freebusy' details." 123 124 filename = self.get_file_object(self.store_dir, user, "freebusy") 125 if not filename: 126 return False 127 128 dir = split(filename)[0] 129 130 if not exists(dir): 131 makedirs(dir) 132 133 record = [] 134 rwrite = record.append 135 136 rwrite(("ORGANIZER", {}, user)) 137 rwrite(("UID", {}, user)) 138 rwrite(("DTSTAMP", {}, datetime.utcnow().strftime("%Y%m%dT%H%M%SZ"))) 139 140 for start, end, uid in freebusy: 141 rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end]))) 142 143 f = open(filename, "w") 144 try: 145 to_stream(f, make_calendar([("VFREEBUSY", {}, record)], "PUBLISH")) 146 finally: 147 f.close() 148 149 return True 150 151 # vim: tabstop=4 expandtab shiftwidth=4