From 5a171fdfc4c08287a2a759800f7588d1902bbfa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20H=C3=B6rist?= Date: Fri, 12 Oct 2018 23:37:12 +0200 Subject: [PATCH] [omemo] Move ui files into gtk folder --- omemo/file_crypto.py | 38 +- omemo/{ui.py => gtk/config.py} | 480 +++++++++--------- omemo/{config_dialog.ui => gtk/config.ui} | 3 +- omemo/gtk/progress.py | 52 ++ .../progress.ui} | 3 +- omemo/omemoplugin.py | 2 +- 6 files changed, 293 insertions(+), 285 deletions(-) rename omemo/{ui.py => gtk/config.py} (75%) rename omemo/{config_dialog.ui => gtk/config.ui} (99%) create mode 100644 omemo/gtk/progress.py rename omemo/{download_progress_dialog.ui => gtk/progress.ui} (98%) diff --git a/omemo/file_crypto.py b/omemo/file_crypto.py index 59dc102..280b1f9 100644 --- a/omemo/file_crypto.py +++ b/omemo/file_crypto.py @@ -32,10 +32,10 @@ from urllib.parse import urlparse, urldefrag from io import BufferedWriter, FileIO, BytesIO from gi.repository import GLib -from gajim import gtkgui_helpers from gajim.common import app from gajim.common import configpaths -from gajim.dialogs import ErrorDialog, YesNoDialog +from gajim.gtk.dialogs import ErrorDialog, YesNoDialog +from omemo.gtk.progress import ProgressWindow if os.name == 'nt': import certifi @@ -265,40 +265,6 @@ class Download: return False -class ProgressWindow: - def __init__(self, plugin, window, event): - self.plugin = plugin - self.event = event - self.xml = gtkgui_helpers.get_gtk_builder( - self.plugin.local_file_path('download_progress_dialog.ui')) - self.dialog = self.xml.get_object('progress_dialog') - self.dialog.set_transient_for(window) - self.label = self.xml.get_object('label') - self.progressbar = self.xml.get_object('progressbar') - self.progressbar.set_text("") - self.dialog.show_all() - self.xml.connect_signals(self) - self.seen = 0 - - def set_text(self, text): - self.label.set_markup('%s' % text) - return False - - def update_progress(self, seen, total): - self.seen += seen - pct = (self.seen / float(total)) * 100.0 - self.progressbar.set_fraction(self.seen / float(total)) - self.progressbar.set_text(str(int(pct)) + "%") - return False - - def close_dialog(self, *args): - self.dialog.destroy() - return False - - def on_destroy(self, *args): - self.event.set() - - class DownloadAbortedException(Exception): def __str__(self): return _('Download Aborted') diff --git a/omemo/ui.py b/omemo/gtk/config.py similarity index 75% rename from omemo/ui.py rename to omemo/gtk/config.py index 67edf4a..510b37b 100644 --- a/omemo/ui.py +++ b/omemo/gtk/config.py @@ -1,244 +1,236 @@ -# -*- coding: utf-8 -*- - -''' -Copyright 2015 Bahtiar `kalkin-` Gadimov -Copyright 2015 Daniel Gultsch -Copyright 2016 Philipp Hörist - -This file is part of Gajim-OMEMO plugin. - -The Gajim-OMEMO 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, either version 3 of the License, or (at your option) any -later version. - -Gajim-OMEMO 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 -the Gajim-OMEMO plugin. If not, see . -''' - -import binascii -import logging -import os -import textwrap -from enum import IntEnum, unique - -from gi.repository import Gtk, GdkPixbuf, Gdk -from axolotl.state.sessionrecord import SessionRecord - -log = logging.getLogger('gajim.plugin_system.omemo') - -PILLOW = False -try: - import qrcode - PILLOW = True -except ImportError as error: - log.debug(error) - log.error('python-qrcode or dependencies of it are not available') - -from gajim.common import app -from gajim.common import configpaths -from gajim.dialogs import YesNoDialog -from gajim.plugins.gui import GajimPluginConfigDialog - -# Since Gajim 1.1.0 _() has to be imported -try: - from gajim.common.i18n import _ -except ImportError: - pass - -@unique -class State(IntEnum): - UNTRUSTED = 0 - TRUSTED = 1 - UNDECIDED = 2 - - -class OMEMOConfigDialog(GajimPluginConfigDialog): - def init(self): - # pylint: disable=attribute-defined-outside-init - self.GTK_BUILDER_FILE_PATH = \ - self.plugin.local_file_path('config_dialog.ui') - self.B = Gtk.Builder() - self.B.set_translation_domain('gajim_plugins') - self.B.add_from_file(self.GTK_BUILDER_FILE_PATH) - - try: - self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS'] - except KeyError: - self.plugin.config['DISABLED_ACCOUNTS'] = [] - self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS'] - - log.debug('Disabled Accounts:') - log.debug(self.disabled_accounts) - - self.device_model = self.B.get_object('deviceid_store') - - self.disabled_acc_store = self.B.get_object('disabled_account_store') - self.account_store = self.B.get_object('account_store') - - self.active_acc_view = self.B.get_object('active_accounts_view') - self.disabled_acc_view = self.B.get_object('disabled_accounts_view') - - box = self.get_content_area() - box.pack_start(self.B.get_object('notebook1'), True, True, 0) - - self.B.connect_signals(self) - - self.plugin_active = False - - def on_run(self): - for plugin in app.plugin_manager.active_plugins: - log.debug(type(plugin)) - if type(plugin).__name__ == 'OmemoPlugin': - self.plugin_active = True - break - self.update_account_store() - self.update_account_combobox() - self.update_disabled_account_view() - - def is_in_accountstore(self, account): - for row in self.account_store: - if row[0] == account: - return True - return False - - def update_account_store(self): - for account in sorted(app.contacts.get_accounts()): - if account in self.disabled_accounts: - continue - if account == 'Local': - continue - if not self.is_in_accountstore(account): - self.account_store.append(row=(account,)) - - def update_account_combobox(self): - if self.plugin_active is False: - return - if len(self.account_store) > 0: - self.B.get_object('account_combobox').set_active(0) - else: - self.account_combobox_changed_cb( - self.B.get_object('account_combobox')) - - def account_combobox_changed_cb(self, box, *args): - self.update_context_list() - - def get_qrcode(self, jid, sid, fingerprint): - file_name = 'omemo_{}.png'.format(jid) - path = os.path.join( - configpaths.get('MY_DATA'), file_name) - - ver_string = 'xmpp:{}?omemo-sid-{}={}'.format(jid, sid, fingerprint) - log.debug('Verification String: ' + ver_string) - - if os.path.exists(path): - return path - - qr = qrcode.QRCode(version=None, error_correction=2, box_size=4, border=1) - qr.add_data(ver_string) - qr.make(fit=True) - img = qr.make_image() - img.save(path) - return path - - def update_disabled_account_view(self): - self.disabled_acc_store.clear() - for account in self.disabled_accounts: - self.disabled_acc_store.append(row=(account,)) - - def activate_accounts_btn_clicked(self, button, *args): - mod, paths = self.disabled_acc_view.get_selection().get_selected_rows() - for path in paths: - it = mod.get_iter(path) - account = mod.get(it, 0) - if account[0] in self.disabled_accounts and \ - not self.is_in_accountstore(account[0]): - self.account_store.append(row=(account[0],)) - self.disabled_accounts.remove(account[0]) - self.update_disabled_account_view() - self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts - self.update_account_combobox() - - def disable_accounts_btn_clicked(self, button, *args): - mod, paths = self.active_acc_view.get_selection().get_selected_rows() - for path in paths: - it = mod.get_iter(path) - account = mod.get(it, 0) - if account[0] not in self.disabled_accounts and \ - self.is_in_accountstore(account[0]): - self.disabled_accounts.append(account[0]) - self.account_store.remove(it) - self.update_disabled_account_view() - self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts - self.update_account_combobox() - - def cleardevice_button_clicked_cb(self, button, *args): - active = self.B.get_object('account_combobox').get_active() - account = self.account_store[active][0] - self.plugin.connections[account].clear_device_list() - self.update_context_list() - - def refresh_button_clicked_cb(self, button, *args): - self.update_context_list() - - def update_context_list(self): - self.device_model.clear() - self.qrcode = self.B.get_object('qrcode') - self.qrinfo = self.B.get_object('qrinfo') - if len(self.account_store) == 0: - self.B.get_object('ID').set_markup('') - self.B.get_object('fingerprint_label').set_markup('') - self.B.get_object('refresh').set_sensitive(False) - self.B.get_object('cleardevice_button').set_sensitive(False) - self.B.get_object('qrcode').clear() - return - active = self.B.get_object('account_combobox').get_active() - account = self.account_store[active][0] - - # Set buttons active - self.B.get_object('refresh').set_sensitive(True) - if account == 'Local': - self.B.get_object('cleardevice_button').set_sensitive(False) - else: - self.B.get_object('cleardevice_button').set_sensitive(True) - - # Set FPR Label and DeviceID - state = self.plugin.get_omemo(account) - deviceid = state.own_device_id - self.B.get_object('ID').set_markup('%s' % deviceid) - - ownfpr = binascii.hexlify(state.store.getIdentityKeyPair() - .getPublicKey().serialize()).decode('utf-8') - human_ownfpr = self.human_hash(ownfpr[2:]) - self.B.get_object('fingerprint_label').set_markup('%s' - % human_ownfpr) - - # Set Device ID List - for item in state.own_devices: - self.device_model.append([item]) - - # Set QR Verification Code - if PILLOW: - path = self.get_qrcode( - app.get_jid_from_account(account), deviceid, ownfpr[2:]) - pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) - self.qrcode.set_from_pixbuf(pixbuf) - self.qrcode.show() - self.qrinfo.set_revealed(False) - else: - self.qrinfo.set_revealed(True) - self.qrcode.hide() - - def human_hash(self, fpr): - fpr = fpr.upper() - fplen = len(fpr) - wordsize = fplen // 8 - buf = '' - for w in range(0, fplen, wordsize): - buf += '{0} '.format(fpr[w:w + wordsize]) - buf = textwrap.fill(buf, width=36) - return buf.rstrip() +''' +Copyright 2015 Bahtiar `kalkin-` Gadimov +Copyright 2015 Daniel Gultsch +Copyright 2016 Philipp Hörist + +This file is part of Gajim-OMEMO plugin. + +The Gajim-OMEMO 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, either version 3 of the License, or (at your option) any +later version. + +Gajim-OMEMO 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 +the Gajim-OMEMO plugin. If not, see . +''' + +import binascii +import logging +import os +import textwrap +from enum import IntEnum, unique + +from gi.repository import GdkPixbuf + +from gajim.common import app +from gajim.common import configpaths +from gajim.plugins.gui import GajimPluginConfigDialog +from gajim.plugins.helpers import get_builder + +log = logging.getLogger('gajim.plugin_system.omemo') + +PILLOW = False +try: + import qrcode + PILLOW = True +except ImportError as error: + log.debug(error) + log.error('python-qrcode or dependencies of it are not available') + + +@unique +class State(IntEnum): + UNTRUSTED = 0 + TRUSTED = 1 + UNDECIDED = 2 + + +class OMEMOConfigDialog(GajimPluginConfigDialog): + def init(self): + # pylint: disable=attribute-defined-outside-init + path = self.plugin.local_file_path('gtk/config.ui') + self._ui = get_builder(path) + + image_path = self.plugin.local_file_path('omemo.png') + self._ui.image.set_from_file(image_path) + + try: + self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS'] + except KeyError: + self.plugin.config['DISABLED_ACCOUNTS'] = [] + self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS'] + + log.debug('Disabled Accounts:') + log.debug(self.disabled_accounts) + + self.device_model = self._ui.get_object('deviceid_store') + + self.disabled_acc_store = self._ui.get_object('disabled_account_store') + self.account_store = self._ui.get_object('account_store') + + self.active_acc_view = self._ui.get_object('active_accounts_view') + self.disabled_acc_view = self._ui.get_object('disabled_accounts_view') + + box = self.get_content_area() + box.pack_start(self._ui.get_object('notebook1'), True, True, 0) + + self._ui.connect_signals(self) + + self.plugin_active = False + + def on_run(self): + for plugin in app.plugin_manager.active_plugins: + log.debug(type(plugin)) + if type(plugin).__name__ == 'OmemoPlugin': + self.plugin_active = True + break + self.update_account_store() + self.update_account_combobox() + self.update_disabled_account_view() + + def is_in_accountstore(self, account): + for row in self.account_store: + if row[0] == account: + return True + return False + + def update_account_store(self): + for account in sorted(app.contacts.get_accounts()): + if account in self.disabled_accounts: + continue + if account == 'Local': + continue + if not self.is_in_accountstore(account): + self.account_store.append(row=(account,)) + + def update_account_combobox(self): + if self.plugin_active is False: + return + if len(self.account_store) > 0: + self._ui.get_object('account_combobox').set_active(0) + else: + self.account_combobox_changed_cb( + self._ui.get_object('account_combobox')) + + def account_combobox_changed_cb(self, box, *args): + self.update_context_list() + + def get_qrcode(self, jid, sid, fingerprint): + file_name = 'omemo_{}.png'.format(jid) + path = os.path.join( + configpaths.get('MY_DATA'), file_name) + + ver_string = 'xmpp:{}?omemo-sid-{}={}'.format(jid, sid, fingerprint) + log.debug('Verification String: ' + ver_string) + + if os.path.exists(path): + return path + + qr = qrcode.QRCode(version=None, error_correction=2, box_size=4, border=1) + qr.add_data(ver_string) + qr.make(fit=True) + img = qr.make_image() + img.save(path) + return path + + def update_disabled_account_view(self): + self.disabled_acc_store.clear() + for account in self.disabled_accounts: + self.disabled_acc_store.append(row=(account,)) + + def activate_accounts_btn_clicked(self, button, *args): + mod, paths = self.disabled_acc_view.get_selection().get_selected_rows() + for path in paths: + it = mod.get_iter(path) + account = mod.get(it, 0) + if account[0] in self.disabled_accounts and \ + not self.is_in_accountstore(account[0]): + self.account_store.append(row=(account[0],)) + self.disabled_accounts.remove(account[0]) + self.update_disabled_account_view() + self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts + self.update_account_combobox() + + def disable_accounts_btn_clicked(self, button, *args): + mod, paths = self.active_acc_view.get_selection().get_selected_rows() + for path in paths: + it = mod.get_iter(path) + account = mod.get(it, 0) + if account[0] not in self.disabled_accounts and \ + self.is_in_accountstore(account[0]): + self.disabled_accounts.append(account[0]) + self.account_store.remove(it) + self.update_disabled_account_view() + self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts + self.update_account_combobox() + + def cleardevice_button_clicked_cb(self, button, *args): + active = self._ui.get_object('account_combobox').get_active() + account = self.account_store[active][0] + self.plugin.connections[account].clear_device_list() + self.update_context_list() + + def refresh_button_clicked_cb(self, button, *args): + self.update_context_list() + + def update_context_list(self): + self.device_model.clear() + self.qrcode = self._ui.get_object('qrcode') + self.qrinfo = self._ui.get_object('qrinfo') + if len(self.account_store) == 0: + self._ui.get_object('ID').set_markup('') + self._ui.get_object('fingerprint_label').set_markup('') + self._ui.get_object('refresh').set_sensitive(False) + self._ui.get_object('cleardevice_button').set_sensitive(False) + self._ui.get_object('qrcode').clear() + return + active = self._ui.get_object('account_combobox').get_active() + account = self.account_store[active][0] + + # Set buttons active + self._ui.get_object('refresh').set_sensitive(True) + if account == 'Local': + self._ui.get_object('cleardevice_button').set_sensitive(False) + else: + self._ui.get_object('cleardevice_button').set_sensitive(True) + + # Set FPR Label and DeviceID + state = self.plugin.get_omemo(account) + deviceid = state.own_device_id + self._ui.get_object('ID').set_markup('%s' % deviceid) + + ownfpr = binascii.hexlify(state.store.getIdentityKeyPair() + .getPublicKey().serialize()).decode('utf-8') + human_ownfpr = self.human_hash(ownfpr[2:]) + self._ui.get_object('fingerprint_label').set_markup('%s' + % human_ownfpr) + + # Set Device ID List + for item in state.own_devices: + self.device_model.append([item]) + + # Set QR Verification Code + if PILLOW: + path = self.get_qrcode( + app.get_jid_from_account(account), deviceid, ownfpr[2:]) + pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) + self.qrcode.set_from_pixbuf(pixbuf) + self.qrcode.show() + self.qrinfo.set_revealed(False) + else: + self.qrinfo.set_revealed(True) + self.qrcode.hide() + + def human_hash(self, fpr): + fpr = fpr.upper() + fplen = len(fpr) + wordsize = fplen // 8 + buf = '' + for w in range(0, fplen, wordsize): + buf += '{0} '.format(fpr[w:w + wordsize]) + buf = textwrap.fill(buf, width=36) + return buf.rstrip() diff --git a/omemo/config_dialog.ui b/omemo/gtk/config.ui similarity index 99% rename from omemo/config_dialog.ui rename to omemo/gtk/config.ui index a5b6b10..e86efef 100644 --- a/omemo/config_dialog.ui +++ b/omemo/gtk/config.ui @@ -229,12 +229,11 @@ - + True False OMEMO start - omemo.png 0 diff --git a/omemo/gtk/progress.py b/omemo/gtk/progress.py new file mode 100644 index 0000000..1d565fc --- /dev/null +++ b/omemo/gtk/progress.py @@ -0,0 +1,52 @@ +# Copyright (C) 2018 Philipp Hörist +# +# This file is part of Gajim. +# +# Gajim 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. +# +# Gajim 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 Gajim. If not, see . + +from gajim.plugins.helpers import get_builder + + +class ProgressWindow: + def __init__(self, plugin, window, event): + self._plugin = plugin + self._event = event + + path = self._plugin.local_file_path('gtk/progress.ui') + self._ui = get_builder(path) + self._ui.progress_dialog.set_transient_for(window) + self._ui.progressbar.set_text("") + self._ui.progress_dialog.show_all() + + image_path = self._plugin.local_file_path('omemo.png') + self._ui.image.set_from_file(image_path) + self._ui.connect_signals(self) + self._seen = 0 + + def set_text(self, text): + self._ui.label.set_markup('%s' % text) + return False + + def update_progress(self, seen, total): + self._seen += seen + pct = (self._seen / float(total)) * 100.0 + self._ui.progressbar.set_fraction(self._seen / float(total)) + self._ui.progressbar.set_text(str(int(pct)) + "%") + return False + + def close_dialog(self, *args): + self._ui.progress_dialog.destroy() + return False + + def on_destroy(self, *args): + self._event.set() diff --git a/omemo/download_progress_dialog.ui b/omemo/gtk/progress.ui similarity index 98% rename from omemo/download_progress_dialog.ui rename to omemo/gtk/progress.ui index 69a4aaf..89eed45 100644 --- a/omemo/download_progress_dialog.ui +++ b/omemo/gtk/progress.ui @@ -60,12 +60,11 @@ - + True False OMEMO 6 - omemo.png False diff --git a/omemo/omemoplugin.py b/omemo/omemoplugin.py index 9706942..bba6404 100644 --- a/omemo/omemoplugin.py +++ b/omemo/omemoplugin.py @@ -38,6 +38,7 @@ from gajim.groupchat_control import GroupchatControl from omemo.xmpp import DevicelistPEP from omemo.gtk.key import KeyDialog +from omemo.gtk.config import OMEMOConfigDialog CRYPTOGRAPHY_MISSING = 'You are missing Python-Cryptography' AXOLOTL_MISSING = 'You are missing Python-Axolotl or use an outdated version' @@ -69,7 +70,6 @@ except Exception as error: if not ERROR_MSG: try: from omemo.omemo_connection import OMEMOConnection - from omemo.ui import OMEMOConfigDialog except Exception as error: log.error(error) ERROR_MSG = 'Error: %s' % error