diff --git a/src/memory/disco.py b/src/memory/disco.py index 2887a4a9..e751c57f 100755 --- a/src/memory/disco.py +++ b/src/memory/disco.py @@ -104,57 +104,56 @@ class Discovery(object): return self.hashes.load() @defer.inlineCallbacks - def hasFeature(self, feature, jid_=None, profile=C.PROF_KEY_NONE): + def hasFeature(self, client, feature, jid_=None, node=u''): """Tell if an entity has the required feature @param feature: feature namespace @param jid_: jid of the target, or None for profile's server - @param profile: %(doc_profile)s + @param node(unicode): optional node to use for disco request @return: a Deferred which fire a boolean (True if feature is available) """ - disco_infos = yield self.getInfos(jid_, profile) + disco_infos = yield self.getInfos(client, jid_, node) defer.returnValue(feature in disco_infos.features) @defer.inlineCallbacks - def checkFeature(self, feature, jid_=None, profile=C.PROF_KEY_NONE): + def checkFeature(self, client, feature, jid_=None, node=u''): """Like hasFeature, but raise an exception is feature is not Found @param feature: feature namespace @param jid_: jid of the target, or None for profile's server - @param profile: %(doc_profile)s + @param node(unicode): optional node to use for disco request @raise: exceptions.FeatureNotFound """ - disco_infos = yield self.getInfos(jid_, profile) + disco_infos = yield self.getInfos(client, jid_, node) if not feature in disco_infos.features: raise failure.Failure(exceptions.FeatureNotFound) @defer.inlineCallbacks - def checkFeatures(self, features, jid_=None, identity=None, profile=C.PROF_KEY_NONE): + def checkFeatures(self, client, features, jid_=None, identity=None, node=u''): """Like checkFeature, but check several features at once, and check also identity @param features(iterable[unicode]): features to check @param jid_(jid.JID): jid of the target, or None for profile's server + @param node(unicode): optional node to use for disco request @param identity(None, tuple(unicode, unicode): if not None, the entity must have an identity with this (category, type) tuple - @param profile: %(doc_profile)s @raise: exceptions.FeatureNotFound """ - disco_infos = yield self.getInfos(jid_, profile) + disco_infos = yield self.getInfos(client, jid_, node) if not set(features).issubset(disco_infos.features): raise failure.Failure(exceptions.FeatureNotFound()) if identity is not None and identity not in disco_infos.identities: raise failure.Failure(exceptions.FeatureNotFound()) - def getInfos(self, jid_=None, profile=C.PROF_KEY_NONE): + def getInfos(self, client, jid_=None, node=u''): """get disco infos from jid_, filling capability hash if needed @param jid_: jid of the target, or None for profile's server - @param profile: %(doc_profile)s + @param node(unicode): optional node to use for disco request @return: a Deferred which fire disco.DiscoInfo """ - client = self.host.getClient(profile) if jid_ is None: jid_ = jid.JID(client.jid.host) try: @@ -178,7 +177,7 @@ class Discovery(object): self.host.memory.updateEntityData(jid_, C.ENTITY_CAP_HASH, CAP_HASH_ERROR, profile_key=client.profile) disco_infos = self.hashes[CAP_HASH_ERROR] return disco_infos - d = client.disco.requestInfo(jid_) + d = client.disco.requestInfo(jid_, nodeIdentifier=node) d.addCallback(infosCb) d.addErrback(infosEb) return d @@ -187,15 +186,13 @@ class Discovery(object): return defer.succeed(disco_infos) @defer.inlineCallbacks - def getItems(self, jid_=None, nodeIdentifier='', profile=C.PROF_KEY_NONE): + def getItems(self, client, jid_=None, node=u''): """get disco items from jid_, cache them for our own server - @param jid_ (jid.JID): jid of the target, or None for profile's server - @param nodeIdentifier (str): optional node identifier - @param profile: %(doc_profile)s + @param jid_(jid.JID): jid of the target, or None for profile's server + @param node(unicode): optional node to use for disco request @return: a Deferred which fire disco.DiscoItems """ - client = self.host.getClient(profile) if jid_ is None: jid_ = jid.JID(client.jid.host) # we cache items only for our own server @@ -204,11 +201,11 @@ class Discovery(object): log.debug(u"[%s] disco items are in cache" % jid_.full()) except (KeyError, exceptions.UnknownEntityError): log.debug(u"Caching [%s] disco items" % jid_.full()) - items = yield client.disco.requestItems(jid_, nodeIdentifier) + items = yield client.disco.requestItems(jid_, nodeIdentifier=node) self.host.memory.updateEntityData(jid_, "DISCO_ITEMS", items, profile_key=client.profile) else: try: - items = yield client.disco.requestItems(jid_, nodeIdentifier) + items = yield client.disco.requestItems(jid_, nodeIdentifier=node) except StanzaError as e: log.warning(u"Error while requesting items for {jid}: {reason}" .format(jid=jid_.full(), reason=e.condition)) @@ -222,13 +219,12 @@ class Discovery(object): log.warning(_(u"Error while requesting [%(jid)s]: %(error)s") % {'jid': entity_jid.full(), 'error': failure_.getErrorMessage()}) - def findServiceEntities(self, category, type_, jid_=None, profile=C.PROF_KEY_NONE): + def findServiceEntities(self, client, category, type_, jid_=None): """Return all available items of an entity which correspond to (category, type_) @param category: identity's category @param type_: identitiy's type @param jid_: the jid of the target server (None for profile's server) - @param profile: %(doc_profile)s @return: a set of found entities @raise defer.CancelledError: the request timed out """ @@ -241,18 +237,18 @@ class Discovery(object): def gotItems(items): defers_list = [] for item in items: - info_d = self.getInfos(item.entity, profile) + info_d = self.getInfos(client, item.entity) info_d.addCallbacks(infosCb, self._infosEb, [item.entity], None, [item.entity]) defers_list.append(info_d) return defer.DeferredList(defers_list) - d = self.getItems(jid_, profile=profile) + d = self.getItems(client, jid_) d.addCallback(gotItems) d.addCallback(lambda dummy: found_entities) reactor.callLater(TIMEOUT, d.cancel) # FIXME: one bad service make a general timeout return d - def findFeaturesSet(self, features, identity=None, jid_=None, profile=C.PROF_KEY_NONE): + def findFeaturesSet(self, client, features, identity=None, jid_=None): """Return entities (including jid_ and its items) offering features @param features: iterable of features which must be present @@ -261,7 +257,6 @@ class Discovery(object): @param profile: %(doc_profile)s @return: a set of found entities """ - client = self.host.getClient(profile) if jid_ is None: jid_ = jid.JID(client.jid.host) features = set(features) @@ -276,12 +271,12 @@ class Discovery(object): def gotItems(items): defer_list = [] for entity in [jid_] + [item.entity for item in items]: - infos_d = self.getInfos(entity, profile) + infos_d = self.getInfos(client, entity) infos_d.addCallbacks(infosCb, self._infosEb, [entity], None, [entity]) defer_list.append(infos_d) return defer.DeferredList(defer_list) - d = self.getItems(jid_, profile=profile) + d = self.getItems(client, jid_) d.addCallback(gotItems) d.addCallback(lambda dummy: found_entities) reactor.callLater(TIMEOUT, d.cancel) # FIXME: one bad service make a general timeout @@ -319,9 +314,9 @@ class Discovery(object): @return: list of tuples """ - profile = self.host.memory.getProfileName(profile_key) + client = self.host.getClient(profile_key) entity = jid.JID(entity_jid_s) - disco_infos = yield self.getInfos(entity, profile) + disco_infos = yield self.getInfos(client, entity) extensions = {} for form_type, form in disco_infos.extensions.items(): fields = [] @@ -341,20 +336,26 @@ class Discovery(object): [(cat, type_, name or '') for (cat, type_), name in disco_infos.identities.items()], extensions)) + def items2tuples(self, disco_items): + """convert disco items to tuple of strings + + @param disco_items(iterable[disco.DiscoItem]): items + @return G(tuple[unicode,unicode,unicode]): serialised items + """ + for item in disco_items: + if not item.entity: + log.warning(_(u"invalid item (no jid)")) + continue + yield (item.entity.full(), item.nodeIdentifier or '', item.name or '') + @defer.inlineCallbacks def _discoItems(self, entity_jid_s, profile_key=C.PROF_KEY_NONE): """ Discovery method for the bridge + @param entity_jid_s: entity we want to discover - @return: list of tuples""" - profile = self.host.memory.getProfileName(profile_key) + client = self.host.getClient(profile_key) entity = jid.JID(entity_jid_s) - disco_items = yield self.getItems(entity, profile=profile) - try: - ret = [(item.entity.full(), item.nodeIdentifier or '', item.name or '') for item in disco_items] - except AttributeError: - log.error(u"error while getting items from {entity}, it may result from invalid item(s)".format(entity=entity.full())) - # second try by ignoring empty items - ret = [(item.entity.full(), item.nodeIdentifier or '', item.name or '') for item in disco_items if item.entity] - + disco_items = yield self.getItems(client, entity) + ret = list(self.items2tuples(disco_items)) defer.returnValue(ret) diff --git a/src/plugins/plugin_misc_file.py b/src/plugins/plugin_misc_file.py index f5b2e15c..ec4b87d6 100644 --- a/src/plugins/plugin_misc_file.py +++ b/src/plugins/plugin_misc_file.py @@ -211,12 +211,13 @@ class FilePlugin(object): @param profile: %(doc_profile)s @return (dict): action dictionary, with progress id in case of success, else xmlui message """ + client = self.host.getClient(profile) if not os.path.isfile(filepath): raise exceptions.DataError(u"The given path doesn't link to a file") if not filename: filename = os.path.basename(filepath) or '_' for namespace, callback, priority, method_name in self._file_callbacks: - has_feature = yield self.host.hasFeature(namespace, peer_jid, profile) + has_feature = yield self.host.hasFeature(client, namespace, peer_jid) if has_feature: log.info(u"{name} method will be used to send the file".format(name=method_name)) progress_id = yield callback(peer_jid, filepath, filename, file_desc, profile) diff --git a/src/plugins/plugin_misc_groupblog.py b/src/plugins/plugin_misc_groupblog.py index 1314c7b1..eb47a324 100755 --- a/src/plugins/plugin_misc_groupblog.py +++ b/src/plugins/plugin_misc_groupblog.py @@ -71,7 +71,7 @@ class GroupBlog(object): @defer.inlineCallbacks def profileConnected(self, client): try: - yield self.host.checkFeatures((NS_PUBSUB_GROUPBLOG,), profile=client.profile) + yield self.host.checkFeatures(client, (NS_PUBSUB_GROUPBLOG,)) except exceptions.FeatureNotFound: client.server_groupblog_available = False log.warning(_(u"Server is not able to manage item-access pubsub, we can't use group blog")) diff --git a/src/plugins/plugin_misc_ip.py b/src/plugins/plugin_misc_ip.py index 014edbc4..91c71d0d 100644 --- a/src/plugins/plugin_misc_ip.py +++ b/src/plugins/plugin_misc_ip.py @@ -254,8 +254,10 @@ class IPPlugin(object): if self._external_ip_cache is not None: defer.returnValue(self._external_ip_cache) + client = self.host.getClient(profile) + # we first try with XEP-0279 - ip_check = yield self.host.hasFeature(NS_IP_CHECK, profile=profile) + ip_check = yield self.host.hasFeature(client, NS_IP_CHECK) if ip_check: log.debug(u"Server IP Check available, we use it to retrieve our IP") client = self.host.getClient(profile) diff --git a/src/plugins/plugin_xep_0033.py b/src/plugins/plugin_xep_0033.py index c6c0105f..243a1778 100644 --- a/src/plugins/plugin_xep_0033.py +++ b/src/plugins/plugin_xep_0033.py @@ -101,7 +101,7 @@ class XEP_0033(object): self.sendAndStoreMessage(mess_data, entries, profile) log.debug("XEP-0033 took over") raise failure.Failure(exceptions.CancelError(u'Cancelled by XEP-0033')) - d = self.host.findFeaturesSet([NS_ADDRESS], profile=profile) + d = self.host.findFeaturesSet(client, [NS_ADDRESS]) d.addCallbacks(discoCallback, lambda dummy: discoCallback(None)) return d @@ -121,8 +121,8 @@ class XEP_0033(object): - redesign the database to save only one entry to the database - change the messageNew signal to eventually pass more than one recipient """ + client = self.host.getClient(profile) def send(mess_data, skip_send=False): - client = self.host.profiles[profile] d = defer.Deferred() if not skip_send: d.addCallback(client.sendMessageData) @@ -156,7 +156,7 @@ class XEP_0033(object): defer_list = [] for type_, jid_ in entries: d = defer.Deferred() - d.addCallback(self.host.findFeaturesSet, jid_=JID(JID(jid_).host), profile=profile) + d.addCallback(self.host.findFeaturesSet, client=client, jid_=JID(JID(jid_).host)) d.addCallbacks(discoCallback, errback, callbackArgs=[jid_], errbackArgs=[jid_]) d.callback([NS_ADDRESS]) defer_list.append(d) diff --git a/src/plugins/plugin_xep_0045.py b/src/plugins/plugin_xep_0045.py index e4b11ca6..ee4a4f07 100755 --- a/src/plugins/plugin_xep_0045.py +++ b/src/plugins/plugin_xep_0045.py @@ -362,8 +362,9 @@ class XEP_0045(object): @param jid_: entity which may have a MUC service, or None for our own server @param profile: %(doc_profile)s """ + client = self.host.getClient(profile) muc_service = None - services = yield self.host.findServiceEntities("conference", "text", jid_, profile=profile) + services = yield self.host.findServiceEntities(client, "conference", "text", jid_) for service in services: if ".irc." not in service.userhost(): # FIXME: @@ -712,7 +713,7 @@ class XEP_0045(object): msg = D_(u"{} is not a valid JID!".format(unparsed)) self.text_cmds.feedBack(client, msg, mess_data) return False - d = self.host.getDiscoItems(service, profile=client.profile) + d = self.host.getDiscoItems(client, service) d.addCallback(self._showListUI, client, service) return False diff --git a/src/plugins/plugin_xep_0055.py b/src/plugins/plugin_xep_0055.py index fcee095e..2fe98452 100644 --- a/src/plugins/plugin_xep_0055.py +++ b/src/plugins/plugin_xep_0055.py @@ -85,7 +85,8 @@ class XEP_0055(object): @param profile (unicode): %(doc_profile)s @return: list[jid.JID] """ - d = self.host.findFeaturesSet([NS_SEARCH], profile=profile) + client = self.host.getClient(profile) + d = self.host.findFeaturesSet(client, [NS_SEARCH]) return d.addCallback(lambda set_: list(set_)) diff --git a/src/plugins/plugin_xep_0060.py b/src/plugins/plugin_xep_0060.py index a63afc04..a4730689 100755 --- a/src/plugins/plugin_xep_0060.py +++ b/src/plugins/plugin_xep_0060.py @@ -100,7 +100,7 @@ class XEP_0060(object): @defer.inlineCallbacks def profileConnected(self, client): - pubsub_services = yield self.host.findServiceEntities("pubsub", "service", profile=client.profile) + pubsub_services = yield self.host.findServiceEntities(client, "pubsub", "service") if pubsub_services: # we use one of the found services as our default pubsub service client.pubsub_service = pubsub_services.pop() @@ -228,7 +228,8 @@ class XEP_0060(object): # @param profile (str): %(doc_profile)s # @return: deferred which fire a list of nodes # """ - # d = self.host.getDiscoItems(service, nodeIdentifier, profile_key=profile) + # client = self.host.getClient(profile) + # d = self.host.getDiscoItems(client, service, nodeIdentifier) # d.addCallback(lambda result: [item.getAttribute('node') for item in result.toElement().children if item.hasAttribute('node')]) # return d diff --git a/src/plugins/plugin_xep_0065.py b/src/plugins/plugin_xep_0065.py index fe4a9ea9..889d3724 100755 --- a/src/plugins/plugin_xep_0065.py +++ b/src/plugins/plugin_xep_0065.py @@ -770,7 +770,7 @@ class XEP_0065(object): except KeyError: pass try: - proxy = (yield self.host.findServiceEntities('proxy', 'bytestreams', profile=profile)).pop() + proxy = (yield self.host.findServiceEntities(client, 'proxy', 'bytestreams')).pop() except (defer.CancelledError, StopIteration): notFound(server) iq_elt = client.IQ('get') diff --git a/src/plugins/plugin_xep_0092.py b/src/plugins/plugin_xep_0092.py index 9609305d..26b34196 100644 --- a/src/plugins/plugin_xep_0092.py +++ b/src/plugins/plugin_xep_0092.py @@ -78,7 +78,7 @@ class XEP_0092(object): d = iq_elt.send() d.addCallback(self._gotVersion) return d - d = self.host.checkFeature(NS_VERSION, jid_, client.profile) + d = self.host.checkFeature(client, NS_VERSION, jid_) d.addCallback(getVersion) reactor.callLater(TIMEOUT, d.cancel) # XXX: timeout needed because some clients don't answer the IQ return d diff --git a/src/plugins/plugin_xep_0115.py b/src/plugins/plugin_xep_0115.py index ed8882c1..2e7e24b8 100755 --- a/src/plugins/plugin_xep_0115.py +++ b/src/plugins/plugin_xep_0115.py @@ -66,7 +66,7 @@ class XEP_0115(object): client.caps_optimize = None if XEP_0115.cap_hash is None: - disco_d.addCallback(lambda dummy: self.host.hasFeature(NS_CAPS_OPTIMIZE, profile=profile)) + disco_d.addCallback(lambda dummy: self.host.hasFeature(client, NS_CAPS_OPTIMIZE)) def updateOptimize(optimize): client.caps_optimize = optimize if optimize: @@ -163,6 +163,6 @@ class XEP_0115_handler(XMPPHandler): msg = failure.value.condition if hasattr(failure.value, 'condition') else failure.getErrorMessage() log.error(_(u"Couldn't retrieve disco info for {jid}: {error}").format(jid=from_jid.full(), error=msg)) - d = self.host.getDiscoInfos(from_jid, self.profile) + d = self.host.getDiscoInfos(self.parent, from_jid) d.addCallbacks(cb, eb) # TODO: me must manage the full algorithm described at XEP-0115 #5.4 part 3 diff --git a/src/plugins/plugin_xep_0260.py b/src/plugins/plugin_xep_0260.py index ec99efea..e301be21 100644 --- a/src/plugins/plugin_xep_0260.py +++ b/src/plugins/plugin_xep_0260.py @@ -447,7 +447,7 @@ class XEP_0260(object): log.warning(u"Jingle IBB (XEP-0261) plugin is not available, we have to close the session") self._j.terminate(self._j.REASON_CONNECTIVITY_ERROR, session, client.profile) else: - d = self.host.hasFeature(self._jingle_ibb.NAMESPACE, session['peer_jid'], client.profile) + d = self.host.hasFeature(client, self._jingle_ibb.NAMESPACE, session['peer_jid']) d.addCallback(self._doFallback, session, content_name, client) return d diff --git a/src/plugins/plugin_xep_0277.py b/src/plugins/plugin_xep_0277.py index cf58f705..3a58bf60 100755 --- a/src/plugins/plugin_xep_0277.py +++ b/src/plugins/plugin_xep_0277.py @@ -105,7 +105,8 @@ class XEP_0277(object): return {'available': C.BOOL_FALSE} def getFeatures(self, profile): - d = self.host.checkFeatures([], identity=('pubsub', 'pep'), profile=profile) + client = self.host.getClient(profile) + d = self.host.checkFeatures(client, [], identity=('pubsub', 'pep')) d.addCallbacks(self._checkFeaturesCb, self._checkFeaturesEb) return d diff --git a/src/plugins/plugin_xep_0280.py b/src/plugins/plugin_xep_0280.py index 30323ac9..e27f5e54 100755 --- a/src/plugins/plugin_xep_0280.py +++ b/src/plugins/plugin_xep_0280.py @@ -99,7 +99,7 @@ class XEP_0280(object): log.info(_(u"Not activating message carbons as requested in params")) return try: - yield self.host.checkFeatures((NS_CARBONS,), profile=client.profile) + yield self.host.checkFeatures(client, (NS_CARBONS,)) except exceptions.FeatureNotFound: log.warning(_(u"server doesn't handle message carbons")) else: diff --git a/src/plugins/plugin_xep_0300.py b/src/plugins/plugin_xep_0300.py index 6e7ce1c0..096855f1 100644 --- a/src/plugins/plugin_xep_0300.py +++ b/src/plugins/plugin_xep_0300.py @@ -83,8 +83,9 @@ class XEP_0300(object): @return (D(unicode, None)): best available algorithm, or None if hashing is not possible """ + client = self.host.getClient(profile) for algo in reversed(XEP_0300.ALGOS): - has_feature = yield self.host.hasFeature(NS_HASHES_FUNCTIONS.format(algo), to_jid, profile) + has_feature = yield self.host.hasFeature(client, NS_HASHES_FUNCTIONS.format(algo), to_jid) if has_feature: log.debug(u"Best hashing algorithm found for {jid}: {algo}".format( jid=to_jid.full(), diff --git a/src/plugins/plugin_xep_0363.py b/src/plugins/plugin_xep_0363.py index 6be7b446..11dd853f 100644 --- a/src/plugins/plugin_xep_0363.py +++ b/src/plugins/plugin_xep_0363.py @@ -110,7 +110,7 @@ class XEP_0363(object): try: entity = client.http_upload_service except AttributeError: - found_entities = yield self.host.findFeaturesSet((NS_HTTP_UPLOAD,), profile=client.profile) + found_entities = yield self.host.findFeaturesSet(client, (NS_HTTP_UPLOAD,)) try: entity = client.http_upload_service = iter(found_entities).next() except StopIteration: