http://posttopic.com/topic/google-voice-add-on-development
"""
+from __future__ import with_statement
import os
import re
self._callbackNumber = ""
self._callbackNumbers = {}
+ _forwardURL = "https://www.google.com/voice/mobile/phones"
+
def is_authed(self, force = False):
"""
Attempts to detect a current session
_loginURL = "https://www.google.com/accounts/ServiceLoginAuth"
_galxRe = re.compile(r"""<input.*?name="GALX".*?value="(.*?)".*?/>""", re.MULTILINE | re.DOTALL)
- def login(self, username, password):
- """
- Attempt to login to GoogleVoice
- @returns Whether login was successful or not
- """
- self.logout()
-
+ def _get_token(self):
try:
tokenPage = self._browser.download(self._tokenURL)
except urllib2.URLError, e:
else:
galxToken = ""
_moduleLogger.debug("Could not grab GALX token")
+ return galxToken
+ def _login(self, username, password, token):
loginPostData = urllib.urlencode({
'Email' : username,
'Passwd' : password,
"ltmpl": "mobile",
"btmpl": "mobile",
"PersistentCookie": "yes",
- "GALX": galxToken,
+ "GALX": token,
"continue": self._forwardURL,
})
except urllib2.URLError, e:
_moduleLogger.exception("Translating error: %s" % str(e))
raise NetworkError("%s is not accesible" % self._loginURL)
+ return loginSuccessOrFailurePage
+
+ def login(self, username, password):
+ """
+ Attempt to login to GoogleVoice
+ @returns Whether login was successful or not
+ """
+ self.logout()
+ galxToken = self._get_token()
+ loginSuccessOrFailurePage = self._login(username, password, galxToken)
try:
self._grab_account_info(loginSuccessOrFailurePage)
except Exception, e:
- _moduleLogger.exception(str(e))
- return False
+ # Retry in case the redirect failed
+ # luckily is_authed does everything we need for a retry
+ loggedIn = self.is_authed(True)
+ if not loggedIn:
+ _moduleLogger.exception(str(e))
+ return False
+ _moduleLogger.info("Redirection failed on initial login attempt, auto-corrected for this")
self._browser.cookies.save()
self._lastAuthed = time.time()
return {}
return self._callbackNumbers
- _setforwardURL = "https://www.google.com//voice/m/setphone"
-
def set_callback_number(self, callbacknumber):
"""
Set the number that GoogleVoice calls
_voicemailURL = "https://www.google.com/voice/inbox/recent/voicemail/"
_smsURL = "https://www.google.com/voice/inbox/recent/sms/"
+ @staticmethod
+ def _merge_messages(parsedMessages, json):
+ for message in parsedMessages:
+ id = message["id"]
+ jsonItem = json["messages"][id]
+ message["isRead"] = jsonItem["isRead"]
+ message["isSpam"] = jsonItem["isSpam"]
+ message["isTrash"] = jsonItem["isTrash"]
+ yield message
+
def get_messages(self):
try:
voicemailPage = self._browser.download(self._voicemailURL)
_moduleLogger.exception("Translating error: %s" % str(e))
raise NetworkError("%s is not accesible" % self._voicemailURL)
voicemailHtml = self._grab_html(voicemailPage)
+ voicemailJson = self._grab_json(voicemailPage)
parsedVoicemail = self._parse_voicemail(voicemailHtml)
- decoratedVoicemails = self._decorate_voicemail(parsedVoicemail)
+ voicemails = self._merge_messages(parsedVoicemail, voicemailJson)
+ decoratedVoicemails = self._decorate_voicemail(voicemails)
try:
smsPage = self._browser.download(self._smsURL)
_moduleLogger.exception("Translating error: %s" % str(e))
raise NetworkError("%s is not accesible" % self._smsURL)
smsHtml = self._grab_html(smsPage)
+ smsJson = self._grab_json(smsPage)
parsedSms = self._parse_sms(smsHtml)
- decoratedSms = self._decorate_sms(parsedSms)
+ smss = self._merge_messages(parsedSms, smsJson)
+ decoratedSms = self._decorate_sms(smss)
allMessages = itertools.chain(decoratedVoicemails, decoratedSms)
return allMessages
_tokenRe = re.compile(r"""<input.*?name="_rnr_se".*?value="(.*?)"\s*/>""")
_accountNumRe = re.compile(r"""<b class="ms\d">(.{14})</b></div>""")
_callbackRe = re.compile(r"""\s+(.*?):\s*(.*?)<br\s*/>\s*$""", re.M)
- _forwardURL = "https://www.google.com/voice/mobile/phones"
def _grab_account_info(self, page):
tokenGroup = self._tokenRe.search(page)
"number": number,
"location": location,
"messageParts": messageParts,
+ "type": "Voicemail",
}
def _decorate_voicemail(self, parsedVoicemails):
"number": number,
"location": "",
"messageParts": messageParts,
+ "type": "Texts",
}
def _decorate_sms(self, parsedTexts):
print "Login?: ", backend.login(username, password)
print "Authenticated: ", backend.is_authed()
- #print "Token: ", backend._token
+ print "Token: ", backend._token
#print "Account: ", backend.get_account_number()
#print "Callback: ", backend.get_callback_number()
#print "All Callback: ",
return backend
+_TEST_WEBPAGES = [
+ ("forward", GVDialer._forwardURL),
+ ("token", GVDialer._tokenURL),
+ ("login", GVDialer._loginURL),
+ ("contacts", GVDialer._contactsURL),
+
+ ("voicemail", GVDialer._voicemailURL),
+ ("sms", GVDialer._smsURL),
+
+ ("recent", GVDialer._recentCallsURL),
+ ("placed", GVDialer._placedCallsURL),
+ ("recieved", GVDialer._receivedCallsURL),
+ ("missed", GVDialer._missedCallsURL),
+]
+
+
+def grab_debug_info(username, password):
+ cookieFile = os.path.join(".", "raw_cookies.txt")
+ try:
+ os.remove(cookieFile)
+ except OSError:
+ pass
+
+ backend = GVDialer(cookieFile)
+ browser = backend._browser
+
+ # Get Pages
+ print "Grabbing pre-login pages"
+ for name, url in _TEST_WEBPAGES:
+ try:
+ page = browser.download(url)
+ except StandardError, e:
+ print e.message
+ continue
+ print "\tWriting to file"
+ with open("not_loggedin_%s.txt" % name, "w") as f:
+ f.write(page)
+
+ # Login
+ print "Attempting login"
+ galxToken = backend._get_token()
+ loginSuccessOrFailurePage = backend._login(username, password, galxToken)
+ with open("loggingin.txt", "w") as f:
+ print "\tWriting to file"
+ f.write(loginSuccessOrFailurePage)
+ try:
+ backend._grab_account_info(loginSuccessOrFailurePage)
+ except Exception:
+ # Retry in case the redirect failed
+ # luckily is_authed does everything we need for a retry
+ loggedIn = backend.is_authed(True)
+ if not loggedIn:
+ raise
+
+ # Get Pages
+ print "Grabbing post-login pages"
+ for name, url in _TEST_WEBPAGES:
+ try:
+ page = browser.download(url)
+ except StandardError, e:
+ print e.message
+ continue
+ print "\tWriting to file"
+ with open("loggedin_%s.txt" % name, "w") as f:
+ f.write(page)
+
+ # Cookies
+ browser.cookies.save()
+ print "\tWriting cookies to file"
+ with open("cookies.txt", "w") as f:
+ f.writelines(
+ "%s: %s\n" % (c.name, c.value)
+ for c in browser.cookies
+ )
+
+
if __name__ == "__main__":
import sys
logging.basicConfig(level=logging.DEBUG)
- test_backend(sys.argv[1], sys.argv[2])
+ #test_backend(sys.argv[1], sys.argv[2])
+ grab_debug_info(sys.argv[1], sys.argv[2])