MANDATORY_PARAMETERS = {
'account' : 's',
- 'password' : 's'
+ 'password' : 's',
+ 'forward' : 's',
}
OPTIONAL_PARAMETERS = {
}
parameters['account'].encode('utf-8'),
parameters['password'].encode('utf-8'),
)
+ self._callbackNumber = parameters['forward'].encode('utf-8')
self._channelManager = channel_manager.ChannelManager(self)
cookieFilePath = "%s/cookies.txt" % constants._data_path_
)
try:
self._backend.login(*self._credentials)
+ self._backend.set_callback_number(self._callbackNumber)
except gv_backend.NetworkError:
self.StatusChanged(
telepathy.CONNECTION_STATUS_DISCONNECTED,
elif type == telepathy.CHANNEL_TYPE_TEXT:
if handleType != telepathy.HANDLE_TYPE_CONTACT:
raise telepathy.NotImplemented("Only Contacts are allowed")
- contact = handle.contact
+ channel = channelManager.channel_for_text(handle, None, suppressHandler)
+ elif type == telepathy.CHANNEL_TYPE_STREAMED_MEDIA:
+ if handleType != telepathy.HANDLE_TYPE_CONTACT:
+ raise telepathy.NotImplemented("Only Contacts are allowed")
channel = channelManager.channel_for_text(handle, None, suppressHandler)
else:
raise telepathy.NotImplemented("unknown channel type %s" % type)
For org.freedesktop.telepathy.Connection
"""
self.check_connected()
- self.check_handleType(handleType)
+ self.check_handle_type(handleType)
handles = []
for name in names:
return handles
def _create_contact_handle(self, name):
- requestedContactId, requestedContactName = handle.field_split(name)
+ requestedContactId = name
contacts = self._backend.get_contacts()
contactsFound = [
(contactId, contactName) for (contactId, contactName) in contacts
- if contactName == name
+ if contactId == requestedContactId
]
if 0 < len(contactsFound):
contactId, contactName = contactsFound[0]
- h = handle.create_handle(self, 'contact', contactId, contactName)
+ if len(contactsFound) != 1:
+ _moduleLogger.error("Contact ID was not unique: %s for %s" % (contactId, contactName))
else:
- h = handle.create_handle(self, 'contact', requestedContactId, requestedContactName)
+ contactId, contactName = requestedContactId, ""
+ h = handle.create_handle(self, 'contact', contactId, contactName)
"""
return self._accountNum
- def set_sane_callback(self):
- """
- Try to set a sane default callback number on these preferences
- 1) 1747 numbers ( Gizmo )
- 2) anything with gizmo in the name
- 3) anything with computer in the name
- 4) the first value
- """
- numbers = self.get_callback_numbers()
-
- for number, description in numbers.iteritems():
- if re.compile(r"""1747""").match(number) is not None:
- self.set_callback_number(number)
- return
-
- for number, description in numbers.iteritems():
- if re.compile(r"""gizmo""", re.I).search(description) is not None:
- self.set_callback_number(number)
- return
-
- for number, description in numbers.iteritems():
- if re.compile(r"""computer""", re.I).search(description) is not None:
- self.set_callback_number(number)
- return
-
- for number, description in numbers.iteritems():
- self.set_callback_number(number)
- return
-
def get_callback_numbers(self):
"""
@returns a dictionary mapping call back numbers to descriptions
for exactDate, name, number, relativeDate, action in sortedRecent:
yield name, number, relativeDate, action
- def get_addressbooks(self):
- """
- @returns Iterable of (Address Book Factory, Book Id, Book Name)
- """
- yield self, "", ""
-
- def open_addressbook(self, bookId):
- return self
-
- @staticmethod
- def contact_source_short_name(contactId):
- return "GV"
-
- @staticmethod
- def factory_name():
- return "Google Voice"
-
_contactsRe = re.compile(r"""<a href="/voice/m/contact/(\d+)">(.*?)</a>""", re.S)
_contactsNextRe = re.compile(r""".*<a href="/voice/m/contacts(\?p=\d+)">Next.*?</a>""", re.S)
_contactsURL = "https://www.google.com/voice/mobile/contacts"
decoratedSms = self._decorate_sms(parsedSms)
allMessages = itertools.chain(decoratedVoicemails, decoratedSms)
- sortedMessages = list(allMessages)
- sortedMessages.sort(reverse=True)
- for exactDate, header, number, relativeDate, message in sortedMessages:
- yield header, number, relativeDate, message
+ return allMessages
def _grab_json(self, flatXml):
xmlTree = ElementTree.fromstring(flatXml)
_voicemailNumberRegex = re.compile(r"""<input type="hidden" class="gc-text gc-quickcall-ac" value="(.*?)"/>""", re.MULTILINE)
_prettyVoicemailNumberRegex = re.compile(r"""<span class="gc-message-type">(.*?)</span>""", re.MULTILINE)
_voicemailLocationRegex = re.compile(r"""<span class="gc-message-location">.*?<a.*?>(.*?)</a></span>""", re.MULTILINE)
+ _messagesContactID = re.compile(r"""<a class=".*?gc-message-name-link.*?">.*?</a>\s*?<span .*?>(.*?)</span>""", re.MULTILINE)
#_voicemailMessageRegex = re.compile(r"""<span id="\d+-\d+" class="gc-word-(.*?)">(.*?)</span>""", re.MULTILINE)
#_voicemailMessageRegex = re.compile(r"""<a .*? class="gc-message-mni">(.*?)</a>""", re.MULTILINE)
_voicemailMessageRegex = re.compile(r"""(<span id="\d+-\d+" class="gc-word-(.*?)">(.*?)</span>|<a .*? class="gc-message-mni">(.*?)</a>)""", re.MULTILINE)
number = numberGroup.group(1).strip() if numberGroup else ""
prettyNumberGroup = self._prettyVoicemailNumberRegex.search(messageHtml)
prettyNumber = prettyNumberGroup.group(1).strip() if prettyNumberGroup else ""
+ contactIdGroup = self._messagesContactID.search(messageHtml)
+ contactId = contactIdGroup.group(1).strip() if contactIdGroup else number
messageGroups = self._voicemailMessageRegex.finditer(messageHtml)
messageParts = (
yield {
"id": messageId.strip(),
+ "contactId": contactId,
"name": name,
"time": exactTime,
"relTime": relativeTime,
"messageParts": messageParts,
}
- def _decorate_voicemail(self, parsedVoicemail):
+ def _decorate_voicemail(self, parsedVoicemails):
messagePartFormat = {
"med1": "<i>%s</i>",
"med2": "%s",
"high": "<b>%s</b>",
}
- for voicemailData in parsedVoicemail:
- exactTime = voicemailData["time"]
- if voicemailData["name"]:
- header = voicemailData["name"]
- elif voicemailData["prettyNumber"]:
- header = voicemailData["prettyNumber"]
- elif voicemailData["location"]:
- header = voicemailData["location"]
- else:
- header = "Unknown"
+ for voicemailData in parsedVoicemails:
message = " ".join((
messagePartFormat[quality] % part
for (quality, part) in voicemailData["messageParts"]
)).strip()
if not message:
message = "No Transcription"
- yield exactTime, header, voicemailData["number"], voicemailData["relTime"], (message, )
+ whoFrom = voicemailData["name"]
+ when = voicemailData["time"]
+ voicemailData["messageParts"] = ((whoFrom, message, when), )
+ yield voicemailData
_smsFromRegex = re.compile(r"""<span class="gc-message-sms-from">(.*?)</span>""", re.MULTILINE | re.DOTALL)
_smsTextRegex = re.compile(r"""<span class="gc-message-sms-time">(.*?)</span>""", re.MULTILINE | re.DOTALL)
number = numberGroup.group(1).strip() if numberGroup else ""
prettyNumberGroup = self._prettyVoicemailNumberRegex.search(messageHtml)
prettyNumber = prettyNumberGroup.group(1).strip() if prettyNumberGroup else ""
+ contactIdGroup = self._messagesContactID.search(messageHtml)
+ contactId = contactIdGroup.group(1).strip() if contactIdGroup else number
fromGroups = self._smsFromRegex.finditer(messageHtml)
fromParts = (group.group(1).strip() for group in fromGroups)
yield {
"id": messageId.strip(),
+ "contactId": contactId,
"name": name,
"time": exactTime,
"relTime": relativeTime,
"prettyNumber": prettyNumber,
"number": number,
+ "location": "",
"messageParts": messageParts,
}
- def _decorate_sms(self, parsedSms):
- for messageData in parsedSms:
- exactTime = messageData["time"]
- if messageData["name"]:
- header = messageData["name"]
- elif messageData["prettyNumber"]:
- header = messageData["prettyNumber"]
- else:
- header = "Unknown"
- number = messageData["number"]
- relativeTime = messageData["relTime"]
- messages = [
- "<b>%s</b>: %s" % (messagePart[0], messagePart[-1])
- for messagePart in messageData["messageParts"]
- ]
- if not messages:
- messages = ("No Transcription", )
- yield exactTime, header, number, relativeTime, messages
+ def _decorate_sms(self, parsedTexts):
+ return parsedTexts
+
+
+def set_sane_callback(backend):
+ """
+ Try to set a sane default callback number on these preferences
+ 1) 1747 numbers ( Gizmo )
+ 2) anything with gizmo in the name
+ 3) anything with computer in the name
+ 4) the first value
+ """
+ numbers = backend.get_callback_numbers()
+
+ priorityOrderedCriteria = [
+ ("1747", None),
+ (None, "gizmo"),
+ (None, "computer"),
+ (None, "sip"),
+ (None, None),
+ ]
+
+ for numberCriteria, descriptionCriteria in priorityOrderedCriteria:
+ for number, description in numbers.iteritems():
+ if numberCriteria is not None and re.compile(numberCriteria).match(number) is None:
+ continue
+ if descriptionCriteria is not None and re.compile(descriptionCriteria).match(description) is None:
+ continue
+ backend.set_callback_number(number)
+ return
+
+
+def sort_messages(allMessages):
+ sortableAllMessages = [
+ (message["time"], message)
+ for message in allMessages
+ ]
+ sortableAllMessages.sort(reverse=True)
+ return (
+ message
+ for (exactTime, message) in sortableAllMessages
+ )
+
+
+def decorate_message(messageData):
+ exactTime = messageData["time"]
+ if messageData["name"]:
+ header = messageData["name"]
+ elif messageData["prettyNumber"]:
+ header = messageData["prettyNumber"]
+ else:
+ header = "Unknown"
+ number = messageData["number"]
+ relativeTime = messageData["relTime"]
+
+ messageParts = list(messageData["messageParts"])
+ if len(messageParts) == 0:
+ messages = ("No Transcription", )
+ elif len(messageParts) == 1:
+ messages = (messageParts[0][1], )
+ else:
+ messages = [
+ "<b>%s</b>: %s" % (messagePart[0], messagePart[-1])
+ for messagePart in messageParts
+ ]
+
+ decoratedResults = header, number, relativeTime, messages
+ return decoratedResults
def test_backend(username, password):
# for contact in backend.get_contacts():
# print contact
# pprint.pprint(list(backend.get_contact_details(contact[0])))
- for message in backend.get_messages():
- pprint.pprint(message)
+ #for message in backend.get_messages():
+ # pprint.pprint(message)
+ for message in sort_messages(backend.get_messages()):
+ pprint.pprint(decorate_message(message))
return backend
+
+
+if __name__ == "__main__":
+ import sys
+ logging.basicConfig(level=logging.DEBUG)
+ test_backend(sys.argv[1], sys.argv[2])