massive everything-breaking overhaul for per-session windows

This commit is contained in:
Brendan Taylor 2007-06-05 21:26:45 +00:00
parent d696f79c55
commit 17c5bf5e52
13 changed files with 319 additions and 188 deletions

View file

@ -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,

View file

@ -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:

View file

@ -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

View file

@ -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,

View file

@ -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

View 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

View file

@ -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()

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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'''