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
33 from gvoice import gvoice
36 _moduleLogger = logging.getLogger(__name__)
39 class GVDialer(object):
41 def __init__(self, cookieFile = None):
42 self._gvoice = gvoice.GVoiceBackend(cookieFile)
46 def is_quick_login_possible(self):
48 @returns True then is_authed might be enough to login, else full login is required
50 return self._gvoice.is_quick_login_possible()
52 def is_authed(self, force = False):
54 Attempts to detect a current session
55 @note Once logged in try not to reauth more than once a minute.
56 @returns If authenticated
58 return self._gvoice.is_authed(force)
60 def login(self, username, password):
62 Attempt to login to GoogleVoice
63 @returns Whether login was successful or not
65 return self._gvoice.login(username, password)
68 return self._gvoice.logout()
71 return self._gvoice.is_dnd()
73 def set_dnd(self, doNotDisturb):
74 return self._gvoice.set_dnd(doNotDisturb)
76 def call(self, outgoingNumber):
78 This is the main function responsible for initating the callback
80 return self._gvoice.call(outgoingNumber)
82 def cancel(self, outgoingNumber=None):
84 Cancels a call matching outgoing and forwarding numbers (if given).
85 Will raise an error if no matching call is being placed
87 return self._gvoice.cancel(outgoingNumber)
89 def send_sms(self, phoneNumbers, message):
90 self._gvoice.send_sms(phoneNumbers, message)
92 def search(self, query):
94 Search your Google Voice Account history for calls, voicemails, and sms
95 Returns ``Folder`` instance containting matching messages
97 return self._gvoice.search(query)
99 def get_feed(self, feed):
100 return self._gvoice.get_feed(feed)
102 def download(self, messageId, adir):
104 Download a voicemail or recorded call MP3 matching the given ``msg``
105 which can either be a ``Message`` instance, or a SHA1 identifier.
106 Saves files to ``adir`` (defaults to current directory).
107 Message hashes can be found in ``self.voicemail().messages`` for example.
108 Returns location of saved file.
110 return self._gvoice.download(messageId, adir)
112 def is_valid_syntax(self, number):
114 @returns If This number be called ( syntax validation only )
116 return self._gvoice.is_valid_syntax(number)
118 def get_account_number(self):
120 @returns The GoogleVoice phone number
122 return self._gvoice.get_account_number()
124 def get_callback_numbers(self):
126 @returns a dictionary mapping call back numbers to descriptions
127 @note These results are cached for 30 minutes.
129 return self._gvoice.get_callback_numbers()
131 def set_callback_number(self, callbacknumber):
133 Set the number that GoogleVoice calls
134 @param callbacknumber should be a proper 10 digit number
136 return self._gvoice.set_callback_number(callbacknumber)
138 def get_callback_number(self):
140 @returns Current callback number or None
142 return self._gvoice.get_callback_number()
144 def get_recent(self):
146 @returns Iterable of (personsName, phoneNumber, exact date, relative date, action)
148 return self._gvoice.get_recent()
150 def get_contacts(self):
152 @returns Iterable of (contact id, contact name)
154 self._update_contacts_cache()
156 (contactDetails["name"], contactId)
157 for contactId, contactDetails in self._contacts.iteritems()
159 contactsToSort.sort()
161 (contactId, contactName)
162 for (contactName, contactId) in contactsToSort
165 def get_contact_details(self, contactId):
167 @returns Iterable of (Phone Type, Phone Number)
169 if self._contacts is None:
170 self._update_contacts_cache()
171 contactDetails = self._contacts[contactId]
172 # Defaulting phoneTypes because those are just things like faxes
174 (number.get("phoneType", ""), number["phoneNumber"])
175 for number in contactDetails["numbers"]
178 def get_messages(self):
179 voicemails = self._gvoice.get_voicemails()
180 smss = self._gvoice.get_texts()
181 conversations = itertools.chain(voicemails, smss)
182 for conversation in conversations:
183 messages = conversation.messages
185 (message.whoFrom, self._format_message(message), message.when)
186 for message in messages
190 "id": conversation.id,
191 "contactId": conversation.contactId,
192 "name": conversation.name,
193 "time": conversation.time,
194 "relTime": conversation.relTime,
195 "prettyNumber": conversation.prettyNumber,
196 "number": conversation.number,
197 "location": conversation.location,
198 "messageParts": messageParts,
199 "type": conversation.type,
200 "isRead": conversation.isRead,
201 "isTrash": conversation.isTrash,
202 "isSpam": conversation.isSpam,
203 "isArchived": conversation.isArchived,
207 def clear_caches(self):
210 def get_addressbooks(self):
212 @returns Iterable of (Address Book Factory, Book Id, Book Name)
216 def open_addressbook(self, bookId):
220 def contact_source_short_name(contactId):
225 return "Google Voice"
227 def _update_contacts_cache(self):
228 self._contacts = dict(self._gvoice.get_contacts())
230 def _format_message(self, message):
231 messagePartFormat = {
237 messagePartFormat[text.accuracy] % text.text
238 for text in message.body
242 def sort_messages(allMessages):
243 sortableAllMessages = [
244 (message["time"], message)
245 for message in allMessages
247 sortableAllMessages.sort(reverse=True)
250 for (exactTime, message) in sortableAllMessages
254 def decorate_recent(recentCallData):
256 @returns (personsName, phoneNumber, date, action)
258 contactId = recentCallData["contactId"]
259 if recentCallData["name"]:
260 header = recentCallData["name"]
261 elif recentCallData["prettyNumber"]:
262 header = recentCallData["prettyNumber"]
263 elif recentCallData["location"]:
264 header = recentCallData["location"]
268 number = recentCallData["number"]
269 relTime = recentCallData["relTime"]
270 action = recentCallData["action"]
271 return contactId, header, number, relTime, action
274 def decorate_message(messageData):
275 contactId = messageData["contactId"]
276 exactTime = messageData["time"]
277 if messageData["name"]:
278 header = messageData["name"]
279 elif messageData["prettyNumber"]:
280 header = messageData["prettyNumber"]
283 number = messageData["number"]
284 relativeTime = messageData["relTime"]
286 messageParts = list(messageData["messageParts"])
287 if len(messageParts) == 0:
288 messages = ("No Transcription", )
289 elif len(messageParts) == 1:
290 messages = (messageParts[0][1], )
293 "<b>%s</b>: %s" % (messagePart[0], messagePart[1])
294 for messagePart in messageParts
297 decoratedResults = contactId, header, number, relativeTime, messages
298 return decoratedResults