PROJECT_NAME=gc_dialer
PROJECT_VERSION=0.8.0
SOURCE_PATH=src
-SOURCE=$(SOURCE_PATH)/gc_dialer.py $(SOURCE_PATH)/gcbackend.py $(SOURCE_PATH)/browser_emu.py
+SOURCE=$(SOURCE_PATH)/gc_dialer.py $(SOURCE_PATH)/evo_backend.py $(SOURCE_PATH)/gc_backend.py $(SOURCE_PATH)/browser_emu.py
OBJ=$(SOURCE:.py=.pyc)
LINT_STATS_PATH=~/.pylint.d
LINT_STATS=$(foreach file, $(addsuffix 1.stats,$(subst /,.,$(basename $(SOURCE)))), $(LINT_STATS_PATH)/$(file) )
#Construct the program by cat-ing all the python files together
echo "#!/usr/bin/python" > $(BUILD_BIN)
#echo "from __future__ import with_statement" >> $(PRE_PACKAGE_PATH)/usr/local/bin/gc_dialer.py
- cat $(SOURCE_PATH)/gc_dialer.py $(SOURCE_PATH)/gcbackend.py $(SOURCE_PATH)/browser_emu.py | grep -e '^import ' | sort -u >> $(BUILD_BIN)
- cat $(SOURCE_PATH)/browser_emu.py $(SOURCE_PATH)/gcbackend.py $(SOURCE_PATH)/gc_dialer.py | grep -v 'browser_emu' | grep -v 'gcbackend' | grep -v "#!" >> $(BUILD_BIN)
+ cat $(SOURCE_PATH)/gc_dialer.py $(SOURCE_PATH)/evo_backend.py $(SOURCE_PATH)/gc_backend.py $(SOURCE_PATH)/browser_emu.py | grep -e '^import ' | sort -u >> $(BUILD_BIN)
+ cat $(SOURCE_PATH)/browser_emu.py $(SOURCE_PATH)/evo_backend.py $(SOURCE_PATH)/gc_backend.py $(SOURCE_PATH)/gc_dialer.py | grep -v 'browser_emu' | grep -v 'gc_backend' | grep -v "evo_backend"| grep -v "#!" >> $(BUILD_BIN)
chmod 755 $(BUILD_BIN)
$(TAG_FILE): $(SOURCE)
--- /dev/null
+#!/usr/bin/python
+
+# GC Dialer - 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.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+"""
+Evolution Contact Support
+"""
+
+
+try:
+ import evolution
+except ImportError:
+ evolution = None
+
+
+class EvolutionAddressBook(object):
+
+ def __init__(self, bookId = None):
+ if not self.is_supported():
+ return
+
+ self._phoneTypes = None
+ self._bookId = bookId if bookId is not None else self.get_addressbooks().next()[1]
+ self._book = evolution.ebook.open_addressbook(self._bookId[1])
+
+ @classmethod
+ def is_supported(cls):
+ return evolution is not None
+
+ def get_addressbooks(self):
+ """
+ @returns Iterable of (Address Book Factory, Book Id, Book Name)
+ """
+ if not self.is_supported():
+ return
+
+ for bookId in evolution.ebook.list_addressbooks():
+ yield self, bookId, bookId[0]
+
+ def open_addressbook(self, bookId):
+ self._bookId = bookId
+ self._book = evolution.ebook.open_addressbook(self._bookId[1])
+ return self
+
+ def get_contacts(self):
+ """
+ @returns Iterable of (contact id, contact name)
+ """
+ if not self.is_supported():
+ return
+
+ for contact in self._book.get_all_contacts():
+ yield contact.get_uid(), contact.props.full_name
+
+ def get_contact_details(self, contactId):
+ """
+ @returns Iterable of (Phone Type, Phone Number)
+ """
+ contact = self._book.get_contact(contactId)
+
+ if self._phoneTypes is None and contact is not None:
+ self._phoneTypes = [pt for pt in dir(contact.props) if "phone" in pt.lower()]
+
+ for phoneType in self._phoneTypes:
+ phoneNumber = getattr(contact.props, phoneType)
+ if isinstance(phoneNumber, str):
+ yield phoneType, phoneNumber
+
+def print_addressbooks():
+ """
+ Included here for debugging.
+
+ Either insert it into the code or launch python with the "-i" flag
+ """
+ if not EvolutionAddressBook.is_supported():
+ print "No Evolution Support"
+ return
+
+ eab = EvolutionAddressBook()
+ for book in eab.get_addressbooks():
+ eab = eab.open_addressbook(book[1])
+ print book
+ for contact in eab.get_contacts():
+ print "\t", contact
+ for details in eab.get_contact_details(contact[0]):
+ print "\t\t", details
--- /dev/null
+#!/usr/bin/python
+
+# GC Dialer - 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.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""
+Grandcentral Dialer backend code
+"""
+
+
+import os
+import re
+import urllib
+import urllib2
+import time
+import warnings
+
+from browser_emu import MozillaEmulator
+
+
+class GCDialer(object):
+ """
+ This class encapsulates all of the knowledge necessary to interace with the grandcentral servers
+ the functions include login, setting up a callback number, and initalting a callback
+ """
+
+ _gcDialingStrRe = re.compile("This may take a few seconds", re.M)
+ _accessTokenRe = re.compile(r"""<input type="hidden" name="a_t" [^>]*value="(.*)"/>""")
+ _isLoginPageRe = re.compile(r"""<form method="post" action="https://www.grandcentral.com/mobile/account/login">""")
+ _callbackRe = re.compile(r"""name="default_number" value="(\d+)" />\s+(.*)\s$""", re.M)
+ _accountNumRe = re.compile(r"""<img src="/images/mobile/inbox_logo.gif" alt="GrandCentral" />\s*(.{14})\s* """, re.M)
+ _inboxRe = re.compile(r"""<td>.*?(voicemail|received|missed|call return).*?</td>\s+<td>\s+<font size="2">\s+(.*?)\s+ \| \s+<a href="/mobile/contacts/.*?">(.*?)\s?</a>\s+<br/>\s+(.*?)\s?<a href=""", re.S)
+ _contactsRe = re.compile(r"""<a href="/mobile/contacts/detail/(\d+)">(.*?)</a>""", re.S)
+ _contactsNextRe = re.compile(r""".*<a href="/mobile/contacts(\?page=\d+)">Next</a>""", re.S)
+ _contactDetailGroupRe = re.compile(r"""Group:\s*(\w*)""", re.S)
+ _contactDetailPhoneRe = re.compile(r"""(\w+):[0-9\-\(\) \t]*?<a href="/mobile/calls/click_to_call\?destno=(\d+).*?">call</a>""", re.S)
+
+ _validateRe = re.compile("^[0-9]{10,}$")
+
+ _forwardselectURL = "http://www.grandcentral.com/mobile/settings/forwarding_select"
+ _loginURL = "https://www.grandcentral.com/mobile/account/login"
+ _setforwardURL = "http://www.grandcentral.com/mobile/settings/set_forwarding?from=settings"
+ _clicktocallURL = "http://www.grandcentral.com/mobile/calls/click_to_call?a_t=%s&destno=%s"
+ _inboxallURL = "http://www.grandcentral.com/mobile/messages/inbox?types=all"
+ _contactsURL = "http://www.grandcentral.com/mobile/contacts"
+ _contactDetailURL = "http://www.grandcentral.com/mobile/contacts/detail"
+
+ def __init__(self, cookieFile = None):
+ # Important items in this function are the setup of the browser emulation and cookie file
+ self._msg = ""
+
+ self._browser = MozillaEmulator(None, 0)
+ if cookieFile is None:
+ cookieFile = os.path.join(os.path.expanduser("~"), ".gc_dialer_cookies.txt")
+ self._browser.cookies.filename = cookieFile
+ if os.path.isfile(cookieFile):
+ self._browser.cookies.load()
+
+ self._accessToken = None
+ self._accountNum = None
+ self._callbackNumbers = {}
+ self._lastAuthed = 0.0
+
+ def is_authed(self, force = False):
+ """
+ Attempts to detect a current session and pull the auth token ( a_t ) from the page.
+ @note Once logged in try not to reauth more than once a minute.
+ @returns If authenticated
+ """
+
+ if time.time() - self._lastAuthed < 60 and not force:
+ return True
+
+ try:
+ forwardSelectionPage = self._browser.download(GCDialer._forwardselectURL)
+ except urllib2.URLError, e:
+ warnings.warn("%s is not accesible" % GCDialer._forwardselectURL, UserWarning, 2)
+ return False
+
+ self._browser.cookies.save()
+ if GCDialer._isLoginPageRe.search(forwardSelectionPage) is None:
+ self._grab_token(forwardSelectionPage)
+ self._lastAuthed = time.time()
+ return True
+
+ return False
+
+ def login(self, username, password):
+ """
+ Attempt to login to grandcentral
+ @returns Whether login was successful or not
+ """
+ if self.is_authed():
+ return True
+
+ loginPostData = urllib.urlencode( {'username' : username , 'password' : password } )
+
+ try:
+ loginSuccessOrFailurePage = self._browser.download(GCDialer._loginURL, loginPostData)
+ except urllib2.URLError, e:
+ warnings.warn("%s is not accesible" % GCDialer._loginURL, UserWarning, 2)
+ return False
+
+ return self.is_authed()
+
+ def logout(self):
+ self._lastAuthed = 0.0
+ self._browser.cookies.clear()
+ self._browser.cookies.save()
+
+ def dial(self, number):
+ """
+ This is the main function responsible for initating the callback
+ """
+ self._msg = ""
+
+ # If the number is not valid throw exception
+ if not self.is_valid_syntax(number):
+ raise ValueError('number is not valid')
+
+ # No point if we don't have the magic cookie
+ if not self.is_authed():
+ self._msg = "Not authenticated"
+ return False
+
+ # Strip leading 1 from 11 digit dialing
+ if len(number) == 11 and number[0] == 1:
+ number = number[1:]
+
+ try:
+ callSuccessPage = self._browser.download(
+ GCDialer._clicktocallURL % (self._accessToken, number),
+ None,
+ {'Referer' : 'http://www.grandcentral.com/mobile/messages'}
+ )
+ except urllib2.URLError, e:
+ warnings.warn("%s is not accesible" % GCDialer._clicktocallURL, UserWarning, 2)
+ return False
+
+ if GCDialer._gcDialingStrRe.search(callSuccessPage) is not None:
+ return True
+ else:
+ self._msg = "Grand Central returned an error"
+ return False
+
+ self._msg = "Unknown Error"
+ return False
+
+ def clear_caches(self):
+ pass
+
+ def is_valid_syntax(self, number):
+ """
+ @returns If This number be called ( syntax validation only )
+ """
+ return self._validateRe.match(number) is not None
+
+ def get_account_number(self):
+ """
+ @returns The grand central phone number
+ """
+ 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 not re.compile(r"""1747""").match(number) is 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:
+ self.set_callback_number(number)
+ return
+
+ for number, description in numbers.iteritems():
+ if not re.compile(r"""computer""", re.I).search(description) is 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
+ @note These results are cached for 30 minutes.
+ """
+ if time.time() - self._lastAuthed < 1800 or self.is_authed():
+ return self._callbackNumbers
+
+ return {}
+
+ def set_callback_number(self, callbacknumber):
+ """
+ Set the number that grandcental calls
+ @param callbacknumber should be a proper 10 digit number
+ """
+ callbackPostData = urllib.urlencode({
+ 'a_t': self._accessToken,
+ 'default_number': callbacknumber
+ })
+ try:
+ callbackSetPage = self._browser.download(GCDialer._setforwardURL, callbackPostData)
+ except urllib2.URLError, e:
+ warnings.warn("%s is not accesible" % GCDialer._setforwardURL, UserWarning, 2)
+ return False
+
+ self._browser.cookies.save()
+ return True
+
+ def get_callback_number(self):
+ """
+ @returns Current callback number or None
+ """
+ for c in self._browser.cookies:
+ if c.name == "pda_forwarding_number":
+ return c.value
+ return None
+
+ def get_recent(self):
+ """
+ @returns Iterable of (personsName, phoneNumber, date, action)
+ """
+ try:
+ recentCallsPage = self._browser.download(GCDialer._inboxallURL)
+ except urllib2.URLError, e:
+ warnings.warn("%s is not accesible" % GCDialer._inboxallURL, UserWarning, 2)
+ return
+
+ for match in self._inboxRe.finditer(recentCallsPage):
+ phoneNumber = match.group(4)
+ action = match.group(1)
+ date = match.group(2)
+ personsName = match.group(3)
+ yield personsName, phoneNumber, date, action
+
+ def get_addressbooks(self):
+ """
+ @returns Iterable of (Address Book Factory, Book Id, Book Name)
+ """
+ yield self, None, "Grand Central"
+
+ def open_addressbook(self, bookId):
+ return self
+
+ def get_contacts(self):
+ """
+ @returns Iterable of (contact id, contact name)
+ """
+ contactsPagesUrls = [GCDialer._contactsURL]
+ for contactsPageUrl in contactsPagesUrls:
+ contactsPage = self._browser.download(contactsPageUrl)
+ for contact_match in self._contactsRe.finditer(contactsPage):
+ contactId = contact_match.group(1)
+ contactName = contact_match.group(2)
+ yield contactId, contactName
+
+ next_match = self._contactsNextRe.match(contactsPage)
+ if next_match is not None:
+ newContactsPageUrl = self._contactsURL + next_match.group(1)
+ contactsPagesUrls.append(newContactsPageUrl)
+
+ def get_contact_details(self, contactId):
+ """
+ @returns Iterable of (Phone Type, Phone Number)
+ """
+ detailPage = self._browser.download(GCDialer._contactDetailURL + '/' + contactId)
+ for detail_match in self._contactDetailPhoneRe.finditer(detailPage):
+ phoneType = detail_match.group(1)
+ phoneNumber = detail_match.group(2)
+ yield (phoneType, phoneNumber)
+
+ def _grab_token(self, data):
+ "Pull the magic cookie from the datastream"
+ atGroup = GCDialer._accessTokenRe.search(data)
+ self._accessToken = atGroup.group(1)
+
+ anGroup = GCDialer._accountNumRe.search(data)
+ self._accountNum = anGroup.group(1)
+
+ self._callbackNumbers = {}
+ for match in GCDialer._callbackRe.finditer(data):
+ self._callbackNumbers[match.group(1)] = match.group(2)
doctest = None
optparse = None
-from gcbackend import GCDialer
+from gc_backend import GCDialer
+from evo_backend import EvolutionAddressBook
import socket
+++ /dev/null
-#!/usr/bin/python
-
-# GC Dialer - 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.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-"""
-Grandcentral Dialer backend code
-"""
-
-
-import os
-import re
-import urllib
-import urllib2
-import time
-import warnings
-
-from browser_emu import MozillaEmulator
-
-
-class GCDialer(object):
- """
- This class encapsulates all of the knowledge necessary to interace with the grandcentral servers
- the functions include login, setting up a callback number, and initalting a callback
- """
-
- _gcDialingStrRe = re.compile("This may take a few seconds", re.M)
- _accessTokenRe = re.compile(r"""<input type="hidden" name="a_t" [^>]*value="(.*)"/>""")
- _isLoginPageRe = re.compile(r"""<form method="post" action="https://www.grandcentral.com/mobile/account/login">""")
- _callbackRe = re.compile(r"""name="default_number" value="(\d+)" />\s+(.*)\s$""", re.M)
- _accountNumRe = re.compile(r"""<img src="/images/mobile/inbox_logo.gif" alt="GrandCentral" />\s*(.{14})\s* """, re.M)
- _inboxRe = re.compile(r"""<td>.*?(voicemail|received|missed|call return).*?</td>\s+<td>\s+<font size="2">\s+(.*?)\s+ \| \s+<a href="/mobile/contacts/.*?">(.*?)\s?</a>\s+<br/>\s+(.*?)\s?<a href=""", re.S)
- _contactsRe = re.compile(r"""<a href="/mobile/contacts/detail/(\d+)">(.*?)</a>""", re.S)
- _contactsNextRe = re.compile(r""".*<a href="/mobile/contacts(\?page=\d+)">Next</a>""", re.S)
- _contactDetailGroupRe = re.compile(r"""Group:\s*(\w*)""", re.S)
- _contactDetailPhoneRe = re.compile(r"""(\w+):[0-9\-\(\) \t]*?<a href="/mobile/calls/click_to_call\?destno=(\d+).*?">call</a>""", re.S)
-
- _validateRe = re.compile("^[0-9]{10,}$")
-
- _forwardselectURL = "http://www.grandcentral.com/mobile/settings/forwarding_select"
- _loginURL = "https://www.grandcentral.com/mobile/account/login"
- _setforwardURL = "http://www.grandcentral.com/mobile/settings/set_forwarding?from=settings"
- _clicktocallURL = "http://www.grandcentral.com/mobile/calls/click_to_call?a_t=%s&destno=%s"
- _inboxallURL = "http://www.grandcentral.com/mobile/messages/inbox?types=all"
- _contactsURL = "http://www.grandcentral.com/mobile/contacts"
- _contactDetailURL = "http://www.grandcentral.com/mobile/contacts/detail"
-
- def __init__(self, cookieFile = None):
- # Important items in this function are the setup of the browser emulation and cookie file
- self._msg = ""
-
- self._browser = MozillaEmulator(None, 0)
- if cookieFile is None:
- cookieFile = os.path.join(os.path.expanduser("~"), ".gc_dialer_cookies.txt")
- self._browser.cookies.filename = cookieFile
- if os.path.isfile(cookieFile):
- self._browser.cookies.load()
-
- self._accessToken = None
- self._accountNum = None
- self._callbackNumbers = {}
- self._lastAuthed = 0.0
-
- def is_authed(self, force = False):
- """
- Attempts to detect a current session and pull the auth token ( a_t ) from the page.
- @note Once logged in try not to reauth more than once a minute.
- @returns If authenticated
- """
-
- if time.time() - self._lastAuthed < 60 and not force:
- return True
-
- try:
- forwardSelectionPage = self._browser.download(GCDialer._forwardselectURL)
- except urllib2.URLError, e:
- warnings.warn("%s is not accesible" % GCDialer._forwardselectURL, UserWarning, 2)
- return False
-
- self._browser.cookies.save()
- if GCDialer._isLoginPageRe.search(forwardSelectionPage) is None:
- self._grab_token(forwardSelectionPage)
- self._lastAuthed = time.time()
- return True
-
- return False
-
- def login(self, username, password):
- """
- Attempt to login to grandcentral
- @returns Whether login was successful or not
- """
- if self.is_authed():
- return True
-
- loginPostData = urllib.urlencode( {'username' : username , 'password' : password } )
-
- try:
- loginSuccessOrFailurePage = self._browser.download(GCDialer._loginURL, loginPostData)
- except urllib2.URLError, e:
- warnings.warn("%s is not accesible" % GCDialer._loginURL, UserWarning, 2)
- return False
-
- return self.is_authed()
-
- def logout(self):
- self._lastAuthed = 0.0
- self._browser.cookies.clear()
- self._browser.cookies.save()
-
- def dial(self, number):
- """
- This is the main function responsible for initating the callback
- """
- self._msg = ""
-
- # If the number is not valid throw exception
- if not self.is_valid_syntax(number):
- raise ValueError('number is not valid')
-
- # No point if we don't have the magic cookie
- if not self.is_authed():
- self._msg = "Not authenticated"
- return False
-
- # Strip leading 1 from 11 digit dialing
- if len(number) == 11 and number[0] == 1:
- number = number[1:]
-
- try:
- callSuccessPage = self._browser.download(
- GCDialer._clicktocallURL % (self._accessToken, number),
- None,
- {'Referer' : 'http://www.grandcentral.com/mobile/messages'}
- )
- except urllib2.URLError, e:
- warnings.warn("%s is not accesible" % GCDialer._clicktocallURL, UserWarning, 2)
- return False
-
- if GCDialer._gcDialingStrRe.search(callSuccessPage) is not None:
- return True
- else:
- self._msg = "Grand Central returned an error"
- return False
-
- self._msg = "Unknown Error"
- return False
-
- def clear_caches(self):
- pass
-
- def is_valid_syntax(self, number):
- """
- @returns If This number be called ( syntax validation only )
- """
- return self._validateRe.match(number) is not None
-
- def get_account_number(self):
- """
- @returns The grand central phone number
- """
- 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 not re.compile(r"""1747""").match(number) is 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:
- self.set_callback_number(number)
- return
-
- for number, description in numbers.iteritems():
- if not re.compile(r"""computer""", re.I).search(description) is 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
- @note These results are cached for 30 minutes.
- """
- if time.time() - self._lastAuthed < 1800 or self.is_authed():
- return self._callbackNumbers
-
- return {}
-
- def set_callback_number(self, callbacknumber):
- """
- Set the number that grandcental calls
- @param callbacknumber should be a proper 10 digit number
- """
- callbackPostData = urllib.urlencode({
- 'a_t': self._accessToken,
- 'default_number': callbacknumber
- })
- try:
- callbackSetPage = self._browser.download(GCDialer._setforwardURL, callbackPostData)
- except urllib2.URLError, e:
- warnings.warn("%s is not accesible" % GCDialer._setforwardURL, UserWarning, 2)
- return False
-
- self._browser.cookies.save()
- return True
-
- def get_callback_number(self):
- """
- @returns Current callback number or None
- """
- for c in self._browser.cookies:
- if c.name == "pda_forwarding_number":
- return c.value
- return None
-
- def get_recent(self):
- """
- @returns Iterable of (personsName, phoneNumber, date, action)
- """
- try:
- recentCallsPage = self._browser.download(GCDialer._inboxallURL)
- except urllib2.URLError, e:
- warnings.warn("%s is not accesible" % GCDialer._inboxallURL, UserWarning, 2)
- return
-
- for match in self._inboxRe.finditer(recentCallsPage):
- phoneNumber = match.group(4)
- action = match.group(1)
- date = match.group(2)
- personsName = match.group(3)
- yield personsName, phoneNumber, date, action
-
- def get_contacts(self):
- """
- @returns Iterable of (contact id, contact name)
- """
- contactsPagesUrls = [GCDialer._contactsURL]
- for contactsPageUrl in contactsPagesUrls:
- contactsPage = self._browser.download(contactsPageUrl)
- for contact_match in self._contactsRe.finditer(contactsPage):
- contactId = contact_match.group(1)
- contactName = contact_match.group(2)
- yield contactId, contactName
-
- next_match = self._contactsNextRe.match(contactsPage)
- if next_match is not None:
- newContactsPageUrl = self._contactsURL + next_match.group(1)
- contactsPagesUrls.append(newContactsPageUrl)
-
- def get_contact_details(self, contactId):
- """
- @returns Iterable of (Phone Type, Phone Number)
- """
- detailPage = self._browser.download(GCDialer._contactDetailURL + '/' + contactId)
- for detail_match in self._contactDetailPhoneRe.finditer(detailPage):
- phoneType = detail_match.group(1)
- phoneNumber = detail_match.group(2)
- yield (phoneType, phoneNumber)
-
- def _grab_token(self, data):
- "Pull the magic cookie from the datastream"
- atGroup = GCDialer._accessTokenRe.search(data)
- self._accessToken = atGroup.group(1)
-
- anGroup = GCDialer._accountNumRe.search(data)
- self._accountNum = anGroup.group(1)
-
- self._callbackNumbers = {}
- for match in GCDialer._callbackRe.finditer(data):
- self._callbackNumbers[match.group(1)] = match.group(2)