4 DialCentral - Front end for Google's GoogleVoice service.
5 Copyright (C) 2008 Eric Warnke ericew AT gmail DOT com
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 Google Voice backend code
24 http://thatsmith.com/2009/03/google-voice-addon-for-firefox/
25 http://posttopic.com/topic/google-voice-add-on-development
28 from __future__ import with_statement
35 _moduleLogger = logging.getLogger("gv_backend")
38 class GVDialer(object):
40 def __init__(self, cookieFile = None):
41 self._gvoice = gvoice.GVoiceBackend(cookieFile)
45 def is_quick_login_possible(self):
47 @returns True then is_authed might be enough to login, else full login is required
49 return self._gvoice.is_quick_login_possible()
51 def is_authed(self, force = False):
53 Attempts to detect a current session
54 @note Once logged in try not to reauth more than once a minute.
55 @returns If authenticated
57 return self._gvoice.is_authed(force)
59 def login(self, username, password):
61 Attempt to login to GoogleVoice
62 @returns Whether login was successful or not
64 return self._gvoice.login(username, password)
67 return self._gvoice.logout()
70 return self._gvoice.is_dnd()
72 def set_dnd(self, doNotDisturb):
73 return self._gvoice.set_dnd(doNotDisturb)
75 def call(self, outgoingNumber):
77 This is the main function responsible for initating the callback
79 return self._gvoice.call(outgoingNumber)
81 def cancel(self, outgoingNumber=None):
83 Cancels a call matching outgoing and forwarding numbers (if given).
84 Will raise an error if no matching call is being placed
86 return self._gvoice.cancel(outgoingNumber)
88 def send_sms(self, phoneNumber, message):
89 self._gvoice.send_sms(phoneNumber, message)
91 def search(self, query):
93 Search your Google Voice Account history for calls, voicemails, and sms
94 Returns ``Folder`` instance containting matching messages
96 return self._gvoice.search(query)
98 def get_feed(self, feed):
99 return self._gvoice.get_feed(feed)
101 def download(self, messageId, adir):
103 Download a voicemail or recorded call MP3 matching the given ``msg``
104 which can either be a ``Message`` instance, or a SHA1 identifier.
105 Saves files to ``adir`` (defaults to current directory).
106 Message hashes can be found in ``self.voicemail().messages`` for example.
107 Returns location of saved file.
109 return self._gvoice.download(messageId, adir)
111 def is_valid_syntax(self, number):
113 @returns If This number be called ( syntax validation only )
115 return self._gvoice.is_valid_syntax(number)
117 def get_account_number(self):
119 @returns The GoogleVoice phone number
121 return self._gvoice.get_account_number()
123 def get_callback_numbers(self):
125 @returns a dictionary mapping call back numbers to descriptions
126 @note These results are cached for 30 minutes.
128 return self._gvoice.get_callback_numbers()
130 def set_callback_number(self, callbacknumber):
132 Set the number that GoogleVoice calls
133 @param callbacknumber should be a proper 10 digit number
135 return self._gvoice.set_callback_number(callbacknumber)
137 def get_callback_number(self):
139 @returns Current callback number or None
141 return self._gvoice.get_callback_number()
143 def get_recent(self):
145 @returns Iterable of (personsName, phoneNumber, exact date, relative date, action)
147 return self._gvoice.get_recent()
149 def get_contacts(self):
151 @returns Iterable of (contact id, contact name)
153 self._update_contacts_cache()
155 (contactDetails["name"], contactId)
156 for contactId, contactDetails in self._contacts.iteritems()
158 contactsToSort.sort()
160 (contactId, contactName)
161 for (contactName, contactId) in contactsToSort
164 def get_contact_details(self, contactId):
166 @returns Iterable of (Phone Type, Phone Number)
168 if self._contacts is None:
169 self._update_contacts_cache()
170 contactDetails = self._contacts[contactId]
171 # Filtering out lack of a phoneType because those are just things like faxes
173 (number["phoneType"], number["phoneNumber"])
174 for number in contactDetails["numbers"]
175 if "phoneType" in number
178 def get_messages(self):
179 conversations = self._gvoice.get_conversations()
180 for conversation in conversations:
181 messages = conversation.messages
183 (message.whoFrom, self._format_message(message), message.when)
184 for message in messages
188 "id": conversation.id,
189 "contactId": conversation.contactId,
190 "name": conversation.name,
191 "time": conversation.time,
192 "relTime": conversation.relTime,
193 "prettyNumber": conversation.prettyNumber,
194 "number": conversation.number,
195 "location": conversation.location,
196 "messageParts": messageParts,
197 "type": conversation.type,
198 "isRead": conversation.isRead,
199 "isTrash": conversation.isTrash,
200 "isSpam": conversation.isSpam,
201 "isArchived": conversation.isArchived,
205 def clear_caches(self):
208 def get_addressbooks(self):
210 @returns Iterable of (Address Book Factory, Book Id, Book Name)
214 def open_addressbook(self, bookId):
218 def contact_source_short_name(contactId):
223 return "Google Voice"
225 def _update_contacts_cache(self):
226 self._contacts = dict(self._gvoice.get_contacts())
228 def _format_message(self, message):
229 messagePartFormat = {
235 messagePartFormat[text.accuracy] % text.text
236 for text in message.body
240 def sort_messages(allMessages):
241 sortableAllMessages = [
242 (message["time"], message)
243 for message in allMessages
245 sortableAllMessages.sort(reverse=True)
248 for (exactTime, message) in sortableAllMessages
252 def decorate_recent(recentCallData):
254 @returns (personsName, phoneNumber, date, action)
256 contactId = recentCallData["contactId"]
257 if recentCallData["name"]:
258 header = recentCallData["name"]
259 elif recentCallData["prettyNumber"]:
260 header = recentCallData["prettyNumber"]
261 elif recentCallData["location"]:
262 header = recentCallData["location"]
266 number = recentCallData["number"]
267 relTime = recentCallData["relTime"]
268 action = recentCallData["action"]
269 return contactId, header, number, relTime, action
272 def decorate_message(messageData):
273 contactId = messageData["contactId"]
274 exactTime = messageData["time"]
275 if messageData["name"]:
276 header = messageData["name"]
277 elif messageData["prettyNumber"]:
278 header = messageData["prettyNumber"]
281 number = messageData["number"]
282 relativeTime = messageData["relTime"]
284 messageParts = list(messageData["messageParts"])
285 if len(messageParts) == 0:
286 messages = ("No Transcription", )
287 elif len(messageParts) == 1:
288 messages = (messageParts[0][1], )
291 "<b>%s</b>: %s" % (messagePart[0], messagePart[1])
292 for messagePart in messageParts
295 decoratedResults = contactId, header, number, relativeTime, messages
296 return decoratedResults