import os
import shutil
import simplejson
+import re
import logging
from PyQt4 import QtGui
self._contacts = []
self._app = app
self._session = session
+ self._session.draft.recipientsChanged.connect(self._on_recipients_changed)
+ self._session.draft.called.connect(self._on_op_finished)
+ self._session.draft.sentMessage.connect(self._on_op_finished)
+ self._session.draft.cancelled.connect(self._on_op_finished)
self._errorLog = errorLog
self._history = QtGui.QListView()
self._buttonLayout.addWidget(self._dialButton)
self._layout = QtGui.QVBoxLayout()
- self._layout.addLayout(self._entryLayout)
+ self._layout.addWidget(self._scrollEntry)
self._layout.addLayout(self._buttonLayout)
centralWidget = QtGui.QWidget()
centralWidget.setLayout(self._layout)
self._window = QtGui.QMainWindow(parent)
- self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, False)
qui_utils.set_autorient(self._window, True)
qui_utils.set_stackable(self._window, True)
self._window.setWindowTitle("Contact")
self._window.setCentralWidget(centralWidget)
+ self._window.show()
def _update_letter_count(self):
count = self._smsEntry.toPlainText().size()
@QtCore.pyqtSlot()
@misc_utils.log_exception(_moduleLogger)
+ def _on_recipients_changed(self):
+ draftContacts = len(self._session.draft.get_contacts())
+ if draftContacts == 0:
+ self._window.hide()
+ else:
+ self._window.show()
+
+ @QtCore.pyqtSlot()
+ @misc_utils.log_exception(_moduleLogger)
+ def _on_op_finished(self):
+ self._window.hide()
+
+ @QtCore.pyqtSlot()
+ @misc_utils.log_exception(_moduleLogger)
def _on_letter_count_changed(self):
self._update_letter_count()
self._update_button_state()
def _on_sms_clicked(self, checked = False):
number = str(self._entry.text())
self._entry.clear()
- self._session.draft.add_contact(number, [])
+
+ contactId = number
+ title = number
+ description = number
+ numbersWithDescriptions = [(number, "")]
+ self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions)
@QtCore.pyqtSlot()
@QtCore.pyqtSlot(bool)
def _on_call_clicked(self, checked = False):
number = str(self._entry.text())
self._entry.clear()
- self._session.draft.add_contact(number, [])
+
+ contactId = number
+ title = number
+ description = number
+ numbersWithDescriptions = [(number, "")]
+ self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions)
self._session.draft.call()
FROM_IDX = 3
MAX_IDX = 4
- HISTORY_ITEM_TYPES = ["All", "Received", "Missed", "Placed"]
+ HISTORY_ITEM_TYPES = ["Received", "Missed", "Placed", "All"]
HISTORY_COLUMNS = ["When", "What", "Number", "From"]
assert len(HISTORY_COLUMNS) == MAX_IDX
def __init__(self, app, session, errorLog):
- self._selectedFilter = self.HISTORY_ITEM_TYPES[0]
+ self._selectedFilter = self.HISTORY_ITEM_TYPES[-1]
self._app = app
self._session = session
self._session.historyUpdated.connect(self._on_history_updated)
self._typeSelection.setCurrentIndex(
self.HISTORY_ITEM_TYPES.index(self._selectedFilter)
)
- self._typeSelection.currentIndexChanged.connect(self._on_filter_changed)
+ self._typeSelection.currentIndexChanged[str].connect(self._on_filter_changed)
self._itemStore = QtGui.QStandardItemModel()
self._itemStore.setHorizontalHeaderLabels(self.HISTORY_COLUMNS)
self._itemView.clear()
def refresh(self):
- pass
+ self._session.update_history()
def _populate_items(self):
- self._errorLog.push_message("Not supported")
+ self._itemStore.clear()
+ history = self._session.get_history()
+ history.sort(key=lambda item: item["time"], reverse=True)
+ for event in history:
+ if self._selectedFilter in [self.HISTORY_ITEM_TYPES[-1], event["action"]]:
+ relTime = abbrev_relative_date(event["relTime"])
+ action = event["action"]
+ number = event["number"]
+ prettyNumber = make_pretty(number)
+ name = event["name"]
+ if not name or name == number:
+ name = event["location"]
+ if not name:
+ name = "Unknown"
+
+ timeItem = QtGui.QStandardItem(relTime)
+ actionItem = QtGui.QStandardItem(action)
+ numberItem = QtGui.QStandardItem(prettyNumber)
+ nameItem = QtGui.QStandardItem(name)
+ row = timeItem, actionItem, numberItem, nameItem
+ for item in row:
+ item.setEditable(False)
+ item.setCheckable(False)
+ if item is not nameItem:
+ itemFont = item.font()
+ itemFont.setPointSize(max(itemFont.pointSize() - 3, 5))
+ item.setFont(itemFont)
+ numberItem.setData(event)
+ self._itemStore.appendRow(row)
@QtCore.pyqtSlot(str)
@misc_utils.log_exception(_moduleLogger)
def _on_filter_changed(self, newItem):
self._selectedFilter = str(newItem)
+ self._populate_items()
@QtCore.pyqtSlot()
@misc_utils.log_exception(_moduleLogger)
@misc_utils.log_exception(_moduleLogger)
def _on_row_activated(self, index):
rowIndex = index.row()
- #self._session.draft.add_contact(number, details)
+ item = self._itemStore.item(rowIndex, self.NUMBER_IDX)
+ contactDetails = item.data().toPyObject()
+
+ title = str(self._itemStore.item(rowIndex, self.FROM_IDX).text())
+ number = str(contactDetails[QtCore.QString("number")])
+ contactId = number # ids don't seem too unique so using numbers
+
+ descriptionRows = []
+ # @bug doesn't seem to print multiple entries
+ for i in xrange(self._itemStore.rowCount()):
+ iItem = self._itemStore.item(i, self.NUMBER_IDX)
+ iContactDetails = iItem.data().toPyObject()
+ iNumber = str(iContactDetails[QtCore.QString("number")])
+ if number != iNumber:
+ continue
+ relTime = abbrev_relative_date(iContactDetails[QtCore.QString("relTime")])
+ action = str(iContactDetails[QtCore.QString("action")])
+ number = str(iContactDetails[QtCore.QString("number")])
+ prettyNumber = make_pretty(number)
+ rowItems = relTime, action, prettyNumber
+ descriptionRows.append("<tr><td>%s</td></tr>" % "</td><td>".join(rowItems))
+ description = "<table>%s</table>" % "".join(descriptionRows)
+ numbersWithDescriptions = [(str(contactDetails[QtCore.QString("number")]), "")]
+ self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions)
class Messages(object):
ALL_STATUS = "Any"
MESSAGE_STATUSES = [UNREAD_STATUS, UNARCHIVED_STATUS, ALL_STATUS]
+ _MIN_MESSAGES_SHOWN = 4
+
def __init__(self, app, session, errorLog):
self._selectedTypeFilter = self.ALL_TYPES
self._selectedStatusFilter = self.ALL_STATUS
self._typeSelection.setCurrentIndex(
self.MESSAGE_TYPES.index(self._selectedTypeFilter)
)
- self._typeSelection.currentIndexChanged.connect(self._on_type_filter_changed)
+ self._typeSelection.currentIndexChanged[str].connect(self._on_type_filter_changed)
self._statusSelection = QtGui.QComboBox()
self._statusSelection.addItems(self.MESSAGE_STATUSES)
self._statusSelection.setCurrentIndex(
self.MESSAGE_STATUSES.index(self._selectedStatusFilter)
)
- self._statusSelection.currentIndexChanged.connect(self._on_status_filter_changed)
+ self._statusSelection.currentIndexChanged[str].connect(self._on_status_filter_changed)
self._selectionLayout = QtGui.QHBoxLayout()
self._selectionLayout.addWidget(self._typeSelection)
self._itemStore = QtGui.QStandardItemModel()
self._itemStore.setHorizontalHeaderLabels(["Messages"])
+ self._htmlDelegate = qui_utils.QHtmlDelegate()
self._itemView = QtGui.QTreeView()
self._itemView.setModel(self._itemStore)
- self._itemView.setUniformRowHeights(True)
+ self._itemView.setUniformRowHeights(False)
self._itemView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self._itemView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self._itemView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
self._itemView.setHeaderHidden(True)
+ self._itemView.setItemDelegate(self._htmlDelegate)
self._itemView.activated.connect(self._on_row_activated)
self._layout = QtGui.QVBoxLayout()
self._itemView.clear()
def refresh(self):
- pass
+ self._session.update_messages()
def _populate_items(self):
- self._errorLog.push_message("Not supported")
+ self._itemStore.clear()
+ rawMessages = self._session.get_messages()
+ rawMessages.sort(key=lambda item: item["time"], reverse=True)
+ for item in rawMessages:
+ isUnarchived = not item["isArchived"]
+ isUnread = not item["isRead"]
+ visibleStatus = {
+ self.UNREAD_STATUS: isUnarchived and isUnread,
+ self.UNARCHIVED_STATUS: isUnarchived,
+ self.ALL_STATUS: True,
+ }[self._selectedStatusFilter]
+
+ visibleType = self._selectedTypeFilter in [item["type"], self.ALL_TYPES]
+ if visibleType and visibleStatus:
+ relTime = abbrev_relative_date(item["relTime"])
+ number = item["number"]
+ prettyNumber = make_pretty(number)
+ name = item["name"]
+ if not name or name == number:
+ name = item["location"]
+ if not name:
+ name = "Unknown"
+
+ messageParts = list(item["messageParts"])
+ if len(messageParts) == 0:
+ messages = ("No Transcription", )
+ elif len(messageParts) == 1:
+ if messageParts[0][1]:
+ messages = (messageParts[0][1], )
+ else:
+ messages = ("No Transcription", )
+ else:
+ messages = [
+ "<b>%s</b>: %s" % (messagePart[0], messagePart[1])
+ for messagePart in messageParts
+ ]
+
+ firstMessage = "<b>%s - %s</b> <i>(%s)</i>" % (name, prettyNumber, relTime)
+
+ expandedMessages = [firstMessage]
+ expandedMessages.extend(messages)
+ if (self._MIN_MESSAGES_SHOWN + 1) < len(messages):
+ secondMessage = "<i>%d Messages Hidden...</i>" % (len(messages) - self._MIN_MESSAGES_SHOWN, )
+ collapsedMessages = [firstMessage, secondMessage]
+ collapsedMessages.extend(messages[-(self._MIN_MESSAGES_SHOWN+0):])
+ else:
+ collapsedMessages = expandedMessages
+
+ item = dict(item.iteritems())
+ item["collapsedMessages"] = "<br/>\n".join(collapsedMessages)
+ item["expandedMessages"] = "<br/>\n".join(expandedMessages)
+
+ messageItem = QtGui.QStandardItem(item["collapsedMessages"])
+ # @bug Not showing all of a message
+ messageItem.setData(item)
+ messageItem.setEditable(False)
+ messageItem.setCheckable(False)
+ row = (messageItem, )
+ self._itemStore.appendRow(row)
@QtCore.pyqtSlot(str)
@misc_utils.log_exception(_moduleLogger)
def _on_type_filter_changed(self, newItem):
self._selectedTypeFilter = str(newItem)
+ self._populate_items()
@QtCore.pyqtSlot(str)
@misc_utils.log_exception(_moduleLogger)
def _on_status_filter_changed(self, newItem):
self._selectedStatusFilter = str(newItem)
+ self._populate_items()
@QtCore.pyqtSlot()
@misc_utils.log_exception(_moduleLogger)
@misc_utils.log_exception(_moduleLogger)
def _on_row_activated(self, index):
rowIndex = index.row()
- #self._session.draft.add_contact(number, details)
+ item = self._itemStore.item(rowIndex, 0)
+ contactDetails = item.data().toPyObject()
+
+ name = str(contactDetails[QtCore.QString("name")])
+ number = str(contactDetails[QtCore.QString("number")])
+ if not name or name == number:
+ name = str(contactDetails[QtCore.QString("location")])
+ if not name:
+ name = "Unknown"
+
+ contactId = str(contactDetails[QtCore.QString("id")])
+ title = name
+ description = str(contactDetails[QtCore.QString("expandedMessages")])
+ numbersWithDescriptions = [(number, "")]
+ self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions)
class Contacts(object):
self._listSelection = QtGui.QComboBox()
self._listSelection.addItems([])
+ # @todo Implement more contact lists
#self._listSelection.setCurrentIndex(self.HISTORY_ITEM_TYPES.index(self._selectedFilter))
- self._listSelection.currentIndexChanged.connect(self._on_filter_changed)
+ self._listSelection.currentIndexChanged[str].connect(self._on_filter_changed)
self._itemStore = QtGui.QStandardItemModel()
self._itemStore.setHorizontalHeaderLabels(["Contacts"])
self._itemView.clear()
def refresh(self):
- pass
+ self._session.update_contacts()
def _populate_items(self):
- self._errorLog.push_message("Not supported")
+ self._itemStore.clear()
+
+ contacts = list(self._session.get_contacts().itervalues())
+ contacts.sort(key=lambda contact: contact["name"].lower())
+ for item in contacts:
+ name = item["name"]
+ numbers = item["numbers"]
+ nameItem = QtGui.QStandardItem(name)
+ nameItem.setEditable(False)
+ nameItem.setCheckable(False)
+ nameItem.setData(item)
+ row = (nameItem, )
+ self._itemStore.appendRow(row)
@QtCore.pyqtSlot(str)
@misc_utils.log_exception(_moduleLogger)
@misc_utils.log_exception(_moduleLogger)
def _on_row_activated(self, index):
rowIndex = index.row()
- #self._session.draft.add_contact(number, details)
+ item = self._itemStore.item(rowIndex, 0)
+ contactDetails = item.data().toPyObject()
+
+ name = str(contactDetails[QtCore.QString("name")])
+ if not name:
+ name = str(contactDetails[QtCore.QString("location")])
+ if not name:
+ name = "Unknown"
+
+ contactId = str(contactDetails[QtCore.QString("contactId")])
+ numbers = contactDetails[QtCore.QString("numbers")]
+ numbers = [
+ dict(
+ (str(k), str(v))
+ for (k, v) in number.iteritems()
+ )
+ for number in numbers
+ ]
+ numbersWithDescriptions = [
+ (
+ number["phoneNumber"],
+ self._choose_phonetype(number),
+ )
+ for number in numbers
+ ]
+ title = name
+ description = name
+ self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions)
+
+ @staticmethod
+ def _choose_phonetype(numberDetails):
+ if "phoneTypeName" in numberDetails:
+ return numberDetails["phoneTypeName"]
+ elif "phoneType" in numberDetails:
+ return numberDetails["phoneType"]
+ else:
+ return ""
class MainWindow(object):
self._session.error.connect(self._on_session_error)
self._session.loggedIn.connect(self._on_login)
self._session.loggedOut.connect(self._on_logout)
+ self._session.draft.recipientsChanged.connect(self._on_recipients_changed)
self._credentialsDialog = None
+ self._smsEntryDialog = None
self._errorLog = qui_utils.QErrorLog()
self._errorDisplay = qui_utils.ErrorDisplay(self._errorLog)
def _initialize_tab(self, index):
assert index < self.MAX_TABS
if not self._tabsContents[index].has_child():
- self._tabsContents[index].set_child(
- self._TAB_CLASS[index](self._app, self._session, self._errorLog)
- )
+ tab = self._TAB_CLASS[index](self._app, self._session, self._errorLog)
+ self._tabsContents[index].set_child(tab)
+ self._tabsContents[index].refresh()
@QtCore.pyqtSlot(str)
@misc_utils.log_exception(_moduleLogger)
tab.disable()
@QtCore.pyqtSlot()
+ @misc_utils.log_exception(_moduleLogger)
+ def _on_recipients_changed(self):
+ if self._smsEntryDialog is None:
+ self._smsEntryDialog = SMSEntryWindow(self.window, self._app, self._session, self._errorLog)
+ pass
+
+ @QtCore.pyqtSlot()
@QtCore.pyqtSlot(bool)
@misc_utils.log_exception(_moduleLogger)
def _on_login_requested(self, checked = True):
self.close()
+def make_ugly(prettynumber):
+ """
+ function to take a phone number and strip out all non-numeric
+ characters
+
+ >>> make_ugly("+012-(345)-678-90")
+ '+01234567890'
+ """
+ return normalize_number(prettynumber)
+
+
+def normalize_number(prettynumber):
+ """
+ function to take a phone number and strip out all non-numeric
+ characters
+
+ >>> normalize_number("+012-(345)-678-90")
+ '+01234567890'
+ >>> normalize_number("1-(345)-678-9000")
+ '+13456789000'
+ >>> normalize_number("+1-(345)-678-9000")
+ '+13456789000'
+ """
+ uglynumber = re.sub('[^0-9+]', '', prettynumber)
+
+ if uglynumber.startswith("+"):
+ pass
+ elif uglynumber.startswith("1"):
+ uglynumber = "+"+uglynumber
+ elif 10 <= len(uglynumber):
+ assert uglynumber[0] not in ("+", "1")
+ uglynumber = "+1"+uglynumber
+ else:
+ pass
+
+ return uglynumber
+
+
+def _make_pretty_with_areacode(phonenumber):
+ prettynumber = "(%s)" % (phonenumber[0:3], )
+ if 3 < len(phonenumber):
+ prettynumber += " %s" % (phonenumber[3:6], )
+ if 6 < len(phonenumber):
+ prettynumber += "-%s" % (phonenumber[6:], )
+ return prettynumber
+
+
+def _make_pretty_local(phonenumber):
+ prettynumber = "%s" % (phonenumber[0:3], )
+ if 3 < len(phonenumber):
+ prettynumber += "-%s" % (phonenumber[3:], )
+ return prettynumber
+
+
+def _make_pretty_international(phonenumber):
+ prettynumber = phonenumber
+ if phonenumber.startswith("1"):
+ prettynumber = "1 "
+ prettynumber += _make_pretty_with_areacode(phonenumber[1:])
+ return prettynumber
+
+
+def make_pretty(phonenumber):
+ """
+ Function to take a phone number and return the pretty version
+ pretty numbers:
+ if phonenumber begins with 0:
+ ...-(...)-...-....
+ if phonenumber begins with 1: ( for gizmo callback numbers )
+ 1 (...)-...-....
+ if phonenumber is 13 digits:
+ (...)-...-....
+ if phonenumber is 10 digits:
+ ...-....
+ >>> make_pretty("12")
+ '12'
+ >>> make_pretty("1234567")
+ '123-4567'
+ >>> make_pretty("2345678901")
+ '+1 (234) 567-8901'
+ >>> make_pretty("12345678901")
+ '+1 (234) 567-8901'
+ >>> make_pretty("01234567890")
+ '+012 (345) 678-90'
+ >>> make_pretty("+01234567890")
+ '+012 (345) 678-90'
+ >>> make_pretty("+12")
+ '+1 (2)'
+ >>> make_pretty("+123")
+ '+1 (23)'
+ >>> make_pretty("+1234")
+ '+1 (234)'
+ """
+ if phonenumber is None or phonenumber is "":
+ return ""
+
+ phonenumber = normalize_number(phonenumber)
+
+ if phonenumber[0] == "+":
+ prettynumber = _make_pretty_international(phonenumber[1:])
+ if not prettynumber.startswith("+"):
+ prettynumber = "+"+prettynumber
+ elif 8 < len(phonenumber) and phonenumber[0] in ("1", ):
+ prettynumber = _make_pretty_international(phonenumber)
+ elif 7 < len(phonenumber):
+ prettynumber = _make_pretty_with_areacode(phonenumber)
+ elif 3 < len(phonenumber):
+ prettynumber = _make_pretty_local(phonenumber)
+ else:
+ prettynumber = phonenumber
+ return prettynumber.strip()
+
+
+def abbrev_relative_date(date):
+ """
+ >>> abbrev_relative_date("42 hours ago")
+ '42 h'
+ >>> abbrev_relative_date("2 days ago")
+ '2 d'
+ >>> abbrev_relative_date("4 weeks ago")
+ '4 w'
+ """
+ parts = date.split(" ")
+ return "%s %s" % (parts[0], parts[1][0])
+
+
def run():
app = QtGui.QApplication([])
handle = Dialcentral(app)
def send(self, text):
assert 0 < len(self._contacts)
- self.sendingMessage.emit()
- self.error.emit("Not Implemented")
- # self.clear()
+ le = concurrent.AsyncLinearExecution(self._pool, self._send)
+ le.start(text)
def call(self):
assert len(self._contacts) == 1
- self.calling.emit()
- self.error.emit("Not Implemented")
- # self.clear()
+ le = concurrent.AsyncLinearExecution(self._pool, self._call)
+ le.start()
def cancel(self):
- self.cancelling.emit()
- self.error.emit("Not Implemented")
+ le = concurrent.AsyncLinearExecution(self._pool, self._cancel)
+ le.start()
- def add_contact(self, contact, details):
- assert contact not in self._contacts
- self._contacts[contact] = details
+ def add_contact(self, contactId, title, description, numbersWithDescriptions):
+ assert contactId not in self._contacts
+ contactDetails = title, description, numbersWithDescriptions
+ self._contacts[contactId] = contactDetails
self.recipientsChanged.emit()
- def remove_contact(self, contact):
- assert contact not in self._contacts
- del self._contacts[contact]
+ def remove_contact(self, contactId):
+ assert contactId in self._contacts
+ del self._contacts[contactId]
self.recipientsChanged.emit()
- def get_contacts(self, contact):
+ def get_contacts(self):
return self._contacts
def clear(self):
self._contacts = {}
self.recipientsChanged.emit()
+ def _send(self, text):
+ self.sendingMessage.emit()
+ try:
+ self.error.emit("Not Implemented")
+ self.sentMessage.emit()
+ self.clear()
+ except Exception, e:
+ self.error.emit(str(e))
+
+ def _call(self):
+ self.calling.emit()
+ try:
+ self.error.emit("Not Implemented")
+ self.called.emit()
+ self.clear()
+ except Exception, e:
+ self.error.emit(str(e))
+
+ def _cancel(self):
+ self.cancelling.emit()
+ try:
+ yield (
+ self._backend.cancel,
+ (),
+ {},
+ )
+ self.cancelled.emit()
+ except Exception, e:
+ self.error.emit(str(e))
+
class Session(QtCore.QObject):
self._username = None
self._draft = Draft(self._pool)
- self._contacts = []
+ self._contacts = {}
self._messages = []
self._history = []
self._dnd = False
+ self._callback = ""
@property
def state(self):
def login(self, username, password):
assert self.state == self.LOGGEDOUT_STATE
+ assert username != ""
if self._cachePath is not None:
cookiePath = os.path.join(self._cachePath, "%s.cookies" % username)
else:
def logout(self):
assert self.state != self.LOGGEDOUT_STATE
self._pool.stop()
- self.error.emit("Not Implemented")
+ self._loggedInTime = self._LOGGEDOUT_TIME
+ self._backend.persist()
+ self._save_to_cache()
def clear(self):
assert self.state == self.LOGGEDOUT_STATE
+ self._backend.logout()
self._backend = None
+ self._clear_cache()
self._draft.clear()
- self._contacts = []
- self.contactsUpdated.emit()
- self._messages = []
- self.messagesUpdated.emit()
- self._history = []
- self.historyUpdated.emit()
- self._dnd = False
- self.dndStateChange.emit(self._dnd)
+
+ def logout_and_clear(self):
+ assert self.state != self.LOGGEDOUT_STATE
+ self._pool.stop()
+ self._loggedInTime = self._LOGGEDOUT_TIME
+ self.clear()
def update_contacts(self):
le = concurrent.AsyncLinearExecution(self._pool, self._update_contacts)
self._perform_op_while_loggedin(le)
def set_dnd(self, dnd):
+ # I'm paranoid about our state geting out of sync so we set no matter
+ # what but act as if we have the cannonical state
assert self.state == self.LOGGEDIN_STATE
- self.error.emit("Not Implemented")
+ oldDnd = self._dnd
+ try:
+ yield (
+ self._backend.set_dnd,
+ (dnd),
+ {},
+ )
+ except Exception, e:
+ self.error.emit(str(e))
+ return
+ self._dnd = dnd
+ if oldDnd != self._dnd:
+ self.dndStateChange.emit(self._dnd)
def get_dnd(self):
return self._dnd
def get_callback_numbers(self):
- return []
+ # @todo Remove evilness
+ return self._backend.get_callback_numbers()
def get_callback_number(self):
- return ""
+ return self._callback
- def set_callback_number(self):
+ def set_callback_number(self, callback):
+ # I'm paranoid about our state geting out of sync so we set no matter
+ # what but act as if we have the cannonical state
assert self.state == self.LOGGEDIN_STATE
- self.error.emit("Not Implemented")
+ oldCallback = self._callback
+ try:
+ yield (
+ self._backend.set_callback_number,
+ (callback),
+ {},
+ )
+ except Exception, e:
+ self.error.emit(str(e))
+ return
+ self._callback = callback
+ if oldCallback != self._callback:
+ self.callbackNumberChanged.emit(self._callback)
def _login(self, username, password):
self._loggedInTime = self._LOGGINGIN_TIME
isLoggedIn = False
if not isLoggedIn and self._backend.is_quick_login_possible():
- try:
- isLoggedIn = yield (
- self._backend.is_authed,
+ isLoggedIn = yield (
+ self._backend.is_authed,
+ (),
+ {},
+ )
+ if isLoggedIn:
+ _moduleLogger.info("Logged in through cookies")
+ else:
+ # Force a clearing of the cookies
+ yield (
+ self._backend.logout,
(),
{},
)
- except Exception, e:
- self.error.emit(str(e))
- return
- if isLoggedIn:
- _moduleLogger.info("Logged in through cookies")
if not isLoggedIn:
- try:
- isLoggedIn = yield (
- self._backend.login,
- (username, password),
- {},
- )
- except Exception, e:
- self.error.emit(str(e))
- return
+ isLoggedIn = yield (
+ self._backend.login,
+ (username, password),
+ {},
+ )
if isLoggedIn:
_moduleLogger.info("Logged in through credentials")
if isLoggedIn:
- self._loggedInTime = time.time()
+ self._loggedInTime = int(time.time())
+ oldUsername = self._username
self._username = username
finalState = self.LOGGEDIN_STATE
self.loggedIn.emit()
- # if the username is the same, do nothing
- # else clear the in-memory caches and attempt to load from file-caches
- # If caches went from empty to something, fire signals
- # Fire off queued async ops
+ if oldUsername != self._username:
+ self._load_from_cache()
+ loginOps = self._loginOps[:]
+ del self._loginOps[:]
+ for asyncOp in loginOps:
+ asyncOp.start()
except Exception, e:
self.error.emit(str(e))
finally:
self.stateChange.emit(finalState)
+ def _load_from_cache(self):
+ updateContacts = len(self._contacts) != 0
+ updateMessages = len(self._messages) != 0
+ updateHistory = len(self._history) != 0
+ oldDnd = self._dnd
+ oldCallback = self._callback
+
+ self._contacts = {}
+ self._messages = []
+ self._history = []
+ self._dnd = False
+ self._callback = ""
+
+ if updateContacts:
+ self.contactsUpdated.emit()
+ if updateMessages:
+ self.messagesUpdated.emit()
+ if updateHistory:
+ self.historyUpdated.emit()
+ if oldDnd != self._dnd:
+ self.dndStateChange.emit(self._dnd)
+ if oldCallback != self._callback:
+ self.callbackNumberChanged.emit(self._callback)
+
+ def _save_to_cache(self):
+ # @todo
+ pass
+
+ def _clear_cache(self):
+ updateContacts = len(self._contacts) != 0
+ updateMessages = len(self._messages) != 0
+ updateHistory = len(self._history) != 0
+ oldDnd = self._dnd
+ oldCallback = self._callback
+
+ self._contacts = {}
+ self._messages = []
+ self._history = []
+ self._dnd = False
+ self._callback = ""
+
+ if updateContacts:
+ self.contactsUpdated.emit()
+ if updateMessages:
+ self.messagesUpdated.emit()
+ if updateHistory:
+ self.historyUpdated.emit()
+ if oldDnd != self._dnd:
+ self.dndStateChange.emit(self._dnd)
+ if oldCallback != self._callback:
+ self.callbackNumberChanged.emit(self._callback)
+
+ self._save_to_cache()
+
def _update_contacts(self):
- self.error.emit("Not Implemented")
try:
- isLoggedIn = yield (
- self._backend.is_authed,
+ self._contacts = yield (
+ self._backend.get_contacts,
(),
{},
)
except Exception, e:
self.error.emit(str(e))
return
+ self.contactsUpdated.emit()
def _update_messages(self):
- self.error.emit("Not Implemented")
try:
- isLoggedIn = yield (
- self._backend.is_authed,
+ self._messages = yield (
+ self._backend.get_messages,
(),
{},
)
except Exception, e:
self.error.emit(str(e))
return
+ self.messagesUpdated.emit()
def _update_history(self):
- self.error.emit("Not Implemented")
try:
- isLoggedIn = yield (
- self._backend.is_authed,
+ self._history = yield (
+ self._backend.get_recent,
(),
{},
)
except Exception, e:
self.error.emit(str(e))
return
+ self.historyUpdated.emit()
def _update_dnd(self):
- self.error.emit("Not Implemented")
+ oldDnd = self._dnd
try:
- isLoggedIn = yield (
- self._backend.is_authed,
+ self._dnd = yield (
+ self._backend.is_dnd,
(),
{},
)
except Exception, e:
self.error.emit(str(e))
return
+ if oldDnd != self._dnd:
+ self.dndStateChange(self._dnd)
def _perform_op_while_loggedin(self, op):
if self.state == self.LOGGEDIN_STATE:
- op()
+ op.start()
else:
self._push_login_op(op)