* 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
This commit is contained in:
Anaël Verrier 2009-06-27 17:56:04 +02:00
parent f2e214a033
commit d347b79c38
4 changed files with 101 additions and 16 deletions

View file

@ -65,6 +65,7 @@ VCARD_PUBLISHED = 'vcard_published'
VCARD_ARRIVED = 'vcard_arrived' VCARD_ARRIVED = 'vcard_arrived'
AGENT_REMOVED = 'agent_removed' AGENT_REMOVED = 'agent_removed'
METACONTACTS_ARRIVED = 'metacontacts_arrived' METACONTACTS_ARRIVED = 'metacontacts_arrived'
ROSTER_ARRIVED = 'roster_arrived'
PRIVACY_ARRIVED = 'privacy_arrived' PRIVACY_ARRIVED = 'privacy_arrived'
PEP_CONFIG = 'pep_config' PEP_CONFIG = 'pep_config'
HAS_IDLE = True HAS_IDLE = True
@ -1166,7 +1167,16 @@ class ConnectionVcard:
# We can now continue connection by requesting the roster # We can now continue connection by requesting the roster
version = gajim.config.get_per('accounts', self.name, version = gajim.config.get_per('accounts', self.name,
'roster_version') '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: elif self.awaiting_answers[id_][0] == PRIVACY_ARRIVED:
if iq_obj.getType() != 'error': if iq_obj.getType() != 'error':
self.privacy_rules_supported = True self.privacy_rules_supported = True
@ -2418,7 +2428,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
self.connection.send(result) self.connection.send(result)
raise common.xmpp.NodeProcessed raise common.xmpp.NodeProcessed
def _getRosterCB(self, con, iq_obj): def _getRoster(self):
log.debug('getRosterCB') log.debug('getRosterCB')
if not self.connection: if not self.connection:
return return
@ -2441,6 +2451,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
gajim.proxy65_manager.resolve(proxy, self.connection, our_jid) gajim.proxy65_manager.resolve(proxy, self.connection, our_jid)
def _on_roster_set(self, roster): def _on_roster_set(self, roster):
roster_version = roster.version
raw_roster = roster.getRaw() raw_roster = roster.getRaw()
roster = {} roster = {}
our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name)) 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.discoverInfo(jid)
self.dispatch('ROSTER', roster) self.dispatch('ROSTER', roster)
gajim.logger.replace_roster(self.name, roster_version, roster)
print raw_roster
def _send_first_presence(self, signed = ''): def _send_first_presence(self, signed = ''):
show = self.continue_connect_info[0] show = self.continue_connect_info[0]
@ -2621,8 +2634,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
common.xmpp.NS_MUC_OWNER) common.xmpp.NS_MUC_OWNER)
con.RegisterHandler('iq', self._MucAdminCB, 'result', con.RegisterHandler('iq', self._MucAdminCB, 'result',
common.xmpp.NS_MUC_ADMIN) common.xmpp.NS_MUC_ADMIN)
con.RegisterHandler('iq', self._getRosterCB, 'result',
common.xmpp.NS_ROSTER)
con.RegisterHandler('iq', self._PrivateCB, 'result', con.RegisterHandler('iq', self._PrivateCB, 'result',
common.xmpp.NS_PRIVATE) common.xmpp.NS_PRIVATE)
con.RegisterHandler('iq', self._HttpAuthCB, 'get', con.RegisterHandler('iq', self._HttpAuthCB, 'get',

View file

@ -339,6 +339,7 @@ class Logger:
return 'mrim' return 'mrim'
def convert_human_subscription_values_to_db_api_values(self, sub): def convert_human_subscription_values_to_db_api_values(self, sub):
'''converts from string style to constant ints for db'''
if sub == 'none': if sub == 'none':
return constants.SUBSCRIPTION_NONE return constants.SUBSCRIPTION_NONE
if sub == 'to': if sub == 'to':
@ -348,6 +349,17 @@ class Logger:
if sub == 'both': if sub == 'both':
return constants.SUBSCRIPTION_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): def commit_to_db(self, values, write_unread = False):
sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message, subject) VALUES (?, ?, ?, ?, ?, ?, ?)' sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message, subject) VALUES (?, ?, ?, ?, ?, ?, ?)'
try: try:
@ -816,7 +828,30 @@ class Logger:
except sqlite.OperationalError, e: except sqlite.OperationalError, e:
print >> sys.stderr, str(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): def del_contact(self, account_jid, jid):
''' Remove jid from account_jid roster. '''
try: try:
account_jid_id = self.get_jid_id(account_jid) account_jid_id = self.get_jid_id(account_jid)
jid_id = self.get_jid_id(jid) jid_id = self.get_jid_id(jid)
@ -826,6 +861,7 @@ class Logger:
self.simple_commit(sql) self.simple_commit(sql)
def add_or_update_contact(self, account_jid, jid, name, sub, groups): def add_or_update_contact(self, account_jid, jid, name, sub, groups):
''' Add or update a contact from account_jid roster. '''
if sub == 'remove': if sub == 'remove':
self.del_contact(account_jid, jid) self.del_contact(account_jid, jid)
return return
@ -836,11 +872,11 @@ class Logger:
except exceptions.PysqliteOperationalError, e: except exceptions.PysqliteOperationalError, e:
raise exceptions.PysqliteOperationalError(str(e)) raise exceptions.PysqliteOperationalError(str(e))
# update groups information # Update groups information
# first we delete all previous 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) sql = 'DELETE FROM roster_group WHERE account_jid_id = %d AND jid_id = %d' % (account_jid_id, jid_id)
self.cur.execute(sql) self.cur.execute(sql)
# then we add all new groups information # Then we add all new groups information
for group in groups: for group in groups:
sql = 'INSERT INTO roster_group VALUES("%d", "%d", "%s")' % ( sql = 'INSERT INTO roster_group VALUES("%d", "%d", "%s")' % (
account_jid_id, jid_id, group) account_jid_id, jid_id, group)
@ -851,4 +887,29 @@ class Logger:
self.convert_human_subscription_values_to_db_api_values(sub)) self.convert_human_subscription_values_to_db_api_values(sub))
self.simple_commit(sql) 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: # vim: se ts=3:

View file

@ -506,13 +506,13 @@ class NonBlockingClient:
def initRoster(self, version=''): def initRoster(self, version=''):
''' Plug in the roster. ''' ''' Plug in the roster. '''
if not self.__dict__.has_key('NonBlockingRoster'): 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 ''' Return the Roster instance, previously plugging it in and
requesting roster from server if needed. ''' requesting roster from server if needed. '''
if self.__dict__.has_key('NonBlockingRoster'): if self.__dict__.has_key('NonBlockingRoster'):
return self.NonBlockingRoster.getRoster(on_ready) return self.NonBlockingRoster.getRoster(on_ready, force)
return None return None
def sendPresence(self, jid=None, typ=None, requestRoster=0): def sendPresence(self, jid=None, typ=None, requestRoster=0):

View file

@ -52,8 +52,11 @@ class NonBlockingRoster(PlugIn):
iq = Iq('get',NS_ROSTER) iq = Iq('get',NS_ROSTER)
iq.setTagAttr('query', 'ver', self.version) iq.setTagAttr('query', 'ver', self.version)
id_ = self._owner.getAnID()
iq.setID(id_)
self._owner.send(iq) self._owner.send(iq)
log.info('Roster requested from server') log.info('Roster requested from server')
return id_
def RosterIqHandler(self,dis,stanza): def RosterIqHandler(self,dis,stanza):
''' Subscription tracker. Used internally for setting items state in ''' Subscription tracker. Used internally for setting items state in
@ -64,6 +67,9 @@ class NonBlockingRoster(PlugIn):
return return
query = stanza.getTag('query') query = stanza.getTag('query')
if query: if query:
self.version = stanza.getTagAttr('query', 'ver')
if self.version is None:
self.version = ''
for item in query.getTags('item'): for item in query.getTags('item'):
jid=item.getAttr('jid') jid=item.getAttr('jid')
if item.getAttr('subscription')=='remove': if item.getAttr('subscription')=='remove':
@ -192,6 +198,11 @@ class NonBlockingRoster(PlugIn):
def getRaw(self): def getRaw(self):
'''Returns the internal data representation of the roster.''' '''Returns the internal data representation of the roster.'''
return self._data 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 # 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('iq', self.RosterIqHandler, 'set', NS_ROSTER)
self._owner.RegisterHandler('presence', self.PresenceHandler) self._owner.RegisterHandler('presence', self.PresenceHandler)
if request: if request:
self.Request() return self.Request()
def _on_roster_set(self, data): def _on_roster_set(self, data):
if data: if data:
@ -216,16 +227,18 @@ class NonBlockingRoster(PlugIn):
self.on_ready = None self.on_ready = None
return True 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. ''' ''' Requests roster from server if neccessary and returns self. '''
return_self = True
if not self.set: if not self.set:
self.on_ready = on_ready self.on_ready = on_ready
self._owner.onreceive(self._on_roster_set) self._owner.onreceive(self._on_roster_set)
return return_self = False
if on_ready: elif on_ready:
on_ready(self) on_ready(self)
on_ready = None return_self = False
else: if return_self or force:
return self return self
return None
# vim: se ts=3: # vim: se ts=3: