from __future__ import with_statement
+import itertools
import logging
-import gvoice
+from gvoice import gvoice
+from util import io as io_utils
-_moduleLogger = logging.getLogger("gv_backend")
+
+_moduleLogger = logging.getLogger(__name__)
class GVDialer(object):
+ MESSAGE_TEXTS = "Text"
+ MESSAGE_VOICEMAILS = "Voicemail"
+ MESSAGE_ALL = "All"
+
+ HISTORY_RECEIVED = "Received"
+ HISTORY_MISSED = "Missed"
+ HISTORY_PLACED = "Placed"
+ HISTORY_ALL = "All"
+
def __init__(self, cookieFile = None):
self._gvoice = gvoice.GVoiceBackend(cookieFile)
-
- self._contacts = None
+ self._texts = []
+ self._voicemails = []
+ self._received = []
+ self._missed = []
+ self._placed = []
def is_quick_login_possible(self):
"""
- @returns True then is_authed might be enough to login, else full login is required
+ @returns True then refresh_account_info might be enough to login, else full login is required
"""
return self._gvoice.is_quick_login_possible()
- def is_authed(self, force = False):
- """
- Attempts to detect a current session
- @note Once logged in try not to reauth more than once a minute.
- @returns If authenticated
- """
- return self._gvoice.is_authed(force)
+ def refresh_account_info(self):
+ return self._gvoice.refresh_account_info()
def login(self, username, password):
"""
return self._gvoice.login(username, password)
def logout(self):
+ self._texts = []
+ self._voicemails = []
+ self._received = []
+ self._missed = []
+ self._placed = []
return self._gvoice.logout()
+ def persist(self):
+ return self._gvoice.persist()
+
def is_dnd(self):
return self._gvoice.is_dnd()
"""
return self._gvoice.cancel(outgoingNumber)
- def send_sms(self, phoneNumber, message):
- self._gvoice.send_sms(phoneNumber, message)
+ def send_sms(self, phoneNumbers, message):
+ self._gvoice.send_sms(phoneNumbers, message)
def search(self, query):
"""
def get_feed(self, feed):
return self._gvoice.get_feed(feed)
- def download(self, messageId, adir):
+ def download(self, messageId, targetPath):
"""
Download a voicemail or recorded call MP3 matching the given ``msg``
which can either be a ``Message`` instance, or a SHA1 identifier.
- Saves files to ``adir`` (defaults to current directory).
Message hashes can be found in ``self.voicemail().messages`` for example.
Returns location of saved file.
"""
- return self._gvoice.download(messageId, adir)
+ self._gvoice.download(messageId, targetPath)
def is_valid_syntax(self, number):
"""
"""
return self._gvoice.get_callback_number()
- def get_recent(self):
+ def get_call_history(self, historyType):
"""
@returns Iterable of (personsName, phoneNumber, exact date, relative date, action)
"""
- return self._gvoice.get_recent()
-
- def get_contacts(self):
- """
- @returns Iterable of (contact id, contact name)
- """
- self._update_contacts_cache()
- contactsToSort = [
- (contactDetails["name"], contactId)
- for contactId, contactDetails in self._contacts.iteritems()
- ]
- contactsToSort.sort()
- return (
- (contactId, contactName)
- for (contactName, contactId) in contactsToSort
- )
+ history = list(self._get_call_history(historyType))
+ history.sort(key=lambda item: item["time"])
+ return history
- def get_contact_details(self, contactId):
+ def _get_call_history(self, historyType):
"""
- @returns Iterable of (Phone Type, Phone Number)
+ @returns Iterable of (personsName, phoneNumber, exact date, relative date, action)
"""
- if self._contacts is None:
- self._update_contacts_cache()
- contactDetails = self._contacts[contactId]
- # Defaulting phoneTypes because those are just things like faxes
- return (
- (number.get("phoneType", ""), number["phoneNumber"])
- for number in contactDetails["numbers"]
- )
-
- def get_messages(self):
- conversations = self._gvoice.get_conversations()
+ if historyType in [self.HISTORY_RECEIVED, self.HISTORY_ALL] or not self._received:
+ self._received = list(self._gvoice.get_received_calls())
+ for item in self._received:
+ item["action"] = self.HISTORY_RECEIVED
+ if historyType in [self.HISTORY_MISSED, self.HISTORY_ALL] or not self._missed:
+ self._missed = list(self._gvoice.get_missed_calls())
+ for item in self._missed:
+ item["action"] = self.HISTORY_MISSED
+ if historyType in [self.HISTORY_PLACED, self.HISTORY_ALL] or not self._placed:
+ self._placed = list(self._gvoice.get_placed_calls())
+ for item in self._placed:
+ item["action"] = self.HISTORY_PLACED
+ received = self._received
+ missed = self._missed
+ placed = self._placed
+ for item in received:
+ yield item
+ for item in missed:
+ yield item
+ for item in placed:
+ yield item
+
+ def get_messages(self, messageType):
+ messages = list(self._get_messages(messageType))
+ messages.sort(key=lambda message: message["time"])
+ return messages
+
+ def _get_messages(self, messageType):
+ if messageType in [self.MESSAGE_VOICEMAILS, self.MESSAGE_ALL] or not self._voicemails:
+ self._voicemails = list(self._gvoice.get_voicemails())
+ if messageType in [self.MESSAGE_TEXTS, self.MESSAGE_ALL] or not self._texts:
+ self._texts = list(self._gvoice.get_texts())
+ voicemails = self._voicemails
+ smss = self._texts
+
+ conversations = itertools.chain(voicemails, smss)
for conversation in conversations:
messages = conversation.messages
- messageParts = (
+ messageParts = [
(message.whoFrom, self._format_message(message), message.when)
for message in messages
- )
+ ]
messageDetails = {
"id": conversation.id,
def factory_name():
return "Google Voice"
- def _update_contacts_cache(self):
- self._contacts = dict(self._gvoice.get_contacts())
-
def _format_message(self, message):
messagePartFormat = {
"med1": "<i>%s</i>",
"high": "<b>%s</b>",
}
return " ".join(
- messagePartFormat[text.accuracy] % text.text
+ messagePartFormat[text.accuracy] % io_utils.escape(text.text)
for text in message.body
)