Fixing several showstopper bugs and starting work on displaying sms
authorepage <eopage@byu.net>
Thu, 21 May 2009 02:15:26 +0000 (02:15 +0000)
committerepage <eopage@byu.net>
Thu, 21 May 2009 02:15:26 +0000 (02:15 +0000)
git-svn-id: file:///svnroot/gc-dialer/trunk@296 c39d3808-3fe2-4d86-a59f-b7f623ee9f21

src/dc_glade.py
src/gc_views.py
src/gv_backend.py

index e9e8d29..e68429e 100755 (executable)
@@ -454,14 +454,50 @@ class Dialcentral(object):
                else:
                        self._window.set_title("%s - %s" % (self.__pretty_app_name__, tabTitle))
 
-       def _on_number_selected(self, number):
-               self._dialpads[self._selectedBackendId].set_number(number)
-               self._notebook.set_current_page(0)
+       def _on_number_selected(self, action, number, message):
+               if action == "select":
+                       self._dialpads[self._selectedBackendId].set_number(number)
+                       self._notebook.set_current_page(0)
+               elif action == "dial":
+                       self._on_dial_clicked(number)
+               elif action == "sms":
+                       self._on_sms_clicked(number, message)
+               else:
+                       assert False, "Unknown action: %s" % action
+
+       def _on_sms_clicked(self, number, message):
+               """
+               @todo Potential blocking on web access, maybe we should defer parts of this or put up a dialog?
+               """
+               assert number
+               assert message
+               try:
+                       loggedIn = self._phoneBackends[self._selectedBackendId].is_authed()
+               except RuntimeError, e:
+                       loggedIn = False
+                       self._errorDisplay.push_exception(e)
+                       return
+
+               if not loggedIn:
+                       self._errorDisplay.push_message(
+                               "Backend link with grandcentral is not working, please try again"
+                       )
+                       return
+
+               dialed = False
+               try:
+                       self._phoneBackends[self._selectedBackendId].send_sms(number, message)
+                       dialed = True
+               except RuntimeError, e:
+                       self._errorDisplay.push_exception(e)
+               except ValueError, e:
+                       self._errorDisplay.push_exception(e)
 
        def _on_dial_clicked(self, number):
                """
                @todo Potential blocking on web access, maybe we should defer parts of this or put up a dialog?
                """
+               assert number
                try:
                        loggedIn = self._phoneBackends[self._selectedBackendId].is_authed()
                except RuntimeError, e:
index 3a6b3da..a8df44d 100644 (file)
@@ -313,6 +313,11 @@ class MergedAddressBook(object):
 
 class PhoneTypeSelector(object):
 
+       ACTION_CANCEL = "cancel"
+       ACTION_SELECT = "select"
+       ACTION_DIAL = "dial"
+       ACTION_SEND_SMS = "sms"
+
        def __init__(self, widgetTree, gcBackend):
                self._gcBackend = gcBackend
                self._widgetTree = widgetTree
@@ -350,6 +355,8 @@ class PhoneTypeSelector(object):
                self._typeviewselection = typeview.get_selection()
                self._typeviewselection.set_mode(gtk.SELECTION_SINGLE)
 
+               self._action = self.ACTION_CANCEL
+
        def run(self, contactDetails, message = ""):
                self._typemodel.clear()
 
@@ -372,10 +379,20 @@ class PhoneTypeSelector(object):
                        phoneNumber = self._get_number()
                else:
                        phoneNumber = ""
+               if not phoneNumber:
+                       self._action = self.ACTION_CANCEL
+
+               if self._action == self.ACTION_SEND_SMS:
+                       smsMessage = self._smsDialog.run(phoneNumber, message)
+               else:
+                       smsMessage = ""
+               if not smsMessage:
+                       phoneNumber = ""
+                       self._action = ACTION_CANCEL
 
                self._typeviewselection.unselect_all()
                self._dialog.hide()
-               return phoneNumber
+               return self._action, phoneNumber, smsMessage
 
        def _get_number(self):
                model, itr = self._typeviewselection.get_selected()
@@ -386,19 +403,20 @@ class PhoneTypeSelector(object):
                return phoneNumber
 
        def _on_phonetype_dial(self, *args):
-               self._gcBackend.dial(self._get_number())
-               self._dialog.response(gtk.RESPONSE_CANCEL)
+               self._dialog.response(gtk.RESPONSE_OK)
+               self._action = self.ACTION_DIAL
 
        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_label())
+               self._dialog.response(gtk.RESPONSE_OK)
+               self._action = self.ACTION_SEND_SMS
 
        def _on_phonetype_select(self, *args):
                self._dialog.response(gtk.RESPONSE_OK)
+               self._action = self.ACTION_SELECT
 
        def _on_phonetype_cancel(self, *args):
                self._dialog.response(gtk.RESPONSE_CANCEL)
+               self._action = self.ACTION_CANCEL
 
 
 class SmsEntryDialog(object):
@@ -436,9 +454,11 @@ class SmsEntryDialog(object):
                        entryBuffer = self._smsEntry.get_buffer()
                        enteredMessage = entryBuffer.get_text(entryBuffer.get_start_iter(), entryBuffer.get_end_iter())
                        enteredMessage = enteredMessage[0:self.MAX_CHAR]
-                       self._gcBackend.send_sms(number, enteredMessage)
+               else:
+                       enteredMessage = ""
 
                self._dialog.hide()
+               return enteredMessage
 
        def _update_letter_count(self, *args):
                entryLength = self._smsEntry.get_buffer().get_char_count()
@@ -641,7 +661,7 @@ class RecentCallsView(object):
                self._recentview.remove_column(self._recentviewColumn)
                self._recentview.set_model(None)
 
-       def number_selected(self, number):
+       def number_selected(self, action, number, message):
                """
                @note Actual dial function is patched in later
                """
@@ -688,11 +708,12 @@ class RecentCallsView(object):
                description = self._recentmodel.get_value(itr, 1)
                print "Activated Recent Row:", repr(contactPhoneNumbers), repr(description)
 
-               phoneNumber = self._phoneTypeSelector.run(contactPhoneNumbers, message = description)
-               if 0 == len(phoneNumber):
+               action, phoneNumber, message = self._phoneTypeSelector.run(contactPhoneNumbers, message = description)
+               if action == PhoneTypeSelector.ACTION_CANCEL:
                        return
+               assert phoneNumber
 
-               self.number_selected(phoneNumber)
+               self.number_selected(action, phoneNumber, message)
                self._recentviewselection.unselect_all()
 
 
@@ -732,7 +753,7 @@ class MessagesView(object):
                self._messageview.remove_column(self._messageviewColumn)
                self._messageview.set_model(None)
 
-       def number_selected(self, number):
+       def number_selected(self, action, number, message):
                """
                @note Actual dial function is patched in later
                """
@@ -778,11 +799,12 @@ class MessagesView(object):
                description = self._messagemodel.get_value(itr, 1)
                print repr(contactPhoneNumbers), repr(description)
 
-               phoneNumber = self._phoneTypeSelector.run(contactPhoneNumbers, message = description)
-               if 0 == len(phoneNumber):
+               action, phoneNumber, message = self._phoneTypeSelector.run(contactPhoneNumbers, message = description)
+               if action == PhoneTypeSelector.ACTION_CANCEL:
                        return
+               assert phoneNumber
 
-               self.number_selected(phoneNumber)
+               self.number_selected(action, phoneNumber, message)
                self._messageviewselection.unselect_all()
 
 
@@ -862,7 +884,7 @@ class ContactsView(object):
                self._contactsview.set_model(None)
                self._contactsview.remove_column(self._contactColumn)
 
-       def number_selected(self, number):
+       def number_selected(self, action, number, message):
                """
                @note Actual dial function is patched in later
                """
@@ -953,12 +975,12 @@ class ContactsView(object):
                contactPhoneNumbers = [phoneNumber for phoneNumber in contactDetails]
 
                if len(contactPhoneNumbers) == 0:
-                       phoneNumber = ""
-               elif len(contactPhoneNumbers) == 1:
-                       phoneNumber = self._phoneTypeSelector.run(contactPhoneNumbers, message = contactName)
+                       return
 
-               if 0 == len(phoneNumber):
+               action, phoneNumber, message = self._phoneTypeSelector.run(contactPhoneNumbers, message = contactName)
+               if action == PhoneTypeSelector.ACTION_CANCEL:
                        return
+               assert phoneNumber
 
-               self.number_selected(phoneNumber)
+               self.number_selected(action, phoneNumber, message)
                self._contactsviewselection.unselect_all()
index 4d0294e..6609042 100644 (file)
@@ -402,21 +402,20 @@ class GVDialer(object):
                except urllib2.URLError, e:
                        warnings.warn(traceback.format_exc())
                        raise RuntimeError("%s is not accesible" % self._voicemailURL)
+               voicemailHtml = self._grab_html(voicemailPage)
+               parsedVoicemail = self._parse_voicemail(voicemailHtml)
+               decoratedVoicemails = self._decorate_voicemail(parsedVoicemail)
 
                try:
                        smsPage = self._browser.download(self._smsURL)
                except urllib2.URLError, e:
                        warnings.warn(traceback.format_exc())
                        raise RuntimeError("%s is not accesible" % self._smsURL)
+               smsHtml = self._grab_html(smsPage)
+               parsedSms = self._parse_sms(smsHtml)
+               decoratedSms = self._decorate_sms(parsedSms)
 
-               voicemailHtml = self._grab_html(voicemailPage)
-               parsedVoicemail = self._parse_voicemail(voicemailHtml)
-               decoratedVoicemails = self._decorated_voicemail(parsedVoicemail)
-
-               # @todo Parse this
-               # smsHtml = self._grab_html(smsPage)
-
-               allMessages = itertools.chain(decoratedVoicemails)
+               allMessages = itertools.chain(decoratedVoicemails, decoratedSms)
                sortedMessages = list(allMessages)
                for exactDate, header, number, relativeDate, message in sortedMessages:
                        yield header, number, relativeDate, message
@@ -523,15 +522,18 @@ class GVDialer(object):
                        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,
@@ -542,7 +544,7 @@ class GVDialer(object):
                                "messageParts": messageParts,
                        }
 
-       def _decorated_voicemail(self, parsedVoicemail):
+       def _decorate_voicemail(self, parsedVoicemail):
                messagePartFormat = {
                        "med1": "<i>%s</i>",
                        "med2": "%s",
@@ -559,6 +561,56 @@ class GVDialer(object):
                                message = "No Transcription"
                        yield exactTime, header, voicemailData["number"], voicemailData["relTime"], message
 
+       _smsFromRegex = re.compile(r"""<span class="gc-message-sms-from">(.*?)</span>""", re.MULTILINE)
+       _smsTextRegex = re.compile(r"""<span class="gc-message-sms-time">(.*?)</span>""", re.MULTILINE)
+       _smsTimeRegex = re.compile(r"""<span class="gc-message-sms-text">(.*?)</span>""", re.MULTILINE)
+
+       def _parse_sms(self, smsHtml):
+               print "="*60
+               print smsHtml
+               print "="*60
+               splitSms = self._seperateVoicemailsRegex.split(smsHtml)
+               for id, messageHtml in itergroup(splitSms[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 ""
+
+                       fromGroups = self._smsFromRegex.finditer(messageHtml)
+                       fromParts = (group.group(1) for group in fromGroups)
+                       textGroups = self._smsTextRegex.finditer(messageHtml)
+                       textParts = (group.group(1) for group in textGroups)
+                       timeGroups = self._smsTimeRegex.finditer(messageHtml)
+                       timeParts = (group.group(1) for group in timeGroups)
+
+                       # @todo Switch from chain to izip once debugged the parts
+                       #messageParts = itertools.izip(fromParts, textParts, timeParts)
+                       messageParts = itertools.chain(fromParts, textParts, timeParts)
+
+                       # @todo Switch pprint to yield and remove list() call once debugged parts
+                       import pprint
+                       pprint.pprint({
+                               "id": id,
+                               "time": exactTime,
+                               "relTime": relativeTime,
+                               "prettyNumber": prettyNumber,
+                               "number": number,
+                               "location": location,
+                               "messageParts": list(messageParts),
+                       })
+               return ()
+
+       def _decorate_sms(self, parsedSms):
+               return ()
+
 
 def test_backend(username, password):
        import pprint