comparison sat_frontends/quick_frontend/quick_chat.py @ 2664:e35a265ec174

quick frontend (app, chat): encryption handling: - new QuickApp.ENCRYPTION_HANDLERS class attribute, if True (default), encryption handlers are set - encryption plugins are retrieved on startup and cached in QuickApp.encryption_plugins list - QuickChat's encrypted boolean attribute indicate if a session is currently encrypted. This is updated automatically if ENCRYPTION_HANDLERS is set - if ENCRYPTION_HANDLERS is set, messageEncryptionStarted and messageEncryptionStopped are called when suitable.
author Goffi <goffi@goffi.org>
date Sat, 11 Aug 2018 18:24:55 +0200
parents 96911768b0f3
children b4c0a5bec729
comparison
equal deleted inserted replaced
2663:32b5f68a23b4 2664:e35a265ec174
17 # You should have received a copy of the GNU Affero General Public License 17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 from sat.core.i18n import _ 20 from sat.core.i18n import _
21 from sat.core.log import getLogger 21 from sat.core.log import getLogger
22 22 from sat.tools.common import data_format
23 log = getLogger(__name__)
24 from sat.core import exceptions 23 from sat.core import exceptions
25 from sat_frontends.quick_frontend import quick_widgets 24 from sat_frontends.quick_frontend import quick_widgets
26 from sat_frontends.quick_frontend.constants import Const as C 25 from sat_frontends.quick_frontend.constants import Const as C
27 from collections import OrderedDict 26 from collections import OrderedDict
28 from sat_frontends.tools import jid 27 from sat_frontends.tools import jid
29 import time 28 import time
29 log = getLogger(__name__)
30 30
31 try: 31 try:
32 from locale import getlocale 32 from locale import getlocale
33 except ImportError: 33 except ImportError:
34 # FIXME: pyjamas workaround 34 # FIXME: pyjamas workaround
54 54
55 55
56 class Message(object): 56 class Message(object):
57 """Message metadata""" 57 """Message metadata"""
58 58
59 def __init__( 59 def __init__(self, parent, uid, timestamp, from_jid, to_jid, msg, subject, type_,
60 self, 60 extra, profile):
61 parent,
62 uid,
63 timestamp,
64 from_jid,
65 to_jid,
66 msg,
67 subject,
68 type_,
69 extra,
70 profile,
71 ):
72 self.parent = parent 61 self.parent = parent
73 self.profile = profile 62 self.profile = profile
74 self.uid = uid 63 self.uid = uid
75 self.timestamp = timestamp 64 self.timestamp = timestamp
76 self.from_jid = from_jid 65 self.from_jid = from_jid
267 256
268 257
269 class QuickChat(quick_widgets.QuickWidget): 258 class QuickChat(quick_widgets.QuickWidget):
270 visible_states = ["chat_state"] # FIXME: to be removed, used only in quick_games 259 visible_states = ["chat_state"] # FIXME: to be removed, used only in quick_games
271 260
272 def __init__( 261 def __init__(self, host, target, type_=C.CHAT_ONE2ONE, nick=None, occupants=None,
273 self, 262 subject=None, profiles=None):
274 host, 263 """
275 target, 264 @param type_: can be C.CHAT_ONE2ONE for single conversation or C.CHAT_GROUP for
276 type_=C.CHAT_ONE2ONE, 265 chat à la IRC
277 nick=None,
278 occupants=None,
279 subject=None,
280 profiles=None,
281 ):
282 """
283 @param type_: can be C.CHAT_ONE2ONE for single conversation or C.CHAT_GROUP for chat à la IRC
284 """ 266 """
285 self.lang = "" # default language to use for messages 267 self.lang = "" # default language to use for messages
286 quick_widgets.QuickWidget.__init__(self, host, target, profiles=profiles) 268 quick_widgets.QuickWidget.__init__(self, host, target, profiles=profiles)
287 self._locked = True # True when we are waiting for history/search 269 self._locked = True # True when we are waiting for history/search
288 # messageNew signals are cached when locked 270 # messageNew signals are cached when locked
289 self._cache = OrderedDict() 271 self._cache = OrderedDict()
290 assert type_ in (C.CHAT_ONE2ONE, C.CHAT_GROUP) 272 assert type_ in (C.CHAT_ONE2ONE, C.CHAT_GROUP)
291 self.current_target = target 273 self.current_target = target
292 self.type = type_ 274 self.type = type_
275 self.encrypted = False # True if this session is currently encrypted
293 if type_ == C.CHAT_GROUP: 276 if type_ == C.CHAT_GROUP:
294 if target.resource: 277 if target.resource:
295 raise exceptions.InternalError( 278 raise exceptions.InternalError(
296 u"a group chat entity can't have a resource" 279 u"a group chat entity can't have a resource"
297 ) 280 )
330 handle the display of history and subject 313 handle the display of history and subject
331 """ 314 """
332 self.historyPrint(profile=self.profile) 315 self.historyPrint(profile=self.profile)
333 if self.subject is not None: 316 if self.subject is not None:
334 self.setSubject(self.subject) 317 self.setSubject(self.subject)
318 if self.host.ENCRYPTION_HANDLERS:
319 self.getEncryptionState()
335 320
336 def onDelete(self): 321 def onDelete(self):
337 if self.host.AVATARS_HANDLER: 322 if self.host.AVATARS_HANDLER:
338 self.host.removeListener("avatar", self.onAvatar) 323 self.host.removeListener("avatar", self.onAvatar)
339 324
563 profile, 548 profile,
564 callback=_historyGetCb, 549 callback=_historyGetCb,
565 errback=_historyGetEb, 550 errback=_historyGetEb,
566 ) 551 )
567 552
568 def messageNew( 553 def messageEncryptionGetCb(self, session_data):
569 self, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile 554 if session_data:
570 ): 555 session_data = data_format.deserialise(session_data)
556 self.messageEncryptionStarted(session_data)
557
558 def messageEncryptionGetEb(self, failure_):
559 log.error(_(u"Can't get encryption state: {reason}").format(reason=failure_))
560
561 def getEncryptionState(self):
562 """Retrieve encryption state with current target.
563
564 Once state is retrieved, default messageEncryptionStarted will be called if
565 suitable
566 """
567 self.host.bridge.messageEncryptionGet(self.target, self.profile,
568 callback=self.messageEncryptionGetCb,
569 errback=self.messageEncryptionGetEb)
570
571
572 def messageNew(self, uid, timestamp, from_jid, to_jid, msg, subject, type_, extra,
573 profile):
571 if self._locked: 574 if self._locked:
572 self._cache[uid] = ( 575 self._cache[uid] = (
573 uid, 576 uid,
574 timestamp, 577 timestamp,
575 from_jid, 578 from_jid,
581 profile, 584 profile,
582 ) 585 )
583 return 586 return
584 if self.type == C.CHAT_GROUP: 587 if self.type == C.CHAT_GROUP:
585 if to_jid.resource and type_ != C.MESS_TYPE_GROUPCHAT: 588 if to_jid.resource and type_ != C.MESS_TYPE_GROUPCHAT:
586 # we have a private message, we forward it to a private conversation widget 589 # we have a private message, we forward it to a private conversation
590 # widget
587 chat_widget = self.getOrCreatePrivateWidget(to_jid) 591 chat_widget = self.getOrCreatePrivateWidget(to_jid)
588 chat_widget.messageNew( 592 chat_widget.messageNew(
589 uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile 593 uid, timestamp, from_jid, to_jid, msg, subject, type_, extra, profile
590 ) 594 )
591 return 595 return
610 614
611 if "received_timestamp" in extra: 615 if "received_timestamp" in extra:
612 log.warning(u"Delayed message received after history, this should not happen") 616 log.warning(u"Delayed message received after history, this should not happen")
613 self.createMessage(message) 617 self.createMessage(message)
614 618
619 def messageEncryptionStarted(self, session_data):
620 self.encrypted = True
621 log.debug(_(u"message encryption started with {target} using {encryption}").format(
622 target=self.target, encryption=session_data[u'name']))
623
624 def messageEncryptionStopped(self, session_data):
625 self.encrypted = False
626 log.debug(_(u"message encryption stopped with {target} (was using {encryption})")
627 .format(target=self.target, encryption=session_data[u'name']))
628
615 def createMessage(self, message, append=False): 629 def createMessage(self, message, append=False):
616 """Must be implemented by frontend to create and show a new message widget 630 """Must be implemented by frontend to create and show a new message widget
617 631
618 This is only called on messageNew, not on history. 632 This is only called on messageNew, not on history.
619 You need to override historyPrint to handle the later 633 You need to override historyPrint to handle the later