From d347b79c38a5cb8aeff8dad2d57dfac192a24b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Verrier?= Date: Sat, 27 Jun 2009 17:56:04 +0200 Subject: [PATCH] * added a method to load roster from DB * now we load roster from DB when we receive an iq result for the roster without any query * added a "force" argument to NonBlockingRoster.getRoster(), to force the return of the instance --- src/common/connection_handlers.py | 19 +++++++-- src/common/logger.py | 67 +++++++++++++++++++++++++++++-- src/common/xmpp/client_nb.py | 6 +-- src/common/xmpp/roster_nb.py | 25 +++++++++--- 4 files changed, 101 insertions(+), 16 deletions(-) diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index abda5877a..96f03244e 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -65,6 +65,7 @@ VCARD_PUBLISHED = 'vcard_published' VCARD_ARRIVED = 'vcard_arrived' AGENT_REMOVED = 'agent_removed' METACONTACTS_ARRIVED = 'metacontacts_arrived' +ROSTER_ARRIVED = 'roster_arrived' PRIVACY_ARRIVED = 'privacy_arrived' PEP_CONFIG = 'pep_config' HAS_IDLE = True @@ -1166,7 +1167,16 @@ class ConnectionVcard: # We can now continue connection by requesting the roster version = gajim.config.get_per('accounts', self.name, 'roster_version') - self.connection.initRoster(version=version) + iq_id = self.connection.initRoster(version=version) + self.awaiting_answers[iq_id] = (ROSTER_ARRIVED, ) + elif self.awaiting_answers[id_][0] == ROSTER_ARRIVED: + if iq_obj.getType() == 'result': + if not iq_obj.getTag('query'): + account_jid = gajim.get_jid_from_account(self.name) + roster_data = gajim.logger.get_roster(account_jid) + roster = self.connection.getRoster(force=True) + roster.setRaw(roster_data) + self._getRoster() elif self.awaiting_answers[id_][0] == PRIVACY_ARRIVED: if iq_obj.getType() != 'error': self.privacy_rules_supported = True @@ -2418,7 +2428,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, self.connection.send(result) raise common.xmpp.NodeProcessed - def _getRosterCB(self, con, iq_obj): + def _getRoster(self): log.debug('getRosterCB') if not self.connection: return @@ -2441,6 +2451,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, gajim.proxy65_manager.resolve(proxy, self.connection, our_jid) def _on_roster_set(self, roster): + roster_version = roster.version raw_roster = roster.getRaw() roster = {} our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name)) @@ -2480,6 +2491,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, self.discoverInfo(jid) self.dispatch('ROSTER', roster) + gajim.logger.replace_roster(self.name, roster_version, roster) + print raw_roster def _send_first_presence(self, signed = ''): show = self.continue_connect_info[0] @@ -2621,8 +2634,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, common.xmpp.NS_MUC_OWNER) con.RegisterHandler('iq', self._MucAdminCB, 'result', common.xmpp.NS_MUC_ADMIN) - con.RegisterHandler('iq', self._getRosterCB, 'result', - common.xmpp.NS_ROSTER) con.RegisterHandler('iq', self._PrivateCB, 'result', common.xmpp.NS_PRIVATE) con.RegisterHandler('iq', self._HttpAuthCB, 'get', diff --git a/src/common/logger.py b/src/common/logger.py index ca83320a9..102300c9e 100644 --- a/src/common/logger.py +++ b/src/common/logger.py @@ -339,6 +339,7 @@ class Logger: return 'mrim' def convert_human_subscription_values_to_db_api_values(self, sub): + '''converts from string style to constant ints for db''' if sub == 'none': return constants.SUBSCRIPTION_NONE if sub == 'to': @@ -348,6 +349,17 @@ class Logger: if sub == 'both': return constants.SUBSCRIPTION_BOTH + def convert_db_api_values_to_human_subscription_values(self, sub): + '''converts from constant ints for db to string style''' + if sub == constants.SUBSCRIPTION_NONE: + return 'none' + if sub == constants.SUBSCRIPTION_TO: + return 'to' + if sub == constants.SUBSCRIPTION_FROM: + return 'from' + if sub == constants.SUBSCRIPTION_BOTH: + return 'both' + def commit_to_db(self, values, write_unread = False): sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message, subject) VALUES (?, ?, ?, ?, ?, ?, ?)' try: @@ -816,7 +828,30 @@ class Logger: except sqlite.OperationalError, e: print >> sys.stderr, str(e) + def replace_roster(self, account_name, roster_version, roster): + ''' Replace current roster in DB by a new one. + accout_name is the name of the account to change + roster_version is the version of the new roster + roster is the new version ''' + gajim.config.set_per('accounts', account_name, 'roster_version', '') + account_jid = gajim.get_jid_from_account(account_name) + account_jid_id = self.get_jid_id(account_jid) + + # Delete old roster + sql = 'DELETE FROM roster_entry WHERE account_jid_id = %d' % ( + account_jid_id) + sql = 'DELETE FROM roster_group WHERE account_jid_id = %d' % ( + account_jid_id) + + # Fill roster tables with the new roster + for jid in roster: + self.add_or_update_contact(account_jid, jid, roster[jid]['name'], + roster[jid]['subscription'], roster[jid]['groups']) + gajim.config.set_per('accounts', account_name, 'roster_version', + roster_version) + def del_contact(self, account_jid, jid): + ''' Remove jid from account_jid roster. ''' try: account_jid_id = self.get_jid_id(account_jid) jid_id = self.get_jid_id(jid) @@ -826,6 +861,7 @@ class Logger: self.simple_commit(sql) def add_or_update_contact(self, account_jid, jid, name, sub, groups): + ''' Add or update a contact from account_jid roster. ''' if sub == 'remove': self.del_contact(account_jid, jid) return @@ -836,11 +872,11 @@ class Logger: except exceptions.PysqliteOperationalError, e: raise exceptions.PysqliteOperationalError(str(e)) - # update groups information - # first we delete all previous groups information + # Update groups information + # First we delete all previous groups information sql = 'DELETE FROM roster_group WHERE account_jid_id = %d AND jid_id = %d' % (account_jid_id, jid_id) self.cur.execute(sql) - # then we add all new groups information + # Then we add all new groups information for group in groups: sql = 'INSERT INTO roster_group VALUES("%d", "%d", "%s")' % ( account_jid_id, jid_id, group) @@ -851,4 +887,29 @@ class Logger: self.convert_human_subscription_values_to_db_api_values(sub)) self.simple_commit(sql) + def get_roster(self, account_jid): + ''' Return the accound_jid roster in NonBlockingRoster format. ''' + data = {} + account_jid_id = self.get_jid_id(account_jid) + + # First we fill data with roster_entry informations + self.cur.execute('SELECT j.jid, re.jid_id, re.name, re.subscription FROM roster_entry re, jids j WHERE re.account_jid_id="%(account_jid_id)s" AND j.jid_id=re.jid_id' % {'account_jid_id': account_jid_id}) + for jid, jid_id, name, subscription in self.cur: + data[jid] = {} + data[jid]['name'] = name + data[jid]['subscription'] = self.convert_db_api_values_to_human_subscription_values(subscription) + data[jid]['groups'] = [] + data[jid]['resources'] = {} + data[jid]['ask'] = None + data[jid]['id'] = jid_id + + # Then we add group for roster entries + for jid in data: + self.cur.execute('SELECT group_name FROM roster_group WHERE account_jid_id="%(account_jid_id)s" AND jid_id="%(jid_id)s"' % {'account_jid_id': account_jid_id, 'jid_id': data[jid]['id']}) + for (group_name,) in self.cur: + data[jid]['groups'].append(group_name) + del data[jid]['id'] + + return data + # vim: se ts=3: diff --git a/src/common/xmpp/client_nb.py b/src/common/xmpp/client_nb.py index e24277824..c89cffb2c 100644 --- a/src/common/xmpp/client_nb.py +++ b/src/common/xmpp/client_nb.py @@ -506,13 +506,13 @@ class NonBlockingClient: def initRoster(self, version=''): ''' Plug in the roster. ''' if not self.__dict__.has_key('NonBlockingRoster'): - roster_nb.NonBlockingRoster.get_instance(version=version).PlugIn(self) + return roster_nb.NonBlockingRoster.get_instance(version=version).PlugIn(self) - def getRoster(self, on_ready=None): + def getRoster(self, on_ready=None, force=False): ''' Return the Roster instance, previously plugging it in and requesting roster from server if needed. ''' if self.__dict__.has_key('NonBlockingRoster'): - return self.NonBlockingRoster.getRoster(on_ready) + return self.NonBlockingRoster.getRoster(on_ready, force) return None def sendPresence(self, jid=None, typ=None, requestRoster=0): diff --git a/src/common/xmpp/roster_nb.py b/src/common/xmpp/roster_nb.py index 7f257fefa..196604114 100644 --- a/src/common/xmpp/roster_nb.py +++ b/src/common/xmpp/roster_nb.py @@ -52,8 +52,11 @@ class NonBlockingRoster(PlugIn): iq = Iq('get',NS_ROSTER) iq.setTagAttr('query', 'ver', self.version) + id_ = self._owner.getAnID() + iq.setID(id_) self._owner.send(iq) log.info('Roster requested from server') + return id_ def RosterIqHandler(self,dis,stanza): ''' Subscription tracker. Used internally for setting items state in @@ -64,6 +67,9 @@ class NonBlockingRoster(PlugIn): return query = stanza.getTag('query') if query: + self.version = stanza.getTagAttr('query', 'ver') + if self.version is None: + self.version = '' for item in query.getTags('item'): jid=item.getAttr('jid') if item.getAttr('subscription')=='remove': @@ -192,6 +198,11 @@ class NonBlockingRoster(PlugIn): def getRaw(self): '''Returns the internal data representation of the roster.''' return self._data + def setRaw(self, data): + '''Returns the internal data representation of the roster.''' + self._data = data + self._data[self._owner.User+'@'+self._owner.Server]={'resources':{},'name':None,'ask':None,'subscription':None,'groups':None,} + self.set=1 # copypasted methods for roster.py from constructor to here @@ -203,7 +214,7 @@ class NonBlockingRoster(PlugIn): self._owner.RegisterHandler('iq', self.RosterIqHandler, 'set', NS_ROSTER) self._owner.RegisterHandler('presence', self.PresenceHandler) if request: - self.Request() + return self.Request() def _on_roster_set(self, data): if data: @@ -216,16 +227,18 @@ class NonBlockingRoster(PlugIn): self.on_ready = None return True - def getRoster(self, on_ready=None): + def getRoster(self, on_ready=None, force=False): ''' Requests roster from server if neccessary and returns self. ''' + return_self = True if not self.set: self.on_ready = on_ready self._owner.onreceive(self._on_roster_set) - return - if on_ready: + return_self = False + elif on_ready: on_ready(self) - on_ready = None - else: + return_self = False + if return_self or force: return self + return None # vim: se ts=3: