XEP-0308 Last Message Correction support.

This commit is contained in:
Yann Leboulanger 2013-04-25 20:38:18 +02:00
parent c6c3f2636b
commit f0a4094cc9
8 changed files with 307 additions and 75 deletions

View File

@ -344,13 +344,13 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if resource is None: if resource is None:
# We very likely got a contact with a random resource. # We very likely got a contact with a random resource.
# This is bad, we need the highest for caps etc. # This is bad, we need the highest for caps etc.
c = gajim.contacts.get_contact_with_highest_priority( c = gajim.contacts.get_contact_with_highest_priority(acct,
acct, contact.jid) contact.jid)
if c and not isinstance(c, GC_Contact): if c and not isinstance(c, GC_Contact):
contact = c contact = c
MessageControl.__init__(self, type_id, parent_win, widget_name, MessageControl.__init__(self, type_id, parent_win, widget_name,
contact, acct, resource=resource) contact, acct, resource=resource)
widget = self.xml.get_object('history_button') widget = self.xml.get_object('history_button')
# set document-open-recent icon for history button # set document-open-recent icon for history button
@ -369,15 +369,15 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
# Create banner and connect signals # Create banner and connect signals
widget = self.xml.get_object('banner_eventbox') widget = self.xml.get_object('banner_eventbox')
id_ = widget.connect('button-press-event', id_ = widget.connect('button-press-event',
self._on_banner_eventbox_button_press_event) self._on_banner_eventbox_button_press_event)
self.handlers[id_] = widget self.handlers[id_] = widget
self.urlfinder = re.compile( self.urlfinder = re.compile(
r"(www\.(?!\.)|[a-z][a-z0-9+.-]*://)[^\s<>'\"]+[^!,\.\s<>\)'\"\]]") r"(www\.(?!\.)|[a-z][a-z0-9+.-]*://)[^\s<>'\"]+[^!,\.\s<>\)'\"\]]")
self.banner_status_label = self.xml.get_object('banner_label') self.banner_status_label = self.xml.get_object('banner_label')
id_ = self.banner_status_label.connect('populate_popup', id_ = self.banner_status_label.connect('populate_popup',
self.on_banner_label_populate_popup) self.on_banner_label_populate_popup)
self.handlers[id_] = self.banner_status_label self.handlers[id_] = self.banner_status_label
# Init DND # Init DND
@ -397,34 +397,38 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
id_ = self.conv_textview.connect('quote', self.on_quote) id_ = self.conv_textview.connect('quote', self.on_quote)
self.handlers[id_] = self.conv_textview.tv self.handlers[id_] = self.conv_textview.tv
id_ = self.conv_textview.tv.connect('key_press_event', id_ = self.conv_textview.tv.connect('key_press_event',
self._conv_textview_key_press_event) self._conv_textview_key_press_event)
self.handlers[id_] = self.conv_textview.tv self.handlers[id_] = self.conv_textview.tv
# FIXME: DND on non editable TextView, find a better way # FIXME: DND on non editable TextView, find a better way
self.drag_entered = False self.drag_entered = False
id_ = self.conv_textview.tv.connect('drag_data_received', id_ = self.conv_textview.tv.connect('drag_data_received',
self._on_drag_data_received) self._on_drag_data_received)
self.handlers[id_] = self.conv_textview.tv self.handlers[id_] = self.conv_textview.tv
id_ = self.conv_textview.tv.connect('drag_motion', self._on_drag_motion) id_ = self.conv_textview.tv.connect('drag_motion', self._on_drag_motion)
self.handlers[id_] = self.conv_textview.tv self.handlers[id_] = self.conv_textview.tv
id_ = self.conv_textview.tv.connect('drag_leave', self._on_drag_leave) id_ = self.conv_textview.tv.connect('drag_leave', self._on_drag_leave)
self.handlers[id_] = self.conv_textview.tv self.handlers[id_] = self.conv_textview.tv
self.conv_textview.tv.drag_dest_set(Gtk.DestDefaults.MOTION | self.conv_textview.tv.drag_dest_set(Gtk.DestDefaults.MOTION |
Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP,
Gtk.DestDefaults.DROP, self.dnd_list, Gdk.DragAction.COPY)
self.dnd_list, Gdk.DragAction.COPY)
self.conv_scrolledwindow = self.xml.get_object( self.conv_scrolledwindow = self.xml.get_object(
'conversation_scrolledwindow') 'conversation_scrolledwindow')
self.conv_scrolledwindow.add(self.conv_textview.tv) self.conv_scrolledwindow.add(self.conv_textview.tv)
widget = self.conv_scrolledwindow.get_vadjustment() widget = self.conv_scrolledwindow.get_vadjustment()
id_ = widget.connect('value-changed', id_ = widget.connect('value-changed',
self.on_conversation_vadjustment_value_changed) self.on_conversation_vadjustment_value_changed)
self.handlers[id_] = widget self.handlers[id_] = widget
id_ = widget.connect('changed', id_ = widget.connect('changed',
self.on_conversation_vadjustment_changed) self.on_conversation_vadjustment_changed)
self.handlers[id_] = widget self.handlers[id_] = widget
self.scroll_to_end_id = None self.scroll_to_end_id = None
self.was_at_the_end = True self.was_at_the_end = True
self.correcting = False
self.last_sent_msg = None
self.last_sent_txt = None
self.last_received_txt = {} # one per name
self.last_received_id = {} # one per name
# add MessageTextView to UI and connect signals # add MessageTextView to UI and connect signals
self.msg_scrolledwindow = self.xml.get_object('message_scrolledwindow') self.msg_scrolledwindow = self.xml.get_object('message_scrolledwindow')
@ -928,12 +932,23 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
label = self.get_seclabel() label = self.get_seclabel()
def _cb(msg, cb, *cb_args):
self.last_sent_msg = msg
self.last_sent_txt = cb_args[1]
if cb:
cb(msg, *cb_args)
if self.correcting and self.last_sent_msg:
correction_msg = self.last_sent_msg
else:
correction_msg = None
gajim.nec.push_outgoing_event(MessageOutgoingEvent(None, gajim.nec.push_outgoing_event(MessageOutgoingEvent(None,
account=self.account, jid=self.contact.jid, message=message, account=self.account, jid=self.contact.jid, message=message,
keyID=keyID, type_=type_, chatstate=chatstate, msg_id=msg_id, keyID=keyID, type_=type_, chatstate=chatstate, msg_id=msg_id,
resource=resource, user_nick=self.user_nick, xhtml=xhtml, resource=resource, user_nick=self.user_nick, xhtml=xhtml,
label=label, callback=callback, callback_args=callback_args, label=label, callback=_cb, callback_args=[callback] + callback_args,
control=self, attention=attention)) control=self, attention=attention, correction_msg=correction_msg))
# Record the history of sent messages # Record the history of sent messages
self.save_message(message, 'sent') self.save_message(message, 'sent')
@ -974,9 +989,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
def print_conversation_line(self, text, kind, name, tim, def print_conversation_line(self, text, kind, name, tim,
other_tags_for_name=[], other_tags_for_time=[], other_tags_for_text=[], other_tags_for_name=[], other_tags_for_time=[], other_tags_for_text=[],
count_as_new=True, subject=None, old_kind=None, xhtml=None, simple=False, count_as_new=True, subject=None, old_kind=None, xhtml=None, simple=False,
xep0184_id=None, graphics=True, displaymarking=None, msg_id=None): xep0184_id=None, graphics=True, displaymarking=None, msg_id=None,
correct_id=None):
""" """
Print 'chat' type messages Print 'chat' type messages
correct_id = (message_id, correct_id)
""" """
jid = self.contact.jid jid = self.contact.jid
full_jid = self.get_full_jid() full_jid = self.get_full_jid()
@ -984,16 +1001,28 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
end = False end = False
if self.was_at_the_end or kind == 'outgoing': if self.was_at_the_end or kind == 'outgoing':
end = True end = True
textview.print_conversation_line(text, jid, kind, name, tim, old_txt = ''
other_tags_for_name, other_tags_for_time, other_tags_for_text, if name in self.last_received_txt:
subject, old_kind, xhtml, simple=simple, graphics=graphics, old_txt = self.last_received_txt[name]
displaymarking=displaymarking) if correct_id and correct_id[1] and \
name in self.conv_textview.last_received_message_marks and \
correct_id[1] == self.last_received_id[name]:
self.conv_textview.correct_last_received_message(text, xhtml,
name, old_txt)
else:
textview.print_conversation_line(text, jid, kind, name, tim,
other_tags_for_name, other_tags_for_time, other_tags_for_text,
subject, old_kind, xhtml, simple=simple, graphics=graphics,
displaymarking=displaymarking)
if xep0184_id is not None: if xep0184_id is not None:
textview.show_xep0184_warning(xep0184_id) textview.show_xep0184_warning(xep0184_id)
if not count_as_new: if not count_as_new:
return return
if kind in ('incoming', 'outgoing'):
self.last_received_txt[name] = text
self.last_received_id[name] = correct_id[0]
if kind == 'incoming': if kind == 'incoming':
if not self.type_id == message_control.TYPE_GC or \ if not self.type_id == message_control.TYPE_GC or \
gajim.config.get('notify_on_all_muc_messages') or \ gajim.config.get('notify_on_all_muc_messages') or \
@ -1407,6 +1436,21 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
start_iter = msg_buf.get_start_iter() start_iter = msg_buf.get_start_iter()
end_iter = msg_buf.get_end_iter() end_iter = msg_buf.get_end_iter()
self.orig_msg = msg_buf.get_text(start_iter, end_iter, False) self.orig_msg = msg_buf.get_text(start_iter, end_iter, False)
if pos == size and size > 0 and direction == 'up' and \
msg_type == 'sent' and not self.correcting:
self.correcting = True
self.old_message_tv_color = self.msg_textview.get_style().base[
Gtk.StateType.NORMAL]
self.msg_textview.modify_base(Gtk.StateType.NORMAL, Gdk.color_parse(
'PaleGoldenrod'))
message = history[pos - 1]
msg_buf.set_text(message)
return
if self.correcting:
# We were previously correcting
self.msg_textview.modify_base(Gtk.StateType.NORMAL,
self.old_message_tv_color)
self.correcting = False
pos += -1 if direction == 'up' else +1 pos += -1 if direction == 'up' else +1
if pos == -1: if pos == -1:
return return
@ -1492,6 +1536,8 @@ class ChatControl(ChatControlBase):
'chat_control', contact, acct, resource) 'chat_control', contact, acct, resource)
self.gpg_is_active = False self.gpg_is_active = False
self.last_recv_message_id = None
self.last_recv_message_marks = None
# for muc use: # for muc use:
# widget = self.xml.get_object('muc_window_actions_button') # widget = self.xml.get_object('muc_window_actions_button')
self.actions_button = self.xml.get_object('message_window_actions_button') self.actions_button = self.xml.get_object('message_window_actions_button')
@ -2355,7 +2401,8 @@ class ChatControl(ChatControlBase):
GObject.source_remove(self.possible_inactive_timeout_id) GObject.source_remove(self.possible_inactive_timeout_id)
self._schedule_activity_timers() self._schedule_activity_timers()
def _on_sent(id_, contact, message, encrypted, xhtml, label): def _on_sent(msg, contact, message, encrypted, xhtml, label, old_txt):
id_ = msg.getID()
if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts', if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts',
self.account, 'request_receipt'): self.account, 'request_receipt'):
xep0184_id = id_ xep0184_id = id_
@ -2365,13 +2412,22 @@ class ChatControl(ChatControlBase):
displaymarking = label.getTag('displaymarking') displaymarking = label.getTag('displaymarking')
else: else:
displaymarking = None displaymarking = None
self.print_conversation(message, self.contact.jid, encrypted=encrypted, if self.correcting and \
xep0184_id=xep0184_id, xhtml=xhtml, displaymarking=displaymarking) self.conv_textview.last_sent_message_marks[0]:
self.conv_textview.correct_last_sent_message(message, xhtml,
self.get_our_nick(), old_txt)
self.correcting = False
self.msg_textview.modify_base(Gtk.StateType.NORMAL,
self.old_message_tv_color)
return
self.print_conversation(message, self.contact.jid,
encrypted=encrypted, xep0184_id=xep0184_id, xhtml=xhtml,
displaymarking=displaymarking)
ChatControlBase.send_message(self, message, keyID, type_='chat', ChatControlBase.send_message(self, message, keyID, type_='chat',
chatstate=chatstate_to_send, xhtml=xhtml, callback=_on_sent, chatstate=chatstate_to_send, xhtml=xhtml, callback=_on_sent,
callback_args=[contact, message, encrypted, xhtml, callback_args=[contact, message, encrypted, xhtml,
self.get_seclabel()], process_commands=process_commands, self.get_seclabel(), self.last_sent_txt], process_commands=process_commands,
attention=attention) attention=attention)
def check_for_possible_paused_chatstate(self, arg): def check_for_possible_paused_chatstate(self, arg):
@ -2483,7 +2539,7 @@ class ChatControl(ChatControlBase):
def print_conversation(self, text, frm='', tim=None, encrypted=False, def print_conversation(self, text, frm='', tim=None, encrypted=False,
subject=None, xhtml=None, simple=False, xep0184_id=None, subject=None, xhtml=None, simple=False, xep0184_id=None,
displaymarking=None, msg_id=None): displaymarking=None, msg_id=None, correct_id=None):
""" """
Print a line in the conversation Print a line in the conversation
@ -2548,7 +2604,7 @@ class ChatControl(ChatControlBase):
ChatControlBase.print_conversation_line(self, text, kind, name, tim, ChatControlBase.print_conversation_line(self, text, kind, name, tim,
subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml, subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml,
simple=simple, xep0184_id=xep0184_id, displaymarking=displaymarking, simple=simple, xep0184_id=xep0184_id, displaymarking=displaymarking,
msg_id=msg_id) msg_id=msg_id, correct_id=correct_id)
if text.startswith('/me ') or text.startswith('/me\n'): if text.startswith('/me ') or text.startswith('/me\n'):
self.old_msg_kind = None self.old_msg_kind = None
else: else:

View File

@ -254,9 +254,11 @@ class CommonConnection:
def _prepare_message(self, jid, msg, keyID, type_='chat', subject='', def _prepare_message(self, jid, msg, keyID, type_='chat', subject='',
chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None, chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None,
session=None, forward_from=None, form_node=None, label=None, session=None, forward_from=None, form_node=None, label=None,
original_message=None, delayed=None, attention=False, callback=None): original_message=None, delayed=None, attention=False, correction_msg=None,
callback=None):
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
return 1 return 1
try: try:
jid = self.check_jid(jid) jid = self.check_jid(jid)
except helpers.InvalidFormat: except helpers.InvalidFormat:
@ -306,7 +308,7 @@ class CommonConnection:
jid, xhtml, subject, chatstate, msg_id, jid, xhtml, subject, chatstate, msg_id,
label, forward_from, delayed, session, label, forward_from, delayed, session,
form_node, user_nick, keyID, attention, form_node, user_nick, keyID, attention,
callback) correction_msg, callback)
gajim.nec.push_incoming_event(GPGTrustKeyEvent(None, gajim.nec.push_incoming_event(GPGTrustKeyEvent(None,
conn=self, callback=_on_always_trust)) conn=self, callback=_on_always_trust))
else: else:
@ -314,7 +316,7 @@ class CommonConnection:
original_message, fjid, resource, jid, xhtml, original_message, fjid, resource, jid, xhtml,
subject, chatstate, msg_id, label, forward_from, subject, chatstate, msg_id, label, forward_from,
delayed, session, form_node, user_nick, keyID, delayed, session, form_node, user_nick, keyID,
attention, callback) attention, correction_msg, callback)
gajim.thread_interface(encrypt_thread, [msg, keyID, False], gajim.thread_interface(encrypt_thread, [msg, keyID, False],
_on_encrypted, []) _on_encrypted, [])
return return
@ -322,18 +324,19 @@ class CommonConnection:
self._message_encrypted_cb(('', error), type_, msg, msgtxt, self._message_encrypted_cb(('', error), type_, msg, msgtxt,
original_message, fjid, resource, jid, xhtml, subject, original_message, fjid, resource, jid, xhtml, subject,
chatstate, msg_id, label, forward_from, delayed, session, chatstate, msg_id, label, forward_from, delayed, session,
form_node, user_nick, keyID, attention, callback) form_node, user_nick, keyID, attention, correction_msg,
callback)
return return
self._on_continue_message(type_, msg, msgtxt, original_message, fjid, self._on_continue_message(type_, msg, msgtxt, original_message, fjid,
resource, jid, xhtml, subject, msgenc, keyID, chatstate, msg_id, resource, jid, xhtml, subject, msgenc, keyID, chatstate, msg_id,
label, forward_from, delayed, session, form_node, user_nick, label, forward_from, delayed, session, form_node, user_nick,
attention, callback) attention, correction_msg, callback)
def _message_encrypted_cb(self, output, type_, msg, msgtxt, def _message_encrypted_cb(self, output, type_, msg, msgtxt,
original_message, fjid, resource, jid, xhtml, subject, chatstate, msg_id, original_message, fjid, resource, jid, xhtml, subject, chatstate, msg_id,
label, forward_from, delayed, session, form_node, user_nick, keyID, label, forward_from, delayed, session, form_node, user_nick, keyID,
attention, callback): attention, correction_msg, callback):
msgenc, error = output msgenc, error = output
if msgenc and not error: if msgenc and not error:
@ -346,7 +349,7 @@ class CommonConnection:
self._on_continue_message(type_, msg, msgtxt, original_message, self._on_continue_message(type_, msg, msgtxt, original_message,
fjid, resource, jid, xhtml, subject, msgenc, keyID, fjid, resource, jid, xhtml, subject, msgenc, keyID,
chatstate, msg_id, label, forward_from, delayed, session, chatstate, msg_id, label, forward_from, delayed, session,
form_node, user_nick, attention, callback) form_node, user_nick, attention, correction_msg, callback)
return return
# Encryption failed, do not send message # Encryption failed, do not send message
tim = localtime() tim = localtime()
@ -356,7 +359,32 @@ class CommonConnection:
def _on_continue_message(self, type_, msg, msgtxt, original_message, fjid, def _on_continue_message(self, type_, msg, msgtxt, original_message, fjid,
resource, jid, xhtml, subject, msgenc, keyID, chatstate, msg_id, resource, jid, xhtml, subject, msgenc, keyID, chatstate, msg_id,
label, forward_from, delayed, session, form_node, user_nick, attention, label, forward_from, delayed, session, form_node, user_nick, attention,
callback): correction_msg, callback):
if correction_msg:
id_ = correction_msg.getID()
if correction_msg.getTag('replace'):
correction_msg.delChild('replace')
correction_msg.setTag('replace', attrs={'id': id_},
namespace=nbxmpp.NS_CORRECT)
id2 = self.connection.getAnID()
correction_msg.setID(id2)
correction_msg.setBody(msgtxt)
if xhtml:
correction_msg.setXHTML(xhtml)
if session:
session.last_send = time.time()
# XEP-0200
if session.enable_encryption:
correction_msg = session.encrypt_stanza(correction_msg)
if callback:
callback(jid, msg, keyID, forward_from, session, original_message,
subject, type_, correction_msg, xhtml)
return
if type_ == 'chat': if type_ == 'chat':
msg_iq = nbxmpp.Message(to=fjid, body=msgtxt, typ=type_, msg_iq = nbxmpp.Message(to=fjid, body=msgtxt, typ=type_,
xhtml=xhtml) xhtml=xhtml)
@ -1941,8 +1969,8 @@ class Connection(CommonConnection, ConnectionHandlers):
def send_message(self, jid, msg, keyID=None, type_='chat', subject='', def send_message(self, jid, msg, keyID=None, type_='chat', subject='',
chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None, chatstate=None, msg_id=None, resource=None, user_nick=None, xhtml=None,
label=None, session=None, forward_from=None, form_node=None, label=None, session=None, forward_from=None, form_node=None,
original_message=None, delayed=None, attention=False, callback=None, original_message=None, delayed=None, attention=False, correction_msg=None,
callback_args=[], now=False): callback=None, callback_args=[], now=False):
def cb(jid, msg, keyID, forward_from, session, original_message, def cb(jid, msg, keyID, forward_from, session, original_message,
subject, type_, msg_iq, xhtml): subject, type_, msg_iq, xhtml):
@ -1961,7 +1989,7 @@ class Connection(CommonConnection, ConnectionHandlers):
user_nick=user_nick, xhtml=xhtml, label=label, session=session, user_nick=user_nick, xhtml=xhtml, label=label, session=session,
forward_from=forward_from, form_node=form_node, forward_from=forward_from, form_node=form_node,
original_message=original_message, delayed=delayed, original_message=original_message, delayed=delayed,
attention=attention, callback=cb) attention=attention, correction_msg=correction_msg, callback=cb)
def _nec_message_outgoing(self, obj): def _nec_message_outgoing(self, obj):
if obj.account != self.name: if obj.account != self.name:
@ -1974,7 +2002,7 @@ class Connection(CommonConnection, ConnectionHandlers):
gajim.nec.push_incoming_event(MessageSentEvent(None, conn=self, gajim.nec.push_incoming_event(MessageSentEvent(None, conn=self,
jid=jid, message=msg, keyID=keyID, chatstate=obj.chatstate)) jid=jid, message=msg, keyID=keyID, chatstate=obj.chatstate))
if obj.callback: if obj.callback:
obj.callback(msg_id, *obj.callback_args) obj.callback(msg_iq, *obj.callback_args)
if not obj.is_loggable: if not obj.is_loggable:
return return
@ -1986,7 +2014,8 @@ class Connection(CommonConnection, ConnectionHandlers):
resource=obj.resource, user_nick=obj.user_nick, xhtml=obj.xhtml, resource=obj.resource, user_nick=obj.user_nick, xhtml=obj.xhtml,
label=obj.label, session=obj.session, forward_from=obj.forward_from, label=obj.label, session=obj.session, forward_from=obj.forward_from,
form_node=obj.form_node, original_message=obj.original_message, form_node=obj.form_node, original_message=obj.original_message,
delayed=obj.delayed, attention=obj.attention, callback=cb) delayed=obj.delayed, attention=obj.attention,
correction_msg=obj.correction_msg, callback=cb)
def send_contacts(self, contacts, fjid, type_='message'): def send_contacts(self, contacts, fjid, type_='message'):
""" """
@ -2524,18 +2553,38 @@ class Connection(CommonConnection, ConnectionHandlers):
t.setTagData('password', password) t.setTagData('password', password)
self.connection.send(p) self.connection.send(p)
def send_gc_message(self, jid, msg, xhtml=None, label=None): def send_gc_message(self, jid, msg, xhtml=None, label=None,
correction_msg=None, callback=None):
if not gajim.account_is_connected(self.name): if not gajim.account_is_connected(self.name):
return return
if correction_msg:
id_ = correction_msg.getID()
if correction_msg.getTag('replace'):
correction_msg.delChild('replace')
correction_msg.setTag('replace', attrs={'id': id_},
namespace=nbxmpp.NS_CORRECT)
id2 = self.connection.getAnID()
correction_msg.setID(id2)
correction_msg.setBody(msg)
if xhtml:
correction_msg.setXHTML(xhtml)
self.connection.send(correction_msg)
gajim.nec.push_incoming_event(MessageSentEvent(None, conn=self,
jid=jid, message=msg, keyID=None, chatstate=None))
if callback:
callback(correction_msg, msg)
return
if not xhtml and gajim.config.get('rst_formatting_outgoing_messages'): if not xhtml and gajim.config.get('rst_formatting_outgoing_messages'):
from common.rst_xhtml_generator import create_xhtml from common.rst_xhtml_generator import create_xhtml
xhtml = create_xhtml(msg) xhtml = create_xhtml(msg)
msg_iq = nbxmpp.Message(jid, msg, typ='groupchat', xhtml=xhtml) msg_iq = nbxmpp.Message(jid, msg, typ='groupchat', xhtml=xhtml)
if label is not None: if label is not None:
msg_iq.addChild(node = label) msg_iq.addChild(node=label)
self.connection.send(msg_iq) self.connection.send(msg_iq)
gajim.nec.push_incoming_event(MessageSentEvent(None, conn=self, gajim.nec.push_incoming_event(MessageSentEvent(None, conn=self,
jid=jid, message=msg, keyID=None, chatstate=None)) jid=jid, message=msg, keyID=None, chatstate=None))
if callback:
callback(msg_iq, msg)
def send_gc_subject(self, jid, subject): def send_gc_subject(self, jid, subject):
if not gajim.account_is_connected(self.name): if not gajim.account_is_connected(self.name):

View File

@ -1248,6 +1248,7 @@ class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.popup = False self.popup = False
self.msg_id = None # id in log database self.msg_id = None # id in log database
self.attention = False # XEP-0224 self.attention = False # XEP-0224
self.correct_id = None # XEP-0308
self.receipt_request_tag = self.stanza.getTag('request', self.receipt_request_tag = self.stanza.getTag('request',
namespace=nbxmpp.NS_RECEIPTS) namespace=nbxmpp.NS_RECEIPTS)
@ -1291,6 +1292,10 @@ class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.msgtxt += _('URL:') self.msgtxt += _('URL:')
self.msgtxt += ' ' + self.oob_url self.msgtxt += ' ' + self.oob_url
replace = self.stanza.getTag('replace', namespace=nbxmpp.NS_CORRECT)
if replace:
self.correct_id = replace.getAttr('id')
return True return True
class ChatstateReceivedEvent(nec.NetworkIncomingEvent): class ChatstateReceivedEvent(nec.NetworkIncomingEvent):
@ -1318,6 +1323,7 @@ class GcMessageReceivedEvent(nec.NetworkIncomingEvent):
self.nickname = self.msg_obj.resource self.nickname = self.msg_obj.resource
self.timestamp = self.msg_obj.timestamp self.timestamp = self.msg_obj.timestamp
self.xhtml_msgtxt = self.stanza.getXHTML() self.xhtml_msgtxt = self.stanza.getXHTML()
self.correct_id = None # XEP-0308
if gajim.config.get('ignore_incoming_xhtml'): if gajim.config.get('ignore_incoming_xhtml'):
self.xhtml_msgtxt = None self.xhtml_msgtxt = None
@ -1390,6 +1396,10 @@ class GcMessageReceivedEvent(nec.NetworkIncomingEvent):
[self.stanza, self.msg_obj], 0) [self.stanza, self.msg_obj], 0)
return return
replace = self.stanza.getTag('replace', namespace=nbxmpp.NS_CORRECT)
if replace:
self.correct_id = replace.getAttr('id')
return True return True
class GcSubjectReceivedEvent(nec.NetworkIncomingEvent): class GcSubjectReceivedEvent(nec.NetworkIncomingEvent):
@ -2444,6 +2454,7 @@ class MessageOutgoingEvent(nec.NetworkOutgoingEvent):
self.is_loggable = True self.is_loggable = True
self.control = None self.control = None
self.attention = False self.attention = False
self.correction_msg = None
def generate(self): def generate(self):
return True return True

View File

@ -212,7 +212,7 @@ gajim_common_features = [nbxmpp.NS_BYTESTREAM, nbxmpp.NS_SI, nbxmpp.NS_FILE,
nbxmpp.NS_SSN, nbxmpp.NS_MOOD, nbxmpp.NS_ACTIVITY, nbxmpp.NS_NICK, nbxmpp.NS_SSN, nbxmpp.NS_MOOD, nbxmpp.NS_ACTIVITY, nbxmpp.NS_NICK,
nbxmpp.NS_ROSTERX, nbxmpp.NS_SECLABEL, nbxmpp.NS_HASHES, nbxmpp.NS_ROSTERX, nbxmpp.NS_SECLABEL, nbxmpp.NS_HASHES,
nbxmpp.NS_HASHES_MD5, nbxmpp.NS_HASHES_SHA1, nbxmpp.NS_HASHES_SHA256, nbxmpp.NS_HASHES_MD5, nbxmpp.NS_HASHES_SHA1, nbxmpp.NS_HASHES_SHA256,
nbxmpp.NS_HASHES_SHA512] nbxmpp.NS_HASHES_SHA512, nbxmpp.NS_CORRECT]
# Optional features gajim supports per account # Optional features gajim supports per account
gajim_optional_features = {} gajim_optional_features = {}

View File

@ -77,7 +77,7 @@ class TextViewImage(Gtk.Image):
self._disconnect_funcs = [] self._disconnect_funcs = []
self.connect('parent-set', self.on_parent_set) self.connect('parent-set', self.on_parent_set)
self.connect('draw', self.on_expose) self.connect('draw', self.on_expose)
self.set_tooltip_text(text) self.set_tooltip_markup(text)
self.anchor.plaintext = text self.anchor.plaintext = text
def _get_selected(self): def _get_selected(self):
@ -172,9 +172,12 @@ class ConversationTextview(GObject.GObject):
) )
) )
FOCUS_OUT_LINE_PIXBUF = gtkgui_helpers.get_icon_pixmap('gajim-muc_separator') FOCUS_OUT_LINE_PIXBUF = gtkgui_helpers.get_icon_pixmap(
'gajim-muc_separator')
XEP0184_WARNING_PIXBUF = gtkgui_helpers.get_icon_pixmap( XEP0184_WARNING_PIXBUF = gtkgui_helpers.get_icon_pixmap(
'gajim-receipt_missing') 'gajim-receipt_missing')
MESSAGE_CORRECTED_PIXBUF = gtkgui_helpers.get_icon_pixmap(
'gajim-message_corrected')
# smooth scroll constants # smooth scroll constants
MAX_SCROLL_TIME = 0.4 # seconds MAX_SCROLL_TIME = 0.4 # seconds
@ -208,6 +211,9 @@ class ConversationTextview(GObject.GObject):
self.image_cache = {} self.image_cache = {}
self.xep0184_marks = {} self.xep0184_marks = {}
self.xep0184_shown = {} self.xep0184_shown = {}
self.last_sent_message_marks = [None, None]
# A pair per occupant. Key is '' in normal chat
self.last_received_message_marks = {}
# It's True when we scroll in the code, so we can detect scroll from user # It's True when we scroll in the code, so we can detect scroll from user
self.auto_scrolling = False self.auto_scrolling = False
@ -463,6 +469,51 @@ class ConversationTextview(GObject.GObject):
self.smooth_id = None self.smooth_id = None
self.smooth_scroll_timer.cancel() self.smooth_scroll_timer.cancel()
def show_corrected_message_warning(self, iter_, text=''):
buffer_ = self.tv.get_buffer()
buffer_.begin_user_action()
buffer_.insert(iter_, ' ')
anchor = buffer_.create_child_anchor(iter_)
img = TextViewImage(anchor, text)
img.set_from_pixbuf(ConversationTextview.MESSAGE_CORRECTED_PIXBUF)
img.show()
self.tv.add_child_at_anchor(img, anchor)
buffer_.end_user_action()
def correct_last_sent_message(self, message, xhtml, name, old_txt):
m1 = self.last_sent_message_marks[0]
m2 = self.last_sent_message_marks[1]
buffer_ = self.tv.get_buffer()
i1 = buffer_.get_iter_at_mark(m1)
i2 = buffer_.get_iter_at_mark(m2)
txt = buffer_.get_text(i1, i2)
buffer_.delete(i1, i2)
i2 = self.print_real_text(message, text_tags=['outgoingtxt'], name=name,
xhtml=xhtml, iter_=i1)
tt_txt = _('<b>Message was corrected. Last message was:</b>\n %s') % \
old_txt
self.show_corrected_message_warning(i2, tt_txt)
self.last_sent_message_marks[1] = buffer_.create_mark(None, i2,
left_gravity=True)
def correct_last_received_message(self, message, xhtml, name, old_txt):
if name not in self.last_received_message_marks:
return
m1 = self.last_received_message_marks[name][0]
m2 = self.last_received_message_marks[name][1]
buffer_ = self.tv.get_buffer()
i1 = buffer_.get_iter_at_mark(m1)
i2 = buffer_.get_iter_at_mark(m2)
txt = buffer_.get_text(i1, i2)
buffer_.delete(i1, i2)
i2 = self.print_real_text(message, text_tags=['incomingtxt'], name=name,
xhtml=xhtml, iter_=i1)
tt_txt = _('<b>Message was corrected. Last message was:</b>\n %s') % \
old_txt
self.show_corrected_message_warning(i2, tt_txt)
self.last_received_message_marks[name][1] = buffer_.create_mark(None, i2,
left_gravity=True)
def show_xep0184_warning(self, id_): def show_xep0184_warning(self, id_):
if id_ in self.xep0184_marks: if id_ in self.xep0184_marks:
return return
@ -991,7 +1042,8 @@ class ConversationTextview(GObject.GObject):
else: else:
helpers.launch_browser_mailer(kind, word) helpers.launch_browser_mailer(kind, word)
def detect_and_print_special_text(self, otext, other_tags, graphics=True): def detect_and_print_special_text(self, otext, other_tags, graphics=True,
iter_=None):
""" """
Detect special text (emots & links & formatting), print normal text Detect special text (emots & links & formatting), print normal text
before any special text it founds, then print special text (that happens before any special text it founds, then print special text (that happens
@ -1025,6 +1077,10 @@ class ConversationTextview(GObject.GObject):
iterator = gajim.interface.emot_and_basic_re.finditer(otext) iterator = gajim.interface.emot_and_basic_re.finditer(otext)
else: # search for just urls + mail + formatting else: # search for just urls + mail + formatting
iterator = gajim.interface.basic_pattern_re.finditer(otext) iterator = gajim.interface.basic_pattern_re.finditer(otext)
if iter_:
end_iter = iter_
else:
end_iter = buffer_.get_end_iter()
for match in iterator: for match in iterator:
start, end = match.span() start, end = match.span()
special_text = otext[start:end] special_text = otext[start:end]
@ -1039,18 +1095,19 @@ class ConversationTextview(GObject.GObject):
index = end # update index index = end # update index
# now print it # now print it
self.print_special_text(special_text, other_tags, graphics=graphics) self.print_special_text(special_text, other_tags, graphics=graphics,
iter_=end_iter)
specials_limit -= 1 specials_limit -= 1
if specials_limit <= 0: if specials_limit <= 0:
break break
# add the rest of text located in the index and after # add the rest of text located in the index and after
end_iter = buffer_.get_end_iter()
insert_tags_func(end_iter, otext[index:], *other_tags) insert_tags_func(end_iter, otext[index:], *other_tags)
return buffer_.get_end_iter() return end_iter
def print_special_text(self, special_text, other_tags, graphics=True): def print_special_text(self, special_text, other_tags, graphics=True,
iter_=None):
""" """
Is called by detect_and_print_special_text and prints special text Is called by detect_and_print_special_text and prints special text
(emots, links, formatting) (emots, links, formatting)
@ -1069,7 +1126,7 @@ class ConversationTextview(GObject.GObject):
text_is_valid_uri = False text_is_valid_uri = False
is_xhtml_link = None is_xhtml_link = None
show_ascii_formatting_chars = \ show_ascii_formatting_chars = \
gajim.config.get('show_ascii_formatting_chars') gajim.config.get('show_ascii_formatting_chars')
buffer_ = self.tv.get_buffer() buffer_ = self.tv.get_buffer()
# Detect XHTML-IM link # Detect XHTML-IM link
@ -1087,17 +1144,20 @@ class ConversationTextview(GObject.GObject):
text_is_valid_uri = True text_is_valid_uri = True
possible_emot_ascii_caps = special_text.upper() # emoticons keys are CAPS possible_emot_ascii_caps = special_text.upper() # emoticons keys are CAPS
if iter_:
end_iter = iter_
else:
end_iter = buffer_.get_end_iter()
if gajim.config.get('emoticons_theme') and \ if gajim.config.get('emoticons_theme') and \
possible_emot_ascii_caps in gajim.interface.emoticons.keys() and graphics: possible_emot_ascii_caps in gajim.interface.emoticons.keys() and graphics:
# it's an emoticon # it's an emoticon
emot_ascii = possible_emot_ascii_caps emot_ascii = possible_emot_ascii_caps
end_iter = buffer_.get_end_iter()
anchor = buffer_.create_child_anchor(end_iter) anchor = buffer_.create_child_anchor(end_iter)
img = TextViewImage(anchor, special_text) img = TextViewImage(anchor, special_text)
animations = gajim.interface.emoticons_animations animations = gajim.interface.emoticons_animations
if not emot_ascii in animations: if not emot_ascii in animations:
animations[emot_ascii] = GdkPixbuf.PixbufAnimation.new_from_file( animations[emot_ascii] = GdkPixbuf.PixbufAnimation.new_from_file(
gajim.interface.emoticons[emot_ascii]) gajim.interface.emoticons[emot_ascii])
img.set_from_animation(animations[emot_ascii]) img.set_from_animation(animations[emot_ascii])
img.show() img.show()
self.images.append(img) self.images.append(img)
@ -1108,13 +1168,13 @@ class ConversationTextview(GObject.GObject):
text_is_valid_uri and not is_xhtml_link: text_is_valid_uri and not is_xhtml_link:
tags.append('url') tags.append('url')
elif special_text.startswith('mailto:') and not is_xhtml_link: elif special_text.startswith('mailto:') and not is_xhtml_link:
tags.append('mail') tags.append('mail')
elif special_text.startswith('xmpp:') and not is_xhtml_link: elif special_text.startswith('xmpp:') and not is_xhtml_link:
tags.append('xmpp') tags.append('xmpp')
elif gajim.interface.sth_at_sth_dot_sth_re.match(special_text) and\ elif gajim.interface.sth_at_sth_dot_sth_re.match(special_text) and\
not is_xhtml_link: not is_xhtml_link:
# it's a JID or mail # it's a JID or mail
tags.append('sth_at_sth') tags.append('sth_at_sth')
elif special_text.startswith('*'): # it's a bold text elif special_text.startswith('*'): # it's a bold text
tags.append('bold') tags.append('bold')
if special_text[1] == '/' and special_text[-2] == '/' and\ if special_text[1] == '/' and special_text[-2] == '/' and\
@ -1163,7 +1223,6 @@ class ConversationTextview(GObject.GObject):
else: else:
# It's nothing special # It's nothing special
if use_other_tags: if use_other_tags:
end_iter = buffer_.get_end_iter()
insert_tags_func = buffer_.insert_with_tags_by_name insert_tags_func = buffer_.insert_with_tags_by_name
if other_tags and isinstance(other_tags[0], Gtk.TextTag): if other_tags and isinstance(other_tags[0], Gtk.TextTag):
insert_tags_func = buffer_.insert_with_tags insert_tags_func = buffer_.insert_with_tags
@ -1173,7 +1232,6 @@ class ConversationTextview(GObject.GObject):
buffer_.insert(end_iter, special_text) buffer_.insert(end_iter, special_text)
if tags: if tags:
end_iter = buffer_.get_end_iter()
all_tags = tags[:] all_tags = tags[:]
if use_other_tags: if use_other_tags:
all_tags += other_tags all_tags += other_tags
@ -1183,7 +1241,6 @@ class ConversationTextview(GObject.GObject):
if 'url' in tags: if 'url' in tags:
puny_text = puny_encode(special_text).decode('utf-8') puny_text = puny_encode(special_text).decode('utf-8')
if not puny_text.endswith('-'): if not puny_text.endswith('-'):
end_iter = buffer_.get_end_iter()
buffer_.insert(end_iter, " (%s)" % puny_text) buffer_.insert(end_iter, " (%s)" % puny_text)
def print_empty_line(self): def print_empty_line(self):
@ -1193,9 +1250,9 @@ class ConversationTextview(GObject.GObject):
self.just_cleared = False self.just_cleared = False
def print_conversation_line(self, text, jid, kind, name, tim, def print_conversation_line(self, text, jid, kind, name, tim,
other_tags_for_name=[], other_tags_for_time=[], other_tags_for_name=[], other_tags_for_time=[], other_tags_for_text=[],
other_tags_for_text=[], subject=None, old_kind=None, xhtml=None, subject=None, old_kind=None, xhtml=None, simple=False, graphics=True,
simple=False, graphics=True, displaymarking=None): displaymarking=None):
""" """
Print 'chat' type messages Print 'chat' type messages
""" """
@ -1276,6 +1333,7 @@ class ConversationTextview(GObject.GObject):
kind = 'status' kind = 'status'
other_text_tag = self.detect_other_text_tag(text, kind) other_text_tag = self.detect_other_text_tag(text, kind)
text_tags = other_tags_for_text[:] # create a new list text_tags = other_tags_for_text[:] # create a new list
mark1 = None
if other_text_tag: if other_text_tag:
# note that color of /me may be overwritten in gc_control # note that color of /me may be overwritten in gc_control
text_tags.append(other_text_tag) text_tags.append(other_text_tag)
@ -1292,11 +1350,21 @@ class ConversationTextview(GObject.GObject):
direction_mark=direction_mark) direction_mark=direction_mark)
if kind == 'incoming': if kind == 'incoming':
text_tags.append('incomingtxt') text_tags.append('incomingtxt')
mark1 = buffer_.create_mark(None, buffer_.get_end_iter(),
left_gravity=True)
elif kind == 'outgoing': elif kind == 'outgoing':
text_tags.append('outgoingtxt') text_tags.append('outgoingtxt')
mark1 = buffer_.create_mark(None, buffer_.get_end_iter(),
left_gravity=True)
self.print_subject(subject) self.print_subject(subject)
self.print_real_text(text, text_tags, name, xhtml, graphics=graphics) self.print_real_text(text, text_tags, name, xhtml, graphics=graphics)
if mark1:
mark2 = buffer_.create_mark(None, buffer_.get_end_iter(),
left_gravity=True)
if kind == 'incoming':
self.last_received_message_marks[name] = [mark1, mark2]
elif kind == 'outgoing':
self.last_sent_message_marks = [mark1, mark2]
# scroll to the end of the textview # scroll to the end of the textview
if at_the_end or kind == 'outgoing': if at_the_end or kind == 'outgoing':
# we are at the end or we are sending something # we are at the end or we are sending something
@ -1367,16 +1435,19 @@ class ConversationTextview(GObject.GObject):
format_ = direction_mark + before_str + name + after_str + ' ' format_ = direction_mark + before_str + name + after_str + ' '
buffer_.insert_with_tags_by_name(end_iter, format_, *name_tags) buffer_.insert_with_tags_by_name(end_iter, format_, *name_tags)
def print_subject(self, subject): def print_subject(self, subject, iter_=None):
if subject: # if we have subject, show it too! if subject: # if we have subject, show it too!
subject = _('Subject: %s\n') % subject subject = _('Subject: %s\n') % subject
buffer_ = self.tv.get_buffer() buffer_ = self.tv.get_buffer()
end_iter = buffer_.get_end_iter() if iter_:
end_iter = iter_
else:
end_iter = buffer_.get_end_iter()
buffer_.insert(end_iter, subject) buffer_.insert(end_iter, subject)
self.print_empty_line() self.print_empty_line()
def print_real_text(self, text, text_tags=[], name=None, xhtml=None, def print_real_text(self, text, text_tags=[], name=None, xhtml=None,
graphics=True): graphics=True, iter_=None):
""" """
Add normal and special text. call this to add text Add normal and special text. call this to add text
""" """
@ -1395,4 +1466,5 @@ class ConversationTextview(GObject.GObject):
text = '* ' + name + text[3:] text = '* ' + name + text[3:]
text_tags.append('italic') text_tags.append('italic')
# detect urls formatting and if the user has it on emoticons # detect urls formatting and if the user has it on emoticons
self.detect_and_print_special_text(text, text_tags, graphics=graphics) return self.detect_and_print_special_text(text, text_tags, graphics=graphics,
iter_=iter_)

View File

@ -1012,9 +1012,26 @@ class GroupchatControl(ChatControlBase):
tim=obj.timestamp, xhtml=None, tim=obj.timestamp, xhtml=None,
displaymarking=obj.displaymarking) displaymarking=obj.displaymarking)
else: else:
if obj.nick in self.last_received_txt and obj.correct_id and \
obj.correct_id == self.last_received_id[obj.nick]:
if obj.nick == self.nick:
old_txt = self.last_sent_txt
self.last_sent_txt = obj.msgtxt
self.conv_textview.correct_last_sent_message(obj.msgtxt,
obj.xhtml_msgtxt, obj.nick, old_txt)
else:
old_txt = self.last_received_txt[obj.nick]
self.conv_textview.correct_last_received_message(obj.msgtxt,
obj.xhtml_msgtxt, obj.nick, old_txt)
self.last_received_txt[obj.nick] = obj.msgtxt
self.last_received_id[obj.nick] = obj.stanza.getID()
return
if obj.nick == self.nick:
self.last_sent_txt = obj.msgtxt
self.print_conversation(obj.msgtxt, contact=obj.nick, self.print_conversation(obj.msgtxt, contact=obj.nick,
tim=obj.timestamp, xhtml=obj.xhtml_msgtxt, tim=obj.timestamp, xhtml=obj.xhtml_msgtxt,
displaymarking=obj.displaymarking) displaymarking=obj.displaymarking,
correct_id=(obj.stanza.getID(), None))
obj.needs_highlight = self.needs_visual_notification(obj.msgtxt) obj.needs_highlight = self.needs_visual_notification(obj.msgtxt)
def on_private_message(self, nick, msg, tim, xhtml, session, msg_id=None, def on_private_message(self, nick, msg, tim, xhtml, session, msg_id=None,
@ -1086,7 +1103,7 @@ class GroupchatControl(ChatControlBase):
displaymarking=displaymarking) displaymarking=displaymarking)
def print_conversation(self, text, contact='', tim=None, xhtml=None, def print_conversation(self, text, contact='', tim=None, xhtml=None,
graphics=True, displaymarking=None): graphics=True, displaymarking=None, correct_id=None):
""" """
Print a line in the conversation Print a line in the conversation
@ -1147,7 +1164,8 @@ class GroupchatControl(ChatControlBase):
ChatControlBase.print_conversation_line(self, text, kind, contact, tim, ChatControlBase.print_conversation_line(self, text, kind, contact, tim,
other_tags_for_name, [], other_tags_for_text, xhtml=xhtml, other_tags_for_name, [], other_tags_for_text, xhtml=xhtml,
graphics=graphics, displaymarking=displaymarking) graphics=graphics, displaymarking=displaymarking,
correct_id=correct_id)
def get_nb_unread(self): def get_nb_unread(self):
type_events = ['printed_marked_gc_msg'] type_events = ['printed_marked_gc_msg']
@ -1590,6 +1608,18 @@ class GroupchatControl(ChatControlBase):
else: else:
s = _('%(nick)s is now known as %(new_nick)s') % { s = _('%(nick)s is now known as %(new_nick)s') % {
'nick': obj.nick, 'new_nick': obj.new_nick} 'nick': obj.nick, 'new_nick': obj.new_nick}
tv = self.conv_textview
if obj.nick in tv.last_received_message_marks:
tv.last_received_message_marks[obj.new_nick] = \
tv.last_received_message_marks[obj.nick]
del tv.last_received_message_marks[obj.nick]
if obj.nick in self.last_received_txt:
self.last_received_txt[obj.new_nick] = \
self.last_received_txt[obj.nick]
del self.last_received_txt[obj.nick]
self.last_received_id[obj.new_nick] = \
self.last_received_id[obj.nick]
del self.last_received_id[obj.nick]
# We add new nick to muc roster here, so we don't see # We add new nick to muc roster here, so we don't see
# that "new_nick has joined the room" when he just changed # that "new_nick has joined the room" when he just changed
# nick. # nick.
@ -1889,9 +1919,23 @@ class GroupchatControl(ChatControlBase):
if message != '' or message != '\n': if message != '' or message != '\n':
self.save_message(message, 'sent') self.save_message(message, 'sent')
def _cb(msg, msg_txt):
# we'll save sent message text when we'll receive it in
# _nec_gc_message_received
self.last_sent_msg = msg
if self.correcting:
self.correcting = False
self.msg_textview.modify_base(Gtk.StateType.NORMAL,
self.old_message_tv_color)
if self.correcting and self.last_sent_msg:
correction_msg = self.last_sent_msg
else:
correction_msg = None
# Send the message # Send the message
gajim.connections[self.account].send_gc_message(self.room_jid, gajim.connections[self.account].send_gc_message(self.room_jid,
message, xhtml=xhtml, label=label) message, xhtml=xhtml, label=label,
correction_msg=correction_msg, callback=_cb)
self.msg_textview.get_buffer().set_text('') self.msg_textview.get_buffer().set_text('')
self.msg_textview.grab_focus() self.msg_textview.grab_focus()

View File

@ -2719,7 +2719,7 @@ class RosterWindow:
obj.session.control.print_conversation(obj.msgtxt, typ, obj.session.control.print_conversation(obj.msgtxt, typ,
tim=obj.timestamp, encrypted=obj.encrypted, subject=obj.subject, tim=obj.timestamp, encrypted=obj.encrypted, subject=obj.subject,
xhtml=obj.xhtml, displaymarking=obj.displaymarking, xhtml=obj.xhtml, displaymarking=obj.displaymarking,
msg_id=obj.msg_id) msg_id=obj.msg_id, correct_id=(obj.id_, obj.correct_id))
if obj.msg_id: if obj.msg_id:
pw = obj.session.control.parent_win pw = obj.session.control.parent_win
end = obj.session.control.was_at_the_end end = obj.session.control.was_at_the_end

View File

@ -99,7 +99,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
sectext = _('The database file (%s) cannot be read. Try to ' sectext = _('The database file (%s) cannot be read. Try to '
'repair it (see http://trac.gajim.org/wiki/DatabaseBackup) ' 'repair it (see http://trac.gajim.org/wiki/DatabaseBackup) '
'or remove it (all history will be lost).') % \ 'or remove it (all history will be lost).') % \
common.logger.LOG_DB_PATH gajim.logger.LOG_DB_PATH
gajim.nec.push_incoming_event(InformationEvent(None, gajim.nec.push_incoming_event(InformationEvent(None,
conn=self.conn, level='error', pri_txt=pritext, conn=self.conn, level='error', pri_txt=pritext,
sec_txt=sectext)) sec_txt=sectext))