1
2
3
4 """Module for sending push notifications to Android devices that have
5 Notify My Android installed. See www.notifymyandroid.com/ for more
6 information.
7
8 copyright: Copyright (c) Jeffrey Goettsch and other contributors.
9 license: BSD, see LICENSE for details.
10
11 """
12
13
14 import logging
15 import urllib
16 import urllib2
17 try:
18 from xml.etree import cElementTree
19 ElementTree = cElementTree
20 except ImportError:
21 from xml.etree import ElementTree
22
23 from pushnotify import exceptions
24
25
26 PUBLIC_API_URL = u'https://www.notifymyandroid.com/publicapi'
27 VERIFY_URL = u'/'.join([PUBLIC_API_URL, 'verify'])
28 NOTIFY_URL = u'/'.join([PUBLIC_API_URL, 'notify'])
29
30
32 """Client for sending push notificiations to Android devices with
33 the Notify My Android application installed.
34
35 Member Vars:
36 apikeys: A list of strings, each containing a 48 character api
37 key.
38 developerkey: A string containing a 48 character developer key.
39
40 """
41
42 - def __init__(self, apikeys=None, developerkey=None):
43 """Initialize the Notify My Android client.
44
45 Args:
46 apikeys: A list of strings, each containing a valid api
47 key.
48 developerkey: A string containing a valid developer key.
49
50 """
51
52 self.logger = logging.getLogger('{0}.{1}'.format(
53 self.__module__, self.__class__.__name__))
54
55 self._browser = urllib2.build_opener(urllib2.HTTPSHandler())
56 self._last_type = None
57 self._last_code = None
58 self._last_message = None
59 self._last_remaining = None
60 self._last_resettimer = None
61
62 self.apikeys = [] if apikeys is None else apikeys
63 self.developerkey = developerkey
64
65 - def _get(self, url):
66
67 self.logger.debug('_get requesting url: {0}'.format(url))
68
69 request = urllib2.Request(url)
70 response_stream = self._browser.open(request)
71 response = response_stream.read()
72
73 self.logger.info('_get received response: {0}'.format(response))
74
75 return response
76
78
79 root = ElementTree.fromstring(xmlresp)
80
81 self._last_type = root[0].tag.lower()
82 self._last_code = root[0].attrib['code']
83
84 if self._last_type == 'success':
85 self._last_message = None
86 self._last_remaining = root[0].attrib['remaining']
87 self._last_resettimer = root[0].attrib['resettimer']
88 elif self._last_type == 'error':
89 self._last_message = root[0].text
90 self._last_remaining = None
91 self._last_resettimer = None
92
93 if (not verify or
94 (self._last_code != '400' and self._last_code != '401')):
95 self._raise_exception()
96 else:
97 raise exceptions.UnrecognizedResponseError(xmlresp, -1)
98
99 return root
100
101 - def _post(self, url, data):
102
103 self.logger.debug('_post sending data: {0}'.format(data))
104 self.logger.debug('_post sending to url: {0}'.format(url))
105
106 request = urllib2.Request(url, data)
107 response_stream = self._browser.open(request)
108 response = response_stream.read()
109
110 self.logger.info('_post received response: {0}'.format(response))
111
112 return response
113
131
132 - def notify(self, app, event, desc, kwargs=None):
133 """Send a notification to each apikey in self.apikeys.
134
135 Args:
136 app: A string of up to 256 characters containing the name
137 of the application sending the notification.
138 event: A string of up to 1000 characters containing the
139 event that is being notified (i.e. subject or brief
140 description.)
141 desc: A string of up to 10000 characters containing the
142 notification text.
143 kwargs: A dictionary with any of the following strings as
144 keys:
145 priority: An integer between -2 and 2, indicating the
146 priority of the notification. -2 is the lowest, 2 is
147 the highest, and 0 is normal.
148 url: A string of up to 2000 characters containing a URL
149 to attach to the notification.
150 content_type: A string containing "text/html" (without
151 the quotes) that then allows some basic HTML to be
152 used while displaying the notification.
153 (default: None)
154
155 Raises:
156 pushnotify.exceptions.FormatError
157 pushnotify.exceptions.ApiKeyError
158 pushnotify.exceptions.RateLimitExceeded
159 pushnotify.exceptions.ServerError
160 pushnotify.exceptions.UnknownError
161 pushnotify.exceptions.UnrecognizedResponseError
162
163 """
164
165 data = {'apikey': ','.join(self.apikeys),
166 'application': app,
167 'event': event,
168 'description': desc}
169
170 if self.developerkey:
171 data['developerkey'] = self.developerkey
172
173 if kwargs:
174 data.update(kwargs)
175
176 data = urllib.urlencode(data)
177
178 response = self._post(NOTIFY_URL, data)
179 self._parse_response(response)
180
182 """Verify an API key.
183
184 Args:
185 apikey: A string of 48 characters containing an API key.
186
187 Raises:
188 pushnotify.exceptions.RateLimitExceeded
189 pushnotify.exceptions.ServerError
190 pushnotify.exceptions.UnknownError
191 pushnotify.exceptions.UnrecognizedResponseError
192
193 Returns:
194 A boolean containing True if the API key is valid, and False
195 if it is not.
196
197 """
198
199 data = {'apikey': apikey}
200
201 if self.developerkey:
202 data['developerkey'] = self.developerkey
203
204 querystring = urllib.urlencode(data)
205 url = '?'.join([VERIFY_URL, querystring])
206
207 response = self._get(url)
208 self._parse_response(response, True)
209
210 return self._last_code == '200'
211
212 if __name__ == '__main__':
213 pass
214