handle correctly vcards in groupchats : ask them to real jid if we know it, but considere it arrive from fake jid. Fixes #3172, #3173
This commit is contained in:
		
							parent
							
								
									241a0f3fda
								
							
						
					
					
						commit
						a45a14546a
					
				
					 6 changed files with 124 additions and 89 deletions
				
			
		|  | @ -1674,24 +1674,34 @@ class ChatControl(ChatControlBase): | |||
| 		if not gajim.config.get('show_avatar_in_chat'): | ||||
| 			return | ||||
| 
 | ||||
| 		jid = self.contact.jid | ||||
| 		jid_with_resource = jid | ||||
| 		if resource: | ||||
| 			jid_with_resource += '/' + resource | ||||
| 		is_fake = False | ||||
| 		if self.TYPE_ID == message_control.TYPE_PM: | ||||
| 			is_fake = True | ||||
| 			jid_with_resource = self.contact.jid # fake jid | ||||
| 		else: | ||||
| 			jid_with_resource = self.contact.jid | ||||
| 			if resource: | ||||
| 				jid_with_resource += '/' + resource | ||||
| 
 | ||||
| 		# we assume contact has no avatar | ||||
| 		scaled_pixbuf = None | ||||
| 
 | ||||
| 		pixbuf = None | ||||
| 		is_fake = False | ||||
| 		if gajim.contacts.is_pm_from_jid(self.account, jid): | ||||
| 			is_fake = True | ||||
| 		pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(jid_with_resource, | ||||
| 			is_fake) | ||||
| 		if pixbuf == 'ask': | ||||
| 			# we don't have the vcard | ||||
| 			gajim.connections[self.account].request_vcard(jid_with_resource, | ||||
| 				is_fake) | ||||
| 			if self.TYPE_ID == message_control.TYPE_PM: | ||||
| 				if self.gc_contact.jid: | ||||
| 					# We know the real jid of this contact | ||||
| 					real_jid = self.gc_contact.jid | ||||
| 					if self.gc_contact.resource: | ||||
| 						real_jid += '/' + self.gc_contact.resource | ||||
| 				else: | ||||
| 					real_jid = jid_with_resource | ||||
| 				gajim.connections[self.account].request_vcard(real_jid, | ||||
| 					jid_with_resource) | ||||
| 			else: | ||||
| 				gajim.connections[self.account].request_vcard(jid_with_resource) | ||||
| 			return | ||||
| 		if pixbuf is not None: | ||||
| 			scaled_pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'chat') | ||||
|  |  | |||
|  | @ -811,6 +811,7 @@ class ConnectionVcard: | |||
| 		self.vcard_sha = None | ||||
| 		self.vcard_shas = {} # sha of contacts | ||||
| 		self.room_jids = [] # list of gc jids so that vcard are saved in a folder | ||||
| 		self.groupchat_jids = {} # {ID : groupchat_jid} | ||||
| 		 | ||||
| 	def add_sha(self, p, send_caps = True): | ||||
| 		c = p.setTag('x', namespace = common.xmpp.NS_VCARD_UPDATE) | ||||
|  | @ -906,9 +907,10 @@ class ConnectionVcard: | |||
| 		vcard['resource'] = gajim.get_resource_from_jid(fjid) | ||||
| 		return vcard | ||||
| 
 | ||||
| 	def request_vcard(self, jid = None, is_fake_jid = False): | ||||
| 		'''request the VCARD. If is_fake_jid is True, it means we request a vcard | ||||
| 		to a fake jid, like in private messages in groupchat''' | ||||
| 	def request_vcard(self, jid = None, groupchat_jid = None): | ||||
| 		'''request the VCARD. If groupchat_jid is not nul, it means we request a vcard | ||||
| 		to a fake jid, like in private messages in groupchat. jid can be the | ||||
| 		real jid of the contact, but we want to consider it comes from a fake jid''' | ||||
| 		if not self.connection: | ||||
| 			return | ||||
| 		iq = common.xmpp.Iq(typ = 'get') | ||||
|  | @ -921,13 +923,13 @@ class ConnectionVcard: | |||
| 		j = jid | ||||
| 		if not j: | ||||
| 			j = gajim.get_jid_from_account(self.name) | ||||
| 		self.awaiting_answers[id] = (VCARD_ARRIVED, j) | ||||
| 		if is_fake_jid: | ||||
| 			room_jid, nick = gajim.get_room_and_nick_from_fjid(jid) | ||||
| 		self.awaiting_answers[id] = (VCARD_ARRIVED, j, groupchat_jid) | ||||
| 		if groupchat_jid: | ||||
| 			room_jid, nick = gajim.get_room_and_nick_from_fjid(groupchat_jid) | ||||
| 			if not room_jid in self.room_jids: | ||||
| 				self.room_jids.append(room_jid) | ||||
| 			self.groupchat_jids[id] = groupchat_jid | ||||
| 		self.connection.send(iq) | ||||
| 			#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...}) | ||||
| 
 | ||||
| 	def send_vcard(self, vcard): | ||||
| 		if not self.connection: | ||||
|  | @ -1010,17 +1012,22 @@ class ConnectionVcard: | |||
| 			# If vcard is empty, we send to the interface an empty vcard so that | ||||
| 			# it knows it arrived | ||||
| 			jid = self.awaiting_answers[id][1] | ||||
| 			groupchat_jid = self.awaiting_answers[id][2] | ||||
| 			frm = jid | ||||
| 			if groupchat_jid: | ||||
| 				# We do as if it comes from the fake_jid | ||||
| 				frm = groupchat_jid | ||||
| 			our_jid = gajim.get_jid_from_account(self.name) | ||||
| 			if iq_obj.getType() == 'error' and jid == our_jid: | ||||
| 				# our server doesn't support vcard | ||||
| 				self.vcard_supported = False | ||||
| 			if not iq_obj.getTag('vCard') or iq_obj.getType() == 'error': | ||||
| 				if jid and jid != our_jid: | ||||
| 				if frm and frm != our_jid: | ||||
| 					# Write an empty file | ||||
| 					self.save_vcard_to_hd(jid, '') | ||||
| 					self.dispatch('VCARD', {'jid': jid}) | ||||
| 				elif jid == our_jid: | ||||
| 					self.dispatch('MYVCARD', {'jid': jid}) | ||||
| 					self.save_vcard_to_hd(frm, '') | ||||
| 					self.dispatch('VCARD', {'jid': frm}) | ||||
| 				elif frm == our_jid: | ||||
| 					self.dispatch('MYVCARD', {'jid': frm}) | ||||
| 		elif self.awaiting_answers[id][0] == AGENT_REMOVED: | ||||
| 			jid = self.awaiting_answers[id][1] | ||||
| 			self.dispatch('AGENT_REMOVED', jid) | ||||
|  | @ -1064,10 +1071,15 @@ class ConnectionVcard: | |||
| 			return | ||||
| 		if not vc.getTag('vCard').getNamespace() == common.xmpp.NS_VCARD: | ||||
| 			return | ||||
| 		id = vc.getID() | ||||
| 		frm_iq = vc.getFrom() | ||||
| 		our_jid = gajim.get_jid_from_account(self.name) | ||||
| 		resource = '' | ||||
| 		if frm_iq: | ||||
| 		if id in self.groupchat_jids: | ||||
| 			who = self.groupchat_jids[id] | ||||
| 			frm, resource = gajim.get_room_and_nick_from_fjid(who) | ||||
| 			del self.groupchat_jids[id] | ||||
| 		elif frm_iq: | ||||
| 			who = helpers.get_full_jid_from_iq(vc) | ||||
| 			frm, resource = gajim.get_room_and_nick_from_fjid(who) | ||||
| 		else: | ||||
|  | @ -1139,6 +1151,7 @@ class ConnectionVcard: | |||
| 			p = self.add_sha(p) | ||||
| 			self.connection.send(p) | ||||
| 		else: | ||||
| 			#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...}) | ||||
| 			self.dispatch('VCARD', vcard) | ||||
| 
 | ||||
| class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub): | ||||
|  | @ -1655,7 +1668,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, | |||
| 			if not ptype or ptype == 'unavailable': | ||||
| 				if gajim.config.get('log_contact_status_changes') and self.name\ | ||||
| 				not in no_log_for and jid_stripped not in no_log_for: | ||||
| 					gc_c = gajim.contacts.get_gc_contact(self.name, jid_stripped, resource) | ||||
| 					gc_c = gajim.contacts.get_gc_contact(self.name, jid_stripped, | ||||
| 						resource) | ||||
| 					st = status or '' | ||||
| 					if gc_c: | ||||
| 						jid = gc_c.jid | ||||
|  | @ -1672,25 +1686,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, | |||
| 						gajim.interface.remove_avatar_files(jid_stripped, puny_nick) | ||||
| 					# if it's a gc presence, don't ask vcard here. We may ask it to | ||||
| 					# real jid in gui part. | ||||
| 					if self.vcard_shas.has_key(who) and not is_gc: | ||||
| 					# Verify sha cached in mem | ||||
| 						if avatar_sha != self.vcard_shas[who]: | ||||
| 							# avatar has been updated | ||||
| 							self.request_vcard(who, True) | ||||
| 					elif not is_gc: # Verify sha cached in hdd | ||||
| 						cached_vcard = self.get_cached_vcard(who, True) | ||||
| 						if cached_vcard and cached_vcard.has_key('PHOTO') and \ | ||||
| 						cached_vcard['PHOTO'].has_key('SHA'): | ||||
| 							cached_sha = cached_vcard['PHOTO']['SHA'] | ||||
| 						else: | ||||
| 							cached_sha = '' | ||||
| 						if cached_sha != avatar_sha: | ||||
| 							# avatar has been updated | ||||
| 							# sha in mem will be updated later | ||||
| 							self.request_vcard(who, True) | ||||
| 						else: | ||||
| 							# save sha in mem NOW | ||||
| 							self.vcard_shas[who] = avatar_sha | ||||
| 				if ns_muc_user_x: | ||||
| 					# Room has been destroyed. see | ||||
| 					# http://www.xmpp.org/extensions/xep-0045.html#destroyroom | ||||
|  | @ -1708,7 +1703,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, | |||
| 					statusCode = prs.getStatusCode() | ||||
| 				self.dispatch('GC_NOTIFY', (jid_stripped, show, status, resource, | ||||
| 					prs.getRole(), prs.getAffiliation(), prs.getJid(), | ||||
| 					reason, prs.getActor(), statusCode, prs.getNewNick())) | ||||
| 					reason, prs.getActor(), statusCode, prs.getNewNick(), | ||||
| 					avatar_sha)) | ||||
| 			return | ||||
| 
 | ||||
| 		if ptype == 'subscribe': | ||||
|  |  | |||
|  | @ -814,8 +814,7 @@ class Interface: | |||
| 						show = 'offline' | ||||
| 					gc_c = gajim.contacts.create_gc_contact(room_jid = jid, | ||||
| 						name = nick, show = show) | ||||
| 					c = gajim.contacts.contact_from_gc_contact(gc_c) | ||||
| 					self.roster.new_chat(c, account, private_chat = True) | ||||
| 					self.roster.new_private_chat(gc_c, account) | ||||
| 				ctrl = self.msg_win_mgr.get_control(full_jid_with_resource, account) | ||||
| 				ctrl.print_conversation('Error %s: %s' % (array[1], array[2]), | ||||
| 							'status') | ||||
|  | @ -1053,7 +1052,7 @@ class Interface: | |||
| 
 | ||||
| 	def handle_event_gc_notify(self, account, array): | ||||
| 		#'GC_NOTIFY' (account, (room_jid, show, status, nick, | ||||
| 		# role, affiliation, jid, reason, actor, statusCode, newNick)) | ||||
| 		# role, affiliation, jid, reason, actor, statusCode, newNick, avatar_sha)) | ||||
| 		nick = array[3] | ||||
| 		if not nick: | ||||
| 			return | ||||
|  | @ -1074,7 +1073,7 @@ class Interface: | |||
| 			return | ||||
| 		if control: | ||||
| 			control.chg_contact_status(nick, show, status, array[4], array[5], | ||||
| 				array[6], array[7], array[8], array[9], array[10]) | ||||
| 				array[6], array[7], array[8], array[9], array[10], array[11]) | ||||
| 		if control and not control.parent_win: | ||||
| 			gajim.interface.roster.draw_contact(room_jid, account) | ||||
| 
 | ||||
|  |  | |||
|  | @ -97,10 +97,11 @@ def tree_cell_data_func(column, renderer, model, iter, tv=None): | |||
| class PrivateChatControl(ChatControl): | ||||
| 	TYPE_ID = message_control.TYPE_PM | ||||
| 
 | ||||
| 	def __init__(self, parent_win, contact, acct): | ||||
| 	def __init__(self, parent_win, gc_contact, contact, acct): | ||||
| 		room_jid = contact.jid.split('/')[0] | ||||
| 		room_ctrl = gajim.interface.msg_win_mgr.get_control(room_jid, acct) | ||||
| 		self.room_name = room_ctrl.name | ||||
| 		self.gc_contact = gc_contact | ||||
| 		ChatControl.__init__(self, parent_win, contact, acct) | ||||
| 		self.TYPE_ID = 'pm' | ||||
| 
 | ||||
|  | @ -852,7 +853,7 @@ class GroupchatControl(ChatControlBase): | |||
| 		model[iter][C_AVATAR] = scaled_pixbuf | ||||
| 
 | ||||
| 	def chg_contact_status(self, nick, show, status, role, affiliation, jid, | ||||
| 	reason, actor, statusCode, new_nick, tim = None): | ||||
| 	reason, actor, statusCode, new_nick, avatar_sha, tim = None): | ||||
| 		'''When an occupant changes his or her status''' | ||||
| 		if show == 'invisible': | ||||
| 			return | ||||
|  | @ -861,7 +862,7 @@ class GroupchatControl(ChatControlBase): | |||
| 			role = 'visitor' | ||||
| 		if not affiliation: | ||||
| 			affiliation = 'none' | ||||
| 
 | ||||
| 		fake_jid = self.room_jid + '/' + nick | ||||
| 		newly_created = False | ||||
| 		if show in ('offline', 'error'): | ||||
| 			if statusCode == '307': | ||||
|  | @ -924,8 +925,7 @@ class GroupchatControl(ChatControlBase): | |||
| 			elif statusCode == 'destroyed': # Room has been destroyed | ||||
| 				self.print_conversation(reason, 'info', tim) | ||||
| 
 | ||||
| 			if len(gajim.events.get_events(self.account, | ||||
| 			self.room_jid + '/' + nick)) == 0: | ||||
| 			if len(gajim.events.get_events(self.account, fake_jid)) == 0: | ||||
| 				self.remove_contact(nick) | ||||
| 			else: | ||||
| 				c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) | ||||
|  | @ -948,20 +948,48 @@ class GroupchatControl(ChatControlBase): | |||
| 				if statusCode == '201': # We just created the room | ||||
| 					gajim.connections[self.account].request_gc_config(self.room_jid) | ||||
| 			else: | ||||
| 				gc_c = gajim.contacts.get_gc_contact(self.account, self.room_jid, | ||||
| 					nick) | ||||
| 				# Re-get vcard if avatar has changed | ||||
| 				# We do that here because we may request it to the real JID if we | ||||
| 				# knows it. connections.py doesn't know it. | ||||
| 				con = gajim.connections[self.account] | ||||
| 				if gc_c.jid: | ||||
| 					real_jid = gc_c.jid | ||||
| 					if gc_c.resource: | ||||
| 						real_jid += '/' + gc_c.resource | ||||
| 				else: | ||||
| 					real_jid = fake_jid | ||||
| 				if con.vcard_shas.has_key(fake_jid): | ||||
| 					if avatar_sha != con.vcard_shas[fake_jid]: | ||||
| 						con.request_vcard(real_jid, fake_jid) | ||||
| 				else: | ||||
| 					cached_vcard = con.get_cached_vcard(fake_jid, True) | ||||
| 					if cached_vcard and cached_vcard.has_key('PHOTO') and \ | ||||
| 					cached_vcard['PHOTO'].has_key('SHA'): | ||||
| 						cached_sha = cached_vcard['PHOTO']['SHA'] | ||||
| 					else: | ||||
| 						cached_sha = '' | ||||
| 					if cached_sha != avatar_sha: | ||||
| 						# avatar has been updated | ||||
| 						# sha in mem will be updated later | ||||
| 						con.request_vcard(real_jid, fake_jid) | ||||
| 					else: | ||||
| 						# save sha in mem NOW | ||||
| 						self.vcard_shas[fake_jid] = avatar_sha | ||||
| 
 | ||||
| 				actual_role = self.get_role(nick) | ||||
| 				if role != actual_role: | ||||
| 					self.remove_contact(nick) | ||||
| 					self.add_contact_to_roster(nick, show, role, | ||||
| 						affiliation, status, jid) | ||||
| 				else: | ||||
| 					c = gajim.contacts.get_gc_contact(self.account, self.room_jid, | ||||
| 						nick) | ||||
| 					if c.show == show and c.status == status and \ | ||||
| 						c.affiliation == affiliation: #no change | ||||
| 					if gc_c.show == show and gc_c.status == status and \ | ||||
| 						gc_c.affiliation == affiliation: # no change | ||||
| 						return | ||||
| 					c.show = show | ||||
| 					c.affiliation = affiliation | ||||
| 					c.status = status | ||||
| 					gc_c.show = show | ||||
| 					gc_c.affiliation = affiliation | ||||
| 					gc_c.status = status | ||||
| 					self.draw_contact(nick) | ||||
| 		if self.parent_win: | ||||
| 			self.parent_win.redraw_tab(self) | ||||
|  | @ -1028,21 +1056,16 @@ class GroupchatControl(ChatControlBase): | |||
| 		server = gajim.get_server_from_jid(self.room_jid) | ||||
| 		if gajim.config.get('ask_avatars_on_startup') and \ | ||||
| 		not server.startswith('irc'): | ||||
| 			if j: | ||||
| 				fjid = j | ||||
| 				if resource: | ||||
| 					fjid += '/' + resource | ||||
| 			else: | ||||
| 				fjid = self.room_jid + '/' + nick | ||||
| 			if j: | ||||
| 				pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(fjid) | ||||
| 			else: | ||||
| 				pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(fjid, True) | ||||
| 			fake_jid = self.room_jid + '/' + nick | ||||
| 			pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(fake_jid, True) | ||||
| 			if pixbuf == 'ask': | ||||
| 				if j: | ||||
| 					gajim.connections[self.account].request_vcard(fjid) | ||||
| 					fjid = j | ||||
| 					if resource: | ||||
| 						fjid += '/' + resource | ||||
| 					gajim.connections[self.account].request_vcard(fjid, fake_jid) | ||||
| 				else: | ||||
| 					gajim.connections[self.account].request_vcard(fjid, True) | ||||
| 					gajim.connections[self.account].request_vcard(fake_jid, fake_jid) | ||||
| 		if nick == self.nick: # we became online | ||||
| 			self.got_connected() | ||||
| 		self.list_treeview.expand_row((model.get_path(role_iter)), False) | ||||
|  | @ -1789,12 +1812,11 @@ class GroupchatControl(ChatControlBase): | |||
| 
 | ||||
| 	def _start_private_message(self, nick): | ||||
| 		gc_c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) | ||||
| 		c = gajim.contacts.contact_from_gc_contact(gc_c) | ||||
| 		nick_jid = c.jid | ||||
| 		nick_jid = gc_c.get_full_jid() | ||||
| 
 | ||||
| 		win = gajim.interface.msg_win_mgr.get_window(nick_jid, self.account) | ||||
| 		if not win: | ||||
| 			gajim.interface.roster.new_chat(c, self.account, private_chat = True) | ||||
| 			gajim.interface.roster.new_private_chat(gc_c, self.account) | ||||
| 			win = gajim.interface.msg_win_mgr.get_window(nick_jid, self.account) | ||||
| 		win.set_active_tab(nick_jid, self.account) | ||||
| 		win.window.present() | ||||
|  | @ -2008,9 +2030,6 @@ class GroupchatControl(ChatControlBase): | |||
| 		'''Call vcard_information_window class to display user's information''' | ||||
| 		c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick) | ||||
| 		c2 = gajim.contacts.contact_from_gc_contact(c) | ||||
| 		if c.jid: | ||||
| 			c2.jid = c.jid | ||||
| 			c2.resource = c.resource | ||||
| 		if gajim.interface.instances[self.account]['infos'].has_key(c2.jid): | ||||
| 			gajim.interface.instances[self.account]['infos'][c2.jid].window.\ | ||||
| 				present() | ||||
|  |  | |||
|  | @ -3464,12 +3464,23 @@ class RosterWindow: | |||
| 			self.actions_menu_needs_rebuild = True | ||||
| 		self.update_status_combobox() | ||||
| 
 | ||||
| 	def new_chat(self, contact, account, private_chat = False, resource = None): | ||||
| 	def new_private_chat(self, gc_contact, account): | ||||
| 		contact = gajim.contacts.contact_from_gc_contact(gc_contact) | ||||
| 		type_ = message_control.TYPE_PM | ||||
| 		fjid = gc_contact.room_jid + '/' + gc_contact.name | ||||
| 		mw = gajim.interface.msg_win_mgr.get_window(fjid, account) | ||||
| 		if not mw: | ||||
| 			mw = gajim.interface.msg_win_mgr.create_window(contact, account, type_) | ||||
| 
 | ||||
| 		chat_control = PrivateChatControl(mw, gc_contact, contact, account) | ||||
| 		mw.new_tab(chat_control) | ||||
| 		if len(gajim.events.get_events(account, fjid)): | ||||
| 			# We call this here to avoid race conditions with widget validation | ||||
| 			chat_control.read_queue() | ||||
| 
 | ||||
| 	def new_chat(self, contact, account, resource = None): | ||||
| 		# Get target window, create a control, and associate it with the window | ||||
| 		if not private_chat: | ||||
| 			type_ = message_control.TYPE_CHAT | ||||
| 		else: | ||||
| 			type_ = message_control.TYPE_PM | ||||
| 		type_ = message_control.TYPE_CHAT | ||||
| 
 | ||||
| 		fjid = contact.jid | ||||
| 		if resource: | ||||
|  | @ -3478,10 +3489,7 @@ class RosterWindow: | |||
| 		if not mw: | ||||
| 			mw = gajim.interface.msg_win_mgr.create_window(contact, account, type_) | ||||
| 
 | ||||
| 		if not private_chat: | ||||
| 			chat_control = ChatControl(mw, contact, account, resource) | ||||
| 		else: | ||||
| 			chat_control = PrivateChatControl(mw, contact, account) | ||||
| 		chat_control = ChatControl(mw, contact, account, resource) | ||||
| 
 | ||||
| 		mw.new_tab(chat_control) | ||||
| 
 | ||||
|  |  | |||
|  | @ -453,8 +453,11 @@ class VcardWindow: | |||
| 
 | ||||
| 		self.fill_status_label() | ||||
| 
 | ||||
| 		gajim.connections[self.account].request_vcard(self.contact.jid, | ||||
| 			(self.gc_contact is not None and not self.gc_contact.jid)) | ||||
| 		if self.gc_contact: | ||||
| 			gajim.connections[self.account].request_vcard(self.contact.jid, | ||||
| 				self.gc_contact.get_full_jid()) | ||||
| 		else: | ||||
| 			gajim.connections[self.account].request_vcard(self.contact.jid) | ||||
| 
 | ||||
| 	def on_close_button_clicked(self, widget): | ||||
| 		self.window.destroy() | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue