2022-06-09 15:33:02 +02:00

142 lines
5.2 KiB
Python

# Slixmpp: The Slick XMPP Library
# Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
# This file is part of Slixmpp.
# See the file LICENSE for copying permission.
import logging
from slixmpp.xmlstream import JID
from slixmpp.exceptions import IqError, IqTimeout
log = logging.getLogger(__name__)
class StaticCaps(object):
"""
Extend the default StaticDisco implementation to provide
support for extended identity information.
"""
def __init__(self, xmpp, static):
"""
Augment the default XEP-0030 static handler object.
Arguments:
static -- The default static XEP-0030 handler object.
"""
self.xmpp = xmpp
self.disco = self.xmpp['xep_0030']
self.caps = self.xmpp['xep_0115']
self.static = static
self.jid_vers = {}
async def supports(self, jid, node, ifrom, data):
"""
Check if a JID supports a given feature.
The data parameter may provide:
feature -- The feature to check for support.
local -- If true, then the query is for a JID/node
combination handled by this Slixmpp instance and
no stanzas need to be sent.
Otherwise, a disco stanza must be sent to the
remove JID to retrieve the info.
cached -- If true, then look for the disco info data from
the local cache system. If no results are found,
send the query as usual. The self.use_cache
setting must be set to true for this option to
be useful. If set to false, then the cache will
be skipped, even if a result has already been
cached. Defaults to false.
"""
feature = data.get('feature', None)
data = {'local': data.get('local', False),
'cached': data.get('cached', True)}
if not feature:
return False
if node in (None, ''):
info = await self.caps.get_caps(jid)
if info and feature in info['features']:
return True
try:
info = await self.disco.get_info(jid=jid, node=node,
ifrom=ifrom, **data)
info = self.disco._wrap(ifrom, jid, info, True)
return feature in info['disco_info']['features']
except IqError:
return False
except IqTimeout:
return None
async def has_identity(self, jid, node, ifrom, data):
"""
Check if a JID has a given identity.
The data parameter may provide:
category -- The category of the identity to check.
itype -- The type of the identity to check.
lang -- The language of the identity to check.
local -- If true, then the query is for a JID/node
combination handled by this Slixmpp instance and
no stanzas need to be sent.
Otherwise, a disco stanza must be sent to the
remove JID to retrieve the info.
cached -- If true, then look for the disco info data from
the local cache system. If no results are found,
send the query as usual. The self.use_cache
setting must be set to true for this option to
be useful. If set to false, then the cache will
be skipped, even if a result has already been
cached. Defaults to false.
"""
identity = (data.get('category', None),
data.get('itype', None),
data.get('lang', None))
data = {'local': data.get('local', False),
'cached': data.get('cached', True)}
trunc = lambda i: (i[0], i[1], i[2])
if node in (None, ''):
info = self.caps.get_caps(jid)
if info and identity in map(trunc, info['identities']):
return True
try:
info = await self.disco.get_info(jid=jid, node=node,
ifrom=ifrom, **data)
info = self.disco._wrap(ifrom, jid, info, True)
return identity in map(trunc, info['disco_info']['identities'])
except IqError:
return False
except IqTimeout:
return None
def cache_caps(self, jid, node, ifrom, data):
verstring = data.get('verstring', None)
info = data.get('info', None)
if not verstring or not info:
return
self.caps.cache.store(verstring, info)
def assign_verstring(self, jid, node, ifrom, data):
if isinstance(jid, JID):
jid = jid.full
self.jid_vers[jid] = data.get('verstring', None)
def get_verstring(self, jid, node, ifrom, data):
return self.jid_vers.get(jid, None)
async def get_caps(self, jid, node, ifrom, data):
verstring = data.get('verstring', None)
if verstring is None:
return None
return self.caps.cache.retrieve(verstring)