[omemo] Move ui files into gtk folder

This commit is contained in:
Philipp Hörist
2018-10-12 23:37:12 +02:00
parent 80a7a5db57
commit 5a171fdfc4
6 changed files with 293 additions and 285 deletions

View File

@@ -32,10 +32,10 @@ from urllib.parse import urlparse, urldefrag
from io import BufferedWriter, FileIO, BytesIO from io import BufferedWriter, FileIO, BytesIO
from gi.repository import GLib from gi.repository import GLib
from gajim import gtkgui_helpers
from gajim.common import app from gajim.common import app
from gajim.common import configpaths 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': if os.name == 'nt':
import certifi import certifi
@@ -265,40 +265,6 @@ class Download:
return False 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('<big>%s</big>' % 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): class DownloadAbortedException(Exception):
def __str__(self): def __str__(self):
return _('Download Aborted') return _('Download Aborted')

View File

@@ -1,244 +1,236 @@
# -*- coding: utf-8 -*- '''
Copyright 2015 Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
''' Copyright 2015 Daniel Gultsch <daniel@cgultsch.de>
Copyright 2015 Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de> Copyright 2016 Philipp Hörist <philipp@hoerist.com>
Copyright 2015 Daniel Gultsch <daniel@cgultsch.de>
Copyright 2016 Philipp Hörist <philipp@hoerist.com> This file is part of Gajim-OMEMO plugin.
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
The Gajim-OMEMO plugin is free software: you can redistribute it and/or modify Software Foundation, either version 3 of the License, or (at your option) any
it under the terms of the GNU General Public License as published by the Free later version.
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
Gajim-OMEMO is distributed in the hope that it will be useful, but WITHOUT ANY A PARTICULAR PURPOSE. See the GNU General Public License for more details.
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 <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License along with '''
the Gajim-OMEMO plugin. If not, see <http://www.gnu.org/licenses/>.
''' import binascii
import logging
import binascii import os
import logging import textwrap
import os from enum import IntEnum, unique
import textwrap
from enum import IntEnum, unique from gi.repository import GdkPixbuf
from gi.repository import Gtk, GdkPixbuf, Gdk from gajim.common import app
from axolotl.state.sessionrecord import SessionRecord from gajim.common import configpaths
from gajim.plugins.gui import GajimPluginConfigDialog
log = logging.getLogger('gajim.plugin_system.omemo') from gajim.plugins.helpers import get_builder
PILLOW = False log = logging.getLogger('gajim.plugin_system.omemo')
try:
import qrcode PILLOW = False
PILLOW = True try:
except ImportError as error: import qrcode
log.debug(error) PILLOW = True
log.error('python-qrcode or dependencies of it are not available') except ImportError as error:
log.debug(error)
from gajim.common import app log.error('python-qrcode or dependencies of it are not available')
from gajim.common import configpaths
from gajim.dialogs import YesNoDialog
from gajim.plugins.gui import GajimPluginConfigDialog @unique
class State(IntEnum):
# Since Gajim 1.1.0 _() has to be imported UNTRUSTED = 0
try: TRUSTED = 1
from gajim.common.i18n import _ UNDECIDED = 2
except ImportError:
pass
class OMEMOConfigDialog(GajimPluginConfigDialog):
@unique def init(self):
class State(IntEnum): # pylint: disable=attribute-defined-outside-init
UNTRUSTED = 0 path = self.plugin.local_file_path('gtk/config.ui')
TRUSTED = 1 self._ui = get_builder(path)
UNDECIDED = 2
image_path = self.plugin.local_file_path('omemo.png')
self._ui.image.set_from_file(image_path)
class OMEMOConfigDialog(GajimPluginConfigDialog):
def init(self): try:
# pylint: disable=attribute-defined-outside-init self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS']
self.GTK_BUILDER_FILE_PATH = \ except KeyError:
self.plugin.local_file_path('config_dialog.ui') self.plugin.config['DISABLED_ACCOUNTS'] = []
self.B = Gtk.Builder() self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS']
self.B.set_translation_domain('gajim_plugins')
self.B.add_from_file(self.GTK_BUILDER_FILE_PATH) log.debug('Disabled Accounts:')
log.debug(self.disabled_accounts)
try:
self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS'] self.device_model = self._ui.get_object('deviceid_store')
except KeyError:
self.plugin.config['DISABLED_ACCOUNTS'] = [] self.disabled_acc_store = self._ui.get_object('disabled_account_store')
self.disabled_accounts = self.plugin.config['DISABLED_ACCOUNTS'] self.account_store = self._ui.get_object('account_store')
log.debug('Disabled Accounts:') self.active_acc_view = self._ui.get_object('active_accounts_view')
log.debug(self.disabled_accounts) self.disabled_acc_view = self._ui.get_object('disabled_accounts_view')
self.device_model = self.B.get_object('deviceid_store') box = self.get_content_area()
box.pack_start(self._ui.get_object('notebook1'), True, True, 0)
self.disabled_acc_store = self.B.get_object('disabled_account_store')
self.account_store = self.B.get_object('account_store') self._ui.connect_signals(self)
self.active_acc_view = self.B.get_object('active_accounts_view') self.plugin_active = False
self.disabled_acc_view = self.B.get_object('disabled_accounts_view')
def on_run(self):
box = self.get_content_area() for plugin in app.plugin_manager.active_plugins:
box.pack_start(self.B.get_object('notebook1'), True, True, 0) log.debug(type(plugin))
if type(plugin).__name__ == 'OmemoPlugin':
self.B.connect_signals(self) self.plugin_active = True
break
self.plugin_active = False self.update_account_store()
self.update_account_combobox()
def on_run(self): self.update_disabled_account_view()
for plugin in app.plugin_manager.active_plugins:
log.debug(type(plugin)) def is_in_accountstore(self, account):
if type(plugin).__name__ == 'OmemoPlugin': for row in self.account_store:
self.plugin_active = True if row[0] == account:
break return True
self.update_account_store() return False
self.update_account_combobox()
self.update_disabled_account_view() def update_account_store(self):
for account in sorted(app.contacts.get_accounts()):
def is_in_accountstore(self, account): if account in self.disabled_accounts:
for row in self.account_store: continue
if row[0] == account: if account == 'Local':
return True continue
return False if not self.is_in_accountstore(account):
self.account_store.append(row=(account,))
def update_account_store(self):
for account in sorted(app.contacts.get_accounts()): def update_account_combobox(self):
if account in self.disabled_accounts: if self.plugin_active is False:
continue return
if account == 'Local': if len(self.account_store) > 0:
continue self._ui.get_object('account_combobox').set_active(0)
if not self.is_in_accountstore(account): else:
self.account_store.append(row=(account,)) self.account_combobox_changed_cb(
self._ui.get_object('account_combobox'))
def update_account_combobox(self):
if self.plugin_active is False: def account_combobox_changed_cb(self, box, *args):
return self.update_context_list()
if len(self.account_store) > 0:
self.B.get_object('account_combobox').set_active(0) def get_qrcode(self, jid, sid, fingerprint):
else: file_name = 'omemo_{}.png'.format(jid)
self.account_combobox_changed_cb( path = os.path.join(
self.B.get_object('account_combobox')) configpaths.get('MY_DATA'), file_name)
def account_combobox_changed_cb(self, box, *args): ver_string = 'xmpp:{}?omemo-sid-{}={}'.format(jid, sid, fingerprint)
self.update_context_list() log.debug('Verification String: ' + ver_string)
def get_qrcode(self, jid, sid, fingerprint): if os.path.exists(path):
file_name = 'omemo_{}.png'.format(jid) return path
path = os.path.join(
configpaths.get('MY_DATA'), file_name) qr = qrcode.QRCode(version=None, error_correction=2, box_size=4, border=1)
qr.add_data(ver_string)
ver_string = 'xmpp:{}?omemo-sid-{}={}'.format(jid, sid, fingerprint) qr.make(fit=True)
log.debug('Verification String: ' + ver_string) img = qr.make_image()
img.save(path)
if os.path.exists(path): return path
return path
def update_disabled_account_view(self):
qr = qrcode.QRCode(version=None, error_correction=2, box_size=4, border=1) self.disabled_acc_store.clear()
qr.add_data(ver_string) for account in self.disabled_accounts:
qr.make(fit=True) self.disabled_acc_store.append(row=(account,))
img = qr.make_image()
img.save(path) def activate_accounts_btn_clicked(self, button, *args):
return path mod, paths = self.disabled_acc_view.get_selection().get_selected_rows()
for path in paths:
def update_disabled_account_view(self): it = mod.get_iter(path)
self.disabled_acc_store.clear() account = mod.get(it, 0)
for account in self.disabled_accounts: if account[0] in self.disabled_accounts and \
self.disabled_acc_store.append(row=(account,)) not self.is_in_accountstore(account[0]):
self.account_store.append(row=(account[0],))
def activate_accounts_btn_clicked(self, button, *args): self.disabled_accounts.remove(account[0])
mod, paths = self.disabled_acc_view.get_selection().get_selected_rows() self.update_disabled_account_view()
for path in paths: self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts
it = mod.get_iter(path) self.update_account_combobox()
account = mod.get(it, 0)
if account[0] in self.disabled_accounts and \ def disable_accounts_btn_clicked(self, button, *args):
not self.is_in_accountstore(account[0]): mod, paths = self.active_acc_view.get_selection().get_selected_rows()
self.account_store.append(row=(account[0],)) for path in paths:
self.disabled_accounts.remove(account[0]) it = mod.get_iter(path)
self.update_disabled_account_view() account = mod.get(it, 0)
self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts if account[0] not in self.disabled_accounts and \
self.update_account_combobox() self.is_in_accountstore(account[0]):
self.disabled_accounts.append(account[0])
def disable_accounts_btn_clicked(self, button, *args): self.account_store.remove(it)
mod, paths = self.active_acc_view.get_selection().get_selected_rows() self.update_disabled_account_view()
for path in paths: self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts
it = mod.get_iter(path) self.update_account_combobox()
account = mod.get(it, 0)
if account[0] not in self.disabled_accounts and \ def cleardevice_button_clicked_cb(self, button, *args):
self.is_in_accountstore(account[0]): active = self._ui.get_object('account_combobox').get_active()
self.disabled_accounts.append(account[0]) account = self.account_store[active][0]
self.account_store.remove(it) self.plugin.connections[account].clear_device_list()
self.update_disabled_account_view() self.update_context_list()
self.plugin.config['DISABLED_ACCOUNTS'] = self.disabled_accounts
self.update_account_combobox() def refresh_button_clicked_cb(self, button, *args):
self.update_context_list()
def cleardevice_button_clicked_cb(self, button, *args):
active = self.B.get_object('account_combobox').get_active() def update_context_list(self):
account = self.account_store[active][0] self.device_model.clear()
self.plugin.connections[account].clear_device_list() self.qrcode = self._ui.get_object('qrcode')
self.update_context_list() self.qrinfo = self._ui.get_object('qrinfo')
if len(self.account_store) == 0:
def refresh_button_clicked_cb(self, button, *args): self._ui.get_object('ID').set_markup('')
self.update_context_list() self._ui.get_object('fingerprint_label').set_markup('')
self._ui.get_object('refresh').set_sensitive(False)
def update_context_list(self): self._ui.get_object('cleardevice_button').set_sensitive(False)
self.device_model.clear() self._ui.get_object('qrcode').clear()
self.qrcode = self.B.get_object('qrcode') return
self.qrinfo = self.B.get_object('qrinfo') active = self._ui.get_object('account_combobox').get_active()
if len(self.account_store) == 0: account = self.account_store[active][0]
self.B.get_object('ID').set_markup('')
self.B.get_object('fingerprint_label').set_markup('') # Set buttons active
self.B.get_object('refresh').set_sensitive(False) self._ui.get_object('refresh').set_sensitive(True)
self.B.get_object('cleardevice_button').set_sensitive(False) if account == 'Local':
self.B.get_object('qrcode').clear() self._ui.get_object('cleardevice_button').set_sensitive(False)
return else:
active = self.B.get_object('account_combobox').get_active() self._ui.get_object('cleardevice_button').set_sensitive(True)
account = self.account_store[active][0]
# Set FPR Label and DeviceID
# Set buttons active state = self.plugin.get_omemo(account)
self.B.get_object('refresh').set_sensitive(True) deviceid = state.own_device_id
if account == 'Local': self._ui.get_object('ID').set_markup('<tt>%s</tt>' % deviceid)
self.B.get_object('cleardevice_button').set_sensitive(False)
else: ownfpr = binascii.hexlify(state.store.getIdentityKeyPair()
self.B.get_object('cleardevice_button').set_sensitive(True) .getPublicKey().serialize()).decode('utf-8')
human_ownfpr = self.human_hash(ownfpr[2:])
# Set FPR Label and DeviceID self._ui.get_object('fingerprint_label').set_markup('<tt>%s</tt>'
state = self.plugin.get_omemo(account) % human_ownfpr)
deviceid = state.own_device_id
self.B.get_object('ID').set_markup('<tt>%s</tt>' % deviceid) # Set Device ID List
for item in state.own_devices:
ownfpr = binascii.hexlify(state.store.getIdentityKeyPair() self.device_model.append([item])
.getPublicKey().serialize()).decode('utf-8')
human_ownfpr = self.human_hash(ownfpr[2:]) # Set QR Verification Code
self.B.get_object('fingerprint_label').set_markup('<tt>%s</tt>' if PILLOW:
% human_ownfpr) path = self.get_qrcode(
app.get_jid_from_account(account), deviceid, ownfpr[2:])
# Set Device ID List pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
for item in state.own_devices: self.qrcode.set_from_pixbuf(pixbuf)
self.device_model.append([item]) self.qrcode.show()
self.qrinfo.set_revealed(False)
# Set QR Verification Code else:
if PILLOW: self.qrinfo.set_revealed(True)
path = self.get_qrcode( self.qrcode.hide()
app.get_jid_from_account(account), deviceid, ownfpr[2:])
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) def human_hash(self, fpr):
self.qrcode.set_from_pixbuf(pixbuf) fpr = fpr.upper()
self.qrcode.show() fplen = len(fpr)
self.qrinfo.set_revealed(False) wordsize = fplen // 8
else: buf = ''
self.qrinfo.set_revealed(True) for w in range(0, fplen, wordsize):
self.qrcode.hide() buf += '{0} '.format(fpr[w:w + wordsize])
buf = textwrap.fill(buf, width=36)
def human_hash(self, fpr): return buf.rstrip()
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()

View File

@@ -229,12 +229,11 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkImage"> <object class="GtkImage" id="image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="tooltip_text">OMEMO</property> <property name="tooltip_text">OMEMO</property>
<property name="valign">start</property> <property name="valign">start</property>
<property name="pixbuf">omemo.png</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>

52
omemo/gtk/progress.py Normal file
View File

@@ -0,0 +1,52 @@
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# 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 <http://www.gnu.org/licenses/>.
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('<big>%s</big>' % 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()

View File

@@ -60,12 +60,11 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkImage"> <object class="GtkImage" id="image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="tooltip_text">OMEMO</property> <property name="tooltip_text">OMEMO</property>
<property name="margin_right">6</property> <property name="margin_right">6</property>
<property name="pixbuf">omemo.png</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>

View File

@@ -38,6 +38,7 @@ from gajim.groupchat_control import GroupchatControl
from omemo.xmpp import DevicelistPEP from omemo.xmpp import DevicelistPEP
from omemo.gtk.key import KeyDialog from omemo.gtk.key import KeyDialog
from omemo.gtk.config import OMEMOConfigDialog
CRYPTOGRAPHY_MISSING = 'You are missing Python-Cryptography' CRYPTOGRAPHY_MISSING = 'You are missing Python-Cryptography'
AXOLOTL_MISSING = 'You are missing Python-Axolotl or use an outdated version' AXOLOTL_MISSING = 'You are missing Python-Axolotl or use an outdated version'
@@ -69,7 +70,6 @@ except Exception as error:
if not ERROR_MSG: if not ERROR_MSG:
try: try:
from omemo.omemo_connection import OMEMOConnection from omemo.omemo_connection import OMEMOConnection
from omemo.ui import OMEMOConfigDialog
except Exception as error: except Exception as error:
log.error(error) log.error(error)
ERROR_MSG = 'Error: %s' % error ERROR_MSG = 'Error: %s' % error