5 from PyQt4 import QtCore
7 from util import qore_utils
8 from util import concurrent
10 from backends import gv_backend
13 _moduleLogger = logging.getLogger(__name__)
16 class Draft(QtCore.QObject):
18 sendingMessage = QtCore.pyqtSignal()
19 sentMessage = QtCore.pyqtSignal()
20 calling = QtCore.pyqtSignal()
21 called = QtCore.pyqtSignal()
22 cancelling = QtCore.pyqtSignal()
23 cancelled = QtCore.pyqtSignal()
24 error = QtCore.pyqtSignal(str)
26 recipientsChanged = QtCore.pyqtSignal()
28 def __init__(self, pool):
29 QtCore.QObject.__init__(self)
34 assert 0 < len(self._contacts)
35 le = concurrent.AsyncLinearExecution(self._pool, self._send)
39 assert len(self._contacts) == 1
40 le = concurrent.AsyncLinearExecution(self._pool, self._call)
44 le = concurrent.AsyncLinearExecution(self._pool, self._cancel)
47 def add_contact(self, contactId, title, description, numbersWithDescriptions):
48 assert contactId not in self._contacts
49 contactDetails = title, description, numbersWithDescriptions
50 self._contacts[contactId] = contactDetails
51 self.recipientsChanged.emit()
53 def remove_contact(self, contactId):
54 assert contactId in self._contacts
55 del self._contacts[contactId]
56 self.recipientsChanged.emit()
58 def get_contacts(self):
63 self.recipientsChanged.emit()
65 def _send(self, text):
66 self.sendingMessage.emit()
68 self.error.emit("Not Implemented")
69 self.sentMessage.emit()
72 self.error.emit(str(e))
77 self.error.emit("Not Implemented")
81 self.error.emit(str(e))
84 self.cancelling.emit()
93 self.error.emit(str(e))
96 class Session(QtCore.QObject):
98 stateChange = QtCore.pyqtSignal(str)
99 loggedOut = QtCore.pyqtSignal()
100 loggedIn = QtCore.pyqtSignal()
101 callbackNumberChanged = QtCore.pyqtSignal(str)
103 contactsUpdated = QtCore.pyqtSignal()
104 messagesUpdated = QtCore.pyqtSignal()
105 historyUpdated = QtCore.pyqtSignal()
106 dndStateChange = QtCore.pyqtSignal(bool)
108 error = QtCore.pyqtSignal(str)
110 LOGGEDOUT_STATE = "logged out"
111 LOGGINGIN_STATE = "logging in"
112 LOGGEDIN_STATE = "logged in"
117 def __init__(self, cachePath = None):
118 QtCore.QObject.__init__(self)
119 self._pool = qore_utils.AsyncPool()
121 self._loggedInTime = self._LOGGEDOUT_TIME
123 self._cachePath = cachePath
124 self._username = None
125 self._draft = Draft(self._pool)
136 self._LOGGEDOUT_TIME: self.LOGGEDOUT_STATE,
137 self._LOGGINGIN_TIME: self.LOGGINGIN_STATE,
138 }.get(self._loggedInTime, self.LOGGEDIN_STATE)
144 def login(self, username, password):
145 assert self.state == self.LOGGEDOUT_STATE
146 assert username != ""
147 if self._cachePath is not None:
148 cookiePath = os.path.join(self._cachePath, "%s.cookies" % username)
152 if self._username != username or self._backend is None:
153 self._backend = gv_backend.GVDialer(cookiePath)
156 le = concurrent.AsyncLinearExecution(self._pool, self._login)
157 le.start(username, password)
160 assert self.state != self.LOGGEDOUT_STATE
162 self._loggedInTime = self._LOGGEDOUT_TIME
163 self._backend.persist()
164 self._save_to_cache()
167 assert self.state == self.LOGGEDOUT_STATE
168 self._backend.logout()
173 def logout_and_clear(self):
174 assert self.state != self.LOGGEDOUT_STATE
176 self._loggedInTime = self._LOGGEDOUT_TIME
179 def update_contacts(self):
180 le = concurrent.AsyncLinearExecution(self._pool, self._update_contacts)
181 self._perform_op_while_loggedin(le)
183 def get_contacts(self):
184 return self._contacts
186 def update_messages(self):
187 le = concurrent.AsyncLinearExecution(self._pool, self._update_messages)
188 self._perform_op_while_loggedin(le)
190 def get_messages(self):
191 return self._messages
193 def update_history(self):
194 le = concurrent.AsyncLinearExecution(self._pool, self._update_history)
195 self._perform_op_while_loggedin(le)
197 def get_history(self):
200 def update_dnd(self):
201 le = concurrent.AsyncLinearExecution(self._pool, self._update_dnd)
202 self._perform_op_while_loggedin(le)
204 def set_dnd(self, dnd):
205 # I'm paranoid about our state geting out of sync so we set no matter
206 # what but act as if we have the cannonical state
207 assert self.state == self.LOGGEDIN_STATE
211 self._backend.set_dnd,
216 self.error.emit(str(e))
219 if oldDnd != self._dnd:
220 self.dndStateChange.emit(self._dnd)
225 def get_callback_numbers(self):
226 # @todo Remove evilness
227 return self._backend.get_callback_numbers()
229 def get_callback_number(self):
230 return self._callback
232 def set_callback_number(self, callback):
233 # I'm paranoid about our state geting out of sync so we set no matter
234 # what but act as if we have the cannonical state
235 assert self.state == self.LOGGEDIN_STATE
236 oldCallback = self._callback
239 self._backend.set_callback_number,
244 self.error.emit(str(e))
246 self._callback = callback
247 if oldCallback != self._callback:
248 self.callbackNumberChanged.emit(self._callback)
250 def _login(self, username, password):
251 self._loggedInTime = self._LOGGINGIN_TIME
252 self.stateChange.emit(self.LOGGINGIN_STATE)
253 finalState = self.LOGGEDOUT_STATE
257 if not isLoggedIn and self._backend.is_quick_login_possible():
259 self._backend.is_authed,
264 _moduleLogger.info("Logged in through cookies")
266 # Force a clearing of the cookies
268 self._backend.logout,
276 (username, password),
280 _moduleLogger.info("Logged in through credentials")
283 self._loggedInTime = int(time.time())
284 oldUsername = self._username
285 self._username = username
286 finalState = self.LOGGEDIN_STATE
288 if oldUsername != self._username:
289 self._load_from_cache()
290 loginOps = self._loginOps[:]
291 del self._loginOps[:]
292 for asyncOp in loginOps:
295 self.error.emit(str(e))
297 self.stateChange.emit(finalState)
299 def _load_from_cache(self):
300 updateContacts = len(self._contacts) != 0
301 updateMessages = len(self._messages) != 0
302 updateHistory = len(self._history) != 0
304 oldCallback = self._callback
313 self.contactsUpdated.emit()
315 self.messagesUpdated.emit()
317 self.historyUpdated.emit()
318 if oldDnd != self._dnd:
319 self.dndStateChange.emit(self._dnd)
320 if oldCallback != self._callback:
321 self.callbackNumberChanged.emit(self._callback)
323 def _save_to_cache(self):
327 def _clear_cache(self):
328 updateContacts = len(self._contacts) != 0
329 updateMessages = len(self._messages) != 0
330 updateHistory = len(self._history) != 0
332 oldCallback = self._callback
341 self.contactsUpdated.emit()
343 self.messagesUpdated.emit()
345 self.historyUpdated.emit()
346 if oldDnd != self._dnd:
347 self.dndStateChange.emit(self._dnd)
348 if oldCallback != self._callback:
349 self.callbackNumberChanged.emit(self._callback)
351 self._save_to_cache()
353 def _update_contacts(self):
355 self._contacts = yield (
356 self._backend.get_contacts,
361 self.error.emit(str(e))
363 self.contactsUpdated.emit()
365 def _update_messages(self):
367 self._messages = yield (
368 self._backend.get_messages,
373 self.error.emit(str(e))
375 self.messagesUpdated.emit()
377 def _update_history(self):
379 self._history = yield (
380 self._backend.get_recent,
385 self.error.emit(str(e))
387 self.historyUpdated.emit()
389 def _update_dnd(self):
393 self._backend.is_dnd,
398 self.error.emit(str(e))
400 if oldDnd != self._dnd:
401 self.dndStateChange(self._dnd)
403 def _perform_op_while_loggedin(self, op):
404 if self.state == self.LOGGEDIN_STATE:
407 self._push_login_op(op)
409 def _push_login_op(self, asyncOp):
410 assert self.state != self.LOGGEDIN_STATE
411 if asyncOp in self._loginOps:
412 _moduleLogger.info("Skipping queueing duplicate op: %r" % asyncOp)
414 self._loginOps.append(asyncOp)