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):
62 oldContacts = self._contacts
65 self.recipientsChanged.emit()
67 def _send(self, text):
68 self.sendingMessage.emit()
70 self.error.emit("Not Implemented")
71 self.sentMessage.emit()
74 self.error.emit(str(e))
79 self.error.emit("Not Implemented")
83 self.error.emit(str(e))
86 self.cancelling.emit()
95 self.error.emit(str(e))
98 class Session(QtCore.QObject):
100 stateChange = QtCore.pyqtSignal(str)
101 loggedOut = QtCore.pyqtSignal()
102 loggedIn = QtCore.pyqtSignal()
103 callbackNumberChanged = QtCore.pyqtSignal(str)
105 contactsUpdated = QtCore.pyqtSignal()
106 messagesUpdated = QtCore.pyqtSignal()
107 historyUpdated = QtCore.pyqtSignal()
108 dndStateChange = QtCore.pyqtSignal(bool)
110 error = QtCore.pyqtSignal(str)
112 LOGGEDOUT_STATE = "logged out"
113 LOGGINGIN_STATE = "logging in"
114 LOGGEDIN_STATE = "logged in"
119 def __init__(self, cachePath = None):
120 QtCore.QObject.__init__(self)
121 self._pool = qore_utils.AsyncPool()
123 self._loggedInTime = self._LOGGEDOUT_TIME
125 self._cachePath = cachePath
126 self._username = None
127 self._draft = Draft(self._pool)
138 self._LOGGEDOUT_TIME: self.LOGGEDOUT_STATE,
139 self._LOGGINGIN_TIME: self.LOGGINGIN_STATE,
140 }.get(self._loggedInTime, self.LOGGEDIN_STATE)
146 def login(self, username, password):
147 assert self.state == self.LOGGEDOUT_STATE
148 assert username != ""
149 if self._cachePath is not None:
150 cookiePath = os.path.join(self._cachePath, "%s.cookies" % username)
154 if self._username != username or self._backend is None:
155 self._backend = gv_backend.GVDialer(cookiePath)
158 le = concurrent.AsyncLinearExecution(self._pool, self._login)
159 le.start(username, password)
162 assert self.state != self.LOGGEDOUT_STATE
164 self._loggedInTime = self._LOGGEDOUT_TIME
165 self._backend.persist()
166 self._save_to_cache()
169 assert self.state == self.LOGGEDOUT_STATE
170 self._backend.logout()
175 def logout_and_clear(self):
176 assert self.state != self.LOGGEDOUT_STATE
178 self._loggedInTime = self._LOGGEDOUT_TIME
181 def update_contacts(self):
182 le = concurrent.AsyncLinearExecution(self._pool, self._update_contacts)
183 self._perform_op_while_loggedin(le)
185 def get_contacts(self):
186 return self._contacts
188 def update_messages(self):
189 le = concurrent.AsyncLinearExecution(self._pool, self._update_messages)
190 self._perform_op_while_loggedin(le)
192 def get_messages(self):
193 return self._messages
195 def update_history(self):
196 le = concurrent.AsyncLinearExecution(self._pool, self._update_history)
197 self._perform_op_while_loggedin(le)
199 def get_history(self):
202 def update_dnd(self):
203 le = concurrent.AsyncLinearExecution(self._pool, self._update_dnd)
204 self._perform_op_while_loggedin(le)
206 def set_dnd(self, dnd):
207 # I'm paranoid about our state geting out of sync so we set no matter
208 # what but act as if we have the cannonical state
209 assert self.state == self.LOGGEDIN_STATE
213 self._backend.set_dnd,
218 self.error.emit(str(e))
221 if oldDnd != self._dnd:
222 self.dndStateChange.emit(self._dnd)
227 def get_callback_numbers(self):
228 # @todo Remove evilness
229 return self._backend.get_callback_numbers()
231 def get_callback_number(self):
232 return self._callback
234 def set_callback_number(self, callback):
235 # I'm paranoid about our state geting out of sync so we set no matter
236 # what but act as if we have the cannonical state
237 assert self.state == self.LOGGEDIN_STATE
238 oldCallback = self._callback
241 self._backend.set_callback_number,
246 self.error.emit(str(e))
248 self._callback = callback
249 if oldCallback != self._callback:
250 self.callbackNumberChanged.emit(self._callback)
252 def _login(self, username, password):
253 self._loggedInTime = self._LOGGINGIN_TIME
254 self.stateChange.emit(self.LOGGINGIN_STATE)
255 finalState = self.LOGGEDOUT_STATE
259 if not isLoggedIn and self._backend.is_quick_login_possible():
261 self._backend.is_authed,
266 _moduleLogger.info("Logged in through cookies")
268 # Force a clearing of the cookies
270 self._backend.logout,
278 (username, password),
282 _moduleLogger.info("Logged in through credentials")
285 self._loggedInTime = int(time.time())
286 oldUsername = self._username
287 self._username = username
288 finalState = self.LOGGEDIN_STATE
290 if oldUsername != self._username:
291 self._load_from_cache()
292 loginOps = self._loginOps[:]
293 del self._loginOps[:]
294 for asyncOp in loginOps:
297 self.error.emit(str(e))
299 self.stateChange.emit(finalState)
301 def _load_from_cache(self):
302 updateContacts = len(self._contacts) != 0
303 updateMessages = len(self._messages) != 0
304 updateHistory = len(self._history) != 0
306 oldCallback = self._callback
315 self.contactsUpdated.emit()
317 self.messagesUpdated.emit()
319 self.historyUpdated.emit()
320 if oldDnd != self._dnd:
321 self.dndStateChange.emit(self._dnd)
322 if oldCallback != self._callback:
323 self.callbackNumberChanged.emit(self._callback)
325 def _save_to_cache(self):
329 def _clear_cache(self):
330 updateContacts = len(self._contacts) != 0
331 updateMessages = len(self._messages) != 0
332 updateHistory = len(self._history) != 0
334 oldCallback = self._callback
343 self.contactsUpdated.emit()
345 self.messagesUpdated.emit()
347 self.historyUpdated.emit()
348 if oldDnd != self._dnd:
349 self.dndStateChange.emit(self._dnd)
350 if oldCallback != self._callback:
351 self.callbackNumberChanged.emit(self._callback)
353 self._save_to_cache()
355 def _update_contacts(self):
357 self._contacts = yield (
358 self._backend.get_contacts,
363 self.error.emit(str(e))
365 self.contactsUpdated.emit()
367 def _update_messages(self):
369 self._messages = yield (
370 self._backend.get_messages,
375 self.error.emit(str(e))
377 self.messagesUpdated.emit()
379 def _update_history(self):
381 self._history = yield (
382 self._backend.get_recent,
387 self.error.emit(str(e))
389 self.historyUpdated.emit()
391 def _update_dnd(self):
395 self._backend.is_dnd,
400 self.error.emit(str(e))
402 if oldDnd != self._dnd:
403 self.dndStateChange(self._dnd)
405 def _perform_op_while_loggedin(self, op):
406 if self.state == self.LOGGEDIN_STATE:
409 self._push_login_op(op)
411 def _push_login_op(self, asyncOp):
412 assert self.state != self.LOGGEDIN_STATE
413 if asyncOp in self._loginOps:
414 _moduleLogger.info("Skipping queueing duplicate op: %r" % asyncOp)
416 self._loginOps.append(asyncOp)