Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dev.gajim.org/gajim/gajim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann Leboulanger <asterix@lagaule.org>2010-06-07 21:11:44 +0400
committerYann Leboulanger <asterix@lagaule.org>2010-06-07 21:11:44 +0400
commitd58841cb2bdf8e900955f306fce8afba37e77aa1 (patch)
tree7ae21615cbef5cfba8e2ac8f1c0e2655edb3493c
parent28e3c36944c42f93c6e82ac2009319a5fc3f9f90 (diff)
[Dave Cridland] add XEP-0258 support. Great thanks for that! Fixes #5772
-rw-r--r--data/gui/chat_control.ui19
-rw-r--r--data/gui/groupchat_control.ui18
-rw-r--r--src/chat_control.py63
-rw-r--r--src/common/connection.py38
-rw-r--r--src/common/connection_handlers.py38
-rw-r--r--src/common/gajim.py2
-rw-r--r--src/common/xmpp/protocol.py2
-rw-r--r--src/conversation_textview.py19
-rw-r--r--src/groupchat_control.py27
-rw-r--r--src/gui_interface.py4
-rw-r--r--src/message_control.py4
-rw-r--r--src/session.py20
12 files changed, 191 insertions, 63 deletions
diff --git a/data/gui/chat_control.ui b/data/gui/chat_control.ui
index de3208afb..8ab302dad 100644
--- a/data/gui/chat_control.ui
+++ b/data/gui/chat_control.ui
@@ -5,7 +5,6 @@
<object class="GtkVBox" id="chat_control_vbox">
<property name="can_focus">True</property>
<property name="border_width">3</property>
- <property name="orientation">vertical</property>
<property name="spacing">1</property>
<child>
<object class="GtkHBox" id="hbox3">
@@ -13,7 +12,6 @@
<child>
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
<child>
<object class="GtkAlignment" id="alignment">
<property name="visible">True</property>
@@ -43,7 +41,6 @@
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
- <property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="banner_name_label">
<property name="visible">True</property>
@@ -195,7 +192,6 @@
<child>
<object class="GtkVBox" id="vbox106">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
<property name="height_request">60</property>
@@ -314,7 +310,6 @@
<object class="GtkVSeparator" id="vseparator1">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
@@ -470,7 +465,6 @@
<object class="GtkVSeparator" id="vseparator3">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
@@ -500,6 +494,14 @@
</packing>
</child>
<child>
+ <object class="GtkComboBox" id="label_selector">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">12</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@@ -508,7 +510,7 @@
</child>
</object>
<packing>
- <property name="position">12</property>
+ <property name="position">13</property>
</packing>
</child>
<child>
@@ -555,7 +557,7 @@
</object>
<packing>
<property name="expand">False</property>
- <property name="position">13</property>
+ <property name="position">14</property>
</packing>
</child>
</object>
@@ -572,7 +574,6 @@
<child>
<object class="GtkVBox" id="audio_vbox">
<property name="no_show_all">True</property>
- <property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label3">
diff --git a/data/gui/groupchat_control.ui b/data/gui/groupchat_control.ui
index f9ebc2798..9c164c76b 100644
--- a/data/gui/groupchat_control.ui
+++ b/data/gui/groupchat_control.ui
@@ -5,7 +5,6 @@
<object class="GtkVBox" id="groupchat_control_vbox">
<property name="can_focus">True</property>
<property name="border_width">3</property>
- <property name="orientation">vertical</property>
<child>
<object class="GtkAlignment" id="alignment">
<property name="visible">True</property>
@@ -35,7 +34,6 @@
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
- <property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="banner_name_label">
<property name="visible">True</property>
@@ -133,7 +131,6 @@
<object class="GtkVSeparator" id="vseparator2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
@@ -233,7 +230,6 @@
<object class="GtkVSeparator" id="vseparator4">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
@@ -270,6 +266,14 @@
</packing>
</child>
<child>
+ <object class="GtkComboBox" id="label_selector">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">9</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@@ -278,7 +282,7 @@
</child>
</object>
<packing>
- <property name="position">9</property>
+ <property name="position">10</property>
</packing>
</child>
<child>
@@ -326,7 +330,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">10</property>
+ <property name="position">11</property>
</packing>
</child>
</object>
@@ -346,12 +350,10 @@
<object class="GtkVBox" id="vbox108">
<property name="width_request">0</property>
<property name="visible">True</property>
- <property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkVBox" id="vbox109">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
diff --git a/src/chat_control.py b/src/chat_control.py
index e71a6d2a5..d0028745e 100644
--- a/src/chat_control.py
+++ b/src/chat_control.py
@@ -232,6 +232,29 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
def status_url_clicked(self, widget, url):
helpers.launch_browser_mailer('url', url)
+ def setup_seclabel(self, combo):
+ self.seclabel_combo = combo
+ self.seclabel_combo.hide()
+ self.seclabel_combo.set_no_show_all(True)
+ lb = gtk.ListStore(str)
+ self.seclabel_combo.set_model(lb)
+ cell = gtk.CellRendererText()
+ cell.set_property('xpad', 5) # padding for status text
+ self.seclabel_combo.pack_start(cell, True)
+ # text to show is in in first column of liststore
+ self.seclabel_combo.add_attribute(cell, 'text', 0)
+ if gajim.connections[self.account].seclabel_supported:
+ gajim.connections[self.account].seclabel_catalogue(self.contact.jid, self.on_seclabels_ready)
+
+ def on_seclabels_ready(self):
+ lb = self.seclabel_combo.get_model()
+ lb.clear()
+ for label in gajim.connections[self.account].seclabel_catalogues[self.contact.jid][2]:
+ lb.append([label])
+ self.seclabel_combo.set_active(0)
+ self.seclabel_combo.set_no_show_all(False)
+ self.seclabel_combo.show_all()
+
def __init__(self, type_id, parent_win, widget_name, contact, acct,
resource=None):
# Undo needs this variable to know if space has been pressed.
@@ -721,6 +744,16 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self.drag_entered_conv = True
self.conv_textview.tv.set_editable(True)
+ def get_seclabel(self):
+ label = None
+ if self.seclabel_combo is not None:
+ idx = self.seclabel_combo.get_active()
+ if idx != -1:
+ cat = gajim.connections[self.account].seclabel_catalogues[self.contact.jid]
+ lname = cat[2][idx]
+ label = cat[1][lname]
+ return label
+
def send_message(self, message, keyID='', type_='chat', chatstate=None,
msg_id=None, composing_xep=None, resource=None, xhtml=None,
callback=None, callback_args=[], process_commands=True):
@@ -733,9 +766,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
if process_commands and self.process_as_command(message):
return
+ label = self.get_seclabel()
MessageControl.send_message(self, message, keyID, type_=type_,
chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep,
resource=resource, user_nick=self.user_nick, xhtml=xhtml,
+ label=label,
callback=callback, callback_args=callback_args)
# Record message history
@@ -769,7 +804,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
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, xep0184_id=None,
- graphics=True):
+ graphics=True, displaymarking=None):
"""
Print 'chat' type messages
"""
@@ -781,7 +816,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
end = True
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)
+ subject, old_kind, xhtml, simple=simple, graphics=graphics,
+ displaymarking=displaymarking)
if xep0184_id is not None:
textview.show_xep0184_warning(xep0184_id)
@@ -1429,6 +1465,7 @@ class ChatControl(ChatControlBase):
session = gajim.connections[self.account].find_controlless_session(
self.contact.jid, resource)
+ self.setup_seclabel(self.xml.get_object('label_selector'))
if session:
session.control = self
self.session = session
@@ -2048,20 +2085,23 @@ class ChatControl(ChatControlBase):
gobject.source_remove(self.possible_inactive_timeout_id)
self._schedule_activity_timers()
- def _on_sent(id_, contact, message, encrypted, xhtml):
+ def _on_sent(id_, contact, message, encrypted, xhtml, label):
if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts',
self.account, 'request_receipt'):
xep0184_id = id_
else:
xep0184_id = None
-
+ if label:
+ displaymarking = label.getTag('displaymarking')
+ else:
+ displaymarking = None
self.print_conversation(message, self.contact.jid, encrypted=encrypted,
- xep0184_id=xep0184_id, xhtml=xhtml)
+ xep0184_id=xep0184_id, xhtml=xhtml, displaymarking=displaymarking)
ChatControlBase.send_message(self, message, keyID, type_='chat',
chatstate=chatstate_to_send, composing_xep=composing_xep,
xhtml=xhtml, callback=_on_sent,
- callback_args=[contact, message, encrypted, xhtml],
+ callback_args=[contact, message, encrypted, xhtml, self.get_seclabel()],
process_commands=process_commands)
def check_for_possible_paused_chatstate(self, arg):
@@ -2150,7 +2190,8 @@ class ChatControl(ChatControlBase):
self.session.is_loggable(), self.session and self.session.verified_identity)
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):
"""
Print a line in the conversation
@@ -2213,7 +2254,7 @@ class ChatControl(ChatControlBase):
xhtml = '<body xmlns="%s">%s</body>' % (NS_XHTML, xhtml)
ChatControlBase.print_conversation_line(self, text, kind, name, tim,
subject=subject, old_kind=self.old_msg_kind, xhtml=xhtml,
- simple=simple, xep0184_id=xep0184_id)
+ simple=simple, xep0184_id=xep0184_id, displaymarking=displaymarking)
if text.startswith('/me ') or text.startswith('/me\n'):
self.old_msg_kind = None
else:
@@ -2660,8 +2701,12 @@ class ChatControl(ChatControlBase):
kind = 'info'
else:
kind = 'print_queue'
+ dm = None
+ if len(data) > 10:
+ dm = data[10]
self.print_conversation(data[0], kind, tim = data[3],
- encrypted = data[4], subject = data[1], xhtml = data[7])
+ encrypted = data[4], subject = data[1], xhtml = data[7],
+ displaymarking=dm)
if len(data) > 6 and isinstance(data[6], int):
message_ids.append(data[6])
diff --git a/src/common/connection.py b/src/common/connection.py
index d9dbb961d..336516fdf 100644
--- a/src/common/connection.py
+++ b/src/common/connection.py
@@ -135,6 +135,9 @@ class CommonConnection:
self.blocked_groups = []
self.blocked_all = False
+ self.seclabel_supported = False
+ self.seclabel_catalogues = {}
+
self.pep_supported = False
self.pep = {}
# Do we continue connection when we get roster (send presence,get vcard..)
@@ -239,7 +242,7 @@ class CommonConnection:
def _prepare_message(self, jid, msg, keyID, type_='chat', subject='',
chatstate=None, msg_id=None, composing_xep=None, resource=None,
user_nick=None, xhtml=None, session=None, forward_from=None, form_node=None,
- original_message=None, delayed=None, callback=None):
+ label=None, original_message=None, delayed=None, callback=None):
if not self.connection or self.connected < 2:
return 1
try:
@@ -287,14 +290,14 @@ class CommonConnection:
else:
self._message_encrypted_cb(output, type_, msg, msgtxt,
original_message, fjid, resource, jid, xhtml,
- subject, chatstate, composing_xep, forward_from,
+ subject, chatstate, composing_xep, label, forward_from,
delayed, session, form_node, user_nick, keyID,
callback)
self.dispatch('GPG_ALWAYS_TRUST', _on_always_trust)
else:
self._message_encrypted_cb(output, type_, msg, msgtxt,
original_message, fjid, resource, jid, xhtml, subject,
- chatstate, composing_xep, forward_from, delayed, session,
+ chatstate, composing_xep, label, forward_from, delayed, session,
form_node, user_nick, keyID, callback)
gajim.thread_interface(encrypt_thread, [msg, keyID, False],
_on_encrypted, [])
@@ -302,15 +305,15 @@ class CommonConnection:
self._message_encrypted_cb(('', error), type_, msg, msgtxt,
original_message, fjid, resource, jid, xhtml, subject, chatstate,
- composing_xep, forward_from, delayed, session, form_node, user_nick,
+ composing_xep, label, forward_from, delayed, session, form_node, user_nick,
keyID, callback)
self._on_continue_message(type_, msg, msgtxt, original_message, fjid,
resource, jid, xhtml, subject, msgenc, keyID, chatstate, composing_xep,
- forward_from, delayed, session, form_node, user_nick, callback)
+ label, forward_from, delayed, session, form_node, user_nick, callback)
def _message_encrypted_cb(self, output, type_, msg, msgtxt, original_message,
- fjid, resource, jid, xhtml, subject, chatstate, composing_xep, forward_from,
+ fjid, resource, jid, xhtml, subject, chatstate, composing_xep, label, forward_from,
delayed, session, form_node, user_nick, keyID, callback):
msgenc, error = output
@@ -323,7 +326,7 @@ class CommonConnection:
' (' + msgtxt + ')'
self._on_continue_message(type_, msg, msgtxt, original_message, fjid,
resource, jid, xhtml, subject, msgenc, keyID, chatstate,
- composing_xep, forward_from, delayed, session, form_node, user_nick,
+ composing_xep, label, forward_from, delayed, session, form_node, user_nick,
callback)
return
# Encryption failed, do not send message
@@ -332,6 +335,7 @@ class CommonConnection:
def _on_continue_message(self, type_, msg, msgtxt, original_message, fjid,
resource, jid, xhtml, subject, msgenc, keyID, chatstate, composing_xep,
+ label,
forward_from, delayed, session, form_node, user_nick, callback):
if type_ == 'chat':
msg_iq = common.xmpp.Message(to=fjid, body=msgtxt, typ=type_,
@@ -348,6 +352,8 @@ class CommonConnection:
if form_node:
msg_iq.addChild(node=form_node)
+ if label:
+ msg_iq.addChild(node=label)
# XEP-0172: user_nickname
if user_nick:
@@ -1605,7 +1611,7 @@ class Connection(CommonConnection, ConnectionHandlers):
def send_message(self, jid, msg, keyID, type_='chat', subject='',
chatstate=None, msg_id=None, composing_xep=None, resource=None,
- user_nick=None, xhtml=None, session=None, forward_from=None, form_node=None,
+ user_nick=None, xhtml=None, label=None, session=None, forward_from=None, form_node=None,
original_message=None, delayed=None, callback=None, callback_args=[],
now=False):
@@ -1622,7 +1628,8 @@ class Connection(CommonConnection, ConnectionHandlers):
self._prepare_message(jid, msg, keyID, type_=type_, subject=subject,
chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep,
- resource=resource, user_nick=user_nick, xhtml=xhtml, session=session,
+ resource=resource, user_nick=user_nick, xhtml=xhtml, label=label,
+ session=session,
forward_from=forward_from, form_node=form_node,
original_message=original_message, delayed=delayed, callback=cb)
@@ -1830,6 +1837,15 @@ class Connection(CommonConnection, ConnectionHandlers):
iq2.addChild(name='gajim', namespace='gajim:prefs')
self.connection.send(iq)
+ def seclabel_catalogue(self, to, callback):
+ if not gajim.account_is_connected(self.name):
+ return
+ self.seclabel_catalogue_request(to, callback)
+ iq = common.xmpp.Iq(typ='get')
+ iq2 = iq.addChild(name='catalog', namespace=common.xmpp.NS_SECLABEL_CATALOG)
+ iq2.setAttr('to', to)
+ self.connection.send(iq)
+
def _request_bookmarks_xml(self):
if not gajim.account_is_connected(self.name):
return
@@ -2041,13 +2057,15 @@ class Connection(CommonConnection, ConnectionHandlers):
t.setTagData('password', password)
self.connection.send(p)
- def send_gc_message(self, jid, msg, xhtml = None):
+ def send_gc_message(self, jid, msg, xhtml = None, label = None):
if not gajim.account_is_connected(self.name):
return
if not xhtml and gajim.config.get('rst_formatting_outgoing_messages'):
from common.rst_xhtml_generator import create_xhtml
xhtml = create_xhtml(msg)
msg_iq = common.xmpp.Message(jid, msg, typ = 'groupchat', xhtml = xhtml)
+ if label is not None:
+ msg_iq.addChild(node = label)
self.connection.send(msg_iq)
self.dispatch('MSGSENT', (jid, msg))
diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py
index d60e14b5e..a42f17cbc 100644
--- a/src/common/connection_handlers.py
+++ b/src/common/connection_handlers.py
@@ -341,6 +341,8 @@ class ConnectionDisco:
if features.__contains__(common.xmpp.NS_GMAILNOTIFY):
gajim.gmail_domains.append(jid)
self.request_gmail_notifications()
+ if features.__contains__(common.xmpp.NS_SECLABEL):
+ self.seclabel_supported = True
for identity in identities:
if identity['category'] == 'pubsub' and identity.get('type') == \
'pep':
@@ -1071,6 +1073,33 @@ ConnectionCaps, ConnectionHandlersBase, ConnectionJingle):
annotation = note.getData()
self.annotations[jid] = annotation
+ def _SecLabelCB(self, con, iq_obj):
+ """
+ Security Label callback, used for catalogues.
+ """
+ log.debug('SecLabelCB')
+ query = iq_obj.getTag('catalog')
+ to = query.getAttr('to')
+ items = query.getTags('securitylabel')
+ labels = {}
+ ll = []
+ for item in items:
+ label = item.getTag('displaymarking').getData()
+ labels[label] = item
+ ll.append(label)
+ if to not in self.seclabel_catalogues:
+ self.seclabel_catalogues[to] = [[], None, None]
+ self.seclabel_catalogues[to][1] = labels
+ self.seclabel_catalogues[to][2] = ll
+ for callback in self.seclabel_catalogues[to][0]:
+ callback()
+ self.seclabel_catalogues[to][0] = []
+
+ def seclabel_catalogue_request(self, to, callback):
+ if to not in self.seclabel_catalogues:
+ self.seclabel_catalogues[to] = [[], None, None]
+ self.seclabel_catalogues[to][0].append(callback)
+
def _parse_bookmarks(self, storage, storage_type):
"""
storage_type can be 'pubsub' or 'xml' to tell from where we got bookmarks
@@ -1618,12 +1647,15 @@ ConnectionCaps, ConnectionHandlersBase, ConnectionJingle):
self.dispatch('GC_CONFIG_CHANGE', (jid, statusCode))
return
- # Ignore message from room in which we are not
+ displaymarking = None
+ seclabel = msg.getTag('securitylabel')
+ if seclabel and seclabel.getNamespace() == common.xmpp.NS_SECLABEL:
+ displaymarking = seclabel.getTag('displaymarking') # Ignore message from room in which we are not
if jid not in self.last_history_time:
return
self.dispatch('GC_MSG', (frm, msgtxt, tim, has_timestamp, msg.getXHTML(),
- statusCode))
+ statusCode, displaymarking))
tim_int = int(float(mktime(tim)))
if gajim.config.should_log(self.name, jid) and not \
@@ -2302,6 +2334,8 @@ ConnectionCaps, ConnectionHandlersBase, ConnectionJingle):
common.xmpp.NS_MUC_ADMIN)
con.RegisterHandler('iq', self._PrivateCB, 'result',
common.xmpp.NS_PRIVATE)
+ con.RegisterHandler('iq', self._SecLabelCB, 'result',
+ common.xmpp.NS_SECLABEL_CATALOG)
con.RegisterHandler('iq', self._HttpAuthCB, 'get',
common.xmpp.NS_HTTP_AUTH)
con.RegisterHandler('iq', self._CommandExecuteCB, 'set',
diff --git a/src/common/gajim.py b/src/common/gajim.py
index 214f5e369..a44029de5 100644
--- a/src/common/gajim.py
+++ b/src/common/gajim.py
@@ -193,7 +193,7 @@ gajim_common_features = [xmpp.NS_BYTESTREAM, xmpp.NS_SI, xmpp.NS_FILE,
'jabber:iq:gateway', xmpp.NS_LAST, xmpp.NS_PRIVACY, xmpp.NS_PRIVATE,
xmpp.NS_REGISTER, xmpp.NS_VERSION, xmpp.NS_DATA, xmpp.NS_ENCRYPTED, 'msglog',
'sslc2s', 'stringprep', xmpp.NS_PING, xmpp.NS_TIME_REVISED, xmpp.NS_SSN,
- xmpp.NS_MOOD, xmpp.NS_ACTIVITY, xmpp.NS_NICK, xmpp.NS_ROSTERX]
+ xmpp.NS_MOOD, xmpp.NS_ACTIVITY, xmpp.NS_NICK, xmpp.NS_ROSTERX, xmpp.NS_SECLABEL]
# Optional features gajim supports per account
gajim_optional_features = {}
diff --git a/src/common/xmpp/protocol.py b/src/common/xmpp/protocol.py
index a14eb8dca..01dd49d86 100644
--- a/src/common/xmpp/protocol.py
+++ b/src/common/xmpp/protocol.py
@@ -100,6 +100,8 @@ NS_ROSTERX ='http://jabber.org/protocol/rosterx'
NS_ROSTER_VER ='urn:xmpp:features:rosterver' # XEP-0273
NS_RPC ='jabber:iq:rpc' # XEP-0009
NS_SASL ='urn:ietf:params:xml:ns:xmpp-sasl'
+NS_SECLABEL ='urn:xmpp:sec-label:0'
+NS_SECLABEL_CATALOG ='urn:xmpp:sec-label:catalog:0'
NS_SEARCH ='jabber:iq:search'
NS_SERVER ='jabber:server'
NS_SESSION ='urn:ietf:params:xml:ns:xmpp-session'
diff --git a/src/conversation_textview.py b/src/conversation_textview.py
index a96c41b67..46e60dfee 100644
--- a/src/conversation_textview.py
+++ b/src/conversation_textview.py
@@ -326,6 +326,7 @@ class ConversationTextview(gobject.GObject):
tag.set_property('underline', pango.UNDERLINE_SINGLE)
buffer_.create_tag('focus-out-line', justification = gtk.JUSTIFY_CENTER)
+ self.displaymarking_tags = {}
tag = buffer_.create_tag('xep0184-warning')
@@ -1173,7 +1174,7 @@ class ConversationTextview(gobject.GObject):
def print_conversation_line(self, text, jid, kind, name, tim,
other_tags_for_name=[], other_tags_for_time=[],
other_tags_for_text=[], subject=None, old_kind=None, xhtml=None,
- simple=False, graphics=True):
+ simple=False, graphics=True, displaymarking=None):
"""
Print 'chat' type messages
"""
@@ -1238,6 +1239,9 @@ class ConversationTextview(gobject.GObject):
tim_format = self.get_time_to_show(tim)
buffer_.insert_with_tags_by_name(end_iter, tim_format + '\n',
'time_sometimes')
+ # If there's a displaymarking, print it here.
+ if displaymarking:
+ self.print_displaymarking(displaymarking)
# kind = info, we print things as if it was a status: same color, ...
if kind in ('error', 'info'):
kind = 'status'
@@ -1309,6 +1313,19 @@ class ConversationTextview(gobject.GObject):
elif text.startswith('/me ') or text.startswith('/me\n'):
return kind
+ def print_displaymarking(self, displaymarking):
+ bgcolor = displaymarking.getAttr('bgcolor') or '#FFF'
+ fgcolor = displaymarking.getAttr('fgcolor') or '#000'
+ text = displaymarking.getData()
+ if text:
+ buffer_ = self.tv.get_buffer()
+ end_iter = buffer_.get_end_iter()
+ tag = self.displaymarking_tags.setdefault(bgcolor + '/' + fgcolor,
+ buffer_.create_tag(None, background=bgcolor, foreground=fgcolor))
+ buffer_.insert_with_tags(end_iter, '[' + text + ']', tag)
+ end_iter = buffer_.get_end_iter()
+ buffer_.insert_with_tags(end_iter, ' ')
+
def print_name(self, name, kind, other_tags_for_name):
if name:
buffer_ = self.tv.get_buffer()
diff --git a/src/groupchat_control.py b/src/groupchat_control.py
index bf78159db..b604c8fba 100644
--- a/src/groupchat_control.py
+++ b/src/groupchat_control.py
@@ -385,6 +385,8 @@ class GroupchatControl(ChatControlBase):
column.set_visible(False)
self.list_treeview.set_expander_column(column)
+ self.setup_seclabel(self.xml.get_object('label_selector'))
+
gajim.gc_connected[self.account][self.room_jid] = False
# disable win, we are not connected yet
ChatControlBase.got_disconnected(self)
@@ -785,30 +787,30 @@ class GroupchatControl(ChatControlBase):
menu.destroy()
def on_message(self, nick, msg, tim, has_timestamp=False, xhtml=None,
- status_code=[]):
+ status_code=[], displaymarking=None):
if '100' in status_code:
# Room is not anonymous
self.is_anonymous = False
if not nick:
# message from server
- self.print_conversation(msg, tim=tim, xhtml=xhtml)
+ self.print_conversation(msg, tim=tim, xhtml=xhtml, displaymarking=displaymarking)
else:
# message from someone
if has_timestamp:
# don't print xhtml if it's an old message.
# Like that xhtml messages are grayed too.
- self.print_old_conversation(msg, nick, tim, None)
+ self.print_old_conversation(msg, nick, tim, None, displaymarking=displaymarking)
else:
- self.print_conversation(msg, nick, tim, xhtml)
+ self.print_conversation(msg, nick, tim, xhtml, displaymarking=displaymarking)
def on_private_message(self, nick, msg, tim, xhtml, session, msg_id=None,
- encrypted=False):
+ encrypted=False, displaymarking=None):
# Do we have a queue?
fjid = self.room_jid + '/' + nick
no_queue = len(gajim.events.get_events(self.account, fjid)) == 0
event = gajim.events.create_event('pm', (msg, '', 'incoming', tim,
- encrypted, '', msg_id, xhtml, session))
+ encrypted, '', msg_id, xhtml, session, displaymarking))
gajim.events.add_event(self.account, fjid, event)
autopopup = gajim.config.get('autopopup')
@@ -851,7 +853,8 @@ class GroupchatControl(ChatControlBase):
role_iter = model.iter_next(role_iter)
return None
- def print_old_conversation(self, text, contact='', tim=None, xhtml = None):
+ def print_old_conversation(self, text, contact='', tim=None, xhtml = None,
+ displaymarking=None):
if isinstance(text, str):
text = unicode(text, 'utf-8')
if contact:
@@ -867,10 +870,11 @@ class GroupchatControl(ChatControlBase):
small_attr = []
ChatControlBase.print_conversation_line(self, text, kind, contact, tim,
small_attr, small_attr + ['restored_message'],
- small_attr + ['restored_message'], count_as_new=False, xhtml=xhtml)
+ small_attr + ['restored_message'], count_as_new=False, xhtml=xhtml,
+ displaymarking=displaymarking)
def print_conversation(self, text, contact='', tim=None, xhtml=None,
- graphics=True):
+ graphics=True, displaymarking=None):
"""
Print a line in the conversation
@@ -937,7 +941,7 @@ class GroupchatControl(ChatControlBase):
ChatControlBase.print_conversation_line(self, text, kind, contact, tim,
other_tags_for_name, [], other_tags_for_text, xhtml=xhtml,
- graphics=graphics)
+ graphics=graphics, displaymarking=displaymarking)
def get_nb_unread(self):
type_events = ['printed_marked_gc_msg']
@@ -1588,12 +1592,13 @@ class GroupchatControl(ChatControlBase):
if not message:
return
+ label = self.get_seclabel()
if message != '' or message != '\n':
self.save_sent_message(message)
# Send the message
gajim.connections[self.account].send_gc_message(self.room_jid,
- message, xhtml=xhtml)
+ message, xhtml=xhtml, label=label)
self.msg_textview.get_buffer().set_text('')
self.msg_textview.grab_focus()
diff --git a/src/gui_interface.py b/src/gui_interface.py
index 769b14ded..369c27637 100644
--- a/src/gui_interface.py
+++ b/src/gui_interface.py
@@ -956,7 +956,7 @@ class Interface:
def handle_event_gc_msg(self, account, array):
# ('GC_MSG', account, (jid, msg, time, has_timestamp, htmlmsg,
- # [status_codes]))
+ # [status_codes], displaymarking))
jids = array[0].split('/', 1)
room_jid = jids[0]
@@ -980,7 +980,7 @@ class Interface:
# message from someone
nick = jids[1]
- gc_control.on_message(nick, msg, array[2], array[3], xhtml, array[5])
+ gc_control.on_message(nick, msg, array[2], array[3], xhtml, array[5], displaymarking=array[6])
if self.remote_ctrl:
highlight = gc_control.needs_visual_notification(msg)
diff --git a/src/message_control.py b/src/message_control.py
index 5dfce76eb..d09cb446b 100644
--- a/src/message_control.py
+++ b/src/message_control.py
@@ -208,7 +208,7 @@ class MessageControl:
def send_message(self, message, keyID='', type_='chat', chatstate=None,
msg_id=None, composing_xep=None, resource=None, user_nick=None,
- xhtml=None, callback=None, callback_args=[]):
+ xhtml=None, label=None, callback=None, callback_args=[]):
# Send the given message to the active tab.
# Doesn't return None if error
jid = self.contact.jid
@@ -241,5 +241,5 @@ class MessageControl:
conn.send_message(jid, message, keyID, type_=type_, chatstate=chatstate,
msg_id=msg_id, composing_xep=composing_xep, resource=self.resource,
user_nick=user_nick, session=self.session,
- original_message=original_message, xhtml=xhtml, callback=callback,
+ original_message=original_message, xhtml=xhtml, label=label, callback=callback,
callback_args=callback_args)
diff --git a/src/session.py b/src/session.py
index 25889e1f0..4af87c20b 100644
--- a/src/session.py
+++ b/src/session.py
@@ -95,6 +95,8 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
self.resource = resource
if self.control and self.control.resource:
self.control.change_resource(self.resource)
+ seclabel = None
+ displaymarking = None
if not msg_type or msg_type not in ('chat', 'groupchat', 'error'):
msg_type = 'normal'
@@ -113,7 +115,9 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
break
composing_xep, chatstate = self.get_chatstate(msg, msgtxt)
-
+ seclabel = msg.getTag('securitylabel')
+ if seclabel and seclabel.getNamespace() == common.xmpp.NS_SECLABEL:
+ displaymarking = seclabel.getTag('displaymarking')
xhtml = msg.getXHTML()
if msg_type == 'chat':
@@ -236,15 +240,15 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
if self.control:
# print if a control is open
self.control.print_conversation(msgtxt, tim=tim, xhtml=xhtml,
- encrypted=encrypted)
+ encrypted=encrypted, displaymarking=displaymarking)
else:
# otherwise pass it off to the control to be queued
groupchat_control.on_private_message(nickname, msgtxt, tim,
- xhtml, self, msg_id=msg_id, encrypted=encrypted)
+ xhtml, self, msg_id=msg_id, encrypted=encrypted, displaymarking=displaymarking)
else:
self.roster_message(jid, msgtxt, tim, encrypted, msg_type,
subject, resource, msg_id, user_nick, advanced_notif_num,
- xhtml=xhtml, form_node=form_node)
+ xhtml=xhtml, form_node=form_node, displaymarking=displaymarking)
nickname = gajim.get_name_from_jid(self.conn.name, jid)
@@ -270,7 +274,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
def roster_message(self, jid, msg, tim, encrypted=False, msg_type='',
subject=None, resource='', msg_id=None, user_nick='',
- advanced_notif_num=None, xhtml=None, form_node=None):
+ advanced_notif_num=None, xhtml=None, form_node=None, displaymarking=None):
"""
Display the message or show notification in the roster
"""
@@ -334,7 +338,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
if msg_type == 'normal' and popup: # it's single message to be autopopuped
dialogs.SingleMessageWindow(self.conn.name, contact.jid,
action='receive', from_whom=jid, subject=subject, message=msg,
- resource=resource, session=self, form_node=form_node)
+ resource=resource, session=self, form_node=form_node, displaymarking=displaymarking)
return
# We print if window is opened and it's not a single message
@@ -345,7 +349,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
typ = 'error'
self.control.print_conversation(msg, typ, tim=tim, encrypted=encrypted,
- subject=subject, xhtml=xhtml)
+ subject=subject, xhtml=xhtml, displaymarking=displaymarking)
if msg_id:
gajim.logger.set_read_messages([msg_id])
@@ -366,7 +370,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
contact)
event = gajim.events.create_event(type_, (msg, subject, msg_type, tim,
- encrypted, resource, msg_id, xhtml, self, form_node),
+ encrypted, resource, msg_id, xhtml, self, form_node, displaymarking),
show_in_roster=show_in_roster, show_in_systray=show_in_systray)
gajim.events.add_event(self.conn.name, fjid, event)