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)]
|
return caps_cache[(self._hash_method, self._hash)]
|
||||||
|
|
||||||
def _discover(self, connection, jid):
|
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):
|
def _is_hash_valid(self, identities, features, dataforms):
|
||||||
computed_hash = compute_caps_hash(identities, features,
|
computed_hash = compute_caps_hash(
|
||||||
dataforms=dataforms, hash_method=self._hash_method)
|
identities, features, dataforms=dataforms,
|
||||||
|
hash_method=self._hash_method)
|
||||||
return computed_hash == self._hash
|
return computed_hash == self._hash
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,7 +229,7 @@ class OldClientCaps(AbstractClientCaps):
|
||||||
return caps_cache[('old', self._node + '#' + self._hash)]
|
return caps_cache[('old', self._node + '#' + self._hash)]
|
||||||
|
|
||||||
def _discover(self, connection, jid):
|
def _discover(self, connection, jid):
|
||||||
connection.discoverInfo(jid)
|
connection.get_module('Discovery').disco_contact(jid)
|
||||||
|
|
||||||
def _is_hash_valid(self, identities, features, dataforms):
|
def _is_hash_valid(self, identities, features, dataforms):
|
||||||
return True
|
return True
|
||||||
|
@ -244,7 +246,7 @@ class NoClientCaps(AbstractClientCaps):
|
||||||
return caps_cache[('no', self._node)]
|
return caps_cache[('no', self._node)]
|
||||||
|
|
||||||
def _discover(self, connection, jid):
|
def _discover(self, connection, jid):
|
||||||
connection.discoverInfo(jid)
|
connection.get_module('Discovery').disco_contact(jid)
|
||||||
|
|
||||||
def _is_hash_valid(self, identities, features, dataforms):
|
def _is_hash_valid(self, identities, features, dataforms):
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -103,7 +103,6 @@ class CommonConnection:
|
||||||
self.priority = app.get_priority(name, 'offline')
|
self.priority = app.get_priority(name, 'offline')
|
||||||
self.time_to_reconnect = None
|
self.time_to_reconnect = None
|
||||||
|
|
||||||
self.pep_supported = False
|
|
||||||
self.pep = {}
|
self.pep = {}
|
||||||
# Do we continue connection when we get roster (send presence,get vcard..)
|
# Do we continue connection when we get roster (send presence,get vcard..)
|
||||||
self.continue_connect_info = None
|
self.continue_connect_info = None
|
||||||
|
@ -115,13 +114,9 @@ class CommonConnection:
|
||||||
# the fake jid
|
# the fake jid
|
||||||
self.groupchat_jids = {} # {ID : groupchat_jid}
|
self.groupchat_jids = {} # {ID : groupchat_jid}
|
||||||
|
|
||||||
self.privacy_rules_supported = False
|
|
||||||
self.vcard_supported = False
|
|
||||||
self.private_storage_supported = False
|
self.private_storage_supported = False
|
||||||
self.roster_supported = True
|
self.roster_supported = True
|
||||||
self.blocking_supported = False
|
|
||||||
self.addressing_supported = False
|
self.addressing_supported = False
|
||||||
self.carbons_available = False
|
|
||||||
|
|
||||||
self.muc_jid = {} # jid of muc server for each transport type
|
self.muc_jid = {} # jid of muc server for each transport type
|
||||||
self._stun_servers = [] # STUN servers of our jabber server
|
self._stun_servers = [] # STUN servers of our jabber server
|
||||||
|
@ -582,7 +577,6 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
self.music_track_info = 0
|
self.music_track_info = 0
|
||||||
|
|
||||||
self.register_supported = False
|
self.register_supported = False
|
||||||
self.pubsub_publish_options_supported = False
|
|
||||||
# Do we auto accept insecure connection
|
# Do we auto accept insecure connection
|
||||||
self.connection_auto_accepted = False
|
self.connection_auto_accepted = False
|
||||||
self.pasword_callback = None
|
self.pasword_callback = None
|
||||||
|
@ -611,10 +605,6 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
# Register all modules
|
# Register all modules
|
||||||
modules.register(self)
|
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,
|
app.ged.register_event_handler('message-outgoing', ged.OUT_CORE,
|
||||||
self._nec_message_outgoing)
|
self._nec_message_outgoing)
|
||||||
app.ged.register_event_handler('gc-message-outgoing', ged.OUT_CORE,
|
app.ged.register_event_handler('gc-message-outgoing', ged.OUT_CORE,
|
||||||
|
@ -629,10 +619,6 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
ConnectionHandlers.cleanup(self)
|
ConnectionHandlers.cleanup(self)
|
||||||
modules.unregister(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,
|
app.ged.remove_event_handler('message-outgoing', ged.OUT_CORE,
|
||||||
self._nec_message_outgoing)
|
self._nec_message_outgoing)
|
||||||
app.ged.remove_event_handler('gc-message-outgoing', ged.OUT_CORE,
|
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.on_purpose = on_purpose
|
||||||
self.connected = 0
|
self.connected = 0
|
||||||
self.time_to_reconnect = None
|
self.time_to_reconnect = None
|
||||||
self.privacy_rules_supported = False
|
self.get_module('PrivacyLists').supported = False
|
||||||
self.get_module('VCardAvatars').avatar_advertised = False
|
self.get_module('VCardAvatars').avatar_advertised = False
|
||||||
if on_purpose:
|
if on_purpose:
|
||||||
self.sm = Smacks(self)
|
self.sm = Smacks(self)
|
||||||
|
@ -1430,7 +1416,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
def send_invisible_presence(self, msg, signed, initial = False):
|
def send_invisible_presence(self, msg, signed, initial = False):
|
||||||
if not app.account_is_connected(self.name):
|
if not app.account_is_connected(self.name):
|
||||||
return
|
return
|
||||||
if not self.privacy_rules_supported:
|
if not self.get_module('PrivacyLists').supported:
|
||||||
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
|
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
|
||||||
show=app.SHOW_LIST[self.connected]))
|
show=app.SHOW_LIST[self.connected]))
|
||||||
app.nec.push_incoming_event(InformationEvent(
|
app.nec.push_incoming_event(InformationEvent(
|
||||||
|
@ -1438,7 +1424,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
return
|
return
|
||||||
# If we are already connected, and privacy rules are supported, send
|
# If we are already connected, and privacy rules are supported, send
|
||||||
# offline presence first as it's required by XEP-0126
|
# 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
|
self.on_purpose = True
|
||||||
p = nbxmpp.Presence(typ='unavailable')
|
p = nbxmpp.Presence(typ='unavailable')
|
||||||
p = self.add_sha(p, False)
|
p = self.add_sha(p, False)
|
||||||
|
@ -1515,10 +1501,9 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
# If we are not resuming, we ask for discovery info
|
# If we are not resuming, we ask for discovery info
|
||||||
# and archiving preferences
|
# and archiving preferences
|
||||||
if not self.sm.supports_sm or (not self.sm.resuming and self.sm.enabled):
|
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')
|
our_server = app.config.get_per('accounts', self.name, 'hostname')
|
||||||
self.discoverInfo(our_jid, id_prefix='Gajim_')
|
self.get_module('Discovery').discover_account_info()
|
||||||
self.discoverInfo(our_server, id_prefix='Gajim_')
|
self.get_module('Discovery').discover_server_info()
|
||||||
else:
|
else:
|
||||||
self.request_roster(resume=True)
|
self.request_roster(resume=True)
|
||||||
|
|
||||||
|
@ -1534,7 +1519,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
self._stun_servers = self._hosts = [i for i in result_array]
|
self._stun_servers = self._hosts = [i for i in result_array]
|
||||||
|
|
||||||
def _continue_connection_request_privacy(self):
|
def _continue_connection_request_privacy(self):
|
||||||
if self.privacy_rules_supported:
|
if self.get_module('PrivacyLists').supported:
|
||||||
if not self.privacy_rules_requested:
|
if not self.privacy_rules_requested:
|
||||||
self.privacy_rules_requested = True
|
self.privacy_rules_requested = True
|
||||||
self.get_module('PrivacyLists').get_privacy_lists(
|
self.get_module('PrivacyLists').get_privacy_lists(
|
||||||
|
@ -1557,104 +1542,12 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
None, dialog_name='invisibility-not-supported',
|
None, dialog_name='invisibility-not-supported',
|
||||||
args=self.name))
|
args=self.name))
|
||||||
return
|
return
|
||||||
if self.blocking_supported:
|
|
||||||
self.get_module('Blocking').get_blocking_list()
|
self.get_module('Blocking').get_blocking_list()
|
||||||
|
|
||||||
# Ask metacontacts before roster
|
# Ask metacontacts before roster
|
||||||
self.get_metacontacts()
|
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):
|
def send_custom_status(self, show, msg, jid):
|
||||||
if not show in app.SHOW_LIST:
|
if not show in app.SHOW_LIST:
|
||||||
return -1
|
return -1
|
||||||
|
@ -1684,7 +1577,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
self.send_invisible_presence(msg, signed)
|
self.send_invisible_presence(msg, signed)
|
||||||
|
|
||||||
def _change_from_invisible(self):
|
def _change_from_invisible(self):
|
||||||
if self.privacy_rules_supported:
|
if self.get_module('PrivacyLists').supported:
|
||||||
self.get_module('PrivacyLists').set_active_list(None)
|
self.get_module('PrivacyLists').set_active_list(None)
|
||||||
|
|
||||||
def _update_status(self, show, msg, idle_time=None):
|
def _update_status(self, show, msg, idle_time=None):
|
||||||
|
@ -1897,7 +1790,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
def bookmarks_available(self):
|
def bookmarks_available(self):
|
||||||
if self.private_storage_supported:
|
if self.private_storage_supported:
|
||||||
return True
|
return True
|
||||||
if self.pubsub_publish_options_supported:
|
if self.get_module('PubSub').publish_options:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -2022,7 +1915,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
# Never join a room when invisible
|
# Never join a room when invisible
|
||||||
return
|
return
|
||||||
|
|
||||||
self.discoverMUC(
|
self.get_module('Discovery').disco_muc(
|
||||||
room_jid, partial(self._join_gc, nick, show, room_jid,
|
room_jid, partial(self._join_gc, nick, show, room_jid,
|
||||||
password, change_nick, rejoin))
|
password, change_nick, rejoin))
|
||||||
|
|
||||||
|
|
|
@ -66,51 +66,6 @@ PRIVACY_ARRIVED = 'privacy_arrived'
|
||||||
|
|
||||||
|
|
||||||
class ConnectionDisco:
|
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):
|
def request_register_agent_info(self, agent):
|
||||||
if not self.connection or self.connected < 2:
|
if not self.connection or self.connected < 2:
|
||||||
|
@ -159,117 +114,10 @@ class ConnectionDisco:
|
||||||
self.agent_registrations[agent] = {'roster_push': False,
|
self.agent_registrations[agent] = {'roster_push': False,
|
||||||
'sub_received': 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):
|
def _ReceivedRegInfo(self, con, resp, agent):
|
||||||
nbxmpp.features_nb._ReceivedRegInfo(con, resp, agent)
|
nbxmpp.features_nb._ReceivedRegInfo(con, resp, agent)
|
||||||
self._IqCB(con, resp)
|
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
|
# basic connection handlers used here and in zeroconf
|
||||||
class ConnectionHandlersBase:
|
class ConnectionHandlersBase:
|
||||||
|
@ -292,25 +140,17 @@ class ConnectionHandlersBase:
|
||||||
# We decrypt GPG messages one after the other. Keep queue in mem
|
# We decrypt GPG messages one after the other. Keep queue in mem
|
||||||
self.gpg_messages_to_decrypt = []
|
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,
|
app.ged.register_event_handler('presence-received', ged.CORE,
|
||||||
self._nec_presence_received)
|
self._nec_presence_received)
|
||||||
app.ged.register_event_handler('gc-message-received', ged.CORE,
|
app.ged.register_event_handler('gc-message-received', ged.CORE,
|
||||||
self._nec_gc_message_received)
|
self._nec_gc_message_received)
|
||||||
|
|
||||||
def cleanup(self):
|
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,
|
app.ged.remove_event_handler('presence-received', ged.CORE,
|
||||||
self._nec_presence_received)
|
self._nec_presence_received)
|
||||||
app.ged.remove_event_handler('gc-message-received', ged.CORE,
|
app.ged.remove_event_handler('gc-message-received', ged.CORE,
|
||||||
self._nec_gc_message_received)
|
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):
|
def _nec_presence_received(self, obj):
|
||||||
account = obj.conn.name
|
account = obj.conn.name
|
||||||
if account != self.name:
|
if account != self.name:
|
||||||
|
@ -647,8 +487,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
ged.CORE, self._nec_roster_set_received)
|
ged.CORE, self._nec_roster_set_received)
|
||||||
app.ged.register_event_handler('roster-received', ged.CORE,
|
app.ged.register_event_handler('roster-received', ged.CORE,
|
||||||
self._nec_roster_received)
|
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',
|
app.ged.register_event_handler('subscribe-presence-received',
|
||||||
ged.CORE, self._nec_subscribe_presence_received)
|
ged.CORE, self._nec_subscribe_presence_received)
|
||||||
app.ged.register_event_handler('subscribed-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)
|
ged.CORE, self._nec_roster_set_received)
|
||||||
app.ged.remove_event_handler('roster-received', ged.CORE,
|
app.ged.remove_event_handler('roster-received', ged.CORE,
|
||||||
self._nec_roster_received)
|
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',
|
app.ged.remove_event_handler('subscribe-presence-received',
|
||||||
ged.CORE, self._nec_subscribe_presence_received)
|
ged.CORE, self._nec_subscribe_presence_received)
|
||||||
app.ged.remove_event_handler('subscribed-presence-received',
|
app.ged.remove_event_handler('subscribed-presence-received',
|
||||||
|
@ -762,28 +598,14 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
self._getRoster()
|
self._getRoster()
|
||||||
elif iq_obj.getType() == 'error':
|
elif iq_obj.getType() == 'error':
|
||||||
self.roster_supported = False
|
self.roster_supported = False
|
||||||
self.discoverItems(app.config.get_per('accounts', self.name,
|
self.get_module('Discovery').discover_server_items()
|
||||||
'hostname'), id_prefix='Gajim_')
|
|
||||||
if app.config.get_per('accounts', self.name,
|
if app.config.get_per('accounts', self.name,
|
||||||
'use_ft_proxies'):
|
'use_ft_proxies'):
|
||||||
self.discover_ft_proxies()
|
self.discover_ft_proxies()
|
||||||
app.nec.push_incoming_event(RosterReceivedEvent(None,
|
app.nec.push_incoming_event(RosterReceivedEvent(None,
|
||||||
conn=self))
|
conn=self))
|
||||||
GLib.timeout_add_seconds(10, self.discover_servers)
|
|
||||||
del self.awaiting_answers[id_]
|
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):
|
def _rosterSetCB(self, con, iq_obj):
|
||||||
log.debug('rosterSetCB')
|
log.debug('rosterSetCB')
|
||||||
app.nec.push_incoming_event(RosterSetReceivedEvent(None, conn=self,
|
app.nec.push_incoming_event(RosterSetReceivedEvent(None, conn=self,
|
||||||
|
@ -972,8 +794,7 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
return
|
return
|
||||||
self.connection.getRoster(self._on_roster_set)
|
self.connection.getRoster(self._on_roster_set)
|
||||||
self.discoverItems(app.config.get_per('accounts', self.name,
|
self.get_module('Discovery').discover_server_items()
|
||||||
'hostname'), id_prefix='Gajim_')
|
|
||||||
if app.config.get_per('accounts', self.name, 'use_ft_proxies'):
|
if app.config.get_per('accounts', self.name, 'use_ft_proxies'):
|
||||||
self.discover_ft_proxies()
|
self.discover_ft_proxies()
|
||||||
|
|
||||||
|
@ -990,17 +811,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
app.proxy65_manager.resolve(proxy, self.connection, our_jid,
|
app.proxy65_manager.resolve(proxy, self.connection, our_jid,
|
||||||
testit=testit)
|
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):
|
def _on_roster_set(self, roster):
|
||||||
app.nec.push_incoming_event(RosterReceivedEvent(None, conn=self,
|
app.nec.push_incoming_event(RosterReceivedEvent(None, conn=self,
|
||||||
xmpp_roster=roster))
|
xmpp_roster=roster))
|
||||||
|
@ -1027,13 +837,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
if send_first_presence:
|
if send_first_presence:
|
||||||
self._send_first_presence(signed)
|
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)
|
app.logger.replace_roster(self.name, obj.version, obj.roster)
|
||||||
|
|
||||||
for contact in app.contacts.iter_contacts(self.name):
|
for contact in app.contacts.iter_contacts(self.name):
|
||||||
|
@ -1080,9 +883,9 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
self.priority = priority
|
self.priority = priority
|
||||||
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
|
app.nec.push_incoming_event(OurShowEvent(None, conn=self,
|
||||||
show=show))
|
show=show))
|
||||||
if self.vcard_supported:
|
|
||||||
# ask our VCard
|
# ask our VCard
|
||||||
self.get_module('VCardTemp').request_vcard()
|
self.get_module('VCardTemp').request_vcard()
|
||||||
|
|
||||||
# Get bookmarks
|
# Get bookmarks
|
||||||
self.get_module('Bookmarks').get_bookmarks()
|
self.get_module('Bookmarks').get_bookmarks()
|
||||||
|
@ -1120,7 +923,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
con.RegisterHandler('iq', self._siSetCB, 'set', nbxmpp.NS_SI)
|
con.RegisterHandler('iq', self._siSetCB, 'set', nbxmpp.NS_SI)
|
||||||
con.RegisterHandler('iq', self._siErrorCB, 'error', 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._siResultCB, 'result', nbxmpp.NS_SI)
|
||||||
con.RegisterHandler('iq', self._discoGetCB, 'get', nbxmpp.NS_DISCO)
|
|
||||||
con.RegisterHandler('iq', self._bytestreamSetCB, 'set',
|
con.RegisterHandler('iq', self._bytestreamSetCB, 'set',
|
||||||
nbxmpp.NS_BYTESTREAM)
|
nbxmpp.NS_BYTESTREAM)
|
||||||
con.RegisterHandler('iq', self._bytestreamResultCB, 'result',
|
con.RegisterHandler('iq', self._bytestreamResultCB, 'result',
|
||||||
|
@ -1130,18 +932,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
|
||||||
con.RegisterHandlerOnce('iq', self.IBBAllIqHandler)
|
con.RegisterHandlerOnce('iq', self.IBBAllIqHandler)
|
||||||
con.RegisterHandler('iq', self.IBBIqHandler, ns=nbxmpp.NS_IBB)
|
con.RegisterHandler('iq', self.IBBIqHandler, ns=nbxmpp.NS_IBB)
|
||||||
con.RegisterHandler('message', self.IBBMessageHandler, 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, 'result')
|
||||||
con.RegisterHandler('iq', self._JingleCB, 'error')
|
con.RegisterHandler('iq', self._JingleCB, 'error')
|
||||||
|
|
|
@ -37,7 +37,6 @@ from gajim.common import helpers
|
||||||
from gajim.common import app
|
from gajim.common import app
|
||||||
from gajim.common import i18n
|
from gajim.common import i18n
|
||||||
from gajim.common.modules import dataforms
|
from gajim.common.modules import dataforms
|
||||||
from gajim.common.zeroconf.zeroconf import Constant
|
|
||||||
from gajim.common.const import KindConstant, SSLError
|
from gajim.common.const import KindConstant, SSLError
|
||||||
from gajim.common.pep import SUPPORTED_PERSONAL_USER_EVENTS
|
from gajim.common.pep import SUPPORTED_PERSONAL_USER_EVENTS
|
||||||
from gajim.common.jingle_transport import JingleTransportSocks5
|
from gajim.common.jingle_transport import JingleTransportSocks5
|
||||||
|
@ -1080,119 +1079,6 @@ class RegisterAgentInfoReceivedEvent(nec.NetworkIncomingEvent):
|
||||||
name = 'register-agent-info-received'
|
name = 'register-agent-info-received'
|
||||||
base_network_events = []
|
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):
|
class FileRequestReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||||
name = 'file-request-received'
|
name = 'file-request-received'
|
||||||
base_network_events = []
|
base_network_events = []
|
||||||
|
|
|
@ -18,7 +18,7 @@ from pathlib import Path
|
||||||
|
|
||||||
log = logging.getLogger('gajim.c.m')
|
log = logging.getLogger('gajim.c.m')
|
||||||
|
|
||||||
ZEROCONF_MODULES = ['adhoc_commands', 'receipts']
|
ZEROCONF_MODULES = ['adhoc_commands', 'receipts', 'discovery']
|
||||||
|
|
||||||
imported_modules = []
|
imported_modules = []
|
||||||
_modules = {}
|
_modules = {}
|
||||||
|
@ -56,6 +56,9 @@ class ModuleMock:
|
||||||
# Bookmarks
|
# Bookmarks
|
||||||
self.bookmarks = {}
|
self.bookmarks = {}
|
||||||
|
|
||||||
|
# Various Modules
|
||||||
|
self.supported = False
|
||||||
|
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
def _mock(self, *args, **kwargs):
|
def _mock(self, *args, **kwargs):
|
||||||
return
|
return
|
||||||
|
|
|
@ -35,7 +35,18 @@ class Blocking:
|
||||||
('iq', self._blocking_push_received, 'set', nbxmpp.NS_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):
|
def get_blocking_list(self):
|
||||||
|
if not self.supported:
|
||||||
|
return
|
||||||
iq = nbxmpp.Iq('get', nbxmpp.NS_BLOCKING)
|
iq = nbxmpp.Iq('get', nbxmpp.NS_BLOCKING)
|
||||||
iq.setQuery('blocklist')
|
iq.setQuery('blocklist')
|
||||||
log.info('Request list')
|
log.info('Request list')
|
||||||
|
@ -119,7 +130,7 @@ class Blocking:
|
||||||
self._con.connection.send(probe)
|
self._con.connection.send(probe)
|
||||||
|
|
||||||
def block(self, contact_list):
|
def block(self, contact_list):
|
||||||
if not self._con.blocking_supported:
|
if not self.supported:
|
||||||
return
|
return
|
||||||
iq = nbxmpp.Iq('set', nbxmpp.NS_BLOCKING)
|
iq = nbxmpp.Iq('set', nbxmpp.NS_BLOCKING)
|
||||||
query = iq.setQuery(name='block')
|
query = iq.setQuery(name='block')
|
||||||
|
@ -131,7 +142,7 @@ class Blocking:
|
||||||
iq, self._default_result_handler, {})
|
iq, self._default_result_handler, {})
|
||||||
|
|
||||||
def unblock(self, contact_list):
|
def unblock(self, contact_list):
|
||||||
if not self._con.blocking_supported:
|
if not self.supported:
|
||||||
return
|
return
|
||||||
iq = nbxmpp.Iq('set', nbxmpp.NS_BLOCKING)
|
iq = nbxmpp.Iq('set', nbxmpp.NS_BLOCKING)
|
||||||
query = iq.setQuery(name='unblock')
|
query = iq.setQuery(name='unblock')
|
||||||
|
|
|
@ -35,8 +35,8 @@ class Bookmarks:
|
||||||
self.handlers = []
|
self.handlers = []
|
||||||
|
|
||||||
def _pubsub_support(self):
|
def _pubsub_support(self):
|
||||||
return (self._con.pep_supported and
|
return (self._con.get_module('PEP').supported and
|
||||||
self._con.pubsub_publish_options_supported)
|
self._con.get_module('PubSub').publish_options)
|
||||||
|
|
||||||
def get_bookmarks(self, storage_type=None):
|
def get_bookmarks(self, storage_type=None):
|
||||||
if not app.account_is_connected(self._account):
|
if not app.account_is_connected(self._account):
|
||||||
|
@ -86,7 +86,7 @@ class Bookmarks:
|
||||||
else:
|
else:
|
||||||
log.info('Received Bookmarks (PrivateStorage)')
|
log.info('Received Bookmarks (PrivateStorage)')
|
||||||
merged = self._parse_bookmarks(stanza, check_merge=True)
|
merged = self._parse_bookmarks(stanza, check_merge=True)
|
||||||
if merged:
|
if merged and self._pubsub_support():
|
||||||
log.info('Merge PrivateStorage with PubSub')
|
log.info('Merge PrivateStorage with PubSub')
|
||||||
self.store_bookmarks(BookmarkStorageType.PUBSUB)
|
self.store_bookmarks(BookmarkStorageType.PUBSUB)
|
||||||
self.auto_join_bookmarks()
|
self.auto_join_bookmarks()
|
||||||
|
|
|
@ -18,9 +18,37 @@ import logging
|
||||||
|
|
||||||
import nbxmpp
|
import nbxmpp
|
||||||
|
|
||||||
|
from gajim.common import app
|
||||||
|
|
||||||
log = logging.getLogger('gajim.c.m.carbons')
|
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):
|
def parse_carbon(con, stanza):
|
||||||
carbon = stanza.getTag(
|
carbon = stanza.getTag(
|
||||||
'received', namespace=nbxmpp.NS_CARBONS, protocol=True)
|
'received', namespace=nbxmpp.NS_CARBONS, protocol=True)
|
||||||
|
@ -75,3 +103,7 @@ def parse_carbon(con, stanza):
|
||||||
raise nbxmpp.NodeProcessed
|
raise nbxmpp.NodeProcessed
|
||||||
|
|
||||||
return message, sent, True
|
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._allowed_headers = ['Authorization', 'Cookie', 'Expires']
|
||||||
self.max_file_size = None # maximum file size in bytes
|
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',
|
app.ged.register_event_handler('stanza-message-outgoing',
|
||||||
ged.OUT_PREGUI,
|
ged.OUT_PREGUI,
|
||||||
self.handle_outgoing_stanza)
|
self.handle_outgoing_stanza)
|
||||||
|
@ -72,9 +69,6 @@ class HTTPUpload:
|
||||||
self.messages = []
|
self.messages = []
|
||||||
|
|
||||||
def cleanup(self):
|
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',
|
app.ged.remove_event_handler('stanza-message-outgoing',
|
||||||
ged.OUT_PREGUI,
|
ged.OUT_PREGUI,
|
||||||
self.handle_outgoing_stanza)
|
self.handle_outgoing_stanza)
|
||||||
|
@ -82,27 +76,18 @@ class HTTPUpload:
|
||||||
ged.OUT_PREGUI,
|
ged.OUT_PREGUI,
|
||||||
self.handle_outgoing_stanza)
|
self.handle_outgoing_stanza)
|
||||||
|
|
||||||
def handle_agent_info_received(self, event):
|
def pass_disco(self, from_, identities, features, data, node):
|
||||||
account = event.conn.name
|
if NS_HTTPUPLOAD_0 in features:
|
||||||
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:
|
|
||||||
self.httpupload_namespace = NS_HTTPUPLOAD_0
|
self.httpupload_namespace = NS_HTTPUPLOAD_0
|
||||||
elif NS_HTTPUPLOAD in event.features:
|
elif NS_HTTPUPLOAD in features:
|
||||||
self.httpupload_namespace = NS_HTTPUPLOAD
|
self.httpupload_namespace = NS_HTTPUPLOAD
|
||||||
else:
|
else:
|
||||||
return
|
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()
|
form_dict = form.asDict()
|
||||||
if form_dict.get('FORM_TYPE', None) != self.httpupload_namespace:
|
if form_dict.get('FORM_TYPE', None) != self.httpupload_namespace:
|
||||||
continue
|
continue
|
||||||
|
@ -112,14 +97,16 @@ class HTTPUpload:
|
||||||
break
|
break
|
||||||
|
|
||||||
if self.max_file_size is None:
|
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:
|
else:
|
||||||
log.info('%s has a maximum file size of: %s MiB',
|
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
|
self.available = True
|
||||||
|
|
||||||
for ctrl in app.interface.msg_win_mgr.get_controls(acct=self._account):
|
for ctrl in app.interface.msg_win_mgr.get_controls(acct=self._account):
|
||||||
ctrl.update_actions()
|
ctrl.update_actions()
|
||||||
|
raise nbxmpp.NodeProcessed
|
||||||
|
|
||||||
def handle_outgoing_stanza(self, event):
|
def handle_outgoing_stanza(self, event):
|
||||||
if event.conn.name != self._account:
|
if event.conn.name != self._account:
|
||||||
|
|
|
@ -47,6 +47,20 @@ class MAM:
|
||||||
self.archiving_namespace = None
|
self.archiving_namespace = None
|
||||||
self._mam_query_ids = {}
|
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):
|
def _from_valid_archive(self, stanza, message, groupchat):
|
||||||
if groupchat:
|
if groupchat:
|
||||||
expected_archive = message.getFrom()
|
expected_archive = message.getFrom()
|
||||||
|
|
|
@ -38,6 +38,18 @@ class MUC:
|
||||||
('message', self._direct_invite, '', nbxmpp.NS_CONFERENCE),
|
('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):
|
def set_subject(self, room_jid, subject):
|
||||||
if not app.account_is_connected(self._account):
|
if not app.account_is_connected(self._account):
|
||||||
return
|
return
|
||||||
|
|
|
@ -36,9 +36,17 @@ class PEP:
|
||||||
'headline', nbxmpp.NS_PUBSUB_EVENT)
|
'headline', nbxmpp.NS_PUBSUB_EVENT)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
self.supported = False
|
||||||
self._pep_handlers = {}
|
self._pep_handlers = {}
|
||||||
self._store_publish_modules = []
|
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):
|
def register_pep_handler(self, namespace, notify_handler, retract_handler):
|
||||||
if namespace in self._pep_handlers:
|
if namespace in self._pep_handlers:
|
||||||
self._pep_handlers[namespace].append(
|
self._pep_handlers[namespace].append(
|
||||||
|
@ -165,7 +173,7 @@ class AbstractPEPModule:
|
||||||
self._stored_publish = None
|
self._stored_publish = None
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
if not self._con.pep_supported:
|
if not self._con.get_module('PEP').supported:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._con.connected == 1:
|
if self._con.connected == 1:
|
||||||
|
@ -184,7 +192,7 @@ class AbstractPEPModule:
|
||||||
'', self.namespace, item, 'current')
|
'', self.namespace, item, 'current')
|
||||||
|
|
||||||
def retract(self):
|
def retract(self):
|
||||||
if not self._con.pep_supported:
|
if not self._con.get_module('PEP').supported:
|
||||||
return
|
return
|
||||||
self.send(None)
|
self.send(None)
|
||||||
self._con.get_module('PubSub').send_pb_retract(
|
self._con.get_module('PubSub').send_pb_retract(
|
||||||
|
|
|
@ -43,6 +43,18 @@ class PrivacyLists:
|
||||||
('iq', self._list_push_received, 'set', nbxmpp.NS_PRIVACY)
|
('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):
|
def _list_push_received(self, con, stanza):
|
||||||
result = stanza.buildReply('result')
|
result = stanza.buildReply('result')
|
||||||
result.delChild(result.getTag('query'))
|
result.delChild(result.getTag('query'))
|
||||||
|
@ -287,7 +299,7 @@ class PrivacyLists:
|
||||||
self.set_default_list(self.default_list)
|
self.set_default_list(self.default_list)
|
||||||
|
|
||||||
def block_contacts(self, contact_list, message):
|
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)
|
self._con.get_module('Blocking').block(contact_list)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -332,7 +344,7 @@ class PrivacyLists:
|
||||||
self.set_privacy_list(self.default_list, new_blocked_list)
|
self.set_privacy_list(self.default_list, new_blocked_list)
|
||||||
|
|
||||||
def unblock_contacts(self, contact_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)
|
self._con.get_module('Blocking').unblock(contact_list)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -367,7 +379,7 @@ class PrivacyLists:
|
||||||
self._presence_probe(contact.jid)
|
self._presence_probe(contact.jid)
|
||||||
|
|
||||||
def block_group(self, group, contact_list, message):
|
def block_group(self, group, contact_list, message):
|
||||||
if not self._con.privacy_rules_supported:
|
if not self.supported:
|
||||||
return
|
return
|
||||||
if group in self.blocked_groups:
|
if group in self.blocked_groups:
|
||||||
return
|
return
|
||||||
|
@ -393,7 +405,7 @@ class PrivacyLists:
|
||||||
self.set_default_list(self.default_list)
|
self.set_default_list(self.default_list)
|
||||||
|
|
||||||
def unblock_group(self, group, contact_list):
|
def unblock_group(self, group, contact_list):
|
||||||
if not self._con.privacy_rules_supported:
|
if not self.supported:
|
||||||
return
|
return
|
||||||
|
|
||||||
if group not in self.blocked_groups:
|
if group not in self.blocked_groups:
|
||||||
|
|
|
@ -38,6 +38,16 @@ class PubSub:
|
||||||
|
|
||||||
self.handlers = []
|
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):
|
def send_pb_subscription_query(self, jid, cb, **kwargs):
|
||||||
if not app.account_is_connected(self._account):
|
if not app.account_is_connected(self._account):
|
||||||
return
|
return
|
||||||
|
|
|
@ -34,6 +34,13 @@ class SecLabels:
|
||||||
self._catalogs = {}
|
self._catalogs = {}
|
||||||
self.supported = False
|
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):
|
def request_catalog(self, jid):
|
||||||
server = app.get_jid_from_account(self._account).split("@")[1]
|
server = app.get_jid_from_account(self._account).split("@")[1]
|
||||||
iq = nbxmpp.Iq(typ='get', to=server)
|
iq = nbxmpp.Iq(typ='get', to=server)
|
||||||
|
|
|
@ -41,6 +41,17 @@ class VCardTemp:
|
||||||
self._own_vcard = None
|
self._own_vcard = None
|
||||||
self.own_vcard_received = False
|
self.own_vcard_received = False
|
||||||
self.room_jids = []
|
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):
|
def _node_to_dict(self, node):
|
||||||
dict_ = {}
|
dict_ = {}
|
||||||
|
@ -67,6 +78,8 @@ class VCardTemp:
|
||||||
|
|
||||||
if isinstance(callback, RequestAvatar):
|
if isinstance(callback, RequestAvatar):
|
||||||
if callback == RequestAvatar.SELF:
|
if callback == RequestAvatar.SELF:
|
||||||
|
if not self.supported:
|
||||||
|
return
|
||||||
callback = self._on_own_avatar_received
|
callback = self._on_own_avatar_received
|
||||||
elif callback == RequestAvatar.ROOM:
|
elif callback == RequestAvatar.ROOM:
|
||||||
callback = self._on_room_avatar_received
|
callback = self._on_room_avatar_received
|
||||||
|
|
|
@ -80,7 +80,20 @@ class ConnectionBytestream:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
app.ged.register_event_handler('file-request-received', ged.GUI1,
|
app.ged.register_event_handler('file-request-received', ged.GUI1,
|
||||||
self._nec_file_request_received)
|
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):
|
def cleanup(self):
|
||||||
app.ged.remove_event_handler('file-request-received', ged.GUI1,
|
app.ged.remove_event_handler('file-request-received', ged.GUI1,
|
||||||
|
|
|
@ -41,14 +41,10 @@ class ConnectionCaps(object):
|
||||||
app.nec.register_incoming_event(CapsReceivedEvent)
|
app.nec.register_incoming_event(CapsReceivedEvent)
|
||||||
app.ged.register_event_handler('caps-presence-received', ged.GUI1,
|
app.ged.register_event_handler('caps-presence-received', ged.GUI1,
|
||||||
self._nec_caps_presence_received)
|
self._nec_caps_presence_received)
|
||||||
app.ged.register_event_handler('agent-info-received', ged.GUI1,
|
|
||||||
self._nec_agent_info_received_caps)
|
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
app.ged.remove_event_handler('caps-presence-received', ged.GUI1,
|
app.ged.remove_event_handler('caps-presence-received', ged.GUI1,
|
||||||
self._nec_caps_presence_received)
|
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):
|
def caps_change_account_name(self, new_name):
|
||||||
self._account = new_name
|
self._account = new_name
|
||||||
|
@ -81,16 +77,19 @@ class ConnectionCaps(object):
|
||||||
contact = app.contacts.get_gc_contact(self._account, room_jid, nick)
|
contact = app.contacts.get_gc_contact(self._account, room_jid, nick)
|
||||||
return contact
|
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
|
callback to update our caps cache with queried information after
|
||||||
we have retrieved an unknown caps hash and issued a disco
|
we have retrieved an unknown caps hash and issued a disco
|
||||||
"""
|
"""
|
||||||
if obj.conn.name != self._account:
|
fjid = str(from_)
|
||||||
return
|
bare_jid = from_.getStripped()
|
||||||
contact = self._get_contact_or_gc_contact_for_jid(obj.fjid)
|
resource = from_.getResource()
|
||||||
|
|
||||||
|
contact = self._get_contact_or_gc_contact_for_jid(fjid)
|
||||||
if not contact:
|
if not contact:
|
||||||
log.info('Received Disco from unknown contact %s' % obj.fjid)
|
log.info('Received Disco from unknown contact %s' % fjid)
|
||||||
return
|
return
|
||||||
|
|
||||||
lookup = contact.client_caps.get_cache_lookup_strategy()
|
lookup = contact.client_caps.get_cache_lookup_strategy()
|
||||||
|
@ -102,17 +101,21 @@ class ConnectionCaps(object):
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
validate = contact.client_caps.get_hash_validation_strategy()
|
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:
|
if hash_is_valid:
|
||||||
cache_item.set_and_store(obj.identities, obj.features)
|
cache_item.set_and_store(identities, features)
|
||||||
else:
|
else:
|
||||||
node = caps_hash = hash_method = None
|
node = caps_hash = hash_method = None
|
||||||
contact.client_caps = self._create_suitable_client_caps(
|
contact.client_caps = self._create_suitable_client_caps(
|
||||||
obj.node, caps_hash, hash_method)
|
node, caps_hash, hash_method)
|
||||||
log.info('Computed and retrieved caps hash differ.' +
|
log.info('Computed and retrieved caps hash differ.'
|
||||||
'Ignoring caps of contact %s' % contact.get_full_jid())
|
'Ignoring caps of contact %s' % contact.get_full_jid())
|
||||||
|
|
||||||
app.nec.push_incoming_event(CapsDiscoReceivedEvent(None,
|
app.nec.push_incoming_event(
|
||||||
conn=self, fjid=obj.fjid, jid=obj.jid, resource=obj.resource,
|
CapsDiscoReceivedEvent(None,
|
||||||
client_caps=contact.client_caps))
|
conn=self,
|
||||||
|
fjid=fjid,
|
||||||
|
jid=bare_jid,
|
||||||
|
resource=resource,
|
||||||
|
client_caps=contact.client_caps))
|
||||||
|
|
|
@ -329,8 +329,6 @@ class P2PClient(IdleObject):
|
||||||
nbxmpp.NS_BYTESTREAM)
|
nbxmpp.NS_BYTESTREAM)
|
||||||
self.RegisterHandler('iq', self._caller._bytestreamErrorCB, 'error',
|
self.RegisterHandler('iq', self._caller._bytestreamErrorCB, 'error',
|
||||||
nbxmpp.NS_BYTESTREAM)
|
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, 'result')
|
||||||
self.RegisterHandler('iq', self._caller._JingleCB, 'error')
|
self.RegisterHandler('iq', self._caller._JingleCB, 'error')
|
||||||
self.RegisterHandler('iq', self._caller._JingleCB, 'set',
|
self.RegisterHandler('iq', self._caller._JingleCB, 'set',
|
||||||
|
|
|
@ -191,20 +191,3 @@ connection_handlers.ConnectionJingle):
|
||||||
# serverside metacontacts are not supported with zeroconf
|
# serverside metacontacts are not supported with zeroconf
|
||||||
# (there is no server)
|
# (there is no server)
|
||||||
pass
|
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.get_object('delete_button').set_sensitive(False)
|
||||||
self.xml.connect_signals(self)
|
self.xml.connect_signals(self)
|
||||||
self.account = account
|
self.account = account
|
||||||
|
self._con = app.connections[self.account]
|
||||||
|
|
||||||
self.init_services()
|
self.init_services()
|
||||||
self.xml.get_object('services_treeview').get_selection().connect(
|
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,
|
app.ged.register_event_handler('pubsub-config-received', ged.GUI1,
|
||||||
self._nec_pep_config_received)
|
self._nec_pep_config_received)
|
||||||
app.ged.register_event_handler('agent-items-received', ged.GUI1,
|
|
||||||
self._nec_agent_items_received)
|
|
||||||
|
|
||||||
self.window.show_all()
|
self.window.show_all()
|
||||||
|
|
||||||
|
@ -2862,8 +2861,6 @@ class ManagePEPServicesWindow:
|
||||||
del app.interface.instances[self.account]['pep_services']
|
del app.interface.instances[self.account]['pep_services']
|
||||||
app.ged.remove_event_handler('pubsub-config-received', ged.GUI1,
|
app.ged.remove_event_handler('pubsub-config-received', ged.GUI1,
|
||||||
self._nec_pep_config_received)
|
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):
|
def on_close_button_clicked(self, widget):
|
||||||
self.window.destroy()
|
self.window.destroy()
|
||||||
|
@ -2885,15 +2882,19 @@ class ManagePEPServicesWindow:
|
||||||
col.pack_start(cellrenderer_text, True)
|
col.pack_start(cellrenderer_text, True)
|
||||||
col.add_attribute(cellrenderer_text, 'text', 0)
|
col.add_attribute(cellrenderer_text, 'text', 0)
|
||||||
|
|
||||||
our_jid = app.get_jid_from_account(self.account)
|
jid = self._con.get_own_jid().getStripped()
|
||||||
app.connections[self.account].discoverItems(our_jid)
|
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):
|
def _items_received(self, from_, node, items):
|
||||||
our_jid = app.get_jid_from_account(self.account)
|
jid = self._con.get_own_jid().getStripped()
|
||||||
for item in obj.items:
|
for item in items:
|
||||||
if 'jid' in item and item['jid'] == our_jid and 'node' in item:
|
if item['jid'] == jid and 'node' in item:
|
||||||
self.treestore.append([item['node']])
|
self.treestore.append([item['node']])
|
||||||
|
|
||||||
|
def _items_error(self, from_, error):
|
||||||
|
ErrorDialog('Error', error)
|
||||||
|
|
||||||
def node_removed(self, jid, node):
|
def node_removed(self, jid, node):
|
||||||
if jid != app.get_jid_from_account(self.account):
|
if jid != app.get_jid_from_account(self.account):
|
||||||
return
|
return
|
||||||
|
|
|
@ -258,24 +258,6 @@ class ServicesCache:
|
||||||
self._info = CacheDictionary(0, getrefresh = False)
|
self._info = CacheDictionary(0, getrefresh = False)
|
||||||
self._subscriptions = CacheDictionary(5, getrefresh=False)
|
self._subscriptions = CacheDictionary(5, getrefresh=False)
|
||||||
self._cbs = {}
|
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):
|
def cleanup(self):
|
||||||
self._items.cleanup()
|
self._items.cleanup()
|
||||||
|
@ -391,7 +373,9 @@ class ServicesCache:
|
||||||
self._cbs[cbkey].append(cb)
|
self._cbs[cbkey].append(cb)
|
||||||
else:
|
else:
|
||||||
self._cbs[cbkey] = [cb]
|
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=()):
|
def get_items(self, jid, node, cb, force=False, nofetch=False, args=()):
|
||||||
"""
|
"""
|
||||||
|
@ -409,24 +393,38 @@ class ServicesCache:
|
||||||
# Create a closure object
|
# Create a closure object
|
||||||
cbkey = ('items', addr)
|
cbkey = ('items', addr)
|
||||||
cb = Closure(cb, userargs=args, remove=self._clean_closure,
|
cb = Closure(cb, userargs=args, remove=self._clean_closure,
|
||||||
removeargs=cbkey)
|
removeargs=cbkey)
|
||||||
# Are we already fetching this?
|
# Are we already fetching this?
|
||||||
if cbkey in self._cbs:
|
if cbkey in self._cbs:
|
||||||
self._cbs[cbkey].append(cb)
|
self._cbs[cbkey].append(cb)
|
||||||
else:
|
else:
|
||||||
self._cbs[cbkey] = [cb]
|
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
|
Callback for when we receive an agent's info
|
||||||
array is (agent, node, identities, features, data)
|
array is (agent, node, identities, features, data)
|
||||||
"""
|
"""
|
||||||
# We receive events from all accounts from GED
|
self._on_agent_info(str(from_), node, identities, features, data)
|
||||||
if obj.conn.name != self.account:
|
|
||||||
return
|
def _disco_info_error(self, from_, error):
|
||||||
self._on_agent_info(obj.fjid, obj.node, obj.identities, obj.features,
|
"""
|
||||||
obj.data)
|
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):
|
def _on_agent_info(self, fjid, node, identities, features, data):
|
||||||
addr = get_agent_address(fjid, node)
|
addr = get_agent_address(fjid, node)
|
||||||
|
@ -443,67 +441,42 @@ class ServicesCache:
|
||||||
if cbkey in self._cbs:
|
if cbkey in self._cbs:
|
||||||
del self._cbs[cbkey]
|
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
|
Callback for when we receive an agent's items
|
||||||
array is (agent, node, items)
|
array is (agent, node, items)
|
||||||
"""
|
"""
|
||||||
# We receive events from all accounts from GED
|
addr = get_agent_address(from_, node)
|
||||||
if obj.conn.name != self.account:
|
|
||||||
return
|
|
||||||
|
|
||||||
addr = get_agent_address(obj.fjid, obj.node)
|
|
||||||
|
|
||||||
# Store in cache
|
# Store in cache
|
||||||
self._items[addr] = obj.items
|
self._items[addr] = items
|
||||||
|
|
||||||
# Call callbacks
|
# Call callbacks
|
||||||
cbkey = ('items', addr)
|
cbkey = ('items', addr)
|
||||||
if cbkey in self._cbs:
|
if cbkey in self._cbs:
|
||||||
for cb in self._cbs[cbkey]:
|
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
|
# clean_closure may have beaten us to it
|
||||||
if cbkey in self._cbs:
|
if cbkey in self._cbs:
|
||||||
del self._cbs[cbkey]
|
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
|
Callback for when a query fails. Even after the browse and agents
|
||||||
namespaces
|
namespaces
|
||||||
"""
|
"""
|
||||||
# We receive events from all accounts from GED
|
addr = get_agent_address(from_)
|
||||||
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)
|
|
||||||
|
|
||||||
# Call callbacks
|
# Call callbacks
|
||||||
cbkey = ('items', addr)
|
cbkey = ('items', addr)
|
||||||
if cbkey in self._cbs:
|
if cbkey in self._cbs:
|
||||||
for cb in self._cbs[cbkey]:
|
for cb in self._cbs[cbkey]:
|
||||||
cb(obj.fjid, '', 0)
|
cb(str(from_), '', 0)
|
||||||
# clean_closure may have beaten us to it
|
# clean_closure may have beaten us to it
|
||||||
if cbkey in self._cbs:
|
if cbkey in self._cbs:
|
||||||
del self._cbs[cbkey]
|
del self._cbs[cbkey]
|
||||||
|
|
||||||
|
|
||||||
# object is needed so that @property works
|
# object is needed so that @property works
|
||||||
class ServiceDiscoveryWindow(object):
|
class ServiceDiscoveryWindow(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1533,7 +1533,7 @@ class GroupchatControl(ChatControlBase):
|
||||||
if '104' in obj.status_code:
|
if '104' in obj.status_code:
|
||||||
changes.append(_('A setting not related to privacy has been '
|
changes.append(_('A setting not related to privacy has been '
|
||||||
'changed'))
|
'changed'))
|
||||||
app.connections[self.account].discoverMUC(
|
app.connections[self.account].get_module('Discovery').disco_muc(
|
||||||
self.room_jid, self.update_actions, update=True)
|
self.room_jid, self.update_actions, update=True)
|
||||||
if '170' in obj.status_code:
|
if '170' in obj.status_code:
|
||||||
# Can be a presence (see chg_contact_status in groupchat_control.py)
|
# 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')
|
item = xml.get_object('block_menuitem')
|
||||||
item2 = xml.get_object('unblock_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)
|
item2.set_no_show_all(True)
|
||||||
item.set_no_show_all(True)
|
item.set_no_show_all(True)
|
||||||
item.hide()
|
item.hide()
|
||||||
|
|
|
@ -80,13 +80,6 @@ class JoinGroupchatWindow(Gtk.ApplicationWindow):
|
||||||
|
|
||||||
self.builder.connect_signals(self)
|
self.builder.connect_signals(self)
|
||||||
self.connect('key-press-event', self._on_key_press_event)
|
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
|
# Hide account combobox if there is only one account
|
||||||
if len(accounts) == 1:
|
if len(accounts) == 1:
|
||||||
|
@ -277,48 +270,36 @@ class JoinGroupchatWindow(Gtk.ApplicationWindow):
|
||||||
con.get_module('Bookmarks').add_bookmark(
|
con.get_module('Bookmarks').add_bookmark(
|
||||||
name, self.room_jid, autojoin, 1, password, nickname)
|
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):
|
def _on_search_clicked(self, widget):
|
||||||
server = self.server_combo.get_active_text().strip()
|
server = self.server_combo.get_active_text().strip()
|
||||||
self.requested_jid = server
|
con = app.connections[self.account]
|
||||||
app.connections[self.account].discoverInfo(server)
|
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):
|
def _disco_info_error(self, from_, error):
|
||||||
if obj.conn.name != self.account:
|
|
||||||
return
|
|
||||||
if obj.jid != self.requested_jid:
|
|
||||||
return
|
|
||||||
self.requested_jid = None
|
|
||||||
ErrorDialog(_('Wrong server'),
|
ErrorDialog(_('Wrong server'),
|
||||||
_('%s is not a groupchat server') % obj.jid,
|
_('%s is not a groupchat server') % from_,
|
||||||
transient_for=self)
|
transient_for=self)
|
||||||
|
|
||||||
def _nec_agent_info_received(self, obj):
|
def _disco_info_received(self, from_, identities, features, data, node):
|
||||||
if obj.conn.name != self.account:
|
if nbxmpp.NS_MUC not in features:
|
||||||
return
|
|
||||||
if obj.jid != self.requested_jid:
|
|
||||||
return
|
|
||||||
self.requested_jid = None
|
|
||||||
if nbxmpp.NS_MUC not in obj.features:
|
|
||||||
ErrorDialog(_('Wrong server'),
|
ErrorDialog(_('Wrong server'),
|
||||||
_('%s is not a groupchat server') % obj.jid,
|
_('%s is not a groupchat server') % from_,
|
||||||
transient_for=self)
|
transient_for=self)
|
||||||
return
|
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()
|
present()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
# Object will add itself to the window dict
|
# Object will add itself to the window dict
|
||||||
from gajim.disco import ServiceDiscoveryWindow
|
from gajim.disco import ServiceDiscoveryWindow
|
||||||
ServiceDiscoveryWindow(
|
ServiceDiscoveryWindow(
|
||||||
self.account, obj.jid,
|
self.account, jid,
|
||||||
initial_identities=[{'category': 'conference',
|
initial_identities=[{'category': 'conference',
|
||||||
'type': 'text'}])
|
'type': 'text'}])
|
||||||
except GajimGeneralException:
|
except GajimGeneralException:
|
||||||
|
|
|
@ -61,9 +61,9 @@ class ServerInfoDialog(Gtk.Dialog):
|
||||||
ged.CORE,
|
ged.CORE,
|
||||||
self._nec_version_result_received)
|
self._nec_version_result_received)
|
||||||
|
|
||||||
app.ged.register_event_handler('agent-info-received',
|
app.ged.register_event_handler('server-disco-received',
|
||||||
ged.GUI1,
|
ged.GUI1,
|
||||||
self._nec_agent_info_received)
|
self._server_disco_received)
|
||||||
|
|
||||||
self.version = ''
|
self.version = ''
|
||||||
self.uptime = ''
|
self.uptime = ''
|
||||||
|
@ -132,9 +132,7 @@ class ServerInfoDialog(Gtk.Dialog):
|
||||||
self.version = obj.client_info
|
self.version = obj.client_info
|
||||||
self.update(self.get_infos, self.info_listbox)
|
self.update(self.get_infos, self.info_listbox)
|
||||||
|
|
||||||
def _nec_agent_info_received(self, obj):
|
def _server_disco_received(self, obj):
|
||||||
if 'Gajim_' not in obj.id_:
|
|
||||||
return
|
|
||||||
self.update(self.get_features, self.feature_listbox)
|
self.update(self.get_features, self.feature_listbox)
|
||||||
|
|
||||||
def add_feature(self, feature):
|
def add_feature(self, feature):
|
||||||
|
@ -154,22 +152,25 @@ class ServerInfoDialog(Gtk.Dialog):
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Feature('XEP-0016: Privacy Lists',
|
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-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',
|
Feature('XEP-0163: Personal Eventing Protocol',
|
||||||
con.pep_supported, '', None),
|
con.get_module('PEP').supported, '', None),
|
||||||
Feature('XEP-0163: #publish-options',
|
Feature('XEP-0163: #publish-options',
|
||||||
con.pubsub_publish_options_supported, '', None),
|
con.get_module('PubSub').publish_options, '', None),
|
||||||
Feature('XEP-0191: Blocking Command',
|
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',
|
Feature('XEP-0198: Stream Management',
|
||||||
con.sm.enabled, nbxmpp.NS_STREAM_MGMT, None),
|
con.sm.enabled, nbxmpp.NS_STREAM_MGMT, None),
|
||||||
Feature('XEP-0258: Security Labels in XMPP',
|
Feature('XEP-0258: Security Labels in XMPP',
|
||||||
con.get_module('SecLabels').supported,
|
con.get_module('SecLabels').supported,
|
||||||
nbxmpp.NS_SECLABEL, None),
|
nbxmpp.NS_SECLABEL, None),
|
||||||
Feature('XEP-0280: Message Carbons',
|
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',
|
Feature('XEP-0313: Message Archive Management',
|
||||||
con.get_module('MAM').archiving_namespace,
|
con.get_module('MAM').archiving_namespace,
|
||||||
con.get_module('MAM').archiving_namespace,
|
con.get_module('MAM').archiving_namespace,
|
||||||
|
@ -198,9 +199,9 @@ class ServerInfoDialog(Gtk.Dialog):
|
||||||
ged.CORE,
|
ged.CORE,
|
||||||
self._nec_version_result_received)
|
self._nec_version_result_received)
|
||||||
|
|
||||||
app.ged.remove_event_handler('agent-info-received',
|
app.ged.remove_event_handler('server-disco-received',
|
||||||
ged.GUI1,
|
ged.GUI1,
|
||||||
self._nec_agent_info_received)
|
self._server_disco_received)
|
||||||
|
|
||||||
|
|
||||||
class FeatureItem(Gtk.Grid):
|
class FeatureItem(Gtk.Grid):
|
||||||
|
|
|
@ -1116,6 +1116,8 @@ class Interface:
|
||||||
app.block_signed_in_notifications[account] = True
|
app.block_signed_in_notifications[account] = True
|
||||||
connected = obj.conn.connected
|
connected = obj.conn.connected
|
||||||
|
|
||||||
|
pep_supported = obj.conn.get_module('PEP').supported
|
||||||
|
|
||||||
if not idle.Monitor.is_unknown() and connected in (2, 3):
|
if not idle.Monitor.is_unknown() and connected in (2, 3):
|
||||||
# we go online or free for chat, so we activate auto status
|
# we go online or free for chat, so we activate auto status
|
||||||
app.sleeper_state[account] = 'online'
|
app.sleeper_state[account] = 'online'
|
||||||
|
@ -1135,11 +1137,11 @@ class Interface:
|
||||||
if connected == invisible_show:
|
if connected == invisible_show:
|
||||||
return
|
return
|
||||||
# send currently played music
|
# 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')):
|
app.config.get_per('accounts', account, 'publish_tune')):
|
||||||
self.enable_music_listener()
|
self.enable_music_listener()
|
||||||
# enable location 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')):
|
app.config.get_per('accounts', account, 'publish_location')):
|
||||||
location_listener.enable()
|
location_listener.enable()
|
||||||
|
|
||||||
|
@ -1785,7 +1787,7 @@ class Interface:
|
||||||
transient_for=transient_for)
|
transient_for=transient_for)
|
||||||
|
|
||||||
disco_account = connected_accounts[0] if account is None else account
|
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)
|
room_jid, _on_discover_result)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
@ -2187,7 +2189,7 @@ class Interface:
|
||||||
for acct in accounts:
|
for acct in accounts:
|
||||||
if not app.account_is_connected(acct):
|
if not app.account_is_connected(acct):
|
||||||
continue
|
continue
|
||||||
if not app.connections[acct].pep_supported:
|
if not app.connections[acct].get_module('PEP').supported:
|
||||||
continue
|
continue
|
||||||
if not app.config.get_per('accounts', acct, 'publish_tune'):
|
if not app.config.get_per('accounts', acct, 'publish_tune'):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -460,8 +460,10 @@ control=None, gc_contact=None, is_anonymous=True):
|
||||||
execute_command_menuitem, send_custom_status_menuitem):
|
execute_command_menuitem, send_custom_status_menuitem):
|
||||||
widget.set_sensitive(False)
|
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):
|
if helpers.jid_is_blocked(account, jid):
|
||||||
block_menuitem.set_no_show_all(True)
|
block_menuitem.set_no_show_all(True)
|
||||||
block_menuitem.hide()
|
block_menuitem.hide()
|
||||||
|
|
|
@ -2840,9 +2840,14 @@ class RosterWindow:
|
||||||
if msg is None:
|
if msg is None:
|
||||||
# user pressed Cancel to change status message dialog
|
# user pressed Cancel to change status message dialog
|
||||||
return
|
return
|
||||||
accounts = set(i[1] for i in list_ if (app.connections[i[1]].\
|
|
||||||
privacy_rules_supported or (group is None and app.\
|
accounts = []
|
||||||
connections[i[1]].blocking_supported)))
|
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:
|
if group is None:
|
||||||
for acct in accounts:
|
for acct in accounts:
|
||||||
l_ = [i[0] for i in list_ if i[1] == acct]
|
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.
|
When clicked on the 'unblock' button in context menu.
|
||||||
"""
|
"""
|
||||||
accounts = set(i[1] for i in list_ if (app.connections[i[1]].\
|
accounts = []
|
||||||
privacy_rules_supported or (group is None and app.\
|
for _, account in list_:
|
||||||
connections[i[1]].blocking_supported)))
|
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:
|
if group is None:
|
||||||
for acct in accounts:
|
for acct in accounts:
|
||||||
l_ = [i[0] for i in list_ if i[1] == acct]
|
l_ = [i[0] for i in list_ if i[1] == acct]
|
||||||
|
@ -4916,7 +4925,7 @@ class RosterWindow:
|
||||||
sub_menu.append(item)
|
sub_menu.append(item)
|
||||||
con = app.connections[account]
|
con = app.connections[account]
|
||||||
if show == 'invisible' and con.connected > 1 and \
|
if show == 'invisible' and con.connected > 1 and \
|
||||||
not con.privacy_rules_supported:
|
not con.get_module('PrivacyLists').supported:
|
||||||
item.set_sensitive(False)
|
item.set_sensitive(False)
|
||||||
else:
|
else:
|
||||||
item.connect('activate', self.change_status, account, show)
|
item.connect('activate', self.change_status, account, show)
|
||||||
|
@ -4940,7 +4949,7 @@ class RosterWindow:
|
||||||
item.connect('activate', self.change_status, account, 'offline')
|
item.connect('activate', self.change_status, account, 'offline')
|
||||||
|
|
||||||
pep_menuitem = xml.get_object('pep_menuitem')
|
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_submenu = Gtk.Menu()
|
||||||
pep_menuitem.set_submenu(pep_submenu)
|
pep_menuitem.set_submenu(pep_submenu)
|
||||||
|
|
||||||
|
@ -5183,8 +5192,7 @@ class RosterWindow:
|
||||||
if helpers.group_is_blocked(account, group):
|
if helpers.group_is_blocked(account, group):
|
||||||
is_blocked = True
|
is_blocked = True
|
||||||
|
|
||||||
if is_blocked and app.connections[account].\
|
if is_blocked and app.connections[account].get_module('PrivacyLists').supported:
|
||||||
privacy_rules_supported:
|
|
||||||
unblock_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Unblock'))
|
unblock_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Unblock'))
|
||||||
unblock_menuitem.connect('activate', self.on_unblock, list_,
|
unblock_menuitem.connect('activate', self.on_unblock, list_,
|
||||||
group)
|
group)
|
||||||
|
@ -5193,7 +5201,7 @@ class RosterWindow:
|
||||||
block_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Block'))
|
block_menuitem = Gtk.MenuItem.new_with_mnemonic(_('_Block'))
|
||||||
block_menuitem.connect('activate', self.on_block, list_, group)
|
block_menuitem.connect('activate', self.on_block, list_, group)
|
||||||
menu.append(block_menuitem)
|
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)
|
block_menuitem.set_sensitive(False)
|
||||||
|
|
||||||
# Remove group
|
# Remove group
|
||||||
|
@ -5245,7 +5253,7 @@ class RosterWindow:
|
||||||
account = model[titer][Column.ACCOUNT]
|
account = model[titer][Column.ACCOUNT]
|
||||||
if app.connections[account].connected < 2:
|
if app.connections[account].connected < 2:
|
||||||
one_account_offline = True
|
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
|
privacy_rules_supported = False
|
||||||
contact = app.contacts.get_contact_with_highest_priority(account,
|
contact = app.contacts.get_contact_with_highest_priority(account,
|
||||||
jid)
|
jid)
|
||||||
|
@ -5411,7 +5419,7 @@ class RosterWindow:
|
||||||
self.on_xml_console_menuitem_activate, account)
|
self.on_xml_console_menuitem_activate, account)
|
||||||
|
|
||||||
if app.connections[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',
|
privacy_lists_menuitem.connect('activate',
|
||||||
self.on_privacy_lists_menuitem_activate, account)
|
self.on_privacy_lists_menuitem_activate, account)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -102,6 +102,9 @@ class Mock(object):
|
||||||
if not name in baseMethods:
|
if not name in baseMethods:
|
||||||
self.__dict__[name] = MockCallable(name, self, handcrafted=True)
|
self.__dict__[name] = MockCallable(name, self, handcrafted=True)
|
||||||
|
|
||||||
|
def get_module(self, name):
|
||||||
|
return Mock()
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return MockCallable(name, self)
|
return MockCallable(name, self)
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@ import unittest
|
||||||
import lib
|
import lib
|
||||||
lib.setup_env()
|
lib.setup_env()
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock
|
||||||
from nbxmpp import NS_MUC, NS_PING, NS_XHTML_IM, Iq
|
from nbxmpp import NS_MUC, NS_PING, NS_XHTML_IM, Iq
|
||||||
from gajim.common import caps_cache as caps
|
from gajim.common import caps_cache as caps
|
||||||
from gajim.common.contacts import Contact
|
from gajim.common.modules.discovery import Discovery
|
||||||
from gajim.common.connection_handlers_events import AgentInfoReceivedEvent
|
|
||||||
|
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
|
|
||||||
|
@ -106,29 +106,29 @@ class TestCapsCache(CommonCapsTest):
|
||||||
|
|
||||||
def test_preload_triggering_query(self):
|
def test_preload_triggering_query(self):
|
||||||
''' Make sure that preload issues a disco '''
|
''' Make sure that preload issues a disco '''
|
||||||
connection = Mock()
|
connection = MagicMock()
|
||||||
client_caps = caps.ClientCaps(self.caps_hash, self.node, self.caps_method)
|
client_caps = caps.ClientCaps(self.caps_hash, self.node, self.caps_method)
|
||||||
|
|
||||||
self.cc.query_client_of_jid_if_unknown(connection, "test@gajim.org",
|
self.cc.query_client_of_jid_if_unknown(
|
||||||
client_caps)
|
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):
|
def test_no_preload_query_if_cashed(self):
|
||||||
''' Preload must not send a query if the data is already cached '''
|
''' 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)
|
client_caps = caps.ClientCaps(self.caps_hash, self.node, self.caps_method)
|
||||||
|
|
||||||
self.cc.initialize_from_db()
|
self.cc.initialize_from_db()
|
||||||
self.cc.query_client_of_jid_if_unknown(connection, "test@gajim.org",
|
self.cc.query_client_of_jid_if_unknown(
|
||||||
client_caps)
|
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):
|
def test_hash(self):
|
||||||
'''tests the hash computation'''
|
'''tests the hash computation'''
|
||||||
stanza = Iq(node=COMPLEX_EXAMPLE)
|
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)
|
computed_hash = caps.compute_caps_hash(identities, features, data)
|
||||||
self.assertEqual('q07IKJEyjvHSyhy//CH0CxmKi8w=', computed_hash)
|
self.assertEqual('q07IKJEyjvHSyhy//CH0CxmKi8w=', computed_hash)
|
||||||
|
|
||||||
|
@ -141,12 +141,11 @@ class TestClientCaps(CommonCapsTest):
|
||||||
|
|
||||||
def test_query_by_get_discover_strategy(self):
|
def test_query_by_get_discover_strategy(self):
|
||||||
''' Client must be queried if the data is unkown '''
|
''' Client must be queried if the data is unkown '''
|
||||||
connection = Mock()
|
connection = MagicMock()
|
||||||
discover = self.client_caps.get_discover_strategy()
|
discover = self.client_caps.get_discover_strategy()
|
||||||
discover(connection, "test@gajim.org")
|
discover(connection, "test@gajim.org")
|
||||||
|
connection.get_module('Discovery').disco_contact.assert_called_once_with(
|
||||||
connection.mockCheckCall(0, "discoverInfo", "test@gajim.org",
|
'test@gajim.org', 'http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=')
|
||||||
"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
|
|
||||||
|
|
||||||
def test_client_supports(self):
|
def test_client_supports(self):
|
||||||
self.assertTrue(caps.client_supports(self.client_caps, NS_PING),
|
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):
|
def test_query_by_get_discover_strategy(self):
|
||||||
''' Client must be queried if the data is unknown '''
|
''' Client must be queried if the data is unknown '''
|
||||||
connection = Mock()
|
connection = MagicMock()
|
||||||
discover = self.client_caps.get_discover_strategy()
|
discover = self.client_caps.get_discover_strategy()
|
||||||
discover(connection, "test@gajim.org")
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Reference in New Issue