massive everything-breaking overhaul for per-session windows
This commit is contained in:
		
							parent
							
								
									d696f79c55
								
							
						
					
					
						commit
						17c5bf5e52
					
				
					 13 changed files with 319 additions and 188 deletions
				
			
		|  | @ -577,7 +577,7 @@ class ChatControlBase(MessageControl): | ||||||
| 				type_ = 'printed_' + self.type_id | 				type_ = 'printed_' + self.type_id | ||||||
| 				event = 'message_received' | 				event = 'message_received' | ||||||
| 				show_in_roster = notify.get_show_in_roster(event, | 				show_in_roster = notify.get_show_in_roster(event, | ||||||
| 					self.account, self.contact) | 					self.account, self.contact, self.session) | ||||||
| 				show_in_systray = notify.get_show_in_systray(event, | 				show_in_systray = notify.get_show_in_systray(event, | ||||||
| 					self.account, self.contact) | 					self.account, self.contact) | ||||||
| 				if gc_message: | 				if gc_message: | ||||||
|  | @ -606,7 +606,7 @@ class ChatControlBase(MessageControl): | ||||||
| 		not self.parent_win.is_active() or not end) and \ | 		not self.parent_win.is_active() or not end) and \ | ||||||
| 		kind in ('incoming', 'incoming_queue'): | 		kind in ('incoming', 'incoming_queue'): | ||||||
| 			self.parent_win.redraw_tab(self) | 			self.parent_win.redraw_tab(self) | ||||||
| 			ctrl = gajim.interface.msg_win_mgr.get_control(full_jid, self.account) | 			ctrl = gajim.interface.msg_win_mgr.get_control(full_jid, self.account, self.session.thread_id) | ||||||
| 			if not self.parent_win.is_active(): | 			if not self.parent_win.is_active(): | ||||||
| 				self.parent_win.show_title(True, ctrl) # Enabled Urgent hint | 				self.parent_win.show_title(True, ctrl) # Enabled Urgent hint | ||||||
| 			else: | 			else: | ||||||
|  | @ -905,10 +905,10 @@ class ChatControl(ChatControlBase): | ||||||
| 	old_msg_kind = None # last kind of the printed message | 	old_msg_kind = None # last kind of the printed message | ||||||
| 	CHAT_CMDS = ['clear', 'compact', 'help', 'ping'] | 	CHAT_CMDS = ['clear', 'compact', 'help', 'ping'] | ||||||
| 	 | 	 | ||||||
| 	def __init__(self, parent_win, contact, acct, resource = None): | 	def __init__(self, parent_win, contact, acct, session, resource = None): | ||||||
| 		ChatControlBase.__init__(self, self.TYPE_ID, parent_win, | 		ChatControlBase.__init__(self, self.TYPE_ID, parent_win, | ||||||
| 			'chat_child_vbox', contact, acct, resource) | 			'chat_child_vbox', contact, acct, resource) | ||||||
| 			 | 
 | ||||||
| 		# for muc use: | 		# for muc use: | ||||||
| 		# widget = self.xml.get_widget('muc_window_actions_button') | 		# widget = self.xml.get_widget('muc_window_actions_button') | ||||||
| 		widget = self.xml.get_widget('message_window_actions_button') | 		widget = self.xml.get_widget('message_window_actions_button') | ||||||
|  | @ -935,7 +935,7 @@ class ChatControl(ChatControlBase): | ||||||
| 		# it is on enter-notify and leave-notify so no need to be per jid | 		# it is on enter-notify and leave-notify so no need to be per jid | ||||||
| 		self.show_bigger_avatar_timeout_id = None | 		self.show_bigger_avatar_timeout_id = None | ||||||
| 		self.bigger_avatar_window = None | 		self.bigger_avatar_window = None | ||||||
| 		self.show_avatar(self.contact.resource)			 | 		self.show_avatar(self.contact.resource)	 | ||||||
| 
 | 
 | ||||||
| 		# chatstate timers and state | 		# chatstate timers and state | ||||||
| 		self.reset_kbd_mouse_timeout_vars() | 		self.reset_kbd_mouse_timeout_vars() | ||||||
|  | @ -949,7 +949,7 @@ class ChatControl(ChatControlBase): | ||||||
| 		id = message_tv_buffer.connect('changed', | 		id = message_tv_buffer.connect('changed', | ||||||
| 			self._on_message_tv_buffer_changed) | 			self._on_message_tv_buffer_changed) | ||||||
| 		self.handlers[id] = message_tv_buffer | 		self.handlers[id] = message_tv_buffer | ||||||
| 		 | 
 | ||||||
| 		widget = self.xml.get_widget('avatar_eventbox') | 		widget = self.xml.get_widget('avatar_eventbox') | ||||||
| 		id = widget.connect('enter-notify-event', | 		id = widget.connect('enter-notify-event', | ||||||
| 			self.on_avatar_eventbox_enter_notify_event) | 			self.on_avatar_eventbox_enter_notify_event) | ||||||
|  | @ -969,7 +969,9 @@ class ChatControl(ChatControlBase): | ||||||
| 
 | 
 | ||||||
| 		if self.contact.jid in gajim.encrypted_chats[self.account]: | 		if self.contact.jid in gajim.encrypted_chats[self.account]: | ||||||
| 			self.xml.get_widget('gpg_togglebutton').set_active(True) | 			self.xml.get_widget('gpg_togglebutton').set_active(True) | ||||||
| 		 | 
 | ||||||
|  | 		self.session = session | ||||||
|  | 
 | ||||||
| 		self.status_tooltip = gtk.Tooltips() | 		self.status_tooltip = gtk.Tooltips() | ||||||
| 		self.update_ui() | 		self.update_ui() | ||||||
| 		# restore previous conversation | 		# restore previous conversation | ||||||
|  | @ -1797,7 +1799,7 @@ class ChatControl(ChatControlBase): | ||||||
| 		# Is it a pm ? | 		# Is it a pm ? | ||||||
| 		is_pm = False | 		is_pm = False | ||||||
| 		room_jid, nick = gajim.get_room_and_nick_from_fjid(jid) | 		room_jid, nick = gajim.get_room_and_nick_from_fjid(jid) | ||||||
| 		control = gajim.interface.msg_win_mgr.get_control(room_jid, self.account) | 		control = gajim.interface.msg_win_mgr.get_control(room_jid, self.account, self.session.thread_id) | ||||||
| 		if control and control.type_id == message_control.TYPE_GC: | 		if control and control.type_id == message_control.TYPE_GC: | ||||||
| 			is_pm = True | 			is_pm = True | ||||||
| 		# list of message ids which should be marked as read | 		# list of message ids which should be marked as read | ||||||
|  | @ -1815,9 +1817,6 @@ class ChatControl(ChatControlBase): | ||||||
| 				encrypted = data[4], subject = data[1], xhtml = data[7]) | 				encrypted = data[4], subject = data[1], xhtml = data[7]) | ||||||
| 			if len(data) > 6 and isinstance(data[6], int): | 			if len(data) > 6 and isinstance(data[6], int): | ||||||
| 				message_ids.append(data[6]) | 				message_ids.append(data[6]) | ||||||
| 
 |  | ||||||
| 			if len(data) > 8: |  | ||||||
| 				self.set_thread_id(data[8]) |  | ||||||
| 		if message_ids: | 		if message_ids: | ||||||
| 			gajim.logger.set_read_messages(message_ids) | 			gajim.logger.set_read_messages(message_ids) | ||||||
| 		gajim.events.remove_events(self.account, jid_with_resource, | 		gajim.events.remove_events(self.account, jid_with_resource, | ||||||
|  |  | ||||||
|  | @ -48,6 +48,8 @@ log = logging.getLogger('gajim.c.connection') | ||||||
| 
 | 
 | ||||||
| import gtkgui_helpers | import gtkgui_helpers | ||||||
| 
 | 
 | ||||||
|  | import time | ||||||
|  | 
 | ||||||
| class Connection(ConnectionHandlers): | class Connection(ConnectionHandlers): | ||||||
| 	'''Connection class''' | 	'''Connection class''' | ||||||
| 	def __init__(self, name): | 	def __init__(self, name): | ||||||
|  | @ -839,7 +841,7 @@ class Connection(ConnectionHandlers): | ||||||
| 
 | 
 | ||||||
| 	def send_message(self, jid, msg, keyID, type = 'chat', subject='', | 	def send_message(self, jid, msg, keyID, type = 'chat', subject='', | ||||||
| 	chatstate = None, msg_id = None, composing_jep = None, resource = None, | 	chatstate = None, msg_id = None, composing_jep = None, resource = None, | ||||||
| 	user_nick = None, xhtml = None, thread = None): | 	user_nick = None, xhtml = None, session = None): | ||||||
| 		if not self.connection: | 		if not self.connection: | ||||||
| 			return 1 | 			return 1 | ||||||
| 		if msg and not xhtml and gajim.config.get('rst_formatting_outgoing_messages'): | 		if msg and not xhtml and gajim.config.get('rst_formatting_outgoing_messages'): | ||||||
|  | @ -884,8 +886,10 @@ class Connection(ConnectionHandlers): | ||||||
| 			msg_iq.setTag(common.xmpp.NS_ENCRYPTED + ' x').setData(msgenc) | 			msg_iq.setTag(common.xmpp.NS_ENCRYPTED + ' x').setData(msgenc) | ||||||
| 
 | 
 | ||||||
| 		# XEP-0201 | 		# XEP-0201 | ||||||
| 		if thread: | 		if session: | ||||||
| 			msg_iq.setTag("thread").setData(thread) | 			session.last_send = time.time() | ||||||
|  | 			if session.thread_id: | ||||||
|  | 				msg_iq.setThread(session.thread_id) | ||||||
| 
 | 
 | ||||||
| 		# JEP-0172: user_nickname | 		# JEP-0172: user_nickname | ||||||
| 		if user_nick: | 		if user_nick: | ||||||
|  |  | ||||||
|  | @ -37,6 +37,8 @@ from common import atom | ||||||
| from common.commands import ConnectionCommands | from common.commands import ConnectionCommands | ||||||
| from common.pubsub import ConnectionPubSub | from common.pubsub import ConnectionPubSub | ||||||
| 
 | 
 | ||||||
|  | from common.stanza_session import StanzaSession | ||||||
|  | 
 | ||||||
| STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd', | STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd', | ||||||
| 	'invisible', 'error'] | 	'invisible', 'error'] | ||||||
| # kind of events we can wait for an answer | # kind of events we can wait for an answer | ||||||
|  | @ -1171,6 +1173,10 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, | ||||||
| 		# keep the latest subscribed event for each jid to prevent loop when we  | 		# keep the latest subscribed event for each jid to prevent loop when we  | ||||||
| 		# acknoledge presences | 		# acknoledge presences | ||||||
| 		self.subscribed_events = {} | 		self.subscribed_events = {} | ||||||
|  | 
 | ||||||
|  | 		# keep track of sessions this connection has with other JIDs | ||||||
|  | 		self.sessions = {} | ||||||
|  | 
 | ||||||
| 		try: | 		try: | ||||||
| 			idle.init() | 			idle.init() | ||||||
| 		except: | 		except: | ||||||
|  | @ -1197,13 +1203,13 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, | ||||||
| 			self.dispatch('HTTP_AUTH', (method, url, id, iq_obj, msg)); | 			self.dispatch('HTTP_AUTH', (method, url, id, iq_obj, msg)); | ||||||
| 		raise common.xmpp.NodeProcessed | 		raise common.xmpp.NodeProcessed | ||||||
| 
 | 
 | ||||||
| 	def _FeatureNegCB(self, con, stanza): | 	def _FeatureNegCB(self, con, stanza, session): | ||||||
| 		gajim.log.debug('FeatureNegCB') | 		gajim.log.debug('FeatureNegCB') | ||||||
| 		feature = stanza.getTag('feature') | 		feature = stanza.getTag('feature') | ||||||
| 		form = common.xmpp.DataForm(node=feature.getTag('x')) | 		form = common.xmpp.DataForm(node=feature.getTag('x')) | ||||||
| 
 | 
 | ||||||
| 		if form['FORM_TYPE'] == 'urn:xmpp:ssn': | 		if form['FORM_TYPE'] == 'urn:xmpp:ssn': | ||||||
| 			self.dispatch('SESSION_NEG', (stanza.getFrom(), stanza.getThread(), form)) | 			self.dispatch('SESSION_NEG', (stanza.getFrom(), session, form)) | ||||||
| 		else: | 		else: | ||||||
| 			reply = stanza.buildReply() | 			reply = stanza.buildReply() | ||||||
| 			reply.setType('error') | 			reply.setType('error') | ||||||
|  | @ -1410,6 +1416,17 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, | ||||||
| 
 | 
 | ||||||
| 	def _messageCB(self, con, msg): | 	def _messageCB(self, con, msg): | ||||||
| 		'''Called when we receive a message''' | 		'''Called when we receive a message''' | ||||||
|  | 		frm = helpers.get_full_jid_from_iq(msg) | ||||||
|  | 		mtype = msg.getType() | ||||||
|  | 		thread_id = msg.getThread() | ||||||
|  | 		if not mtype: | ||||||
|  | 			mtype = 'normal' | ||||||
|  | 
 | ||||||
|  | 		session = self.get_session(frm, thread_id, mtype) | ||||||
|  | 
 | ||||||
|  | 		if thread_id and not session.received_thread_id: | ||||||
|  | 			session.received_thread_id = True | ||||||
|  | 
 | ||||||
| 		# check if the message is pubsub#event | 		# check if the message is pubsub#event | ||||||
| 		if msg.getTag('event') is not None: | 		if msg.getTag('event') is not None: | ||||||
| 			self._pubsubEventCB(con, msg) | 			self._pubsubEventCB(con, msg) | ||||||
|  | @ -1421,18 +1438,15 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, | ||||||
| 			return | 			return | ||||||
| 		if msg.getTag('feature') and msg.getTag('feature').namespace == \ | 		if msg.getTag('feature') and msg.getTag('feature').namespace == \ | ||||||
| 		common.xmpp.NS_FEATURE: | 		common.xmpp.NS_FEATURE: | ||||||
| 			self._FeatureNegCB(con, msg) | 			self._FeatureNegCB(con, msg, session) | ||||||
| 			return | 			return | ||||||
| 
 | 
 | ||||||
| 		msgtxt = msg.getBody() | 		msgtxt = msg.getBody() | ||||||
| 		msghtml = msg.getXHTML() | 		msghtml = msg.getXHTML() | ||||||
| 		mtype = msg.getType() |  | ||||||
| 		subject = msg.getSubject() # if not there, it's None | 		subject = msg.getSubject() # if not there, it's None | ||||||
| 		thread = msg.getThread() |  | ||||||
| 		tim = msg.getTimestamp() | 		tim = msg.getTimestamp() | ||||||
| 		tim = time.strptime(tim, '%Y%m%dT%H:%M:%S') | 		tim = time.strptime(tim, '%Y%m%dT%H:%M:%S') | ||||||
| 		tim = time.localtime(timegm(tim)) | 		tim = time.localtime(timegm(tim)) | ||||||
| 		frm = helpers.get_full_jid_from_iq(msg) |  | ||||||
| 		jid = helpers.get_jid_from_iq(msg) | 		jid = helpers.get_jid_from_iq(msg) | ||||||
| 		no_log_for = gajim.config.get_per('accounts', self.name, | 		no_log_for = gajim.config.get_per('accounts', self.name, | ||||||
| 			'no_log_for') | 			'no_log_for') | ||||||
|  | @ -1541,13 +1555,42 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, | ||||||
| 				gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim, | 				gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim, | ||||||
| 					subject = subject) | 					subject = subject) | ||||||
| 			mtype = 'normal' | 			mtype = 'normal' | ||||||
|  | 
 | ||||||
| 		treat_as = gajim.config.get('treat_incoming_messages') | 		treat_as = gajim.config.get('treat_incoming_messages') | ||||||
| 		if treat_as: | 		if treat_as: | ||||||
| 			mtype = treat_as | 			mtype = treat_as | ||||||
| 		self.dispatch('MSG', (frm, msgtxt, tim, encrypted, mtype, | 		self.dispatch('MSG', (frm, msgtxt, tim, encrypted, mtype, | ||||||
| 			subject, chatstate, msg_id, composing_jep, user_nick, msghtml, thread)) | 			subject, chatstate, msg_id, composing_jep, user_nick, msghtml, session)) | ||||||
| 	# END messageCB | 	# END messageCB | ||||||
| 
 | 
 | ||||||
|  | 	def get_session(self, jid, thread_id, type): | ||||||
|  | 		'''returns an existing session between this connection and 'jid' or starts a new one.''' | ||||||
|  | 		try: | ||||||
|  | 			if type == 'chat' and not thread_id: | ||||||
|  | 				return self.find_null_session(jid) | ||||||
|  | 			else: | ||||||
|  | 				return self.sessions[jid][thread_id] | ||||||
|  | 		except KeyError: | ||||||
|  | 			return self.make_new_session(jid, thread_id, type) | ||||||
|  | 
 | ||||||
|  | 	def find_null_session(self, jid): | ||||||
|  | 		'''returns the session between this connecting and 'jid' that we last sent a message in.''' | ||||||
|  | 		all = self.sessions[jid].values() | ||||||
|  | 		null_sessions = filter(lambda s: not s.received_thread_id, all) | ||||||
|  | 		null_sessions.sort(key=lambda s: s.last_send) | ||||||
|  | 
 | ||||||
|  | 		return null_sessions[-1] | ||||||
|  | 
 | ||||||
|  | 	def make_new_session(self, jid, thread_id = None, type = 'chat'): | ||||||
|  | 		sess = StanzaSession(self, jid, thread_id, type) | ||||||
|  | 
 | ||||||
|  | 		if not jid in self.sessions: | ||||||
|  | 			self.sessions[jid] = {} | ||||||
|  | 
 | ||||||
|  | 		self.sessions[jid][sess.thread_id] = sess | ||||||
|  | 
 | ||||||
|  | 		return sess | ||||||
|  | 
 | ||||||
| 	def _pubsubEventCB(self, con, msg): | 	def _pubsubEventCB(self, con, msg): | ||||||
| 		''' Called when we receive <message/> with pubsub event. ''' | 		''' Called when we receive <message/> with pubsub event. ''' | ||||||
| 		# TODO: Logging? (actually services where logging would be useful, should | 		# TODO: Logging? (actually services where logging would be useful, should | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
| 
 | 
 | ||||||
| import common.gajim | import common.gajim | ||||||
| 
 | 
 | ||||||
| import random, string | #import random, string | ||||||
| 
 | 
 | ||||||
| class Contact: | class Contact: | ||||||
| 	'''Information concerning each contact''' | 	'''Information concerning each contact''' | ||||||
|  | @ -53,18 +53,18 @@ class Contact: | ||||||
| 		self.last_status_time = last_status_time | 		self.last_status_time = last_status_time | ||||||
| 
 | 
 | ||||||
| 		# XEP-0201 | 		# XEP-0201 | ||||||
| 		self.sessions = {} | #		self.sessions = {} | ||||||
| 
 | 
 | ||||||
| 	def new_session(self): | #	def new_session(self): | ||||||
| 		thread_id = "".join([random.choice(string.letters) for x in xrange(0,32)]) | #		thread_id = "".join([random.choice(string.letters) for x in xrange(0,32)]) | ||||||
| 		self.sessions[self.get_full_jid()] = thread_id | #		self.sessions[self.get_full_jid()] = thread_id | ||||||
| 		return thread_id | #		return thread_id | ||||||
| 
 | 
 | ||||||
| 	def get_session(self): | #	def get_session(self): | ||||||
| 		try: | #		try: | ||||||
| 			return self.sessions[self.get_full_jid()] | #			return self.sessions[self.get_full_jid()] | ||||||
| 		except KeyError: | #		except KeyError: | ||||||
| 			return None | #			return None | ||||||
| 
 | 
 | ||||||
| 	def get_full_jid(self): | 	def get_full_jid(self): | ||||||
| 		if self.resource: | 		if self.resource: | ||||||
|  | @ -169,7 +169,7 @@ class Contacts: | ||||||
| 		return Contact(jid, name, groups, show, status, sub, ask, resource, | 		return Contact(jid, name, groups, show, status, sub, ask, resource, | ||||||
| 			priority, keyID, our_chatstate, chatstate, last_status_time, | 			priority, keyID, our_chatstate, chatstate, last_status_time, | ||||||
| 			composing_jep) | 			composing_jep) | ||||||
| 	 | 
 | ||||||
| 	def copy_contact(self, contact): | 	def copy_contact(self, contact): | ||||||
| 		return self.create_contact(jid = contact.jid, name = contact.name, | 		return self.create_contact(jid = contact.jid, name = contact.name, | ||||||
| 			groups = contact.groups, show = contact.show, status = contact.status, | 			groups = contact.groups, show = contact.show, status = contact.status, | ||||||
|  |  | ||||||
|  | @ -820,7 +820,7 @@ def allow_sound_notification(sound_event, advanced_notif_num = None): | ||||||
| 		return True | 		return True | ||||||
| 	return False | 	return False | ||||||
| 
 | 
 | ||||||
| def get_chat_control(account, contact): | def get_chat_control(account, contact, session): | ||||||
| 	full_jid_with_resource = contact.jid | 	full_jid_with_resource = contact.jid | ||||||
| 	if contact.resource: | 	if contact.resource: | ||||||
| 		full_jid_with_resource += '/' + contact.resource | 		full_jid_with_resource += '/' + contact.resource | ||||||
|  | @ -829,16 +829,16 @@ def get_chat_control(account, contact): | ||||||
| 	# Look for a chat control that has the given resource, or default to | 	# Look for a chat control that has the given resource, or default to | ||||||
| 	# one without resource | 	# one without resource | ||||||
| 	ctrl = gajim.interface.msg_win_mgr.get_control(full_jid_with_resource, | 	ctrl = gajim.interface.msg_win_mgr.get_control(full_jid_with_resource, | ||||||
| 		account) | 		account, session.thread_id) | ||||||
| 	if ctrl: | 	if ctrl: | ||||||
| 		return ctrl | 		return ctrl | ||||||
| 	elif not highest_contact or not highest_contact.resource: | 	elif not highest_contact or not highest_contact.resource: | ||||||
| 		# unknow contact or offline message | 		# unknow contact or offline message | ||||||
| 		return gajim.interface.msg_win_mgr.get_control(contact.jid, account) | 		return gajim.interface.msg_win_mgr.get_control(contact.jid, account, session.thread_id) | ||||||
| 	elif highest_contact and contact.resource != \ | 	elif highest_contact and contact.resource != \ | ||||||
| 	highest_contact.resource: | 	highest_contact.resource: | ||||||
| 		return None | 		return None | ||||||
| 	return gajim.interface.msg_win_mgr.get_control(contact.jid, account) | 	return gajim.interface.msg_win_mgr.get_control(contact.jid, account, session.thread_id) | ||||||
| 
 | 
 | ||||||
| def reduce_chars_newlines(text, max_chars = 0, max_lines = 0): | def reduce_chars_newlines(text, max_chars = 0, max_lines = 0): | ||||||
| 	'''Cut the chars after 'max_chars' on each line | 	'''Cut the chars after 'max_chars' on each line | ||||||
|  |  | ||||||
							
								
								
									
										51
									
								
								src/common/stanza_session.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/common/stanza_session.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | ||||||
|  | import gajim | ||||||
|  | 
 | ||||||
|  | from common import xmpp | ||||||
|  | from common import helpers | ||||||
|  | 
 | ||||||
|  | import random | ||||||
|  | import string | ||||||
|  | 
 | ||||||
|  | class StanzaSession: | ||||||
|  | 	def __init__(self, conn, jid, thread_id, type): | ||||||
|  | 		self.conn = conn | ||||||
|  | 
 | ||||||
|  | 		if isinstance(jid, str) or isinstance(jid, unicode): | ||||||
|  | 			self.jid = xmpp.JID(jid) | ||||||
|  | 		else: | ||||||
|  | 			self.jid = jid | ||||||
|  | 
 | ||||||
|  | 		self.type = type | ||||||
|  | 
 | ||||||
|  | 		if thread_id: | ||||||
|  | 			self.received_thread_id = True | ||||||
|  | 			self.thread_id = thread_id | ||||||
|  | 		else: | ||||||
|  | 			self.received_thread_id = False | ||||||
|  | 			if type == 'normal': | ||||||
|  | 				self.thread_id = None | ||||||
|  | 			else: | ||||||
|  | 				self.thread_id = self.generate_thread_id() | ||||||
|  | 
 | ||||||
|  | 		self.last_send = 0 | ||||||
|  | 
 | ||||||
|  | 	def generate_thread_id(self): | ||||||
|  | 		return "".join([random.choice(string.letters) for x in xrange(0,32)]) | ||||||
|  | 
 | ||||||
|  | 	def get_control(self, advanced_notif_num = None): | ||||||
|  | 		account = self.conn.name | ||||||
|  | 		highest_contact = gajim.contacts.get_contact_with_highest_priority(account, str(self.jid)) | ||||||
|  | 		contact = gajim.contacts.get_contact(account, self.jid.getStripped(), self.jid.getResource()) | ||||||
|  | 		if isinstance(contact, list): | ||||||
|  | 			# there was no resource (maybe we're reading unread messages after shutdown). just take the first one for now :/ | ||||||
|  | 			contact = contact[0] | ||||||
|  | 
 | ||||||
|  | 		ctrl = gajim.interface.msg_win_mgr.get_control(str(self.jid), account, self.thread_id) | ||||||
|  | #		if not ctrl: | ||||||
|  | #			if highest_contact and contact.resource == highest_contact.resource and not str(self.jid) == gajim.get_jid_from_account(account): | ||||||
|  | #				ctrl = gajim.interface.msg_win_mgr.get_control(self.jid.getStripped(), account, self.thread_id) | ||||||
|  | 
 | ||||||
|  | 		if not ctrl and helpers.allow_popup_window(account, advanced_notif_num): | ||||||
|  | 			gajim.new_chat(contact, account, resource = resource_for_chat, session = self) | ||||||
|  | 
 | ||||||
|  | 		return ctrl | ||||||
|  | @ -1404,7 +1404,7 @@ class SynchroniseSelectAccountDialog: | ||||||
| 		if not iter: | 		if not iter: | ||||||
| 			return | 			return | ||||||
| 		remote_account = model.get_value(iter, 0).decode('utf-8') | 		remote_account = model.get_value(iter, 0).decode('utf-8') | ||||||
| 		 | 
 | ||||||
| 		if gajim.connections[remote_account].connected < 2: | 		if gajim.connections[remote_account].connected < 2: | ||||||
| 			ErrorDialog(_('This account is not connected to the server'), | 			ErrorDialog(_('This account is not connected to the server'), | ||||||
| 				_('You cannot synchronize with an account unless it is connected.')) | 				_('You cannot synchronize with an account unless it is connected.')) | ||||||
|  | @ -1686,7 +1686,7 @@ class SingleMessageWindow: | ||||||
| 	or 'receive'. | 	or 'receive'. | ||||||
| 	''' | 	''' | ||||||
| 	def __init__(self, account, to = '', action = '', from_whom = '', | 	def __init__(self, account, to = '', action = '', from_whom = '', | ||||||
| 	subject = '', message = '', resource = '', thread = None): | 	subject = '', message = '', resource = '', session = None): | ||||||
| 		self.account = account | 		self.account = account | ||||||
| 		self.action = action | 		self.action = action | ||||||
| 
 | 
 | ||||||
|  | @ -1695,7 +1695,7 @@ class SingleMessageWindow: | ||||||
| 		self.to = to | 		self.to = to | ||||||
| 		self.from_whom = from_whom | 		self.from_whom = from_whom | ||||||
| 		self.resource = resource | 		self.resource = resource | ||||||
| 		self.thread = thread | 		self.session = session | ||||||
| 
 | 
 | ||||||
| 		self.xml = gtkgui_helpers.get_glade('single_message_window.glade') | 		self.xml = gtkgui_helpers.get_glade('single_message_window.glade') | ||||||
| 		self.window = self.xml.get_widget('single_message_window') | 		self.window = self.xml.get_widget('single_message_window') | ||||||
|  | @ -1897,7 +1897,7 @@ class SingleMessageWindow: | ||||||
| 
 | 
 | ||||||
| 			# FIXME: allow GPG message some day | 			# FIXME: allow GPG message some day | ||||||
| 			gajim.connections[self.account].send_message(to_whom_jid, message, | 			gajim.connections[self.account].send_message(to_whom_jid, message, | ||||||
| 				keyID = None, type = 'normal', subject=subject, thread = self.thread) | 				keyID = None, type = 'normal', subject=subject, session = self.session) | ||||||
| 
 | 
 | ||||||
| 		self.subject_entry.set_text('') # we sent ok, clear the subject | 		self.subject_entry.set_text('') # we sent ok, clear the subject | ||||||
| 		self.message_tv_buffer.set_text('') # we sent ok, clear the textview | 		self.message_tv_buffer.set_text('') # we sent ok, clear the textview | ||||||
|  | @ -1914,7 +1914,7 @@ class SingleMessageWindow: | ||||||
| 		self.window.destroy() | 		self.window.destroy() | ||||||
| 		SingleMessageWindow(self.account, to = self.from_whom, | 		SingleMessageWindow(self.account, to = self.from_whom, | ||||||
| 			action = 'send',	from_whom = self.from_whom, subject = self.subject, | 			action = 'send',	from_whom = self.from_whom, subject = self.subject, | ||||||
| 			message = self.message, thread = self.thread) | 			message = self.message, session = self.session) | ||||||
| 
 | 
 | ||||||
| 	def on_send_and_close_button_clicked(self, widget): | 	def on_send_and_close_button_clicked(self, widget): | ||||||
| 		self.send_single_message() | 		self.send_single_message() | ||||||
|  | @ -2099,7 +2099,7 @@ class PrivacyListWindow: | ||||||
| 		jid_entry_completion.set_text_column(0) | 		jid_entry_completion.set_text_column(0) | ||||||
| 		jid_entry_completion.set_model(jids_list_store) | 		jid_entry_completion.set_model(jids_list_store) | ||||||
| 		jid_entry_completion.set_popup_completion(True) | 		jid_entry_completion.set_popup_completion(True) | ||||||
|   		self.edit_type_jabberid_entry.set_completion(jid_entry_completion)			 | 		self.edit_type_jabberid_entry.set_completion(jid_entry_completion) | ||||||
| 
 | 
 | ||||||
| 		if action == 'EDIT': | 		if action == 'EDIT': | ||||||
| 			self.refresh_rules() | 			self.refresh_rules() | ||||||
|  |  | ||||||
							
								
								
									
										98
									
								
								src/gajim.py
									
										
									
									
									
								
							
							
						
						
									
										98
									
								
								src/gajim.py
									
										
									
									
									
								
							|  | @ -443,9 +443,9 @@ class Interface: | ||||||
| 					(jid_from, file_props)) | 					(jid_from, file_props)) | ||||||
| 				conn.disconnect_transfer(file_props) | 				conn.disconnect_transfer(file_props) | ||||||
| 				return | 				return | ||||||
| 		ctrl = self.msg_win_mgr.get_control(jid_from, account) | 		for ctrl in self.msg_win_mgr.get_controls(jid=jid_from, acct=account): | ||||||
| 		if ctrl and ctrl.type_id == message_control.TYPE_GC: | 			if ctrl and ctrl.type_id == message_control.TYPE_GC: | ||||||
| 			ctrl.print_conversation('Error %s: %s' % (array[2], array[1])) | 				ctrl.print_conversation('Error %s: %s' % (array[2], array[1])) | ||||||
| 
 | 
 | ||||||
| 	def handle_event_con_type(self, account, con_type): | 	def handle_event_con_type(self, account, con_type): | ||||||
| 		# ('CON_TYPE', account, con_type) which can be 'ssl', 'tls', 'tcp' | 		# ('CON_TYPE', account, con_type) which can be 'ssl', 'tls', 'tcp' | ||||||
|  | @ -667,7 +667,7 @@ class Interface: | ||||||
| 
 | 
 | ||||||
| 	def handle_event_msg(self, account, array): | 	def handle_event_msg(self, account, array): | ||||||
| 		# 'MSG' (account, (jid, msg, time, encrypted, msg_type, subject, | 		# 'MSG' (account, (jid, msg, time, encrypted, msg_type, subject, | ||||||
| 		# chatstate, msg_id, composing_jep, user_nick, xhtml, thread)) | 		# chatstate, msg_id, composing_jep, user_nick, xhtml, session)) | ||||||
| 		# user_nick is JEP-0172 | 		# user_nick is JEP-0172 | ||||||
| 
 | 
 | ||||||
| 		full_jid_with_resource = array[0] | 		full_jid_with_resource = array[0] | ||||||
|  | @ -682,13 +682,13 @@ class Interface: | ||||||
| 		msg_id = array[7] | 		msg_id = array[7] | ||||||
| 		composing_jep = array[8] | 		composing_jep = array[8] | ||||||
| 		xhtml = array[10] | 		xhtml = array[10] | ||||||
| 		thread = array[11] | 		session = array[11] | ||||||
| 		if gajim.config.get('ignore_incoming_xhtml'): | 		if gajim.config.get('ignore_incoming_xhtml'): | ||||||
| 			xhtml = None | 			xhtml = None | ||||||
| 		if gajim.jid_is_transport(jid): | 		if gajim.jid_is_transport(jid): | ||||||
| 			jid = jid.replace('@', '') | 			jid = jid.replace('@', '') | ||||||
| 
 | 
 | ||||||
| 		groupchat_control = self.msg_win_mgr.get_control(jid, account) | 		groupchat_control = self.msg_win_mgr.get_control(jid, account, session.thread_id) | ||||||
| 		if not groupchat_control and \ | 		if not groupchat_control and \ | ||||||
| 		gajim.interface.minimized_controls.has_key(account) and \ | 		gajim.interface.minimized_controls.has_key(account) and \ | ||||||
| 		jid in gajim.interface.minimized_controls[account]: | 		jid in gajim.interface.minimized_controls[account]: | ||||||
|  | @ -700,28 +700,29 @@ class Interface: | ||||||
| 			pm = True | 			pm = True | ||||||
| 			msg_type = 'pm' | 			msg_type = 'pm' | ||||||
| 
 | 
 | ||||||
| 		chat_control = None | #		chat_control = None | ||||||
| 		jid_of_control = full_jid_with_resource | #		jid_of_control = full_jid_with_resource | ||||||
| 		highest_contact = gajim.contacts.get_contact_with_highest_priority( | 		highest_contact = gajim.contacts.get_contact_with_highest_priority( | ||||||
| 			account, jid) | 			account, jid) | ||||||
| 		# Look for a chat control that has the given resource, or default to one | 		# Look for a chat control that has the given resource, or default to one | ||||||
| 		# without resource | 		# without resource | ||||||
| 		ctrl = self.msg_win_mgr.get_control(full_jid_with_resource, account) | 		chat_control = session.get_control() | ||||||
| 		if ctrl: | #		ctrl = self.msg_win_mgr.get_control(full_jid_with_resource, account, session.thread_id) | ||||||
| 			chat_control = ctrl | #		if ctrl: | ||||||
| 		elif not pm and (not highest_contact or not highest_contact.resource): | #			chat_control = ctrl | ||||||
|  | #		elif not pm and (not highest_contact or not highest_contact.resource): | ||||||
| 			# unknow contact or offline message | 			# unknow contact or offline message | ||||||
| 			jid_of_control = jid | #			jid_of_control = jid | ||||||
| 			chat_control = self.msg_win_mgr.get_control(jid, account) | #			chat_control = self.msg_win_mgr.get_control(jid, account, session.thread_id) | ||||||
| 		elif highest_contact and resource != highest_contact.resource and \ | #		elif highest_contact and resource != highest_contact.resource and \ | ||||||
| 		highest_contact.show != 'offline': | #		highest_contact.show != 'offline': | ||||||
| 			jid_of_control = full_jid_with_resource | #			jid_of_control = full_jid_with_resource | ||||||
| 			chat_control = None | #			chat_control = None | ||||||
| 		elif not pm: | #		elif not pm: | ||||||
| 			jid_of_control = jid | #			jid_of_control = jid | ||||||
| 			chat_control = self.msg_win_mgr.get_control(jid, account) | #			chat_control = self.msg_win_mgr.get_control(jid, account, session.thread_id) | ||||||
| 
 | 
 | ||||||
| 		# Handle chat states   | 		# Handle chat states | ||||||
| 		contact = gajim.contacts.get_contact(account, jid, resource) | 		contact = gajim.contacts.get_contact(account, jid, resource) | ||||||
| 		if contact and isinstance(contact, list): | 		if contact and isinstance(contact, list): | ||||||
| 			contact = contact[0] | 			contact = contact[0] | ||||||
|  | @ -739,7 +740,7 @@ class Interface: | ||||||
| 					# got no valid jep85 answer, peer does not support it | 					# got no valid jep85 answer, peer does not support it | ||||||
| 					contact.chatstate = False | 					contact.chatstate = False | ||||||
| 			elif chatstate == 'active': | 			elif chatstate == 'active': | ||||||
| 				# Brand new message, incoming.   | 				# Brand new message, incoming. | ||||||
| 				contact.our_chatstate = chatstate | 				contact.our_chatstate = chatstate | ||||||
| 				contact.chatstate = chatstate | 				contact.chatstate = chatstate | ||||||
| 				if msg_id: # Do not overwrite an existing msg_id with None | 				if msg_id: # Do not overwrite an existing msg_id with None | ||||||
|  | @ -753,10 +754,12 @@ class Interface: | ||||||
| 		if gajim.config.get('ignore_unknown_contacts') and \ | 		if gajim.config.get('ignore_unknown_contacts') and \ | ||||||
| 			not gajim.contacts.get_contact(account, jid) and not pm: | 			not gajim.contacts.get_contact(account, jid) and not pm: | ||||||
| 			return | 			return | ||||||
|  | 
 | ||||||
| 		if not contact: | 		if not contact: | ||||||
| 			# contact is not in the roster, create a fake one to display | 			# contact is not in the roster, create a fake one to display | ||||||
| 			# notification | 			# notification | ||||||
| 			contact = common.contacts.Contact(jid = jid, resource = resource)  | 			contact = common.contacts.Contact(jid = jid, resource = resource) | ||||||
|  | 
 | ||||||
| 		advanced_notif_num = notify.get_advanced_notification('message_received', | 		advanced_notif_num = notify.get_advanced_notification('message_received', | ||||||
| 			account, contact) | 			account, contact) | ||||||
| 
 | 
 | ||||||
|  | @ -765,8 +768,8 @@ class Interface: | ||||||
| 		if msg_type == 'normal': | 		if msg_type == 'normal': | ||||||
| 			if not gajim.events.get_events(account, jid, ['normal']): | 			if not gajim.events.get_events(account, jid, ['normal']): | ||||||
| 				first = True | 				first = True | ||||||
| 		elif not chat_control and not gajim.events.get_events(account,  | 		elif not chat_control and not gajim.events.get_events(account, | ||||||
| 		jid_of_control, [msg_type]): # msg_type can be chat or pm | 		full_jid_with_resource, [msg_type]): # msg_type can be chat or pm | ||||||
| 			first = True | 			first = True | ||||||
| 
 | 
 | ||||||
| 		if pm: | 		if pm: | ||||||
|  | @ -778,18 +781,19 @@ class Interface: | ||||||
| 			if encrypted: | 			if encrypted: | ||||||
| 				self.roster.on_message(jid, message, array[2], account, array[3], | 				self.roster.on_message(jid, message, array[2], account, array[3], | ||||||
| 					msg_type, subject, resource, msg_id, array[9], | 					msg_type, subject, resource, msg_id, array[9], | ||||||
| 					advanced_notif_num, thread = thread) | 					advanced_notif_num, session = session) | ||||||
| 			else: | 			else: | ||||||
| 				# xhtml in last element | 				# xhtml in last element | ||||||
| 				self.roster.on_message(jid, message, array[2], account, array[3], | 				self.roster.on_message(jid, message, array[2], account, array[3], | ||||||
| 					msg_type, subject, resource, msg_id, array[9], | 					msg_type, subject, resource, msg_id, array[9], | ||||||
| 					advanced_notif_num, xhtml = xhtml, thread = thread) | 					advanced_notif_num, xhtml = xhtml, session = session) | ||||||
| 			nickname = gajim.get_name_from_jid(account, jid) | 			nickname = gajim.get_name_from_jid(account, jid) | ||||||
| 		# Check and do wanted notifications	 | 
 | ||||||
|  | 		# Check and do wanted notifications | ||||||
| 		msg = message | 		msg = message | ||||||
| 		if subject: | 		if subject: | ||||||
| 			msg = _('Subject: %s') % subject + '\n' + msg | 			msg = _('Subject: %s') % subject + '\n' + msg | ||||||
| 		notify.notify('new_message', jid_of_control, account, [msg_type, | 		notify.notify('new_message', full_jid_with_resource, account, [msg_type, | ||||||
| 			first, nickname, msg], advanced_notif_num) | 			first, nickname, msg], advanced_notif_num) | ||||||
| 
 | 
 | ||||||
| 		if self.remote_ctrl: | 		if self.remote_ctrl: | ||||||
|  | @ -986,7 +990,7 @@ class Interface: | ||||||
| 		resource = '' | 		resource = '' | ||||||
| 		if vcard.has_key('resource'): | 		if vcard.has_key('resource'): | ||||||
| 			resource = vcard['resource'] | 			resource = vcard['resource'] | ||||||
| 		 | 
 | ||||||
| 		# vcard window | 		# vcard window | ||||||
| 		win = None | 		win = None | ||||||
| 		if self.instances[account]['infos'].has_key(jid): | 		if self.instances[account]['infos'].has_key(jid): | ||||||
|  | @ -1008,11 +1012,14 @@ class Interface: | ||||||
| 		elif self.msg_win_mgr.has_window(jid, account): | 		elif self.msg_win_mgr.has_window(jid, account): | ||||||
| 			win = self.msg_win_mgr.get_window(jid, account) | 			win = self.msg_win_mgr.get_window(jid, account) | ||||||
| 			ctrl = win.get_control(jid, account) | 			ctrl = win.get_control(jid, account) | ||||||
| 		if win and ctrl.type_id != message_control.TYPE_GC: | 
 | ||||||
| 			ctrl.show_avatar() | 		for ctrl in self.msg_win_mgr.get_controls(jid=jid, acct=account): | ||||||
|  | 			if ctrl.type_id != message_control.TYPE_GC: | ||||||
|  | 				ctrl.show_avatar() | ||||||
| 
 | 
 | ||||||
| 		# Show avatar in roster or gc_roster | 		# Show avatar in roster or gc_roster | ||||||
| 		gc_ctrl = self.msg_win_mgr.get_control(jid, account) | 		gc_ctrl = self.msg_win_mgr.get_control(jid, account) | ||||||
|  | 		# XXX get_gc_control? | ||||||
| 		if gc_ctrl and gc_ctrl.type_id == message_control.TYPE_GC: | 		if gc_ctrl and gc_ctrl.type_id == message_control.TYPE_GC: | ||||||
| 			gc_ctrl.draw_avatar(resource) | 			gc_ctrl.draw_avatar(resource) | ||||||
| 		else: | 		else: | ||||||
|  | @ -1656,25 +1663,24 @@ class Interface: | ||||||
| 		AtomWindow.newAtomEntry(atom_entry) | 		AtomWindow.newAtomEntry(atom_entry) | ||||||
| 
 | 
 | ||||||
| 	def handle_session_negotiation(self, account, data): | 	def handle_session_negotiation(self, account, data): | ||||||
| 		jid, thread_id, form = data | 		jid, session, form = data | ||||||
| 		# XXX check negotiation state, etc. | 		# XXX check negotiation state, etc. | ||||||
| 		# XXX check if we can autoaccept | 		# XXX check if we can autoaccept | ||||||
| 
 | 
 | ||||||
| 		if form.getType() == 'form': | 		if form.getType() == 'form': | ||||||
| 			ctrl = gajim.interface.msg_win_mgr.get_control(str(jid), account) | 			ctrl = session.get_control() | ||||||
| 			if not ctrl: | #			ctrl = gajim.interface.msg_win_mgr.get_control(str(jid), account) | ||||||
| 				resource = jid.getResource() | #			if not ctrl: | ||||||
| 				contact = gajim.contacts.get_contact(account, str(jid), resource) | #				resource = jid.getResource() | ||||||
| 				if not contact: | #				contact = gajim.contacts.get_contact(account, str(jid), resource) | ||||||
| 					connection = gajim.connections[account] | #				if not contact: | ||||||
| 					contact = gajim.contacts.create_contact(jid = jid.getStripped(), resource = resource, show = connection.get_status()) | #					connection = gajim.connections[account] | ||||||
| 				self.roster.new_chat(contact, account, resource = resource) | #					contact = gajim.contacts.create_contact(jid = jid.getStripped(), resource = resource, show = connection.get_status()) | ||||||
|  | #				self.roster.new_chat(contact, account, resource = resource) | ||||||
| 
 | 
 | ||||||
| 				ctrl = gajim.interface.msg_win_mgr.get_control(str(jid), account) | #				ctrl = gajim.interface.msg_win_mgr.get_control(str(jid), account) | ||||||
| 
 | 
 | ||||||
| 			ctrl.set_thread_id(thread_id) | 			negotiation.FeatureNegotiationWindow(account, jid, session, form) | ||||||
| 
 |  | ||||||
| 			negotiation.FeatureNegotiationWindow(account, jid, thread_id, form) |  | ||||||
| 
 | 
 | ||||||
| 	def handle_event_privacy_lists_received(self, account, data): | 	def handle_event_privacy_lists_received(self, account, data): | ||||||
| 		# ('PRIVACY_LISTS_RECEIVED', account, list) | 		# ('PRIVACY_LISTS_RECEIVED', account, list) | ||||||
|  |  | ||||||
|  | @ -37,8 +37,6 @@ class MessageControl: | ||||||
| 		self.hide_chat_buttons_current = False | 		self.hide_chat_buttons_current = False | ||||||
| 		self.resource = resource | 		self.resource = resource | ||||||
| 
 | 
 | ||||||
| 		self.thread_id = self.contact.get_session() |  | ||||||
| 
 |  | ||||||
| 		gajim.last_message_time[self.account][self.get_full_jid()] = 0 | 		gajim.last_message_time[self.account][self.get_full_jid()] = 0 | ||||||
| 
 | 
 | ||||||
| 		self.xml = gtkgui_helpers.get_glade('message_window.glade', widget_name) | 		self.xml = gtkgui_helpers.get_glade('message_window.glade', widget_name) | ||||||
|  | @ -112,14 +110,6 @@ class MessageControl: | ||||||
| 	def get_specific_unread(self): | 	def get_specific_unread(self): | ||||||
| 		return len(gajim.events.get_events(self.account, self.contact.jid)) | 		return len(gajim.events.get_events(self.account, self.contact.jid)) | ||||||
| 
 | 
 | ||||||
| 	def set_thread_id(self, thread_id): |  | ||||||
| 		if thread_id == self.thread_id: |  | ||||||
| 			return |  | ||||||
| 		if self.thread_id: |  | ||||||
| 			print "starting a new session, forgetting about the old one!" |  | ||||||
| 		self.thread_id = thread_id |  | ||||||
| 		self.contact.sessions[self.contact.get_full_jid()] = thread_id |  | ||||||
| 
 |  | ||||||
| 	def send_message(self, message, keyID = '', type = 'chat', | 	def send_message(self, message, keyID = '', type = 'chat', | ||||||
| 	chatstate = None, msg_id = None, composing_jep = None, resource = None, | 	chatstate = None, msg_id = None, composing_jep = None, resource = None, | ||||||
| 	user_nick = None): | 	user_nick = None): | ||||||
|  | @ -127,11 +117,8 @@ class MessageControl: | ||||||
| 		''' | 		''' | ||||||
| 		jid = self.contact.jid | 		jid = self.contact.jid | ||||||
| 
 | 
 | ||||||
| 		if not self.thread_id: |  | ||||||
| 			self.thread_id = self.contact.new_session() |  | ||||||
| 
 |  | ||||||
| 		# Send and update history | 		# Send and update history | ||||||
| 		return gajim.connections[self.account].send_message(jid, message, keyID, | 		return gajim.connections[self.account].send_message(jid, message, keyID, | ||||||
| 			type = type, chatstate = chatstate, msg_id = msg_id, | 			type = type, chatstate = chatstate, msg_id = msg_id, | ||||||
| 			composing_jep = composing_jep, resource = self.resource, | 			composing_jep = composing_jep, resource = self.resource, | ||||||
| 			user_nick = user_nick, thread = self.thread_id) | 			user_nick = user_nick, session = self.session) | ||||||
|  |  | ||||||
|  | @ -123,8 +123,9 @@ class MessageWindow: | ||||||
| 
 | 
 | ||||||
| 	def get_num_controls(self): | 	def get_num_controls(self): | ||||||
| 		n = 0 | 		n = 0 | ||||||
| 		for dict in self._controls.values(): | 		for sess_dict in self._controls.values(): | ||||||
| 			n += len(dict) | 			for dict in sess_dict.values(): | ||||||
|  | 				n += len(dict) | ||||||
| 		return n | 		return n | ||||||
| 
 | 
 | ||||||
| 	def _on_window_focus(self, widget, event): | 	def _on_window_focus(self, widget, event): | ||||||
|  | @ -165,7 +166,9 @@ class MessageWindow: | ||||||
| 		if not self._controls.has_key(control.account): | 		if not self._controls.has_key(control.account): | ||||||
| 			self._controls[control.account] = {} | 			self._controls[control.account] = {} | ||||||
| 		fjid = control.get_full_jid() | 		fjid = control.get_full_jid() | ||||||
| 		self._controls[control.account][fjid] = control | 		if not self._controls.has_key(fjid): | ||||||
|  | 			self._controls[control.account][fjid] = {} | ||||||
|  | 		self._controls[control.account][fjid][control.session.thread_id] = control | ||||||
| 
 | 
 | ||||||
| 		if self.get_num_controls() == 2: | 		if self.get_num_controls() == 2: | ||||||
| 			# is first conversation_textview scrolled down ? | 			# is first conversation_textview scrolled down ? | ||||||
|  | @ -292,11 +295,11 @@ class MessageWindow: | ||||||
| 		else: | 		else: | ||||||
| 			gtkgui_helpers.set_unset_urgency_hint(self.window, False) | 			gtkgui_helpers.set_unset_urgency_hint(self.window, False) | ||||||
| 
 | 
 | ||||||
| 	def set_active_tab(self, jid, acct): | 	def set_active_tab(self, jid, acct, thread_id): | ||||||
| 		ctrl = self._controls[acct][jid] | 		ctrl = self._controls[acct][jid][thread_id] | ||||||
| 		ctrl_page = self.notebook.page_num(ctrl.widget) | 		ctrl_page = self.notebook.page_num(ctrl.widget) | ||||||
| 		self.notebook.set_current_page(ctrl_page) | 		self.notebook.set_current_page(ctrl_page) | ||||||
| 	 | 
 | ||||||
| 	def remove_tab(self, ctrl, method, reason = None, force = False): | 	def remove_tab(self, ctrl, method, reason = None, force = False): | ||||||
| 		'''reason is only for gc (offline status message) | 		'''reason is only for gc (offline status message) | ||||||
| 		if force is True, do not ask any confirmation''' | 		if force is True, do not ask any confirmation''' | ||||||
|  | @ -317,7 +320,9 @@ class MessageWindow: | ||||||
| 		self.notebook.remove_page(self.notebook.page_num(ctrl.widget)) | 		self.notebook.remove_page(self.notebook.page_num(ctrl.widget)) | ||||||
| 
 | 
 | ||||||
| 		fjid = ctrl.get_full_jid() | 		fjid = ctrl.get_full_jid() | ||||||
| 		del self._controls[ctrl.account][fjid] | 		del self._controls[ctrl.account][fjid][ctrl.session.thread_id] | ||||||
|  | 		if len(self._controls[ctrl.account][fjid]) == 0: | ||||||
|  | 			del self._controls[ctrl.account][fjid] | ||||||
| 		if len(self._controls[ctrl.account]) == 0: | 		if len(self._controls[ctrl.account]) == 0: | ||||||
| 			del self._controls[ctrl.account] | 			del self._controls[ctrl.account] | ||||||
| 
 | 
 | ||||||
|  | @ -415,7 +420,19 @@ class MessageWindow: | ||||||
| 		for ctrl in self.controls(): | 		for ctrl in self.controls(): | ||||||
| 			ctrl.update_tags() | 			ctrl.update_tags() | ||||||
| 
 | 
 | ||||||
| 	def get_control(self, key, acct): | 	def has_control(self, jid, acct, thread_id = None): | ||||||
|  | 		try: | ||||||
|  | 			if thread_id: | ||||||
|  | 				return (thread_id in self._controls[acct][jid]) | ||||||
|  | 			else: | ||||||
|  | 				return (jid in self._controls[acct]) | ||||||
|  | 		except KeyError: | ||||||
|  | 			return False | ||||||
|  | 
 | ||||||
|  | 	def get_controls(self, jid, acct): | ||||||
|  | 		return self._controls[acct][jid].values() | ||||||
|  | 
 | ||||||
|  | 	def get_control(self, key, acct, thread_id): | ||||||
| 		'''Return the MessageControl for jid or n, where n is a notebook page index. | 		'''Return the MessageControl for jid or n, where n is a notebook page index. | ||||||
| 		When key is an int index acct may be None''' | 		When key is an int index acct may be None''' | ||||||
| 		if isinstance(key, str): | 		if isinstance(key, str): | ||||||
|  | @ -424,7 +441,7 @@ class MessageWindow: | ||||||
| 		if isinstance(key, unicode): | 		if isinstance(key, unicode): | ||||||
| 			jid = key | 			jid = key | ||||||
| 			try: | 			try: | ||||||
| 				return self._controls[acct][jid] | 				return self._controls[acct][jid][thread_id] | ||||||
| 			except: | 			except: | ||||||
| 				return None | 				return None | ||||||
| 		else: | 		else: | ||||||
|  | @ -436,9 +453,10 @@ class MessageWindow: | ||||||
| 			return self._widget_to_control(nth_child) | 			return self._widget_to_control(nth_child) | ||||||
| 
 | 
 | ||||||
| 	def controls(self): | 	def controls(self): | ||||||
| 		for ctrl_dict in self._controls.values(): | 		for jid_dict in self._controls.values(): | ||||||
| 			for ctrl in ctrl_dict.values(): | 			for sess_dict in jid_dict.values(): | ||||||
| 				yield ctrl | 				for ctrl in sess_dict.values(): | ||||||
|  | 					yield ctrl | ||||||
| 
 | 
 | ||||||
| 	def move_to_next_unread_tab(self, forward): | 	def move_to_next_unread_tab(self, forward): | ||||||
| 		ind = self.notebook.get_current_page() | 		ind = self.notebook.get_current_page() | ||||||
|  | @ -495,7 +513,7 @@ class MessageWindow: | ||||||
| 		if old_no >= 0: | 		if old_no >= 0: | ||||||
| 			old_ctrl = self._widget_to_control(notebook.get_nth_page(old_no)) | 			old_ctrl = self._widget_to_control(notebook.get_nth_page(old_no)) | ||||||
| 			old_ctrl.set_control_active(False) | 			old_ctrl.set_control_active(False) | ||||||
| 		 | 
 | ||||||
| 		new_ctrl = self._widget_to_control(notebook.get_nth_page(page_num)) | 		new_ctrl = self._widget_to_control(notebook.get_nth_page(page_num)) | ||||||
| 		new_ctrl.set_control_active(True) | 		new_ctrl.set_control_active(True) | ||||||
| 		self.show_title(control = new_ctrl) | 		self.show_title(control = new_ctrl) | ||||||
|  | @ -569,11 +587,11 @@ class MessageWindow: | ||||||
| 		source_child = self.notebook.get_nth_page(source_page_num) | 		source_child = self.notebook.get_nth_page(source_page_num) | ||||||
| 		if dest_page_num != source_page_num: | 		if dest_page_num != source_page_num: | ||||||
| 			self.notebook.reorder_child(source_child, dest_page_num) | 			self.notebook.reorder_child(source_child, dest_page_num) | ||||||
| 		 | 
 | ||||||
| 	def get_tab_at_xy(self, x, y): | 	def get_tab_at_xy(self, x, y): | ||||||
| 		'''Thanks to Gaim | 		'''Thanks to Gaim | ||||||
| 		Return the tab under xy and | 		Return the tab under xy and | ||||||
| 		if its nearer from left or right side of the tab	 | 		if its nearer from left or right side of the tab | ||||||
| 		''' | 		''' | ||||||
| 		page_num = -1 | 		page_num = -1 | ||||||
| 		to_right = False | 		to_right = False | ||||||
|  | @ -594,7 +612,7 @@ class MessageWindow: | ||||||
| 				if (y >= tab_alloc.y) and \ | 				if (y >= tab_alloc.y) and \ | ||||||
| 				(y <= (tab_alloc.y + tab_alloc.height)): | 				(y <= (tab_alloc.y + tab_alloc.height)): | ||||||
| 					page_num = i | 					page_num = i | ||||||
| 				 | 
 | ||||||
| 					if y > tab_alloc.y + (tab_alloc.height / 2.0): | 					if y > tab_alloc.y + (tab_alloc.height / 2.0): | ||||||
| 						to_right = True | 						to_right = True | ||||||
| 					break | 					break | ||||||
|  | @ -659,14 +677,22 @@ class MessageWindowMgr: | ||||||
| 				return w | 				return w | ||||||
| 		return None | 		return None | ||||||
| 
 | 
 | ||||||
| 	def get_window(self, jid, acct): | 	def get_window(self, jid, acct, thread_id): | ||||||
| 		for win in self.windows(): | 		for win in self.windows(): | ||||||
| 			if win.get_control(jid, acct): | 			if win.has_control(jid, acct, thread_id): | ||||||
| 				return win | 				return win | ||||||
| 		return None | 		return None | ||||||
| 
 | 
 | ||||||
| 	def has_window(self, jid, acct): | 	def get_windows(self, jid, acct): | ||||||
| 		return self.get_window(jid, acct) != None | 		for win in self.windows(): | ||||||
|  | 			if win.has_control(jid, acct): | ||||||
|  | 				yield win | ||||||
|  | 
 | ||||||
|  | 	def has_window(self, jid, acct, thread_id = None): | ||||||
|  | 		for win in self.windows(): | ||||||
|  | 			if win.has_control(jid, acct, thread_id): | ||||||
|  | 				return True | ||||||
|  | 		return False | ||||||
| 
 | 
 | ||||||
| 	def one_window_opened(self, contact, acct, type): | 	def one_window_opened(self, contact, acct, type): | ||||||
| 		try: | 		try: | ||||||
|  | @ -678,7 +704,7 @@ class MessageWindowMgr: | ||||||
| 		'''Resizes window according to config settings''' | 		'''Resizes window according to config settings''' | ||||||
| 		if not gajim.config.get('saveposition'): | 		if not gajim.config.get('saveposition'): | ||||||
| 			return | 			return | ||||||
| 			 | 
 | ||||||
| 		if self.mode == self.ONE_MSG_WINDOW_ALWAYS: | 		if self.mode == self.ONE_MSG_WINDOW_ALWAYS: | ||||||
| 			size = (gajim.config.get('msgwin-width'), | 			size = (gajim.config.get('msgwin-width'), | ||||||
| 				gajim.config.get('msgwin-height')) | 				gajim.config.get('msgwin-height')) | ||||||
|  | @ -695,7 +721,7 @@ class MessageWindowMgr: | ||||||
| 			return | 			return | ||||||
| 
 | 
 | ||||||
| 		gtkgui_helpers.resize_window(win.window, size[0], size[1]) | 		gtkgui_helpers.resize_window(win.window, size[0], size[1]) | ||||||
| 	 | 
 | ||||||
| 	def _position_window(self, win, acct, type): | 	def _position_window(self, win, acct, type): | ||||||
| 		'''Moves window according to config settings''' | 		'''Moves window according to config settings''' | ||||||
| 		if not gajim.config.get('saveposition') or\ | 		if not gajim.config.get('saveposition') or\ | ||||||
|  | @ -773,18 +799,20 @@ class MessageWindowMgr: | ||||||
| 				del self._windows[k] | 				del self._windows[k] | ||||||
| 				return | 				return | ||||||
| 
 | 
 | ||||||
| 	def get_control(self, jid, acct): | 	def get_control(self, jid, acct, thread_id): | ||||||
| 		'''Amongst all windows, return the MessageControl for jid''' | 		'''Amongst all windows, return the MessageControl for jid''' | ||||||
| 		win = self.get_window(jid, acct) | 		win = self.get_window(jid, acct, thread_id) | ||||||
| 		if win: | 		if win: | ||||||
| 			return win.get_control(jid, acct) | 			return win.get_control(jid, acct, thread_id) | ||||||
| 		return None | 		return None | ||||||
| 
 | 
 | ||||||
| 	def get_controls(self, type = None, acct = None): | 	def get_controls(self, type = None, acct = None, jid = None): | ||||||
| 		ctrls = [] | 		ctrls = [] | ||||||
| 		for c in self.controls(): | 		for c in self.controls(): | ||||||
| 			if acct and c.account != acct: | 			if acct and c.account != acct: | ||||||
| 				continue | 				continue | ||||||
|  | 			if jid and c.get_full_jid() != jid: | ||||||
|  | 				continue | ||||||
| 			if not type or c.type_id == type: | 			if not type or c.type_id == type: | ||||||
| 				ctrls.append(c) | 				ctrls.append(c) | ||||||
| 		return ctrls | 		return ctrls | ||||||
|  | @ -808,7 +836,7 @@ class MessageWindowMgr: | ||||||
| 	def save_state(self, msg_win): | 	def save_state(self, msg_win): | ||||||
| 		if not gajim.config.get('saveposition'): | 		if not gajim.config.get('saveposition'): | ||||||
| 			return | 			return | ||||||
| 		 | 
 | ||||||
| 		# Save window size and position | 		# Save window size and position | ||||||
| 		pos_x_key = 'msgwin-x-position' | 		pos_x_key = 'msgwin-x-position' | ||||||
| 		pos_y_key = 'msgwin-y-position' | 		pos_y_key = 'msgwin-y-position' | ||||||
|  | @ -843,11 +871,11 @@ class MessageWindowMgr: | ||||||
| 			if self.mode != self.ONE_MSG_WINDOW_NEVER: | 			if self.mode != self.ONE_MSG_WINDOW_NEVER: | ||||||
| 				gajim.config.set_per('accounts', acct, pos_x_key, x) | 				gajim.config.set_per('accounts', acct, pos_x_key, x) | ||||||
| 				gajim.config.set_per('accounts', acct, pos_y_key, y) | 				gajim.config.set_per('accounts', acct, pos_y_key, y) | ||||||
| 		 | 
 | ||||||
| 		else: | 		else: | ||||||
| 			gajim.config.set(size_width_key, width) | 			gajim.config.set(size_width_key, width) | ||||||
| 			gajim.config.set(size_height_key, height) | 			gajim.config.set(size_height_key, height) | ||||||
| 			 | 
 | ||||||
| 			if self.mode != self.ONE_MSG_WINDOW_NEVER: | 			if self.mode != self.ONE_MSG_WINDOW_NEVER: | ||||||
| 				gajim.config.set(pos_x_key, x) | 				gajim.config.set(pos_x_key, x) | ||||||
| 				gajim.config.set(pos_y_key, y) | 				gajim.config.set(pos_y_key, y) | ||||||
|  |  | ||||||
|  | @ -7,11 +7,11 @@ from common import xmpp | ||||||
| 
 | 
 | ||||||
| class FeatureNegotiationWindow: | class FeatureNegotiationWindow: | ||||||
| 	'''FeatureNegotiotionWindow class''' | 	'''FeatureNegotiotionWindow class''' | ||||||
| 	def __init__(self, account, jid, thread_id, form): | 	def __init__(self, account, jid, session, form): | ||||||
| 		self.account = account | 		self.account = account | ||||||
| 		self.jid = jid | 		self.jid = jid | ||||||
| 		self.form = form | 		self.form = form | ||||||
| 		self.thread_id = thread_id | 		self.session = session | ||||||
| 
 | 
 | ||||||
| 		self.xml = gtkgui_helpers.get_glade('data_form_window.glade', 'data_form_window') | 		self.xml = gtkgui_helpers.get_glade('data_form_window.glade', 'data_form_window') | ||||||
| 		self.window = self.xml.get_widget('data_form_window') | 		self.window = self.xml.get_widget('data_form_window') | ||||||
|  | @ -27,7 +27,7 @@ class FeatureNegotiationWindow: | ||||||
| 
 | 
 | ||||||
| 	def on_ok_button_clicked(self, widget): | 	def on_ok_button_clicked(self, widget): | ||||||
| 		acceptance = xmpp.Message(self.jid) | 		acceptance = xmpp.Message(self.jid) | ||||||
| 		acceptance.setThread(self.thread_id) | 		acceptance.setThread(self.session.thread_id) | ||||||
| 		feature = acceptance.NT.feature | 		feature = acceptance.NT.feature | ||||||
| 		feature.setNamespace(xmpp.NS_FEATURE) | 		feature.setNamespace(xmpp.NS_FEATURE) | ||||||
| 
 | 
 | ||||||
|  | @ -44,7 +44,7 @@ class FeatureNegotiationWindow: | ||||||
| 		# XXX determine whether to reveal presence | 		# XXX determine whether to reveal presence | ||||||
| 
 | 
 | ||||||
| 		rejection = xmpp.Message(self.jid) | 		rejection = xmpp.Message(self.jid) | ||||||
| 		rejection.setThread(self.thread_id) | 		rejection.setThread(self.session.thread_id) | ||||||
| 		feature = rejection.NT.feature | 		feature = rejection.NT.feature | ||||||
| 		feature.setNamespace(xmpp.NS_FEATURE) | 		feature.setNamespace(xmpp.NS_FEATURE) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ try: | ||||||
| except ImportError: | except ImportError: | ||||||
| 	USER_HAS_PYNOTIFY = False | 	USER_HAS_PYNOTIFY = False | ||||||
| 
 | 
 | ||||||
| def get_show_in_roster(event, account, contact): | def get_show_in_roster(event, account, contact, session): | ||||||
| 	'''Return True if this event must be shown in roster, else False''' | 	'''Return True if this event must be shown in roster, else False''' | ||||||
| 	if event == 'gc_message_received': | 	if event == 'gc_message_received': | ||||||
| 		return True | 		return True | ||||||
|  | @ -51,7 +51,7 @@ def get_show_in_roster(event, account, contact): | ||||||
| 		if gajim.config.get_per('notifications', str(num), 'roster') == 'no': | 		if gajim.config.get_per('notifications', str(num), 'roster') == 'no': | ||||||
| 			return False | 			return False | ||||||
| 	if event == 'message_received': | 	if event == 'message_received': | ||||||
| 		chat_control = helpers.get_chat_control(account, contact) | 		chat_control = helpers.get_chat_control(account, contact, session) | ||||||
| 		if chat_control: | 		if chat_control: | ||||||
| 			return False | 			return False | ||||||
| 	return True | 	return True | ||||||
|  |  | ||||||
|  | @ -1190,10 +1190,14 @@ class RosterWindow: | ||||||
| 		'''reads from db the unread messages, and fire them up''' | 		'''reads from db the unread messages, and fire them up''' | ||||||
| 		for jid in gajim.contacts.get_jid_list(account): | 		for jid in gajim.contacts.get_jid_list(account): | ||||||
| 			results = gajim.logger.get_unread_msgs_for_jid(jid) | 			results = gajim.logger.get_unread_msgs_for_jid(jid) | ||||||
|  | 
 | ||||||
|  | 			# XXX results should contain sessions anyways | ||||||
|  | 			session = gajim.connections[account].make_new_session(jid) | ||||||
|  | 
 | ||||||
| 			for result in results: | 			for result in results: | ||||||
| 				tim = time.localtime(float(result[2])) | 				tim = time.localtime(float(result[2])) | ||||||
| 				self.on_message(jid, result[1], tim, account, msg_type = 'chat', | 				self.on_message(jid, result[1], tim, account, msg_type = 'chat', | ||||||
| 					msg_id = result[0]) | 					msg_id = result[0], session = session) | ||||||
| 
 | 
 | ||||||
| 	def fill_contacts_and_groups_dicts(self, array, account): | 	def fill_contacts_and_groups_dicts(self, array, account): | ||||||
| 		'''fill gajim.contacts and gajim.groups''' | 		'''fill gajim.contacts and gajim.groups''' | ||||||
|  | @ -1255,8 +1259,8 @@ class RosterWindow: | ||||||
| 							gajim.transport_avatar[account][host].append(contact1.jid) | 							gajim.transport_avatar[account][host].append(contact1.jid) | ||||||
| 			# If we already have a chat window opened, update it with new contact | 			# If we already have a chat window opened, update it with new contact | ||||||
| 			# instance | 			# instance | ||||||
| 			chat_control = gajim.interface.msg_win_mgr.get_control(ji, account) | 			chat_controls = gajim.interface.msg_win_mgr.get_controls(jid=ji, acct=account) | ||||||
| 			if chat_control: | 			for chat_control in chat_controls: | ||||||
| 				chat_control.contact = contact1 | 				chat_control.contact = contact1 | ||||||
| 
 | 
 | ||||||
| 	def chg_contact_status(self, contact, show, status, account): | 	def chg_contact_status(self, contact, show, status, account): | ||||||
|  | @ -1283,14 +1287,14 @@ class RosterWindow: | ||||||
| 		jid_list = [contact.jid] | 		jid_list = [contact.jid] | ||||||
| 		for jid in jid_list: | 		for jid in jid_list: | ||||||
| 			if gajim.interface.msg_win_mgr.has_window(jid, account): | 			if gajim.interface.msg_win_mgr.has_window(jid, account): | ||||||
| 				win = gajim.interface.msg_win_mgr.get_window(jid, account) | 				for win in gajim.interface.msg_win_mgr.get_windows(jid, account): | ||||||
| 				ctrl = win.get_control(jid, account) | 					for ctrl in win.get_controls(jid=jid, acct=account): | ||||||
| 				ctrl.contact = gajim.contacts.get_contact_with_highest_priority( | 						ctrl.contact = gajim.contacts.get_contact_with_highest_priority( | ||||||
| 					account, contact.jid) | 							account, contact.jid) | ||||||
| 				ctrl.update_ui() | 						ctrl.update_ui() | ||||||
| 				win.redraw_tab(ctrl) | 					win.redraw_tab(ctrl) | ||||||
| 
 | 
 | ||||||
| 				name = contact.get_shown_name() | 					name = contact.get_shown_name() | ||||||
| 
 | 
 | ||||||
| 				# if multiple resources (or second one disconnecting) | 				# if multiple resources (or second one disconnecting) | ||||||
| 				if (len(contact_instances) > 1 or (len(contact_instances) == 1 and \ | 				if (len(contact_instances) > 1 or (len(contact_instances) == 1 and \ | ||||||
|  | @ -3477,18 +3481,22 @@ class RosterWindow: | ||||||
| 			# We call this here to avoid race conditions with widget validation | 			# We call this here to avoid race conditions with widget validation | ||||||
| 			chat_control.read_queue() | 			chat_control.read_queue() | ||||||
| 
 | 
 | ||||||
| 	def new_chat(self, contact, account, resource = None): | 	def new_chat(self, contact, account, resource = None, session = None): | ||||||
| 		# Get target window, create a control, and associate it with the window | 		# Get target window, create a control, and associate it with the window | ||||||
| 		type_ = message_control.TYPE_CHAT | 		type_ = message_control.TYPE_CHAT | ||||||
| 
 | 
 | ||||||
| 		fjid = contact.jid | 		fjid = contact.jid | ||||||
| 		if resource: | 		if resource: | ||||||
| 			fjid += '/' + resource | 			fjid += '/' + resource | ||||||
| 		mw = gajim.interface.msg_win_mgr.get_window(fjid, account) | 
 | ||||||
|  | 		if not session: | ||||||
|  | 			session = gajim.connections[account].make_new_session(fjid) | ||||||
|  | 
 | ||||||
|  | 		mw = gajim.interface.msg_win_mgr.get_window(fjid, account, session.thread_id) | ||||||
| 		if not mw: | 		if not mw: | ||||||
| 			mw = gajim.interface.msg_win_mgr.create_window(contact, account, type_) | 			mw = gajim.interface.msg_win_mgr.create_window(contact, account, type_) | ||||||
| 
 | 
 | ||||||
| 		chat_control = ChatControl(mw, contact, account, resource) | 		chat_control = ChatControl(mw, contact, account, session, resource) | ||||||
| 
 | 
 | ||||||
| 		mw.new_tab(chat_control) | 		mw.new_tab(chat_control) | ||||||
| 
 | 
 | ||||||
|  | @ -3496,6 +3504,8 @@ class RosterWindow: | ||||||
| 			# We call this here to avoid race conditions with widget validation | 			# We call this here to avoid race conditions with widget validation | ||||||
| 			chat_control.read_queue() | 			chat_control.read_queue() | ||||||
| 
 | 
 | ||||||
|  | 		return session | ||||||
|  | 
 | ||||||
| 	def new_chat_from_jid(self, account, fjid): | 	def new_chat_from_jid(self, account, fjid): | ||||||
| 		jid, resource = gajim.get_room_and_nick_from_fjid(fjid) | 		jid, resource = gajim.get_room_and_nick_from_fjid(fjid) | ||||||
| 		if resource: | 		if resource: | ||||||
|  | @ -3531,7 +3541,7 @@ class RosterWindow: | ||||||
| 
 | 
 | ||||||
| 	def on_message(self, jid, msg, tim, account, encrypted = False, | 	def on_message(self, jid, msg, tim, account, encrypted = False, | ||||||
| 			msg_type = '', subject = None, resource = '', msg_id = None, | 			msg_type = '', subject = None, resource = '', msg_id = None, | ||||||
| 			user_nick = '', advanced_notif_num = None, xhtml = None, thread = None): | 			user_nick = '', advanced_notif_num = None, xhtml = None, session = None): | ||||||
| 		'''when we receive a message''' | 		'''when we receive a message''' | ||||||
| 		contact = None | 		contact = None | ||||||
| 		# if chat window will be for specific resource | 		# if chat window will be for specific resource | ||||||
|  | @ -3569,16 +3579,18 @@ class RosterWindow: | ||||||
| 
 | 
 | ||||||
| 		path = self.get_path(jid, account) # Try to get line of contact in roster | 		path = self.get_path(jid, account) # Try to get line of contact in roster | ||||||
| 
 | 
 | ||||||
|  | 		ctrl = session.get_control(advanced_notif_num) | ||||||
|  | 
 | ||||||
| 		# Look for a chat control that has the given resource | 		# Look for a chat control that has the given resource | ||||||
| 		ctrl = gajim.interface.msg_win_mgr.get_control(fjid, account) | #		ctrl = gajim.interface.msg_win_mgr.get_control(fjid, account) | ||||||
| 		if not ctrl: | #		if not ctrl: | ||||||
| 			# if not, if message comes from highest prio, get control or open one | 			# if not, if message comes from highest prio, get control or open one | ||||||
| 			# without resource | 			# without resource | ||||||
| 			if highest_contact and contact.resource == highest_contact.resource \ | #			if highest_contact and contact.resource == highest_contact.resource \ | ||||||
| 			and not jid == gajim.get_jid_from_account(account): | #			and not jid == gajim.get_jid_from_account(account): | ||||||
| 				ctrl = gajim.interface.msg_win_mgr.get_control(jid, account) | #				ctrl = gajim.interface.msg_win_mgr.get_control(jid, account) | ||||||
| 				fjid = jid | #				fjid = jid | ||||||
| 				resource_for_chat = None | #				resource_for_chat = None | ||||||
| 
 | 
 | ||||||
| 		# Do we have a queue? | 		# Do we have a queue? | ||||||
| 		no_queue = len(gajim.events.get_events(account, fjid)) == 0 | 		no_queue = len(gajim.events.get_events(account, fjid)) == 0 | ||||||
|  | @ -3588,7 +3600,7 @@ class RosterWindow: | ||||||
| 		if msg_type == 'normal' and popup: # it's single message to be autopopuped | 		if msg_type == 'normal' and popup: # it's single message to be autopopuped | ||||||
| 			dialogs.SingleMessageWindow(account, contact.jid, | 			dialogs.SingleMessageWindow(account, contact.jid, | ||||||
| 				action = 'receive', from_whom = jid, subject = subject, | 				action = 'receive', from_whom = jid, subject = subject, | ||||||
| 				message = msg, resource = resource, thread = thread) | 				message = msg, resource = resource, session = session) | ||||||
| 			return | 			return | ||||||
| 
 | 
 | ||||||
| 		# We print if window is opened and it's not a single message | 		# We print if window is opened and it's not a single message | ||||||
|  | @ -3596,8 +3608,6 @@ class RosterWindow: | ||||||
| 			typ = '' | 			typ = '' | ||||||
| 			if msg_type == 'error': | 			if msg_type == 'error': | ||||||
| 				typ = 'status' | 				typ = 'status' | ||||||
| 			if thread: |  | ||||||
| 				ctrl.set_thread_id(thread) |  | ||||||
| 			ctrl.print_conversation(msg, typ, tim = tim, encrypted = encrypted, | 			ctrl.print_conversation(msg, typ, tim = tim, encrypted = encrypted, | ||||||
| 						subject = subject, xhtml = xhtml) | 						subject = subject, xhtml = xhtml) | ||||||
| 			if msg_id: | 			if msg_id: | ||||||
|  | @ -3610,26 +3620,26 @@ class RosterWindow: | ||||||
| 		if msg_type == 'normal': | 		if msg_type == 'normal': | ||||||
| 			type_ = 'normal' | 			type_ = 'normal' | ||||||
| 			event_type = 'single_message_received' | 			event_type = 'single_message_received' | ||||||
| 		show_in_roster = notify.get_show_in_roster(event_type, account, contact) | 		show_in_roster = notify.get_show_in_roster(event_type, account, contact, session) | ||||||
| 		show_in_systray = notify.get_show_in_systray(event_type, account, contact) | 		show_in_systray = notify.get_show_in_systray(event_type, account, contact) | ||||||
| 		event = gajim.events.create_event(type_, (msg, subject, msg_type, tim, | 		event = gajim.events.create_event(type_, (msg, subject, msg_type, tim, | ||||||
| 			encrypted, resource, msg_id, xhtml, thread), show_in_roster = show_in_roster, | 			encrypted, resource, msg_id, xhtml, session), show_in_roster = show_in_roster, | ||||||
| 			show_in_systray = show_in_systray) | 			show_in_systray = show_in_systray) | ||||||
| 		gajim.events.add_event(account, fjid, event) | 		gajim.events.add_event(account, fjid, event) | ||||||
| 		if popup: | #		if popup: | ||||||
| 			if not ctrl: | #			if not ctrl: | ||||||
| 				self.new_chat(contact, account, resource = resource_for_chat) | #				self.new_chat(contact, account, resource = resource_for_chat) | ||||||
| 				if path and not self.dragging and gajim.config.get( | #				if path and not self.dragging and gajim.config.get( | ||||||
| 				'scroll_roster_to_last_message'): | #				'scroll_roster_to_last_message'): | ||||||
| 					# we curently see contact in our roster OR he | #					# we curently see contact in our roster OR he | ||||||
| 					# is not in the roster at all.  | #					# is not in the roster at all.  | ||||||
| 					# show and select his line in roster  | 					# show and select his line in roster  | ||||||
| 					# do not change selection while DND'ing | 					# do not change selection while DND'ing | ||||||
| 					self.tree.expand_row(path[0:1], False) | #					self.tree.expand_row(path[0:1], False) | ||||||
| 					self.tree.expand_row(path[0:2], False) | #					self.tree.expand_row(path[0:2], False) | ||||||
| 					self.tree.scroll_to_cell(path) | #					self.tree.scroll_to_cell(path) | ||||||
| 					self.tree.set_cursor(path) | #					self.tree.set_cursor(path) | ||||||
| 		else: | 		if not popup: | ||||||
| 			if no_queue: # We didn't have a queue: we change icons | 			if no_queue: # We didn't have a queue: we change icons | ||||||
| 				self.draw_contact(jid, account) | 				self.draw_contact(jid, account) | ||||||
| 			self.show_title() # we show the * or [n] | 			self.show_title() # we show the * or [n] | ||||||
|  | @ -3875,7 +3885,7 @@ class RosterWindow: | ||||||
| 		if event.type_ == 'normal': | 		if event.type_ == 'normal': | ||||||
| 			dialogs.SingleMessageWindow(account, jid, | 			dialogs.SingleMessageWindow(account, jid, | ||||||
| 				action = 'receive', from_whom = jid, subject = data[1], | 				action = 'receive', from_whom = jid, subject = data[1], | ||||||
| 				message = data[0], resource = data[5], thread = data[8]) | 				message = data[0], resource = data[5], session = data[8]) | ||||||
| 			gajim.interface.remove_first_event(account, jid, event.type_) | 			gajim.interface.remove_first_event(account, jid, event.type_) | ||||||
| 			return True | 			return True | ||||||
| 		elif event.type_ == 'file-request': | 		elif event.type_ == 'file-request': | ||||||
|  | @ -3912,22 +3922,22 @@ class RosterWindow: | ||||||
| 			jid = jid + u'/' + resource | 			jid = jid + u'/' + resource | ||||||
| 		adhoc_commands.CommandWindow(account, jid) | 		adhoc_commands.CommandWindow(account, jid) | ||||||
| 
 | 
 | ||||||
| 	def on_open_chat_window(self, widget, contact, account, resource = None): | 	def on_open_chat_window(self, widget, contact, account, resource = None, session = None): | ||||||
| 		# Get the window containing the chat | 		# Get the window containing the chat | ||||||
| 		fjid = contact.jid | 		fjid = contact.jid | ||||||
| 		if resource: | 		if resource: | ||||||
| 			fjid += '/' + resource | 			fjid += '/' + resource | ||||||
| 		win = gajim.interface.msg_win_mgr.get_window(fjid, account) | 
 | ||||||
| 		if not win: | 		session = self.new_chat(contact, account, resource=resource, session=session) | ||||||
| 			self.new_chat(contact, account, resource = resource) | 		win = gajim.interface.msg_win_mgr.get_window(fjid, account, session.thread_id) | ||||||
| 			win = gajim.interface.msg_win_mgr.get_window(fjid, account) | 		ctrl = win.get_control(fjid, account, session.thread_id) | ||||||
| 			ctrl = win.get_control(fjid, account) | 		# last message is long time ago | ||||||
| 			# last message is long time ago | 		gajim.last_message_time[account][ctrl.get_full_jid()] = 0 | ||||||
| 			gajim.last_message_time[account][ctrl.get_full_jid()] = 0 | 
 | ||||||
| 		win.set_active_tab(fjid, account) | 		win.set_active_tab(fjid, account, session.thread_id) | ||||||
| 		if gajim.connections[account].is_zeroconf and \ | 		if gajim.connections[account].is_zeroconf and \ | ||||||
| 				gajim.connections[account].status in ('offline', 'invisible'): | 				gajim.connections[account].status in ('offline', 'invisible'): | ||||||
| 			win.get_control(fjid, account).got_disconnected() | 			win.get_control(fjid, account, session.thread_id).got_disconnected() | ||||||
| 
 | 
 | ||||||
| 		win.window.present() | 		win.window.present() | ||||||
| 
 | 
 | ||||||
|  | @ -3967,7 +3977,10 @@ class RosterWindow: | ||||||
| 						jid = child_jid | 						jid = child_jid | ||||||
| 					else: | 					else: | ||||||
| 						child_iter = model.iter_next(child_iter) | 						child_iter = model.iter_next(child_iter) | ||||||
|  | 
 | ||||||
|  | 			session = None | ||||||
| 			if first_ev: | 			if first_ev: | ||||||
|  | 				session = first_ev.parameters[8] | ||||||
| 				fjid = jid | 				fjid = jid | ||||||
| 				if resource: | 				if resource: | ||||||
| 					fjid += '/' + resource | 					fjid += '/' + resource | ||||||
|  | @ -3978,7 +3991,7 @@ class RosterWindow: | ||||||
| 				c = gajim.contacts.get_contact_with_highest_priority(account, jid) | 				c = gajim.contacts.get_contact_with_highest_priority(account, jid) | ||||||
| 			if jid == gajim.get_jid_from_account(account): | 			if jid == gajim.get_jid_from_account(account): | ||||||
| 				resource = c.resource | 				resource = c.resource | ||||||
| 			self.on_open_chat_window(widget, c, account, resource = resource) | 			self.on_open_chat_window(widget, c, account, resource = resource, session=session) | ||||||
| 
 | 
 | ||||||
| 	def on_roster_treeview_row_activated(self, widget, path, col = 0): | 	def on_roster_treeview_row_activated(self, widget, path, col = 0): | ||||||
| 		'''When an iter is double clicked: open the first event window''' | 		'''When an iter is double clicked: open the first event window''' | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue