Mercurial > libervia-web
diff src/browser/sat_browser/plugin_sec_otr.py @ 665:6a8a1103ad10 frontends_multi_profiles
browser_side: OTR uses 'profilePlugged', 'disconnect' and 'gotMenus' listeners
author | souliane <souliane@mailoo.org> |
---|---|
date | Tue, 03 Mar 2015 22:31:54 +0100 |
parents | 8449a5db0602 |
children | 849ffb24d5bf |
line wrap: on
line diff
--- a/src/browser/sat_browser/plugin_sec_otr.py Tue Mar 03 19:00:21 2015 +0100 +++ b/src/browser/sat_browser/plugin_sec_otr.py Tue Mar 03 22:31:54 2015 +0100 @@ -359,6 +359,14 @@ else: return self.contexts.get(other_jid, None) + def getContextsForBareUser(self, bare_jid): + """Get all the contexts for the users sharing the given bare JID. + + @param bare_jid (jid.JID): bare JID + @return: list[Context] + """ + return [context for other_jid, context in self.contexts.iteritems() if other_jid.bare == bare_jid] + def fixResource(self, other_jid): """Return the full JID in case the resource of the given JID is missing. @@ -383,6 +391,13 @@ self.host.trigger.add("newMessageTrigger", self.newMessageTg, priority=TriggerManager.MAX_PRIORITY) self.host.trigger.add("sendMessageTrigger", self.sendMessageTg, priority=TriggerManager.MAX_PRIORITY) + # FIXME: workaround for a pyjamas issue: calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword) + self._profilePluggedListener = self.profilePluggedListener + self._gotMenusListener = self.gotMenusListener + # FIXME: these listeners are never removed, can't be removed by themselves (it modifies the list while looping), maybe need a 'one_shot' argument + self.host.addListener('profilePlugged', self._profilePluggedListener) + self.host.addListener('gotMenus', self._gotMenusListener) + @classmethod def getInfoText(self, state=otr.context.STATE_PLAINTEXT, trust=''): """Get the widget info text for a certain message state and trust. @@ -406,32 +421,45 @@ else: return OTR.getInfoText(otrctx.state, otrctx.getCurrentTrust()) - def inhibitMenus(self): - """Tell the caller which dynamic menus should be inhibited""" - return ["OTR"] # menu categories name to inhibit - - def extraMenus(self): + def gotMenusListener(self, menus, profile): + menus_to_delete = [] + for menu in menus: + id_, type_, path, path_i18n = menu + if path[0] == 'OTR': + menus_to_delete.append(menu) + for menu in menus_to_delete: + menus.remove(menu) # FIXME: handle help strings too - return [(self._startRefresh, C.MENU_SINGLE, (MAIN_MENU, "Start / refresh"), (MAIN_MENU, D_("Start / refresh"))), - (self._endSession, C.MENU_SINGLE, (MAIN_MENU, "Stop encryption"), (MAIN_MENU, D_("Stop encryption"))), - (self._authenticate, C.MENU_SINGLE, (MAIN_MENU, "Authenticate correspondent"), (MAIN_MENU, D_("Authenticate correspondent"))), - (self._dropPrivkey, C.MENU_SINGLE, (MAIN_MENU, "Drop your private key"), (MAIN_MENU, D_("Drop your private key")))] + menus.extend([(self._startRefresh, C.MENU_SINGLE, (MAIN_MENU, "Start / refresh"), (MAIN_MENU, D_("Start / refresh"))), + (self._endSession, C.MENU_SINGLE, (MAIN_MENU, "Stop encryption"), (MAIN_MENU, D_("Stop encryption"))), + (self._authenticate, C.MENU_SINGLE, (MAIN_MENU, "Authenticate correspondent"), (MAIN_MENU, D_("Authenticate correspondent"))), + (self._dropPrivkey, C.MENU_SINGLE, (MAIN_MENU, "Drop your private key"), (MAIN_MENU, D_("Drop your private key"))), + ]) - def profileConnected(self): + def profilePluggedListener(self, profile): + # FIXME: workaround for a pyjamas issue: calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword) + self._presenceListener = self.presenceListener + self._disconnectListener = self.disconnectListener + self.host.addListener('presence', self._presenceListener, [C.PROF_KEY_NONE]) + # FIXME: this listener is never removed, can't be removed by itself (it modifies the list while looping), maybe need a 'one_shot' argument + self.host.addListener('disconnect', self._disconnectListener, [C.PROF_KEY_NONE]) + self.host.bridge.call('skipOTR', None) self.context_manager = ContextManager(self.host) # TODO: retrieve the encrypted private key from a HTML5 persistent storage, # decrypt it, parse it with otr.crypt.PK.parsePrivateKey(privkey) and # assign it to self.context_manager.account.privkey - # FIXME: workaround for a pyjamas issue: calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword) - self.presenceListener = self.onPresenceUpdate - self.host.addListener('presence', self.presenceListener, [C.PROF_KEY_NONE]) + def disconnectListener(self, profile): + """Things to do just before the profile disconnection""" + self.host.removeListener('presence', self._presenceListener) - def profileDisconnected(self): for context in self.context_manager.contexts.values(): - context.disconnect() - self.host.removeListener('presence', self.presenceListener) + context.disconnect() # FIXME: no time to send the message before the profile has been disconnected + + def presenceListener(self, entity, show, priority, statuses, profile): + if show == C.PRESENCE_UNAVAILABLE: + self.endSession(entity, disconnect=False) def newMessageTg(self, from_jid, msg, msg_type, to_jid, extra, profile): if msg_type != C.MESS_TYPE_CHAT: @@ -477,27 +505,26 @@ log.debug(u"sending message unencrypted") return True - def onPresenceUpdate(self, entity, show, priority, statuses, profile): - if show == C.PRESENCE_UNAVAILABLE: - self.endSession(entity, finish=True) - - def endSession(self, other_jid, finish=False): + def endSession(self, other_jid, disconnect=True): """Finish or disconnect an OTR session @param other_jid (jid.JID): other JID - @param finish: if True, finish the session but do not disconnect it - @return: True if the session has been finished or disconnected, False if there was nothing to do + @param disconnect (bool): if False, finish the session but do not disconnect it """ # checking for private key existence is not needed, context checking is enough - otrctx = self.context_manager.getContextForUser(other_jid, start=False) - if otrctx is None or otrctx.state == otr.context.STATE_PLAINTEXT: - if not finish: - self.host.newMessageHandler(unicode(other_jid), END_PLAIN_HAS_NOT.format(jid=other_jid), C.MESS_TYPE_INFO, unicode(self.host.whoami), {}) - return - if finish: - otrctx.finish() - else: - otrctx.disconnect() + if other_jid.resource: + contexts = [self.context_manager.getContextForUser(other_jid, start=False)] + else: # contact disconnected itself so we need to terminate the OTR session but the Chat panel lost its resource + contexts = self.context_manager.getContextsForBareUser(other_jid) + for otrctx in contexts: + if otrctx is None or otrctx.state == otr.context.STATE_PLAINTEXT: + if disconnect: + self.host.newMessageHandler(unicode(other_jid), END_PLAIN_HAS_NOT.format(jid=other_jid), C.MESS_TYPE_INFO, unicode(self.host.whoami), {}) + return + if disconnect: + otrctx.disconnect() + else: + otrctx.finish() # Menu callbacks