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:
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
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()
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()
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):
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()
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
"""
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()
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
"""
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()
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
"""
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()
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
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,
"messageParts": messageParts,
}
- def _decorated_voicemail(self, parsedVoicemail):
+ def _decorate_voicemail(self, parsedVoicemail):
messagePartFormat = {
"med1": "<i>%s</i>",
"med2": "%s",
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