Mercurial > hg > gcmultimerge
annotate multimerge.py @ 14:8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 04 Jul 2016 12:59:30 +0300 |
parents | dd240a7ad913 |
children | 4168dde804ae |
rev | line source |
---|---|
1 | 1 #!/usr/bin/python |
3 | 2 # coding=utf-8 |
2 | 3 ### |
4 ### Google Calendar MultiMerge v0.000001 | |
5 ### (C) 2016 Matti 'ccr' Hamalainen <ccr@tnsp.org> | |
6 ### | |
7 ### Python 2.7 <= x < 3 required! Please refer to | |
8 ### README.txt for information on other depencies. | |
9 ### | |
1 | 10 import os |
11 import sys | |
12 import signal | |
13 import re | |
14 import time | |
15 import datetime | |
14
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
16 |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
17 import smtplib |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
18 from email.mime.text import MIMEText |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
19 |
1 | 20 import httplib2 |
21 import ConfigParser | |
22 import oauth2client | |
23 from oauth2client import client | |
24 from oauth2client import tools | |
4 | 25 from oauth2client import file |
1 | 26 from googleapiclient import discovery |
27 | |
28 | |
29 ### | |
30 ### Misc. helper functions | |
31 ### | |
32 | |
33 ## Wrapper for print() that does not break when redirecting stdin/out | |
34 ## because of piped output not having a defined encoding. We default | |
35 ## to UTF-8 encoding in output here. | |
36 def gcm_print(smsg): | |
37 gcm_msgbuf.append(smsg.encode("UTF-8")) | |
38 if sys.stdout.encoding != None: | |
39 print(smsg.encode(sys.stdout.encoding)) | |
40 else: | |
41 print(smsg.encode("UTF-8")) | |
42 | |
43 | |
44 ## Fatal errors | |
45 def gcm_fatal(smsg): | |
46 gcm_print(u"ERROR: "+ smsg) | |
14
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
47 if cfg.email_ok and cfg.email: |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
48 ## If e-mail is set, send e-mail |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
49 msg = MIMEText(("\n".join(gcm_msgbuf)).encode("UTF-8"), "plain") |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
50 msg.set_charset("UTF-8") |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
51 msg["Subject"] = cfg.email_subject |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
52 msg["From"] = cfg.email_sender |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
53 msg["To"] = ",".join(cfg.email_to) |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
54 try: |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
55 smtpH = smtplib.SMTP('localhost') |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
56 smtpH.sendmail(cfg.email_sender, cfg.email_to, msg.as_string()) |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
57 smtpH.quit() |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
58 except: |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
59 gcm_print("FATAL: Oh crap, e-mail sending failed.") |
1 | 60 sys.exit(1) |
61 | |
62 | |
63 ## Debug messages | |
64 def gcm_debug(smsg): | |
65 if cfg.debug: | |
66 gcm_print(u"DBG: "+ smsg) | |
67 else: | |
68 gcm_msgbuf.append(u"DBG: "+ smsg.encode("UTF-8")) | |
69 | |
70 | |
71 ## Handle SIGINT signals here | |
72 def gcm_signal_handler(signal, frame): | |
73 gcm_print("\nQuitting due to SIGINT / Ctrl+C!") | |
74 sys.exit(0) | |
75 | |
76 | |
77 def gcm_get_credentials(mcfg): | |
78 store = oauth2client.file.Storage(mcfg.credential_file) | |
79 credentials = store.get() | |
80 if not credentials or credentials.invalid: | |
81 flow = client.flow_from_clientsecrets(mcfg.secret_file, mcfg.scope) | |
82 flow.user_agent = mcfg.app_name | |
83 credentials = tools.run_flow(flow, store, mcfg) | |
84 if not credentials or credentials.invalid: | |
85 gcm_fatal("Failed to authenticate / invalid credentials.") | |
86 return credentials | |
87 | |
88 | |
89 def gcm_dump_events(events): | |
90 for event in events: | |
91 ev_start = event["start"].get("dateTime", event["start"].get("date")) | |
92 ev_end = event["end"].get("dateTime", event["end"].get("date")) | |
93 gcm_print(u"{0:25} - {1:25} : {2}".format(ev_start, ev_end, event["summary"])) | |
94 | |
95 | |
5
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
96 def gcm_is_str(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
97 return isinstance(mstr, basestring) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
98 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
99 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
100 def gcm_is_string(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
101 return mstr == None or gcm_is_str(mstr) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
102 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
103 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
104 def gcm_is_log_level(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
105 if not gcm_is_str(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
106 return False |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
107 else: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
108 return mstr.upper() in ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
109 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
110 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
111 def gcm_trans_log_level(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
112 return mstr.upper() |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
113 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
114 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
115 def gcm_is_filename(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
116 if not gcm_is_str(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
117 return False |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
118 else: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
119 return re.match("^[a-z0-9][a-z0-9\.\_\-]+$", mstr, flags=re.IGNORECASE) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
120 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
121 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
122 def gcm_trans_bool(mbool): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
123 if gcm_is_str(mbool): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
124 if re.match("^\s*(true|1|on|yes)\s*$", mbool, re.IGNORECASE): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
125 mbool = True |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
126 elif re.match("^\s*(false|0|off|no)\s*$", mbool, re.IGNORECASE): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
127 mbool = False |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
128 else: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
129 return None |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
130 return mbool |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
131 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
132 def gcm_is_bool(mbool): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
133 mval = gcm_trans_bool(mbool) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
134 if not isinstance(mval, bool): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
135 gcm_fatal("gcm_is_bool(): Invalid boolean value '{0}', should be true|false|1|0|on|off|yes|no.".format(mbool)) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
136 else: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
137 return True |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
138 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
139 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
140 def gcm_trans_list(mlist): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
141 morig = mlist |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
142 if gcm_is_str(mlist): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
143 mlist = re.split("\s*,\s*", mlist, flags=re.IGNORECASE) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
144 if not isinstance(mlist, list): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
145 gcm_fatal("gcm_trans_list(): Could not parse list '{0}'.".format(mlist)) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
146 elif not isinstance(mlist, list): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
147 gcm_fatal("gcm_trans_list(): Invalid value '{0}'.".format(mlist)) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
148 return mlist |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
149 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
150 def gcm_is_list(mlist): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
151 return gcm_trans_list(mlist) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
152 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
153 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
154 def gcm_is_email(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
155 if not gcm_is_string(mstr): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
156 return False |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
157 else: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
158 return re.match("^.*?\s+<[a-z0-9]+[a-z0-9\.\+\-]*\@[a-z0-9]+[a-z0-9\.\-]+>\s*$|[a-z0-9]+[a-z0-9\.\+\-]*\@[a-z0-9]+[a-z0-9\.\-]+", mstr, flags=re.IGNORECASE) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
159 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
160 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
161 def gcm_trans_email_list(mlist): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
162 if mlist == None: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
163 return mlist |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
164 else: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
165 return gcm_trans_list(mlist.strip()) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
166 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
167 def gcm_is_email_list(mlist): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
168 mlist = gcm_trans_email_list(mlist) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
169 if mlist != None: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
170 for email in mlist: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
171 if not gcm_is_email(email): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
172 gcm_fatal("Invalid e-mail address '{0}' in list {1}.".format(email, ", ".join(mlist))) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
173 return True |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
174 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
175 |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
176 |
1 | 177 class GCMSettings(dict): |
178 def __init__(self): | |
179 self.m_data = {} | |
180 self.m_saveable = {} | |
5
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
181 self.m_validate = {} |
1 | 182 self.m_translate = {} |
183 | |
184 def __getattr__(self, name): | |
185 if name in self.m_data: | |
186 return self.m_data[name] | |
187 else: | |
188 gcm_fatal("GCMSettings.__getattr__(): No such attribute '"+ name +"'.") | |
189 | |
5
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
190 def mvalidate(self, name, value): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
191 if name in self.m_validate and self.m_validate[name]: |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
192 if not self.m_validate[name](value): |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
193 gcm_fatal("GCMSettings.mvalidate(): Invalid value for attribute '{0}': {1}".format(name, value)) |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
194 |
1 | 195 def mtranslate(self, name, value): |
196 if name in self.m_translate and self.m_translate[name]: | |
197 return self.m_translate[name](value) | |
198 else: | |
199 return value | |
200 | |
201 def mdef(self, name, saveable, validate, translate, value): | |
5
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
202 self.mvalidate(name, value) |
1 | 203 self.m_saveable[name] = saveable |
5
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
204 self.m_validate[name] = validate |
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
205 self.m_translate[name] = translate |
1 | 206 self.m_data[name] = self.mtranslate(name, value) |
207 | |
208 def mset(self, name, value): | |
5
9d4152f32223
Add some code for settings validation.
Matti Hamalainen <ccr@tnsp.org>
parents:
4
diff
changeset
|
209 self.mvalidate(name, value) |
1 | 210 if name in self.m_data: |
211 self.m_data[name] = self.mtranslate(name, value) | |
212 else: | |
213 gcm_fatal("GCMSettings.mset(): No such attribute '"+ name +"'.") | |
214 | |
215 def mget(self, name): | |
216 if name in self.m_data: | |
217 return self.m_data[name] | |
218 else: | |
219 return None | |
220 | |
6
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
221 def mread(self, cfgparser, sect): |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
222 for name in self.m_saveable: |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
223 if cfgparser.has_option(sect, name): |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
224 value = cfgparser.get(sect, name) |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
225 self.mset(name, value) |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
226 gcm_debug("{0} -> '{1}' == {2}".format(name, value, self.mget(name))) |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
227 |
1 | 228 |
229 ### | |
230 ### Main program starts | |
231 ### | |
232 gcm_msgbuf = [] | |
233 signal.signal(signal.SIGINT, gcm_signal_handler) | |
234 | |
235 | |
236 ## Settings | |
237 cfg = GCMSettings() | |
238 | |
239 cfg.mdef("debug", True, gcm_is_bool, gcm_trans_bool, False) | |
240 | |
14
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
241 cfg.mdef("email_ok", False, None, None, False) |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
242 cfg.mdef("email", True, gcm_is_bool, gcm_trans_bool, False) |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
243 cfg.mdef("email_to", True, gcm_is_email_list, gcm_trans_email_list, None) |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
244 cfg.mdef("email_sender", True, gcm_is_email, None, None) |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
245 cfg.mdef("email_subject", True, gcm_is_string, None, "Google Calendar MultiMerge status") |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
246 |
1 | 247 cfg.mdef("source_regex", True, gcm_is_string, None, "^R:\s*(.*?)\s*\(\s*(.+?)\s*\)\s*$") |
248 cfg.mdef("source_regmap", False, gcm_is_list, gcm_trans_list, [1, 2]) | |
249 cfg.mdef("source_regmap_len", False, None, None, len(cfg.source_regmap)) | |
250 | |
251 cfg.mdef("dest_name", True, gcm_is_string, None, u"Raahen kansainvälisyystoiminta") | |
252 cfg.mdef("dest_id", True, gcm_is_string, None, None) | |
253 | |
254 cfg.mdef("noauth_local_webserver", False, None, None, True) | |
255 #cfg.mdef("auth_host_name", False, None, None, "localhost") | |
256 #cfg.mdef("auth_host_port", False, None, None, [8080, 8090]) | |
257 cfg.mdef("logging_level", True, gcm_is_log_level, gcm_trans_log_level, "ERROR") | |
258 | |
259 # No need to touch these | |
260 cfg.mdef("app_name", False, None, None, "Google Calendar MultiMerge") | |
261 cfg.mdef("scope", False, None, None, "https://www.googleapis.com/auth/calendar") | |
262 #cfg.mdef("scope", False, None, None, "https://www.googleapis.com/auth/calendar.readonly") | |
263 cfg.mdef("secret_file", True, gcm_is_filename, None, "client_secret.json") | |
264 cfg.mdef("credential_file", True, gcm_is_filename, None, "client_credentials.json") | |
265 | |
6
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
266 |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
267 ## Read, parse and validate configuration file |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
268 if len(sys.argv) > 1: |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
269 gcm_debug("Reading configuration from '{0}'.".format(sys.argv[1])) |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
270 try: |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
271 cfgparser = ConfigParser.RawConfigParser() |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
272 cfgparser.read(sys.argv[1]) |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
273 except Exception as e: |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
274 gcm_fatal("Failed to read configuration file '{0}': {1}".format(sys.argv[1], str(e))) |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
275 |
7
f2ecfb3e04ee
Check that the required section exists in configuration.
Matti Hamalainen <ccr@tnsp.org>
parents:
6
diff
changeset
|
276 # Check that the required section exists |
f2ecfb3e04ee
Check that the required section exists in configuration.
Matti Hamalainen <ccr@tnsp.org>
parents:
6
diff
changeset
|
277 section = "gcm" |
f2ecfb3e04ee
Check that the required section exists in configuration.
Matti Hamalainen <ccr@tnsp.org>
parents:
6
diff
changeset
|
278 if not cfgparser.has_section(section): |
f2ecfb3e04ee
Check that the required section exists in configuration.
Matti Hamalainen <ccr@tnsp.org>
parents:
6
diff
changeset
|
279 gcm_fatal("Invalid configuration, missing '{0}' section.".format(section)) |
f2ecfb3e04ee
Check that the required section exists in configuration.
Matti Hamalainen <ccr@tnsp.org>
parents:
6
diff
changeset
|
280 |
10
b237b96602ad
We need to handle "debug" setting before other settings, so we need a
Matti Hamalainen <ccr@tnsp.org>
parents:
9
diff
changeset
|
281 # Debug setting is a special case, we need to get it |
b237b96602ad
We need to handle "debug" setting before other settings, so we need a
Matti Hamalainen <ccr@tnsp.org>
parents:
9
diff
changeset
|
282 # set before everything else, so do it here .. |
b237b96602ad
We need to handle "debug" setting before other settings, so we need a
Matti Hamalainen <ccr@tnsp.org>
parents:
9
diff
changeset
|
283 if cfgparser.has_option(section, "debug"): |
b237b96602ad
We need to handle "debug" setting before other settings, so we need a
Matti Hamalainen <ccr@tnsp.org>
parents:
9
diff
changeset
|
284 cfg.mset("debug", cfgparser.get(section, "debug")) |
b237b96602ad
We need to handle "debug" setting before other settings, so we need a
Matti Hamalainen <ccr@tnsp.org>
parents:
9
diff
changeset
|
285 |
6
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
286 # Parse the settings and validate |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
287 cfg.mread(cfgparser, section) |
ee6bf617f839
Implement configuration file reading.
Matti Hamalainen <ccr@tnsp.org>
parents:
5
diff
changeset
|
288 |
8 | 289 |
290 ## Validate settings | |
14
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
291 if cfg.email: |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
292 if cfg.email_subject == None or len(cfg.email_subject) == 0: |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
293 gcm_fatal("E-mail enabled but email_subject not set.") |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
294 elif cfg.email_sender == None: |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
295 gcm_fatal("E-mail enabled but email_sender not set.") |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
296 elif cfg.email_to == None: |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
297 gcm_fatal("E-mail enabled but email_to not set.") |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
298 else: |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
299 cfg.mset("email_ok", True) |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
300 |
8262efacf3fb
Initial implementation of sending e-mail in fatal error cases.
Matti Hamalainen <ccr@tnsp.org>
parents:
13
diff
changeset
|
301 |
9
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
302 if len(cfg.source_regmap) != cfg.source_regmap_len: |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
303 gcm_fatal("Setting source_regmap list must be {0} items.".format(cfg.source_regmap_len)) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
304 else: |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
305 # Force to integers |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
306 try: |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
307 cfg.source_regmap = map(lambda x: int(x), cfg.source_regmap) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
308 except Exception as e: |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
309 gcm_fatal("Invalid source_regmap: {0}".format(str(e))) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
310 |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
311 |
8 | 312 if not cfg.dest_name and not cfg.dest_id: |
313 gcm_fatal("Target calendar ID or name required, but not set.") | |
314 | |
315 | |
316 if cfg.dest_name: | |
317 cfg.mset("dest_name", cfg.mget("dest_name").strip()) | |
318 | |
319 | |
1 | 320 ## Initialize and authorize API connection |
321 credentials = gcm_get_credentials(cfg) | |
322 http = credentials.authorize(httplib2.Http()) | |
323 service = discovery.build("calendar", "v3", http=http) | |
324 | |
325 | |
326 ## Fetch complete calendar list | |
327 gcm_debug("Fetching available calendars ..") | |
328 calendars = [] | |
329 calPageToken = None | |
330 while True: | |
331 # We want everything except deleted and hidden calendars | |
332 calResult = service.calendarList().list( | |
333 showHidden=False, | |
334 showDeleted=False, | |
335 pageToken=calPageToken | |
336 ).execute() | |
337 | |
338 calendars.extend(calResult.get("items", [])) | |
339 calPageToken = calResult.get("nextPageToken") | |
340 if not calPageToken: | |
341 break | |
342 | |
343 if len(calendars) == 0: | |
344 gcm_fatal("No calendars found?") | |
345 | |
346 | |
9
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
347 ## Filter desired SOURCE calendars based on specified regexp |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
348 src_re = re.compile(cfg.source_regex) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
349 src_calendars = [] |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
350 for calendar in calendars: |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
351 if "summary" in calendar: |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
352 if not cfg.dest_id and cfg.dest_name == calendar["summary"].strip(): |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
353 cfg.mset("dest_id", calendar["id"]) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
354 |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
355 mre = src_re.match(calendar["summary"]) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
356 if mre: |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
357 calendar["gcm_title"] = mre.group(cfg.source_regmap[0]) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
358 calendar["gcm_id"] = mre.group(cfg.source_regmap[1]) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
359 src_calendars.append(calendar) |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
360 |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
361 |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
362 ## Check if we have target ID |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
363 if not cfg.dest_id: |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
364 gcm_fatal(u"Could not find target/destination calendar ID for '"+ cfg.dest_name +"'.") |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
365 |
01c933dba120
Filter source calendars based on regexp.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
366 |
11
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
367 ## Now, we fetch and collect events |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
368 gcm_debug(u"Fetching calendar events .. ") |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
369 calEvents = [] |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
370 for calendar in src_calendars: |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
371 gcm_debug("- "+calendar["id"]) |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
372 eventsResult = service.events().list( |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
373 timeZone="EEST", |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
374 calendarId=calendar["id"], |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
375 singleEvents=True, |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
376 showDeleted=False, |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
377 orderBy="startTime").execute() |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
378 |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
379 # Add events, if any, to main list |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
380 events = eventsResult.get("items", []) |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
381 if events: |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
382 calEvents.append(events) |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
383 if cfg.debug: |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
384 gcm_dump_events(events) |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
385 |
fcdee7c04ed8
Implement fetching of source events.
Matti Hamalainen <ccr@tnsp.org>
parents:
10
diff
changeset
|
386 |
13
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
387 ## Get current events |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
388 gcm_debug(u"Fetching current target calendar events {0}".format(cfg.dest_id)) |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
389 eventsResult = service.events().list( |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
390 calendarId=cfg.dest_id, |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
391 singleEvents=True, |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
392 showDeleted=True).execute() |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
393 |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
394 currEvents = eventsResult.get("items", []) |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
395 if currEvents: |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
396 gcm_debug(u"Found {0} event(s).".format(len(currEvents))) |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
397 else: |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
398 gcm_debug(u"No current events.") |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
399 |
dd240a7ad913
Fetch current events in destination calendar.
Matti Hamalainen <ccr@tnsp.org>
parents:
11
diff
changeset
|
400 |