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
path: root/src
diff options
context:
space:
mode:
authorPhilipp Hörist <forenjunkie@chello.at>2017-04-13 23:58:51 +0300
committerPhilipp Hörist <forenjunkie@chello.at>2017-05-07 19:38:06 +0300
commit5116af037ba31bc30d7eaa7aeb5e3b0ba9ea2d76 (patch)
treed5a0907a5143c9b99f4426580cb59ef1c0456219 /src
parent3e6ecccc269855dde20f96b2923cd18e0dbf4a69 (diff)
Add Encryption Plugin API
- Add extension points when receiving/sending a message - Add extension point for setting the lock image - Add extension point after clicking the send button - Add extension point when typing - Add a new menu button to choose the desired encryption - Extend the PluginManager to hold a list of encryption plugins
Diffstat (limited to 'src')
-rw-r--r--src/chat_control.py33
-rw-r--r--src/chat_control_base.py40
-rw-r--r--src/common/config.py1
-rw-r--r--src/common/connection.py10
-rw-r--r--src/common/connection_handlers.py14
-rw-r--r--src/common/connection_handlers_events.py1
-rw-r--r--src/gui_menu_builder.py11
-rw-r--r--src/plugins/gajimplugin.py10
-rw-r--r--src/plugins/pluginmanager.py16
9 files changed, 134 insertions, 2 deletions
diff --git a/src/chat_control.py b/src/chat_control.py
index 83eecc57f..0fb0706b2 100644
--- a/src/chat_control.py
+++ b/src/chat_control.py
@@ -94,6 +94,7 @@ class ChatControl(ChatControlBase):
self.last_recv_message_id = None
self.last_recv_message_marks = None
self.last_message_timestamp = None
+
# for muc use:
# widget = self.xml.get_object('muc_window_actions_button')
self.actions_button = self.xml.get_object('message_window_actions_button')
@@ -302,6 +303,11 @@ class ChatControl(ChatControlBase):
True)
self.update_ui()
+ self.set_lock_image()
+
+ self.encryption_menu = self.xml.get_object('encryption_menu')
+ self.encryption_menu.set_menu_model(
+ gui_menu_builder.get_encryption_menu(self.contact))
# restore previous conversation
self.restore_conversation()
self.msg_textview.grab_focus()
@@ -907,6 +913,21 @@ class ChatControl(ChatControlBase):
self._show_lock_image(self.gpg_is_active, 'OpenPGP',
self.gpg_is_active, loggable, True)
+ def set_lock_image(self):
+ visible = self.encryption != 'disabled'
+ loggable = self.session and self.session.is_loggable()
+
+ encryption_state = {'visible': visible,
+ 'enc_type': self.encryption,
+ 'enc_enabled': False,
+ 'chat_logged': loggable,
+ 'authenticated': False}
+
+ gajim.plugin_manager.gui_extension_point(
+ 'encryption_state' + self.encryption, self, encryption_state)
+
+ self._show_lock_image(**encryption_state)
+
def _show_lock_image(self, visible, enc_type='', enc_enabled=False,
chat_logged=False, authenticated=False):
"""
@@ -940,6 +961,8 @@ class ChatControl(ChatControlBase):
self.lock_image.set_sensitive(enc_enabled)
def _on_authentication_button_clicked(self, widget):
+ gajim.plugin_manager.gui_extension_point(
+ 'encryption_dialog' + self.encryption, self)
if self.gpg_is_active:
dialogs.GPGInfoWindow(self, self.parent_win.window)
elif self.session and self.session.enable_encryption:
@@ -950,6 +973,14 @@ class ChatControl(ChatControlBase):
"""
Send a message to contact
"""
+
+ if self.encryption:
+ self.sendmessage = True
+ gajim.plugin_manager.gui_extension_point(
+ 'send_message' + self.encryption, self)
+ if not self.sendmessage:
+ return
+
message = helpers.remove_invalid_xml_chars(message)
if message in ('', None, '\n'):
return None
@@ -1481,6 +1512,8 @@ class ChatControl(ChatControlBase):
def _on_message_tv_buffer_changed(self, textbuffer):
super()._on_message_tv_buffer_changed(textbuffer)
if textbuffer.get_char_count():
+ gajim.plugin_manager.gui_extension_point(
+ 'typing' + self.encryption, self)
e2e_is_active = self.session and \
self.session.enable_encryption
e2e_pref = gajim.config.get_per('accounts', self.account,
diff --git a/src/chat_control_base.py b/src/chat_control_base.py
index a81533b6a..248d4990f 100644
--- a/src/chat_control_base.py
+++ b/src/chat_control_base.py
@@ -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,10 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
self._on_window_motion_notify)
self.handlers[id_] = parent_win.window
+ self.encryption = 'disabled'
+ self.set_encryption_state()
+ 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 +417,38 @@ 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
+ 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 +760,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')
diff --git a/src/common/config.py b/src/common/config.py
index 3411bbb4c..f0c1aecb0 100644
--- a/src/common/config.py
+++ b/src/common/config.py
@@ -481,6 +481,7 @@ class Config:
}, {}),
'contacts': ({
'gpg_enabled': [ opt_bool, False, _('Is OpenPGP enabled for this contact?')],
+ 'encryption': [ opt_str, '', _('Encryption used for this contact.')],
'autonegotiate_esessions': [opt_bool, False, _('Should Gajim automatically start an encrypted session with this contact when possible?')],
'speller_language': [ opt_str, '', _('Language for which we want to check misspelled words')],
}, {}),
diff --git a/src/common/connection.py b/src/common/connection.py
index efc77bba9..36104e34a 100644
--- a/src/common/connection.py
+++ b/src/common/connection.py
@@ -499,7 +499,7 @@ class CommonConnection:
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 +2136,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(
diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py
index 7252f9046..2c45ec661 100644
--- a/src/common/connection_handlers.py
+++ b/src/common/connection_handlers.py
@@ -1091,6 +1091,12 @@ class ConnectionHandlersBase:
def _nec_message_received(self, obj):
if obj.conn.name != self.name:
return
+
+ gajim.plugin_manager.gui_extension_point(
+ 'decrypt', self, obj, self._on_message_received)
+ if not obj.encrypted:
+ self._on_message_received(obj)
+
if obj.encrypted == 'xep200':
try:
obj.stanza = obj.session.decrypt_stanza(obj.stanza)
@@ -1153,6 +1159,14 @@ class ConnectionHandlersBase:
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:
return
diff --git a/src/common/connection_handlers_events.py b/src/common/connection_handlers_events.py
index 286f935fb..f5489600b 100644
--- a/src/common/connection_handlers_events.py
+++ b/src/common/connection_handlers_events.py
@@ -2796,6 +2796,7 @@ class MessageOutgoingEvent(nec.NetworkOutgoingEvent):
self.attention = False
self.correction_msg = None
self.automatic_message = True
+ self.encryption = ''
def get_full_jid(self):
if self.resource:
diff --git a/src/gui_menu_builder.py b/src/gui_menu_builder.py
index 835b78578..6db2a8bb1 100644
--- a/src/gui_menu_builder.py
+++ b/src/gui_menu_builder.py
@@ -781,3 +781,14 @@ def build_bookmark_menu(account):
label = menu.get_item_attribute_value(1, 'label').get_string()
menu.remove(1)
menu.insert_submenu(1, label, bookmark_menu)
+
+
+def get_encryption_menu(contact):
+ menu = Gio.Menu()
+ menu.append(
+ 'Disabled', 'win.{}-encryptiongroup::{}'.format(contact.jid, 'disabled'))
+ for encryption in gajim.plugin_manager.encryption_plugins:
+ menu_action = 'win.{}-encryptiongroup::{}'.format(
+ contact.jid, encryption)
+ menu.append(encryption, menu_action)
+ return menu
diff --git a/src/plugins/gajimplugin.py b/src/plugins/gajimplugin.py
index 2a78e4977..18a8a75b0 100644
--- a/src/plugins/gajimplugin.py
+++ b/src/plugins/gajimplugin.py
@@ -59,6 +59,16 @@ class GajimPlugin(object):
:todo: decide whether we really need this one, because class name (with
module name) can act as such short name
'''
+ encryption_name = ''
+ '''
+ Name of the encryption scheme.
+
+ The name that Gajim displays in the encryption menu.
+ Leave empty if the plugin is not an encryption plugin.
+
+ :type: str
+
+ '''
version = ''
'''
Version of plugin.
diff --git a/src/plugins/pluginmanager.py b/src/plugins/pluginmanager.py
index eeeafcb04..dc7e867eb 100644
--- a/src/plugins/pluginmanager.py
+++ b/src/plugins/pluginmanager.py
@@ -101,6 +101,12 @@ class PluginManager(metaclass=Singleton):
'''
Registered handlers of GUI extension points.
'''
+
+ self.encryption_plugins = {}
+ '''
+ Registered names with instances of encryption Plugins.
+ '''
+
for path in [gajim.PLUGINS_DIRS[1], gajim.PLUGINS_DIRS[0]]:
pc = PluginManager.scan_dir_for_plugins(path)
self.add_plugins(pc)
@@ -291,6 +297,10 @@ class PluginManager(metaclass=Singleton):
elif issubclass(event_class, nec.NetworkOutgoingEvent):
gajim.nec.unregister_outgoing_event(event_class)
+ def _remove_name_from_encryption_plugins(self, plugin):
+ if plugin.encryption_name:
+ del self.encryption_plugins[plugin.encryption_name]
+
@log_calls('PluginManager')
def activate_plugin(self, plugin):
'''
@@ -300,6 +310,7 @@ class PluginManager(metaclass=Singleton):
if not plugin.active and plugin.activatable:
self._add_gui_extension_points_handlers_from_plugin(plugin)
+ self._add_encryption_name_from_plugin(plugin)
self._handle_all_gui_extension_points_with_plugin(plugin)
self._register_events_handlers_in_ged(plugin)
self._register_network_events_in_nec(plugin)
@@ -339,6 +350,7 @@ class PluginManager(metaclass=Singleton):
self._remove_events_handler_from_ged(plugin)
self._remove_network_events_from_nec(plugin)
+ self._remove_name_from_encryption_plugins(plugin)
# removing plug-in from active plug-ins list
plugin.deactivate()
@@ -357,6 +369,10 @@ class PluginManager(metaclass=Singleton):
self.gui_extension_points_handlers.setdefault(gui_extpoint_name,
[]).append(gui_extpoint_handlers)
+ def _add_encryption_name_from_plugin(self, plugin):
+ if plugin.encryption_name:
+ self.encryption_plugins[plugin.encryption_name] = plugin
+
@log_calls('PluginManager')
def _handle_all_gui_extension_points_with_plugin(self, plugin):
for gui_extpoint_name, gui_extpoint_handlers in \