Improve Plugin API (allow to move encryption into plugin)
This commit is contained in:
parent
1ccad732b9
commit
4c48bdc072
|
@ -62,7 +62,11 @@ compile_gresources(
|
|||
|
||||
vala_precompile(LIBDINO_VALA_C
|
||||
SOURCES
|
||||
src/plugin.vala
|
||||
src/application.vala
|
||||
|
||||
src/plugin/interfaces.vala
|
||||
src/plugin/loader.vala
|
||||
src/plugin/registry.vala
|
||||
|
||||
src/dbus/login1.vala
|
||||
src/dbus/networkmanager.vala
|
||||
|
@ -72,6 +76,7 @@ SOURCES
|
|||
src/entity/conversation.vala
|
||||
src/entity/jid.vala
|
||||
src/entity/message.vala
|
||||
src/entity/encryption.vala
|
||||
|
||||
src/service/avatar_manager.vala
|
||||
src/service/avatar_storage.vala
|
||||
|
@ -101,7 +106,6 @@ SOURCES
|
|||
src/ui/add_conversation/list_row.vala
|
||||
src/ui/add_conversation/select_jid_fragment.vala
|
||||
src/ui/avatar_generator.vala
|
||||
src/ui/application.vala
|
||||
src/ui/chat_input.vala
|
||||
src/ui/conversation_list_titlebar.vala
|
||||
src/ui/conversation_selector/chat_row.vala
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<object class="GtkPopoverMenu" id="menu_encryption">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<object class="GtkBox" id="encryption_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
|
@ -24,22 +24,6 @@
|
|||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="button_pgp">
|
||||
<property name="label" translatable="yes">OpenPGP</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">button_unencrypted</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="submenu">main</property>
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
using Gtk;
|
||||
|
||||
using Dino.Entities;
|
||||
using Dino.Ui;
|
||||
|
||||
public class Dino.Ui.Application : Gtk.Application {
|
||||
public class Dino.Application : Gtk.Application {
|
||||
|
||||
private Database db;
|
||||
private StreamInteractor stream_interaction;
|
||||
public Database db;
|
||||
public StreamInteractor stream_interaction;
|
||||
public Plugins.Registry plugin_registry = new Plugins.Registry();
|
||||
|
||||
private Notifications notifications;
|
||||
private UnifiedWindow? window;
|
|
@ -3,11 +3,6 @@ public class Conversation : Object {
|
|||
|
||||
public signal void object_updated(Conversation conversation);
|
||||
|
||||
public enum Encryption {
|
||||
UNENCRYPTED,
|
||||
PGP
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
CHAT,
|
||||
GROUPCHAT
|
||||
|
@ -27,7 +22,7 @@ public class Conversation : Object {
|
|||
this.account = account;
|
||||
this.active = false;
|
||||
this.last_active = new DateTime.from_unix_utc(0);
|
||||
this.encryption = Encryption.UNENCRYPTED;
|
||||
this.encryption = Encryption.NONE;
|
||||
}
|
||||
|
||||
public Conversation.with_id(Jid jid, Account account, int id) {
|
||||
|
|
9
libdino/src/entity/encryption.vala
Normal file
9
libdino/src/entity/encryption.vala
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Dino.Entities {
|
||||
|
||||
public enum Encryption {
|
||||
NONE,
|
||||
PGP,
|
||||
OMEMO
|
||||
}
|
||||
|
||||
}
|
|
@ -16,11 +16,6 @@ public class Dino.Entities.Message : Object {
|
|||
WONTSEND
|
||||
}
|
||||
|
||||
public enum Encryption {
|
||||
NONE,
|
||||
PGP
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
ERROR,
|
||||
CHAT,
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
namespace Dino {
|
||||
|
||||
public errordomain PluginError {
|
||||
NOT_SUPPORTED,
|
||||
UNEXPECTED_TYPE,
|
||||
NO_REGISTRATION_FUNCTION,
|
||||
FAILED
|
||||
}
|
||||
|
||||
public interface PluginIface : Object {
|
||||
public abstract void registered(Dino.Ui.Application app);
|
||||
}
|
||||
|
||||
private class PluginInfo : Object {
|
||||
public Module module;
|
||||
public Type gtype;
|
||||
|
||||
public PluginInfo(Type type, owned Module module) {
|
||||
this.module = (owned) module;
|
||||
this.gtype = type;
|
||||
}
|
||||
}
|
||||
|
||||
public class PluginLoader : Object {
|
||||
[CCode (has_target = false)]
|
||||
private delegate Type RegisterPluginFunction (Module module);
|
||||
|
||||
private PluginIface[] plugins = new PluginIface[0];
|
||||
private PluginInfo[] infos = new PluginInfo[0];
|
||||
|
||||
public PluginIface load(string name, Dino.Ui.Application app) throws PluginError {
|
||||
if (Module.supported () == false) {
|
||||
throw new PluginError.NOT_SUPPORTED ("Plugins are not supported");
|
||||
}
|
||||
|
||||
Module module = Module.open ("plugins/" + name, ModuleFlags.BIND_LAZY);
|
||||
if (module == null) {
|
||||
throw new PluginError.FAILED (Module.error ());
|
||||
}
|
||||
|
||||
void* function;
|
||||
module.symbol ("register_plugin", out function);
|
||||
if (function == null) {
|
||||
throw new PluginError.NO_REGISTRATION_FUNCTION ("register_plugin () not found");
|
||||
}
|
||||
|
||||
RegisterPluginFunction register_plugin = (RegisterPluginFunction) function;
|
||||
Type type = register_plugin (module);
|
||||
if (type.is_a (typeof (PluginIface)) == false) {
|
||||
throw new PluginError.UNEXPECTED_TYPE ("Unexpected type");
|
||||
}
|
||||
|
||||
PluginInfo info = new PluginInfo (type, (owned) module);
|
||||
infos += info;
|
||||
|
||||
PluginIface plugin = (PluginIface) Object.new (type);
|
||||
plugins += plugin;
|
||||
plugin.registered (app);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
16
libdino/src/plugin/interfaces.vala
Normal file
16
libdino/src/plugin/interfaces.vala
Normal file
|
@ -0,0 +1,16 @@
|
|||
namespace Dino.Plugins {
|
||||
|
||||
public interface RootInterface : Object {
|
||||
public abstract void registered(Dino.Application app);
|
||||
|
||||
public abstract void shutdown();
|
||||
}
|
||||
|
||||
public interface EncryptionListEntry : Object {
|
||||
public abstract Entities.Encryption encryption { get; }
|
||||
public abstract string name { get; }
|
||||
|
||||
public abstract bool can_encrypt(Entities.Conversation conversation);
|
||||
}
|
||||
|
||||
}
|
66
libdino/src/plugin/loader.vala
Normal file
66
libdino/src/plugin/loader.vala
Normal file
|
@ -0,0 +1,66 @@
|
|||
namespace Dino.Plugins {
|
||||
|
||||
public errordomain Error {
|
||||
NOT_SUPPORTED,
|
||||
UNEXPECTED_TYPE,
|
||||
NO_REGISTRATION_FUNCTION,
|
||||
FAILED
|
||||
}
|
||||
|
||||
private class Info : Object {
|
||||
public Module module;
|
||||
public Type gtype;
|
||||
|
||||
public Info(Type type, owned Module module) {
|
||||
this.module = (owned) module;
|
||||
this.gtype = type;
|
||||
}
|
||||
}
|
||||
|
||||
public class Loader : Object {
|
||||
[CCode (has_target = false)]
|
||||
private delegate Type RegisterPluginFunction (Module module);
|
||||
|
||||
private RootInterface[] plugins = new RootInterface[0];
|
||||
private Info[] infos = new Info[0];
|
||||
|
||||
public RootInterface load(string name, Dino.Application app) throws Error {
|
||||
if (Module.supported () == false) {
|
||||
throw new Error.NOT_SUPPORTED ("Plugins are not supported");
|
||||
}
|
||||
|
||||
Module module = Module.open ("plugins/" + name, ModuleFlags.BIND_LAZY);
|
||||
if (module == null) {
|
||||
throw new Error.FAILED (Module.error ());
|
||||
}
|
||||
|
||||
void* function;
|
||||
module.symbol ("register_plugin", out function);
|
||||
if (function == null) {
|
||||
throw new Error.NO_REGISTRATION_FUNCTION ("register_plugin () not found");
|
||||
}
|
||||
|
||||
RegisterPluginFunction register_plugin = (RegisterPluginFunction) function;
|
||||
Type type = register_plugin (module);
|
||||
if (type.is_a (typeof (RootInterface)) == false) {
|
||||
throw new Error.UNEXPECTED_TYPE ("Unexpected type");
|
||||
}
|
||||
|
||||
Info info = new Plugins.Info (type, (owned) module);
|
||||
infos += info;
|
||||
|
||||
RootInterface plugin = (RootInterface) Object.new (type);
|
||||
plugins += plugin;
|
||||
plugin.registered (app);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
foreach (RootInterface p in plugins) {
|
||||
p.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
20
libdino/src/plugin/registry.vala
Normal file
20
libdino/src/plugin/registry.vala
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Gee;
|
||||
|
||||
namespace Dino.Plugins {
|
||||
|
||||
public class Registry {
|
||||
internal ArrayList<EncryptionListEntry> encryption_list_entries = new ArrayList<EncryptionListEntry>();
|
||||
|
||||
public bool register_encryption_list_entry(EncryptionListEntry entry) {
|
||||
lock(encryption_list_entries) {
|
||||
foreach(var e in encryption_list_entries) {
|
||||
if (e.encryption == entry.encryption) return false;
|
||||
}
|
||||
encryption_list_entries.add(entry);
|
||||
encryption_list_entries.sort((a,b) => b.name.collate(a.name));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -70,7 +70,7 @@ public class ConversationManager : StreamInteractionModule, Object {
|
|||
}
|
||||
}
|
||||
|
||||
private void on_message_received(Entities.Message message, Conversation conversation) {
|
||||
private void on_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
|
||||
ensure_start_conversation(conversation.counterpart, conversation.account);
|
||||
}
|
||||
|
||||
|
|
|
@ -337,7 +337,7 @@ public class Database : Qlite.Database {
|
|||
new_message.body = row[message.body];
|
||||
new_message.account = get_account_by_id(row[message.account_id]); // TODO dont have to generate acc new
|
||||
new_message.marked = (Message.Marked) row[message.marked];
|
||||
new_message.encryption = (Message.Encryption) row[message.encryption];
|
||||
new_message.encryption = (Encryption) row[message.encryption];
|
||||
new_message.real_jid = get_real_jid_for_message(new_message);
|
||||
|
||||
new_message.notify.connect(on_message_update);
|
||||
|
@ -396,7 +396,7 @@ public class Database : Qlite.Database {
|
|||
int64? last_active = row[conversation.last_active];
|
||||
if (last_active != null) new_conversation.last_active = new DateTime.from_unix_utc(last_active);
|
||||
new_conversation.type_ = (Conversation.Type) row[conversation.type_];
|
||||
new_conversation.encryption = (Conversation.Encryption) row[conversation.encryption];
|
||||
new_conversation.encryption = (Encryption) row[conversation.encryption];
|
||||
int? read_up_to = row[conversation.read_up_to];
|
||||
if (read_up_to != null) new_conversation.read_up_to = get_message_by_id(read_up_to);
|
||||
|
||||
|
|
|
@ -8,8 +8,10 @@ namespace Dino {
|
|||
public class MessageManager : StreamInteractionModule, Object {
|
||||
public const string ID = "message_manager";
|
||||
|
||||
public signal void pre_message_received(Entities.Message message, Conversation conversation);
|
||||
public signal void pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation);
|
||||
public signal void message_received(Entities.Message message, Conversation conversation);
|
||||
public signal void out_message_created(Entities.Message message, Conversation conversation);
|
||||
public signal void pre_message_send(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation);
|
||||
public signal void message_sent(Entities.Message message, Conversation conversation);
|
||||
|
||||
private StreamInteractor stream_interactor;
|
||||
|
@ -78,7 +80,6 @@ public class MessageManager : StreamInteractionModule, Object {
|
|||
stream_interactor.module_manager.get_module(account, Xmpp.Message.Module.IDENTITY).received_message.connect( (stream, message) => {
|
||||
on_message_received(account, message);
|
||||
});
|
||||
stream_interactor.stream_negotiated.connect(send_unsent_messages);
|
||||
}
|
||||
|
||||
private void send_unsent_messages(Account account) {
|
||||
|
@ -110,11 +111,8 @@ public class MessageManager : StreamInteractionModule, Object {
|
|||
Xep.DelayedDelivery.MessageFlag? deleyed_delivery_flag = Xep.DelayedDelivery.MessageFlag.get_flag(message);
|
||||
new_message.time = deleyed_delivery_flag != null ? deleyed_delivery_flag.datetime : new DateTime.now_utc();
|
||||
new_message.local_time = new DateTime.now_utc();
|
||||
if (Xep.Pgp.MessageFlag.get_flag(message) != null) {
|
||||
new_message.encryption = Entities.Message.Encryption.PGP;
|
||||
}
|
||||
Conversation conversation = ConversationManager.get_instance(stream_interactor).get_add_conversation(new_message.counterpart, account);
|
||||
pre_message_received(new_message, conversation);
|
||||
pre_message_received(new_message, message, conversation);
|
||||
|
||||
bool is_uuid = new_message.stanza_id != null && Regex.match_simple("""[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}""", new_message.stanza_id);
|
||||
if ((is_uuid && !db.contains_message_by_stanza_id(new_message.stanza_id)) ||
|
||||
|
@ -149,14 +147,15 @@ public class MessageManager : StreamInteractionModule, Object {
|
|||
message.direction = Entities.Message.DIRECTION_SENT;
|
||||
message.counterpart = conversation.counterpart;
|
||||
message.ourpart = new Jid(conversation.account.bare_jid.to_string() + "/" + conversation.account.resourcepart);
|
||||
message.marked = Entities.Message.Marked.UNSENT;
|
||||
message.encryption = conversation.encryption;
|
||||
|
||||
if (conversation.encryption == Conversation.Encryption.PGP) {
|
||||
message.encryption = Entities.Message.Encryption.PGP;
|
||||
}
|
||||
out_message_created(message, conversation);
|
||||
return message;
|
||||
}
|
||||
|
||||
private void send_xmpp_message(Entities.Message message, Conversation conversation, bool delayed = false) {
|
||||
lock (messages) {
|
||||
Core.XmppStream stream = stream_interactor.get_stream(conversation.account);
|
||||
message.marked = Entities.Message.Marked.NONE;
|
||||
if (stream != null) {
|
||||
|
@ -168,16 +167,8 @@ public class MessageManager : StreamInteractionModule, Object {
|
|||
} else {
|
||||
new_message.type_ = Xmpp.Message.Stanza.TYPE_CHAT;
|
||||
}
|
||||
if (message.encryption == Entities.Message.Encryption.PGP) {
|
||||
string? key_id = PgpManager.get_instance(stream_interactor).get_key_id(conversation.account, message.counterpart);
|
||||
if (key_id != null) {
|
||||
bool encrypted = stream.get_module(Xep.Pgp.Module.IDENTITY).encrypt(new_message, key_id);
|
||||
if (!encrypted) {
|
||||
message.marked = Entities.Message.Marked.WONTSEND;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
pre_message_send(message, new_message, conversation);
|
||||
if (message.marked == Entities.Message.Marked.UNSENT || message.marked == Entities.Message.Marked.WONTSEND) return;
|
||||
if (delayed) {
|
||||
stream.get_module(Xmpp.Xep.DelayedDelivery.Module.IDENTITY).set_message_delay(new_message, message.time);
|
||||
}
|
||||
|
@ -188,6 +179,7 @@ public class MessageManager : StreamInteractionModule, Object {
|
|||
message.marked = Entities.Message.Marked.UNSENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -161,7 +161,7 @@ public class MucManager : StreamInteractionModule, Object {
|
|||
if (stream != null) stream.get_module(Xep.Bookmarks.Module.IDENTITY).get_conferences(stream, new BookmarksRetrieveResponseListener(this, account));
|
||||
}
|
||||
|
||||
private void on_pre_message_received(Entities.Message message, Conversation conversation) {
|
||||
private void on_pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
|
||||
if (conversation.type_ != Conversation.Type.GROUPCHAT) return;
|
||||
Core.XmppStream stream = stream_interactor.get_stream(conversation.account);
|
||||
if (stream == null) return;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Gee;
|
||||
using Xmpp;
|
||||
|
||||
using Xmpp;
|
||||
using Dino.Entities;
|
||||
|
@ -16,6 +17,27 @@ namespace Dino {
|
|||
public static void start(StreamInteractor stream_interactor, Database db) {
|
||||
PgpManager m = new PgpManager(stream_interactor, db);
|
||||
stream_interactor.add_module(m);
|
||||
(GLib.Application.get_default() as Application).plugin_registry.register_encryption_list_entry(new EncryptionListEntry(m));
|
||||
}
|
||||
|
||||
private class EncryptionListEntry : Plugins.EncryptionListEntry, Object {
|
||||
private PgpManager pgp_manager;
|
||||
|
||||
public EncryptionListEntry(PgpManager pgp_manager) {
|
||||
this.pgp_manager = pgp_manager;
|
||||
}
|
||||
|
||||
public Entities.Encryption encryption { get {
|
||||
return Encryption.PGP;
|
||||
}}
|
||||
|
||||
public string name { get {
|
||||
return "OpenPGP";
|
||||
}}
|
||||
|
||||
public bool can_encrypt(Entities.Conversation conversation) {
|
||||
return pgp_manager.pgp_key_ids.has_key(conversation.counterpart);
|
||||
}
|
||||
}
|
||||
|
||||
private PgpManager(StreamInteractor stream_interactor, Database db) {
|
||||
|
@ -23,6 +45,27 @@ namespace Dino {
|
|||
this.db = db;
|
||||
|
||||
stream_interactor.account_added.connect(on_account_added);
|
||||
MessageManager.get_instance(stream_interactor).pre_message_received.connect(on_pre_message_received);
|
||||
MessageManager.get_instance(stream_interactor).pre_message_send.connect(on_pre_message_send);
|
||||
}
|
||||
|
||||
private void on_pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
|
||||
if (Xep.Pgp.MessageFlag.get_flag(message_stanza) != null && Xep.Pgp.MessageFlag.get_flag(message_stanza).decrypted) {
|
||||
message.encryption = Encryption.PGP;
|
||||
}
|
||||
}
|
||||
|
||||
private void on_pre_message_send(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
|
||||
if (message.encryption == Encryption.PGP) {
|
||||
string? key_id = get_key_id(conversation.account, message.counterpart);
|
||||
bool encrypted = false;
|
||||
if (key_id != null) {
|
||||
encrypted = stream_interactor.get_stream(conversation.account).get_module(Xep.Pgp.Module.IDENTITY).encrypt(message_stanza, key_id);
|
||||
}
|
||||
if (!encrypted) {
|
||||
message.marked = Entities.Message.Marked.WONTSEND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string? get_key_id(Account account, Jid jid) {
|
||||
|
|
|
@ -64,7 +64,7 @@ public class StreamInteractor {
|
|||
}
|
||||
|
||||
public interface StreamInteractionModule : Object {
|
||||
internal abstract string get_id();
|
||||
public abstract string get_id();
|
||||
}
|
||||
|
||||
}
|
|
@ -33,7 +33,7 @@ public class MergedMessageItem : Grid {
|
|||
string display_name = Util.get_message_display_name(stream_interactor, message, conversation.account);
|
||||
name_label.set_markup(@"<span foreground=\"#$(Util.get_name_hex_color(display_name))\">$display_name</span>");
|
||||
Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(30, 30, image.scale_factor)).draw_message(stream_interactor, message));
|
||||
if (message.encryption == Entities.Message.Encryption.PGP) {
|
||||
if (message.encryption != Encryption.NONE) {
|
||||
encryption_image.visible = true;
|
||||
encryption_image.set_from_icon_name("changes-prevent-symbolic", IconSize.SMALL_TOOLBAR);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Gtk;
|
||||
using Gee;
|
||||
|
||||
using Dino.Entities;
|
||||
|
||||
|
@ -12,7 +13,7 @@ public class ConversationTitlebar : Gtk.HeaderBar {
|
|||
[GtkChild] private MenuButton groupchat_button;
|
||||
|
||||
private RadioButton? button_unencrypted;
|
||||
private RadioButton? button_pgp;
|
||||
private Map<RadioButton, Plugins.EncryptionListEntry> encryption_radios = new HashMap<RadioButton, Plugins.EncryptionListEntry>();
|
||||
|
||||
private StreamInteractor stream_interactor;
|
||||
private Conversation? conversation;
|
||||
|
@ -36,22 +37,19 @@ public class ConversationTitlebar : Gtk.HeaderBar {
|
|||
}
|
||||
|
||||
private void update_encryption_menu_state() {
|
||||
string? pgp_id = PgpManager.get_instance(stream_interactor).get_key_id(conversation.account, conversation.counterpart);
|
||||
button_pgp.set_sensitive(pgp_id != null);
|
||||
switch (conversation.encryption) {
|
||||
case Conversation.Encryption.UNENCRYPTED:
|
||||
foreach (RadioButton e in encryption_radios.keys) {
|
||||
e.set_sensitive(encryption_radios[e].can_encrypt(conversation));
|
||||
if (conversation.encryption == encryption_radios[e].encryption) e.set_active(true);
|
||||
}
|
||||
if (conversation.encryption == Encryption.NONE) {
|
||||
button_unencrypted.set_active(true);
|
||||
break;
|
||||
case Conversation.Encryption.PGP:
|
||||
button_pgp.set_active(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void update_encryption_menu_icon() {
|
||||
encryption_button.visible = (conversation.type_ == Conversation.Type.CHAT);
|
||||
if (conversation.type_ == Conversation.Type.CHAT) {
|
||||
if (conversation.encryption == Conversation.Encryption.UNENCRYPTED) {
|
||||
if (conversation.encryption == Encryption.NONE) {
|
||||
encryption_button.set_image(new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON));
|
||||
} else {
|
||||
encryption_button.set_image(new Image.from_icon_name("changes-prevent-symbolic", IconSize.BUTTON));
|
||||
|
@ -92,25 +90,35 @@ public class ConversationTitlebar : Gtk.HeaderBar {
|
|||
menu_button.set_menu_model(menu);
|
||||
}
|
||||
|
||||
private void encryption_changed() {
|
||||
foreach (RadioButton e in encryption_radios.keys) {
|
||||
if (e.get_active()) {
|
||||
conversation.encryption = encryption_radios[e].encryption;
|
||||
update_encryption_menu_icon();
|
||||
return;
|
||||
}
|
||||
}
|
||||
conversation.encryption = Encryption.NONE;
|
||||
update_encryption_menu_icon();
|
||||
}
|
||||
|
||||
private void create_encryption_menu() {
|
||||
Builder builder = new Builder.from_resource("/org/dino-im/menu_encryption.ui");
|
||||
PopoverMenu menu = builder.get_object("menu_encryption") as PopoverMenu;
|
||||
Box encryption_box = builder.get_object("encryption_box") as Box;
|
||||
button_unencrypted = builder.get_object("button_unencrypted") as RadioButton;
|
||||
button_pgp = builder.get_object("button_pgp") as RadioButton;
|
||||
button_unencrypted.toggled.connect(encryption_changed);
|
||||
Application app = GLib.Application.get_default() as Application;
|
||||
foreach(var e in app.plugin_registry.encryption_list_entries) {
|
||||
RadioButton btn = new RadioButton.with_label(button_unencrypted.get_group(), e.name);
|
||||
encryption_radios[btn] = e;
|
||||
btn.toggled.connect(encryption_changed);
|
||||
btn.visible = true;
|
||||
encryption_box.pack_end(btn, false);
|
||||
}
|
||||
encryption_button.set_use_popover(true);
|
||||
encryption_button.set_popover(menu);
|
||||
encryption_button.set_image(new Image.from_icon_name("changes-allow-symbolic", IconSize.BUTTON));
|
||||
|
||||
button_unencrypted.toggled.connect(() => {
|
||||
if (conversation != null) {
|
||||
if (button_unencrypted.get_active()) {
|
||||
conversation.encryption = Conversation.Encryption.UNENCRYPTED;
|
||||
} else if (button_pgp.get_active()) {
|
||||
conversation.encryption = Conversation.Encryption.PGP;
|
||||
}
|
||||
update_encryption_menu_icon();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void on_groupchat_subject_set(Account account, Jid jid, string subject) {
|
||||
|
|
|
@ -5,16 +5,17 @@ namespace Dino {
|
|||
|
||||
void main(string[] args) {
|
||||
Gtk.init(ref args);
|
||||
Dino.Ui.Application app = new Dino.Ui.Application();
|
||||
PluginLoader loader = new PluginLoader();
|
||||
Application app = new Application();
|
||||
Plugins.Loader loader = new Plugins.Loader();
|
||||
foreach(string plugin in new string[]{}) {
|
||||
try {
|
||||
loader.load(plugin, app);
|
||||
} catch (Dino.PluginError e) {
|
||||
} catch (Plugins.Error e) {
|
||||
print(@"Error loading plugin $plugin: $(e.message)\n");
|
||||
}
|
||||
}
|
||||
app.run(args);
|
||||
loader.shutdown();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
namespace Xmpp {
|
||||
string? get_bare_jid(string jid) {
|
||||
public string? get_bare_jid(string jid) {
|
||||
return jid.split("/")[0];
|
||||
}
|
||||
|
||||
bool is_bare_jid(string jid) {
|
||||
public bool is_bare_jid(string jid) {
|
||||
return !jid.contains("/");
|
||||
}
|
||||
|
||||
string? get_resource_part(string jid) {
|
||||
public string? get_resource_part(string jid) {
|
||||
return jid.split("/")[1];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue