# Copyright (C) 2019 Philipp Hörist # # This file is part of the PGP Gajim Plugin. # # PGP Gajim Plugin is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; version 3 only. # # PGP Gajim Plugin is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PGP Gajim Plugin. If not, see . from __future__ import annotations from typing import Any from typing import cast from typing import TYPE_CHECKING from collections.abc import Callable from pathlib import Path from gi.repository import GLib from gi.repository import Gtk from nbxmpp import JID from gajim.common import app from gajim.gtk.window import GajimAppWindow from gajim.plugins.helpers import get_builder from gajim.plugins.plugins_i18n import _ from ..modules.pgp_legacy import PGPLegacy if TYPE_CHECKING: from ..plugin import PGPPlugin class ChooseKeyBuilder(Gtk.Builder): liststore: Gtk.ListStore box: Gtk.Box keys_treeview: Gtk.TreeView cancel_button: Gtk.Button ok_button: Gtk.Button class KeyDialog(GajimAppWindow): def __init__( self, plugin: PGPPlugin, account: str, jid: JID, transient: Gtk.Window ) -> None: GajimAppWindow.__init__( self, name="PGPKeyDialog", title=_("Assign key for %s") % jid, default_width=450, transient_for=transient, modal=True, add_window_padding=True, header_bar=True, ) self.set_resizable(True) self._plugin = plugin self._jid = str(jid) self._module = cast( PGPLegacy, app.get_client(account).get_module("PGPLegacy"), # pyright: ignore ) self._label = Gtk.Label() self._assign_button = Gtk.Button(label=_("Assign Key")) self._assign_button.get_style_context().add_class("suggested-action") self._assign_button.set_halign(Gtk.Align.CENTER) self._assign_button.set_margin_top(18) self._connect(self._assign_button, "clicked", self._choose_key) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) box.append(self._label) box.append(self._assign_button) self.set_child(box) self._load_key() self.show() def _cleanup(self) -> None: del self._plugin del self._module def _choose_key(self, _button: Gtk.Button) -> None: ChooseGPGKeyDialog(self._module.pgp_backend.get_keys(), self, self._on_response) def _load_key(self) -> None: key_data = self._module.get_contact_key_data(self._jid) if key_data is None: self._set_key(None) else: key_id, key_user = key_data.values() self._set_key((key_id, key_user)) def _on_response(self, key: tuple[str, str] | None) -> None: if key is None: self._module.set_contact_key_data(self._jid, None) self._set_key(None) else: self._module.set_contact_key_data(self._jid, key) self._set_key(key) def _set_key(self, key_data: tuple[str, str] | None) -> None: if key_data is None: self._label.set_text(_("No key assigned")) else: key_id, key_user = key_data self._label.set_markup( "%s %s" % (key_id, GLib.markup_escape_text(key_user)) ) class ChooseGPGKeyDialog(GajimAppWindow): def __init__( self, secret_keys: dict[str, str], transient: Gtk.Window, callback: Callable[[tuple[str, str] | None], None], ) -> None: GajimAppWindow.__init__( self, name="PGPChooseKeyDialog", title=_("Assign PGP Key"), default_width=450, default_height=400, transient_for=transient, modal=True, add_window_padding=True, header_bar=True, ) secret_keys[_("None")] = _("None") self.set_resizable(True) self._callback = callback self._selected_key = None ui_path = Path(__file__).parent self._ui = cast( ChooseKeyBuilder, get_builder(str(ui_path.resolve() / "choose_key.ui")) ) self._connect(self._ui.cancel_button, "clicked", self._on_cancel) self._connect(self._ui.ok_button, "clicked", self._on_ok) self._connect(self._ui.keys_treeview, "cursor-changed", self._on_row_changed) model = cast(Gtk.ListStore, self._ui.keys_treeview.get_model()) model.set_sort_func(1, self._sort) for key_id, key_label in secret_keys.items(): model.append((key_id, key_label)) self.set_child(self._ui.box) self.show() def _cleanup(self) -> None: del self._callback @staticmethod def _sort( model: Gtk.TreeModel, iter1: Gtk.TreeIter, iter2: Gtk.TreeIter, _data: Any ) -> int: value1 = model[iter1][1] value2 = model[iter2][1] if value1 == _("None"): return -1 if value2 == _("None"): return 1 if value1 < value2: return -1 return 1 def _on_cancel(self, _button: Gtk.Button) -> None: self.close() def _on_ok(self, _button: Gtk.Button) -> None: self._callback(self._selected_key) self.close() def _on_row_changed(self, treeview: Gtk.TreeView) -> None: selection = treeview.get_selection() model, iter_ = selection.get_selected() if iter_ is None: self._selected_key = None else: key_id, key_user = model[iter_][0], model[iter_][1] if key_id == _("None"): self._selected_key = None else: self._selected_key = key_id, key_user