diff options
Diffstat (limited to 'main/src/plugins/omemo/ui/bad_messages_populator.vala')
| -rw-r--r-- | main/src/plugins/omemo/ui/bad_messages_populator.vala | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/main/src/plugins/omemo/ui/bad_messages_populator.vala b/main/src/plugins/omemo/ui/bad_messages_populator.vala new file mode 100644 index 00000000..c291a422 --- /dev/null +++ b/main/src/plugins/omemo/ui/bad_messages_populator.vala @@ -0,0 +1,198 @@ +using Gee; +using Gtk; + +using Dino.Entities; +using Dino.Qlite; +using Xmpp; + +namespace Dino.Plugins.Omemo { + +public enum BadnessType { + UNTRUSTED, + UNDECRYPTABLE +} + +public class BadMessagesPopulator : Plugins.ConversationItemPopulator, Plugins.ConversationAdditionPopulator, Object { + + public string id { get { return "bad_omemo_messages"; } } + + private StreamInteractor stream_interactor; + private Plugin plugin; + private Database db; + + private Conversation? current_conversation; + private Plugins.ConversationItemCollection? item_collection; + + private Gee.List<BadMessageItem> bad_items = new ArrayList<BadMessageItem>(); + + public BadMessagesPopulator(StreamInteractor stream_interactor, Plugin plugin) { + this.stream_interactor = stream_interactor; + this.plugin = plugin; + this.db = plugin.db; + + plugin.trust_manager.bad_message_state_updated.connect((account, jid, device_id) => { + clear_state(); + init_state(); + }); + } + + private void init_state() { + if (current_conversation == null) return; + if (current_conversation.type_ == Conversation.Type.GROUPCHAT_PM) return; + + var qry = db.identity_meta.select() + .join_with(db.identity, db.identity.id, db.identity_meta.identity_id) + .with(db.identity.account_id, "=", current_conversation.account.id) + .where("last_message_untrusted is not NULL OR last_message_undecryptable is not NULL"); + + switch (current_conversation.type_) { + case Conversation.Type.CHAT: + qry.with(db.identity_meta.address_name, "=", current_conversation.counterpart.to_string()); + break; + case Conversation.Type.GROUPCHAT: + bool is_private = stream_interactor.get_module(MucManager.IDENTITY).is_private_room(current_conversation.account, current_conversation.counterpart); + if (!is_private) return; + + var list = stream_interactor.get_module(MucManager.IDENTITY).get_offline_members(current_conversation.counterpart, current_conversation.account); + if (list == null || list.is_empty) return; + + var selection = new StringBuilder(); + string[] selection_args = {}; + foreach (Jid jid in list) { + if (selection.len == 0) { + selection.append(@" ($(db.identity_meta.address_name) = ?"); + } else { + selection.append(@" OR $(db.identity_meta.address_name) = ?"); + } + selection_args += jid.to_string(); + } + selection.append(")"); + qry.where(selection.str, selection_args); + break; + case Conversation.Type.GROUPCHAT_PM: + break; + } + + foreach (Row row in qry) { + Jid jid = Jid.from_string(row[db.identity_meta.address_name]); + if (!db.identity_meta.last_message_untrusted.is_null(row)) { + DateTime time = new DateTime.from_unix_utc(row[db.identity_meta.last_message_untrusted]); + var item = new BadMessageItem(plugin, current_conversation, jid, time, BadnessType.UNTRUSTED); + bad_items.add(item); + item_collection.insert_item(item); + } + if (!db.identity_meta.last_message_undecryptable.is_null(row)) { + DateTime time = new DateTime.from_unix_utc(row[db.identity_meta.last_message_undecryptable]); + var item = new BadMessageItem(plugin, current_conversation, jid, time, BadnessType.UNDECRYPTABLE); + bad_items.add(item); + item_collection.insert_item(item); + } + } + } + + private void clear_state() { + foreach (BadMessageItem bad_item in bad_items) { + item_collection.remove_item(bad_item); + } + bad_items.clear(); + } + + public void init(Conversation conversation, Plugins.ConversationItemCollection item_collection, Plugins.WidgetType type) { + current_conversation = conversation; + this.item_collection = item_collection; + + init_state(); + } + + public void close(Conversation conversation) { + clear_state(); + } + + public void populate_timespan(Conversation conversation, DateTime after, DateTime before) { } +} + +public class BadMessageItem : Plugins.MetaConversationItem { + + private Plugin plugin; + private Conversation conversation; + private Jid problem_jid; + private BadnessType badness_type; + + public BadMessageItem(Plugin plugin, Conversation conversation, Jid jid, DateTime date, BadnessType badness_type) { + this.plugin = plugin; + this.conversation = conversation; + this.problem_jid = jid; + this.time = date; + this.badness_type = badness_type; + } + + public override Object? get_widget(Plugins.ConversationItemWidgetInterface outer, Plugins.WidgetType widget_type) { + return new BadMessagesWidget(plugin, conversation, problem_jid, badness_type); + } + + public override Gee.List<Plugins.MessageAction>? get_item_actions(Plugins.WidgetType type) { return null; } +} + +public class BadMessagesWidget : Box { + private Plugin plugin; + private Conversation conversation; + private Jid jid; + private Label label; + + public BadMessagesWidget(Plugin plugin, Conversation conversation, Jid jid, BadnessType badness_type) { + Object(orientation:Orientation.HORIZONTAL, spacing:5); + + this.plugin = plugin; + this.conversation = conversation; + this.jid = jid; + this.halign = Align.CENTER; + this.visible = true; + + string who = ""; + if (conversation.type_ == Conversation.Type.CHAT) { + who = Dino.get_participant_display_name(plugin.app.stream_interactor, conversation, jid); + } else if (conversation.type_ == Conversation.Type.GROUPCHAT) { + who = jid.to_string(); + // `jid` is a real JID. In MUCs, try to show nicks instead (given that the JID is currently online) + var occupants = plugin.app.stream_interactor.get_module(MucManager.IDENTITY).get_occupants(conversation.counterpart, conversation.account); + if (occupants == null) return; + foreach (Jid occupant in occupants) { + if (jid.equals_bare(plugin.app.stream_interactor.get_module(MucManager.IDENTITY).get_real_jid(occupant, conversation.account))) { + who = occupant.resourcepart; + } + } + } + + string warning_text = ""; + if (badness_type == BadnessType.UNTRUSTED) { + warning_text = _("%s has been using an untrusted device. You won't see messages from devices that you do not trust.").printf(who) + + " <a href=\"\">%s</a>".printf(_("Manage devices")); + } else { + warning_text += _("%s does not trust this device. That means, you might be missing messages.").printf(who); + } + label = new Label(warning_text) { margin_start=70, margin_end=70, justify=Justification.CENTER, use_markup=true, selectable=true, wrap=true, wrap_mode=Pango.WrapMode.WORD_CHAR, hexpand=true }; + label.add_css_class("dim-label"); + this.append(label); + + if (badness_type == BadnessType.UNTRUSTED) { + label.activate_link.connect(on_label_activate_link); + } + } + + private bool on_label_activate_link() { + var variant = new Variant.tuple(new Variant[] {new Variant.int32(conversation.id), new Variant.string("encryption")}); + GLib.Application.get_default().activate_action("open-conversation-details", variant); + return false; + } + + public override void dispose() { + if (label != null) { + label.unparent(); + label.dispose(); + label = null; + } + base.dispose(); + } +} + +} |
