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