comparison sat/core/xmpp.py @ 3715:b9718216a1c0 0.9

merge bookmark 0.9
author Goffi <goffi@goffi.org>
date Wed, 01 Dec 2021 16:13:31 +0100
parents e3dddf65fa88 09f5ac48ffe3
children e52de21873d3
comparison
equal deleted inserted replaced
3714:af09b5aaa5d7 3715:b9718216a1c0
40 from wokkel import client as wokkel_client, disco, xmppim, generic, iwokkel 40 from wokkel import client as wokkel_client, disco, xmppim, generic, iwokkel
41 from wokkel import component 41 from wokkel import component
42 from wokkel import delay 42 from wokkel import delay
43 from sat.core.log import getLogger 43 from sat.core.log import getLogger
44 from sat.core import exceptions 44 from sat.core import exceptions
45 from sat.core import core_types
45 from sat.memory import encryption 46 from sat.memory import encryption
46 from sat.memory import persistent 47 from sat.memory import persistent
47 from sat.tools import xml_tools 48 from sat.tools import xml_tools
48 from sat.tools import utils 49 from sat.tools import utils
49 from sat.tools.common import data_format 50 from sat.tools.common import data_format
81 else: 82 else:
82 return lambda *args, **kwargs: missing 83 return lambda *args, **kwargs: missing
83 return partial(getattr(self.plugin, attr), self.client) 84 return partial(getattr(self.plugin, attr), self.client)
84 85
85 86
86 class SatXMPPEntity: 87 class SatXMPPEntity(core_types.SatXMPPEntity):
87 """Common code for Client and Component""" 88 """Common code for Client and Component"""
88 # profile is added there when startConnection begins and removed when it is finished 89 # profile is added there when startConnection begins and removed when it is finished
89 profiles_connecting = set() 90 profiles_connecting = set()
90 91
91 def __init__(self, host_app, profile, max_retries): 92 def __init__(self, host_app, profile, max_retries):
714 mess_data["message"] or mess_data["subject"] 715 mess_data["message"] or mess_data["subject"]
715 or mess_data["extra"].get(C.MESS_KEY_ATTACHMENTS) 716 or mess_data["extra"].get(C.MESS_KEY_ATTACHMENTS)
716 or mess_data["type"] == C.MESS_TYPE_INFO 717 or mess_data["type"] == C.MESS_TYPE_INFO
717 ) 718 )
718 719
719 def messageAddToHistory(self, data): 720 async def messageAddToHistory(self, data):
720 """Store message into database (for local history) 721 """Store message into database (for local history)
721 722
722 @param data: message data dictionnary 723 @param data: message data dictionnary
723 @param client: profile's client 724 @param client: profile's client
724 """ 725 """
726 # we don't add groupchat message to history, as we get them back 727 # we don't add groupchat message to history, as we get them back
727 # and they will be added then 728 # and they will be added then
728 729
729 # we need a message to store 730 # we need a message to store
730 if self.isMessagePrintable(data): 731 if self.isMessagePrintable(data):
731 self.host_app.memory.addToHistory(self, data) 732 await self.host_app.memory.addToHistory(self, data)
732 else: 733 else:
733 log.warning( 734 log.warning(
734 "No message found" 735 "No message found"
735 ) # empty body should be managed by plugins before this point 736 ) # empty body should be managed by plugins before this point
736 return data 737 return data
876 # we want to be sure that we got the roster 877 # we want to be sure that we got the roster
877 return self.roster.got_roster 878 return self.roster.got_roster
878 879
879 def addPostXmlCallbacks(self, post_xml_treatments): 880 def addPostXmlCallbacks(self, post_xml_treatments):
880 post_xml_treatments.addCallback(self.messageProt.completeAttachments) 881 post_xml_treatments.addCallback(self.messageProt.completeAttachments)
881 post_xml_treatments.addCallback(self.messageAddToHistory) 882 post_xml_treatments.addCallback(
883 lambda ret: defer.ensureDeferred(self.messageAddToHistory(ret))
884 )
882 post_xml_treatments.addCallback(self.messageSendToBridge) 885 post_xml_treatments.addCallback(self.messageSendToBridge)
883 886
884 def send(self, obj): 887 def send(self, obj):
885 # original send method accept string 888 # original send method accept string
886 # but we restrict to domish.Element to make trigger treatments easier 889 # but we restrict to domish.Element to make trigger treatments easier
1061 else: 1064 else:
1062 return start_cb(self) 1065 return start_cb(self)
1063 1066
1064 def addPostXmlCallbacks(self, post_xml_treatments): 1067 def addPostXmlCallbacks(self, post_xml_treatments):
1065 if self.sendHistory: 1068 if self.sendHistory:
1066 post_xml_treatments.addCallback(self.messageAddToHistory) 1069 post_xml_treatments.addCallback(
1070 lambda ret: defer.ensureDeferred(self.messageAddToHistory(ret))
1071 )
1067 1072
1068 def getOwnerFromJid(self, to_jid: jid.JID) -> jid.JID: 1073 def getOwnerFromJid(self, to_jid: jid.JID) -> jid.JID:
1069 """Retrieve "owner" of a component resource from the destination jid of the request 1074 """Retrieve "owner" of a component resource from the destination jid of the request
1070 1075
1071 This method needs plugin XEP-0106 for unescaping, if you use it you must add the 1076 This method needs plugin XEP-0106 for unescaping, if you use it you must add the
1212 if not cont: 1217 if not cont:
1213 return 1218 return
1214 data = self.parseMessage(message_elt) 1219 data = self.parseMessage(message_elt)
1215 post_treat.addCallback(self.completeAttachments) 1220 post_treat.addCallback(self.completeAttachments)
1216 post_treat.addCallback(self.skipEmptyMessage) 1221 post_treat.addCallback(self.skipEmptyMessage)
1217 post_treat.addCallback(self.addToHistory) 1222 post_treat.addCallback(
1223 lambda ret: defer.ensureDeferred(self.addToHistory(ret))
1224 )
1218 post_treat.addCallback(self.bridgeSignal, data) 1225 post_treat.addCallback(self.bridgeSignal, data)
1219 post_treat.addErrback(self.cancelErrorTrap) 1226 post_treat.addErrback(self.cancelErrorTrap)
1220 post_treat.callback(data) 1227 post_treat.callback(data)
1221 1228
1222 def onMessage(self, message_elt): 1229 def onMessage(self, message_elt):
1253 def skipEmptyMessage(self, data): 1260 def skipEmptyMessage(self, data):
1254 if not data["message"] and not data["extra"] and not data["subject"]: 1261 if not data["message"] and not data["extra"] and not data["subject"]:
1255 raise failure.Failure(exceptions.CancelError("Cancelled empty message")) 1262 raise failure.Failure(exceptions.CancelError("Cancelled empty message"))
1256 return data 1263 return data
1257 1264
1258 def addToHistory(self, data): 1265 async def addToHistory(self, data):
1259 if data.pop("history", None) == C.HISTORY_SKIP: 1266 if data.pop("history", None) == C.HISTORY_SKIP:
1260 log.debug("history is skipped as requested") 1267 log.debug("history is skipped as requested")
1261 data["extra"]["history"] = C.HISTORY_SKIP 1268 data["extra"]["history"] = C.HISTORY_SKIP
1262 else: 1269 else:
1263 # we need a message to store 1270 # we need a message to store
1264 if self.parent.isMessagePrintable(data): 1271 if self.parent.isMessagePrintable(data):
1265 return self.host.memory.addToHistory(self.parent, data) 1272 return await self.host.memory.addToHistory(self.parent, data)
1266 else: 1273 else:
1267 log.debug("not storing empty message to history: {data}" 1274 log.debug("not storing empty message to history: {data}"
1268 .format(data=data)) 1275 .format(data=data))
1269 1276
1270 def bridgeSignal(self, __, data): 1277 def bridgeSignal(self, __, data):
1478 except KeyError: 1485 except KeyError:
1479 pass # no previous item registration (or it's been cleared) 1486 pass # no previous item registration (or it's been cleared)
1480 self._jids[entity] = item 1487 self._jids[entity] = item
1481 self._registerItem(item) 1488 self._registerItem(item)
1482 self.host.bridge.newContact( 1489 self.host.bridge.newContact(
1483 entity.full(), self.getAttributes(item), item.groups, self.parent.profile 1490 entity.full(), self.getAttributes(item), list(item.groups),
1491 self.parent.profile
1484 ) 1492 )
1485 1493
1486 def removeReceived(self, request): 1494 def removeReceived(self, request):
1487 entity = request.item.entity 1495 entity = request.item.entity
1488 log.info(_("removing {entity} from roster").format(entity=entity.full())) 1496 log.info(_("removing {entity} from roster").format(entity=entity.full()))
1544 if not isinstance(entity_jid, jid.JID): 1552 if not isinstance(entity_jid, jid.JID):
1545 raise exceptions.InternalError( 1553 raise exceptions.InternalError(
1546 f"a JID is expected, not {type(entity_jid)}: {entity_jid!r}") 1554 f"a JID is expected, not {type(entity_jid)}: {entity_jid!r}")
1547 return entity_jid in self._jids 1555 return entity_jid in self._jids
1548 1556
1549 def isPresenceAuthorised(self, entity_jid): 1557 def isSubscribedFrom(self, entity_jid: jid.JID) -> bool:
1550 """Return True if entity is authorised to see our presence""" 1558 """Return True if entity is authorised to see our presence"""
1551 try: 1559 try:
1552 item = self._jids[entity_jid.userhostJID()] 1560 item = self._jids[entity_jid.userhostJID()]
1553 except KeyError: 1561 except KeyError:
1554 return False 1562 return False
1555 return item.subscriptionFrom 1563 return item.subscriptionFrom
1564
1565 def isSubscribedTo(self, entity_jid: jid.JID) -> bool:
1566 """Return True if we are subscribed to entity"""
1567 try:
1568 item = self._jids[entity_jid.userhostJID()]
1569 except KeyError:
1570 return False
1571 return item.subscriptionTo
1556 1572
1557 def getItems(self): 1573 def getItems(self):
1558 """Return all items of the roster""" 1574 """Return all items of the roster"""
1559 return list(self._jids.values()) 1575 return list(self._jids.values())
1560 1576