[Git][gajim/gajim][master] Add roster implementation to Gajim
Philipp Hörist
gitlab at dev.gajim.org
Thu Jul 26 20:51:16 CEST 2018
Philipp Hörist pushed to branch master at gajim / gajim
Commits:
db77fa1a by Philipp Hörist at 2018-07-26T18:38:00Z
Add roster implementation to Gajim
- - - - -
12 changed files:
- gajim/accounts_window.py
- gajim/common/connection.py
- gajim/common/connection_handlers.py
- gajim/common/connection_handlers_events.py
- gajim/common/modules/__init__.py
- gajim/common/modules/presence.py
- + gajim/common/modules/roster.py
- gajim/common/zeroconf/connection_zeroconf.py
- gajim/common/zeroconf/roster_zeroconf.py
- gajim/gui_interface.py
- gajim/roster_window.py
- gajim/tooltips.py
Changes:
=====================================
gajim/accounts_window.py
=====================================
--- a/gajim/accounts_window.py
+++ b/gajim/accounts_window.py
@@ -301,6 +301,8 @@ class AccountsWindow(Gtk.ApplicationWindow):
app.interface.roster.regroup = app.config.get('mergeaccounts')
else:
app.interface.roster.regroup = False
+ app.config.set_per(
+ 'accounts', account, 'roster_version', '')
app.interface.roster.setup_and_draw_roster()
gui_menu_builder.build_accounts_menu()
=====================================
gajim/common/connection.py
=====================================
--- a/gajim/common/connection.py
+++ b/gajim/common/connection.py
@@ -387,15 +387,15 @@ class CommonConnection:
raise NotImplementedError
def update_contact(self, jid, name, groups):
- if self.connection and self.roster_supported:
- self.connection.getRoster().setItem(jid=jid, name=name, groups=groups)
+ if self.connection:
+ self.getRoster().setItem(jid=jid, name=name, groups=groups)
def update_contacts(self, contacts):
"""
Update multiple roster items
"""
- if self.connection and self.roster_supported:
- self.connection.getRoster().setItemMulti(contacts)
+ if self.connection:
+ self.getRoster().setItemMulti(contacts)
def new_account(self, name, config, sync=False):
"""
@@ -443,10 +443,6 @@ class CommonConnection:
return self.gpg.get_secret_keys()
return None
- def load_roster_from_db(self):
- # Do nothing by default
- return
-
def _event_dispatcher(self, realm, event, data):
if realm == '':
if event == 'STANZA_RECEIVED':
@@ -1622,7 +1618,7 @@ class Connection(CommonConnection, ConnectionHandlers):
iq.setID(id_)
self.awaiting_answers[id_] = (AGENT_REMOVED, agent)
self.connection.send(iq)
- self.connection.getRoster().delItem(agent)
+ self.getRoster().delItem(agent)
def send_new_account_infos(self, form, is_form):
if is_form:
@@ -1747,6 +1743,9 @@ class Connection(CommonConnection, ConnectionHandlers):
iq3.addChild(name='meta', attrs=dict_)
self.connection.send(iq)
+ def getRoster(self):
+ return self.get_module('Roster')
+
def request_roster(self, resume=False):
version = None
features = self.connection.Dispatcher.Stream.features
@@ -1754,18 +1753,8 @@ class Connection(CommonConnection, ConnectionHandlers):
version = app.config.get_per(
'accounts', self.name, 'roster_version')
- iq_id = self.connection.initRoster(version=version,
- request=not resume)
- if resume:
- self._init_roster_from_db()
- else:
- self.awaiting_answers[iq_id] = (ROSTER_ARRIVED, )
-
- def _init_roster_from_db(self):
- account_jid = app.get_jid_from_account(self.name)
- roster_data = app.logger.get_roster(account_jid)
- roster = self.connection.getRoster(force=True)
- roster.setRaw(roster_data)
+ if not resume:
+ self.get_module('Roster').request_roster(version)
def send_agent_status(self, agent, ptype):
if not app.account_is_connected(self.name):
@@ -2056,8 +2045,3 @@ class Connection(CommonConnection, ConnectionHandlers):
self.reconnect()
else:
self.time_to_reconnect = None
-
- def load_roster_from_db(self):
- app.nec.push_incoming_event(RosterReceivedEvent(None, conn=self))
-
-# END Connection
=====================================
gajim/common/connection_handlers.py
=====================================
--- a/gajim/common/connection_handlers.py
+++ b/gajim/common/connection_handlers.py
@@ -468,19 +468,11 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
app.nec.register_incoming_event(StreamConflictReceivedEvent)
app.nec.register_incoming_event(NotificationEvent)
- app.ged.register_event_handler('roster-set-received',
- ged.CORE, self._nec_roster_set_received)
- app.ged.register_event_handler('roster-received', ged.CORE,
- self._nec_roster_received)
app.ged.register_event_handler('agent-removed', ged.CORE,
self._nec_agent_removed)
def cleanup(self):
ConnectionHandlersBase.cleanup(self)
- app.ged.remove_event_handler('roster-set-received',
- ged.CORE, self._nec_roster_set_received)
- app.ged.remove_event_handler('roster-received', ged.CORE,
- self._nec_roster_received)
app.ged.remove_event_handler('agent-removed', ged.CORE,
self._nec_agent_removed)
@@ -555,41 +547,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
# We can now continue connection by requesting the roster
self.request_roster()
- elif self.awaiting_answers[id_][0] == ROSTER_ARRIVED:
- if iq_obj.getType() == 'result':
- if not iq_obj.getTag('query'):
- self._init_roster_from_db()
- self._getRoster()
- elif iq_obj.getType() == 'error':
- self.roster_supported = False
- self.get_module('Discovery').discover_server_items()
- if app.config.get_per('accounts', self.name,
- 'use_ft_proxies'):
- self.discover_ft_proxies()
- app.nec.push_incoming_event(RosterReceivedEvent(None,
- conn=self))
- del self.awaiting_answers[id_]
-
- def _rosterSetCB(self, con, iq_obj):
- log.debug('rosterSetCB')
- app.nec.push_incoming_event(RosterSetReceivedEvent(None, conn=self,
- stanza=iq_obj))
- raise nbxmpp.NodeProcessed
-
- def _nec_roster_set_received(self, obj):
- if obj.conn.name != self.name:
- return
- for jid in obj.items:
- item = obj.items[jid]
- app.nec.push_incoming_event(RosterInfoEvent(None, conn=self,
- jid=jid, nickname=item['name'], sub=item['sub'],
- ask=item['ask'], groups=item['groups']))
- account_jid = app.get_jid_from_account(self.name)
- app.logger.add_or_update_contact(account_jid, jid, item['name'],
- item['sub'], item['ask'], item['groups'])
- if obj.version:
- app.config.set_per('accounts', self.name, 'roster_version',
- obj.version)
def _dispatch_gc_msg_with_captcha(self, stanza, msg_obj):
msg_obj.stanza = stanza
@@ -657,15 +614,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
# This way we'll really remove it
app.to_be_removed[self.name].remove(jid)
- def _getRoster(self):
- log.debug('getRosterCB')
- if not self.connection:
- return
- self.connection.getRoster(self._on_roster_set)
- self.get_module('Discovery').discover_server_items()
- if app.config.get_per('accounts', self.name, 'use_ft_proxies'):
- self.discover_ft_proxies()
-
def discover_ft_proxies(self):
cfg_proxies = app.config.get_per('accounts', self.name,
'file_transfer_proxies')
@@ -679,15 +627,7 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
app.proxy65_manager.resolve(proxy, self.connection, our_jid,
testit=testit)
- def _on_roster_set(self, roster):
- app.nec.push_incoming_event(RosterReceivedEvent(None, conn=self,
- xmpp_roster=roster))
-
- def _nec_roster_received(self, obj):
- if obj.conn.name != self.name:
- return
- our_jid = app.get_jid_from_account(self.name)
-
+ def send_first_presence(self):
if self.connected > 1 and self.continue_connect_info:
msg = self.continue_connect_info[1]
sign_msg = self.continue_connect_info[2]
@@ -705,20 +645,6 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
if send_first_presence:
self._send_first_presence(signed)
- app.logger.replace_roster(self.name, obj.version, obj.roster)
-
- for contact in app.contacts.iter_contacts(self.name):
- if not contact.is_groupchat() and contact.jid not in obj.roster\
- and contact.jid != our_jid:
- app.nec.push_incoming_event(RosterInfoEvent(None,
- conn=self, jid=contact.jid, nickname=None, sub=None,
- ask=None, groups=()))
- for jid, info in obj.roster.items():
- app.nec.push_incoming_event(RosterInfoEvent(None,
- conn=self, jid=jid, nickname=info['name'],
- sub=info['subscription'], ask=info['ask'],
- groups=info['groups'], avatar_sha=info['avatar_sha']))
-
def _send_first_presence(self, signed=''):
show = self.continue_connect_info[0]
msg = self.continue_connect_info[1]
@@ -786,7 +712,7 @@ class ConnectionHandlers(ConnectionSocks5Bytestream, ConnectionDisco,
def _register_handlers(self, con, con_type):
# try to find another way to register handlers in each class
# that defines handlers
- con.RegisterHandler('iq', self._rosterSetCB, 'set', nbxmpp.NS_ROSTER)
+
con.RegisterHandler('iq', self._siSetCB, 'set', nbxmpp.NS_SI)
con.RegisterHandler('iq', self._siErrorCB, 'error', nbxmpp.NS_SI)
con.RegisterHandler('iq', self._siResultCB, 'result', nbxmpp.NS_SI)
=====================================
gajim/common/connection_handlers_events.py
=====================================
--- a/gajim/common/connection_handlers_events.py
+++ b/gajim/common/connection_handlers_events.py
@@ -179,93 +179,6 @@ class HelperEvent:
self.muc_pm = muc_user.getChildren() == []
return self.muc_pm
-class RosterReceivedEvent(nec.NetworkIncomingEvent):
- name = 'roster-received'
- base_network_events = []
-
- def generate(self):
- if hasattr(self, 'xmpp_roster'):
- self.version = self.xmpp_roster.version
- self.received_from_server = self.xmpp_roster.received_from_server
- self.roster = {}
- raw_roster = self.xmpp_roster.getRaw()
- our_jid = app.get_jid_from_account(self.conn.name)
-
- for jid in raw_roster:
- try:
- j = helpers.parse_jid(jid)
- except Exception:
- print(_('JID %s is not RFC compliant. It will not be added '
- 'to your roster. Use roster management tools such as '
- 'http://jru.jabberstudio.org/ to remove it') % jid,
- file=sys.stderr)
- else:
- infos = raw_roster[jid]
- if jid != our_jid and (not infos['subscription'] or \
- infos['subscription'] == 'none') and (not infos['ask'] or \
- infos['ask'] == 'none') and not infos['name'] and \
- not infos['groups']:
- # remove this useless item, it won't be shown in roster
- # anyway
- self.conn.connection.getRoster().delItem(jid)
- elif jid != our_jid: # don't add our jid
- self.roster[j] = raw_roster[jid]
- self.roster[j]['avatar_sha'] = None
- else:
- # Roster comes from DB
- self.received_from_server = False
- self.version = app.config.get_per('accounts', self.conn.name,
- 'roster_version')
- self.roster = app.logger.get_roster(app.get_jid_from_account(
- self.conn.name))
- if not self.roster:
- app.config.set_per(
- 'accounts', self.conn.name, 'roster_version', '')
- return True
-
-class RosterSetReceivedEvent(nec.NetworkIncomingEvent):
- name = 'roster-set-received'
- base_network_events = []
-
- def generate(self):
- frm = self.stanza.getFrom()
- our_jid = self.conn.get_own_jid()
- if frm is not None and not frm.bareMatch(our_jid):
- return
- self.version = self.stanza.getTagAttr('query', 'ver')
- self.items = {}
- for item in self.stanza.getTag('query').getChildren():
- try:
- jid = helpers.parse_jid(item.getAttr('jid'))
- except helpers.InvalidFormat:
- log.warning('Invalid JID: %s, ignoring it' % item.getAttr('jid'))
- continue
- name = item.getAttr('name')
- sub = item.getAttr('subscription')
- ask = item.getAttr('ask')
- groups = []
- for group in item.getTags('group'):
- groups.append(group.getData())
- self.items[jid] = {'name': name, 'sub': sub, 'ask': ask,
- 'groups': groups}
- if len(self.items) > 1:
- reply = nbxmpp.Iq(typ='error', attrs={'id': self.stanza.getID()},
- to=self.stanza.getFrom(), frm=self.stanza.getTo(), xmlns=None)
- self.conn.connection.send(reply)
- return
- if self.conn.connection and self.conn.connected > 1:
- reply = nbxmpp.Iq(typ='result', attrs={'id': self.stanza.getID()},
- to=self.stanza.getFrom(), frm=self.stanza.getTo(), xmlns=None)
- self.conn.connection.send(reply)
- return True
-
-class RosterInfoEvent(nec.NetworkIncomingEvent):
- name = 'roster-info'
- base_network_events = []
-
- def init(self):
- self.avatar_sha = None
-
class IqErrorReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
name = 'iq-error-received'
base_network_events = []
=====================================
gajim/common/modules/__init__.py
=====================================
--- a/gajim/common/modules/__init__.py
+++ b/gajim/common/modules/__init__.py
@@ -15,6 +15,7 @@
import logging
from importlib import import_module
from pathlib import Path
+from unittest.mock import MagicMock
log = logging.getLogger('gajim.c.m')
@@ -60,9 +61,7 @@ class ModuleMock:
self.supported = False
def __getattr__(self, key):
- def _mock(self, *args, **kwargs):
- return
- return _mock
+ return MagicMock()
def register(con, *args, **kwargs):
=====================================
gajim/common/modules/presence.py
=====================================
--- a/gajim/common/modules/presence.py
+++ b/gajim/common/modules/presence.py
@@ -140,15 +140,15 @@ class Presence:
if not app.account_is_connected(self._account):
return
if remove_auth:
- self._con.connection.getRoster().delItem(jid)
+ self._con.getRoster().delItem(jid)
jid_list = app.config.get_per('contacts')
for j in jid_list:
if j.startswith(jid):
app.config.del_per('contacts', j)
else:
log.info('Unsubscribe from %s', jid)
- self._con.connection.getRoster().Unsubscribe(jid)
- self._con.connection.getRoster().setItem(jid)
+ self._con.getRoster().Unsubscribe(jid)
+ self._con.getRoster().setItem(jid)
def subscribe(self, jid, msg='', name='', groups=None,
auto_auth=False, user_nick=''):
=====================================
gajim/common/modules/roster.py
=====================================
--- /dev/null
+++ b/gajim/common/modules/roster.py
@@ -0,0 +1,351 @@
+# 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/>.
+
+# Roster
+
+import logging
+from collections import namedtuple
+
+import nbxmpp
+
+from gajim.common import app
+from gajim.common.nec import NetworkEvent
+
+log = logging.getLogger('gajim.c.m.roster')
+
+
+# TODO: Error IQs
+# What if roster not supported on server -> error
+
+RosterItem = namedtuple('RosterItem', 'jid data')
+
+
+class Roster:
+ def __init__(self, con):
+ self._con = con
+ self._account = con.name
+
+ self.handlers = [
+ ('iq', self._roster_push_received, 'set', nbxmpp.NS_ROSTER),
+ ('presence', self._presence_received)
+ ]
+
+ self._data = {}
+ self._set = None
+
+ def load_roster(self):
+ log.info('Load from database')
+ account_jid = self._con.get_own_jid().getStripped()
+ data = app.logger.get_roster(account_jid)
+ if data:
+ self.setRaw(data)
+ for jid, item in self._data.items():
+ app.nec.push_incoming_event(NetworkEvent(
+ 'roster-info',
+ conn=self._con,
+ jid=jid,
+ nickname=item['name'],
+ sub=item['subscription'],
+ ask=item['ask'],
+ groups=item['groups'],
+ avatar_sha=item['avatar_sha']))
+ else:
+ log.info('Database empty, reset roster version')
+ app.config.set_per(
+ 'accounts', self._account, 'roster_version', '')
+
+ def request_roster(self, version):
+ log.info('Requested from server')
+ iq = nbxmpp.Iq('get', nbxmpp.NS_ROSTER)
+ if version is not None:
+ iq.setTagAttr('query', 'ver', version)
+ log.info('Request version: %s', version)
+ self._con.connection.SendAndCallForResponse(
+ iq, self._roster_received)
+
+ def _roster_received(self, stanza):
+ if not nbxmpp.isResultNode(stanza):
+ log.warning('Unable to retrive roster: %s', stanza.getError())
+ return
+
+ log.info('Received Roster')
+ received_from_server = False
+ if stanza.getTag('query') is not None:
+ # clear Roster
+ self._data = {}
+ version = self._parse_roster(stanza)
+
+ log.info('New version: %s', version)
+ app.logger.replace_roster(self._account, version, self._data)
+
+ received_from_server = True
+
+ app.nec.push_incoming_event(NetworkEvent(
+ 'roster-received',
+ conn=self._con,
+ roster=self._data.copy(),
+ received_from_server=received_from_server))
+
+ self._con.send_first_presence()
+
+ def _roster_push_received(self, con, stanza):
+ log.info('Push received')
+
+ sender = stanza.getFrom()
+ if sender is not None:
+ if not self._con.get_own_jid().bareMatch(sender):
+ log.warning('Wrong JID %s', stanza.getFrom())
+ return
+
+ push_items, version = self._parse_push(stanza)
+
+ self._ack_roster_push(stanza)
+
+ for item in push_items:
+ attrs = item.data
+ app.nec.push_incoming_event(NetworkEvent(
+ 'roster-info',
+ conn=self._con,
+ jid=item.jid,
+ nickname=attrs['name'],
+ sub=attrs['subscription'],
+ ask=attrs['ask'],
+ groups=attrs['groups'],
+ avatar_sha=None))
+ account_jid = self._con.get_own_jid().getStripped()
+ app.logger.add_or_update_contact(
+ account_jid, item.jid, attrs['name'],
+ attrs['subscription'], attrs['ask'], attrs['groups'])
+
+ log.info('New version: %s', version)
+ app.config.set_per(
+ 'accounts', self._account, 'roster_version', version)
+
+ raise nbxmpp.NodeProcessed
+
+ def _parse_roster(self, stanza):
+ query = stanza.getTag('query')
+ version = query.getAttr('ver')
+
+ for item in query.getTags('item'):
+ jid = item.getAttr('jid')
+ self._data[jid] = self._get_item_attrs(item, update=False)
+ log.info('Item %s: %s', jid, self._data[jid])
+ return version
+
+ @staticmethod
+ def _get_item_attrs(item, update=True):
+ '''
+ update: True
+ returns only the attrs that are present in the item
+
+ update: False
+ returns the attrs of the item but fills missing
+ attrs with default values
+ '''
+
+ default_attrs = {'name': None,
+ 'ask': None,
+ 'subscription': None,
+ 'groups': [],
+ 'avatar_sha': None}
+
+ attrs = item.getAttrs()
+ del attrs['jid']
+ groups = set([group.getData() for group in item.getTags('group')])
+ attrs['groups'] = list(groups)
+
+ if update:
+ return attrs
+ default_attrs.update(attrs)
+ return default_attrs
+
+ def _parse_push(self, stanza):
+ query = stanza.getTag('query')
+ version = query.getAttr('ver')
+ push_items = []
+
+ for item in query.getTags('item'):
+ push_items.append(self._update_roster_item(item))
+ for item in push_items:
+ log.info('Push: %s', item)
+ return push_items, version
+
+ def _update_roster_item(self, item):
+ jid = item.getAttr('jid')
+
+ if item.getAttr('subscription') == 'remove':
+ self._data.pop(jid, None)
+ attrs = self._get_item_attrs(item, update=False)
+ return RosterItem(jid, attrs)
+
+ else:
+ if jid not in self._data:
+ self._data[jid] = self._get_item_attrs(item, update=False)
+ else:
+ self._data[jid].update(self._get_item_attrs(item))
+
+ return RosterItem(jid, self._data[jid])
+
+ def _ack_roster_push(self, stanza):
+ iq = nbxmpp.Iq('result',
+ to=stanza.getFrom(),
+ frm=stanza.getTo(),
+ attrs={'id': stanza.getID()})
+ self._con.connection.send(iq)
+
+ def _presence_received(self, con, pres):
+ '''
+ Add contacts that request subscription to our internal
+ roster and also to the database. The contact is put into the
+ 'Not in roster' group and because we save it to the database
+ it is also after a restart available.
+ '''
+
+ if pres.getType() != 'subscribe':
+ return
+
+ jid = pres.getFrom().getStripped()
+
+ if jid in self._data:
+ return
+
+ log.info('Add Contact from presence %s', jid)
+ self._data[jid] = {'name': None,
+ 'ask': None,
+ 'subscription':
+ 'none',
+ 'groups': ['Not in roster']}
+ account_jid = self._con.get_own_jid().getStripped()
+ app.logger.add_or_update_contact(
+ account_jid, jid,
+ self._data[jid]['name'],
+ self._data[jid]['subscription'],
+ self._data[jid]['ask'],
+ self._data[jid]['groups'])
+
+ def _getItemData(self, jid, dataname):
+ """
+ Return specific jid's representation in internal format.
+ """
+ jid = jid[:(jid + '/').find('/')]
+ return self._data[jid][dataname]
+
+ def delItem(self, jid):
+ """
+ Delete contact 'jid' from roster
+ """
+ self._con.connection.send(
+ nbxmpp.Iq('set', nbxmpp.NS_ROSTER, payload=[
+ nbxmpp.Node('item', {'jid': jid, 'subscription': 'remove'})]))
+
+ def getGroups(self, jid):
+ """
+ Return groups list that contact 'jid' belongs to
+ """
+ return self._getItemData(jid, 'groups')
+
+ def getName(self, jid):
+ """
+ Return name of contact 'jid'
+ """
+ return self._getItemData(jid, 'name')
+
+ def setItem(self, jid, name=None, groups=None):
+ """
+ Rename contact 'jid' and sets the groups list that it now belongs to
+ """
+ iq = nbxmpp.Iq('set', nbxmpp.NS_ROSTER)
+ query = iq.getTag('query')
+ attrs = {'jid': jid}
+ if name:
+ attrs['name'] = name
+ item = query.setTag('item', attrs)
+ if groups is not None:
+ for group in groups:
+ item.addChild(node=nbxmpp.Node('group', payload=[group]))
+ self._con.connection.send(iq)
+
+ def setItemMulti(self, items):
+ """
+ Rename multiple contacts and sets their group lists
+ """
+ for i in items:
+ iq = nbxmpp.Iq('set', nbxmpp.NS_ROSTER)
+ query = iq.getTag('query')
+ attrs = {'jid': i['jid']}
+ if i['name']:
+ attrs['name'] = i['name']
+ item = query.setTag('item', attrs)
+ for group in i['groups']:
+ item.addChild(node=nbxmpp.Node('group', payload=[group]))
+ self._con.connection.send(iq)
+
+ def getItems(self):
+ """
+ Return list of all [bare] JIDs that the roster is currently tracks
+ """
+ return list(self._data.keys())
+
+ def keys(self):
+ """
+ Same as getItems. Provided for the sake of dictionary interface
+ """
+ return list(self._data.keys())
+
+ def __getitem__(self, item):
+ """
+ Get the contact in the internal format.
+ Raises KeyError if JID 'item' is not in roster
+ """
+ return self._data[item]
+
+ def getItem(self, item):
+ """
+ Get the contact in the internal format (or None if JID 'item' is not in
+ roster)
+ """
+ if item in self._data:
+ return self._data[item]
+
+ def Unsubscribe(self, jid):
+ """
+ Ask for removing our subscription for JID 'jid'
+ """
+ self._con.connection.send(nbxmpp.Presence(jid, 'unsubscribe'))
+
+ def getRaw(self):
+ """
+ Return the internal data representation of the roster
+ """
+ return self._data
+
+ def setRaw(self, data):
+ """
+ Set the internal data representation of the roster
+ """
+ own_jid = self._con.get_own_jid().getStripped()
+ self._data = data
+ self._data[own_jid] = {
+ 'resources': {},
+ 'name': None,
+ 'ask': None,
+ 'subscription': None,
+ 'groups': None,
+ 'avatar_sha': None
+ }
+
+
+def get_instance(*args, **kwargs):
+ return Roster(*args, **kwargs), 'Roster'
=====================================
gajim/common/zeroconf/connection_zeroconf.py
=====================================
--- a/gajim/common/zeroconf/connection_zeroconf.py
+++ b/gajim/common/zeroconf/connection_zeroconf.py
@@ -135,9 +135,11 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
diffs = self.roster.getDiffs()
for key in diffs:
self.roster.setItem(key)
- app.nec.push_incoming_event(RosterInfoEvent(None, conn=self,
- jid=key, nickname=self.roster.getName(key), sub='both',
- ask='no', groups=self.roster.getGroups(key)))
+ app.nec.push_incoming_event(NetworkEvent(
+ 'roster-info', conn=self,jid=key,
+ nickname=self.roster.getName(key), sub='both',
+ ask='no', groups=self.roster.getGroups(key),
+ avatar_sha=None))
app.nec.push_incoming_event(ZeroconfPresenceReceivedEvent(
None, conn=self, fjid=key, show=self.roster.getStatus(key),
status=self.roster.getMessage(key)))
@@ -147,9 +149,11 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
# callbacks called from zeroconf
def _on_new_service(self, jid):
self.roster.setItem(jid)
- app.nec.push_incoming_event(RosterInfoEvent(None, conn=self,
- jid=jid, nickname=self.roster.getName(jid), sub='both',
- ask='no', groups=self.roster.getGroups(jid)))
+ app.nec.push_incoming_event(NetworkEvent(
+ 'roster-info', conn=self, jid=jid,
+ nickname=self.roster.getName(jid), sub='both',
+ ask='no', groups=self.roster.getGroups(jid),
+ avatar_sha=None))
app.nec.push_incoming_event(ZeroconfPresenceReceivedEvent(
None, conn=self, fjid=jid, show=self.roster.getStatus(jid),
status=self.roster.getMessage(jid)))
@@ -219,14 +223,16 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
else:
self.connection.announce()
self.roster = self.connection.getRoster()
- app.nec.push_incoming_event(RosterReceivedEvent(None, conn=self,
- xmpp_roster=self.roster))
+ app.nec.push_incoming_event(NetworkEvent('roster-received', conn=self,
+ roster=self.roster.copy(), received_from_server=True))
# display contacts already detected and resolved
for jid in self.roster.keys():
- app.nec.push_incoming_event(RosterInfoEvent(None, conn=self,
- jid=jid, nickname=self.roster.getName(jid), sub='both',
- ask='no', groups=self.roster.getGroups(jid)))
+ app.nec.push_incoming_event(NetworkEvent(
+ 'roster-info', conn=self, jid=jid,
+ nickname=self.roster.getName(jid), sub='both',
+ ask='no', groups=self.roster.getGroups(jid),
+ avatar_sha=None))
app.nec.push_incoming_event(ZeroconfPresenceReceivedEvent(
None, conn=self, fjid=jid, show=self.roster.getStatus(jid),
status=self.roster.getMessage(jid)))
=====================================
gajim/common/zeroconf/roster_zeroconf.py
=====================================
--- a/gajim/common/zeroconf/roster_zeroconf.py
+++ b/gajim/common/zeroconf/roster_zeroconf.py
@@ -18,15 +18,14 @@
##
-from gajim.common.zeroconf import zeroconf
from gajim.common.zeroconf.zeroconf import Constant, ConstantRI
+
class Roster:
def __init__(self, zeroconf):
self._data = None
self.zeroconf = zeroconf # our zeroconf instance
self.version = ''
- self.received_from_server = True
def update_roster(self):
for val in self.zeroconf.contacts.values():
@@ -109,6 +108,9 @@ class Roster:
def __getitem__(self, jid):
return self._data[jid]
+ def __setitem__(self, jid, value):
+ self._data[jid] = value
+
def getItems(self):
# Return list of all [bare] JIDs that the roster currently tracks.
return self._data.keys()
@@ -157,3 +159,6 @@ class Roster:
def Unauthorize(self, jid):
pass
+
+ def copy(self):
+ return self._data.copy()
=====================================
gajim/gui_interface.py
=====================================
--- a/gajim/gui_interface.py
+++ b/gajim/gui_interface.py
@@ -2628,7 +2628,7 @@ class Interface:
self.roster._before_fill()
for account in app.connections:
- app.connections[account].load_roster_from_db()
+ app.connections[account].get_module('Roster').load_roster()
self.roster._after_fill()
# get instances for windows/dialogs that will show_all()/hide()
=====================================
gajim/roster_window.py
=====================================
--- a/gajim/roster_window.py
+++ b/gajim/roster_window.py
@@ -2593,8 +2593,8 @@ class RosterWindow:
return
if obj.nick == gc_ctrl.nick:
- contact = app.contacts.get_contact_with_highest_priority(account,
- obj.room_jid)
+ contact = app.contacts.get_contact_with_highest_priority(
+ account, obj.room_jid)
if contact:
contact.show = obj.show
self.draw_contact(obj.room_jid, account)
@@ -2615,28 +2615,28 @@ class RosterWindow:
if app.connections[account].server_resource:
resource = app.connections[account].server_resource
sha = app.config.get_per('accounts', account, 'avatar_sha')
- contact = app.contacts.create_contact(jid=self_jid,
- account=account, name=app.nicks[account],
+ contact = app.contacts.create_contact(
+ jid=self_jid, account=account, name=app.nicks[account],
groups=['self_contact'], show='offline', sub='both',
ask='none', resource=resource, avatar_sha=sha)
app.contacts.add_contact(account, contact)
self.add_contact(self_jid, account)
if app.config.get('remember_opened_chat_controls'):
account = obj.conn.name
- controls = app.config.get_per('accounts', account,
- 'opened_chat_controls')
+ controls = app.config.get_per(
+ 'accounts', account, 'opened_chat_controls')
if controls:
for jid in controls.split(','):
contact = \
app.contacts.get_contact_with_highest_priority(
- account, jid)
+ account, jid)
if not contact:
- contact = self.add_to_not_in_the_roster(account,
- jid)
- app.interface.on_open_chat_window(None, contact,
- account)
- app.config.set_per('accounts', account,
- 'opened_chat_controls', '')
+ contact = self.add_to_not_in_the_roster(
+ account, jid)
+ app.interface.on_open_chat_window(
+ None, contact, account)
+ app.config.set_per(
+ 'accounts', account, 'opened_chat_controls', '')
GLib.idle_add(self.refilter_shown_roster_items)
def _nec_anonymous_auth(self, obj):
=====================================
gajim/tooltips.py
=====================================
--- a/gajim/tooltips.py
+++ b/gajim/tooltips.py
@@ -384,34 +384,6 @@ class RosterTooltip(Gtk.Window, StatusTable):
contact.keyID = app.config.get_per('accounts',
connection.name, 'keyid')
contacts.append(contact)
- # if we're online ...
- if connection.connection:
- roster = connection.connection.getRoster()
- # in threadless connection when no roster stanza is sent
- # 'roster' is None
- if roster and roster.getItem(jid):
- resources = roster.getResources(jid)
- # ...get the contact info for our other online
- # resources
- for resource in resources:
- # Check if we already have this resource
- found = False
- for contact_ in contacts:
- if contact_.resource == resource:
- found = True
- break
- if found:
- continue
- show = roster.getShow(jid + '/' + resource)
- if not show:
- show = 'online'
- contact = app.contacts.create_self_contact(
- jid=jid, account=account, show=show,
- status=roster.getStatus(
- jid + '/' + resource),
- priority=roster.getPriority(
- jid + '/' + resource), resource=resource)
- contacts.append(contact)
# Username/Account/Groupchat
self.prim_contact = app.contacts.get_highest_prio_contact_from_contacts(
View it on GitLab: https://dev.gajim.org/gajim/gajim/commit/db77fa1aceb0364ad98521c38a5164997f3cd6c8
--
View it on GitLab: https://dev.gajim.org/gajim/gajim/commit/db77fa1aceb0364ad98521c38a5164997f3cd6c8
You're receiving this email because of your account on dev.gajim.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.gajim.org/pipermail/commits/attachments/20180726/eeed23d4/attachment-0001.html>
More information about the Commits
mailing list