comparison src/plugins/plugin_sec_otr.py @ 1963:a2bc5089c2eb

backend, frontends: message refactoring (huge commit): /!\ several features are temporarily disabled, like notifications in frontends next step in refactoring, with the following changes: - jp: updated jp message to follow changes in backend/bridge - jp: added --lang, --subject, --subject_lang, and --type options to jp message + fixed unicode handling for jid - quick_frontend (QuickApp, QuickChat): - follow backend changes - refactored chat, message are now handled in OrderedDict and uid are kept so they can be updated - Message and Occupant classes handle metadata, so frontend just have to display them - Primitivus (Chat): - follow backend/QuickFrontend changes - info & standard messages are handled in the same MessageWidget class - improved/simplified handling of messages, removed update() method - user joined/left messages are merged when next to each other - a separator is shown when message is received while widget is out of focus, so user can quickly see the new messages - affiliation/role are shown (in a basic way for now) in occupants panel - removed "/me" messages handling, as it will be done by a backend plugin - message language is displayed when available (only one language per message for now) - fixed :history and :search commands - core (constants): new constants for messages type, XML namespace, entity type - core: *Message methods renamed to follow new code sytle (e.g. sendMessageToBridge => messageSendToBridge) - core (messages handling): fixed handling of language - core (messages handling): mes_data['from'] and ['to'] are now jid.JID - core (core.xmpp): reorganised message methods, added getNick() method to client.roster - plugin text commands: fixed plugin and adapted to new messages behaviour. client is now used in arguments instead of profile - plugins: added information for cancellation reason in CancelError calls - plugin XEP-0045: various improvments, but this plugin still need work: - trigger is used to avoid message already handled by the plugin to be handled a second time - changed the way to handle history, the last message from DB is checked and we request only messages since this one, in seconds (thanks Poezio folks :)) - subject reception is waited before sending the roomJoined signal, this way we are sure that everything including history is ready - cmd_* method now follow the new convention with client instead of profile - roomUserJoined and roomUserLeft messages are removed, the events are now handled with info message with a "ROOM_USER_JOINED" info subtype - probably other forgotten stuffs :p
author Goffi <goffi@goffi.org>
date Mon, 20 Jun 2016 18:41:53 +0200
parents 633b5c21aefd
children 200cd707a46d
comparison
equal deleted inserted replaced
1962:a45235d8dc93 1963:a2bc5089c2eb
207 self.host = host 207 self.host = host
208 self.context_managers = {} 208 self.context_managers = {}
209 self.skipped_profiles = set() 209 self.skipped_profiles = set()
210 host.trigger.add("MessageReceived", self.MessageReceivedTrigger, priority=100000) 210 host.trigger.add("MessageReceived", self.MessageReceivedTrigger, priority=100000)
211 host.trigger.add("messageSend", self.messageSendTrigger, priority=100000) 211 host.trigger.add("messageSend", self.messageSendTrigger, priority=100000)
212 host.bridge.addMethod("skipOTR", ".plugin", in_sign='s', out_sign='', method=self._skipOTR) 212 host.bridge.addMethod("skipOTR", ".plugin", in_sign='s', out_sign='', method=self._skipOTR) # FIXME: must be removed, must be done on per-message basis
213 host.importMenu((MAIN_MENU, D_("Start/Refresh")), self._startRefresh, security_limit=0, help_string=D_("Start or refresh an OTR session"), type_=C.MENU_SINGLE) 213 host.importMenu((MAIN_MENU, D_("Start/Refresh")), self._startRefresh, security_limit=0, help_string=D_("Start or refresh an OTR session"), type_=C.MENU_SINGLE)
214 host.importMenu((MAIN_MENU, D_("End session")), self._endSession, security_limit=0, help_string=D_("Finish an OTR session"), type_=C.MENU_SINGLE) 214 host.importMenu((MAIN_MENU, D_("End session")), self._endSession, security_limit=0, help_string=D_("Finish an OTR session"), type_=C.MENU_SINGLE)
215 host.importMenu((MAIN_MENU, D_("Authenticate")), self._authenticate, security_limit=0, help_string=D_("Authenticate user/see your fingerprint"), type_=C.MENU_SINGLE) 215 host.importMenu((MAIN_MENU, D_("Authenticate")), self._authenticate, security_limit=0, help_string=D_("Authenticate user/see your fingerprint"), type_=C.MENU_SINGLE)
216 host.importMenu((MAIN_MENU, D_("Drop private key")), self._dropPrivKey, security_limit=0, type_=C.MENU_SINGLE) 216 host.importMenu((MAIN_MENU, D_("Drop private key")), self._dropPrivKey, security_limit=0, type_=C.MENU_SINGLE)
217 host.trigger.add("presenceReceived", self._presenceReceivedTrigger) 217 host.trigger.add("presenceReceived", self._presenceReceivedTrigger)
235 def _skipOTR(self, profile): 235 def _skipOTR(self, profile):
236 """Tell the backend to not handle OTR for this profile. 236 """Tell the backend to not handle OTR for this profile.
237 237
238 @param profile (str): %(doc_profile)s 238 @param profile (str): %(doc_profile)s
239 """ 239 """
240 # FIXME: should not be done per profile but per message, using extra data
241 # for message received, profile wide hook may be need, but client
242 # should be used anyway instead of a class attribute
240 self.skipped_profiles.add(profile) 243 self.skipped_profiles.add(profile)
241 244
242 @defer.inlineCallbacks 245 @defer.inlineCallbacks
243 def profileConnected(self, profile): 246 def profileConnected(self, profile):
244 if profile in self.skipped_profiles: 247 if profile in self.skipped_profiles:
404 407
405 confirm = xml_tools.XMLUI(C.XMLUI_DIALOG, title=_('Confirm private key drop'), dialog_opt = {'type': C.XMLUI_DIALOG_CONFIRM, 'message': _(DROP_TXT)}, submit_id = submit_id) 408 confirm = xml_tools.XMLUI(C.XMLUI_DIALOG, title=_('Confirm private key drop'), dialog_opt = {'type': C.XMLUI_DIALOG_CONFIRM, 'message': _(DROP_TXT)}, submit_id = submit_id)
406 return {'xmlui': confirm.toXml()} 409 return {'xmlui': confirm.toXml()}
407 410
408 def _receivedTreatment(self, data, profile): 411 def _receivedTreatment(self, data, profile):
409 from_jid = jid.JID(data['from']) 412 from_jid = data['from']
410 log.debug(u"_receivedTreatment [from_jid = %s]" % from_jid) 413 log.debug(u"_receivedTreatment [from_jid = %s]" % from_jid)
411 otrctx = self.context_managers[profile].getContextForUser(from_jid) 414 otrctx = self.context_managers[profile].getContextForUser(from_jid)
412 encrypted = True 415 encrypted = True
413 416
414 try: 417 try:
435 # decrypted messages handling. 438 # decrypted messages handling.
436 # receiveMessage() will return a tuple, the first part of which will be the decrypted message 439 # receiveMessage() will return a tuple, the first part of which will be the decrypted message
437 data['message'] = {'':res[0].decode('utf-8')} # FIXME: Q&D fix for message refactoring, message is now a dict 440 data['message'] = {'':res[0].decode('utf-8')} # FIXME: Q&D fix for message refactoring, message is now a dict
438 raise failure.Failure(exceptions.SkipHistory()) # we send the decrypted message to frontends, but we don't want it in history 441 raise failure.Failure(exceptions.SkipHistory()) # we send the decrypted message to frontends, but we don't want it in history
439 else: 442 else:
440 raise failure.Failure(exceptions.CancelError()) # no message at all (no history, no signal) 443 raise failure.Failure(exceptions.CancelError('Cancelled by OTR')) # no message at all (no history, no signal)
441 444
442 def _receivedTreatmentForSkippedProfiles(self, data, profile): 445 def _receivedTreatmentForSkippedProfiles(self, data, profile):
443 """This profile must be skipped because the frontend manages OTR itself, 446 """This profile must be skipped because the frontend manages OTR itself,
444 but we still need to check if the message must be stored in history or not""" 447 but we still need to check if the message must be stored in history or not"""
445 try: 448 try:
448 return data 451 return data
449 if message.startswith(potr.proto.OTRTAG): 452 if message.startswith(potr.proto.OTRTAG):
450 raise failure.Failure(exceptions.SkipHistory()) 453 raise failure.Failure(exceptions.SkipHistory())
451 return data 454 return data
452 455
453 def MessageReceivedTrigger(self, client, message, post_treat): 456 def MessageReceivedTrigger(self, client, message_elt, post_treat):
454 profile = client.profile 457 profile = client.profile
455 if profile in self.skipped_profiles: 458 if profile in self.skipped_profiles:
456 post_treat.addCallback(self._receivedTreatmentForSkippedProfiles, profile) 459 post_treat.addCallback(self._receivedTreatmentForSkippedProfiles, profile)
457 else: 460 else:
458 post_treat.addCallback(self._receivedTreatment, profile) 461 post_treat.addCallback(self._receivedTreatment, profile)
476 msg = mess_data['message'].itervalues().next() 479 msg = mess_data['message'].itervalues().next()
477 except StopIteration: 480 except StopIteration:
478 log.warning(u"No message found") 481 log.warning(u"No message found")
479 return False 482 return False
480 otrctx.sendMessage(0, msg.encode('utf-8')) 483 otrctx.sendMessage(0, msg.encode('utf-8'))
481 self.host.sendMessageToBridge(mess_data, client) 484 self.host.messageSendToBridge(mess_data, client)
482 else: 485 else:
483 feedback = D_("Your message was not sent because your correspondent closed the encrypted conversation on his/her side. Either close your own side, or refresh the session.") 486 feedback = D_("Your message was not sent because your correspondent closed the encrypted conversation on his/her side. Either close your own side, or refresh the session.")
484 self.host.bridge.messageNew(to_jid.full(), 487 self.host.bridge.messageNew(to_jid.full(),
485 feedback, 488 feedback,
486 mess_type=C.MESS_TYPE_INFO, 489 mess_type=C.MESS_TYPE_INFO,