First step towards displaying of voicemail message
authorepage <eopage@byu.net>
Wed, 20 May 2009 02:44:47 +0000 (02:44 +0000)
committerepage <eopage@byu.net>
Wed, 20 May 2009 02:44:47 +0000 (02:44 +0000)
git-svn-id: file:///svnroot/gc-dialer/trunk@294 c39d3808-3fe2-4d86-a59f-b7f623ee9f21

src/dialcentral.glade
src/gc_views.py
src/gv_backend.py

index 17cd93c..5f260f9 100644 (file)
@@ -904,6 +904,7 @@ Number:</property>
           <widget class="GtkLabel" id="phoneSelectionMessage">
             <property name="visible">True</property>
             <property name="use_markup">True</property>
+            <property name="wrap">True</property>
           </widget>
           <packing>
             <property name="expand">False</property>
@@ -993,8 +994,11 @@ Number:</property>
   </widget>
   <widget class="GtkDialog" id="smsDialog">
     <property name="border_width">5</property>
+    <property name="title" translatable="yes">Send SMS</property>
     <property name="modal">True</property>
     <property name="window_position">center</property>
+    <property name="default_width">800</property>
+    <property name="default_height">300</property>
     <property name="type_hint">normal</property>
     <property name="skip_taskbar_hint">True</property>
     <property name="skip_pager_hint">True</property>
@@ -1012,6 +1016,7 @@ Number:</property>
               <widget class="GtkLabel" id="smsMessage">
                 <property name="visible">True</property>
                 <property name="use_markup">True</property>
+                <property name="wrap">True</property>
               </widget>
               <packing>
                 <property name="expand">False</property>
index b751451..3a6b3da 100644 (file)
@@ -354,12 +354,16 @@ class PhoneTypeSelector(object):
                self._typemodel.clear()
 
                for phoneType, phoneNumber in contactDetails:
+                       # @bug this isn't populating correctly for recent and messages but it is for contacts
+                       print repr(phoneNumber), repr(phoneType)
                        self._typemodel.append((phoneNumber, "%s - %s" % (make_pretty(phoneNumber), phoneType)))
 
+               # @todo Need to decide how how to handle the single phone number case
                if message:
+                       self._message.set_markup(message)
                        self._message.show()
-                       self._message.set_text(message)
                else:
+                       self._message.set_markup("")
                        self._message.hide()
 
                userResponse = self._dialog.run()
@@ -388,7 +392,7 @@ class PhoneTypeSelector(object):
        def _on_phonetype_send_sms(self, *args):
                self._dialog.response(gtk.RESPONSE_CANCEL)
                idly_run = gtk_toolbox.asynchronous_gtk_message(self._smsDialog.run)
-               idly_run(self._get_number(), self._message.get_text())
+               idly_run(self._get_number(), self._message.get_label())
 
        def _on_phonetype_select(self, *args):
                self._dialog.response(gtk.RESPONSE_OK)
@@ -419,9 +423,10 @@ class SmsEntryDialog(object):
 
        def run(self, number, message = ""):
                if message:
+                       self._message.set_markup(message)
                        self._message.show()
-                       self._message.set_text(message)
                else:
+                       self._message.set_markup("")
                        self._message.hide()
                self._smsEntry.get_buffer().set_text("")
                self._update_letter_count()
@@ -613,6 +618,7 @@ class RecentCallsView(object):
                self._onRecentviewRowActivatedId = 0
 
                textrenderer = gtk.CellRendererText()
+               # @todo Make seperate columns for each item in recent item payload
                self._recentviewColumn = gtk.TreeViewColumn("Calls")
                self._recentviewColumn.pack_start(textrenderer, expand=True)
                self._recentviewColumn.add_attribute(textrenderer, "text", 1)
@@ -676,9 +682,11 @@ class RecentCallsView(object):
                if not itr:
                        return
 
-               contactPhoneNumbers = [("Phone", self._recentmodel.get_value(itr, 0))]
+               number = self._recentmodel.get_value(itr, 0)
+               number = make_ugly(number)
+               contactPhoneNumbers = [("Phone", number)]
                description = self._recentmodel.get_value(itr, 1)
-               print repr(contactPhoneNumbers), repr(description)
+               print "Activated Recent Row:", repr(contactPhoneNumbers), repr(description)
 
                phoneNumber = self._phoneTypeSelector.run(contactPhoneNumbers, message = description)
                if 0 == len(phoneNumber):
@@ -701,9 +709,10 @@ class MessagesView(object):
                self._onMessageviewRowActivatedId = 0
 
                textrenderer = gtk.CellRendererText()
+               # @todo Make seperate columns for each item in message payload
                self._messageviewColumn = gtk.TreeViewColumn("Messages")
                self._messageviewColumn.pack_start(textrenderer, expand=True)
-               self._messageviewColumn.add_attribute(textrenderer, "text", 1)
+               self._messageviewColumn.add_attribute(textrenderer, "markup", 1)
                self._messageviewColumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
 
                self._phoneTypeSelector = PhoneTypeSelector(widgetTree, self._backend)
@@ -751,8 +760,10 @@ class MessagesView(object):
                        self._messagetime = 0.0
                        messageItems = []
 
-               for phoneNumber, data in messageItems:
-                       item = (phoneNumber, data)
+               for header, number, relativeDate, message in messageItems:
+                       number = make_ugly(number)
+                       print "Discarding", header, relativeDate
+                       item = (number, message)
                        with gtk_toolbox.gtk_lock():
                                self._messagemodel.append(item)
 
index b354de9..75ec4bd 100644 (file)
@@ -32,6 +32,7 @@ import urllib
 import urllib2
 import time
 import datetime
+import itertools
 import warnings
 import traceback
 from xml.sax import saxutils
@@ -64,6 +65,39 @@ else:
                return simplejson.loads(flattened)
 
 
+def itergroup(iterator, count, padValue = None):
+       """
+       Iterate in groups of 'count' values. If there
+       aren't enough values, the last result is padded with
+       None.
+
+       >>> for val in itergroup([1, 2, 3, 4, 5, 6], 3):
+       ...     print tuple(val)
+       (1, 2, 3)
+       (4, 5, 6)
+       >>> for val in itergroup([1, 2, 3, 4, 5, 6], 3):
+       ...     print list(val)
+       [1, 2, 3]
+       [4, 5, 6]
+       >>> for val in itergroup([1, 2, 3, 4, 5, 6, 7], 3):
+       ...     print tuple(val)
+       (1, 2, 3)
+       (4, 5, 6)
+       (7, None, None)
+       >>> for val in itergroup("123456", 3):
+       ...     print tuple(val)
+       ('1', '2', '3')
+       ('4', '5', '6')
+       >>> for val in itergroup("123456", 3):
+       ...     print repr("".join(val))
+       '123'
+       '456'
+       """
+       paddedIterator = itertools.chain(iterator, itertools.repeat(padValue, count-1))
+       nIterators = (paddedIterator, ) * count
+       return itertools.izip(*nIterators)
+
+
 class GVDialer(object):
        """
        This class encapsulates all of the knowledge necessary to interace with the grandcentral servers
@@ -97,6 +131,14 @@ class GVDialer(object):
        _voicemailURL = "https://www.google.com/voice/inbox/recent/voicemail/"
        _smsURL = "https://www.google.com/voice/inbox/recent/sms/"
 
+       _seperateVoicemailsRegex = re.compile(r"""^\s*<div id="(\w+)"\s* class="gc-message.*?">""", re.MULTILINE | re.DOTALL)
+       _exactVoicemailTimeRegex = re.compile(r"""<span class="gc-message-time">(.*?)</span>""", re.MULTILINE)
+       _relativeVoicemailTimeRegex = re.compile(r"""<span class="gc-message-relative">(.*?)</span>""", re.MULTILINE)
+       _voicemailNumberRegex = re.compile(r"""<input type="hidden" class="gc-text gc-quickcall-ac" value="(.*?)"/>""", re.MULTILINE)
+       _prettyVoicemailNumberRegex = re.compile(r"""<span class="gc-message-type">(.*?)</span>""", re.MULTILINE)
+       _voicemailLocationRegex = re.compile(r"""<span class="gc-message-location">(.*?)</span>""", re.MULTILINE)
+       _voicemailMessageRegex = re.compile(r"""<span class="gc-word-(.*?)">(.*?)</span>""", re.MULTILINE)
+
        def __init__(self, cookieFile = None):
                # Important items in this function are the setup of the browser emulation and cookie file
                self._browser = browser_emu.MozillaEmulator(1)
@@ -382,15 +424,16 @@ class GVDialer(object):
                        raise RuntimeError("%s is not accesible" % self._smsURL)
 
                voicemailHtml = self._grab_html(voicemailPage)
-               smsHtml = self._grab_html(smsPage)
+               parsedVoicemail = self._parse_voicemail(voicemailHtml)
+               decoratedVoicemails = self._decorated_voicemail(parsedVoicemail)
 
-               print "="*60
-               print voicemailHtml
-               print "-"*60
-               print smsHtml
-               print "="*60
+               # @todo Parse this
+               # smsHtml = self._grab_html(smsPage)
 
-               return ()
+               allMessages = itertools.chain(decoratedVoicemails)
+               sortedMessages = list(allMessages)
+               for exactDate, header, number, relativeDate, message in sortedMessages:
+                       yield header, number, relativeDate, message
 
        def _grab_json(self, flatXml):
                xmlTree = ElementTree.fromstring(flatXml)
@@ -467,6 +510,51 @@ class GVDialer(object):
                                action = saxutils.unescape(action)
                                yield "", number, exactDate, relativeDate, action
 
+       def _parse_voicemail(self, voicemailHtml):
+               splitVoicemail = self._seperateVoicemailsRegex.split(voicemailHtml)
+               for id, messageHtml in itergroup(splitVoicemail[1:], 2):
+                       exactTimeGroup = self._exactVoicemailTimeRegex.search(messageHtml)
+                       exactTime = exactTimeGroup.group(1) if exactTimeGroup else ""
+                       relativeTimeGroup = self._relativeVoicemailTimeRegex.search(messageHtml)
+                       relativeTime = relativeTimeGroup.group(1) if relativeTimeGroup else ""
+                       locationGroup = self._voicemailLocationRegex.search(messageHtml)
+                       location = locationGroup.group(1) if locationGroup else ""
+                       numberGroup = self._voicemailNumberRegex.search(messageHtml)
+                       number = numberGroup.group(1) if numberGroup else ""
+                       prettyNumberGroup = self._prettyVoicemailNumberRegex.search(messageHtml)
+                       prettyNumber = prettyNumberGroup.group(1) if prettyNumberGroup else ""
+                       messageGroups = self._voicemailMessageRegex.finditer(messageHtml)
+                       messageParts = (
+                               (group.group(1), group.group(2))
+                               for group in messageGroups
+                       ) if messageGroups else ()
+                       yield {
+                               "id": id,
+                               "time": exactTime,
+                               "relTime": relativeTime,
+                               "prettyNumber": prettyNumber,
+                               "number": number,
+                               "location": location,
+                               "messageParts": messageParts,
+                       }
+
+       def _decorated_voicemail(self, parsedVoicemail):
+               messagePartFormat = {
+                       "med1": "<i>%s</i>",
+                       "med2": "%s",
+                       "high": "<b>%s</b>",
+               }
+               for voicemailData in parsedVoicemail:
+                       exactTime = voicemailData["time"] # @todo Parse This
+                       header = "%s %s" % (voicemailData["prettyNumber"], voicemailData["location"])
+                       message = " ".join((
+                               messagePartFormat[quality] % part
+                               for (quality, part) in voicemailData["messageParts"]
+                       )).strip()
+                       if not message:
+                               message = "No Transcription"
+                       yield exactTime, header, voicemailData["number"], voicemailData["relTime"], message
+
 
 def test_backend(username, password):
        import pprint
@@ -477,8 +565,8 @@ 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 "All Callback: ",
+       # pprint.pprint(backend.get_callback_numbers())
        # print "Recent: ",
        # pprint.pprint(list(backend.get_recent()))
        # print "Contacts: ",