def __init__(self, connection, h):
AbstractListChannel.__init__(self, connection, h)
+ self._callback = coroutines.func_sink(
+ coroutines.expand_positional(
+ self._on_contacts_refreshed
+ )
+ )
self._session.addressbook.updateSignalHandler.register_sink(
- self._on_contacts_refreshed
+ self._callback
)
self.GroupFlagsChanged(0, 0)
telepathy.server.ChannelTypeContactList.Close(self)
self.remove_from_connection()
self._session.addressbook.updateSignalHandler.unregister_sink(
- self._on_contacts_refreshed
+ self._callback
)
- @coroutines.func_sink
- @coroutines.expand_positional
@gobject_utils.async
@gtk_toolbox.log_exception(_moduleLogger)
def _on_contacts_refreshed(self, addressbook, added, removed, changed):
self._otherHandle = h
+ self._callback = coroutines.func_sink(
+ coroutines.expand_positional(
+ self._on_conversations_updated
+ )
+ )
self._conn.session.conversations.updateSignalHandler.register_sink(
- self._on_conversations_updated
+ self._callback
)
# The only reason there should be anything in the conversation is if
self._conn.session.conversations.clear_conversation(self._contactKey)
self._conn.session.conversations.updateSignalHandler.unregister_sink(
- self._on_conversations_updated
+ self._callback
)
finally:
telepathy.server.ChannelTypeText.Close(self)
contactKey = self._otherHandle.contactID, self._otherHandle.phoneNumber
return contactKey
- @coroutines.func_sink
- @coroutines.expand_positional
@gobject_utils.async
@gtk_toolbox.log_exception(_moduleLogger)
- def _on_conversations_updated(self, conversationIds):
+ def _on_conversations_updated(self, conv, conversationIds):
if self._contactKey not in conversationIds:
return
_moduleLogger.info("Incoming messages from %r for existing conversation" % (self._contactKey, ))
self._report_new_message(formattedMessage)
def _filter_seen_messages(self, messages):
- return (
+ return [
message
for message in messages
if self._lastMessageTimestamp < message[0]
- )
+ ]
def _format_messages(self, messages):
return "\n".join(message[1] for message in messages)
timestamp = int(time.time())
type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL
- message = message.content
_moduleLogger.info("Received message from User %r" % self._otherHandle)
- self.Received(id, timestamp, self._otherHandle, type, 0, message)
+ self.Received(currentReceivedId, timestamp, self._otherHandle, type, 0, message)
self._nextRecievedId += 1
self.set_self_handle(handle.create_handle(self, 'connection'))
+ self._callback = coroutines.func_sink(
+ coroutines.expand_positional(
+ self._on_conversations_updated
+ )
+ )
_moduleLogger.info("Connection to the account %s created" % account)
except Exception, e:
_moduleLogger.exception("Failed to create Connection")
)
try:
self.session.conversations.updateSignalHandler.register_sink(
- self._on_conversations_updated
+ self._callback
)
self.session.login(*self._credentials)
self.session.backend.set_callback_number(self._callbackNumber)
_moduleLogger.info("Disconnecting")
try:
self.session.conversations.updateSignalHandler.unregister_sink(
- self._on_conversations_updated
+ self._callback
)
self._channelManager.close()
self.session.logout()
h = handle.create_handle(self, 'contact', requestedContactId, requestedContactNumber)
return h
- @coroutines.func_sink
- @coroutines.expand_positional
@gobject_utils.async
@gtk_toolbox.log_exception(_moduleLogger)
- def _on_conversations_updated(self, conversationIds):
+ def _on_conversations_updated(self, conv, conversationIds):
# @todo get conversations update running
# @todo test conversatiuons
_moduleLogger.info("Incoming messages from: %r" % (conversationIds, ))
channelManager = self._channelManager
for contactId, phoneNumber in conversationIds:
- h = self._create_contact_handle(contactId, phoneNumber)
+ h = handle.create_handle(self, 'contact', contactId, phoneNumber)
# if its new, __init__ will take care of things
# if its old, its own update will take care of it
- channel = channelManager.channel_for_text(handle)
+ channel = channelManager.channel_for_text(h)
if self._contacts:
return
contacts = self._backend.get_contacts()
- for contactId, contactName in contacts:
- self._contacts[contactId] = (contactName, [])
+ for contactId, contactDetails in contacts:
+ contactName = contactDetails["name"]
+ contactNumbers = [
+ (numberDetails.get("phoneType", "Mobile"), numberDetails["phoneNumber"])
+ for numberDetails in contactDetails["numbers"]
+ ]
+ self._contacts[contactId] = (contactName, contactNumbers)
def _populate_contact_details(self, contactId):
if self._get_contact_details(contactId):
self._downloadVoicemailURL = SECURE_URL_BASE + "media/send_voicemail/"
self._XML_SEARCH_URL = SECURE_URL_BASE + "inbox/search/"
- self._XML_ACCOUNT_URL = SECURE_URL_BASE + "inbox/contacts/"
+ self._XML_ACCOUNT_URL = SECURE_URL_BASE + "contacts/"
+ self._XML_CONTACTS_URL = "http://www.google.com/voice/inbox/search/contact"
self._XML_RECENT_URL = SECURE_URL_BASE + "inbox/recent/"
self.XML_FEEDS = (
self._XML_RECEIVED_URL = SECURE_URL_BASE + "inbox/recent/received/"
self._XML_MISSED_URL = SECURE_URL_BASE + "inbox/recent/missed/"
- self._contactsURL = SECURE_MOBILE_URL_BASE + "contacts"
- self._contactDetailURL = SECURE_MOBILE_URL_BASE + "contact"
-
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._contactsRe = re.compile(r"""<a href="/voice/m/contact/(\d+)">(.*?)</a>""", re.S)
- self._contactsNextRe = re.compile(r""".*<a href="/voice/m/contacts(\?p=\d+)">Next.*?</a>""", re.S)
- self._contactDetailPhoneRe = re.compile(r"""<div.*?>([0-9+\-\(\) \t]+?)<span.*?>\((\w+)\)</span>""", re.S)
-
+ self._contactsBodyRe = re.compile(r"""gcData\s*=\s*({.*?});""", re.MULTILINE | re.DOTALL)
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)
self._relativeVoicemailTimeRegex = re.compile(r"""<span class="gc-message-relative">(.*?)</span>""", re.MULTILINE)
"""
@returns Iterable of (contact id, contact name)
"""
- contactsPagesUrls = [self._contactsURL]
- for contactsPageUrl in contactsPagesUrls:
- contactsPage = self._get_page(contactsPageUrl)
- for contact_match in self._contactsRe.finditer(contactsPage):
- contactId = contact_match.group(1)
- contactName = saxutils.unescape(contact_match.group(2))
- contact = contactId, contactName
- yield contact
-
- 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._get_page(self._contactDetailURL + '/' + contactId)
-
- for detail_match in self._contactDetailPhoneRe.finditer(detailPage):
- phoneNumber = detail_match.group(1)
- phoneType = saxutils.unescape(detail_match.group(2))
- yield (phoneType, phoneNumber)
+ page = self._get_page(self._XML_CONTACTS_URL)
+ contactsBody = self._contactsBodyRe.search(page)
+ if contactsBody is None:
+ raise RuntimeError("Could not extract contact information")
+ accountData = _fake_parse_json(contactsBody.group(1))
+ for contactId, contactDetails in accountData["contacts"].iteritems():
+ yield contactId, contactDetails
def get_messages(self):
voicemailPage = self._get_page(self._XML_VOICEMAIL_URL)
if not backend.is_authed():
print "Login?: ", backend.login(username, password)
print "Authenticated: ", backend.is_authed()
- print "Is Dnd: ", backend.is_dnd()
+ #print "Is Dnd: ", backend.is_dnd()
#print "Setting Dnd", backend.set_dnd(True)
#print "Is Dnd: ", backend.is_dnd()
#print "Setting Dnd", backend.set_dnd(False)
#print "Account: ", backend.get_account_number()
#print "Callback: ", backend.get_callback_number()
#print "All Callback: ",
- #import pprint
+ import pprint
#pprint.pprint(backend.get_callback_numbers())
#print "Recent: "
# pprint.pprint(decorate_recent(data))
#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])))
+ print "Contacts: ",
+ for contact in backend.get_contacts():
+ pprint.pprint(contact)
#print "Messages: ",
#for message in backend.get_messages():
("token", backend._tokenURL),
("login", backend._loginURL),
("isdnd", backend._isDndURL),
- ("contacts", backend._contactsURL),
-
("account", backend._XML_ACCOUNT_URL),
+ ("contacts", backend._XML_CONTACTS_URL),
+
("voicemail", backend._XML_VOICEMAIL_URL),
("sms", backend._XML_SMS_URL),
try:
page = browser.download(url)
except StandardError, e:
- print e.message
+ print str(e)
continue
print "\tWriting to file"
with open("loggedin_%s.txt" % name, "w") as f:
f.write(page)
# Cookies
- browser.cookies.save()
+ browser.save_cookies()
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
+ for c in browser._cookies
)
return openerdirector
return self._read(openerdirector, trycount)
- except urllib2.URLError:
+ except urllib2.URLError, e:
+ _moduleLogger.info("%s: %s" % (e, url))
cnt += 1
if (-1 < trycount) and (trycount < cnt):
raise
# Retry :-)
- _moduleLogger.info("MozillaEmulator: urllib2.URLError, retryting %d" % cnt)
+ _moduleLogger.info("MozillaEmulator: urllib2.URLError, retrying %d" % cnt)
def _build_opener(self, url, postdata = None, extraheaders = None, forbidRedirect = False):
if extraheaders is None:
"""
import Queue
-import threading
import logging
import gobject
import util.algorithms as algorithms
+import util.go_utils as gobject_utils
import util.coroutines as coroutines
+import gtk_toolbox
_moduleLogger = logging.getLogger("gvoice.state_machine")
self._initItems = initItems
self._updateItems = updateItems
- self._actions = Queue.Queue()
self._state = self.STATE_ACTIVE
self._timeoutId = None
- self._thread = None
self._currentPeriod = self._INITIAL_ACTIVE_PERIOD
self._set_initial_period()
+ self._callback = coroutines.func_sink(
+ coroutines.expand_positional(
+ self._request_reset_timers
+ )
+ )
+
+ @gobject_utils.async
+ @gtk_toolbox.log_exception(_moduleLogger)
def start(self):
- assert self._thread is None
- self._thread = threading.Thread(target=self._run)
- self._thread.setDaemon(self._IS_DAEMON)
- self._thread.start()
+ _moduleLogger.info("Starting State Machine")
+ for item in self._initItems:
+ try:
+ item.update()
+ except Exception:
+ _moduleLogger.exception("Initial update failed for %r" % item)
+ self._schedule_update()
def stop(self):
- if self._thread is not None:
- self._actions.put(self._ACTION_STOP)
- self._thread = None
- else:
- _moduleLogger.info("Stopping an already stopped state machine")
+ _moduleLogger.info("Stopping an already stopped state machine")
+ self._stop_update()
def set_state(self, state):
self._state = state
return self._state
def reset_timers(self):
- self._actions.put(self._ACTION_RESET)
+ self._reset_timers()
- @coroutines.func_sink
- def request_reset_timers(self, args):
- self.reset_timers()
+ @property
+ def request_reset_timers(self):
+ return self._callback
- def _run(self):
- logging.basicConfig(level=logging.DEBUG)
- _moduleLogger.info("Starting State Machine")
- for item in self._initItems:
- try:
- item.update()
- except Exception:
- _moduleLogger.exception("Initial update failed for %r" % item)
-
- # empty the task queue
- actions = list(algorithms.itr_available(self._actions, initiallyBlock = False))
- self._schedule_update()
- if len(self._updateItems) == 0:
- self.stop()
-
- while True:
- # block till we get a task, or get all the tasks if we were late
- actions = list(algorithms.itr_available(self._actions, initiallyBlock = True))
-
- if self._ACTION_STOP in actions:
- _moduleLogger.info("Requested to stop")
- self._stop_update()
- break
- elif self._ACTION_RESET in actions:
- _moduleLogger.info("Reseting timers")
- self._reset_timers()
- elif self._ACTION_UPDATE in actions:
- _moduleLogger.info("Update")
- for item in self._updateItems:
- try:
- item.update(force=True)
- except Exception:
- _moduleLogger.exception("Update failed for %r" % item)
- self._schedule_update()
+ @gobject_utils.async
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _request_reset_timers(self, *args):
+ self.reset_timers()
def _set_initial_period(self):
self._currentPeriod = self._INITIAL_ACTIVE_PERIOD / 2 # We will double it later
- def _reset_timers(self):
- self._stop_update()
- self._set_initial_period()
- self._schedule_update()
-
def _schedule_update(self):
nextTimeout = self._calculate_step(self._state, self._currentPeriod)
nextTimeout = int(nextTimeout)
gobject.source_remove(self._timeoutId)
self._timeoutId = None
+ def _reset_timers(self):
+ self._stop_update()
+ self._set_initial_period()
+ self._schedule_update()
+
def _on_timeout(self):
- self._actions.put(self._ACTION_UPDATE)
+ _moduleLogger.info("Update")
+ for item in self._updateItems:
+ try:
+ item.update(force=True)
+ except Exception:
+ _moduleLogger.exception("Update failed for %r" % item)
+ self._schedule_update()
return False # do not continue
@classmethod
def get_contacts(self):
return (
- (i, contactData["name"])
+ (i, contactData)
for (i, contactData) in enumerate(self.contactsData)
)
- def get_contact_details(self, contactId):
- return self.contactsData[contactId]["details"]
-
def generate_update_callback(callbackData):
backend = MockBackend([
{
"name": "One",
- "details": [],
+ "numbers": [],
},
])
book = gvoice.addressbook.Addressbook(backend)
name = book.get_contact_name(id)
assert name == backend.contactsData[id]["name"]
- contactDetails = list(book.get_contact_details(id))
- assert len(contactDetails) == 0
-
def test_one_contact_with_details():
callbackData = []
backend = MockBackend([
{
"name": "One",
- "details": [("Type A", "123"), ("Type B", "456"), ("Type C", "789")],
+ "numbers": [
+ {"phoneType": "Type A", "phoneNumber": "123"},
+ {"phoneType": "Type B", "phoneNumber": "456"},
+ {"phoneType": "Type C", "phoneNumber": "789"}],
},
])
book = gvoice.addressbook.Addressbook(backend)
name = book.get_contact_name(id)
assert name == backend.contactsData[id]["name"]
- contactDetails = list(book.get_contact_details(id))
- print "%r" % contactDetails
- assert len(contactDetails) == 3
- assert contactDetails[0][0] == "Type A"
- assert contactDetails[0][1] == "123"
- assert contactDetails[1][0] == "Type B"
- assert contactDetails[1][1] == "456"
- assert contactDetails[2][0] == "Type C"
- assert contactDetails[2][1] == "789"
-
def test_adding_a_contact():
callbackData = []
backend = MockBackend([
{
"name": "One",
- "details": [],
+ "numbers": [],
},
])
book = gvoice.addressbook.Addressbook(backend)
backend.contactsData.append({
"name": "Two",
- "details": [],
+ "numbers": [],
})
book.update()
backend = MockBackend([
{
"name": "One",
- "details": [],
+ "numbers": [],
},
])
book = gvoice.addressbook.Addressbook(backend)