X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fgv_backend.py;h=0d05d41ab55901d9495050cd8d8af8a4180b5fb3;hb=e05a73034ce93f0ac08ed94b40ed67cb2181b9bb;hp=9d6d4fb5be03e4d00929153776dc995ace104a57;hpb=2b053a403ff9763a8dac9ff460af8e27e6fd7ffd;p=gc-dialer
diff --git a/src/gv_backend.py b/src/gv_backend.py
index 9d6d4fb..0d05d41 100644
--- a/src/gv_backend.py
+++ b/src/gv_backend.py
@@ -1,3 +1,15 @@
+#!/usr/bin/python
+
+# DialCentral - Front end for Google's Grand Central service.
+# Copyright (C) 2008 Eric Warnke ericew AT gmail DOT com
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
@@ -20,20 +32,17 @@ import urllib
import urllib2
import time
import warnings
+import traceback
from xml.etree import ElementTree
from browser_emu import MozillaEmulator
-import socket
-
try:
import simplejson
except ImportError:
simplejson = None
-socket.setdefaulttimeout(5)
-
_TRUE_REGEX = re.compile("true")
_FALSE_REGEX = re.compile("false")
@@ -50,7 +59,7 @@ if simplejson is None:
return safe_eval(flattened)
else:
def parse_json(flattened):
- return simplejson.loads(json)
+ return simplejson.loads(flattened)
class GVDialer(object):
@@ -59,11 +68,6 @@ class GVDialer(object):
the functions include login, setting up a callback number, and initalting a callback
"""
- _contactsRe = re.compile(r"""(.*?)""", re.S)
- _contactsNextRe = re.compile(r""".*Next""", re.S)
- _contactDetailGroupRe = re.compile(r"""Group:\s*(\w*)""", re.S)
- _contactDetailPhoneRe = re.compile(r"""(\w+):[0-9\-\(\) \t]*?call""", re.S)
-
_isNotLoginPageRe = re.compile(r"""I cannot access my account""")
_tokenRe = re.compile(r"""""")
_accountNumRe = re.compile(r"""(.{14})""")
@@ -71,13 +75,18 @@ class GVDialer(object):
_validateRe = re.compile("^[0-9]{10,}$")
_gvDialingStrRe = re.compile("This may take a few seconds", re.M)
- _clicktocallURL = "http://www.google.com/voice/m/sendcall"
- _contactsURL = "http://www.google.com/voice/m/contacts"
- _contactDetailURL = "http://www.google.com/voice/m/contact"
+ _contactsRe = re.compile(r"""(.*?)""", re.S)
+ _contactsNextRe = re.compile(r""".*Next.*?""", re.S)
+ _contactDetailPhoneRe = re.compile(r"""
([0-9\-\(\) \t]+?)\((\w+)\)""", re.S)
+
+ _clicktocallURL = "https://www.google.com/voice/m/sendcall"
+ _contactsURL = "https://www.google.com/voice/mobile/contacts"
+ _contactDetailURL = "https://www.google.com/voice/mobile/contact"
_loginURL = "https://www.google.com/accounts/ServiceLoginAuth"
+ _setforwardURL = "https://www.google.com//voice/m/setphone"
_accountNumberURL = "https://www.google.com/voice/mobile"
- _forwardURL = "https://www.google.com/voice/m/phones"
+ _forwardURL = "https://www.google.com/voice/mobile/phones"
_inboxURL = "https://www.google.com/voice/inbox/"
_recentCallsURL = "https://www.google.com/voice/inbox/recent/"
@@ -115,12 +124,14 @@ class GVDialer(object):
try:
inboxPage = self._browser.download(self._inboxURL)
except urllib2.URLError, e:
+ warnings.warn(traceback.format_exc())
raise RuntimeError("%s is not accesible" % self._inboxURL)
self._browser.cookies.save()
if self._isNotLoginPageRe.search(inboxPage) is not None:
return False
+ self._grab_account_info()
self._lastAuthed = time.time()
return True
@@ -129,8 +140,8 @@ class GVDialer(object):
Attempt to login to grandcentral
@returns Whether login was successful or not
"""
- #if self.is_authed():
- # return True
+ if self.is_authed():
+ return True
loginPostData = urllib.urlencode({
'Email' : username,
@@ -141,10 +152,9 @@ class GVDialer(object):
try:
loginSuccessOrFailurePage = self._browser.download(self._loginURL, loginPostData)
except urllib2.URLError, e:
+ warnings.warn(traceback.format_exc())
raise RuntimeError("%s is not accesible" % self._loginURL)
- #self._grab_account_info(loginSuccessOrFailurePage)
- self._grab_account_info()
return self.is_authed()
def logout(self):
@@ -172,17 +182,17 @@ class GVDialer(object):
"number": number,
"phone": self._callbackNumber,
"_rnr_se": self._token,
- "submit": "Call",
})
otherData = {
- 'Referer': 'https://www.google.com/voice/m/callsms',
+ 'Referer' : 'https://google.com/voice/m/callsms',
}
- callSuccessPage = self._browser.download(self._clicktocallURL, clickToCallData, otherData)
+ callSuccessPage = self._browser.download(self._clicktocallURL, clickToCallData, None, otherData)
except urllib2.URLError, e:
+ warnings.warn(traceback.format_exc())
raise RuntimeError("%s is not accesible" % self._clicktocallURL)
if self._gvDialingStrRe.search(callSuccessPage) is None:
- raise RuntimeError("Grand Central returned an error")
+ raise RuntimeError("Google Voice returned an error")
return True
@@ -212,17 +222,17 @@ class GVDialer(object):
numbers = self.get_callback_numbers()
for number, description in numbers.iteritems():
- if not re.compile(r"""1747""").match(number) is None:
+ if re.compile(r"""1747""").match(number) is not None:
self.set_callback_number(number)
return
for number, description in numbers.iteritems():
- if not re.compile(r"""gizmo""", re.I).search(description) is None:
+ 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 not re.compile(r"""computer""", re.I).search(description) is None:
+ if re.compile(r"""computer""", re.I).search(description) is not None:
self.set_callback_number(number)
return
@@ -246,6 +256,17 @@ class GVDialer(object):
@param callbacknumber should be a proper 10 digit number
"""
self._callbackNumber = callbacknumber
+ callbackPostData = urllib.urlencode({
+ '_rnr_se': self._token,
+ 'phone': callbacknumber
+ })
+ try:
+ callbackSetPage = self._browser.download(self._setforwardURL, callbackPostData)
+ except urllib2.URLError, e:
+ warnings.warn(traceback.format_exc())
+ raise RuntimeError("%s is not accesible" % self._setforwardURL)
+
+ self._browser.cookies.save()
return True
def get_callback_number(self):
@@ -266,6 +287,7 @@ class GVDialer(object):
try:
allRecentData = self._grab_json(url)
except urllib2.URLError, e:
+ warnings.warn(traceback.format_exc())
raise RuntimeError("%s is not accesible" % self._clicktocallURL)
for recentCallData in allRecentData["messages"].itervalues():
@@ -307,6 +329,7 @@ class GVDialer(object):
try:
contactsPage = self._browser.download(contactsPageUrl)
except urllib2.URLError, e:
+ warnings.warn(traceback.format_exc())
raise RuntimeError("%s is not accesible" % self._clicktocallURL)
for contact_match in self._contactsRe.finditer(contactsPage):
contactId = contact_match.group(1)
@@ -330,11 +353,12 @@ class GVDialer(object):
try:
detailPage = self._browser.download(self._contactDetailURL + '/' + contactId)
except urllib2.URLError, e:
+ warnings.warn(traceback.format_exc())
raise RuntimeError("%s is not accesible" % self._clicktocallURL)
for detail_match in self._contactDetailPhoneRe.finditer(detailPage):
- phoneType = detail_match.group(1)
- phoneNumber = detail_match.group(2)
+ phoneNumber = detail_match.group(1)
+ phoneType = detail_match.group(2)
yield (phoneType, phoneNumber)
def _grab_json(self, url):
@@ -345,22 +369,25 @@ class GVDialer(object):
jsonTree = parse_json(flatJson)
return jsonTree
- def _grab_account_info(self, loginPage = None):
- if loginPage is None:
+ def _grab_account_info(self, accountNumberPage = None):
+ if accountNumberPage is None:
accountNumberPage = self._browser.download(self._accountNumberURL)
- else:
- accountNumberPage = loginPage
+
tokenGroup = self._tokenRe.search(accountNumberPage)
- if tokenGroup is not None:
- self._token = tokenGroup.group(1)
+ if tokenGroup is None:
+ raise RuntimeError("Could not extract authentication token from GrandCentral")
+ self._token = tokenGroup.group(1)
+
anGroup = self._accountNumRe.search(accountNumberPage)
- if anGroup is not None:
- self._accountNum = anGroup.group(1)
+ if atGroup is None:
+ raise RuntimeError("Could not extract account number from GrandCentral")
+ self._accountNum = anGroup.group(1)
callbackPage = self._browser.download(self._forwardURL)
self._callbackNumbers = {}
for match in self._callbackRe.finditer(callbackPage):
self._callbackNumbers[match.group(2)] = match.group(1)
+
if len(self._callbackNumber) == 0:
self.set_sane_callback()
@@ -374,9 +401,13 @@ def test_backend(username, password):
print "Token: ", backend._token
print "Account: ", backend.get_account_number()
print "Callback: ", backend.get_callback_number()
- print "All Callback: ",
- pprint.pprint(backend.get_callback_numbers())
- print "Recent: ",
- pprint.pprint(list(backend.get_recent()))
+ # print "All Callback: ",
+ # pprint.pprint(backend.get_callback_numbers())
+ # print "Recent: ",
+ # pprint.pprint(list(backend.get_recent()))
+ # print "Contacts: ",
+ # for contact in backend.get_contacts():
+ # print contact
+ # pprint.pprint(list(backend.get_contact_details(contact[0])))
return backend