084127cd14eb465b7dad92dee9200e7be266a165
[gc-dialer] / dialcentral / alarm_notify.py
1 #!/usr/bin/env python
2
3 import os
4 import filecmp
5 import ConfigParser
6 import pprint
7 import logging
8 import logging.handlers
9
10 import constants
11 from util import linux as linux_utils
12 from backends.gvoice import gvoice
13
14
15 CACHE_PATH = linux_utils.get_resource_path("cache", constants.__app_name__)
16
17
18 def get_missed(backend):
19         missedPage = backend._browser.download(backend._XML_MISSED_URL)
20         missedJson = backend._grab_json(missedPage)
21         return missedJson
22
23
24 def get_voicemail(backend):
25         voicemailPage = backend._browser.download(backend._XML_VOICEMAIL_URL)
26         voicemailJson = backend._grab_json(voicemailPage)
27         return voicemailJson
28
29
30 def get_sms(backend):
31         smsPage = backend._browser.download(backend._XML_SMS_URL)
32         smsJson = backend._grab_json(smsPage)
33         return smsJson
34
35
36 def remove_reltime(data):
37         for messageData in data["messages"].itervalues():
38                 for badPart in [
39                         "relTime",
40                         "relativeStartTime",
41                         "time",
42                         "star",
43                         "isArchived",
44                         "isRead",
45                         "isSpam",
46                         "isTrash",
47                         "labels",
48                 ]:
49                         if badPart in messageData:
50                                 del messageData[badPart]
51         for globalBad in ["unreadCounts", "totalSize", "resultsPerPage"]:
52                 if globalBad in data:
53                         del data[globalBad]
54
55
56 def is_type_changed(backend, type, get_material):
57         jsonMaterial = get_material(backend)
58         unreadCount = jsonMaterial["unreadCounts"][type]
59
60         previousSnapshotPath = os.path.join(CACHE_PATH, "snapshot_%s.old.json" % type)
61         currentSnapshotPath = os.path.join(CACHE_PATH, "snapshot_%s.json" % type)
62
63         try:
64                 os.remove(previousSnapshotPath)
65         except OSError, e:
66                 # check if failed purely because the old file didn't exist, which is fine
67                 if e.errno != 2:
68                         raise
69         try:
70                 os.rename(currentSnapshotPath, previousSnapshotPath)
71                 previousExists = True
72         except OSError, e:
73                 # check if failed purely because the new old file didn't exist, which is fine
74                 if e.errno != 2:
75                         raise
76                 previousExists = False
77
78         remove_reltime(jsonMaterial)
79         textMaterial = pprint.pformat(jsonMaterial)
80         currentSnapshot = file(currentSnapshotPath, "w")
81         try:
82                 currentSnapshot.write(textMaterial)
83         finally:
84                 currentSnapshot.close()
85
86         if unreadCount == 0 or not previousExists:
87                 return False
88
89         seemEqual = filecmp.cmp(previousSnapshotPath, currentSnapshotPath)
90         return not seemEqual
91
92
93 def create_backend(config):
94         gvCookiePath = os.path.join(CACHE_PATH, "gv_cookies.txt")
95         backend = gvoice.GVoiceBackend(gvCookiePath)
96
97         loggedIn = False
98
99         if not loggedIn:
100                 loggedIn = backend.refresh_account_info() is not None
101
102         if not loggedIn:
103                 import base64
104                 try:
105                         blobs = (
106                                 config.get(constants.__pretty_app_name__, "bin_blob_%i" % i)
107                                 for i in xrange(2)
108                         )
109                         creds = (
110                                 base64.b64decode(blob)
111                                 for blob in blobs
112                         )
113                         username, password = tuple(creds)
114                         loggedIn = backend.login(username, password) is not None
115                 except ConfigParser.NoOptionError, e:
116                         pass
117                 except ConfigParser.NoSectionError, e:
118                         pass
119
120         assert loggedIn
121         return backend
122
123
124 def is_changed(config, backend):
125         try:
126                 notifyOnMissed = config.getboolean("2 - Account Info", "notifyOnMissed")
127                 notifyOnVoicemail = config.getboolean("2 - Account Info", "notifyOnVoicemail")
128                 notifyOnSms = config.getboolean("2 - Account Info", "notifyOnSms")
129         except ConfigParser.NoOptionError, e:
130                 notifyOnMissed = False
131                 notifyOnVoicemail = False
132                 notifyOnSms = False
133         except ConfigParser.NoSectionError, e:
134                 notifyOnMissed = False
135                 notifyOnVoicemail = False
136                 notifyOnSms = False
137         logging.debug(
138                 "Missed: %s, Voicemail: %s, SMS: %s" % (notifyOnMissed, notifyOnVoicemail, notifyOnSms)
139         )
140
141         notifySources = []
142         if notifyOnMissed:
143                 notifySources.append(("missed", get_missed))
144         if notifyOnVoicemail:
145                 notifySources.append(("voicemail", get_voicemail))
146         if notifyOnSms:
147                 notifySources.append(("sms", get_sms))
148
149         notifyUser = False
150         for type, get_material in notifySources:
151                 if is_type_changed(backend, type, get_material):
152                         notifyUser = True
153         return notifyUser
154
155
156 def notify_on_change():
157         settingsPath = linux_utils.get_resource_path("config", constants.__app_name__, "settings.ini")
158
159         config = ConfigParser.SafeConfigParser()
160         config.read(settingsPath)
161         backend = create_backend(config)
162         notifyUser = is_changed(config, backend)
163
164         if notifyUser:
165                 logging.info("Changed")
166                 import led_handler
167                 led = led_handler.LedHandler()
168                 led.on()
169         else:
170                 logging.info("No Change")
171
172
173 def run():
174         notifierPath = os.path.join(CACHE_PATH, "notifier.log")
175
176         logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
177         logging.basicConfig(level=logging.DEBUG, format=logFormat)
178         rotating = logging.handlers.RotatingFileHandler(notifierPath, maxBytes=512*1024, backupCount=1)
179         rotating.setFormatter(logging.Formatter(logFormat))
180         root = logging.getLogger()
181         root.addHandler(rotating)
182         logging.info("Notifier %s-%s" % (constants.__version__, constants.__build__))
183         logging.info("OS: %s" % (os.uname()[0], ))
184         logging.info("Kernel: %s (%s) for %s" % os.uname()[2:])
185         logging.info("Hostname: %s" % os.uname()[1])
186         try:
187                 notify_on_change()
188         except:
189                 logging.exception("Error")
190                 raise
191
192
193 if __name__ == "__main__":
194         run()