Rewrite discovery code and move it into own module
This commit is contained in:
parent
5ff9e9febf
commit
07c87a4194
|
@ -207,11 +207,13 @@ class ClientCaps(AbstractClientCaps):
|
|||
return caps_cache[(self._hash_method, self._hash)]
|
||||
|
||||
def _discover(self, connection, jid):
|
||||
connection.discoverInfo(jid, '%s#%s' % (self._node, self._hash))
|
||||
connection.get_module('Discovery').disco_contact(
|
||||
jid, '%s#%s' % (self._node, self._hash))
|
||||
|
||||
def _is_hash_valid(self, identities, features, dataforms):
|
||||
computed_hash = compute_caps_hash(identities, features,
|
||||
dataforms=dataforms, hash_method=self._hash_method)
|
||||
computed_hash = compute_caps_hash(
|
||||
identities, features, dataforms=dataforms,
|
||||
hash_method=self._hash_method)
|
||||
return computed_hash == self._hash
|
||||
|
||||
|
||||
|
@ -227,7 +229,7 @@ class OldClientCaps(AbstractClientCaps):
|
|||
return caps_cache[('old', self._node + '#' + self._hash)]
|
||||
|
||||
def _discover(self, connection, jid):
|
||||
connection.discoverInfo(jid)
|
||||
connection.get_module('Discovery').disco_contact(jid)
|
||||
|
||||
def _is_hash_valid(self, identities, features, dataforms):
|
||||
return True
|
||||
|
@ -244,7 +246,7 @@ class NoClientCaps(AbstractClientCaps):
|
|||
return caps_cache[('no', self._node)]
|
||||
|
||||
def _discover(self, connection, jid):
|
||||
connection.discoverInfo(jid)
|
||||
connection.get_module('Discovery').disco_contact(jid)
|
||||
|
||||
def _is_hash_valid(self, identities, features, dataforms):
|
||||
return True
|
||||
|
|
|
@ -103,7 +103,6 @@ class CommonConnection:
|
|||
self.priority = app.get_priority(name, 'offline')
|
||||
self.time_to_reconnect = None
|
||||
|
||||
self.pep_supported = False
|
||||
self.pep = {}
|
||||
# Do we continue connection when we get roster (send presence,get vcard..)
|
||||
self.continue_connect_info = None
|
||||
|
@ -115,13 +114,9 @@ class CommonConnection:
|
|||
# the fake jid
|
||||
self.groupchat_jids = {} # {ID : groupchat_jid}
|
||||
|
||||
self.privacy_rules_supported = False
|
||||
self.vcard_supported = False
|
||||
self.private_storage_supported = False
|
||||
self.roster_supported = True
|
||||
self.blocking_supported = False
|
||||
self.addressing_supported = False
|
||||
self.carbons_available = False
|
||||
|
||||
self.muc_jid = {} # jid of muc server for each transport type
|
||||
self._stun_servers = [] # STUN servers of our jabber server
|
||||
|
@ -582,7 +577,6 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
self.music_track_info = 0
|
||||
|
||||
self.register_supported = False
|
||||
self.pubsub_publish_options_supported = False
|
||||
# Do we auto accept insecure connection
|
||||
self.connection_auto_accepted = False
|
||||
self.pasword_callback = None
|
||||
|
@ -611,10 +605,6 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
# Register all modules
|
||||
modules.register(self)
|
||||
|
||||
app.ged.register_event_handler('agent-info-error-received', ged.CORE,
|
||||
self._nec_agent_info_error_received)
|
||||
app.ged.register_event_handler('agent-info-received', ged.CORE,
|
||||
self._nec_agent_info_received)
|
||||
app.ged.register_event_handler('message-outgoing', ged.OUT_CORE,
|
||||
self._nec_message_outgoing)
|
||||
app.ged.register_event_handler('gc-message-outgoing', ged.OUT_CORE,
|
||||
|
@ -629,10 +619,6 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
ConnectionHandlers.cleanup(self)
|
||||
modules.unregister(self)
|
||||
|
||||
app.ged.remove_event_handler('agent-info-error-received', ged.CORE,
|
||||
self._nec_agent_info_error_received)
|
||||
app.ged.remove_event_handler('agent-info-received', ged.CORE,
|
||||
self._nec_agent_info_received)
|
||||
app.ged.remove_event_handler('message-outgoing', ged.OUT_CORE,
|
||||
self._nec_message_outgoing)
|
||||
app.ged.remove_event_handler('gc-message-outgoing', ged.OUT_CORE,
|
||||
|
@ -699,7 +685,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
self.on_purpose = on_purpose
|
||||
self.connected = 0
|
||||
self.time_to_reconnect = None
|
||||
self.privacy_rules_supported = False
|
||||
self.get_module('PrivacyLists').supported = False
|
||||
self.get_module('VCardAvatars').avatar_advertised = False
|
||||
if on_purpose:
|
||||
self.sm = Smacks(self)
|
||||
|
@ -1430,7 +1416,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
def send_invisible_presence(self, msg, signed, initial = False):
|
||||
if not app.account_is_connected(self.name):
|
||||
return
|
||||
if not self.privacy_rules_supported:
|
||||
if not self.get_module('PrivacyLists').supported:
|
||||
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
|
||||
show=app.SHOW_LIST[self.connected]))
|
||||
app.nec.push_incoming_event(InformationEvent(
|
||||
|
@ -1438,7 +1424,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
return
|
||||
# If we are already connected, and privacy rules are supported, send
|
||||
# offline presence first as it's required by XEP-0126
|
||||
if self.connected > 1 and self.privacy_rules_supported:
|
||||
if self.connected > 1 and self.get_module('PrivacyLists').supported:
|
||||
self.on_purpose = True
|
||||
p = nbxmpp.Presence(typ='unavailable')
|
||||
p = self.add_sha(p, False)
|
||||
|
@ -1515,10 +1501,9 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
# If we are not resuming, we ask for discovery info
|
||||
# and archiving preferences
|
||||
if not self.sm.supports_sm or (not self.sm.resuming and self.sm.enabled):
|
||||
our_jid = app.get_jid_from_account(self.name)
|
||||
our_server = app.config.get_per('accounts', self.name, 'hostname')
|
||||
self.discoverInfo(our_jid, id_prefix='Gajim_')
|
||||
self.discoverInfo(our_server, id_prefix='Gajim_')
|
||||
self.get_module('Discovery').discover_account_info()
|
||||
self.get_module('Discovery').discover_server_info()
|
||||
else:
|
||||
self.request_roster(resume=True)
|
||||
|
||||
|
@ -1534,7 +1519,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
self._stun_servers = self._hosts = [i for i in result_array]
|
||||
|
||||
def _continue_connection_request_privacy(self):
|
||||
if self.privacy_rules_supported:
|
||||
if self.get_module('PrivacyLists').supported:
|
||||
if not self.privacy_rules_requested:
|
||||
self.privacy_rules_requested = True
|
||||
self.get_module('PrivacyLists').get_privacy_lists(
|
||||
|
@ -1557,104 +1542,12 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
None, dialog_name='invisibility-not-supported',
|
||||
args=self.name))
|
||||
return
|
||||
if self.blocking_supported:
|
||||
|
||||
self.get_module('Blocking').get_blocking_list()
|
||||
|
||||
# Ask metacontacts before roster
|
||||
self.get_metacontacts()
|
||||
|
||||
def _nec_agent_info_error_received(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
hostname = app.config.get_per('accounts', self.name, 'hostname')
|
||||
if obj.id_[:6] == 'Gajim_' and obj.fjid == hostname:
|
||||
self._continue_connection_request_privacy()
|
||||
|
||||
def _nec_agent_info_received(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
is_muc = False
|
||||
transport_type = ''
|
||||
for identity in obj.identities:
|
||||
if 'category' in identity and identity['category'] in ('gateway',
|
||||
'headline') and 'type' in identity:
|
||||
transport_type = identity['type']
|
||||
if 'category' in identity and identity['category'] == 'server' and \
|
||||
'type' in identity and identity['type'] == 'im':
|
||||
transport_type = 'jabber' # it's a jabber server
|
||||
if 'category' in identity and identity['category'] == 'conference' \
|
||||
and 'type' in identity and identity['type'] == 'text':
|
||||
is_muc = True
|
||||
|
||||
if transport_type != '' and obj.fjid not in app.transport_type:
|
||||
app.transport_type[obj.fjid] = transport_type
|
||||
app.logger.save_transport_type(obj.fjid, transport_type)
|
||||
|
||||
if obj.id_[:6] == 'Gajim_':
|
||||
hostname = app.config.get_per('accounts', self.name, 'hostname')
|
||||
our_jid = app.get_jid_from_account(self.name)
|
||||
|
||||
if obj.fjid == our_jid:
|
||||
if nbxmpp.NS_MAM_2 in obj.features:
|
||||
self.get_module('MAM').archiving_namespace = nbxmpp.NS_MAM_2
|
||||
elif nbxmpp.NS_MAM_1 in obj.features:
|
||||
self.get_module('MAM').archiving_namespace = nbxmpp.NS_MAM_1
|
||||
if self.get_module('MAM').archiving_namespace:
|
||||
self.get_module('MAM').available = True
|
||||
get_action(self.name + '-archive').set_enabled(True)
|
||||
for identity in obj.identities:
|
||||
if identity['category'] == 'pubsub':
|
||||
self.pep_supported = identity.get('type') == 'pep'
|
||||
break
|
||||
if nbxmpp.NS_PUBSUB_PUBLISH_OPTIONS in obj.features:
|
||||
self.pubsub_publish_options_supported = True
|
||||
else:
|
||||
# Remove stored bookmarks accessible to everyone.
|
||||
self.get_module('Bookmarks').purge_pubsub_bookmarks()
|
||||
|
||||
if obj.fjid == hostname:
|
||||
if nbxmpp.NS_SECLABEL in obj.features:
|
||||
self.get_module('SecLabels').supported = True
|
||||
if nbxmpp.NS_VCARD in obj.features:
|
||||
self.vcard_supported = True
|
||||
get_action(self.name + '-profile').set_enabled(True)
|
||||
if nbxmpp.NS_REGISTER in obj.features:
|
||||
self.register_supported = True
|
||||
if nbxmpp.NS_BLOCKING in obj.features:
|
||||
self.blocking_supported = True
|
||||
if nbxmpp.NS_ADDRESS in obj.features:
|
||||
self.addressing_supported = True
|
||||
if nbxmpp.NS_CARBONS in obj.features:
|
||||
self.carbons_available = True
|
||||
if app.config.get_per('accounts', self.name,
|
||||
'enable_message_carbons'):
|
||||
# Server supports carbons, activate it
|
||||
iq = nbxmpp.Iq('set')
|
||||
iq.setTag('enable', namespace=nbxmpp.NS_CARBONS)
|
||||
self.connection.send(iq)
|
||||
if nbxmpp.NS_PRIVACY in obj.features:
|
||||
self.privacy_rules_supported = True
|
||||
get_action(self.name + '-privacylists').set_enabled(True)
|
||||
|
||||
self._continue_connection_request_privacy()
|
||||
|
||||
if nbxmpp.NS_BYTESTREAM in obj.features and \
|
||||
app.config.get_per('accounts', self.name, 'use_ft_proxies'):
|
||||
our_fjid = helpers.parse_jid(our_jid + '/' + \
|
||||
self.server_resource)
|
||||
testit = app.config.get_per('accounts', self.name,
|
||||
'test_ft_proxies_on_startup')
|
||||
app.proxy65_manager.resolve(obj.fjid, self.connection,
|
||||
our_fjid, default=self.name, testit=testit)
|
||||
if nbxmpp.NS_MUC in obj.features and is_muc:
|
||||
type_ = transport_type or 'jabber'
|
||||
self.muc_jid[type_] = obj.fjid
|
||||
if transport_type:
|
||||
if transport_type in self.available_transports:
|
||||
self.available_transports[transport_type].append(obj.fjid)
|
||||
else:
|
||||
self.available_transports[transport_type] = [obj.fjid]
|
||||
|
||||
def send_custom_status(self, show, msg, jid):
|
||||
if not show in app.SHOW_LIST:
|
||||
return -1
|
||||
|
@ -1684,7 +1577,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
self.send_invisible_presence(msg, signed)
|
||||
|
||||
def _change_from_invisible(self):
|
||||
if self.privacy_rules_supported:
|
||||
if self.get_module('PrivacyLists').supported:
|
||||
self.get_module('PrivacyLists').set_active_list(None)
|
||||
|
||||
def _update_status(self, show, msg, idle_time=None):
|
||||
|
@ -1897,7 +1790,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
def bookmarks_available(self):
|
||||
if self.private_storage_supported:
|
||||
return True
|
||||
if self.pubsub_publish_options_supported:
|
||||
if self.get_module('PubSub').publish_options:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -2022,7 +1915,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
# Never join a room when invisible
|
||||
return
|
||||
|
||||
self.discoverMUC(
|
||||
self.get_module('Discovery').disco_muc(
|
||||
room_jid, partial(self._join_gc, nick, show, room_jid,
|
||||
password, change_nick, rejoin))
|
||||
|
||||
|
|
|
@ -66,51 +66,6 @@ PRIVACY_ARRIVED = 'privacy_arrived'
|
|||
|
||||
|
||||
class ConnectionDisco:
|
||||
"""
|
||||
Holds xmpppy handlers and public methods for discover services
|
||||
"""
|
||||
|
||||
def discoverItems(self, jid, node=None, id_prefix=None):
|
||||
"""
|
||||
According to XEP-0030:
|
||||
jid is mandatory;
|
||||
name, node, action is optional.
|
||||
"""
|
||||
id_ = self._discover(nbxmpp.NS_DISCO_ITEMS, jid, node, id_prefix)
|
||||
self.disco_items_ids.append(id_)
|
||||
|
||||
def discoverInfo(self, jid, node=None, id_prefix=None):
|
||||
"""
|
||||
According to XEP-0030:
|
||||
For identity: category, type is mandatory, name is optional.
|
||||
For feature: var is mandatory.
|
||||
"""
|
||||
id_ = self._discover(nbxmpp.NS_DISCO_INFO, jid, node, id_prefix)
|
||||
self.disco_info_ids.append(id_)
|
||||
|
||||
def discoverMUC(self, jid, callback, update=False):
|
||||
if muc_caps_cache.is_cached(jid) and not update:
|
||||
callback()
|
||||
return
|
||||
disco_info = nbxmpp.Iq(typ='get', to=jid, queryNS=nbxmpp.NS_DISCO_INFO)
|
||||
self.connection.SendAndCallForResponse(
|
||||
disco_info, self.received_muc_info, {'callback': callback})
|
||||
|
||||
def received_muc_info(self, conn, stanza, callback):
|
||||
if nbxmpp.isResultNode(stanza):
|
||||
app.log('gajim.muc').info(
|
||||
'Received MUC DiscoInfo for %s', stanza.getFrom())
|
||||
muc_caps_cache.append(stanza)
|
||||
callback()
|
||||
else:
|
||||
error = stanza.getError()
|
||||
if error == 'item-not-found':
|
||||
# Groupchat does not exist
|
||||
callback()
|
||||
return
|
||||
app.nec.push_incoming_event(
|
||||
InformationEvent(
|
||||
None, dialog_name='unable-join-groupchat', args=error))
|
||||
|
||||
def request_register_agent_info(self, agent):
|
||||
if not self.connection or self.connected < 2:
|
||||
|
@ -159,117 +114,10 @@ class ConnectionDisco:
|
|||
self.agent_registrations[agent] = {'roster_push': False,
|
||||
'sub_received': False}
|
||||
|
||||
def _discover(self, ns, jid, node=None, id_prefix=None):
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
iq = nbxmpp.Iq(typ='get', to=jid, queryNS=ns)
|
||||
id_ = self.connection.getAnID()
|
||||
if id_prefix:
|
||||
id_ = id_prefix + id_
|
||||
iq.setID(id_)
|
||||
if node:
|
||||
iq.setQuerynode(node)
|
||||
self.connection.send(iq)
|
||||
return id_
|
||||
|
||||
def _ReceivedRegInfo(self, con, resp, agent):
|
||||
nbxmpp.features_nb._ReceivedRegInfo(con, resp, agent)
|
||||
self._IqCB(con, resp)
|
||||
|
||||
def _discoGetCB(self, con, iq_obj):
|
||||
"""
|
||||
Get disco info
|
||||
"""
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
frm = helpers.get_full_jid_from_iq(iq_obj)
|
||||
to = iq_obj.getAttr('to')
|
||||
id_ = iq_obj.getAttr('id')
|
||||
iq = nbxmpp.Iq(to=frm, typ='result', queryNS=nbxmpp.NS_DISCO, frm=to)
|
||||
iq.setAttr('id', id_)
|
||||
query = iq.setTag('query')
|
||||
query.setAttr('node', 'http://gajim.org#' + app.version.split('-', 1)[
|
||||
0])
|
||||
for f in (nbxmpp.NS_BYTESTREAM, nbxmpp.NS_SI, nbxmpp.NS_FILE,
|
||||
nbxmpp.NS_COMMANDS, nbxmpp.NS_JINGLE_FILE_TRANSFER_5,
|
||||
nbxmpp.NS_JINGLE_XTLS, nbxmpp.NS_PUBKEY_PUBKEY, nbxmpp.NS_PUBKEY_REVOKE,
|
||||
nbxmpp.NS_PUBKEY_ATTEST):
|
||||
feature = nbxmpp.Node('feature')
|
||||
feature.setAttr('var', f)
|
||||
query.addChild(node=feature)
|
||||
|
||||
self.connection.send(iq)
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def _DiscoverItemsErrorCB(self, con, iq_obj):
|
||||
log.debug('DiscoverItemsErrorCB')
|
||||
app.nec.push_incoming_event(AgentItemsErrorReceivedEvent(None,
|
||||
conn=self, stanza=iq_obj))
|
||||
|
||||
def _DiscoverItemsCB(self, con, iq_obj):
|
||||
log.debug('DiscoverItemsCB')
|
||||
app.nec.push_incoming_event(AgentItemsReceivedEvent(None, conn=self,
|
||||
stanza=iq_obj))
|
||||
|
||||
def _DiscoverItemsGetCB(self, con, iq_obj):
|
||||
log.debug('DiscoverItemsGetCB')
|
||||
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
|
||||
if self.get_module('AdHocCommands').command_items_query(iq_obj):
|
||||
raise nbxmpp.NodeProcessed
|
||||
node = iq_obj.getTagAttr('query', 'node')
|
||||
if node is None:
|
||||
result = iq_obj.buildReply('result')
|
||||
self.connection.send(result)
|
||||
raise nbxmpp.NodeProcessed
|
||||
if node == nbxmpp.NS_COMMANDS:
|
||||
self.get_module('AdHocCommands').command_list_query(iq_obj)
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def _DiscoverInfoGetCB(self, con, iq_obj):
|
||||
log.debug('DiscoverInfoGetCB')
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
node = iq_obj.getQuerynode()
|
||||
|
||||
if self.get_module('AdHocCommands').command_info_query(iq_obj):
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
id_ = iq_obj.getAttr('id')
|
||||
if id_[:6] == 'Gajim_':
|
||||
# We get this request from echo.server
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
iq = iq_obj.buildReply('result')
|
||||
q = iq.setQuery()
|
||||
if node:
|
||||
q.setAttr('node', node)
|
||||
q.addChild('identity', attrs=app.gajim_identity)
|
||||
client_version = 'http://gajim.org#' + app.caps_hash[self.name]
|
||||
|
||||
if node in (None, client_version):
|
||||
for f in app.gajim_common_features:
|
||||
q.addChild('feature', attrs={'var': f})
|
||||
for f in app.gajim_optional_features[self.name]:
|
||||
q.addChild('feature', attrs={'var': f})
|
||||
|
||||
if q.getChildren():
|
||||
self.connection.send(iq)
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def _DiscoverInfoErrorCB(self, con, iq_obj):
|
||||
log.debug('DiscoverInfoErrorCB')
|
||||
app.nec.push_incoming_event(AgentInfoErrorReceivedEvent(None,
|
||||
conn=self, stanza=iq_obj))
|
||||
|
||||
def _DiscoverInfoCB(self, con, iq_obj):
|
||||
log.debug('DiscoverInfoCB')
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
app.nec.push_incoming_event(AgentInfoReceivedEvent(None, conn=self,
|
||||
stanza=iq_obj))
|
||||
|
||||
# basic connection handlers used here and in zeroconf
|
||||
class ConnectionHandlersBase:
|
||||
|
@ -292,25 +140,17 @@ class ConnectionHandlersBase:
|
|||
# We decrypt GPG messages one after the other. Keep queue in mem
|
||||
self.gpg_messages_to_decrypt = []
|
||||
|
||||
app.ged.register_event_handler('iq-error-received', ged.CORE,
|
||||
self._nec_iq_error_received)
|
||||
app.ged.register_event_handler('presence-received', ged.CORE,
|
||||
self._nec_presence_received)
|
||||
app.ged.register_event_handler('gc-message-received', ged.CORE,
|
||||
self._nec_gc_message_received)
|
||||
|
||||
def cleanup(self):
|
||||
app.ged.remove_event_handler('iq-error-received', ged.CORE,
|
||||
self._nec_iq_error_received)
|
||||
app.ged.remove_event_handler('presence-received', ged.CORE,
|
||||
self._nec_presence_received)
|
||||
app.ged.remove_event_handler('gc-message-received', ged.CORE,
|
||||
self._nec_gc_message_received)
|
||||
|
||||
def _nec_iq_error_received(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
|
||||
def _nec_presence_received(self, obj):
|
||||
account = obj.conn.name
|
||||
if account != self.name:
|
||||
|
@ -647,8 +487,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
ged.CORE, self._nec_roster_set_received)
|
||||
app.ged.register_event_handler('roster-received', ged.CORE,
|
||||
self._nec_roster_received)
|
||||
app.ged.register_event_handler('iq-error-received', ged.CORE,
|
||||
self._nec_iq_error_received)
|
||||
app.ged.register_event_handler('subscribe-presence-received',
|
||||
ged.CORE, self._nec_subscribe_presence_received)
|
||||
app.ged.register_event_handler('subscribed-presence-received',
|
||||
|
@ -669,8 +507,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
ged.CORE, self._nec_roster_set_received)
|
||||
app.ged.remove_event_handler('roster-received', ged.CORE,
|
||||
self._nec_roster_received)
|
||||
app.ged.remove_event_handler('iq-error-received', ged.CORE,
|
||||
self._nec_iq_error_received)
|
||||
app.ged.remove_event_handler('subscribe-presence-received',
|
||||
ged.CORE, self._nec_subscribe_presence_received)
|
||||
app.ged.remove_event_handler('subscribed-presence-received',
|
||||
|
@ -762,28 +598,14 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
self._getRoster()
|
||||
elif iq_obj.getType() == 'error':
|
||||
self.roster_supported = False
|
||||
self.discoverItems(app.config.get_per('accounts', self.name,
|
||||
'hostname'), id_prefix='Gajim_')
|
||||
self.get_module('Discovery').discover_server_items()
|
||||
if app.config.get_per('accounts', self.name,
|
||||
'use_ft_proxies'):
|
||||
self.discover_ft_proxies()
|
||||
app.nec.push_incoming_event(RosterReceivedEvent(None,
|
||||
conn=self))
|
||||
GLib.timeout_add_seconds(10, self.discover_servers)
|
||||
del self.awaiting_answers[id_]
|
||||
|
||||
def _nec_iq_error_received(self, obj):
|
||||
if obj.conn.name != self.name:
|
||||
return
|
||||
if obj.id_ in self.disco_items_ids:
|
||||
app.nec.push_incoming_event(AgentItemsErrorReceivedEvent(None,
|
||||
conn=self, stanza=obj.stanza))
|
||||
return True
|
||||
if obj.id_ in self.disco_info_ids:
|
||||
app.nec.push_incoming_event(AgentInfoErrorReceivedEvent(None,
|
||||
conn=self, stanza=obj.stanza))
|
||||
return True
|
||||
|
||||
def _rosterSetCB(self, con, iq_obj):
|
||||
log.debug('rosterSetCB')
|
||||
app.nec.push_incoming_event(RosterSetReceivedEvent(None, conn=self,
|
||||
|
@ -972,8 +794,7 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
if not self.connection:
|
||||
return
|
||||
self.connection.getRoster(self._on_roster_set)
|
||||
self.discoverItems(app.config.get_per('accounts', self.name,
|
||||
'hostname'), id_prefix='Gajim_')
|
||||
self.get_module('Discovery').discover_server_items()
|
||||
if app.config.get_per('accounts', self.name, 'use_ft_proxies'):
|
||||
self.discover_ft_proxies()
|
||||
|
||||
|
@ -990,17 +811,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
app.proxy65_manager.resolve(proxy, self.connection, our_jid,
|
||||
testit=testit)
|
||||
|
||||
def discover_servers(self):
|
||||
if not self.connection:
|
||||
return
|
||||
servers = []
|
||||
for c in app.contacts.iter_contacts(self.name):
|
||||
s = app.get_server_from_jid(c.jid)
|
||||
if s not in servers and s not in app.transport_type:
|
||||
servers.append(s)
|
||||
for s in servers:
|
||||
self.discoverInfo(s)
|
||||
|
||||
def _on_roster_set(self, roster):
|
||||
app.nec.push_incoming_event(RosterReceivedEvent(None, conn=self,
|
||||
xmpp_roster=roster))
|
||||
|
@ -1027,13 +837,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
if send_first_presence:
|
||||
self._send_first_presence(signed)
|
||||
|
||||
if obj.received_from_server:
|
||||
for jid in obj.roster:
|
||||
if jid != our_jid and app.jid_is_transport(jid) and \
|
||||
not app.get_transport_name_from_jid(jid):
|
||||
# we can't determine which iconset to use
|
||||
self.discoverInfo(jid)
|
||||
|
||||
app.logger.replace_roster(self.name, obj.version, obj.roster)
|
||||
|
||||
for contact in app.contacts.iter_contacts(self.name):
|
||||
|
@ -1080,7 +883,7 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
self.priority = priority
|
||||
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
|
||||
show=show))
|
||||
if self.vcard_supported:
|
||||
|
||||
# ask our VCard
|
||||
self.get_module('VCardTemp').request_vcard()
|
||||
|
||||
|
@ -1120,7 +923,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
con.RegisterHandler('iq', self._siSetCB, 'set', nbxmpp.NS_SI)
|
||||
con.RegisterHandler('iq', self._siErrorCB, 'error', nbxmpp.NS_SI)
|
||||
con.RegisterHandler('iq', self._siResultCB, 'result', nbxmpp.NS_SI)
|
||||
con.RegisterHandler('iq', self._discoGetCB, 'get', nbxmpp.NS_DISCO)
|
||||
con.RegisterHandler('iq', self._bytestreamSetCB, 'set',
|
||||
nbxmpp.NS_BYTESTREAM)
|
||||
con.RegisterHandler('iq', self._bytestreamResultCB, 'result',
|
||||
|
@ -1130,18 +932,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
|||
con.RegisterHandlerOnce('iq', self.IBBAllIqHandler)
|
||||
con.RegisterHandler('iq', self.IBBIqHandler, ns=nbxmpp.NS_IBB)
|
||||
con.RegisterHandler('message', self.IBBMessageHandler, ns=nbxmpp.NS_IBB)
|
||||
con.RegisterHandler('iq', self._DiscoverItemsCB, 'result',
|
||||
nbxmpp.NS_DISCO_ITEMS)
|
||||
con.RegisterHandler('iq', self._DiscoverItemsErrorCB, 'error',
|
||||
nbxmpp.NS_DISCO_ITEMS)
|
||||
con.RegisterHandler('iq', self._DiscoverInfoCB, 'result',
|
||||
nbxmpp.NS_DISCO_INFO)
|
||||
con.RegisterHandler('iq', self._DiscoverInfoErrorCB, 'error',
|
||||
nbxmpp.NS_DISCO_INFO)
|
||||
con.RegisterHandler('iq', self._DiscoverInfoGetCB, 'get',
|
||||
nbxmpp.NS_DISCO_INFO)
|
||||
con.RegisterHandler('iq', self._DiscoverItemsGetCB, 'get',
|
||||
nbxmpp.NS_DISCO_ITEMS)
|
||||
|
||||
con.RegisterHandler('iq', self._JingleCB, 'result')
|
||||
con.RegisterHandler('iq', self._JingleCB, 'error')
|
||||
|
|
|
@ -37,7 +37,6 @@ from gajim.common import helpers
|
|||
from gajim.common import app
|
||||
from gajim.common import i18n
|
||||
from gajim.common.modules import dataforms
|
||||
from gajim.common.zeroconf.zeroconf import Constant
|
||||
from gajim.common.const import KindConstant, SSLError
|
||||
from gajim.common.pep import SUPPORTED_PERSONAL_USER_EVENTS
|
||||
from gajim.common.jingle_transport import JingleTransportSocks5
|
||||
|
@ -1080,119 +1079,6 @@ class RegisterAgentInfoReceivedEvent(nec.NetworkIncomingEvent):
|
|||
name = 'register-agent-info-received'
|
||||
base_network_events = []
|
||||
|
||||
class AgentItemsReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||
name = 'agent-items-received'
|
||||
base_network_events = []
|
||||
|
||||
def generate(self):
|
||||
q = self.stanza.getTag('query')
|
||||
self.node = q.getAttr('node')
|
||||
if not self.node:
|
||||
self.node = ''
|
||||
qp = self.stanza.getQueryPayload()
|
||||
self.items = []
|
||||
if not qp:
|
||||
qp = []
|
||||
for i in qp:
|
||||
# CDATA payload is not processed, only nodes
|
||||
if not isinstance(i, nbxmpp.simplexml.Node):
|
||||
continue
|
||||
attr = {}
|
||||
for key in i.getAttrs():
|
||||
attr[key] = i.getAttrs()[key]
|
||||
if 'jid' not in attr:
|
||||
continue
|
||||
try:
|
||||
attr['jid'] = helpers.parse_jid(attr['jid'])
|
||||
except helpers.InvalidFormat:
|
||||
# jid is not conform
|
||||
continue
|
||||
self.items.append(attr)
|
||||
self.get_jid_resource()
|
||||
hostname = app.config.get_per('accounts', self.conn.name, 'hostname')
|
||||
self.get_id()
|
||||
if self.id_ in self.conn.disco_items_ids:
|
||||
self.conn.disco_items_ids.remove(self.id_)
|
||||
if self.fjid == hostname and self.id_[:6] == 'Gajim_':
|
||||
for item in self.items:
|
||||
self.conn.discoverInfo(item['jid'], id_prefix='Gajim_')
|
||||
else:
|
||||
return True
|
||||
|
||||
class AgentItemsErrorReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||
name = 'agent-items-error-received'
|
||||
base_network_events = []
|
||||
|
||||
def generate(self):
|
||||
self.get_jid_resource()
|
||||
self.get_id()
|
||||
if self.id_ in self.conn.disco_items_ids:
|
||||
self.conn.disco_items_ids.remove(self.id_)
|
||||
return True
|
||||
|
||||
class AgentInfoReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||
name = 'agent-info-received'
|
||||
base_network_events = []
|
||||
|
||||
def generate(self):
|
||||
self.get_id()
|
||||
if self.id_ in self.conn.disco_info_ids:
|
||||
self.conn.disco_info_ids.remove(self.id_)
|
||||
if self.id_ is None:
|
||||
log.warning('Invalid IQ received without an ID. '
|
||||
'Ignoring it: %s', self.stanza)
|
||||
return
|
||||
# According to XEP-0030:
|
||||
# For identity: category, type is mandatory, name is optional.
|
||||
# For feature: var is mandatory
|
||||
self.identities, self.features, self.data, self.node = self.parse_stanza(self.stanza)
|
||||
|
||||
if not self.identities:
|
||||
# ejabberd doesn't send identities when we browse online users
|
||||
# see http://www.jabber.ru/bugzilla/show_bug.cgi?id=225
|
||||
self.identities = [{'category': 'server', 'type': 'im',
|
||||
'name': self.node}]
|
||||
self.get_jid_resource()
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def parse_stanza(cls, stanza):
|
||||
identities, features, data, node = [], [], [], None
|
||||
q = stanza.getTag('query')
|
||||
node = q.getAttr('node')
|
||||
if not node:
|
||||
node = ''
|
||||
|
||||
qc = stanza.getQueryChildren()
|
||||
if not qc:
|
||||
qc = []
|
||||
|
||||
for i in qc:
|
||||
if i.getName() == 'identity':
|
||||
attr = {}
|
||||
for key in i.getAttrs().keys():
|
||||
attr[key] = i.getAttr(key)
|
||||
identities.append(attr)
|
||||
elif i.getName() == 'feature':
|
||||
var = i.getAttr('var')
|
||||
if var:
|
||||
features.append(var)
|
||||
elif i.getName() == 'x' and i.getNamespace() == nbxmpp.NS_DATA:
|
||||
data.append(nbxmpp.DataForm(node=i))
|
||||
|
||||
return identities, features, data, node
|
||||
|
||||
class AgentInfoErrorReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||
name = 'agent-info-error-received'
|
||||
base_network_events = []
|
||||
|
||||
def generate(self):
|
||||
self.get_jid_resource()
|
||||
self.get_id()
|
||||
if self.id_ in self.conn.disco_info_ids:
|
||||
self.conn.disco_info_ids.remove(self.id_)
|
||||
return True
|
||||
|
||||
class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||
name = 'file-request-received'
|
||||
base_network_events = []
|
||||
|
|
|
@ -18,7 +18,7 @@ from pathlib import Path
|
|||
|
||||
log = logging.getLogger('gajim.c.m')
|
||||
|
||||
ZEROCONF_MODULES = ['adhoc_commands', 'receipts']
|
||||
ZEROCONF_MODULES = ['adhoc_commands', 'receipts', 'discovery']
|
||||
|
||||
imported_modules = []
|
||||
_modules = {}
|
||||
|
@ -56,6 +56,9 @@ class ModuleMock:
|
|||
# Bookmarks
|
||||
self.bookmarks = {}
|
||||
|
||||
# Various Modules
|
||||
self.supported = False
|
||||
|
||||
def __getattr__(self, key):
|
||||
def _mock(self, *args, **kwargs):
|
||||
return
|
||||
|
|
|
@ -35,7 +35,18 @@ class Blocking:
|
|||
('iq', self._blocking_push_received, 'set', nbxmpp.NS_BLOCKING)
|
||||
]
|
||||
|
||||
self.supported = False
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_BLOCKING not in features:
|
||||
return
|
||||
|
||||
self.supported = True
|
||||
log.info('Discovered blocking: %s', from_)
|
||||
|
||||
def get_blocking_list(self):
|
||||
if not self.supported:
|
||||
return
|
||||
iq = nbxmpp.Iq('get', nbxmpp.NS_BLOCKING)
|
||||
iq.setQuery('blocklist')
|
||||
log.info('Request list')
|
||||
|
@ -119,7 +130,7 @@ class Blocking:
|
|||
self._con.connection.send(probe)
|
||||
|
||||
def block(self, contact_list):
|
||||
if not self._con.blocking_supported:
|
||||
if not self.supported:
|
||||
return
|
||||
iq = nbxmpp.Iq('set', nbxmpp.NS_BLOCKING)
|
||||
query = iq.setQuery(name='block')
|
||||
|
@ -131,7 +142,7 @@ class Blocking:
|
|||
iq, self._default_result_handler, {})
|
||||
|
||||
def unblock(self, contact_list):
|
||||
if not self._con.blocking_supported:
|
||||
if not self.supported:
|
||||
return
|
||||
iq = nbxmpp.Iq('set', nbxmpp.NS_BLOCKING)
|
||||
query = iq.setQuery(name='unblock')
|
||||
|
|
|
@ -35,8 +35,8 @@ class Bookmarks:
|
|||
self.handlers = []
|
||||
|
||||
def _pubsub_support(self):
|
||||
return (self._con.pep_supported and
|
||||
self._con.pubsub_publish_options_supported)
|
||||
return (self._con.get_module('PEP').supported and
|
||||
self._con.get_module('PubSub').publish_options)
|
||||
|
||||
def get_bookmarks(self, storage_type=None):
|
||||
if not app.account_is_connected(self._account):
|
||||
|
@ -86,7 +86,7 @@ class Bookmarks:
|
|||
else:
|
||||
log.info('Received Bookmarks (PrivateStorage)')
|
||||
merged = self._parse_bookmarks(stanza, check_merge=True)
|
||||
if merged:
|
||||
if merged and self._pubsub_support():
|
||||
log.info('Merge PrivateStorage with PubSub')
|
||||
self.store_bookmarks(BookmarkStorageType.PUBSUB)
|
||||
self.auto_join_bookmarks()
|
||||
|
|
|
@ -18,9 +18,37 @@ import logging
|
|||
|
||||
import nbxmpp
|
||||
|
||||
from gajim.common import app
|
||||
|
||||
log = logging.getLogger('gajim.c.m.carbons')
|
||||
|
||||
|
||||
class Carbons:
|
||||
def __init__(self, con):
|
||||
self._con = con
|
||||
self._account = con.name
|
||||
|
||||
self.handlers = []
|
||||
|
||||
self.supported = False
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_CARBONS not in features:
|
||||
return
|
||||
|
||||
self.supported = True
|
||||
log.info('Discovered carbons: %s', from_)
|
||||
|
||||
if app.config.get_per('accounts', self._account,
|
||||
'enable_message_carbons'):
|
||||
iq = nbxmpp.Iq('set')
|
||||
iq.setTag('enable', namespace=nbxmpp.NS_CARBONS)
|
||||
log.info('Activate')
|
||||
self._con.connection.send(iq)
|
||||
else:
|
||||
log.warning('Carbons deactivated (user setting)')
|
||||
|
||||
|
||||
def parse_carbon(con, stanza):
|
||||
carbon = stanza.getTag(
|
||||
'received', namespace=nbxmpp.NS_CARBONS, protocol=True)
|
||||
|
@ -75,3 +103,7 @@ def parse_carbon(con, stanza):
|
|||
raise nbxmpp.NodeProcessed
|
||||
|
||||
return message, sent, True
|
||||
|
||||
|
||||
def get_instance(*args, **kwargs):
|
||||
return Carbons(*args, **kwargs), 'Carbons'
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
# This file is part of Gajim.
|
||||
#
|
||||
# Gajim is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published
|
||||
# by the Free Software Foundation; version 3 only.
|
||||
#
|
||||
# Gajim is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# XEP-0030: Service Discovery
|
||||
|
||||
import logging
|
||||
import weakref
|
||||
|
||||
import nbxmpp
|
||||
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.common.caps_cache import muc_caps_cache
|
||||
from gajim.common.nec import NetworkIncomingEvent
|
||||
from gajim.common.connection_handlers_events import InformationEvent
|
||||
|
||||
log = logging.getLogger('gajim.c.m.discovery')
|
||||
|
||||
|
||||
class Discovery:
|
||||
def __init__(self, con):
|
||||
self._con = con
|
||||
self._account = con.name
|
||||
|
||||
self.handlers = [
|
||||
('iq', self._answer_disco_info, 'get', nbxmpp.NS_DISCO_INFO),
|
||||
('iq', self._answer_disco_items, 'get', nbxmpp.NS_DISCO_ITEMS),
|
||||
]
|
||||
|
||||
def disco_contact(self, jid, node=None):
|
||||
success_cb = self._con._nec_agent_info_received_caps
|
||||
self._disco(nbxmpp.NS_DISCO_INFO, jid, node, success_cb, None)
|
||||
|
||||
def disco_items(self, jid, node=None, success_cb=None, error_cb=None):
|
||||
self._disco(nbxmpp.NS_DISCO_ITEMS, jid, node, success_cb, error_cb)
|
||||
|
||||
def disco_info(self, jid, node=None, success_cb=None, error_cb=None):
|
||||
self._disco(nbxmpp.NS_DISCO_INFO, jid, node, success_cb, error_cb)
|
||||
|
||||
def _disco(self, namespace, jid, node, success_cb, error_cb):
|
||||
if success_cb is None:
|
||||
raise ValueError('success_cb is required')
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
iq = nbxmpp.Iq(typ='get', to=jid, queryNS=namespace)
|
||||
if node:
|
||||
iq.setQuerynode(node)
|
||||
|
||||
log_str = 'Request info: %s %s'
|
||||
if namespace == nbxmpp.NS_DISCO_ITEMS:
|
||||
log_str = 'Request items: %s %s'
|
||||
log.info(log_str, jid, node or '')
|
||||
|
||||
# Create weak references so we can pass GUI object methods
|
||||
weak_success_cb = weakref.WeakMethod(success_cb)
|
||||
if error_cb is not None:
|
||||
weak_error_cb = weakref.WeakMethod(error_cb)
|
||||
else:
|
||||
weak_error_cb = None
|
||||
self._con.connection.SendAndCallForResponse(
|
||||
iq, self._disco_response, {'success_cb': weak_success_cb,
|
||||
'error_cb': weak_error_cb})
|
||||
|
||||
def _disco_response(self, conn, stanza, success_cb, error_cb):
|
||||
if not nbxmpp.isResultNode(stanza):
|
||||
if error_cb is not None:
|
||||
error_cb()(stanza.getFrom(), stanza.getError())
|
||||
else:
|
||||
log.info('Error: %s', stanza.getError())
|
||||
return
|
||||
|
||||
from_ = stanza.getFrom()
|
||||
node = stanza.getQuerynode()
|
||||
if stanza.getQueryNS() == nbxmpp.NS_DISCO_INFO:
|
||||
identities, features, data, node = self.parse_info_response(stanza)
|
||||
success_cb()(from_, identities, features, data, node)
|
||||
|
||||
elif stanza.getQueryNS() == nbxmpp.NS_DISCO_ITEMS:
|
||||
items = self.parse_items_response(stanza)
|
||||
success_cb()(from_, node, items)
|
||||
else:
|
||||
log.warning('Wrong query namespace: %s', stanza)
|
||||
|
||||
@classmethod
|
||||
def parse_items_response(cls, stanza):
|
||||
payload = stanza.getQueryPayload()
|
||||
items = []
|
||||
for item in payload:
|
||||
# CDATA payload is not processed, only nodes
|
||||
if not isinstance(item, nbxmpp.simplexml.Node):
|
||||
continue
|
||||
attr = item.getAttrs()
|
||||
if 'jid' not in attr:
|
||||
log.warning('No jid attr in disco items: %s', stanza)
|
||||
continue
|
||||
try:
|
||||
attr['jid'] = helpers.parse_jid(attr['jid'])
|
||||
except helpers.InvalidFormat:
|
||||
log.warning('Invalid jid attr in disco items: %s', stanza)
|
||||
continue
|
||||
items.append(attr)
|
||||
return items
|
||||
|
||||
@classmethod
|
||||
def parse_info_response(cls, stanza):
|
||||
identities, features, data, node = [], [], [], None
|
||||
q = stanza.getTag('query')
|
||||
node = q.getAttr('node')
|
||||
if not node:
|
||||
node = ''
|
||||
|
||||
qc = stanza.getQueryChildren()
|
||||
if not qc:
|
||||
qc = []
|
||||
|
||||
for i in qc:
|
||||
if i.getName() == 'identity':
|
||||
attr = {}
|
||||
for key in i.getAttrs().keys():
|
||||
attr[key] = i.getAttr(key)
|
||||
identities.append(attr)
|
||||
elif i.getName() == 'feature':
|
||||
var = i.getAttr('var')
|
||||
if var:
|
||||
features.append(var)
|
||||
elif i.getName() == 'x' and i.getNamespace() == nbxmpp.NS_DATA:
|
||||
data.append(nbxmpp.DataForm(node=i))
|
||||
|
||||
return identities, features, data, node
|
||||
|
||||
def discover_server_items(self):
|
||||
server = self._con.get_own_jid().getDomain()
|
||||
self.disco_items(server, success_cb=self._server_items_received)
|
||||
|
||||
def _server_items_received(self, from_, node, items):
|
||||
log.info('Server items received')
|
||||
for item in items:
|
||||
self.disco_info(item['jid'],
|
||||
success_cb=self._server_items_info_received)
|
||||
|
||||
def _server_items_info_received(self, from_, *args):
|
||||
from_ = from_.getStripped()
|
||||
log.info('Server item info received: %s', from_)
|
||||
self._parse_transports(from_, *args)
|
||||
try:
|
||||
self._con.get_module('MUC').pass_disco(from_, *args)
|
||||
self._con.get_module('HTTPUpload').pass_disco(from_, *args)
|
||||
self._con.pass_bytestream_disco(from_, *args)
|
||||
except nbxmpp.NodeProcessed:
|
||||
pass
|
||||
|
||||
app.nec.push_incoming_event(
|
||||
NetworkIncomingEvent('server-disco-received'))
|
||||
|
||||
def discover_account_info(self):
|
||||
own_jid = self._con.get_own_jid().getStripped()
|
||||
self.disco_info(own_jid, success_cb=self._account_info_received)
|
||||
|
||||
def _account_info_received(self, from_, *args):
|
||||
from_ = from_.getStripped()
|
||||
log.info('Account info received: %s', from_)
|
||||
|
||||
self._con.get_module('MAM').pass_disco(from_, *args)
|
||||
self._con.get_module('PEP').pass_disco(from_, *args)
|
||||
self._con.get_module('PubSub').pass_disco(from_, *args)
|
||||
|
||||
def discover_server_info(self):
|
||||
server = self._con.get_own_jid().getDomain()
|
||||
self.disco_info(server, success_cb=self._server_info_received)
|
||||
|
||||
def _server_info_received(self, from_, *args):
|
||||
log.info('Server info received: %s', from_)
|
||||
|
||||
self._con.get_module('SecLabels').pass_disco(from_, *args)
|
||||
self._con.get_module('Blocking').pass_disco(from_, *args)
|
||||
self._con.get_module('VCardTemp').pass_disco(from_, *args)
|
||||
self._con.get_module('Carbons').pass_disco(from_, *args)
|
||||
self._con.get_module('PrivacyLists').pass_disco(from_, *args)
|
||||
|
||||
identities, features, data, node = args
|
||||
if nbxmpp.NS_REGISTER in features:
|
||||
self._con.register_supported = True
|
||||
|
||||
if nbxmpp.NS_ADDRESS in features:
|
||||
self._con.addressing_supported = True
|
||||
|
||||
self._con._continue_connection_request_privacy()
|
||||
|
||||
def _parse_transports(self, from_, identities, features, data, node):
|
||||
for identity in identities:
|
||||
category = identity.get('category')
|
||||
if category not in ('gateway', 'headline'):
|
||||
continue
|
||||
transport_type = identity.get('type')
|
||||
log.info('Found transport: %s %s %s',
|
||||
from_, category, transport_type)
|
||||
jid = str(from_)
|
||||
if jid not in app.transport_type:
|
||||
app.transport_type[jid] = transport_type
|
||||
app.logger.save_transport_type(jid, transport_type)
|
||||
|
||||
if transport_type in self._con.available_transports:
|
||||
self._con.available_transports[transport_type].append(jid)
|
||||
else:
|
||||
self._con.available_transports[transport_type] = [jid]
|
||||
|
||||
def _answer_disco_items(self, con, stanza):
|
||||
from_ = stanza.getFrom()
|
||||
log.info('Answer disco items to %s', from_)
|
||||
|
||||
if self._con.get_module('AdHocCommands').command_items_query(stanza):
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
node = stanza.getTagAttr('query', 'node')
|
||||
if node is None:
|
||||
result = stanza.buildReply('result')
|
||||
self._con.connection.send(result)
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
if node == nbxmpp.NS_COMMANDS:
|
||||
self._con.get_module('AdHocCommands').command_list_query(stanza)
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def _answer_disco_info(self, con, stanza):
|
||||
from_ = stanza.getFrom()
|
||||
log.info('Answer disco info %s', from_)
|
||||
if str(from_).startswith('echo.'):
|
||||
# Service that echos all stanzas, ignore it
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
if self._con.get_module('AdHocCommands').command_info_query(stanza):
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
node = stanza.getQuerynode()
|
||||
iq = stanza.buildReply('result')
|
||||
query = iq.setQuery()
|
||||
if node:
|
||||
query.setAttr('node', node)
|
||||
query.addChild('identity', attrs=app.gajim_identity)
|
||||
client_version = 'http://gajim.org#' + app.caps_hash[self._account]
|
||||
|
||||
if node in (None, client_version):
|
||||
for f in app.gajim_common_features:
|
||||
query.addChild('feature', attrs={'var': f})
|
||||
for f in app.gajim_optional_features[self._account]:
|
||||
query.addChild('feature', attrs={'var': f})
|
||||
|
||||
self._con.connection.send(iq)
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def disco_muc(self, jid, callback, update=False):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
if muc_caps_cache.is_cached(jid) and not update:
|
||||
callback()
|
||||
return
|
||||
|
||||
iq = nbxmpp.Iq(typ='get', to=jid, queryNS=nbxmpp.NS_DISCO_INFO)
|
||||
log.info('Request MUC info %s', jid)
|
||||
|
||||
self._con.connection.SendAndCallForResponse(
|
||||
iq, self._muc_info_response, {'callback': callback})
|
||||
|
||||
def _muc_info_response(self, conn, stanza, callback):
|
||||
if not nbxmpp.isResultNode(stanza):
|
||||
error = stanza.getError()
|
||||
if error == 'item-not-found':
|
||||
# Groupchat does not exist
|
||||
log.info('MUC does not exist: %s', stanza.getFrom())
|
||||
callback()
|
||||
else:
|
||||
log.info('MUC disco error: %s', error)
|
||||
app.nec.push_incoming_event(
|
||||
InformationEvent(
|
||||
None, dialog_name='unable-join-groupchat', args=error))
|
||||
return
|
||||
|
||||
log.info('MUC info received: %s', stanza.getFrom())
|
||||
muc_caps_cache.append(stanza)
|
||||
callback()
|
||||
|
||||
|
||||
def get_instance(*args, **kwargs):
|
||||
return Discovery(*args, **kwargs), 'Discovery'
|
|
@ -59,9 +59,6 @@ class HTTPUpload:
|
|||
self._allowed_headers = ['Authorization', 'Cookie', 'Expires']
|
||||
self.max_file_size = None # maximum file size in bytes
|
||||
|
||||
app.ged.register_event_handler('agent-info-received',
|
||||
ged.GUI1,
|
||||
self.handle_agent_info_received)
|
||||
app.ged.register_event_handler('stanza-message-outgoing',
|
||||
ged.OUT_PREGUI,
|
||||
self.handle_outgoing_stanza)
|
||||
|
@ -72,9 +69,6 @@ class HTTPUpload:
|
|||
self.messages = []
|
||||
|
||||
def cleanup(self):
|
||||
app.ged.remove_event_handler('agent-info-received',
|
||||
ged.GUI1,
|
||||
self.handle_agent_info_received)
|
||||
app.ged.remove_event_handler('stanza-message-outgoing',
|
||||
ged.OUT_PREGUI,
|
||||
self.handle_outgoing_stanza)
|
||||
|
@ -82,27 +76,18 @@ class HTTPUpload:
|
|||
ged.OUT_PREGUI,
|
||||
self.handle_outgoing_stanza)
|
||||
|
||||
def handle_agent_info_received(self, event):
|
||||
account = event.conn.name
|
||||
if account != self._account:
|
||||
return
|
||||
|
||||
if not app.jid_is_transport(event.jid):
|
||||
return
|
||||
|
||||
if not event.id_.startswith('Gajim_'):
|
||||
return
|
||||
|
||||
if NS_HTTPUPLOAD_0 in event.features:
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
if NS_HTTPUPLOAD_0 in features:
|
||||
self.httpupload_namespace = NS_HTTPUPLOAD_0
|
||||
elif NS_HTTPUPLOAD in event.features:
|
||||
elif NS_HTTPUPLOAD in features:
|
||||
self.httpupload_namespace = NS_HTTPUPLOAD
|
||||
else:
|
||||
return
|
||||
|
||||
self.component = event.jid
|
||||
self.component = from_
|
||||
log.info('Discovered component: %s', from_)
|
||||
|
||||
for form in event.data:
|
||||
for form in data:
|
||||
form_dict = form.asDict()
|
||||
if form_dict.get('FORM_TYPE', None) != self.httpupload_namespace:
|
||||
continue
|
||||
|
@ -112,14 +97,16 @@ class HTTPUpload:
|
|||
break
|
||||
|
||||
if self.max_file_size is None:
|
||||
log.warning('%s does not provide maximum file size', account)
|
||||
log.warning('%s does not provide maximum file size', self._account)
|
||||
else:
|
||||
log.info('%s has a maximum file size of: %s MiB',
|
||||
account, self.max_file_size / (1024 * 1024))
|
||||
self._account, self.max_file_size / (1024 * 1024))
|
||||
|
||||
self.available = True
|
||||
|
||||
for ctrl in app.interface.msg_win_mgr.get_controls(acct=self._account):
|
||||
ctrl.update_actions()
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def handle_outgoing_stanza(self, event):
|
||||
if event.conn.name != self._account:
|
||||
|
|
|
@ -47,6 +47,20 @@ class MAM:
|
|||
self.archiving_namespace = None
|
||||
self._mam_query_ids = {}
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_MAM_2 in features:
|
||||
self.archiving_namespace = nbxmpp.NS_MAM_2
|
||||
elif nbxmpp.NS_MAM_1 in features:
|
||||
self.archiving_namespace = nbxmpp.NS_MAM_1
|
||||
else:
|
||||
return
|
||||
|
||||
self.available = True
|
||||
log.info('Discovered MAM %s: %s', self.archiving_namespace, from_)
|
||||
# TODO: Move this GUI code out
|
||||
action = app.app.lookup_action('%s-archive' % self._account)
|
||||
action.set_enabled(True)
|
||||
|
||||
def _from_valid_archive(self, stanza, message, groupchat):
|
||||
if groupchat:
|
||||
expected_archive = message.getFrom()
|
||||
|
|
|
@ -38,6 +38,18 @@ class MUC:
|
|||
('message', self._direct_invite, '', nbxmpp.NS_CONFERENCE),
|
||||
]
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
for identity in identities:
|
||||
if identity.get('category') != 'conference':
|
||||
continue
|
||||
if identity.get('type') != 'text':
|
||||
continue
|
||||
if nbxmpp.NS_MUC in features:
|
||||
log.info('Discovered MUC: %s', from_)
|
||||
# TODO: make this nicer
|
||||
self._con.muc_jid['jabber'] = from_
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def set_subject(self, room_jid, subject):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
|
|
@ -36,9 +36,17 @@ class PEP:
|
|||
'headline', nbxmpp.NS_PUBSUB_EVENT)
|
||||
]
|
||||
|
||||
self.supported = False
|
||||
self._pep_handlers = {}
|
||||
self._store_publish_modules = []
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
for identity in identities:
|
||||
if identity['category'] == 'pubsub':
|
||||
if identity.get('type') == 'pep':
|
||||
log.info('Discovered PEP support: %s', from_)
|
||||
self.supported = True
|
||||
|
||||
def register_pep_handler(self, namespace, notify_handler, retract_handler):
|
||||
if namespace in self._pep_handlers:
|
||||
self._pep_handlers[namespace].append(
|
||||
|
@ -165,7 +173,7 @@ class AbstractPEPModule:
|
|||
self._stored_publish = None
|
||||
|
||||
def send(self, data):
|
||||
if not self._con.pep_supported:
|
||||
if not self._con.get_module('PEP').supported:
|
||||
return
|
||||
|
||||
if self._con.connected == 1:
|
||||
|
@ -184,7 +192,7 @@ class AbstractPEPModule:
|
|||
'', self.namespace, item, 'current')
|
||||
|
||||
def retract(self):
|
||||
if not self._con.pep_supported:
|
||||
if not self._con.get_module('PEP').supported:
|
||||
return
|
||||
self.send(None)
|
||||
self._con.get_module('PubSub').send_pb_retract(
|
||||
|
|
|
@ -43,6 +43,18 @@ class PrivacyLists:
|
|||
('iq', self._list_push_received, 'set', nbxmpp.NS_PRIVACY)
|
||||
]
|
||||
|
||||
self.supported = False
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_PRIVACY not in features:
|
||||
return
|
||||
|
||||
self.supported = True
|
||||
log.info('Discovered XEP-0016: Privacy Lists: %s', from_)
|
||||
# TODO: Move this GUI code out
|
||||
action = app.app.lookup_action('%s-privacylists' % self._account)
|
||||
action.set_enabled(True)
|
||||
|
||||
def _list_push_received(self, con, stanza):
|
||||
result = stanza.buildReply('result')
|
||||
result.delChild(result.getTag('query'))
|
||||
|
@ -287,7 +299,7 @@ class PrivacyLists:
|
|||
self.set_default_list(self.default_list)
|
||||
|
||||
def block_contacts(self, contact_list, message):
|
||||
if not self._con.privacy_rules_supported:
|
||||
if not self.supported:
|
||||
self._con.get_module('Blocking').block(contact_list)
|
||||
return
|
||||
|
||||
|
@ -332,7 +344,7 @@ class PrivacyLists:
|
|||
self.set_privacy_list(self.default_list, new_blocked_list)
|
||||
|
||||
def unblock_contacts(self, contact_list):
|
||||
if not self._con.privacy_rules_supported:
|
||||
if not self.supported:
|
||||
self._con.get_module('Blocking').unblock(contact_list)
|
||||
return
|
||||
|
||||
|
@ -367,7 +379,7 @@ class PrivacyLists:
|
|||
self._presence_probe(contact.jid)
|
||||
|
||||
def block_group(self, group, contact_list, message):
|
||||
if not self._con.privacy_rules_supported:
|
||||
if not self.supported:
|
||||
return
|
||||
if group in self.blocked_groups:
|
||||
return
|
||||
|
@ -393,7 +405,7 @@ class PrivacyLists:
|
|||
self.set_default_list(self.default_list)
|
||||
|
||||
def unblock_group(self, group, contact_list):
|
||||
if not self._con.privacy_rules_supported:
|
||||
if not self.supported:
|
||||
return
|
||||
|
||||
if group not in self.blocked_groups:
|
||||
|
|
|
@ -38,6 +38,16 @@ class PubSub:
|
|||
|
||||
self.handlers = []
|
||||
|
||||
self.publish_options = False
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_PUBSUB_PUBLISH_OPTIONS not in features:
|
||||
# Remove stored bookmarks accessible to everyone.
|
||||
self._con.get_module('Bookmarks').purge_pubsub_bookmarks()
|
||||
return
|
||||
log.info('Discovered Pubsub publish options: %s', from_)
|
||||
self.publish_options = True
|
||||
|
||||
def send_pb_subscription_query(self, jid, cb, **kwargs):
|
||||
if not app.account_is_connected(self._account):
|
||||
return
|
||||
|
|
|
@ -34,6 +34,13 @@ class SecLabels:
|
|||
self._catalogs = {}
|
||||
self.supported = False
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_SECLABEL not in features:
|
||||
return
|
||||
|
||||
self.supported = True
|
||||
log.info('Discovered security labels: %s', from_)
|
||||
|
||||
def request_catalog(self, jid):
|
||||
server = app.get_jid_from_account(self._account).split("@")[1]
|
||||
iq = nbxmpp.Iq(typ='get', to=server)
|
||||
|
|
|
@ -41,6 +41,17 @@ class VCardTemp:
|
|||
self._own_vcard = None
|
||||
self.own_vcard_received = False
|
||||
self.room_jids = []
|
||||
self.supported = False
|
||||
|
||||
def pass_disco(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_VCARD not in features:
|
||||
return
|
||||
|
||||
self.supported = True
|
||||
log.info('Discovered vcard-temp: %s', from_)
|
||||
# TODO: Move this GUI code out
|
||||
action = app.app.lookup_action('%s-profile' % self._account)
|
||||
action.set_enabled(True)
|
||||
|
||||
def _node_to_dict(self, node):
|
||||
dict_ = {}
|
||||
|
@ -67,6 +78,8 @@ class VCardTemp:
|
|||
|
||||
if isinstance(callback, RequestAvatar):
|
||||
if callback == RequestAvatar.SELF:
|
||||
if not self.supported:
|
||||
return
|
||||
callback = self._on_own_avatar_received
|
||||
elif callback == RequestAvatar.ROOM:
|
||||
callback = self._on_room_avatar_received
|
||||
|
|
|
@ -82,6 +82,19 @@ class ConnectionBytestream:
|
|||
app.ged.register_event_handler('file-request-received', ged.GUI1,
|
||||
self._nec_file_request_received)
|
||||
|
||||
def pass_bytestream_disco(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_BYTESTREAM not in features:
|
||||
return
|
||||
if app.config.get_per('accounts', self.name, 'use_ft_proxies'):
|
||||
log.info('Discovered proxy: %s', from_)
|
||||
our_fjid = self.get_own_jid()
|
||||
testit = app.config.get_per(
|
||||
'accounts', self.name, 'test_ft_proxies_on_startup')
|
||||
app.proxy65_manager.resolve(
|
||||
from_, self.connection, str(our_fjid),
|
||||
default=self.name, testit=testit)
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
||||
def cleanup(self):
|
||||
app.ged.remove_event_handler('file-request-received', ged.GUI1,
|
||||
self._nec_file_request_received)
|
||||
|
|
|
@ -41,14 +41,10 @@ class ConnectionCaps(object):
|
|||
app.nec.register_incoming_event(CapsReceivedEvent)
|
||||
app.ged.register_event_handler('caps-presence-received', ged.GUI1,
|
||||
self._nec_caps_presence_received)
|
||||
app.ged.register_event_handler('agent-info-received', ged.GUI1,
|
||||
self._nec_agent_info_received_caps)
|
||||
|
||||
def cleanup(self):
|
||||
app.ged.remove_event_handler('caps-presence-received', ged.GUI1,
|
||||
self._nec_caps_presence_received)
|
||||
app.ged.remove_event_handler('agent-info-received', ged.GUI1,
|
||||
self._nec_agent_info_received_caps)
|
||||
|
||||
def caps_change_account_name(self, new_name):
|
||||
self._account = new_name
|
||||
|
@ -81,16 +77,19 @@ class ConnectionCaps(object):
|
|||
contact = app.contacts.get_gc_contact(self._account, room_jid, nick)
|
||||
return contact
|
||||
|
||||
def _nec_agent_info_received_caps(self, obj):
|
||||
def _nec_agent_info_received_caps(self, from_, identities, features,
|
||||
data, node):
|
||||
"""
|
||||
callback to update our caps cache with queried information after
|
||||
we have retrieved an unknown caps hash and issued a disco
|
||||
"""
|
||||
if obj.conn.name != self._account:
|
||||
return
|
||||
contact = self._get_contact_or_gc_contact_for_jid(obj.fjid)
|
||||
fjid = str(from_)
|
||||
bare_jid = from_.getStripped()
|
||||
resource = from_.getResource()
|
||||
|
||||
contact = self._get_contact_or_gc_contact_for_jid(fjid)
|
||||
if not contact:
|
||||
log.info('Received Disco from unknown contact %s' % obj.fjid)
|
||||
log.info('Received Disco from unknown contact %s' % fjid)
|
||||
return
|
||||
|
||||
lookup = contact.client_caps.get_cache_lookup_strategy()
|
||||
|
@ -102,17 +101,21 @@ class ConnectionCaps(object):
|
|||
return
|
||||
else:
|
||||
validate = contact.client_caps.get_hash_validation_strategy()
|
||||
hash_is_valid = validate(obj.identities, obj.features, obj.data)
|
||||
hash_is_valid = validate(identities, features, data)
|
||||
|
||||
if hash_is_valid:
|
||||
cache_item.set_and_store(obj.identities, obj.features)
|
||||
cache_item.set_and_store(identities, features)
|
||||
else:
|
||||
node = caps_hash = hash_method = None
|
||||
contact.client_caps = self._create_suitable_client_caps(
|
||||
obj.node, caps_hash, hash_method)
|
||||
log.info('Computed and retrieved caps hash differ.' +
|
||||
node, caps_hash, hash_method)
|
||||
log.info('Computed and retrieved caps hash differ.'
|
||||
'Ignoring caps of contact %s' % contact.get_full_jid())
|
||||
|
||||
app.nec.push_incoming_event(CapsDiscoReceivedEvent(None,
|
||||
conn=self, fjid=obj.fjid, jid=obj.jid, resource=obj.resource,
|
||||
app.nec.push_incoming_event(
|
||||
CapsDiscoReceivedEvent(None,
|
||||
conn=self,
|
||||
fjid=fjid,
|
||||
jid=bare_jid,
|
||||
resource=resource,
|
||||
client_caps=contact.client_caps))
|
||||
|
|
|
@ -329,8 +329,6 @@ class P2PClient(IdleObject):
|
|||
nbxmpp.NS_BYTESTREAM)
|
||||
self.RegisterHandler('iq', self._caller._bytestreamErrorCB, 'error',
|
||||
nbxmpp.NS_BYTESTREAM)
|
||||
self.RegisterHandler('iq', self._caller._DiscoverItemsGetCB, 'get',
|
||||
nbxmpp.NS_DISCO_ITEMS)
|
||||
self.RegisterHandler('iq', self._caller._JingleCB, 'result')
|
||||
self.RegisterHandler('iq', self._caller._JingleCB, 'error')
|
||||
self.RegisterHandler('iq', self._caller._JingleCB, 'set',
|
||||
|
|
|
@ -191,20 +191,3 @@ connection_handlers.ConnectionJingle):
|
|||
# serverside metacontacts are not supported with zeroconf
|
||||
# (there is no server)
|
||||
pass
|
||||
|
||||
def _DiscoverItemsGetCB(self, con, iq_obj):
|
||||
log.debug('DiscoverItemsGetCB')
|
||||
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
|
||||
if self.get_module('AdHocCommands').command_items_query(iq_obj):
|
||||
raise nbxmpp.NodeProcessed
|
||||
node = iq_obj.getTagAttr('query', 'node')
|
||||
if node is None:
|
||||
result = iq_obj.buildReply('result')
|
||||
self.connection.send(result)
|
||||
raise nbxmpp.NodeProcessed
|
||||
if node == nbxmpp.NS_COMMANDS:
|
||||
self.get_module('AdHocCommands').command_list_query(iq_obj)
|
||||
raise nbxmpp.NodeProcessed
|
||||
|
|
|
@ -2845,6 +2845,7 @@ class ManagePEPServicesWindow:
|
|||
self.xml.get_object('delete_button').set_sensitive(False)
|
||||
self.xml.connect_signals(self)
|
||||
self.account = account
|
||||
self._con = app.connections[self.account]
|
||||
|
||||
self.init_services()
|
||||
self.xml.get_object('services_treeview').get_selection().connect(
|
||||
|
@ -2852,8 +2853,6 @@ class ManagePEPServicesWindow:
|
|||
|
||||
app.ged.register_event_handler('pubsub-config-received', ged.GUI1,
|
||||
self._nec_pep_config_received)
|
||||
app.ged.register_event_handler('agent-items-received', ged.GUI1,
|
||||
self._nec_agent_items_received)
|
||||
|
||||
self.window.show_all()
|
||||
|
||||
|
@ -2862,8 +2861,6 @@ class ManagePEPServicesWindow:
|
|||
del app.interface.instances[self.account]['pep_services']
|
||||
app.ged.remove_event_handler('pubsub-config-received', ged.GUI1,
|
||||
self._nec_pep_config_received)
|
||||
app.ged.remove_event_handler('agent-items-received', ged.GUI1,
|
||||
self._nec_agent_items_received)
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
@ -2885,15 +2882,19 @@ class ManagePEPServicesWindow:
|
|||
col.pack_start(cellrenderer_text, True)
|
||||
col.add_attribute(cellrenderer_text, 'text', 0)
|
||||
|
||||
our_jid = app.get_jid_from_account(self.account)
|
||||
app.connections[self.account].discoverItems(our_jid)
|
||||
jid = self._con.get_own_jid().getStripped()
|
||||
self._con.get_module('Discovery').disco_items(
|
||||
jid, success_cb=self._items_received, error_cb=self._items_error)
|
||||
|
||||
def _nec_agent_items_received(self, obj):
|
||||
our_jid = app.get_jid_from_account(self.account)
|
||||
for item in obj.items:
|
||||
if 'jid' in item and item['jid'] == our_jid and 'node' in item:
|
||||
def _items_received(self, from_, node, items):
|
||||
jid = self._con.get_own_jid().getStripped()
|
||||
for item in items:
|
||||
if item['jid'] == jid and 'node' in item:
|
||||
self.treestore.append([item['node']])
|
||||
|
||||
def _items_error(self, from_, error):
|
||||
ErrorDialog('Error', error)
|
||||
|
||||
def node_removed(self, jid, node):
|
||||
if jid != app.get_jid_from_account(self.account):
|
||||
return
|
||||
|
|
|
@ -258,24 +258,6 @@ class ServicesCache:
|
|||
self._info = CacheDictionary(0, getrefresh = False)
|
||||
self._subscriptions = CacheDictionary(5, getrefresh=False)
|
||||
self._cbs = {}
|
||||
app.ged.register_event_handler('agent-items-received', ged.GUI1,
|
||||
self._nec_agent_items_received)
|
||||
app.ged.register_event_handler('agent-items-error-received', ged.GUI1,
|
||||
self._nec_agent_items_error_received)
|
||||
app.ged.register_event_handler('agent-info-received', ged.GUI1,
|
||||
self._nec_agent_info_received)
|
||||
app.ged.register_event_handler('agent-info-error-received', ged.GUI1,
|
||||
self._nec_agent_info_error_received)
|
||||
|
||||
def __del__(self):
|
||||
app.ged.remove_event_handler('agent-items-received', ged.GUI1,
|
||||
self._nec_agent_items_received)
|
||||
app.ged.remove_event_handler('agent-items-error-received', ged.GUI1,
|
||||
self._nec_agent_items_error_received)
|
||||
app.ged.remove_event_handler('agent-info-received', ged.GUI1,
|
||||
self._nec_agent_info_received)
|
||||
app.ged.remove_event_handler('agent-info-error-received', ged.GUI1,
|
||||
self._nec_agent_info_error_received)
|
||||
|
||||
def cleanup(self):
|
||||
self._items.cleanup()
|
||||
|
@ -391,7 +373,9 @@ class ServicesCache:
|
|||
self._cbs[cbkey].append(cb)
|
||||
else:
|
||||
self._cbs[cbkey] = [cb]
|
||||
app.connections[self.account].discoverInfo(jid, node)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('Discovery').disco_info(
|
||||
jid, node, self._disco_info_received, self._disco_info_error)
|
||||
|
||||
def get_items(self, jid, node, cb, force=False, nofetch=False, args=()):
|
||||
"""
|
||||
|
@ -415,18 +399,32 @@ class ServicesCache:
|
|||
self._cbs[cbkey].append(cb)
|
||||
else:
|
||||
self._cbs[cbkey] = [cb]
|
||||
app.connections[self.account].discoverItems(jid, node)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('Discovery').disco_items(
|
||||
jid, node, self._disco_items_received, self._disco_items_error)
|
||||
|
||||
def _nec_agent_info_received(self, obj):
|
||||
def _disco_info_received(self, from_, identities, features, data, node):
|
||||
"""
|
||||
Callback for when we receive an agent's info
|
||||
array is (agent, node, identities, features, data)
|
||||
"""
|
||||
# We receive events from all accounts from GED
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
self._on_agent_info(obj.fjid, obj.node, obj.identities, obj.features,
|
||||
obj.data)
|
||||
self._on_agent_info(str(from_), node, identities, features, data)
|
||||
|
||||
def _disco_info_error(self, from_, error):
|
||||
"""
|
||||
Callback for when a query fails. Even after the browse and agents
|
||||
namespaces
|
||||
"""
|
||||
addr = get_agent_address(from_)
|
||||
|
||||
# Call callbacks
|
||||
cbkey = ('info', addr)
|
||||
if cbkey in self._cbs:
|
||||
for cb in self._cbs[cbkey]:
|
||||
cb(str(from_), '', 0, 0, 0)
|
||||
# clean_closure may have beaten us to it
|
||||
if cbkey in self._cbs:
|
||||
del self._cbs[cbkey]
|
||||
|
||||
def _on_agent_info(self, fjid, node, identities, features, data):
|
||||
addr = get_agent_address(fjid, node)
|
||||
|
@ -443,67 +441,42 @@ class ServicesCache:
|
|||
if cbkey in self._cbs:
|
||||
del self._cbs[cbkey]
|
||||
|
||||
def _nec_agent_items_received(self, obj):
|
||||
def _disco_items_received(self, from_, node, items):
|
||||
"""
|
||||
Callback for when we receive an agent's items
|
||||
array is (agent, node, items)
|
||||
"""
|
||||
# We receive events from all accounts from GED
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
|
||||
addr = get_agent_address(obj.fjid, obj.node)
|
||||
addr = get_agent_address(from_, node)
|
||||
|
||||
# Store in cache
|
||||
self._items[addr] = obj.items
|
||||
self._items[addr] = items
|
||||
|
||||
# Call callbacks
|
||||
cbkey = ('items', addr)
|
||||
if cbkey in self._cbs:
|
||||
for cb in self._cbs[cbkey]:
|
||||
cb(obj.fjid, obj.node, obj.items)
|
||||
cb(str(from_), node, items)
|
||||
# clean_closure may have beaten us to it
|
||||
if cbkey in self._cbs:
|
||||
del self._cbs[cbkey]
|
||||
|
||||
def _nec_agent_info_error_received(self, obj):
|
||||
def _disco_items_error(self, from_, error):
|
||||
"""
|
||||
Callback for when a query fails. Even after the browse and agents
|
||||
namespaces
|
||||
"""
|
||||
# We receive events from all accounts from GED
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
addr = get_agent_address(obj.fjid)
|
||||
|
||||
# Call callbacks
|
||||
cbkey = ('info', addr)
|
||||
if cbkey in self._cbs:
|
||||
for cb in self._cbs[cbkey]:
|
||||
cb(obj.fjid, '', 0, 0, 0)
|
||||
# clean_closure may have beaten us to it
|
||||
if cbkey in self._cbs:
|
||||
del self._cbs[cbkey]
|
||||
|
||||
def _nec_agent_items_error_received(self, obj):
|
||||
"""
|
||||
Callback for when a query fails. Even after the browse and agents
|
||||
namespaces
|
||||
"""
|
||||
# We receive events from all accounts from GED
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
addr = get_agent_address(obj.fjid)
|
||||
addr = get_agent_address(from_)
|
||||
|
||||
# Call callbacks
|
||||
cbkey = ('items', addr)
|
||||
if cbkey in self._cbs:
|
||||
for cb in self._cbs[cbkey]:
|
||||
cb(obj.fjid, '', 0)
|
||||
cb(str(from_), '', 0)
|
||||
# clean_closure may have beaten us to it
|
||||
if cbkey in self._cbs:
|
||||
del self._cbs[cbkey]
|
||||
|
||||
|
||||
# object is needed so that @property works
|
||||
class ServiceDiscoveryWindow(object):
|
||||
"""
|
||||
|
|
|
@ -1533,7 +1533,7 @@ class GroupchatControl(ChatControlBase):
|
|||
if '104' in obj.status_code:
|
||||
changes.append(_('A setting not related to privacy has been '
|
||||
'changed'))
|
||||
app.connections[self.account].discoverMUC(
|
||||
app.connections[self.account].get_module('Discovery').disco_muc(
|
||||
self.room_jid, self.update_actions, update=True)
|
||||
if '170' in obj.status_code:
|
||||
# Can be a presence (see chg_contact_status in groupchat_control.py)
|
||||
|
@ -2693,7 +2693,7 @@ class GroupchatControl(ChatControlBase):
|
|||
|
||||
item = xml.get_object('block_menuitem')
|
||||
item2 = xml.get_object('unblock_menuitem')
|
||||
if not app.connections[self.account].privacy_rules_supported:
|
||||
if not app.connections[self.account].get_module('PrivacyLists').supported:
|
||||
item2.set_no_show_all(True)
|
||||
item.set_no_show_all(True)
|
||||
item.hide()
|
||||
|
|
|
@ -80,13 +80,6 @@ class JoinGroupchatWindow(Gtk.ApplicationWindow):
|
|||
|
||||
self.builder.connect_signals(self)
|
||||
self.connect('key-press-event', self._on_key_press_event)
|
||||
self.connect('destroy', self._on_destroy)
|
||||
|
||||
if not self.minimal_mode:
|
||||
app.ged.register_event_handler('agent-info-received', ged.GUI1,
|
||||
self._nec_agent_info_received)
|
||||
app.ged.register_event_handler('agent-info-error-received', ged.GUI1,
|
||||
self._nec_agent_info_error_received)
|
||||
|
||||
# Hide account combobox if there is only one account
|
||||
if len(accounts) == 1:
|
||||
|
@ -277,48 +270,36 @@ class JoinGroupchatWindow(Gtk.ApplicationWindow):
|
|||
con.get_module('Bookmarks').add_bookmark(
|
||||
name, self.room_jid, autojoin, 1, password, nickname)
|
||||
|
||||
def _on_destroy(self, *args):
|
||||
if not self.minimal_mode:
|
||||
app.ged.remove_event_handler('agent-info-received', ged.GUI1,
|
||||
self._nec_agent_info_received)
|
||||
app.ged.remove_event_handler('agent-info-error-received', ged.GUI1,
|
||||
self._nec_agent_info_error_received)
|
||||
|
||||
def _on_search_clicked(self, widget):
|
||||
server = self.server_combo.get_active_text().strip()
|
||||
self.requested_jid = server
|
||||
app.connections[self.account].discoverInfo(server)
|
||||
con = app.connections[self.account]
|
||||
con.get_module('Discovery').disco_info(
|
||||
server,
|
||||
success_cb=self._disco_info_received,
|
||||
error_cb=self._disco_info_error)
|
||||
|
||||
def _nec_agent_info_error_received(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
if obj.jid != self.requested_jid:
|
||||
return
|
||||
self.requested_jid = None
|
||||
def _disco_info_error(self, from_, error):
|
||||
ErrorDialog(_('Wrong server'),
|
||||
_('%s is not a groupchat server') % obj.jid,
|
||||
_('%s is not a groupchat server') % from_,
|
||||
transient_for=self)
|
||||
|
||||
def _nec_agent_info_received(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
return
|
||||
if obj.jid != self.requested_jid:
|
||||
return
|
||||
self.requested_jid = None
|
||||
if nbxmpp.NS_MUC not in obj.features:
|
||||
def _disco_info_received(self, from_, identities, features, data, node):
|
||||
if nbxmpp.NS_MUC not in features:
|
||||
ErrorDialog(_('Wrong server'),
|
||||
_('%s is not a groupchat server') % obj.jid,
|
||||
_('%s is not a groupchat server') % from_,
|
||||
transient_for=self)
|
||||
return
|
||||
if obj.jid in app.interface.instances[self.account]['disco']:
|
||||
app.interface.instances[self.account]['disco'][obj.jid].window.\
|
||||
|
||||
jid = str(from_)
|
||||
if jid in app.interface.instances[self.account]['disco']:
|
||||
app.interface.instances[self.account]['disco'][jid].window.\
|
||||
present()
|
||||
else:
|
||||
try:
|
||||
# Object will add itself to the window dict
|
||||
from gajim.disco import ServiceDiscoveryWindow
|
||||
ServiceDiscoveryWindow(
|
||||
self.account, obj.jid,
|
||||
self.account, jid,
|
||||
initial_identities=[{'category': 'conference',
|
||||
'type': 'text'}])
|
||||
except GajimGeneralException:
|
||||
|
|
|
@ -61,9 +61,9 @@ class ServerInfoDialog(Gtk.Dialog):
|
|||
ged.CORE,
|
||||
self._nec_version_result_received)
|
||||
|
||||
app.ged.register_event_handler('agent-info-received',
|
||||
app.ged.register_event_handler('server-disco-received',
|
||||
ged.GUI1,
|
||||
self._nec_agent_info_received)
|
||||
self._server_disco_received)
|
||||
|
||||
self.version = ''
|
||||
self.uptime = ''
|
||||
|
@ -132,9 +132,7 @@ class ServerInfoDialog(Gtk.Dialog):
|
|||
self.version = obj.client_info
|
||||
self.update(self.get_infos, self.info_listbox)
|
||||
|
||||
def _nec_agent_info_received(self, obj):
|
||||
if 'Gajim_' not in obj.id_:
|
||||
return
|
||||
def _server_disco_received(self, obj):
|
||||
self.update(self.get_features, self.feature_listbox)
|
||||
|
||||
def add_feature(self, feature):
|
||||
|
@ -154,22 +152,25 @@ class ServerInfoDialog(Gtk.Dialog):
|
|||
|
||||
return [
|
||||
Feature('XEP-0016: Privacy Lists',
|
||||
con.privacy_rules_supported, '', None),
|
||||
con.get_module('PrivacyLists').supported, '', None),
|
||||
Feature('XEP-0045: Multi-User Chat', con.muc_jid, '', None),
|
||||
Feature('XEP-0054: vcard-temp', con.vcard_supported, '', None),
|
||||
Feature('XEP-0054: vcard-temp',
|
||||
con.get_module('VCardTemp').supported, '', None),
|
||||
Feature('XEP-0163: Personal Eventing Protocol',
|
||||
con.pep_supported, '', None),
|
||||
con.get_module('PEP').supported, '', None),
|
||||
Feature('XEP-0163: #publish-options',
|
||||
con.pubsub_publish_options_supported, '', None),
|
||||
con.get_module('PubSub').publish_options, '', None),
|
||||
Feature('XEP-0191: Blocking Command',
|
||||
con.blocking_supported, nbxmpp.NS_BLOCKING, None),
|
||||
con.get_module('Blocking').supported,
|
||||
nbxmpp.NS_BLOCKING, None),
|
||||
Feature('XEP-0198: Stream Management',
|
||||
con.sm.enabled, nbxmpp.NS_STREAM_MGMT, None),
|
||||
Feature('XEP-0258: Security Labels in XMPP',
|
||||
con.get_module('SecLabels').supported,
|
||||
nbxmpp.NS_SECLABEL, None),
|
||||
Feature('XEP-0280: Message Carbons',
|
||||
con.carbons_available, nbxmpp.NS_CARBONS, carbons_enabled),
|
||||
con.get_module('Carbons').supported,
|
||||
nbxmpp.NS_CARBONS, carbons_enabled),
|
||||
Feature('XEP-0313: Message Archive Management',
|
||||
con.get_module('MAM').archiving_namespace,
|
||||
con.get_module('MAM').archiving_namespace,
|
||||
|
@ -198,9 +199,9 @@ class ServerInfoDialog(Gtk.Dialog):
|
|||
ged.CORE,
|
||||
self._nec_version_result_received)
|
||||
|
||||
app.ged.remove_event_handler('agent-info-received',
|
||||
app.ged.remove_event_handler('server-disco-received',
|
||||
ged.GUI1,
|
||||
self._nec_agent_info_received)
|
||||
self._server_disco_received)
|
||||
|
||||
|
||||
class FeatureItem(Gtk.Grid):
|
||||
|
|
|
@ -1116,6 +1116,8 @@ class Interface:
|
|||
app.block_signed_in_notifications[account] = True
|
||||
connected = obj.conn.connected
|
||||
|
||||
pep_supported = obj.conn.get_module('PEP').supported
|
||||
|
||||
if not idle.Monitor.is_unknown() and connected in (2, 3):
|
||||
# we go online or free for chat, so we activate auto status
|
||||
app.sleeper_state[account] = 'online'
|
||||
|
@ -1135,11 +1137,11 @@ class Interface:
|
|||
if connected == invisible_show:
|
||||
return
|
||||
# send currently played music
|
||||
if (obj.conn.pep_supported and sys.platform == 'linux' and
|
||||
if (pep_supported and sys.platform == 'linux' and
|
||||
app.config.get_per('accounts', account, 'publish_tune')):
|
||||
self.enable_music_listener()
|
||||
# enable location listener
|
||||
if (obj.conn.pep_supported and app.is_installed('GEOCLUE') and
|
||||
if (pep_supported and app.is_installed('GEOCLUE') and
|
||||
app.config.get_per('accounts', account, 'publish_location')):
|
||||
location_listener.enable()
|
||||
|
||||
|
@ -1785,7 +1787,7 @@ class Interface:
|
|||
transient_for=transient_for)
|
||||
|
||||
disco_account = connected_accounts[0] if account is None else account
|
||||
app.connections[disco_account].discoverMUC(
|
||||
app.connections[disco_account].get_module('Discovery').disco_muc(
|
||||
room_jid, _on_discover_result)
|
||||
|
||||
################################################################################
|
||||
|
@ -2187,7 +2189,7 @@ class Interface:
|
|||
for acct in accounts:
|
||||
if not app.account_is_connected(acct):
|
||||
continue
|
||||
if not app.connections[acct].pep_supported:
|
||||
if not app.connections[acct].get_module('PEP').supported:
|
||||
continue
|
||||
if not app.config.get_per('accounts', acct, 'publish_tune'):
|
||||
continue
|
||||
|
|
|
@ -460,8 +460,10 @@ control=None, gc_contact=None, is_anonymous=True):
|
|||
execute_command_menuitem, send_custom_status_menuitem):
|
||||
widget.set_sensitive(False)
|
||||
|
||||
if app.connections[account] and (app.connections[account].\
|
||||
privacy_rules_supported or app.connections[account].blocking_supported):
|
||||
|
||||
con = app.connections[account]
|
||||
if con and (con.get_module('PrivacyLists').supported or
|
||||
con.get_module('Blocking').supported):
|
||||
if helpers.jid_is_blocked(account, jid):
|
||||
block_menuitem.set_no_show_all(True)
|
||||
block_menuitem.hide()
|
||||
|
|
|
@ -2840,9 +2840,14 @@ class RosterWindow:
|
|||
if msg is None:
|
||||
# user pressed Cancel to change status message dialog
|
||||
return
|
||||
accounts = set(i[1] for i in list_ if (app.connections[i[1]].\
|
||||
privacy_rules_supported or (group is None and app.\
|
||||
connections[i[1]].blocking_supported)))
|
||||
|
||||
accounts = []
|
||||
for _, account in list_:
|
||||
con = app.connections[account]
|
||||
if con.get_module('PrivacyLists').supported or (
|
||||
group is None and con.get_module('Blocking').supported):
|
||||
accounts.append(account)
|
||||
|
||||
if group is None:
|
||||
for acct in accounts:
|
||||
l_ = [i[0] for i in list_ if i[1] == acct]
|
||||
|
@ -2882,9 +2887,13 @@ class RosterWindow:
|
|||
"""
|
||||
When clicked on the 'unblock' button in context menu.
|
||||
"""
|
||||
accounts = set(i[1] for i in list_ if (app.connections[i[1]].\
|
||||
privacy_rules_supported or (group is None and app.\
|
||||
connections[i[1]].blocking_supported)))
|
||||
accounts = []
|
||||
for _, account in list_:
|
||||
con = app.connections[account]
|
||||
if con.get_module('PrivacyLists').supported or (
|
||||
group is None and con.get_module('Blocking').supported):
|
||||
accounts.append(account)
|
||||
|
||||
if group is None:
|
||||
for acct in accounts:
|
||||
l_ = [i[0] for i in list_ if i[1] == acct]
|
||||
|
@ -4916,7 +4925,7 @@ class RosterWindow:
|
|||
sub_menu.append(item)
|
||||
con = app.connections[account]
|
||||
if show == 'invisible' and con.connected > 1 and \
|
||||
not con.privacy_rules_supported:
|
||||
not con.get_module('PrivacyLists').supported:
|
||||
item.set_sensitive(False)
|
||||
else:
|
||||
item.connect('activate', self.change_status, account, show)
|
||||
|
@ -4940,7 +4949,7 @@ class RosterWindow:
|
|||
item.connect('activate', self.change_status, account, 'offline')
|
||||
|
||||
pep_menuitem = xml.get_object('pep_menuitem')
|
||||
if app.connections[account].pep_supported:
|
||||
if app.connections[account].get_module('PEP').supported:
|
||||
pep_submenu = Gtk.Menu()
|
||||
pep_menuitem.set_submenu(pep_submenu)
|
||||
|
||||
|
@ -5183,8 +5192,7 @@ class RosterWindow:
|
|||
if helpers.group_is_blocked(account, group):
|
||||
is_blocked = True
|
||||
|
||||
if is_blocked and app.connections[account].\
|
||||
privacy_rules_supported:
|
||||
if is_blocked and app.connections[account].get_module('PrivacyLists').supported:
|
||||
unblock_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Unblock'))
|
||||
unblock_menuitem.connect('activate', self.on_unblock, list_,
|
||||
group)
|
||||
|
@ -5193,7 +5201,7 @@ class RosterWindow:
|
|||
block_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Block'))
|
||||
block_menuitem.connect('activate', self.on_block, list_, group)
|
||||
menu.append(block_menuitem)
|
||||
if not app.connections[account].privacy_rules_supported:
|
||||
if not app.connections[account].get_module('PrivacyLists').supported:
|
||||
block_menuitem.set_sensitive(False)
|
||||
|
||||
# Remove group
|
||||
|
@ -5245,7 +5253,7 @@ class RosterWindow:
|
|||
account = model[titer][Column.ACCOUNT]
|
||||
if app.connections[account].connected < 2:
|
||||
one_account_offline = True
|
||||
if not app.connections[account].privacy_rules_supported:
|
||||
if not app.connections[account].get_module('PrivacyLists').supported:
|
||||
privacy_rules_supported = False
|
||||
contact = app.contacts.get_contact_with_highest_priority(account,
|
||||
jid)
|
||||
|
@ -5411,7 +5419,7 @@ class RosterWindow:
|
|||
self.on_xml_console_menuitem_activate, account)
|
||||
|
||||
if app.connections[account]:
|
||||
if app.connections[account].privacy_rules_supported:
|
||||
if app.connections[account].get_module('PrivacyLists').supported:
|
||||
privacy_lists_menuitem.connect('activate',
|
||||
self.on_privacy_lists_menuitem_activate, account)
|
||||
else:
|
||||
|
|
|
@ -102,6 +102,9 @@ class Mock(object):
|
|||
if not name in baseMethods:
|
||||
self.__dict__[name] = MockCallable(name, self, handcrafted=True)
|
||||
|
||||
def get_module(self, name):
|
||||
return Mock()
|
||||
|
||||
def __getattr__(self, name):
|
||||
return MockCallable(name, self)
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ import unittest
|
|||
import lib
|
||||
lib.setup_env()
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
from nbxmpp import NS_MUC, NS_PING, NS_XHTML_IM, Iq
|
||||
from gajim.common import caps_cache as caps
|
||||
from gajim.common.contacts import Contact
|
||||
from gajim.common.connection_handlers_events import AgentInfoReceivedEvent
|
||||
from gajim.common.modules.discovery import Discovery
|
||||
|
||||
from mock import Mock
|
||||
|
||||
|
@ -106,29 +106,29 @@ class TestCapsCache(CommonCapsTest):
|
|||
|
||||
def test_preload_triggering_query(self):
|
||||
''' Make sure that preload issues a disco '''
|
||||
connection = Mock()
|
||||
connection = MagicMock()
|
||||
client_caps = caps.ClientCaps(self.caps_hash, self.node, self.caps_method)
|
||||
|
||||
self.cc.query_client_of_jid_if_unknown(connection, "test@gajim.org",
|
||||
client_caps)
|
||||
self.cc.query_client_of_jid_if_unknown(
|
||||
connection, "test@gajim.org", client_caps)
|
||||
|
||||
self.assertEqual(1, len(connection.mockGetAllCalls()))
|
||||
self.assertEqual(1, connection.get_module('Discovery').disco_contact.call_count)
|
||||
|
||||
def test_no_preload_query_if_cashed(self):
|
||||
''' Preload must not send a query if the data is already cached '''
|
||||
connection = Mock()
|
||||
connection = MagicMock()
|
||||
client_caps = caps.ClientCaps(self.caps_hash, self.node, self.caps_method)
|
||||
|
||||
self.cc.initialize_from_db()
|
||||
self.cc.query_client_of_jid_if_unknown(connection, "test@gajim.org",
|
||||
client_caps)
|
||||
self.cc.query_client_of_jid_if_unknown(
|
||||
connection, "test@gajim.org", client_caps)
|
||||
|
||||
self.assertEqual(0, len(connection.mockGetAllCalls()))
|
||||
self.assertEqual(0, connection.get_module('Discovery').disco_contact.call_count)
|
||||
|
||||
def test_hash(self):
|
||||
'''tests the hash computation'''
|
||||
stanza = Iq(node=COMPLEX_EXAMPLE)
|
||||
identities, features, data, _ = AgentInfoReceivedEvent.parse_stanza(stanza)
|
||||
identities, features, data, _ = Discovery.parse_info_response(stanza)
|
||||
computed_hash = caps.compute_caps_hash(identities, features, data)
|
||||
self.assertEqual('q07IKJEyjvHSyhy//CH0CxmKi8w=', computed_hash)
|
||||
|
||||
|
@ -141,12 +141,11 @@ class TestClientCaps(CommonCapsTest):
|
|||
|
||||
def test_query_by_get_discover_strategy(self):
|
||||
''' Client must be queried if the data is unkown '''
|
||||
connection = Mock()
|
||||
connection = MagicMock()
|
||||
discover = self.client_caps.get_discover_strategy()
|
||||
discover(connection, "test@gajim.org")
|
||||
|
||||
connection.mockCheckCall(0, "discoverInfo", "test@gajim.org",
|
||||
"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
|
||||
connection.get_module('Discovery').disco_contact.assert_called_once_with(
|
||||
'test@gajim.org', 'http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=')
|
||||
|
||||
def test_client_supports(self):
|
||||
self.assertTrue(caps.client_supports(self.client_caps, NS_PING),
|
||||
|
@ -175,11 +174,11 @@ class TestOldClientCaps(TestClientCaps):
|
|||
|
||||
def test_query_by_get_discover_strategy(self):
|
||||
''' Client must be queried if the data is unknown '''
|
||||
connection = Mock()
|
||||
connection = MagicMock()
|
||||
discover = self.client_caps.get_discover_strategy()
|
||||
discover(connection, "test@gajim.org")
|
||||
|
||||
connection.mockCheckCall(0, "discoverInfo", "test@gajim.org")
|
||||
connection.get_module('Discovery').disco_contact.assert_called_once_with('test@gajim.org')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in New Issue