Commit 8ec3ec8a authored by Philipp Hörist's avatar Philipp Hörist

Merge branch 'extensionpoints' into 'master'

New Encryption Plugin API

See merge request !96
parents 3e6ecccc 2e148a61
......@@ -939,6 +939,26 @@
<property name="position">11</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="encryption_menu">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="relief">none</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">channel-secure-symbolic.symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">12</property>
</packing>
</child>
<child>
<object class="GtkBox" id="audio_buttons_hbox">
<property name="can_focus">False</property>
......@@ -1039,7 +1059,7 @@ audio-mic-volume-low</property>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">12</property>
<property name="position">13</property>
</packing>
</child>
<child>
......@@ -1050,12 +1070,9 @@ audio-mic-volume-low</property>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">13</property>
<property name="position">14</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="send_button">
<property name="label" translatable="yes">_Send</property>
......@@ -1077,6 +1094,9 @@ audio-mic-volume-low</property>
<property name="position">15</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
......
......@@ -45,28 +45,6 @@
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="encryption_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkCheckMenuItem" id="toggle_gpg_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Toggle Open_PGP Encryption</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkCheckMenuItem" id="toggle_e2e_menuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Toggle End to End Encryption</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="menuitem3">
<property name="visible">True</property>
......
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkImage" id="image1">
......@@ -127,19 +127,56 @@
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="message_scrolledwindow">
<object class="GtkBox" id="hbox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">3</property>
<child>
<placeholder/>
<object class="GtkButton" id="authentication_button">
<property name="name">ChatControl-AuthenticationButton</property>
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">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="no_show_all">True</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="lock_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-dialog-authentication</property>
<property name="icon_size">1</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="message_scrolledwindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
......@@ -214,12 +251,12 @@
<object class="GtkButton" id="formattings_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">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="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show a list of formattings</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>
<object class="GtkImage" id="image11">
<property name="visible">True</property>
......@@ -364,12 +401,12 @@
<object class="GtkButton" id="muc_window_actions_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">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="has_tooltip">True</property>
<property name="tooltip_text" translatable="yes">Show advanced functions (Alt+D)</property>
<property name="relief">none</property>
<property name="focus_on_click">False</property>
<child>
<object class="GtkImage" id="image1344">
<property name="visible">True</property>
......@@ -397,7 +434,24 @@
</packing>
</child>
<child>
<placeholder/>
<object class="GtkMenuButton" id="encryption_menu">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="relief">none</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">channel-secure-symbolic.symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">10</property>
</packing>
</child>
<child>
<object class="GtkButton" id="send_button">
......@@ -418,6 +472,9 @@
<property name="position">11</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
......
......@@ -64,7 +64,7 @@
</object>
</child>
</object>
<object class="GtkWindow" id="message_window">
<object class="GtkApplicationWindow" id="message_window">
<property name="can_focus">False</property>
<property name="default_width">480</property>
<property name="default_height">440</property>
......
This diff is collapsed.
......@@ -34,6 +34,7 @@ from gi.repository import Gdk
from gi.repository import Pango
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gio
import gtkgui_helpers
import message_control
import dialogs
......@@ -395,6 +396,11 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self._on_window_motion_notify)
self.handlers[id_] = parent_win.window
self.encryption = 'disabled'
self.set_encryption_state()
if self.parent_win:
self.add_window_actions()
# PluginSystem: adding GUI extension point for ChatControlBase
# instance object (also subclasses, eg. ChatControl or GroupchatControl)
gajim.plugin_manager.gui_extension_point('chat_control_base', self)
......@@ -412,6 +418,41 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
# to properly use the super, because of the old code.
CommandTools.__init__(self)
def add_window_actions(self):
action = Gio.SimpleAction.new_stateful(
"%s-encryptiongroup" % self.contact.jid,
GLib.VariantType.new("s"),
GLib.Variant("s", self.encryption))
action.connect("change-state", self.activate_encryption)
self.parent_win.window.add_action(action)
def activate_encryption(self, action, param):
encryption = param.get_string()
if self.encryption == encryption:
return
if encryption != 'disabled':
plugin = gajim.plugin_manager.encryption_plugins[encryption]
if not plugin.activate_encryption(self):
return
else:
if not self.widget_name == 'groupchat_control':
self.terminate_esessions()
action.set_state(param)
gajim.config.set_per(
'contacts', self.contact.jid, 'encryption', encryption)
self.encryption = encryption
self.set_lock_image()
def set_encryption_state(self):
enc = gajim.config.get_per('contacts', self.contact.jid, 'encryption')
if enc not in gajim.plugin_manager.encryption_plugins:
self.encryption = 'disabled'
gajim.config.set_per(
'contacts', self.contact.jid, 'encryption', 'disabled')
else:
self.encryption = enc
def set_speller(self):
# now set the one the user selected
per_type = 'contacts'
......@@ -723,7 +764,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
keyID=keyID, type_=type_, chatstate=chatstate, msg_id=msg_id,
resource=resource, user_nick=self.user_nick, xhtml=xhtml,
label=label, callback=_cb, callback_args=[callback] + callback_args,
control=self, attention=attention, correction_msg=correction_msg, automatic_message=False))
control=self, attention=attention, correction_msg=correction_msg,
automatic_message=False, encryption=self.encryption))
# Record the history of sent messages
self.save_message(message, 'sent')
......
......@@ -179,11 +179,6 @@ class StandardCommonChatCommands(CommandContainer):
def clear(self):
self.conv_textview.clear()
@command
@doc(_("Toggle the OpenPGP encryption"))
def gpg(self):
self._toggle_gpg()
@command
@doc(_("Send a ping to the contact"))
def ping(self):
......
......@@ -480,8 +480,7 @@ class Config:
'state_muc_directed_msg_color': [ opt_color, 'red2' ],
}, {}),
'contacts': ({
'gpg_enabled': [ opt_bool, False, _('Is OpenPGP enabled for this contact?')],
'autonegotiate_esessions': [opt_bool, False, _('Should Gajim automatically start an encrypted session with this contact when possible?')],
'encryption': [ opt_str, '', _('Encryption used for this contact.')],
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
}, {}),
'rooms': ({
......
......@@ -296,65 +296,9 @@ class CommonConnection:
if not obj.message and obj.chatstate is None and obj.form_node is None:
return
if obj.keyID and self.USE_GPG:
self._encrypt_message(obj)
return
self._build_message_stanza(obj)
def _encrypt_message(self, obj):
obj.xhtml = None
if obj.keyID == 'UNKNOWN':
error = _('Neither the remote presence is signed, nor a key was '
'assigned.')
elif obj.keyID.endswith('MISMATCH'):
error = _('The contact\'s key (%s) does not match the key assigned '
'in Gajim.' % obj.keyID[:8])
else:
myKeyID = gajim.config.get_per('accounts', self.name, 'keyid')
key_list = [obj.keyID, myKeyID]
def _on_encrypted(output):
msgenc, error = output
if error.startswith('NOT_TRUSTED'):
def _on_always_trust(answer):
if answer:
gajim.thread_interface(
self.gpg.encrypt, [obj.message, key_list, True],
_on_encrypted, [])
else:
self._finished_encrypt(obj, msgenc=msgenc,
error=error)
gajim.nec.push_incoming_event(GPGTrustKeyEvent(None,
conn=self, keyID=error.split(' ')[-1],
callback=_on_always_trust))
else:
self._finished_encrypt(obj, msgenc=msgenc, error=error)
gajim.thread_interface(
self.gpg.encrypt, [obj.message, key_list, False],
_on_encrypted, [])
return
self._finished_encrypt(obj, error=error)
def _finished_encrypt(self, obj, msgenc=None, error=None):
if error:
gajim.nec.push_incoming_event(
MessageNotSentEvent(
None, conn=self, jid=obj.jid, message=obj.message,
error=error, time_=time.time(), session=obj.session))
return
self._build_message_stanza(obj, msgenc)
def _build_message_stanza(self, obj, msgenc=None):
if msgenc:
msgtxt = '[This message is *encrypted* (See :XEP:`27`]'
lang = os.getenv('LANG')
if lang is not None and not lang.startswith('en'):
# we're not english: one in locale and one en
msgtxt = _('[This message is *encrypted* (See :XEP:`27`]') + \
' (' + msgtxt + ')'
else:
msgtxt = obj.message
def _build_message_stanza(self, obj):
if obj.jid == gajim.get_jid_from_account(self.name):
fjid = obj.jid
else:
......@@ -368,44 +312,30 @@ class CommonConnection:
namespace=nbxmpp.NS_CORRECT)
id2 = self.connection.getAnID()
obj.correction_msg.setID(id2)
obj.correction_msg.setBody(msgtxt)
obj.correction_msg.setBody(obj.message)
if obj.xhtml:
obj.correction_msg.setXHTML(obj.xhtml)
if msgenc:
encrypted_tag = obj.correction_msg.getTag(
'x', namespace=nbxmpp.NS_ENCRYPTED)
obj.correction_msg.delChild(encrypted_tag)
obj.correction_msg.setTag(
'x', namespace=nbxmpp.NS_ENCRYPTED).setData(msgenc)
if obj.session:
obj.session.last_send = time.time()
# XEP-0200
if obj.session.enable_encryption:
obj.correction_msg = obj.session.encrypt_stanza(obj.correction_msg)
self._push_stanza_message_outgoing(obj, obj.correction_msg)
return
if obj.type_ == 'chat':
msg_iq = nbxmpp.Message(body=msgtxt, typ=obj.type_,
msg_iq = nbxmpp.Message(body=obj.message, typ=obj.type_,
xhtml=obj.xhtml)
else:
if obj.subject:
msg_iq = nbxmpp.Message(body=msgtxt, typ='normal',
msg_iq = nbxmpp.Message(body=obj.message, typ='normal',
subject=obj.subject, xhtml=obj.xhtml)
else:
msg_iq = nbxmpp.Message(body=msgtxt, typ='normal',
msg_iq = nbxmpp.Message(body=obj.message, typ='normal',
xhtml=obj.xhtml)
if obj.msg_id:
msg_iq.setID(obj.msg_id)
if msgenc:
msg_iq.setTag('x', namespace=nbxmpp.NS_ENCRYPTED).setData(msgenc)
if obj.form_node:
msg_iq.addChild(node=obj.form_node)
if obj.label:
......@@ -460,7 +390,7 @@ class CommonConnection:
if obj.chatstate and contact and contact.supports(nbxmpp.NS_CHATSTATES):
msg_iq.setTag(obj.chatstate, namespace=nbxmpp.NS_CHATSTATES)
only_chatste = False
if not msgtxt:
if not obj.message:
only_chatste = True
if only_chatste and not obj.session.enable_encryption:
msg_iq.setTag('no-store',
......@@ -468,8 +398,9 @@ class CommonConnection:
# XEP-0184
if obj.jid != gajim.get_jid_from_account(self.name):
if msgtxt and gajim.config.get_per('accounts', self.name,
'request_receipt'):
request = gajim.config.get_per('accounts', self.name,
'request_receipt')
if obj.message and request:
msg_iq.setTag('request', namespace=nbxmpp.NS_RECEIPTS)
if obj.forward_from:
......@@ -483,23 +414,9 @@ class CommonConnection:
obj.session.last_send = time.time()
msg_iq.setThread(obj.session.thread_id)
# XEP-0200
if obj.session.enable_encryption:
msg_iq = obj.session.encrypt_stanza(msg_iq)
if self.carbons_enabled:
msg_iq.addChild(name='private',
namespace=nbxmpp.NS_CARBONS)
msg_iq.addChild(name='no-permanent-store',
namespace=nbxmpp.NS_MSG_HINTS)
msg_iq.addChild(name='no-copy',
namespace=nbxmpp.NS_MSG_HINTS)
if only_chatste:
msg_iq.addChild(name='no-store',
namespace=nbxmpp.NS_MSG_HINTS)
self._push_stanza_message_outgoing(obj, msg_iq)
def _push_stanza_message_outgoing(self, obj, msg_iq):
def _push_stanza_message_outgoing(self, obj, msg_iq):
obj.conn = self
if isinstance(msg_iq, list):
for iq in msg_iq:
......@@ -2136,6 +2053,14 @@ class Connection(CommonConnection, ConnectionHandlers):
def _nec_stanza_message_outgoing(self, obj):
if obj.conn.name != self.name:
return
encryption = gajim.config.get_per('contacts', obj.jid, 'encryption')
if encryption != 'disabled':
gajim.plugin_manager.gui_extension_point(
'encrypt' + encryption, self, obj, self.send_message)
else:
self.send_message(obj)
def send_message(self, obj):
obj.msg_id = self.connection.send(obj.msg_iq, now=obj.now)
gajim.nec.push_incoming_event(MessageSentEvent(
......@@ -2747,6 +2672,14 @@ class Connection(CommonConnection, ConnectionHandlers):
def _nec_gc_stanza_message_outgoing(self, obj):
if obj.conn.name != self.name:
return
encryption = gajim.config.get_per('contacts', obj.jid, 'encryption')
if encryption != 'disabled':
gajim.plugin_manager.gui_extension_point(
'gc_encrypt' + encryption, self, obj, self.send_gc_message)
else:
self.send_gc_message(obj)
def send_gc_message(self, obj):
if obj.correction_msg:
obj.msg_id = self.connection.send(obj.correction_msg)
else:
......
......@@ -897,7 +897,7 @@ class ConnectionHandlersBase:
gajim.ged.register_event_handler('message-received', ged.CORE,
self._nec_message_received)
gajim.ged.register_event_handler('mam-message-received', ged.CORE,
self._nec_mam_message_received)
self._nec_message_received)
gajim.ged.register_event_handler('decrypted-message-received', ged.CORE,
self._nec_decrypted_message_received)
......@@ -911,7 +911,7 @@ class ConnectionHandlersBase:
gajim.ged.remove_event_handler('message-received', ged.CORE,
self._nec_message_received)
gajim.ged.remove_event_handler('mam-message-received', ged.CORE,
self._nec_mam_message_received)
self._nec_message_received)
gajim.ged.remove_event_handler('decrypted-message-received', ged.CORE,
self._nec_decrypted_message_received)
......@@ -1080,78 +1080,22 @@ class ConnectionHandlersBase:
if sess.enable_encryption:
sess.terminate_e2e()
def decrypt_thread(self, encmsg, keyID, obj):
decmsg = self.gpg.decrypt(encmsg, keyID)
decmsg = self.connection.Dispatcher.replace_non_character(decmsg)
# \x00 chars are not allowed in C (so in GTK)
obj.msgtxt = decmsg.replace('\x00', '')
obj.encrypted = 'xep27'
self.gpg_messages_to_decrypt.remove([encmsg, keyID, obj])
def _nec_message_received(self, obj):
if obj.conn.name != self.name:
return
if obj.encrypted == 'xep200':
try:
obj.stanza = obj.session.decrypt_stanza(obj.stanza)
obj.msgtxt = obj.stanza.getBody()
except Exception:
gajim.nec.push_incoming_event(FailedDecryptEvent(None,
conn=self, msg_obj=obj))
return
if obj.enc_tag and self.USE_GPG:
encmsg = obj.enc_tag.getData()
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
if keyID:
self.gpg_messages_to_decrypt.append([encmsg, keyID, obj])
if len(self.gpg_messages_to_decrypt) == 1:
gajim.thread_interface(self.decrypt_thread, [encmsg, keyID,
obj], self._on_message_decrypted, [obj])
return
gajim.nec.push_incoming_event(DecryptedMessageReceivedEvent(None,
conn=self, msg_obj=obj))
gajim.plugin_manager.gui_extension_point(
'decrypt', self, obj, self._on_message_received)
if not obj.encrypted:
self._on_message_received(obj)
def _nec_mam_message_received(self, obj):
if obj.conn.name != self.name:
return
if obj.enc_tag and self.USE_GPG:
encmsg = obj.enc_tag.getData()
keyID = gajim.config.get_per('accounts', self.name, 'keyid')
if keyID:
self.gpg_messages_to_decrypt.append([encmsg, keyID, obj])
if len(self.gpg_messages_to_decrypt) == 1:
gajim.thread_interface(self.decrypt_thread, [encmsg, keyID,
obj], self._on_mam_message_decrypted, [obj])
return
gajim.nec.push_incoming_event(MamDecryptedMessageReceivedEvent(None,
conn=self, msg_obj=obj))
def _on_message_decrypted(self, output, obj):
if len(self.gpg_messages_to_decrypt):
encmsg, keyID, obj2 = self.gpg_messages_to_decrypt[0]
if type(obj2) == MessageReceivedEvent:
cb = self._on_message_decrypted
else:
cb = self._on_mam_message_decrypted
gajim.thread_interface(self.decrypt_thread, [encmsg, keyID, obj2],
cb, [obj2])
gajim.nec.push_incoming_event(DecryptedMessageReceivedEvent(None,
conn=self, msg_obj=obj))
def _on_mam_message_decrypted(self, output, obj):
if len(self.gpg_messages_to_decrypt):
encmsg, keyID, obj2 = self.gpg_messages_to_decrypt[0]
if type(obj2) == MessageReceivedEvent:
cb = self._on_message_decrypted
else:
cb = self._on_mam_message_decrypted
gajim.thread_interface(self.decrypt_thread, [encmsg, keyID, obj2],
cb, [obj2])
gajim.nec.push_incoming_event(MamDecryptedMessageReceivedEvent(None,
conn=self, msg_obj=obj))
def _on_message_received(self, obj):
if isinstance(obj, MessageReceivedEvent):
gajim.nec.push_incoming_event(
DecryptedMessageReceivedEvent(None, conn=self, msg_obj=obj))
else:
gajim.nec.push_incoming_event(
MamDecryptedMessageReceivedEvent(None, conn=self, msg_obj=obj))
def _nec_decrypted_message_received(self, obj):
if obj.conn.name != self.name:
......
......@@ -1035,6 +1035,7 @@ class MamMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
def init(self):
self.additional_data = {}
self.encrypted = False
def generate(self):
if not self.stanza:
......@@ -1067,7 +1068,6 @@ class MamMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.with_ = to_
self.direction = 'to'
self.resource = gajim.get_resource_from_jid(self.msg_.getAttr('to'))
self.enc_tag = self.msg_.getTag('x', namespace=nbxmpp.NS_ENCRYPTED)
return True
class MamDecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
......@@ -1122,6 +1122,7 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.get_id()
self.forwarded = False
self.sent = False
self.encrypted = False
account = self.conn.name
our_full_jid = gajim.get_jid_from_account(account, full=True)
......@@ -1216,33 +1217,31 @@ class MessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
conn=self.conn, stanza=forwarded))
return
self.enc_tag = self.stanza.getTag('x', namespace=nbxmpp.NS_ENCRYPTED)
if not self.enc_tag:
# Mediated invitation?
muc_user = self.stanza.getTag('x', namespace=nbxmpp.NS_MUC_USER)
if muc_user:
if muc_user.getTag('decline'):
gajim.nec.push_incoming_event(
GcDeclineReceivedEvent(
None, conn=self.conn,
room_jid=self.fjid, stanza=muc_user))
return
if muc_user.getTag('invite'):
gajim.nec.push_incoming_event(
GcInvitationReceivedEvent(
None, conn=self.conn, jid_from=self.fjid,
mediated=True, stanza=muc_user))
return
else:
# Direct invitation?
direct = self.stanza.getTag(
'x', namespace=nbxmpp.NS_CONFERENCE)
if direct:
gajim.nec.push_incoming_event(
GcInvitationReceivedEvent(
None, conn=self.conn, jid_from=self.fjid,
mediated=False, stanza=direct))
return
# Mediated invitation?
muc_user = self.stanza.getTag('x', namespace=nbxmpp.NS_MUC_USER)
if muc_user:
if muc_user.getTag('decline'):
gajim.nec.push_incoming_event(
GcDeclineReceivedEvent(
None, conn=self.conn,
room_jid=self.fjid, stanza=muc_user))
return
if muc_user.getTag('invite'):
gajim.nec.push_incoming_event(
GcInvitationReceivedEvent(
None, conn=self.conn, jid_from=self.fjid,
mediated=True, stanza=muc_user))
return
else:
# Direct invitation?
direct = self.stanza.getTag(
'x', namespace=nbxmpp.NS_CONFERENCE)
if direct:
gajim.nec.push_incoming_event(
GcInvitationReceivedEvent(
None, conn=self.conn, jid_from=self.fjid,
mediated=False, stanza=direct))
return