Tunneling account data out to the session to allow for optimizations
authorEd Page <eopage@byu.net>
Sat, 26 Feb 2011 23:10:22 +0000 (17:10 -0600)
committerEd Page <eopage@byu.net>
Tue, 19 Apr 2011 23:49:22 +0000 (18:49 -0500)
src/alarm_notify.py
src/backends/gv_backend.py
src/backends/gvoice/gvoice.py
src/session.py

index 5810710..9f7e690 100755 (executable)
@@ -92,7 +92,7 @@ def create_backend(config):
        loggedIn = False
 
        if not loggedIn:
-               loggedIn = backend.is_authed()
+               loggedIn = backend.refresh_account_info() is not None
 
        if not loggedIn:
                import base64
@@ -106,7 +106,7 @@ def create_backend(config):
                                for blob in blobs
                        )
                        username, password = tuple(creds)
-                       loggedIn = backend.login(username, password)
+                       loggedIn = backend.login(username, password) is not None
                except ConfigParser.NoOptionError, e:
                        pass
                except ConfigParser.NoSectionError, e:
index cf7fd6a..f2a3ec2 100644 (file)
@@ -45,17 +45,12 @@ class GVDialer(object):
 
        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):
                """
index 3cfd53f..021a03c 100755 (executable)
@@ -170,7 +170,6 @@ class GVoiceBackend(object):
 
                SECURE_URL_BASE = "https://www.google.com/voice/"
                SECURE_MOBILE_URL_BASE = SECURE_URL_BASE + "mobile/"
-               self._forwardURL = SECURE_MOBILE_URL_BASE + "phones"
                self._tokenURL = SECURE_URL_BASE + "m"
                self._callUrl = SECURE_URL_BASE + "call/connect"
                self._callCancelURL = SECURE_URL_BASE + "call/cancel"
@@ -211,9 +210,6 @@ class GVoiceBackend(object):
                self._XML_MISSED_URL = SECURE_URL_BASE + "inbox/recent/missed/"
 
                self._galxRe = re.compile(r"""<input.*?name="GALX".*?value="(.*?)".*?/>""", re.MULTILINE | re.DOTALL)
-               self._tokenRe = re.compile(r"""<input.*?name="_rnr_se".*?value="(.*?)"\s*/>""")
-               self._accountNumRe = re.compile(r"""<b class="ms\d">(.{14})</b></div>""")
-               self._callbackRe = re.compile(r"""\s+(.*?):\s*(.*?)<br\s*/>\s*$""", re.M)
 
                self._seperateVoicemailsRegex = re.compile(r"""^\s*<div id="(\w+)"\s* class=".*?gc-message.*?">""", re.MULTILINE | re.DOTALL)
                self._exactVoicemailTimeRegex = re.compile(r"""<span class="gc-message-time">(.*?)</span>""", re.MULTILINE)
@@ -230,32 +226,21 @@ class GVoiceBackend(object):
 
        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._loadedFromCookies or 0.0 < self._lastAuthed
 
-       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
-               @blocks
-               """
-               isRecentledAuthed = (time.time() - self._lastAuthed) < 120
-               isPreviouslyAuthed = self._token is not None
-               if isRecentledAuthed and isPreviouslyAuthed and not force:
-                       return True
-
+       def refresh_account_info(self):
                try:
-                       page = self._get_page(self._forwardURL)
-                       self._grab_account_info(page)
+                       page = self._get_page(self._JSON_CONTACTS_URL)
+                       accountData = self._grab_account_info(page)
                except Exception, e:
                        _moduleLogger.exception(str(e))
-                       return False
+                       return None
 
                self._browser.save_cookies()
                self._lastAuthed = time.time()
-               return True
+               return accountData
 
        def _get_token(self):
                tokenPage = self._get_page(self._tokenURL)
@@ -277,7 +262,7 @@ class GVoiceBackend(object):
                        "btmpl": "mobile",
                        "PersistentCookie": "yes",
                        "GALX": token,
-                       "continue": self._forwardURL,
+                       "continue": self._JSON_CONTACTS_URL,
                }
 
                loginSuccessOrFailurePage = self._get_page(self._loginURL, loginData)
@@ -294,19 +279,19 @@ class GVoiceBackend(object):
                loginSuccessOrFailurePage = self._login(username, password, galxToken)
 
                try:
-                       self._grab_account_info(loginSuccessOrFailurePage)
+                       accountData = self._grab_account_info(loginSuccessOrFailurePage)
                except Exception, e:
                        # Retry in case the redirect failed
-                       # luckily is_authed does everything we need for a retry
-                       loggedIn = self.is_authed(True)
-                       if not loggedIn:
+                       # luckily refresh_account_info does everything we need for a retry
+                       accountData = self.refresh_account_info()
+                       if accountData is None:
                                _moduleLogger.exception(str(e))
-                               return False
+                               return None
                        _moduleLogger.info("Redirection failed on initial login attempt, auto-corrected for this")
 
                self._browser.save_cookies()
                self._lastAuthed = time.time()
-               return True
+               return accountData
 
        def persist(self):
                self._browser.save_cookies()
@@ -578,30 +563,18 @@ class GVoiceBackend(object):
                return flatHtml
 
        def _grab_account_info(self, page):
-               tokenGroup = self._tokenRe.search(page)
-               if tokenGroup is None:
-                       raise RuntimeError("Could not extract authentication token from GoogleVoice")
-               self._token = tokenGroup.group(1)
-
-               anGroup = self._accountNumRe.search(page)
-               if anGroup is not None:
-                       self._accountNum = anGroup.group(1)
-               else:
-                       _moduleLogger.debug("Could not extract account number from GoogleVoice")
-
-               self._callbackNumbers = {}
-               for match in self._callbackRe.finditer(page):
-                       callbackNumber = match.group(2)
-                       callbackName = match.group(1)
-                       self._callbackNumbers[callbackNumber] = callbackName
+               accountData = parse_json(page)
+               self._token = accountData["r"]
+               self._accountNum = accountData["number"]["raw"]
+               for callback in accountData["phones"].itervalues():
+                       self._callbackNumbers[callback["phoneNumber"]] = callback["name"]
                if len(self._callbackNumbers) == 0:
                        _moduleLogger.debug("Could not extract callback numbers from GoogleVoice (the troublesome page follows):\n%s" % page)
+               return accountData
 
        def _send_validation(self, number):
                if not self.is_valid_syntax(number):
                        raise ValueError('Number is not valid: "%s"' % number)
-               elif not self.is_authed():
-                       raise RuntimeError("Not Authenticated")
                return number
 
        def _parse_recent(self, recentPages):
@@ -986,7 +959,6 @@ def grab_debug_info(username, password):
        browser = backend._browser
 
        _TEST_WEBPAGES = [
-               ("forward", backend._forwardURL),
                ("token", backend._tokenURL),
                ("login", backend._loginURL),
                ("isdnd", backend._isDndURL),
@@ -1029,8 +1001,8 @@ def grab_debug_info(username, password):
                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)
+               # luckily refresh_account_info does everything we need for a retry
+               loggedIn = backend.refresh_account_info() is not None
                if not loggedIn:
                        raise
 
index 8728b68..bd7914d 100644 (file)
@@ -395,15 +395,15 @@ class Session(QtCore.QObject):
                        self._loggedInTime = self._LOGGINGIN_TIME
                        self.stateChange.emit(self.LOGGINGIN_STATE)
                        finalState = self.LOGGEDOUT_STATE
-                       isLoggedIn = False
+                       accountData = None
                        try:
-                               if not isLoggedIn and self._backend[0].is_quick_login_possible():
-                                       isLoggedIn = yield (
-                                               self._backend[0].is_authed,
+                               if accountData is None and self._backend[0].is_quick_login_possible():
+                                       accountData = yield (
+                                               self._backend[0].refresh_account_info,
                                                (),
                                                {},
                                        )
-                                       if isLoggedIn:
+                                       if accountData is not None:
                                                _moduleLogger.info("Logged in through cookies")
                                        else:
                                                # Force a clearing of the cookies
@@ -413,16 +413,16 @@ class Session(QtCore.QObject):
                                                        {},
                                                )
 
-                               if not isLoggedIn:
-                                       isLoggedIn = yield (
+                               if accountData is None:
+                                       accountData = yield (
                                                self._backend[0].login,
                                                (username, password),
                                                {},
                                        )
-                                       if isLoggedIn:
+                                       if accountData is not None:
                                                _moduleLogger.info("Logged in through credentials")
 
-                               if isLoggedIn:
+                               if accountData is not None:
                                        self._loggedInTime = int(time.time())
                                        oldUsername = self._username
                                        self._username = username
@@ -454,7 +454,7 @@ class Session(QtCore.QObject):
                        finally:
                                if finalState is not None:
                                        self.stateChange.emit(finalState)
-                       if isLoggedIn and self._callback:
+                       if accountData is not None and self._callback:
                                self.set_callback_number(self._callback)
 
        def _load(self):