gajim

changeset 10773:1076fc9700f5

merge elghinn's branch (roster versioning) to trunk. Fixes #4661, #3190
author Yann Leboulanger <asterix@lagaule.org>
date Fri, 10 Jul 2009 15:05:01 +0200
parents a736d5846aab 4e609a89ac14
children b2d16bc55260
files configure.ac src/common/check_paths.py src/common/config.py src/common/connection.py src/common/connection_handlers.py src/common/defs.py src/common/optparser.py src/common/xmpp/client_nb.py src/common/xmpp/roster_nb.py src/config.py src/gajim.py src/roster_window.py
diffstat 10 files changed, 263 insertions(+), 17 deletions(-) [+]
line diff
     1.1 --- a/src/common/check_paths.py	Thu Jul 09 19:06:08 2009 +0200
     1.2 +++ b/src/common/check_paths.py	Fri Jul 10 15:05:01 2009 +0200
     1.3 @@ -96,6 +96,22 @@
     1.4  			jid_id INTEGER PRIMARY KEY UNIQUE,
     1.5  			time INTEGER
     1.6  		);
     1.7 +
     1.8 +		CREATE TABLE IF NOT EXISTS roster_entry(
     1.9 +			account_jid_id INTEGER,
    1.10 +			jid_id INTEGER,
    1.11 +			name TEXT,
    1.12 +			subscription INTEGER,
    1.13 +			ask BOOLEAN,
    1.14 +			PRIMARY KEY (account_jid_id, jid_id)
    1.15 +		);
    1.16 +
    1.17 +		CREATE TABLE IF NOT EXISTS roster_group(
    1.18 +			account_jid_id INTEGER,
    1.19 +			jid_id INTEGER,
    1.20 +			group_name TEXT,
    1.21 +			PRIMARY KEY (account_jid_id, jid_id, group_name)
    1.22 +		);
    1.23  		'''
    1.24  		)
    1.25  
     2.1 --- a/src/common/config.py	Thu Jul 09 19:06:08 2009 +0200
     2.2 +++ b/src/common/config.py	Fri Jul 10 15:05:01 2009 +0200
     2.3 @@ -336,6 +336,7 @@
     2.4  			'ignore_unknown_contacts': [ opt_bool, False ],
     2.5  			'send_os_info': [ opt_bool, True ],
     2.6  			'log_encrypted_sessions': [opt_bool, True, _('When negotiating an encrypted session, should Gajim assume you want your messages to be logged?')],
     2.7 +			'roster_version': [opt_str, ''],
     2.8  		}, {}),
     2.9  		'statusmsg': ({
    2.10  			'message': [ opt_str, '' ],
     3.1 --- a/src/common/connection.py	Thu Jul 09 19:06:08 2009 +0200
     3.2 +++ b/src/common/connection.py	Fri Jul 10 15:05:01 2009 +0200
     3.3 @@ -1970,6 +1970,11 @@
     3.4  
     3.5  		self.connection.SendAndCallForResponse(iq, _on_response)
     3.6  
     3.7 +	def load_roster_from_db(self):
     3.8 +		roster = gajim.logger.get_roster(gajim.get_jid_from_account(self.name))
     3.9 +		self.dispatch('ROSTER', roster)
    3.10 +
    3.11 +
    3.12  # END Connection
    3.13  
    3.14  # vim: se ts=3:
     4.1 --- a/src/common/connection_handlers.py	Thu Jul 09 19:06:08 2009 +0200
     4.2 +++ b/src/common/connection_handlers.py	Fri Jul 10 15:05:01 2009 +0200
     4.3 @@ -65,6 +65,7 @@
     4.4  VCARD_ARRIVED = 'vcard_arrived'
     4.5  AGENT_REMOVED = 'agent_removed'
     4.6  METACONTACTS_ARRIVED = 'metacontacts_arrived'
     4.7 +ROSTER_ARRIVED = 'roster_arrived'
     4.8  PRIVACY_ARRIVED = 'privacy_arrived'
     4.9  PEP_CONFIG = 'pep_config'
    4.10  HAS_IDLE = True
    4.11 @@ -1172,7 +1173,18 @@
    4.12  				if iq_obj.getErrorCode() not in ('403', '406', '404'):
    4.13  					self.private_storage_supported = False
    4.14  			# We can now continue connection by requesting the roster
    4.15 -			self.connection.initRoster()
    4.16 +			version = gajim.config.get_per('accounts', self.name,
    4.17 +				'roster_version')
    4.18 +			iq_id = self.connection.initRoster(version=version)
    4.19 +			self.awaiting_answers[iq_id] = (ROSTER_ARRIVED, )
    4.20 +		elif self.awaiting_answers[id_][0] == ROSTER_ARRIVED:
    4.21 +			if iq_obj.getType() == 'result':
    4.22 +				if not iq_obj.getTag('query'):
    4.23 +					account_jid = gajim.get_jid_from_account(self.name)
    4.24 +					roster_data = gajim.logger.get_roster(account_jid)
    4.25 +					roster = self.connection.getRoster(force=True)
    4.26 +					roster.setRaw(roster_data)
    4.27 +				self._getRoster()
    4.28  		elif self.awaiting_answers[id_][0] == PRIVACY_ARRIVED:
    4.29  			if iq_obj.getType() != 'error':
    4.30  				self.privacy_rules_supported = True
    4.31 @@ -1556,6 +1568,7 @@
    4.32  
    4.33  	def _rosterSetCB(self, con, iq_obj):
    4.34  		log.debug('rosterSetCB')
    4.35 +		version = iq_obj.getTagAttr('query', 'ver')
    4.36  		for item in iq_obj.getTag('query').getChildren():
    4.37  			try:
    4.38  				jid = helpers.parse_jid(item.getAttr('jid'))
    4.39 @@ -1569,6 +1582,12 @@
    4.40  			for group in item.getTags('group'):
    4.41  				groups.append(group.getData())
    4.42  			self.dispatch('ROSTER_INFO', (jid, name, sub, ask, groups))
    4.43 +			account_jid = gajim.get_jid_from_account(self.name)
    4.44 +			gajim.logger.add_or_update_contact(account_jid, jid, name, sub, ask,
    4.45 +				groups)
    4.46 +			if version:
    4.47 +				gajim.config.set_per('accounts', self.name, 'roster_version',
    4.48 +					version)
    4.49  		if not self.connection or self.connected < 2:
    4.50  			raise common.xmpp.NodeProcessed
    4.51  		reply = common.xmpp.Iq(typ='result', attrs={'id': iq_obj.getID()},
    4.52 @@ -2484,7 +2503,7 @@
    4.53  		self.connection.send(result)
    4.54  		raise common.xmpp.NodeProcessed
    4.55  
    4.56 -	def _getRosterCB(self, con, iq_obj):
    4.57 +	def _getRoster(self):
    4.58  		log.debug('getRosterCB')
    4.59  		if not self.connection:
    4.60  			return
    4.61 @@ -2507,6 +2526,8 @@
    4.62  				gajim.proxy65_manager.resolve(proxy, self.connection, our_jid)
    4.63  
    4.64  	def _on_roster_set(self, roster):
    4.65 +		roster_version = roster.version
    4.66 +		received_from_server = roster.received_from_server
    4.67  		raw_roster = roster.getRaw()
    4.68  		roster = {}
    4.69  		our_jid = helpers.parse_jid(gajim.get_jid_from_account(self.name))
    4.70 @@ -2545,7 +2566,16 @@
    4.71  						# we can't determine which iconset to use
    4.72  						self.discoverInfo(jid)
    4.73  
    4.74 -		self.dispatch('ROSTER', roster)
    4.75 +		gajim.logger.replace_roster(self.name, roster_version, roster)
    4.76 +		if received_from_server:
    4.77 +			for contact in gajim.contacts.iter_contacts(self.name):
    4.78 +				if not contact.is_groupchat() and contact.jid not in roster:
    4.79 +					self.dispatch('ROSTER_INFO', (self.name,
    4.80 +						(contact.jid, None, None, None, ())))
    4.81 +			for jid in roster:
    4.82 +				self.dispatch('ROSTER_INFO', (jid, roster[jid]['name'],
    4.83 +					roster[jid]['subscription'], roster[jid]['ask'],
    4.84 +					roster[jid]['groups']))
    4.85  
    4.86  	def _send_first_presence(self, signed = ''):
    4.87  		show = self.continue_connect_info[0]
    4.88 @@ -2689,8 +2719,6 @@
    4.89  			common.xmpp.NS_MUC_OWNER)
    4.90  		con.RegisterHandler('iq', self._MucAdminCB, 'result',
    4.91  			common.xmpp.NS_MUC_ADMIN)
    4.92 -		con.RegisterHandler('iq', self._getRosterCB, 'result',
    4.93 -			common.xmpp.NS_ROSTER)
    4.94  		con.RegisterHandler('iq', self._PrivateCB, 'result',
    4.95  			common.xmpp.NS_PRIVATE)
    4.96  		con.RegisterHandler('iq', self._HttpAuthCB, 'get',
     5.1 --- a/src/common/logger.py	Thu Jul 09 19:06:08 2009 +0200
     5.2 +++ b/src/common/logger.py	Fri Jul 10 15:05:01 2009 +0200
     5.3 @@ -92,6 +92,13 @@
     5.4  			self.TYPE_MRIM,
     5.5  		) = range(14)
     5.6  
     5.7 +		(
     5.8 +			self.SUBSCRIPTION_NONE,
     5.9 +			self.SUBSCRIPTION_TO,
    5.10 +			self.SUBSCRIPTION_FROM,
    5.11 +			self.SUBSCRIPTION_BOTH,
    5.12 +		) = range(4)
    5.13 +
    5.14  constants = Constants()
    5.15  
    5.16  class Logger:
    5.17 @@ -331,6 +338,28 @@
    5.18  		if type_id == constants.TYPE_MRIM:
    5.19  			return 'mrim'
    5.20  
    5.21 +	def convert_human_subscription_values_to_db_api_values(self, sub):
    5.22 +		'''converts from string style to constant ints for db'''
    5.23 +		if sub == 'none':
    5.24 +			return constants.SUBSCRIPTION_NONE
    5.25 +		if sub == 'to':
    5.26 +			return constants.SUBSCRIPTION_TO
    5.27 +		if sub == 'from':
    5.28 +			return constants.SUBSCRIPTION_FROM
    5.29 +		if sub == 'both':
    5.30 +			return constants.SUBSCRIPTION_BOTH
    5.31 +
    5.32 +	def convert_db_api_values_to_human_subscription_values(self, sub):
    5.33 +		'''converts from constant ints for db to string style'''
    5.34 +		if sub == constants.SUBSCRIPTION_NONE:
    5.35 +			return 'none'
    5.36 +		if sub == constants.SUBSCRIPTION_TO:
    5.37 +			return 'to'
    5.38 +		if sub == constants.SUBSCRIPTION_FROM:
    5.39 +			return 'from'
    5.40 +		if sub == constants.SUBSCRIPTION_BOTH:
    5.41 +			return 'both'
    5.42 +
    5.43  	def commit_to_db(self, values, write_unread = False):
    5.44  		sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message, subject) VALUES (?, ?, ?, ?, ?, ?, ?)'
    5.45  		try:
    5.46 @@ -799,4 +828,112 @@
    5.47  		except sqlite.OperationalError, e:
    5.48  			print >> sys.stderr, str(e)
    5.49  
    5.50 +	def replace_roster(self, account_name, roster_version, roster):
    5.51 +		''' Replace current roster in DB by a new one.
    5.52 +		accout_name is the name of the account to change
    5.53 +		roster_version is the version of the new roster
    5.54 +		roster is the new version '''
    5.55 +		gajim.config.set_per('accounts', account_name, 'roster_version', '')
    5.56 +		account_jid = gajim.get_jid_from_account(account_name)
    5.57 +		account_jid_id = self.get_jid_id(account_jid)
    5.58 +
    5.59 +		# Delete old roster
    5.60 +		sql = 'DELETE FROM roster_entry WHERE account_jid_id = %d' % (
    5.61 +			account_jid_id)
    5.62 +		sql = 'DELETE FROM roster_group WHERE account_jid_id = %d' % (
    5.63 +			account_jid_id)
    5.64 +
    5.65 +		# Fill roster tables with the new roster
    5.66 +		for jid in roster:
    5.67 +			self.add_or_update_contact(account_jid, jid, roster[jid]['name'],
    5.68 +				roster[jid]['subscription'], roster[jid]['ask'],
    5.69 +				roster[jid]['groups'])
    5.70 +		gajim.config.set_per('accounts', account_name, 'roster_version',
    5.71 +			roster_version)
    5.72 +
    5.73 +	def del_contact(self, account_jid, jid):
    5.74 +		''' Remove jid from account_jid roster. '''
    5.75 +		try:
    5.76 +			account_jid_id = self.get_jid_id(account_jid)
    5.77 +			jid_id = self.get_jid_id(jid)
    5.78 +		except exceptions.PysqliteOperationalError, e:
    5.79 +			raise exceptions.PysqliteOperationalError(str(e))
    5.80 +		sql = 'DELETE FROM roster_group WHERE account_jid_id=%d AND jid_id=%d' % (account_jid_id, jid_id)
    5.81 +		self.cur.execute(sql)
    5.82 +		sql = 'DELETE FROM roster_entry WHERE account_jid_id=%d AND jid_id=%d' % (account_jid_id, jid_id)
    5.83 +		self.simple_commit(sql)
    5.84 +
    5.85 +	def add_or_update_contact(self, account_jid, jid, name, sub, ask, groups):
    5.86 +		''' Add or update a contact from account_jid roster. '''
    5.87 +		if sub == 'remove':
    5.88 +			self.del_contact(account_jid, jid)
    5.89 +			return
    5.90 +
    5.91 +		try:
    5.92 +			account_jid_id = self.get_jid_id(account_jid)
    5.93 +			jid_id = self.get_jid_id(jid)
    5.94 +		except exceptions.PysqliteOperationalError, e:
    5.95 +			raise exceptions.PysqliteOperationalError(str(e))
    5.96 +
    5.97 +		# Update groups information
    5.98 +		# First we delete all previous groups information
    5.99 +		sql = 'DELETE FROM roster_group WHERE account_jid_id=%d AND jid_id=%d' % (account_jid_id, jid_id)
   5.100 +		self.cur.execute(sql)
   5.101 +		# Then we add all new groups information
   5.102 +		for group in groups:
   5.103 +			sql = 'INSERT INTO roster_group VALUES("%d", "%d", "%s")' % (
   5.104 +				account_jid_id, jid_id, group)
   5.105 +			self.cur.execute(sql)
   5.106 +
   5.107 +		if name is None:
   5.108 +			name = ''
   5.109 +
   5.110 +		sql = 'REPLACE INTO roster_entry VALUES("%d", "%d", "%s", "%s", "%d")'\
   5.111 +			% (account_jid_id, jid_id, name,
   5.112 +			self.convert_human_subscription_values_to_db_api_values(sub),
   5.113 +			bool(ask))
   5.114 +		self.simple_commit(sql)
   5.115 +
   5.116 +	def get_roster(self, account_jid):
   5.117 +		''' Return the accound_jid roster in NonBlockingRoster format. '''
   5.118 +		data = {}
   5.119 +		account_jid_id = self.get_jid_id(account_jid)
   5.120 +
   5.121 +		# First we fill data with roster_entry informations
   5.122 +		self.cur.execute('SELECT j.jid, re.jid_id, re.name, re.subscription, re.ask 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})
   5.123 +		for jid, jid_id, name, subscription, ask in self.cur:
   5.124 +			data[jid] = {}
   5.125 +			if name:
   5.126 +				data[jid]['name'] = name
   5.127 +			else:
   5.128 +				data[jid]['name'] = None
   5.129 +			data[jid]['subscription'] = self.convert_db_api_values_to_human_subscription_values(subscription)
   5.130 +			data[jid]['groups'] = []
   5.131 +			data[jid]['resources'] = {}
   5.132 +			if ask:
   5.133 +				data[jid]['ask'] = 'subscribe'
   5.134 +			else:
   5.135 +				data[jid]['ask'] = None
   5.136 +			data[jid]['id'] = jid_id
   5.137 +
   5.138 +		# Then we add group for roster entries
   5.139 +		for jid in data:
   5.140 +			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']})
   5.141 +			for (group_name,) in self.cur:
   5.142 +				data[jid]['groups'].append(group_name)
   5.143 +			del data[jid]['id']
   5.144 +
   5.145 +		return data
   5.146 +
   5.147 +	def remove_roster(self, account_jid):
   5.148 +		account_jid_id = self.get_jid_id(account_jid)
   5.149 +
   5.150 +		sql = 'DELETE FROM roster_group WHERE account_jid_id=%d' % (
   5.151 +			account_jid_id)
   5.152 +		self.cur.execute(sql)
   5.153 +
   5.154 +		sql = 'DELETE FROM roster_entry WHERE account_jid_id=%d' % (
   5.155 +			account_jid_id)
   5.156 +		self.simple_commit(sql)
   5.157 +
   5.158  # vim: se ts=3:
     6.1 --- a/src/common/optparser.py	Thu Jul 09 19:06:08 2009 +0200
     6.2 +++ b/src/common/optparser.py	Fri Jul 10 15:05:01 2009 +0200
     6.3 @@ -198,6 +198,8 @@
     6.4  			self.update_config_to_01214()
     6.5  		if old < [0, 12, 1, 5] and new >= [0, 12, 1, 5]:
     6.6  			self.update_config_to_01215()
     6.7 +		if old < [0, 12, 3, 1] and new >= [0, 12, 3, 1]:
     6.8 +			self.update_config_to_01231()
     6.9  
    6.10  		gajim.logger.init_vars()
    6.11  		gajim.config.set('version', new_version)
    6.12 @@ -671,4 +673,39 @@
    6.13  			gajim.config.set_per('soundevents', evt, 'path', path)
    6.14  		gajim.config.set('version', '0.12.1.5')
    6.15  
    6.16 +	def update_config_to_01231(self):
    6.17 +		back = os.getcwd()
    6.18 +		os.chdir(logger.LOG_DB_FOLDER)
    6.19 +		con = sqlite.connect(logger.LOG_DB_FILE)
    6.20 +		os.chdir(back)
    6.21 +		cur = con.cursor()
    6.22 +		try:
    6.23 +			cur.executescript(
    6.24 +				'''
    6.25 +				CREATE TABLE IF NOT EXISTS roster_entry(
    6.26 +					account_jid_id INTEGER,
    6.27 +					jid_id INTEGER,
    6.28 +					name TEXT,
    6.29 +					subscription INTEGER,
    6.30 +					ask BOOLEAN,
    6.31 +					PRIMARY KEY (account_jid_id, jid_id)
    6.32 +				);
    6.33 +
    6.34 +				CREATE TABLE IF NOT EXISTS roster_group(
    6.35 +					account_jid_id INTEGER,
    6.36 +					jid_id INTEGER,
    6.37 +   					group_name TEXT,
    6.38 +					PRIMARY KEY (account_jid_id, jid_id, group_name)
    6.39 +				);
    6.40 +				'''
    6.41 +			)
    6.42 +			con.commit()
    6.43 +		except sqlite.OperationalError:
    6.44 +			pass
    6.45 +		con.close()
    6.46 +		gajim.config.set('version', '0.12.3.1')
    6.47 +
    6.48 +
    6.49 +
    6.50 +
    6.51  # vim: se ts=3:
     7.1 --- a/src/common/xmpp/client_nb.py	Thu Jul 09 19:06:08 2009 +0200
     7.2 +++ b/src/common/xmpp/client_nb.py	Fri Jul 10 15:05:01 2009 +0200
     7.3 @@ -503,16 +503,16 @@
     7.4  		self.NonBlockingBind.NonBlockingBind(self._Resource, self._on_sasl_auth)
     7.5  		return True
     7.6  
     7.7 -	def initRoster(self):
     7.8 +	def initRoster(self, version=''):
     7.9  		''' Plug in the roster. '''
    7.10  		if not self.__dict__.has_key('NonBlockingRoster'):
    7.11 -			roster_nb.NonBlockingRoster.get_instance().PlugIn(self)
    7.12 +			return roster_nb.NonBlockingRoster.get_instance(version=version).PlugIn(self)
    7.13  
    7.14 -	def getRoster(self, on_ready=None):
    7.15 +	def getRoster(self, on_ready=None, force=False):
    7.16  		''' Return the Roster instance, previously plugging it in and
    7.17  			requesting roster from server if needed. '''
    7.18  		if self.__dict__.has_key('NonBlockingRoster'):
    7.19 -			return self.NonBlockingRoster.getRoster(on_ready)
    7.20 +			return self.NonBlockingRoster.getRoster(on_ready, force)
    7.21  		return None
    7.22  
    7.23  	def sendPresence(self, jid=None, typ=None, requestRoster=0):
     8.1 --- a/src/common/xmpp/roster_nb.py	Thu Jul 09 19:06:08 2009 +0200
     8.2 +++ b/src/common/xmpp/roster_nb.py	Fri Jul 10 15:05:01 2009 +0200
     8.3 @@ -36,20 +36,28 @@
     8.4  		You can also use mapping interface for access to the internal representation of
     8.5  		contacts in roster.
     8.6  		'''
     8.7 -	def __init__(self):
     8.8 +	def __init__(self, version=''):
     8.9  		''' Init internal variables. '''
    8.10  		PlugIn.__init__(self)
    8.11 +		self.version = version
    8.12  		self._data = {}
    8.13  		self.set=None
    8.14  		self._exported_methods=[self.getRoster]
    8.15 +		self.received_from_server = False
    8.16  
    8.17  	def Request(self,force=0):
    8.18  		''' Request roster from server if it were not yet requested
    8.19  			(or if the 'force' argument is set). '''
    8.20  		if self.set is None: self.set=0
    8.21  		elif not force: return
    8.22 -		self._owner.send(Iq('get',NS_ROSTER))
    8.23 +
    8.24 +		iq = Iq('get',NS_ROSTER)
    8.25 +		iq.setTagAttr('query', 'ver', self.version)
    8.26 +		id_ = self._owner.getAnID()
    8.27 +		iq.setID(id_)
    8.28 +		self._owner.send(iq)
    8.29  		log.info('Roster requested from server')
    8.30 +		return id_
    8.31  
    8.32  	def RosterIqHandler(self,dis,stanza):
    8.33  		''' Subscription tracker. Used internally for setting items state in
    8.34 @@ -60,6 +68,10 @@
    8.35  			return
    8.36  		query = stanza.getTag('query')
    8.37  		if query:
    8.38 +			self.received_from_server = True
    8.39 +			self.version = stanza.getTagAttr('query', 'ver')
    8.40 +			if self.version is None:
    8.41 +				self.version = ''
    8.42  			for item in query.getTags('item'):
    8.43  				jid=item.getAttr('jid')
    8.44  				if item.getAttr('subscription')=='remove':
    8.45 @@ -188,6 +200,11 @@
    8.46  	def getRaw(self):
    8.47  		'''Returns the internal data representation of the roster.'''
    8.48  		return self._data
    8.49 +	def setRaw(self, data):
    8.50 +		'''Returns the internal data representation of the roster.'''
    8.51 +		self._data = data
    8.52 +		self._data[self._owner.User+'@'+self._owner.Server]={'resources':{},'name':None,'ask':None,'subscription':None,'groups':None,}
    8.53 +		self.set=1
    8.54  	# copypasted methods for roster.py from constructor to here
    8.55  
    8.56  
    8.57 @@ -199,7 +216,7 @@
    8.58  		self._owner.RegisterHandler('iq', self.RosterIqHandler, 'set', NS_ROSTER)
    8.59  		self._owner.RegisterHandler('presence', self.PresenceHandler)
    8.60  		if request:
    8.61 -			self.Request()
    8.62 +			return self.Request()
    8.63  
    8.64  	def _on_roster_set(self, data):
    8.65  		if data:
    8.66 @@ -212,16 +229,18 @@
    8.67  			self.on_ready = None
    8.68  		return True
    8.69  
    8.70 -	def getRoster(self, on_ready=None):
    8.71 +	def getRoster(self, on_ready=None, force=False):
    8.72  		''' Requests roster from server if neccessary and returns self. '''
    8.73 +		return_self = True
    8.74  		if not self.set:
    8.75  			self.on_ready = on_ready
    8.76  			self._owner.onreceive(self._on_roster_set)
    8.77 -			return
    8.78 -		if on_ready:
    8.79 +			return_self = False
    8.80 +		elif on_ready:
    8.81  			on_ready(self)
    8.82 -			on_ready = None
    8.83 -		else:
    8.84 +			return_self = False
    8.85 +		if return_self or force:
    8.86  			return self
    8.87 +		return None
    8.88  
    8.89  # vim: se ts=3:
     9.1 --- a/src/config.py	Thu Jul 09 19:06:08 2009 +0200
     9.2 +++ b/src/config.py	Fri Jul 10 15:05:01 2009 +0200
     9.3 @@ -2616,6 +2616,7 @@
     9.4  		gajim.interface.roster.close_all(self.account, force = True)
     9.5  		gajim.connections[self.account].disconnect(on_purpose = True)
     9.6  		del gajim.connections[self.account]
     9.7 +		gajim.logger.remove_roster(gajim.get_jid_from_account(self.account))
     9.8  		gajim.config.del_per('accounts', self.account)
     9.9  		gajim.interface.save_config()
    9.10  		del gajim.interface.instances[self.account]
    10.1 --- a/src/gajim.py	Thu Jul 09 19:06:08 2009 +0200
    10.2 +++ b/src/gajim.py	Fri Jul 10 15:05:01 2009 +0200
    10.3 @@ -3435,6 +3435,8 @@
    10.4  		gtk.window_set_default_icon(pix)
    10.5  
    10.6  		self.roster = roster_window.RosterWindow()
    10.7 +		for account in gajim.connections:
    10.8 +			gajim.connections[account].load_roster_from_db()
    10.9  
   10.10  		self.init_emoticons()
   10.11  		self.make_regexps()