diff --git a/README.md b/README.md index f401e6b..41df2f1 100644 --- a/README.md +++ b/README.md @@ -3,52 +3,68 @@ Pyrite - Python/GTK+ encryption/signing frontend for GnuPG and OpenSSL ![](http://b19.org/linux/pyrite/1enc_txt.png) +## FEATURES -FEDORA/RHEL7 INSTALLATION -------------------------- -There's an RPM (and yum repository) @ [people.redhat.com/rsawhill/rpms](http://people.redhat.com/rsawhill/rpms/). To configure it and install Pyrite, simply run the following as root: +Pyrite acts as a frontend for GnuPG, doing symmetric or asymmetric encrypting/decrypting, as well as signing and verifying. +Additionally, it can use OpenSSL for simple symmetric encryption/decryption. + +Pyrite can operate on text input or can take input and output filenames (text or binary) to pass directly to the backend program (i.e., gpg or openssl). + +As you can see from the screenshots, Pyrite can utilize virtually all the encrypting features of GnuPG -- you can mix and match passphrase & public-key encryption & signing with one file, just like gpg, which will require interacting with your gpg-agent. +Or you can keep it simple and just use a passphrase as a shared key, in which case gpg-agent is bypassed and you only have to type the passphrase once. + +Also shown in the screenshots is a Sign/Verify mode, where you can choose between the three types of signing: normal (Pyrite calls it "embedded"), where a signed copy of the message is created; clearsign, where the message is wrapped with a plaintext ASCII sig; or detached-sign, where a separate sig file is created. + +If you're operating directly on files (in sign or encrypt mode) instead of ASCII text in the Pyrite window, you can choose what kind of output you want -- ASCII-armored (base64-encoded) text or normal binary output. + +Not shown in the screenshots is drag & drop. You can drag text files onto the Message area and they are loaded up and you can drag text or binary files onto the *Input File For Direct Operation* button to set that. + +If you end up working on very large input, you'll get a chance to *really* see the progress bar + pause/cancel buttons. +At the moment the progress bar doesn't report actual progress (that's coming), but the buttons do what they advertise, pausing or canceling the backend processing. + +To top it all off, everything is configurable. +There's a preferences dialog that lets you play with all the settings, from tweaking gpg verbosity to setting the default operating mode to choosing your favorite cipher to configuring font size/color and window opacity. + +If you find yourself wondering about a particular feature, just hover your mouse over its widget -- there are detailed tooltips for everything. + + +## FEDORA/RHEL7 INSTALLATION +There's an RPM (and yum repository) @ [people.redhat.com/rsawhill/rpms](https://people.redhat.com/rsawhill/rpms/). To configure it and install Pyrite, simply run the following as root: ``` -yum install http://people.redhat.com/rsawhill/rpms/latest-rsawaroha-release.rpm +yum install https://people.redhat.com/rsawhill/rpms/latest-rsawaroha-release.rpm yum install pyrite ``` Requirements and package names: -- gtk2 >= v2.24: `gtk2` -- python2 >= v2.7: `python` -- pygtk: `pygtk2` -- gpg/openssl: `gnupg2` or `gnupg` or `openssl` - -*As per above, Pyrite is not compatible with RHEL6.* +- GTK3: `gtk3` +- Python3: `python3` +- `python3-gi`, `python3-gi-cairo` +- PGP `gnupg2` or OpenSSL `openssl` -DEBIAN/UBUNTU/OTHER LINUX INSTALLATION --------------------------------------- -There is a simple interactive shell installer. Before using it, ensure you have the following on your Linux system (Ubuntu package names): +## DEBIAN/UBUNTU/OTHER LINUX INSTALLATION -- gtk2 >= v2.24: `libgtk2.0-bin` -- python2 >= v2.7: `python` -- pygtk: `python-gtk2` -- gpg/openssl: `gnupg2` or (`gnupg` and `gnupg-agent`) or `openssl` +There is a simple interactive shell installer. -If requirements are met, clone the Pyrite repo with `git clone git://github.com/ryran/pyrite.git` **OR** [download a zip of the source](https://github.com/ryran/pyrite/archive/master.zip). +If requirements are met, clone the Pyrite repo with `git clone https://github.com/ryran/pyrite.git` **OR** [download a zip of the source](https://github.com/ryran/pyrite/archive/master.zip). From the root source folder execute the interactive `INSTALL` script. -MORE SCREENSHOTS (v1.0.1): -------------------------------- +## MORE SCREENSHOTS (v1.0.1): + ![](http://b19.org/linux/pyrite/2clearsign_txt.png) ![](http://b19.org/linux/pyrite/3enc_prog.png) ![](http://b19.org/linux/pyrite/4dec_txt.png) ![](http://b19.org/linux/pyrite/5openssl_txt.png) ![](http://b19.org/linux/pyrite/6prefs.png) -**`pyrite` command-line options:** +## `pyrite` command-line options +Type `pyrite --help`: ``` -[rsaw:~]$ pyrite --help usage: pyrite [-h] [-d | -t] [-e | -s] [-c] [-r RECIP] [-k KEYUID] [-b {gpg,openssl}] [INPUT] @@ -75,48 +91,16 @@ optional arguments: ``` -FEATURES ----------- -Pyrite acts as a frontend for GnuPG, doing symmetric or asymmetric encrypting/decrypting, as well as signing and verifying. Additionally, it can use OpenSSL for simple symmetric encryption/decryption. - -Pyrite can operate on text input or can take input and output filenames (text or binary) to pass directly to the backend program (i.e., gpg/gpg2 or openssl). - -As you can see from the screenshots, Pyrite can utilize virtually all of the encrypting features of GnuPG -- you can mix and match passphrase & public-key encryption & signing with one file, just like gpg, which will require interacting with your gpg-agent. Or you can keep it simple and just use a passphrase as a shared key, in which case gpg-agent is bypassed and you only have to type the passphrase once. - -Also shown in the screenshots is a Sign/Verify mode, where you can choose between the three types of signing: normal (Pyrite calls it "embedded"), where a signed copy of the message is created; clearsign, where the message is wrapped with a plaintext ASCII sig; or detached-sign, where a separate sig file is created. - -If you're operating directly on files (in sign or encrypt mode) instead of ASCII text in the Pyrite window, you can choose what kind of output you want -- ASCII-armored (base64-encoded) text or normal binary output. - -Not shown in the screenshots is drag & drop. You can drag text files onto the Message area and they are loaded up and you can drag text or binary files onto the *Input File For Direct Operation* button to set that. - -If you end up working on very large input, you'll get a chance to *really* see the progress bar + pause/cancel buttons. At the moment the progress bar doesn't report actual progress (that's coming), but the buttons do what they advertise, pausing or canceling the backend processing. - -To top it all off, everything is configurable. There's a preferences dialog that lets you play with all the settings, from tweaking gpg verbosity to setting the default operating mode to choosing your favorite cipher to configuring font size/color and window opacity. - -If you find yourself wondering about a particular feature, just hover your mouse over its widget -- there are detailed tooltips for everything. - +## BUGS and TODO -BUGS ----------- -1) After launching Pyrite, the **first** drag/drop of a file onto the *Input File For Direct Operation* GtkFileChooserButton fails. After that the button works properly. I've been seeking out expertise on this weird bug but I haven't gotten anywhere. If you have any hints, hit me up, or check out [my post about it on stackoverflow](http://stackoverflow.com/questions/9047844/pygtk-troubles-with-drag-and-drop-file-to-gtkfilechooserbutton). - -2) No undo. It wasn't a top priority at the beginning, but I think it's pretty essential for an application that basically contains a text editor to have an undo/redo stack. I'll do it eventually. - - -BACKGROUND ----------- - -The original goal of this project was to make symmetric {en,de}cryption more accessible and easy to use. While GPG rocks if you're comfortable on the commandline (for both symmetric & public-key), and there are GUI encryption options for public-key encryption (seahorse-plugins for nautilus being the best, in my opinion), there's not much out there for people who need to do the simplest kind of encryption -- with a shared passphrase. - -After creating a few simple apps with BASH scripting, I decided it was time to learn Python. After the first few days I was in love. - -Long story short, after a couple weeks of learning, I released my first version of this project in January 2012, quickly added public-key encryption, signing, & verifying, and have been improving it ever since. This being my first learning experience with GTK+, I have lots more to learn, but I'm damn proud of Pyrite. +- No undo. It wasn't a top priority at the beginning, but I think it's pretty essential for an application that basically contains a text editor to have an undo/redo stack. I'll do it eventually. +- Icons for encrypt, decrypt, sign, verify buttons, application +- Update notifications PLEASE contact me (or [post a new issue on the tracker](/ryran/pyrite/issues)) with any suggestions, feedback, bug reports, or questions! -AUTHORS -------- +## AUTHORS As far as direct contributions go, so far it's just me, [ryran](/ryran), aka rsaw, aka [Ryan Sawhill Aroha](http://b19.org). @@ -125,8 +109,7 @@ The project could really use a little assistance from an artist -- it doesn't ha -LICENSE -------- +## LICENSE Copyright (C) 2012, 2013 [Ryan Sawhill Aroha](http://b19.org) @@ -138,19 +121,17 @@ the Free Software Foundation, either version 3 of the License, or This program 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 @[gnu.org/licenses/gpl.html](http://gnu.org/licenses/gpl.html>) for more details. - - +General Public License @[gnu.org/licenses/gpl.html](https://gnu.org/licenses/gpl.html>) for more details. -------- - Hmmmm. You're still here? -Oh. You must be wondering why the name [*Pyrite*](http://en.wikipedia.org/wiki/Pyrite), eh? +Oh. You must be wondering why the name [*Pyrite*](https://en.wikipedia.org/wiki/Pyrite), eh? -Well, I'll let my friend River--who came up with the name--explain it to you: +Well, I'll let my friend River who came up with the name explain it to you: -*"It should be 'Pyrite', because people think they are getting your data, but really it's just gibberish to them. Fool's gold."* +> It should be 'Pyrite', because people think they are getting your data, but really it's just gibberish to them. +> Fool's gold. diff --git a/modules/cfg.py b/modules/cfg.py index 4b9daf7..c481d90 100644 --- a/modules/cfg.py +++ b/modules/cfg.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,28 +15,33 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ -import gtk +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk from os import getenv # Important variables -VERSION = 'v1.0.2' -ASSETDIR = '/usr/share/pyrite/' -USERPREF_FILE = getenv('HOME') + '/.pyrite' -USERPREF_FORMAT_INFO = {'version':'Must6fa'} +VERSION = 'v2.0.0' +ASSETDIR = './' +USERPREF_FILE = getenv('HOME') + '/.pyrite' +USERPREF_FORMAT_INFO = {'version': 'Must6fa'} # List of possible Infobar message types -MSGTYPES = [0, - gtk.MESSAGE_INFO, # 1 - gtk.MESSAGE_QUESTION, # 2 - gtk.MESSAGE_WARNING, # 3 - gtk.MESSAGE_ERROR] # 4 +MSGTYPES = [ + 0, + Gtk.MessageType.INFO, # 1 + Gtk.MessageType.QUESTION, # 2 + Gtk.MessageType.WARNING, # 3 + Gtk.MessageType.ERROR # 4 +] # List of possible images to show in Infobar -IMGTYPES = [gtk.STOCK_APPLY, # 0 - gtk.STOCK_DIALOG_INFO, # 1 - gtk.STOCK_DIALOG_QUESTION, # 2 - gtk.STOCK_DIALOG_WARNING, # 3 - gtk.STOCK_DIALOG_ERROR] # 4 +IMGTYPES = [ + Gtk.STOCK_APPLY, # 0 + Gtk.STOCK_DIALOG_INFO, # 1 + Gtk.STOCK_DIALOG_QUESTION, # 2 + Gtk.STOCK_DIALOG_WARNING, # 3 + Gtk.STOCK_DIALOG_ERROR # 4 +] diff --git a/modules/core.py b/modules/core.py index 2d69fa4..eb33d74 100644 --- a/modules/core.py +++ b/modules/core.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,138 +15,151 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ # StdLib: -import gtk -gtk.gdk.threads_init() +import gi + +gi.require_version('GLib', '2.0') +gi.require_version('Gdk', '3.0') +gi.require_version('Gtk', '3.0') +from gi.repository import GLib +from gi.repository import Gdk +from gi.repository import Gtk +from gi.repository import Pango + +# gtk.gdk.threads_init() import glib -glib.threads_init() +# glib.threads_init() from threading import Thread from sys import stderr -from pango import FontDescription from os import access, R_OK, read, close, pipe from os.path import isfile -from urllib import url2pathname +from urllib.request import url2pathname from shlex import split from subprocess import check_output from time import sleep # Custom Modules: -import cfg -import prefs -import crypt_interface -from messages import MESSAGE_DICT +from . import cfg +from . import prefs +from . import crypt_interface +from .messages import MESSAGE_DICT # Important variables -SIGSTOP, SIGCONT = 19, 18 -TARGET_TYPE_URI_LIST = 80 - +SIGSTOP, SIGCONT = 19, 18 +TARGET_TYPE_URI_LIST = 80 class Pyrite: """Display GTK+ window to interact with gpg or openssl via Xface object.""" - - - def show_errmsg(self, msg, dialog=gtk.MESSAGE_ERROR, parent=None): + + def show_errmsg(self, msg, dialog=Gtk.MessageType.ERROR, parent=None): """Display msg with GtkMessageDialog.""" - d = gtk.MessageDialog( - parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, dialog, - gtk.BUTTONS_OK, msg) + d = Gtk.MessageDialog( + flags=0, + message_type=Gtk.MessageType.ERROR, + buttons=Gtk.ButtonsType.OK, + text=msg + ) d.run() d.destroy() - - + def __init__(self, cmdlineargs): - """Build GUI interface from XML, etc.""" - + """Build GUI interface from XML, etc.""" + self.x = None + self.filemode_saved_buff = None + self.encdec_sig_state_active = False + self.encdec_sig_state_sensitive = False + self.canceled = False + self.paused = False + # Use GtkBuilder to build our GUI from the XML file - builder = gtk.Builder() - try: builder.add_from_file(cfg.ASSETDIR + 'ui/main.glade') + builder = Gtk.Builder() + try: + builder.add_from_file(cfg.ASSETDIR + 'ui/main.glade') except: self.show_errmsg( "Problem loading GtkBuilder UI definition file at:\n " + cfg.ASSETDIR + "ui/main.glade\nCannot continue.") raise - - #--------------------------------------------------------- GET WIDGETS! + + # GET WIDGETS! # Main window - self.g_window = builder.get_object('window1') + self.g_window = builder.get_object('window1') # Toolbars - self.g_maintoolbar = builder.get_object('hbox1') - self.g_modetoolbar = builder.get_object('hbox2') - self.g_enctoolbar = builder.get_object('hbox3') - self.g_sigtoolbar = builder.get_object('hbox4') + self.g_maintoolbar = builder.get_object('hbox1') + self.g_modetoolbar = builder.get_object('hbox2') + self.g_enctoolbar = builder.get_object('hbox3') + self.g_sigtoolbar = builder.get_object('hbox4') # Menu items - self.g_mclear = builder.get_object('mnu_clear') - self.g_mopen = builder.get_object('mnu_open') - self.g_msave = builder.get_object('mnu_save') - self.g_mengine = builder.get_object('mnu_switchengine') - self.g_mcut = builder.get_object('mnu_cut') - self.g_mcopy = builder.get_object('mnu_copy') - self.g_mpaste = builder.get_object('mnu_paste') - self.g_mprefs = builder.get_object('mnu_preferences') - self.g_wrap = builder.get_object('toggle_wordwrap') - self.g_taskstatus = builder.get_object('toggle_taskstatus') - self.g_taskverbose = builder.get_object('toggle_gpgverbose') + self.g_mclear = builder.get_object('mnu_clear') + self.g_mopen = builder.get_object('mnu_open') + self.g_msave = builder.get_object('mnu_save') + self.g_mengine = builder.get_object('mnu_switchengine') + self.g_mcut = builder.get_object('mnu_cut') + self.g_mcopy = builder.get_object('mnu_copy') + self.g_mpaste = builder.get_object('mnu_paste') + self.g_mprefs = builder.get_object('mnu_preferences') + self.g_wrap = builder.get_object('toggle_wordwrap') + self.g_taskstatus = builder.get_object('toggle_taskstatus') + self.g_taskverbose = builder.get_object('toggle_gpgverbose') # Top action toolbar - self.g_encrypt = builder.get_object('btn_encrypt') - self.g_decrypt = builder.get_object('btn_decrypt') - self.g_bclear = builder.get_object('btn_clear') - self.g_progbar = builder.get_object('progressbar') - self.g_cancel = builder.get_object('btn_cancel') - self.g_pause = builder.get_object('btn_pause') - self.g_slider = builder.get_object('opacity_slider') + self.g_encrypt = builder.get_object('btn_encrypt') + self.g_decrypt = builder.get_object('btn_decrypt') + self.g_bclear = builder.get_object('btn_clear') + self.g_progbar = builder.get_object('progressbar') + self.g_cancel = builder.get_object('btn_cancel') + self.g_pause = builder.get_object('btn_pause') + self.g_slider = builder.get_object('opacity_slider') # Mode-setting toolbar - self.g_signverify = builder.get_object('toggle_mode_signverify') - self.g_chk_outfile = builder.get_object('toggle_sign_chooseoutput') - self.g_encdec = builder.get_object('toggle_mode_encdec') - self.g_symmetric = builder.get_object('toggle_mode_symmetric') - self.g_asymmetric = builder.get_object('toggle_mode_asymmetric') - self.g_advanced = builder.get_object('toggle_advanced') + self.g_signverify = builder.get_object('toggle_mode_signverify') + self.g_chk_outfile = builder.get_object('toggle_sign_chooseoutput') + self.g_encdec = builder.get_object('toggle_mode_encdec') + self.g_symmetric = builder.get_object('toggle_mode_symmetric') + self.g_asymmetric = builder.get_object('toggle_mode_asymmetric') + self.g_advanced = builder.get_object('toggle_advanced') # Encryption toolbar - self.g_passlabel = builder.get_object('label_entry_pass') - self.g_pass = builder.get_object('entry_pass') - self.g_reciplabel = builder.get_object('label_entry_recip') - self.g_recip = builder.get_object('entry_recip') - self.g_enctoself = builder.get_object('toggle_enctoself') - self.g_cipherlabel = builder.get_object('label_combobox_cipher') - self.g_cipher = builder.get_object('combobox_cipher') + self.g_passlabel = builder.get_object('label_entry_pass') + self.g_pass = builder.get_object('entry_pass') + self.g_reciplabel = builder.get_object('label_entry_recip') + self.g_recip = builder.get_object('entry_recip') + self.g_enctoself = builder.get_object('toggle_enctoself') + self.g_cipherlabel = builder.get_object('label_combobox_cipher') + self.g_cipher = builder.get_object('combobox_cipher') # Middle input area - self.g_bopen = builder.get_object('btn_open') - self.g_bsave = builder.get_object('btn_save') - self.g_bcopyall = builder.get_object('btn_copyall') - self.g_msgtxtview = builder.get_object('textview1') - self.buff = self.g_msgtxtview.get_buffer() - self.vbox_ibar = builder.get_object('vbox_ibar') - self.vbox_ibar2 = builder.get_object('vbox_ibar2') - self.g_expander = builder.get_object('expander_filemode') - self.g_chooserbtn = builder.get_object('btn_filechooser') - self.g_plaintext = builder.get_object('toggle_plaintext') - self.g_frame2 = builder.get_object('frame2') - self.g_errtxtview = builder.get_object('textview2') - self.buff2 = self.g_errtxtview.get_buffer() + self.g_bopen = builder.get_object('btn_open') + self.g_bsave = builder.get_object('btn_save') + self.g_bcopyall = builder.get_object('btn_copyall') + self.g_msgtxtview = builder.get_object('textview1') + self.buff = self.g_msgtxtview.get_buffer() + self.vbox_ibar = builder.get_object('vbox_ibar') + self.vbox_ibar2 = builder.get_object('vbox_ibar2') + self.g_expander = builder.get_object('expander_filemode') + self.g_chooserbtn = builder.get_object('btn_filechooser') + self.g_plaintext = builder.get_object('toggle_plaintext') + self.g_frame2 = builder.get_object('frame2') + self.g_errtxtview = builder.get_object('textview2') + self.buff2 = self.g_errtxtview.get_buffer() # Signing toolbar - self.g_signature = builder.get_object('toggle_signature') - self.g_sigmode = builder.get_object('combobox_sigmode') - self.g_digestlabel = builder.get_object('label_combobox_digest') - self.g_digest = builder.get_object('combobox_digest') - self.g_chk_defkey = builder.get_object('toggle_defaultkey') - self.g_defaultkey = builder.get_object('entry_defaultkey') + self.g_signature = builder.get_object('toggle_signature') + self.g_sigmode = builder.get_object('combobox_sigmode') + self.g_digestlabel = builder.get_object('label_combobox_digest') + self.g_digest = builder.get_object('combobox_digest') + self.g_chk_defkey = builder.get_object('toggle_defaultkey') + self.g_defaultkey = builder.get_object('entry_defaultkey') # Statusbar - self.g_statusbar = builder.get_object('statusbar') + self.g_statusbar = builder.get_object('statusbar') self.g_activityspin = builder.get_object('spinner1') - + # Set app icon to something halfway-decent - gtk.window_set_default_icon_name(gtk.STOCK_DIALOG_AUTHENTICATION) - + Gtk.Window.set_default_icon_name("dialog-password") + # Connect signals builder.connect_signals(self) - + # Other class attributes - self.ib_filemode = None - self.engine = 'missing_backend' - self.quiting = False + self.ib_filemode = None + self.engine = 'missing_backend' + self.quiting = False self.working_widgets_filemode = [ self.g_mclear, self.g_mprefs, self.g_encrypt, self.g_decrypt, self.g_bclear, self.g_modetoolbar, self.g_enctoolbar, self.g_expander, self.g_sigtoolbar] @@ -160,37 +168,37 @@ def __init__(self, cmdlineargs): self.g_modetoolbar, self.g_enctoolbar, self.g_expander, self.g_sigtoolbar, self.g_mengine, self.g_bcopyall, self.g_bopen, self.g_mopen, self.g_bsave, self.g_msave, self.g_mcut, self.g_mcopy, self.g_mpaste] - + # Initialize main Statusbar self.status = self.g_statusbar.get_context_id('main') self.g_statusbar.push(self.status, "Enter message to encrypt/decrypt") - + # Sensitivity for these GtkEntrys not defaulted to False in xml because # that makes their icons stay insensitive-looking forever - self.g_pass.set_sensitive (False) - self.g_recip.set_sensitive (False) + self.g_pass.set_sensitive(False) + self.g_recip.set_sensitive(False) - #------------------------------ LOAD PREFERENCES AND SET WIDGET STATES! + # LOAD PREFERENCES AND SET WIDGET STATES! self.preferences = prefs.Preferences() - + # Make a clone of preferences dictionary self.p = self.preferences.p - + # Launch gpg/openssl interface if cmdlineargs and cmdlineargs.backend: backend = cmdlineargs.backend else: backend = None - + self.instantiate_xface(preferred=backend, startup=True) - - #------------------------------------------------ DRAG AND DROP FUNNESS - dnd_list = [ ( 'text/uri-list', 0, TARGET_TYPE_URI_LIST ) ] - self.g_msgtxtview.drag_dest_set( - gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT, - dnd_list, gtk.gdk.ACTION_COPY) - - #---------------------------------------------------- CMDLINE ARGUMENTS + + # DRAG AND DROP FUNNESS + dnd_list = [('text/uri-list', 0, TARGET_TYPE_URI_LIST)] + # self.g_msgtxtview.drag_dest_set( + # Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT, + # dnd_list, Gdk.DragAction.COPY) + + # CMDLINE ARGUMENTS if cmdlineargs: a = cmdlineargs @@ -199,15 +207,18 @@ def __init__(self, cmdlineargs): if a.direct_file: self.g_chooserbtn.set_filename(a.input) self.g_expander.set_expanded(True) - elif a.text_input: self.buff.set_text(a.input) - else: self.open_in_txtview(a.input) - + elif a.text_input: + self.buff.set_text(a.input) + else: + self.open_in_txtview(a.input) + if self.engine not in 'OpenSSL': if a.recipients: self.g_recip.set_text(a.recipients) self.g_asymmetric.set_active(True) if a.symmetric: - if a.recipients: self.g_advanced.set_active(True) + if a.recipients: + self.g_advanced.set_active(True) self.g_symmetric.set_active(True) if a.defaultkey: self.g_defaultkey.set_text(a.defaultkey) @@ -216,72 +227,71 @@ def __init__(self, cmdlineargs): self.g_encdec.set_active(True) elif a.signverify: self.g_signverify.set_active(True) - - #--------------------------------------------------- OUR LOVELY COMM DEVICE + + # OUR LOVELY COMM DEVICE def infobar(self, id, filename=None, customtext=None, vbox=None): """Popup a new auto-hiding InfoBar.""" - + # Find the needed dictionary inside our message dict, by id MSG = MESSAGE_DICT[id] - # Use value from MSG type & icon to lookup Gtk constant, e.g. gtk.MESSAGE_INFO - msgtype = cfg.MSGTYPES[ MSG['type'] ] - imgtype = cfg.IMGTYPES[ MSG['icon'] ] + # Use value from MSG type & icon to lookup Gtk constant, e.g. Gtk.MessageType.INFO + msgtype = cfg.MSGTYPES[MSG['type']] + imgtype = cfg.IMGTYPES[MSG['icon']] # Replace variables in message text & change text color message = ("" + MSG['text'].format(filename=filename, customtext=customtext) + "") - + # Now that we have all the data we need, START creating! - ibar = gtk.InfoBar() + ibar = Gtk.InfoBar() ibar.set_message_type(msgtype) if vbox: # If specific vbox requested: assume ibar for filemode, add cancel button - ibar.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) - ibar.connect ('response', self.cleanup_filemode) + ibar.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) + ibar.connect('response', self.cleanup_filemode) else: # If no specific vbox requested: do normal ibar at the top of message area - vbox = self.vbox_ibar - ibar.add_button (gtk.STOCK_OK, gtk.RESPONSE_OK) - ibar.connect ('response', lambda *args: ibar.destroy()) - vbox.pack_end (ibar, False, False) - content = ibar.get_content_area() - img = gtk.Image() - img.set_from_stock (imgtype, gtk.ICON_SIZE_LARGE_TOOLBAR) - content.pack_start (img, False, False) - img.show () - label = gtk.Label() - label.set_markup (message) - content.pack_start (label, False, False) - label.show () + vbox = self.vbox_ibar + ibar.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK) + ibar.connect('response', lambda *args: ibar.destroy()) + vbox.pack_end(ibar, False, False, 0) + content = ibar.get_content_area() + img = Gtk.Image() + img.set_from_stock(imgtype, Gtk.IconSize.LARGE_TOOLBAR) + content.pack_start(img, False, False, 0) + img.show() + label = Gtk.Label() + label.set_markup(message) + content.pack_start(label, False, False, 0) + label.show() # FIXME: Why doesn't Esc trigger this close signal? - ibar.connect ('close', lambda *args: ibar.destroy()) + ibar.connect('close', lambda *args: ibar.destroy()) ibar.show() if MSG['timeout'] > 0: - glib.timeout_add_seconds(MSG['timeout'], ibar.destroy) + GLib.timeout_add_seconds(MSG['timeout'], ibar.destroy) return ibar - - - #----------------------------------------------------- BRING UP GPG/OPENSSL + + # BRING UP GPG/OPENSSL def instantiate_xface(self, preferred=None, startup=False): - """Instantiate Gpg or Openssl interface.""" - - b = ['gpg2', 'gpg', 'openssl'] - # self.p['backend'] contains 0, 1, or 2, corresponding to the above items in b - # Desired: convert the number setting to the human-readable name and store as b - b = b[self.p['backend']] - + """Instantiate Gpg or Openssl interface.""" + # If we weren't passed preferred argument, set desired interface to backend pref - if not preferred: preferred = b - + if not preferred: + b = ['gpg', 'openssl'] + # self.p['backend'] contains 0, 1, or 2, corresponding to the above items in b + # Desired: convert the number setting to the human-readable name and store as b + b = b[self.p['backend']] + preferred = b + # Loading gpg - def gpg(backend_pref=b, fallback=False): - self.x = crypt_interface.Gpg(firstchoice=backend_pref) - self.engine = self.x.GPG_BINARY.upper() + def gpg(fallback=False): + self.x = crypt_interface.Gpg() + self.engine = 'GPG' self.g_mengine.set_label("Use OpenSSL as Engine") if fallback: self.g_mengine.set_sensitive(False) self.infobar('engine_openssl_missing') - + # Loading openssl def openssl(fallback=False): self.x = crypt_interface.Openssl() @@ -292,16 +302,20 @@ def openssl(fallback=False): self.infobar('engine_gpg_missing') else: self.infobar('engine_openssl_notice') - + # Setup for neutered-run (when missing all backends) def err_allmissing(): self.infobar('engine_all_missing') self.g_mengine.set_sensitive(False) - for w in self.g_encrypt, self.g_decrypt: w.set_sensitive(False) - class dummy: pass + for w in self.g_encrypt, self.g_decrypt: + w.set_sensitive(False) + + class dummy: + pass + self.x = dummy() self.x.io = dict(stdin='', stdout='', gstatus=0, infile=0, outfile=0) - + # Get it done! if preferred in 'openssl': # If loading openssl, try that first, then fallback to gpg @@ -321,153 +335,156 @@ class dummy: pass openssl(fallback=True) except: err_allmissing() - + self.g_window.set_title("Pyrite [{}]".format(self.engine)) - + self.buff2.set_text("Any output generated from calls to {} will be " - "displayed here.\n\nIn the View menu you can change " + "displayed here.\n\n" + "In the View menu you can change " "the verbosity level, hide this pane, or simply change " - "the font size.".format(self.engine.lower())) - + "the font size.".format(self.engine)) + self.set_defaults_from_prefs(startup) - - - #--------------------------------------------- SET OPMODES, ETC, FROM PREFS + + # SET OPMODES, ETC, FROM PREFS def set_defaults_from_prefs(self, startup=False): """Set window toggle states via preferences.""" - + if self.p['enctype'] == 0: - self.g_symmetric.set_active (True) + self.g_symmetric.set_active(True) elif self.p['enctype'] == 1: - self.g_asymmetric.set_active (True) + self.g_asymmetric.set_active(True) elif self.p['enctype'] == 2: - self.g_advanced.set_active (True) - self.g_symmetric.set_active (True) - self.g_asymmetric.set_active (True) - + self.g_advanced.set_active(True) + self.g_symmetric.set_active(True) + self.g_asymmetric.set_active(True) + if self.p['advanced']: - self.g_advanced.set_active (True) - + self.g_advanced.set_active(True) + if self.p['advanced'] or self.p['enctype'] > 0: if self.p['addsig']: - self.g_signature.set_active (True) + self.g_signature.set_active(True) if self.p['enctoself']: - self.g_enctoself.set_active (True) - + self.g_enctoself.set_active(True) + if self.p['opmode']: - self.g_signverify.set_active (True) + self.g_signverify.set_active(True) if not self.g_expander.get_expanded(): - self.g_expander.set_expanded (self.p['expander']) - - self.g_cipher.set_active (self.p['cipher']) - self.g_digest.set_active (self.p['digest']) - self.g_chk_defkey.set_active (self.p['defkey']) - self.g_defaultkey.set_text (self.p['defkeytxt']) - + self.g_expander.set_expanded(self.p['expander']) + + self.g_cipher.set_active(self.p['cipher']) + self.g_digest.set_active(self.p['digest']) + self.g_chk_defkey.set_active(self.p['defkey']) + self.g_defaultkey.set_text(self.p['defkeytxt']) + if startup: - self.g_taskstatus.set_active (self.p['taskstatus']) - self.g_taskverbose.set_active (self.p['verbose']) - self.g_wrap.set_active (self.p['wrap']) - + self.g_taskstatus.set_active(self.p['taskstatus']) + self.g_taskverbose.set_active(self.p['verbose']) + self.g_wrap.set_active(self.p['wrap']) + # Set TextView fonts, sizes, and colors self.g_msgtxtview.modify_font( - FontDescription("monospace {}".format(self.p['msgfntsize']))) + Pango.FontDescription("monospace {}".format(self.p['msgfntsize']))) self.g_errtxtview.modify_font( - FontDescription("normal {}".format(self.p['errfntsize']))) + Pango.FontDescription("normal {}".format(self.p['errfntsize']))) + + bg_color = Gdk.Color(0, 0, 0) + bg_color.parse(self.p['color_bg']) + fg_color = Gdk.Color(0, 0, 0) + fg_color.parse(self.p['color_fg']) self.g_msgtxtview.modify_base( - gtk.STATE_NORMAL, gtk.gdk.color_parse(self.p['color_bg'])) + Gtk.StateType.NORMAL, bg_color) self.g_msgtxtview.modify_text( - gtk.STATE_NORMAL, gtk.gdk.color_parse(self.p['color_fg'])) - + Gtk.StateType.NORMAL, fg_color) + if self.p['opc_slider']: - self.g_slider.set_range (0, 100) - self.g_slider.set_value (self.p['opacity']) - self.g_slider.set_tooltip_text ("Change window opacity (current:{}%)".format(self.p['opacity'])) - self.g_slider.set_visible (True) + self.g_slider.set_range(0, 100) + self.g_slider.set_value(self.p['opacity']) + self.g_slider.set_tooltip_text("Change window opacity (current:{}%)".format(self.p['opacity'])) + self.g_slider.set_visible(True) else: - self.g_window.set_opacity(self.p['opacity']/100.0) - + self.g_window.set_opacity(self.p['opacity'] / 100.0) + # These are all the widgets that can't be used in openssl mode def setsensitive_gpgwidgets(x=True): - self.g_signverify.set_sensitive (x) - self.g_symmetric.set_sensitive (x) - self.g_asymmetric.set_sensitive (x) - self.g_advanced.set_sensitive (x) - self.g_chk_defkey.set_sensitive (x) - self.g_taskverbose.set_visible (x) # OpenSSL doesn't have verbosity - + self.g_signverify.set_sensitive(x) + self.g_symmetric.set_sensitive(x) + self.g_asymmetric.set_sensitive(x) + self.g_advanced.set_sensitive(x) + self.g_chk_defkey.set_sensitive(x) + self.g_taskverbose.set_visible(x) # OpenSSL doesn't have verbosity + if self.engine in 'OpenSSL': - self.g_encdec.set_active (True) - self.g_symmetric.set_active (True) - self.g_advanced.set_active (False) - self.g_chk_defkey.set_active (False) + self.g_encdec.set_active(True) + self.g_symmetric.set_active(True) + self.g_advanced.set_active(False) + self.g_chk_defkey.set_active(False) if startup or self.g_cipher.get_active() in {0, 2}: # If starting up, or current cipher set to 'Default' or 'Twofish' if self.p['cipher'] not in {0, 2}: # Set cipher to preference unless pref is 'Default' or 'Twofish' - self.g_cipher.set_active (self.p['cipher']) + self.g_cipher.set_active(self.p['cipher']) else: # Otherwise, set to AES - self.g_cipher.set_active (1) - setsensitive_gpgwidgets (False) + self.g_cipher.set_active(1) + setsensitive_gpgwidgets(False) else: - setsensitive_gpgwidgets (True) - - - #--------------------------------------------------------- HELPER FUNCTIONS - - def fix_msgtxtviewcolor(self, sensitive): + setsensitive_gpgwidgets(True) + + # HELPER FUNCTIONS + + def fix_msgtxtview_color(self, sensitive): """Change Message area text to black when TextView insensitive.""" if sensitive: + fg_color = Gdk.Color(0, 0, 0) + fg_color.parse(self.p['color_fg']) self.g_msgtxtview.modify_text( - gtk.STATE_NORMAL, gtk.gdk.color_parse(self.p['color_fg'])) + Gtk.StateType.NORMAL, fg_color) else: + fg_color = Gdk.Color(0, 0, 0) + fg_color.parse('black') self.g_msgtxtview.modify_text( - gtk.STATE_NORMAL, gtk.gdk.color_parse('black')) - - + Gtk.StateType.NORMAL, fg_color) + def get_file_path_from_dnd_dropped_uri(self, uri): path = '' - if uri.startswith('file:\\\\\\'): # windows + if uri.startswith('file:\\\\\\'): # windows path = uri[8:] # 8 is len('file:///') - elif uri.startswith('file://'): # nautilus, rox + elif uri.startswith('file://'): # nautilus, rox path = uri[7:] # 7 is len('file://') - elif uri.startswith('file:'): # xffm + elif uri.startswith('file:'): # xffm path = uri[5:] # 5 is len('file:') path = url2pathname(path) # escape special chars path = path.strip('\r\n\x00') # remove \r\n and NULL return path - - + def set_stdstatus(self): - """Set a standard mode-depenedent status message.""" + """Set a standard mode-dependent status message.""" self.g_statusbar.pop(self.status) if self.g_signverify.get_active(): s = "Enter message to sign or verify" else: s = "Enter message to encrypt or decrypt" self.g_statusbar.push(self.status, s) - - - def test_file_isbinary(self, filename): + + def test_file_is_plain_text(self, filename): """Utilize nix file cmd to determine if filename is binary or text.""" cmd = split("file -b -e soft '{}'".format(filename)) - if check_output(cmd)[:4] in {'ASCI', 'UTF-'}: - return False - return True - - + output = check_output(cmd) + return output[:4] in (b'ASCI', b'UTF-') + def open_in_txtview(self, filename): """Replace contents of msg TextView's TextBuffer with contents of file.""" try: - with open(filename) as f: self.buff.set_text(f.read()) + with open(filename) as f: + self.buff.set_text(f.read()) if self.buff.get_char_count() < 1: self.infobar('txtview_fileopen_binary_error') except: self.infobar('txtview_fileopen_error', filename) - - + # This is called when entering & exiting direct-file mode def filemode_enablewidgets(self, x=True): """Enable/disable certain widgets due to working in direct-file mode.""" @@ -476,17 +493,15 @@ def filemode_enablewidgets(self, x=True): self.g_mpaste, self.g_msgtxtview] for w in widgets: w.set_sensitive(x) - self.fix_msgtxtviewcolor(x) - - + self.fix_msgtxtview_color(x) + # This is called when user tries to copyall, save, or {en,de}crypt/sign/verify def test_msgbuff_isempty(self, message): """Return True + show infobar containing msg if Message area is empty.""" if self.buff.get_char_count() < 1: self.infobar('txtview_empty', customtext=message) return True - - + def confirm_overwrite_callback(self, chooser): """In filechooser, disallow output file being the input file.""" outfile = chooser.get_filename() @@ -494,41 +509,46 @@ def confirm_overwrite_callback(self, chooser): self.show_errmsg( "Simultaneously reading from & writing to a file is a baaad idea. " "Choose a different output filename.", parent=chooser) - return gtk.FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN + return Gtk.FileChooserConfirmation.SELECT_AGAIN else: - return gtk.FILE_CHOOSER_CONFIRMATION_CONFIRM - - + return Gtk.FileChooserConfirmation.CONFIRM + # Generic file chooser for opening or saving def chooser_grab_filename(self, mode, save_suggestion=None): """Present file chooser dialog and return filename or None.""" - + filename = None - if mode in 'open': title = "Choose text file to open as input..." - elif mode in 'save': title = "Choose output filename..." - cmd = ("gtk.FileChooserDialog('{0}', None, gtk.FILE_CHOOSER_ACTION_{1}, " - "(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))" + if mode in 'open': + title = "Choose text file to open as input..." + elif mode in 'save': + title = "Choose output filename..." + cmd = ("Gtk.FileChooserDialog('{0}', None, Gtk.FileChooserAction.{1}, " + "(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))" .format(title, mode.upper())) chooser = eval(cmd) - + if mode in 'open': # Setup file filters - t = gtk.FileFilter() ; t.set_name("Text Files") ; t.add_mime_type("text/*") - a = gtk.FileFilter() ; a.set_name("All Files") ; a.add_pattern("*") + t = Gtk.FileFilter() + t.set_name("Text Files") + t.add_mime_type("text/*") + a = Gtk.FileFilter() + a.set_name("All Files") + a.add_pattern("*") chooser.add_filter(t) chooser.add_filter(a) elif mode in 'save': # Setup overwrite-confirmation cb + current filename chooser.set_do_overwrite_confirmation(True) chooser.connect('confirm-overwrite', self.confirm_overwrite_callback) - if save_suggestion: chooser.set_current_name(save_suggestion) - - if chooser.run() == gtk.RESPONSE_OK: + if save_suggestion: + chooser.set_current_name(save_suggestion) + + if chooser.run() == Gtk.ResponseType.OK: filename = chooser.get_filename() chooser.destroy() return filename - - + def grab_activetext_combobox(self, combobox): """Return the text of active combobox selection.""" cbmodel = combobox.get_model() @@ -537,72 +557,65 @@ def grab_activetext_combobox(self, combobox): return None # If first choice is selected, i.e. 'Default' else: return cbmodel[cbindex][0] - - + # This is called by encrypt/decrypt buttons when operating in direct-file mode def filemode_get_outfile(self, mode): """Use FileChooser to get an output filename for direct enc/dec.""" - + # Prompt for output file outfile = self.chooser_grab_filename('save', self.x.io['infile']) - + # Kick off processing unless user canceled if outfile: self.x.io['outfile'] = outfile self.launchxface(mode) - - + def initiate_filemode(self): - """Ensure read access of file set by chooserwidget and notify user of next steps.""" - + """Ensure read access of file set by chooser widget and notify user of next steps.""" + # Prompt for filename but err out if file can't be read infile = self.g_chooserbtn.get_filename() if not access(infile, R_OK): self.infobar('filemode_fileopen_error', infile) return - + # Tweak some widgets if in Sign/Verify mode if self.g_signverify.get_active(): - self.g_chk_outfile.set_visible (True) - self.g_chk_outfile.set_active (self.p['svoutfiles']) - self.g_sigmode.set_active (self.p['file_sigmode']) - + self.g_chk_outfile.set_visible(True) + self.g_chk_outfile.set_active(self.p['svoutfiles']) + self.g_sigmode.set_active(self.p['file_sigmode']) + # Configure state of plaintext output checkbox via user-settings - self.g_plaintext.set_sensitive (True) - + self.g_plaintext.set_sensitive(True) + if self.p['txtoutput'] == 0: # Autodetect - if self.test_file_isbinary(infile): - self.g_plaintext.set_active (False) - else: - self.g_plaintext.set_active (True) - + self.g_plaintext.set_active(self.test_file_is_plain_text(infile)) elif self.p['txtoutput'] == 1: # Always Binary - self.g_plaintext.set_active (False) - + self.g_plaintext.set_active(False) elif self.p['txtoutput'] == 2: # Always Text - self.g_plaintext.set_active (True) - + self.g_plaintext.set_active(True) + # Set statusbar w/ filemode status self.g_statusbar.pop(self.status) self.g_statusbar.push(self.status, "Choose an action to perform on {!r}".format(infile)) - + if self.ib_filemode: # If filemode infobar already present: user picked a new file, so destroy old ibar self.ib_filemode.destroy() else: # Otherwise, save TextView buffer for later and then blow it away self.filemode_saved_buff = self.buff.get_text(self.buff.get_start_iter(), - self.buff.get_end_iter()) + self.buff.get_end_iter(), + False) self.buff.set_text('') self.filemode_enablewidgets(False) - + # Create filemode infobar with cancel button self.ib_filemode = self.infobar('filemode_blue_banner', infile, vbox=self.vbox_ibar2) - + # Set input file self.x.io['infile'] = infile - - + def cleanup_filemode(self, *args): """Revert the changes (to widgets, etc) that filemode causes.""" # Restore message buffer @@ -612,40 +625,38 @@ def cleanup_filemode(self, *args): self.ib_filemode.destroy() self.ib_filemode = None # Enable/sensitize widgets - self.filemode_enablewidgets (True) - self.g_chk_outfile.set_visible (False) + self.filemode_enablewidgets(True) + self.g_chk_outfile.set_visible(False) # Ensure sigmode combobox is back to proper 'normal' if self.g_signverify.get_active(): - self.g_sigmode.set_active (self.p['text_sigmode']) + self.g_sigmode.set_active(self.p['text_sigmode']) else: - self.g_sigmode.set_active (0) + self.g_sigmode.set_active(0) # Set statusbar self.set_stdstatus() - #while gtk.events_pending(): - gtk.main_iteration() + # while Gtk.events_pending(): + Gtk.main_iteration() # Reset filenames self.x.io['infile'] = 0 self.x.io['outfile'] = 0 # Disable plaintext CheckButton - self.g_plaintext.set_sensitive (False) - self.g_plaintext.set_active (True) - - - #--------------------------------------------------- HERE BE GTK SIGNAL CBs - + self.g_plaintext.set_sensitive(False) + self.g_plaintext.set_active(True) + + # HERE BE GTK SIGNAL CBs + # Called by window destroy / Quit menu item def action_quit(self, w): """Shutdown application and any child process.""" self.quiting = True - if self.x.childprocess and self.x.childprocess.returncode == None: + if self.x.childprocess and self.x.childprocess.returncode is None: if self.paused: self.x.childprocess.send_signal(SIGCONT) self.x.childprocess.terminate() stderr.write("\n") - #sleep(0.2) - gtk.main_quit() - - + # sleep(0.2) + Gtk.main_quit() + # Called when dnd occurs on Message TextView def action_drag_data_received(self, w, context, x, y, selection, target_type, timestamp): """Read dragged text file into Message area.""" @@ -655,17 +666,15 @@ def action_drag_data_received(self, w, context, x, y, selection, target_type, ti path = self.get_file_path_from_dnd_dropped_uri(uri) if isfile(path): self.open_in_txtview(path) - - + # Called by changing opacity hscale def action_opacity_slider(self, w): """Actions to perform when opacity scale is changed.""" val = w.get_value() - self.g_window.set_opacity(val/100.0) + self.g_window.set_opacity(val / 100.0) w.set_tooltip_text( "Change window opacity (current:{:.1f}%)".format(val)) - - + # Called by SwitchEngine menu item def action_switch_engine(self, w): """Switch backend between openssl & gpg.""" @@ -673,28 +682,26 @@ def action_switch_engine(self, w): self.instantiate_xface('gpg') else: self.instantiate_xface('openssl') - - + # Called by About menu item def action_about(self, w): """Launch About dialog.""" - builder = gtk.Builder() - builder.add_from_file(cfg.ASSETDIR + 'ui/about.glade') + builder = Gtk.Builder() + builder.add_from_file(cfg.ASSETDIR + 'ui/about.glade') about = builder.get_object('aboutdialog') - about.set_logo_icon_name(gtk.STOCK_DIALOG_AUTHENTICATION) - about.set_transient_for(self.g_window) + about.set_logo_icon_name(Gtk.STOCK_DIALOG_AUTHENTICATION) + # about.set_transient_for(self.g_window) about.set_version(cfg.VERSION) about.connect('response', lambda *args: about.destroy()) about.show() - - + # Called by Preferences menu item def action_preferences(self, w): """Launch preferences window.""" - + # Run preferences window method from already-open pref instance self.preferences.open_preferences_window(parentwindow=self.g_window) - + # CB for pref window's save button def savepref(*args): # Attempt to save preferences @@ -702,7 +709,7 @@ def savepref(*args): # If success: destroy pref window, show infobar self.preferences.window.destroy() self.infobar('preferences_save_success', cfg.USERPREF_FILE) - + # CB for pref window's apply button def applypref(*args): # Attempt to save preferences @@ -710,15 +717,15 @@ def applypref(*args): # If success, destroy pref window, import new prefs, show infobar self.preferences.window.destroy() self.p = self.preferences.p - if self.x.io['infile']: self.cleanup_filemode() + if self.x.io['infile']: + self.cleanup_filemode() self.instantiate_xface(startup=True) self.infobar('preferences_apply_success', cfg.USERPREF_FILE) - + # Connect signals - self.preferences.btn_save.connect ('clicked', savepref) - self.preferences.btn_apply.connect ('clicked', applypref) - - + self.preferences.btn_save.connect('clicked', savepref) + self.preferences.btn_apply.connect('clicked', applypref) + # Called by Clear toolbar btn or menu item def action_clear(self, w): """Reset Statusbar, filemode stuff, TextView buffers.""" @@ -726,91 +733,83 @@ def action_clear(self, w): self.cleanup_filemode() else: self.set_stdstatus() - self.buff.set_text ('') - self.buff2.set_text ('') + self.buff.set_text('') + self.buff2.set_text('') self.x.io = dict(stdin='', stdout='', gstatus=0, infile=0, outfile=0) - - + # Called when user clicks the entry_icon in any of the entry widgets def action_clear_entry(self, entry, *args): """Clear TextEntry widget.""" entry.set_text('') - - + # Called by Open toolbar btn or menu item def action_open(self, w): """Read in a text file and push its contents to our TextView.""" filename = self.chooser_grab_filename('open') if filename: self.open_in_txtview(filename) - - + # Called when direct-file-mode FileChooserButton gets a new file set, # either because of dnd or manual selection def action_chooserbtn_file_set(self, w): - print "[on_file-set] FileChooserButton.get_filename() output:\n{!r}\n".format(w.get_filename()) + print("[on_file-set] FileChooserButton.get_filename() output:\n{!r}\n".format(w.get_filename())) self.initiate_filemode() - - + # Called by Save toolbar btn or menu item def action_save(self, w): """Save contents of msg TextView's TextBuffer to file.""" - + # If Message area is empty, err out if self.test_msgbuff_isempty("No text to save."): return - + # Prompt for filename to save to; cancel if user cancels filename = self.chooser_grab_filename('save') if not filename: return - + # Set saving status self.g_statusbar.push(self.status, "Saving {}".format(filename)) - #while gtk.events_pending(): - gtk.main_iteration() - + # while Gtk.events_pending(): + Gtk.main_iteration() + # Grab text from buffer buffertext = self.buff.get_text(self.buff.get_start_iter(), - self.buff.get_end_iter()) + self.buff.get_end_iter(), + False) try: # If can open file for writing, show success infobar - with open(filename, 'w') as f: f.write(buffertext) + with open(filename, 'w') as f: + f.write(buffertext) self.infobar('txtview_save_success', filename) except: # Otherwise, show error self.infobar('txtview_save_error', filename) - + # Clear saving status self.g_statusbar.pop(self.status) - - + def action_undo(self, w): pass - - + def action_redo(self, w): pass - - + # Called by Cut toolbar btn or menu item def action_cut(self, w): """Cut msg TextBuffer selection.""" - self.buff.cut_clipboard(gtk.clipboard_get(), True) - - + self.buff.cut_clipboard(Gtk.clipboard_get(), True) + # Called by Copy toolbar btn or menu item def action_copy(self, w): """Copy msg TextBuffer selection.""" - self.buff.copy_clipboard(gtk.clipboard_get()) - - + self.buff.copy_clipboard(Gtk.clipboard_get()) + # Called by Paste toolbar btn or menu item def action_paste(self, w): """Paste clipboard into msg TextBuffer at selection.""" - self.buff.paste_clipboard(gtk.clipboard_get(), None, True) - - + self.buff.paste_clipboard(Gtk.clipboard_get(), None, True) + # Called by Copyall toolbar btn def action_copyall(self, w): """Select whole msg TextBuffer contents and copy it to clipboard.""" @@ -818,10 +817,9 @@ def action_copyall(self, w): return self.buff.select_range(self.buff.get_start_iter(), self.buff.get_end_iter()) - self.buff.copy_clipboard(gtk.clipboard_get()) + self.buff.copy_clipboard(Gtk.clipboard_get()) self.infobar('txtview_copyall_success') - - + # Called by Zoom menu items def action_zoom(self, w): """Increase/decrease font size of TextViews.""" @@ -833,11 +831,10 @@ def action_zoom(self, w): self.p['msgfntsize'] -= 1 self.p['errfntsize'] -= 1 self.g_msgtxtview.modify_font( - FontDescription("monospace {}".format(self.p['msgfntsize']))) + Pango.FontDescription("monospace {}".format(self.p['msgfntsize']))) self.g_errtxtview.modify_font( - FontDescription("normal {}".format(self.p['errfntsize']))) - - + Pango.FontDescription("normal {}".format(self.p['errfntsize']))) + # Called when Cipher combobox selection is changed def action_cipher_changed(self, w): """Disallow certain cipher selections in OpenSSL mode.""" @@ -851,16 +848,10 @@ def action_cipher_changed(self, w): self.infobar('cipher_openssl_no_twofish') elif cipher in 'AES': self.infobar('cipher_openssl_aes_note') - - + # Called by Encrypt/Sign toolbar btn def action_encrypt(self, w): """Encrypt or sign input.""" - # DEBUG - #self.g_chooserbtn.select_filename('/etc/passwd') - #self.g_expander.set_expanded(True) - #gtk.main_iteration() - #return if self.g_signverify.get_active(): # If in sign-only mode, figure out which sig-type if self.g_sigmode.get_active() == 0: @@ -873,8 +864,7 @@ def action_encrypt(self, w): else: # Normal enc/dec mode self.launchxface('enc') - - + # Called by Decrypt/Verify toolbar btn def action_decrypt(self, w): """Decrypt or verify input.""" @@ -884,232 +874,222 @@ def action_decrypt(self, w): else: # Normal enc/dec mode self.launchxface('dec') - - + # Called by Symmetric checkbox toggle def action_toggle_symmetric(self, w): """Toggle symmetric encryption (enable/disable certain widgets).""" - + symm_widgets = [self.g_passlabel, self.g_pass] - + if w.get_active(): # If entering toggled state, allow pass entry for widget in symm_widgets: - widget.set_sensitive (True) + widget.set_sensitive(True) if not self.g_advanced.get_active(): # If not in advanced mode, disable Asymmetric - self.g_asymmetric.set_active (False) - + self.g_asymmetric.set_active(False) + else: # If leaving toggled state, hide pass entry for widget in symm_widgets: - widget.set_sensitive (False) + widget.set_sensitive(False) if not self.g_asymmetric.get_active(): # If unchecking Symm & Asymm isn't already on, turn it on - self.g_asymmetric.set_active (True) - - + self.g_asymmetric.set_active(True) + # Called by Asymmetric checkbox toggle def action_toggle_asymmetric(self, w): """Toggle asymmetric encryption (enable/disable certain widgets).""" - + asymm_widgets = [self.g_reciplabel, self.g_recip, self.g_enctoself] - + if w.get_active(): # If entering toggled state, allow recip entry, enctoself for widget in asymm_widgets: - widget.set_sensitive (True) - self.g_signature.set_sensitive (True) + widget.set_sensitive(True) + self.g_signature.set_sensitive(True) if not self.g_advanced.get_active(): # If not in advanced mode, disable Symmetric - self.g_symmetric.set_active (False) - + self.g_symmetric.set_active(False) + self.load_recipients_autocmplete() else: # If leaving toggled state, hide recip entry, enctoself for widget in asymm_widgets: - widget.set_sensitive (False) - self.g_enctoself.set_active (False) + widget.set_sensitive(False) + self.g_enctoself.set_active(False) if not self.g_advanced.get_active(): # If not in advanced mode, ensure add signature is unchecked - self.g_signature.set_sensitive (False) - self.g_signature.set_active (False) + self.g_signature.set_sensitive(False) + self.g_signature.set_active(False) if not self.g_symmetric.get_active(): # If unchecking Asymm & Symm isn't already on, turn it on - self.g_symmetric.set_active (True) - - + self.g_symmetric.set_active(True) + # Called by Advanced checkbox toggle def action_toggle_advanced(self, w): """Enable/disable encryption widgets for advanced mode.""" - + if w.get_active(): # If entering the toggled state, allow adding signature - self.g_signature.set_sensitive (True) - + self.g_signature.set_sensitive(True) + else: # If leaving the toggled state... if self.g_symmetric.get_active(): # We have some things to do if Symmetric is checked... if self.g_asymmetric.get_active(): # If Asymmetric is also checked, disable it - self.g_asymmetric.set_active (False) + self.g_asymmetric.set_active(False) else: # If Asymmetric isn't checked, ensure addsig is disabled - self.g_signature.set_sensitive (False) - self.g_signature.set_active (False) - - + self.g_signature.set_sensitive(False) + self.g_signature.set_active(False) + # Called by Sign/Verify radio toggle def action_toggle_mode_signverify(self, w): """Hide/show, change some widgets when switching modes.""" - + enc_widgets = [self.g_symmetric, self.g_asymmetric, self.g_advanced, self.g_enctoolbar] - + # Change statusbar self.set_stdstatus() - + if w.get_active(): # If entering the toggled state: modify buttons, hide & show widgets # Modify Encrypt/Decrypt button labels - self.g_encrypt.set_label ("Sign") - self.g_decrypt.set_label ("Verify") + self.g_encrypt.set_label("Sign") + self.g_decrypt.set_label("Verify") # Hide encryption toolbar & Symmetric, Asymmetric, Adv toggles for widget in enc_widgets: - widget.set_visible (False) + widget.set_visible(False) # Save state of AddSignature for switching back to Enc/Dec mode self.encdec_sig_state_sensitive = self.g_signature.get_sensitive() - self.encdec_sig_state_active = self.g_signature.get_active() + self.encdec_sig_state_active = self.g_signature.get_active() # Desensitize AddSignature checkbox and turn it on - self.g_signature.set_sensitive (False) - self.g_signature.set_active (True) + self.g_signature.set_sensitive(False) + self.g_signature.set_active(True) # Sensitize sigmode combobox - self.g_sigmode.set_sensitive (True) + self.g_sigmode.set_sensitive(True) # Set sigmode combobox via user prefs if self.x.io['infile']: - self.g_sigmode.set_active (self.p['file_sigmode']) - self.g_chk_outfile.set_visible (True) + self.g_sigmode.set_active(self.p['file_sigmode']) + self.g_chk_outfile.set_visible(True) else: - self.g_sigmode.set_active (self.p['text_sigmode']) - + self.g_sigmode.set_active(self.p['text_sigmode']) + else: # If leaving the toggled state, we have some things to reverse - self.g_encrypt.set_label ("_Encrypt") - self.g_decrypt.set_label ("_Decrypt") - self.g_chk_outfile.set_visible (False) + self.g_encrypt.set_label("_Encrypt") + self.g_decrypt.set_label("_Decrypt") + self.g_chk_outfile.set_visible(False) for widget in enc_widgets: - widget.set_visible (True) - self.g_signature.set_sensitive (self.encdec_sig_state_sensitive) - self.g_signature.set_active (self.encdec_sig_state_active) - self.g_sigmode.set_sensitive (False) - self.g_sigmode.set_active (0) # Reset to 'Embedded' type for Enc/Dec mode - - + widget.set_visible(True) + self.g_signature.set_sensitive(self.encdec_sig_state_sensitive) + self.g_signature.set_active(self.encdec_sig_state_active) + self.g_sigmode.set_sensitive(False) + self.g_sigmode.set_active(0) # Reset to 'Embedded' type for Enc/Dec mode + # Called by 'Change Default Key' checkbox toggle def action_toggle_defaultkey(self, w): """Hide/show Entry widget for setting gpg 'localuser' argument.""" - + if w.get_active(): # If entering toggled state, show default key TextEntry - self.g_defaultkey.set_visible (True) + self.g_defaultkey.set_visible(True) else: # If leaving toggled state, hide default key TextEntry - self.g_defaultkey.set_visible (False) - - + self.g_defaultkey.set_visible(False) + # Called by 'Add Signature' checkbox toggle def action_toggle_signature(self, w): """Hide/show some widgets when toggling adding of a signature to input.""" sig_widgets = [self.g_sigmode, self.g_digest, self.g_digestlabel] - + if w.get_active(): # If entering toggled state, show sig toolbar widgets for widget in sig_widgets: - widget.set_visible (True) + widget.set_visible(True) else: # If leaving toggled state, hide sig toolbar widgets for widget in sig_widgets: - widget.set_visible (False) - - + widget.set_visible(False) + # Called by 'Task Status Side Panel' checkbox toggle def action_toggle_taskstatus(self, w): """Show/hide side pane containing gpg stderr output.""" if w.get_active(): # If entering toggled state, show Task Status TextView frame - self.g_frame2.set_visible (True) + self.g_frame2.set_visible(True) else: # If leaving toggled state, hide Task Status TextView frame - self.g_frame2.set_visible (False) - - + self.g_frame2.set_visible(False) + # Called by 'Text Wrapping' checkbox toggle def action_toggle_wordwrap(self, w): """Toggle word wrapping for main message TextView.""" if w.get_active(): # If entering toggled state, enable word wrapping - self.g_msgtxtview.set_wrap_mode(gtk.WRAP_WORD) + self.g_msgtxtview.set_wrap_mode(Gtk.WrapMode.WORD) else: # If leaving toggled state, disable word wrapping - self.g_msgtxtview.set_wrap_mode(gtk.WRAP_NONE) - - + self.g_msgtxtview.set_wrap_mode(Gtk.WrapMode.NONE) + # Called by [processing progbar] Cancel button def action_cancel_child_process(self, btn): """Terminate gpg/openssl subprocess.""" - - stderr.write ("Canceling Operation\n") - self.canceled = True + + stderr.write("Canceling Operation\n") + self.canceled = True for w in self.g_cancel, self.g_pause: - w.set_sensitive (False) - self.g_progbar.set_text ("Canceling Operation...") + w.set_sensitive(False) + self.g_progbar.set_text("Canceling Operation...") self.g_activityspin.stop() - gtk.main_iteration() + Gtk.main_iteration() while not self.x.childprocess: - gtk.main_iteration() + Gtk.main_iteration() if self.paused: self.x.childprocess.send_signal(SIGCONT) self.x.childprocess.terminate() self.show_working_progress(False) - - + # Called by [processing progbar] Pause button def action_pause_child_process(self, btn): """Suspend/resume gpg/openssl subprocess with SIGSTOP/SIGCONT.""" - + # We can't pause childprocess until it actually starts while not self.x.childprocess: - gtk.main_iteration() - + Gtk.main_iteration() + if self.paused: # Already paused, so, time to unpause - stderr.write ("\n") - self.paused = False - btn.set_relief (gtk.RELIEF_NONE) - self.g_progbar.set_text ("{} working...".format(self.engine)) + stderr.write("\n") + self.paused = False + btn.set_relief(Gtk.ReliefStyle.NONE) + self.g_progbar.set_text("{} working...".format(self.engine)) self.g_activityspin.start() self.x.childprocess.send_signal(SIGCONT) else: # Time to pause - stderr.write ("\n") - self.paused = True - btn.set_relief (gtk.RELIEF_NORMAL) - self.g_progbar.set_text ("Operation PAUSED") + stderr.write("\n") + self.paused = True + btn.set_relief(Gtk.ReliefStyle.NORMAL) + self.g_progbar.set_text("Operation PAUSED") self.g_activityspin.stop() self.x.childprocess.send_signal(SIGSTOP) - - - #------------------------------------------------------ MAIN XFACE FUNCTION + + # MAIN XFACE FUNCTION def launchxface(self, action): """Manage I/O between Gtk objects and our GpgXface or OpensslXface object.""" - self.canceled = False - self.paused = False + # User Canceled + self.canceled = False + self.paused = False self.x.childprocess = None - - ### PREPARE Xface ARGS - passwd = None - recip = None - localuser = None + + # PREPARE Xface ARGS + passwd = None + recip = None + localuser = None # symmetric & passwd symmetric = self.g_symmetric.get_active() if symmetric: @@ -1119,7 +1099,7 @@ def launchxface(self, action): self.infobar('x_missing_passphrase') return passwd = None # If passwd was '' , set to None, which will trigger gpg-agent if necessary - + # INTERLUDE: If operating in textinput mode, check for input text if not self.x.io['infile']: # Make sure textview has a proper message in it @@ -1127,15 +1107,16 @@ def launchxface(self, action): return False # Make TextView immutable to changes self.g_msgtxtview.set_sensitive(False) - self.fix_msgtxtviewcolor(False) - + self.fix_msgtxtview_color(False) + # enctoself enctoself = self.g_enctoself.get_active() # recip asymmetric = self.g_asymmetric.get_active() if asymmetric: recip = self.g_recip.get_text() - if not recip: recip = None # If recip was '' , set to None + if not recip: + recip = None # If recip was '' , set to None # cipher, base64 cipher = self.grab_activetext_combobox(self.g_cipher) base64 = self.g_plaintext.get_active() @@ -1154,11 +1135,11 @@ def launchxface(self, action): # localuser if self.g_chk_defkey.get_active(): localuser = self.g_defaultkey.get_text() - if not localuser: localuser = None - + if not localuser: + localuser = None + # INITIAL FILE INPUT MODE PREP if self.x.io['infile'] and not self.x.io['outfile']: - if base64 or action in 'clearsign': outfile = self.x.io['infile'] + '.asc' elif self.engine in 'OpenSSL': @@ -1167,10 +1148,10 @@ def launchxface(self, action): outfile = self.x.io['infile'] + '.sig' else: outfile = self.x.io['infile'] + '.gpg' - + if action in 'dec': outfile = self.x.io['infile'][:-4] - + if action not in 'verify': if self.g_signverify.get_active() and not self.g_chk_outfile.get_active(): pass @@ -1182,113 +1163,103 @@ def launchxface(self, action): return working_widgets = self.working_widgets_filemode - for w in working_widgets: w.set_sensitive(False) + for w in working_widgets: + w.set_sensitive(False) self.ib_filemode.hide() - + # FILE INPUT MODE PREP WHEN ALREADY HAVE OUTPUT FILE elif self.x.io['infile'] and self.x.io['outfile']: - working_widgets = self.working_widgets_filemode - for w in working_widgets: w.set_sensitive(False) + for w in working_widgets: + w.set_sensitive(False) self.ib_filemode.hide() - + # TEXT INPUT MODE PREP else: - working_widgets = self.working_widgets_textmode - for w in working_widgets: w.set_sensitive(False) - + for w in working_widgets: + w.set_sensitive(False) # Save textview buffer to Xface stdin self.x.io['stdin'] = self.buff.get_text(self.buff.get_start_iter(), - self.buff.get_end_iter()) - + self.buff.get_end_iter(), + False) + # Set working status + spinner + progress bar self.show_working_progress(True, action) # Clear Task Status self.buff2.set_text('') - + # Setup stderr file descriptors & update task status while processing self.x.io['stderr'] = pipe() - glib.io_add_watch( + GLib.io_add_watch( self.x.io['stderr'][0], - glib.IO_IN | glib.IO_HUP, + GLib.IOCondition.IN | GLib.IOCondition.HUP, self.update_task_status) - + if self.engine in 'OpenSSL': # ATTEMPT EN-/DECRYPTION w/OPENSSL Thread( target=self.x.openssl, args=(action, passwd, base64, cipher) - ).start() - + ).start() + else: # GPG if verbose: # Setup gpg-status file descriptors & update terminal while processing self.x.io['gstatus'] = pipe() - glib.io_add_watch( + GLib.io_add_watch( self.x.io['gstatus'][0], - glib.IO_IN | glib.IO_HUP, + GLib.IOCondition.IN | GLib.IOCondition.HUP, self.update_task_status, 'term') # ATTEMPT EN-/DECRYPTION w/GPG Thread( target=self.x.gpg, args=(action, encsign, digest, localuser, base64, symmetric, passwd, asymmetric, recip, enctoself, cipher, verbose, alwaystrust) - ).start() - + ).start() + # Wait for subprocess to finish or for Cancel button to be clicked c = 0 - while not self.x.childprocess or self.x.childprocess.returncode == None: - if self.canceled: break + while not self.x.childprocess or self.x.childprocess.returncode is None: + if self.canceled: + break if c % 15 == 0 and not self.paused: self.g_progbar.pulse() - gtk.main_iteration() + Gtk.main_iteration() c += 1 if self.quiting: # If application is shutting down return # Restore widgets to normal states - for w in working_widgets: w.set_sensitive(True) + for w in working_widgets: + w.set_sensitive(True) self.show_working_progress(False) - + # FILE INPUT MODE CLEANUP if self.x.io['infile']: - if self.canceled: # User Canceled! - self.ib_filemode.show() - if action in {'enc', 'dec'}: action = "{}rypt".format(action.title()) elif action in {'embedsign', 'clearsign', 'detachsign'}: action = "Sign" elif action in 'verify': action = action.title() - self.infobar('x_canceled_filemode', customtext=action) - elif self.x.childprocess.returncode == 0: # File Success! - if self.engine in 'OpenSSL' and action in 'enc': self.infobar('x_opensslenc_success_filemode', self.x.io['outfile'], cipher) - elif action in {'enc', 'dec'}: self.infobar('x_crypt_success_filemode', self.x.io['outfile'], action) - elif action in {'embedsign', 'clearsign'}: self.infobar('x_sign_success_filemode', self.x.io['outfile']) - elif action in 'detachsign': self.infobar('x_detachsign_success_filemode', self.x.io['outfile']) - elif action in 'verify': self.infobar('x_verify_success') - self.cleanup_filemode() - else: # File Fail! - self.ib_filemode.show() if action in 'verify': self.infobar('x_verify_failed') @@ -1301,38 +1272,31 @@ def launchxface(self, action): elif action in {'embedsign', 'clearsign', 'detachsign'}: action = 'sign' self.infobar('x_generic_failed_filemode', customtext=action) - + # TEXT INPUT MODE CLEANUP else: - self.set_stdstatus() self.g_msgtxtview.set_sensitive(True) - self.fix_msgtxtviewcolor(True) - + self.fix_msgtxtview_color(True) if self.canceled: # User Canceled! - if action in {'enc', 'dec'}: action = "{}rypt".format(action.title()) elif action in {'embedsign', 'clearsign', 'detachsign'}: action = "Sign" elif action in 'verify': action = action.title() - self.infobar('x_canceled_textmode', customtext=action) - elif self.x.childprocess.returncode == 0: # Text Success! - if action in 'verify': self.infobar('x_verify_success') else: # Set TextBuffer to gpg stdout - self.buff.set_text(self.x.io['stdout']) + b = self.x.io['stdout'].decode('utf-8') + self.buff.set_text(b) self.x.io['stdout'] = 0 if self.engine in 'OpenSSL' and action in 'enc': self.infobar('x_opensslenc_success_textmode', customtext=cipher) - else: # Text Fail! - if action in 'verify': self.infobar('x_verify_failed') return @@ -1344,43 +1308,41 @@ def launchxface(self, action): elif action in {'embedsign', 'clearsign', 'detachsign'}: action = 'sign' self.infobar('x_generic_failed_textmode', customtext=action) - - - #------------------------------------------ HELPERS FOR MAIN XFACE FUNCTION - - # CB for glib.io_add_watch() + + # HELPERS FOR MAIN XFACE FUNCTION + + # CB for GLib.io_add_watch() def update_task_status(self, fd, condition, output='task'): """Read data waiting in file descriptor; close fd if other end hangs up.""" - + # If there's data to be read, let's read it - if condition == glib.IO_IN: + if condition == GLib.IOCondition.IN: + b = read(fd, 1024).decode('utf-8') if output in 'task': # Output to Task Status - self.buff2.insert(self.buff2.get_end_iter(), read(fd, 1024)) + self.buff2.insert(self.buff2.get_end_iter(), b) else: # Output to stderr (will show if run from terminal) - stderr.write(read(fd, 1024)) + stderr.write(b) return True - # If other end of pipe hangs up, close our fd and destroy the watcher - elif condition == glib.IO_HUP: + elif condition == GLib.IOCondition.HUP: if output in 'term': stderr.write("\n") close(fd) return False - - + # Called when gpg/openssl begins and ends processing def show_working_progress(self, show=True, action=None): """Hide/show progress widgets; set/unset working status + activity spinner.""" - + # Show/hide progress bar & its buttons for w in self.g_progbar, self.g_cancel, self.g_pause: w.set_visible(show) - + if show: # If beginning processing: set progbar text + working status, start spinner - self.g_progbar.set_text ("{} working...".format(self.engine)) + self.g_progbar.set_text("{} working...".format(self.engine)) if action in {'embedsign', 'clearsign', 'detachsign'}: status = "Signing input ..." elif action in 'verify': @@ -1390,26 +1352,53 @@ def show_working_progress(self, show=True, action=None): self.g_statusbar.push(self.status, status) self.g_activityspin.set_visible(True) self.g_activityspin.start() - gtk.main_iteration() - + Gtk.main_iteration() else: # If finished processing: ensure progbar buttons are normal, reset status, stop spinner for w in self.g_cancel, self.g_pause: w.set_sensitive(True) - w.set_relief(gtk.RELIEF_NONE) + w.set_relief(Gtk.ReliefStyle.NONE) self.g_activityspin.stop() self.g_activityspin.set_visible(False) self.g_statusbar.pop(self.status) - - - #---------------------------------------------- RUN MAIN APPLICATION WINDOW - def main(self): - """Show main window, tweak some GTK+ settings and start GTK+ main loop.""" - self.g_window.show() - settings = gtk.settings_get_default() - settings.props.gtk_button_images = True - with gtk.gdk.lock: - gtk.main() + def loadmails_string_list(self): + """Return emails from all known keys.""" + mails = list() + if self.engine == 'OpenSSL': + return mails + cmd = split("gpg --list-public-keys --with-colons") + keys_string = check_output(cmd).decode('utf-8') + keys_all = keys_string.split('\n') + for line in keys_all: + line_fields = line.split(':') + if line_fields[0] == 'uid': + name_email = line_fields[9] + mails.append(name_email) + return mails + + # Loading names and emails for the recipient menu completion + def load_recipients_autocmplete(self): + mails = Gtk.ListStore(str) + for mail in self.loadmails_string_list(): + mails.append([mail]) + completion = Gtk.EntryCompletion() + completion.set_model(mails) + completion.set_text_column(0) + completion.set_match_func(self.recipient_contains, None) + self.g_recip.set_completion(completion) + + def recipient_contains(self, completion, key_string, iter, data): + model = completion.get_model() + # get the completion strings + modelstr = model[iter][0] + return key_string in modelstr + # RUN MAIN APPLICATION WINDOW + def main(self): + """Show main window, and start GTK+ main loop.""" + self.g_window.show() + self.g_window.connect("destroy", Gtk.main_quit) + self.g_window.show_all() + Gtk.main() diff --git a/modules/crypt_interface.py b/modules/crypt_interface.py index b553809..1e25779 100644 --- a/modules/crypt_interface.py +++ b/modules/crypt_interface.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,30 +15,26 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ -from sys import stderr from os import pipe, write, close from shlex import split from subprocess import Popen, PIPE, check_output +from sys import stderr from time import sleep - -def flatten_list_to_stderr(list): +def flatten_list_to_stderr(lines): stderr.write("-" * 79 + "\n") - for item in list: + for item in lines: stderr.write(item + " ") stderr.write("\n\n") - -class Gpg(): - """GPG/GPG2 interface for encryption/decryption/signing/verifying. +class Gpg: + """GPG interface for encryption/decryption/signing/verifying. - First thing: use subprocess module to call a gpg or gpg2 process, ensuring - that one of them is available on the system; if not, of course we have to + First thing: use subprocess module to call a gpg process, ensuring + that it is available on the system; if not, of course we have to quit (raise exception). Either way, that's all for __init__. See the docstring for the main method -- gpg() -- for next steps. @@ -51,79 +42,60 @@ class Gpg(): Security: Xface.gpg() can take a passphrase for symmetric enc/dec as an argument, but it never stores that passphrase on disk; the passphrase is passed to gpg via an os file descriptor. If any access to your secret key is - required, gpg() invokes gpg/gpg2 with gpg-agent enabled. + required, gpg() invokes gpg with gpg-agent enabled. """ - - - def __init__(self, show_version=True, firstchoice='gpg2'): - """Confirm we can run gpg or gpg2.""" - - def gpg1(): + + def __init__(self, show_version=True): + """Confirm we can run gpg.""" + + try: self.vers = Popen(['gpg', '--version'], stdout=PIPE).communicate()[0] - self.GPG_BINARY = 'gpg' - - def gpg2(): - self.vers = Popen(['gpg2', '--version'], stdout=PIPE).communicate()[0] - self.GPG_BINARY = 'gpg2' - - if firstchoice == 'gpg': - try: gpg1() - except: - try: gpg2() - except: - stderr.write("gpg, gpg2 not found on your system.\n\n") - raise - else: - try: gpg2() - except: - try: gpg1() - except: - stderr.write("gpg, gpg2 not found on your system.\n\n") - raise - + except: + stderr.write("gpg not found on your system.\n\n") + raise + # To show or not to show version info if show_version: stderr.write("{}\n".format(self.vers)) - + # I/O dictionary obj self.io = dict( - stdin='', # Stores input text for subprocess + stdin='', # Stores input text for subprocess stdout='', # Stores stdout stream from subprocess - stderr=0, # Stores tuple of r/w file descriptors for stderr stream + stderr=0, # Stores tuple of r/w file descriptors for stderr stream gstatus=0, # Stores tuple of r/w file descriptors for gpg-status stream - infile=0, # Input filename for subprocess + infile=0, # Input filename for subprocess outfile=0) # Output filename for subprocess - + self.childprocess = None - - + # Main gpg interface method def gpg( - self, - action= None, # One of: enc, dec, embedsign, clearsign, detachsign, verify - encsign= False, # Add '--sign' when encrypting? - digest= None, # One of: sha256, sha1, etc; None == use gpg defaults - localuser= None, # Value passed to --local-user to set default key for signing, etc - base64= True, # Add '--armor' when encrypting/signing? - symmetric= False, # Add '--symmetric'? - passwd= None, # Passphrase for symmetric - asymmetric= False, # Add '--encrypt'? - recip= None, # Recipients for asymmetric (semicolon-delimited) - enctoself= False, # Add first id from secret keyring as recipient? - cipher= None, # One of: aes256, 3des, etc; None == use gpg defaults - verbose= False, # Add '--verbose'? - alwaystrust=False, # Add '--trust-model always'? - yes= True # Add '--yes'? (will overwrite files) - ): - """Build a gpg cmdline and then launch gpg/gpg2, saving output appropriately. + self, + action=None, # One of: enc, dec, embedsign, clearsign, detachsign, verify + encsign=False, # Add '--sign' when encrypting? + digest=None, # One of: sha256, sha1, etc; None == use gpg defaults + localuser=None, # Value passed to --local-user to set default key for signing, etc + base64=True, # Add '--armor' when encrypting/signing? + symmetric=False, # Add '--symmetric'? + passwd=None, # Passphrase for symmetric + asymmetric=False, # Add '--encrypt'? + recip=None, # Recipients for asymmetric (semicolon-delimited) + enctoself=False, # Add first id from secret keyring as recipient? + cipher=None, # One of: aes256, 3des, etc; None == use gpg defaults + verbose=False, # Add '--verbose'? + alwaystrust=False, # Add '--trust-model always'? + yes=True # Add '--yes'? (will overwrite files) + ): + """Build a gpg cmdline and then launch gpg, saving output appropriately. This method inspects the contents of class attr 'io' -- a dict object that should - contain all of the following keys, at least initialized to 0 or '': + contain all the following keys, at least initialized to 0 or '': stdin # Input text for subprocess infile # Input filename for subprocess, in place of stdin outfile # Output filename if infile was given - io['infile'] should contain a filename OR be set to 0, in which case io'[stdin'] + io['infile'] should contain a filename OR be set to 0, in which case io['stdin'] must contain the input data. If using infile, outfile is not necessarily required, but it's probably a good idea unless you're doing sign-only. @@ -147,32 +119,32 @@ def gpg( the caller (i.e., by examining the Popen instance's returncode attribute). """ - + if self.io['infile'] and self.io['infile'] == self.io['outfile']: stderr.write("Same file for both input and output, eh? Is it going " "to work? ... NOPE. Chuck Testa.\n") raise Exception("infile, outfile must be different") - - fd_pwd_R = None - fd_pwd_W = None - useagent = True - cmd = [self.GPG_BINARY] - + + fd_pwd_R = None + fd_pwd_W = None + useagent = True + cmd = ['gpg'] + if self.io['gstatus']: # Status to file descriptor option cmd.append('--status-fd') cmd.append(str(self.io['gstatus'][1])) - + # Setup passphrase file descriptor for symmetric enc/dec if (action in 'enc' and symmetric and passwd and not encsign) or ( - action in 'dec' and symmetric and passwd): - useagent=False - fd_pwd_R, fd_pwd_W = pipe() - write(fd_pwd_W, passwd) - close(fd_pwd_W) - cmd.append('--passphrase-fd') - cmd.append(str(fd_pwd_R)) - + action in 'dec' and symmetric and passwd): + useagent = False + fd_pwd_R, fd_pwd_W = pipe() + write(fd_pwd_W, passwd) + close(fd_pwd_W) + cmd.append('--passphrase-fd') + cmd.append(str(fd_pwd_R)) + # Encrypt opts if action in 'enc': if encsign: @@ -191,48 +163,47 @@ def gpg( if enctoself: cmd.append('--recipient') if localuser: - cmd.append(localuser) + cmd.append("'" + localuser + "'") else: - cmd.append(self.get_gpgdefaultkey()) + cmd.append(self.get_gpg_default_key()) if recip: while recip[-1] == ' ' or recip[-1] == ';': recip = recip.strip() recip = recip.strip(';') for r in recip.split(';'): cmd.append('--recipient') - cmd.append(r) - + cmd.append("'" + r + "'") + # Decrypt opts elif action in 'dec': cmd.append('--decrypt') - + # Sign opts elif action in {'embedsign', 'clearsign', 'detachsign'}: - if action in 'embedsign': cmd.append('--sign') - elif action in 'clearsign': cmd.append('--clearsign') - elif action in 'detachsign': cmd.append('--detach-sign') + if action in 'embedsign': + cmd.append('--sign') + elif action in 'clearsign': + cmd.append('--clearsign') + elif action in 'detachsign': + cmd.append('--detach-sign') if digest: cmd.append('--digest-algo') cmd.append(digest) - + # Verify opts elif action in 'verify': cmd.append('--verify') - + # Wouldn't hurt to use armor for all, but it only works with these 3 if action in {'enc', 'embedsign', 'detachsign'}: if base64: cmd.append('--armor') - + # Action-independent opts if useagent: - if self.GPG_BINARY in 'gpg': - cmd.append('--use-agent') + cmd.append('--use-agent') else: - if self.GPG_BINARY in 'gpg': - cmd.append('--no-use-agent') - else: - cmd.append('--batch') + cmd.append('--no-use-agent') if localuser: cmd.append('--local-user') cmd.append(localuser) @@ -249,40 +220,41 @@ def gpg( cmd.append(self.io['outfile']) if self.io['infile']: cmd.append(self.io['infile']) - + # Print a separator + the command-arguments to stderr flatten_list_to_stderr(cmd) - - # If working direct with files, setup our Popen instance with no stdin + + # If working direct with files, set up our Popen instance with no stdin if self.io['infile']: self.childprocess = Popen(cmd, stdout=PIPE, stderr=self.io['stderr'][1]) # Otherwise, only difference for Popen is we need the stdin pipe else: - self.childprocess = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=self.io['stderr'][1]) - + b = self.io['stderr'] + self.childprocess = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=b[1]) + # Time to communicate! Save output for later - self.io['stdout'] = self.childprocess.communicate(input=self.io['stdin'])[0] - + b = self.io['stdin'].encode('utf-8') + self.io['stdout'] = self.childprocess.communicate(input=b)[0] + # Clear stdin from our dictionary asap, in case it's huge self.io['stdin'] = '' - + # Close os file descriptors - if fd_pwd_R: close(fd_pwd_R) + if fd_pwd_R: + close(fd_pwd_R) sleep(0.1) # Sleep a bit to ensure everything gets read close(self.io['stderr'][1]) if self.io['gstatus']: close(self.io['gstatus'][1]) - - - def get_gpgdefaultkey(self): - """Return key id of first secret key in gpg keyring.""" - return check_output(split( - "{} --list-secret-keys --with-colons --fast-list-mode" - .format(self.GPG_BINARY))).split(':', 5)[4] + def get_gpg_default_key(self): + """Return key id of first secret key in gpg keyring.""" + cmd = split("gpg --list-secret-keys --with-colons --fast-list-mode") + output = str(check_output(cmd)) + return output.split(':', 5)[4] -class Openssl(): +class Openssl: """OpenSSL interface for encryption/decryption. First thing: use subprocess module to call an openssl process, ensuring it @@ -296,47 +268,46 @@ class Openssl(): passed to openssl via an os file descriptor. """ - + def __init__(self, show_version=True): """Confirm we can run openssl.""" - + try: vers = Popen(['openssl', 'version'], stdout=PIPE).communicate()[0] except: stderr.write("OpenSSL not found on your system.\n\n") raise - + # To show or not to show version info if show_version: stderr.write("{}\n".format(vers)) - + # I/O dictionary obj self.io = dict( - stdin='', # Stores input text for subprocess + stdin='', # Stores input text for subprocess stdout='', # Stores stdout stream from subprocess - stderr=0, # Stores tuple of r/w file descriptors for stderr stream - infile=0, # Input filename for subprocess + stderr=0, # Stores tuple of r/w file descriptors for stderr stream + infile=0, # Input filename for subprocess outfile=0) # Output filename for subprocess - + self.childprocess = None - - + # Main openssl interface method def openssl( - self, - action, # One of: enc, dec - passwd, # Passphrase for symmetric - base64=True, # Add '-a' when encrypting/decrypting? - cipher=None, # Cipher in gpg-format; None = use aes256 - ): + self, + action, # One of: enc, dec + passwd, # Passphrase for symmetric + base64=True, # Add '-a' when encrypting/decrypting? + cipher=None, # Cipher in gpg-format; None = use aes256 + ): """Build an openssl cmdline and then launch it, saving output appropriately. This method inspects the contents of class attr 'io' -- a dict object that should - contain all of the following keys, at least initialized to 0 or '': + contain all the following keys, at least initialized to 0 or '': stdin # Input text for subprocess infile # Input filename for subprocess, in place of stdin outfile # Output filename -- required if infile was given - io['infile'] should contain a filename OR be set to 0, in which case io'[stdin'] + io['infile'] should contain a filename OR be set to 0, in which case io['stdin'] must contain the input data. Whether reading input from infile or stdin, each openssl command's stdout & @@ -347,35 +318,46 @@ def openssl( the caller (i.e., by examining the Popen instance's returncode attribute). """ - + if self.io['infile'] and self.io['infile'] == self.io['outfile']: stderr.write("Same file for both input and output, eh? Is it going " "to work? ... NOPE. Chuck Testa.\n") raise Exception("infile, outfile must be different") - - if cipher: cipher = cipher.lower() - if cipher == None: cipher = 'aes-256-cbc' - elif cipher == '3des': cipher = 'des-ede3-cbc' - elif cipher == 'cast5': cipher = 'cast5-cbc' - elif cipher == 'blowfish': cipher = 'bf-cbc' - elif cipher == 'aes': cipher = 'aes-128-cbc' - elif cipher == 'aes192': cipher = 'aes-192-cbc' - elif cipher == 'aes256': cipher = 'aes-256-cbc' - elif cipher == 'camellia128': cipher = 'camellia-128-cbc' - elif cipher == 'camellia192': cipher = 'camellia-192-cbc' - elif cipher == 'camellia256': cipher = 'camellia-256-cbc' - #else: cipher = 'aes-256-cbc' - - fd_pwd_R = None - fd_pwd_W = None - cmd = ['openssl', cipher, '-md', 'sha256', '-pass'] - + + if cipher: + cipher = cipher.lower() + if cipher is None: + cipher = 'aes-256-cbc' + elif cipher == '3des': + cipher = 'des-ede3-cbc' + elif cipher == 'cast5': + cipher = 'cast5-cbc' + elif cipher == 'blowfish': + cipher = 'bf-cbc' + elif cipher == 'aes': + cipher = 'aes-128-cbc' + elif cipher == 'aes192': + cipher = 'aes-192-cbc' + elif cipher == 'aes256': + cipher = 'aes-256-cbc' + elif cipher == 'camellia128': + cipher = 'camellia-128-cbc' + elif cipher == 'camellia192': + cipher = 'camellia-192-cbc' + elif cipher == 'camellia256': + cipher = 'camellia-256-cbc' + # else: cipher = 'aes-256-cbc' + + fd_pwd_R = None + fd_pwd_W = None + cmd = ['openssl', cipher, '-md', 'sha256', '-pass'] + # Setup passphrase file descriptors fd_pwd_R, fd_pwd_W = pipe() write(fd_pwd_W, passwd) close(fd_pwd_W) cmd.append('fd:{}'.format(fd_pwd_R)) - + if base64: cmd.append('-a') if action in 'enc': @@ -387,26 +369,25 @@ def openssl( cmd.append(self.io['infile']) cmd.append('-out') cmd.append(self.io['outfile']) - + # Print a separator + the command-arguments to stderr flatten_list_to_stderr(cmd) - - # If working direct with files, setup our Popen instance with no stdin + + # If working direct with files, set up our Popen instance with no stdin if self.io['infile']: self.childprocess = Popen(cmd, stdout=PIPE, stderr=self.io['stderr'][1]) # Otherwise, only difference for Popen is we need the stdin pipe else: self.childprocess = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=self.io['stderr'][1]) - + # Time to communicate! Save output for later - self.io['stdout'] = self.childprocess.communicate(input=self.io['stdin'])[0] - + b = self.io['stdin'].encode('utf-8') + self.io['stdout'] = self.childprocess.communicate(input=b)[0] + # Clear stdin from our dictionary asap, in case it's huge self.io['stdin'] = '' - + # Close os file descriptors close(fd_pwd_R) sleep(0.1) # Sleep a bit to ensure everything gets read close(self.io['stderr'][1]) - - diff --git a/modules/messages.py b/modules/messages.py index c79fa61..c385378 100644 --- a/modules/messages.py +++ b/modules/messages.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,223 +15,218 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ -SUCCESS = 0 -INFO = 1 -QUESTION = 2 -WARNING = 3 -ERROR = 4 +SUCCESS = 0 +INFO = 1 +QUESTION = 2 +WARNING = 3 +ERROR = 4 + def msg(text, type, icon, timeout=5): """Dictionar-ify input arguments.""" return {'text': text, 'type': type, 'icon': icon, 'timeout': timeout} -#------------------------------------------------------------------------------ - # INFOBAR MESSAGES FOR MAIN WINDOW +# INFOBAR MESSAGES FOR MAIN WINDOW MESSAGE_DICT = dict( - - #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Backend Engine - engine_openssl_missing = msg( - ("Shockingly, your system does not appear to have OpenSSL."), + + # Backend Engine + engine_openssl_missing=msg( + ("Your system does not appear to have OpenSSL."), INFO, WARNING), - - engine_gpg_missing = msg( + + engine_gpg_missing=msg( ("GnuPG not found. Operating in OpenSSL fallback-mode.\n" - "To make full use of this program you need either gpg or gpg2 installed.\n" - "Without one of them, you won't have access key-based functions like\n" - "asymmetric encryption or singing."), + "To make full use of this program you need gpg installed.\n" + "Without it, you won't have access key-based functions like\n" + "asymmetric encryption or singing."), INFO, WARNING, 20), - - engine_all_missing = msg( - ("This program requires one of: gpg, gpg2, or openssl\n" - "None of these were found on your system. You can look around\n" - "the interface, but to have real fun you'll need to install gpg or gpg2\n" - "from your linux distribution's software repository."), + + engine_all_missing=msg( + ("This program requires one of: gpg or openssl\n" + "None of these were found on your system. You can look around\n" + "the interface, but to have real fun you'll need to install gpg\n" + "from your linux distribution's software repository."), ERROR, WARNING, 0), - - engine_openssl_notice = msg( + + engine_openssl_notice=msg( ("OpenSSL only supports symmetric {{en,de}}cryption.\n" - "All key-based functions are disabled."), + "All key-based functions are disabled."), INFO, INFO, 7), - - #- - - - - - - - - - - - - - - - - - - - - Textview Message Area Operations - txtview_empty = msg( + + # Textview Message Area Operations + txtview_empty=msg( ("{customtext}"), INFO, WARNING, 2), - - txtview_fileopen_error = msg( + + txtview_fileopen_error=msg( ("Error. Could not open file:\n" - "{filename}"), + "{filename}"), WARNING, ERROR), - - txtview_fileopen_binary_error = msg( + + txtview_fileopen_binary_error=msg( ("To operate on binary files, use the\n" - "Input File For Direct Operation chooser button."), + "Input File For Direct Operation chooser button."), INFO, WARNING, 8), - - txtview_save_success = msg( + + txtview_save_success=msg( ("Saved contents of Message area to file:\n" - "{filename}"), + "{filename}"), INFO, SUCCESS), - - txtview_save_error = msg( + + txtview_save_error=msg( ("Error. Could not save to file:\n" - "{filename}"), + "{filename}"), WARNING, ERROR), - txtview_copyall_success = msg( + txtview_copyall_success=msg( ("Copied contents of Message area to clipboard."), INFO, SUCCESS, 3), - - #- - - - - - - - - - - - - - - - - - - - - - - - - - - Filemode Operations - filemode_fileopen_error = msg( + + # Filemode Operations + filemode_fileopen_error=msg( ("Error. Could not open file:\n" - "{filename}\n" - "Choose a new file."), + "{filename}\n" + "Choose a new file."), WARNING, ERROR), - - filemode_blue_banner = msg( + + filemode_blue_banner=msg( ("Encrypt, Decrypt, Sign, or Verify?\n" - "Choose an action to perform on file:\n" - "{filename}\n" - "You will be prompted for an output filename if necessary."), + "Choose an action to perform on file:\n" + "{filename}\n" + "You will be prompted for an output filename if necessary."), QUESTION, QUESTION, 0), - - #- - - - - - - - - - - - - - - Main xface (Enc/Dec/Sign/Verify) Operations - x_missing_passphrase= msg( + + # Main xface (Enc/Dec/Sign/Verify) Operations + x_missing_passphrase=msg( ("Passphrase?"), INFO, QUESTION, 3), - - x_canceled_filemode = msg( + + x_canceled_filemode=msg( ("{customtext} operation canceled.\n" - "To choose different input or output filenames, select Cancel\n" - "from the blue bar below."), + "To choose different input or output filenames, select Cancel\n" + "from the blue bar below."), INFO, WARNING, 6), - - x_canceled_textmode = msg( + + x_canceled_textmode=msg( ("{customtext} operation canceled."), INFO, WARNING, 4), - x_opensslenc_success_filemode = msg( + x_opensslenc_success_filemode=msg( ("OpenSSL encrypted input file with {customtext} cipher;\n" - "saved output to file:\n" - "{filename}\n" - "In order to decrypt that file in the future, you will need to \n" - "remember which cipher you used .. or guess until you figure it out."), + "saved output to file:\n" + "{filename}\n" + "In order to decrypt that file in the future, you will need to \n" + "remember which cipher you used .. or guess until you figure it out."), INFO, SUCCESS, 10), - - x_opensslenc_success_textmode = msg( + + x_opensslenc_success_textmode=msg( ("OpenSSL encrypted input using {customtext} cipher.\n" - "In order to decrypt the output in the future, you will need to \n" - "remember which cipher you used .. or guess until you figure it out."), + "In order to decrypt the output in the future, you will need to \n" + "remember which cipher you used .. or guess until you figure it out."), INFO, SUCCESS, 9), - - x_crypt_success_filemode = msg( + + x_crypt_success_filemode=msg( ("Saved {customtext}rypted copy of input to file:\n" - "{filename}"), + "{filename}"), INFO, SUCCESS), - - x_sign_success_filemode = msg( + + x_sign_success_filemode=msg( ("Saved signed copy of input to file:\n" - "{filename}"), + "{filename}"), INFO, SUCCESS), - - x_detachsign_success_filemode = msg( + + x_detachsign_success_filemode=msg( ("Saved detached signature of input to file:\n" - "{filename}"), + "{filename}"), INFO, SUCCESS), - - x_verify_success = msg( + + x_verify_success=msg( ("Signature verified. Data integrity intact."), INFO, SUCCESS, 4), - - x_verify_failed = msg( + + x_verify_failed=msg( ("Signature or data integrity could not be verified.\n" - "See Task Status for details."), + "See Task Status for details."), WARNING, ERROR, 7), - - x_missing_recip = msg( + + x_missing_recip=msg( ("For whom do you want to encrypt your message?\n" - "If you don't want to enter recipients and you don't want to select\n" - " Enc. To Self, you must add one of the directives\n" - "\tdefault-recipient-self\n" - "\tdefault-recipient name\n" - "to your gpg.conf file."), + "If you don't want to enter recipients and you don't want to select\n" + " Enc. To Self, you must add one of the directives\n" + "\tdefault-recipient-self\n" + "\tdefault-recipient name\n" + "to your gpg.conf file."), WARNING, QUESTION, 0), - - x_generic_failed_filemode = msg( + + x_generic_failed_filemode=msg( ("Problem {customtext}ing file.\n" - "See Task Status for details. Try a different passphrase or Cancel."), + "See Task Status for details. Try a different passphrase or Cancel."), WARNING, ERROR, 8), - - x_generic_failed_textmode = msg( + + x_generic_failed_textmode=msg( ("Problem {customtext}ing input.\n" - "See Task Status for details."), + "See Task Status for details."), WARNING, ERROR), - - #- - - - - - - - - - - - - - - - - - - - - - - - - OpenSSL Cipher Warnings - cipher_openssl_no_default = msg( + + # OpenSSL Cipher Warnings + cipher_openssl_no_default=msg( ("OpenSSL has no default cipher.\n" - "AES256 is a good choice."), + "AES256 is a good choice."), INFO, INFO, 7), - - cipher_openssl_no_twofish = msg( + + cipher_openssl_no_twofish=msg( ("OpenSSL has no support for the Twofish cipher."), INFO, INFO), - - cipher_openssl_aes_note = msg( + + cipher_openssl_aes_note=msg( ("Note for the command-line geeks:\n" - "AES translates to OpenSSL's aes-128-cbc."), + "AES translates to OpenSSL's aes-128-cbc."), INFO, INFO), - - #- - - - - - - - - - - - - - - - - - - - - - - - - - - Preferences Actions - preferences_save_success = msg( + + # Preferences Actions + preferences_save_success=msg( ("Saved preferences to {filename}\n" - "but no changes made to current session."), + "but no changes made to current session."), INFO, SUCCESS), - - preferences_apply_success = msg( + + preferences_apply_success=msg( ("Saved preferences to {filename}\n" - "and applied them to current session."), + "and applied them to current session."), INFO, SUCCESS), - - ) - +) -#------------------------------------------------------------------------------ - # INFOBAR MESSAGES FOR PREFERENCES DIALOG +# INFOBAR MESSAGES FOR PREFERENCES DIALOG PREFS_MESSAGE_DICT = dict( - - prefs_save_failed = msg( + + prefs_save_failed=msg( ("Saving preferences failed.\n" - "Unable to open config file {filename} for writing."), + "Unable to open config file {filename} for writing."), ERROR, WARNING, 10), - - prefs_reverted = msg( + + prefs_reverted=msg( ("Reverted to user-saved preferences."), INFO, SUCCESS, 3), - - prefs_reset_to_defaults = msg( + + prefs_reset_to_defaults=msg( ("Preferences reset to defaults. You still need to Save or Apply."), INFO, SUCCESS, 3), - - prefs_notice_enctoself = msg( + + prefs_notice_enctoself=msg( ("If you want Encrypt to Self on in Symmetric mode, you must set\n" - "Encryption Type to 'Both'."), + "Encryption Type to 'Both'."), INFO, INFO), - - prefs_notice_addsig = msg( + + prefs_notice_addsig=msg( ("If you want Add Signature on in Symmetric mode, you must also enable\n" - "Advanced."), + "Advanced."), INFO, INFO), - - prefs_notice_enc_both = msg( + + prefs_notice_enc_both=msg( ("In order for both encryption types to be on by default, Advanced will also be\n" - "turned on, whether or not you select it now."), + "turned on, whether or not you select it now."), INFO, INFO), - - ) + +) diff --git a/modules/prefs.py b/modules/prefs.py index 4074209..6de3d40 100644 --- a/modules/prefs.py +++ b/modules/prefs.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,19 +15,23 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ # StdLib: -import gtk -import glib -import cPickle as pickle +import gi + +gi.require_version('GLib', '2.0') +gi.require_version('Gdk', '3.0') +gi.require_version('Gtk', '3.0') +from gi.repository import GLib +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GObject +import pickle as pickle from sys import stderr from os import access, R_OK # Custom Modules: -import cfg -from messages import PREFS_MESSAGE_DICT as MESSAGE_DICT - +from . import cfg +from .messages import PREFS_MESSAGE_DICT as MESSAGE_DICT class Preferences: @@ -41,10 +40,9 @@ class Preferences: Try to read preferences from user preferences file; failing that, initialize good defaults. This class also includes the Preferences-setting window. """ - - + def __init__(self, reset_defaults=False): - + try: if reset_defaults: raise Exception @@ -54,7 +52,7 @@ def __init__(self, reset_defaults=False): raise Exception self.p = dict(pickle.load(f)) stderr.write("Pyrite loaded preferences from file {!r}\n".format(cfg.USERPREF_FILE)) - + except: stderr.write("Pyrite loaded default preferences\n") # Default preferences @@ -89,171 +87,173 @@ def __init__(self, reset_defaults=False): errfntsize=7, color_fg='#000000000000', color_bg='#ffffffffffff') - - + def infobar(self, id, filename=None, customtext=None): """Popup a new auto-hiding InfoBar.""" - + # CB for destroy timeout def destroy_ibar(): self.ibar_timeout = 0 self.ibar.destroy() - self.window.resize(1,1) - + self.window.resize(1, 1) + # If infobar already active: delete old timeout, destroy old ibar if self.ibar_timeout > 0: - glib.source_remove(self.ibar_timeout) + GObject.source_remove(self.ibar_timeout) destroy_ibar() - + # Find the needed dictionary inside our message dict, by id MSG = MESSAGE_DICT[id] - # Use value from MSG type & icon to lookup Gtk constant, e.g. gtk.MESSAGE_INFO - msgtype = cfg.MSGTYPES[ MSG['type'] ] - imgtype = cfg.IMGTYPES[ MSG['icon'] ] + # Use value from MSG type & icon to lookup Gtk constant, e.g. Gtk.MessageType.INFO + msgtype = cfg.MSGTYPES[MSG['type']] + imgtype = cfg.IMGTYPES[MSG['icon']] # Replace variables in message text & change text color message = ("" + MSG['text'].format(filename=filename, customtext=customtext) + "") - + # Now that we have all the data we need, START creating! - self.ibar = gtk.InfoBar() + self.ibar = Gtk.InfoBar() self.ibar.set_message_type(msgtype) - self.vbox_ib.pack_end (self.ibar, False, False) - img = gtk.Image() - img.set_from_stock (imgtype, gtk.ICON_SIZE_LARGE_TOOLBAR) - label = gtk.Label() - label.set_markup (message) - content = self.ibar.get_content_area() - content.pack_start (img, False, False) - content.pack_start (label, False, False) - img.show () - label.show () - self.ibar.show () - self.ibar_timeout = glib.timeout_add_seconds(MSG['timeout'], destroy_ibar) - - + self.vbox_ib.pack_end(self.ibar, False, False, 0) + img = Gtk.Image() + img.set_from_stock(imgtype, Gtk.IconSize.LARGE_TOOLBAR) + label = Gtk.Label() + label.set_markup(message) + content = self.ibar.get_content_area() + content.pack_start(img, False, False, 0) + content.pack_start(label, False, False, 0) + img.show() + label.show() + self.ibar.show() + self.ibar_timeout = GLib.timeout_add_seconds(MSG['timeout'], destroy_ibar) + def open_preferences_window(self, parentwindow): """Show the preferences window. Duh.""" self.ibar_timeout = 0 - builder = gtk.Builder() + builder = Gtk.Builder() builder.add_from_file(cfg.ASSETDIR + 'ui/preferences.glade') # Main window - self.window = builder.get_object('window1') - self.btn_save = builder.get_object('btn_save') - self.btn_apply = builder.get_object('btn_apply') - self.vbox_ib = builder.get_object('vbox_ib') + self.window = builder.get_object('window1') + self.btn_save = builder.get_object('btn_save') + self.btn_apply = builder.get_object('btn_apply') + self.vbox_ib = builder.get_object('vbox_ib') # Main Operation Mode - self.cb_opmode = builder.get_object('cb_opmode') + self.cb_opmode = builder.get_object('cb_opmode') # Engine - self.cb_backend = builder.get_object('cb_backend') + self.cb_backend = builder.get_object('cb_backend') # Enc/Dec Mode - self.cb_enctype = builder.get_object('cb_enctype') - self.tg_advanced = builder.get_object('tg_advanced') - self.tg_enctoself = builder.get_object('tg_enctoself') - self.cb_cipher = builder.get_object('cb_cipher') - self.tg_addsig = builder.get_object('tg_addsig') + self.cb_enctype = builder.get_object('cb_enctype') + self.tg_advanced = builder.get_object('tg_advanced') + self.tg_enctoself = builder.get_object('tg_enctoself') + self.cb_cipher = builder.get_object('cb_cipher') + self.tg_addsig = builder.get_object('tg_addsig') # Mode-Independent - self.cb_digest = builder.get_object('cb_digest') - self.tg_defkey = builder.get_object('tg_defkey') - self.ent_defkey = builder.get_object('ent_defkey') - self.cb_txtoutput = builder.get_object('cb_txtoutput') - self.tg_expander = builder.get_object('tg_expander') + self.cb_digest = builder.get_object('cb_digest') + self.tg_defkey = builder.get_object('tg_defkey') + self.ent_defkey = builder.get_object('ent_defkey') + self.cb_txtoutput = builder.get_object('cb_txtoutput') + self.tg_expander = builder.get_object('tg_expander') # Sign/Verify Mode - self.tg_svoutfiles = builder.get_object('tg_svoutfiles') - self.cb_text_sigmode= builder.get_object('cb_text_sigmode') - self.cb_file_sigmode= builder.get_object('cb_file_sigmode') + self.tg_svoutfiles = builder.get_object('tg_svoutfiles') + self.cb_text_sigmode = builder.get_object('cb_text_sigmode') + self.cb_file_sigmode = builder.get_object('cb_file_sigmode') # Display - self.tg_taskstatus = builder.get_object('tg_taskstatus') - self.tg_verbose = builder.get_object('tg_verbose') - self.tg_wrap = builder.get_object('tg_wrap') - self.tg_opc_slider = builder.get_object('tg_opc_slider') - self.sp_opacity = builder.get_object('sp_opacity') - self.sp_msgfntsize = builder.get_object('sp_msgfntsize') - self.sp_errfntsize = builder.get_object('sp_errfntsize') - self.btn_color_fg = builder.get_object('btn_color_fg') - self.btn_color_bg = builder.get_object('btn_color_bg') + self.tg_taskstatus = builder.get_object('tg_taskstatus') + self.tg_verbose = builder.get_object('tg_verbose') + self.tg_wrap = builder.get_object('tg_wrap') + self.tg_opc_slider = builder.get_object('tg_opc_slider') + self.sp_opacity = builder.get_object('sp_opacity') + self.sp_msgfntsize = builder.get_object('sp_msgfntsize') + self.sp_errfntsize = builder.get_object('sp_errfntsize') + self.btn_color_fg = builder.get_object('btn_color_fg') + self.btn_color_bg = builder.get_object('btn_color_bg') # TODO: Advanced tab - #self.tg_args_gpg_e = builder.get_object('tg_args_gpg_e') - #self.en_args_gpg_e = builder.get_object('en_args_gpg_e') - self.window.set_transient_for(parentwindow) + # self.tg_args_gpg_e = builder.get_object('tg_args_gpg_e') + # self.en_args_gpg_e = builder.get_object('en_args_gpg_e') + # self.set_transient_for(parentwindow) if access(cfg.USERPREF_FILE, R_OK): btn_revert = builder.get_object('btn_revert') btn_revert.set_sensitive(True) self.populate_pref_window_prefs() builder.connect_signals(self) self.window.show() - - + def populate_pref_window_prefs(self): """Set state of widgets in prefs window via preferences.""" # Main Operation Mode - self.cb_opmode.set_active (self.p['opmode']) + self.cb_opmode.set_active(self.p['opmode']) # Engine - self.cb_backend.set_active (self.p['backend']) + self.cb_backend.set_active(self.p['backend']) # Enc/Dec Mode - self.cb_enctype.set_active (self.p['enctype']) - self.tg_advanced.set_active (self.p['advanced']) - self.tg_enctoself.set_active (self.p['enctoself']) - self.cb_cipher.set_active (self.p['cipher']) - self.tg_addsig.set_active (self.p['addsig']) + self.cb_enctype.set_active(self.p['enctype']) + self.tg_advanced.set_active(self.p['advanced']) + self.tg_enctoself.set_active(self.p['enctoself']) + self.cb_cipher.set_active(self.p['cipher']) + self.tg_addsig.set_active(self.p['addsig']) # Mode-Independent - self.cb_digest.set_active (self.p['digest']) - self.tg_defkey.set_active (self.p['defkey']) - self.ent_defkey.set_text (self.p['defkeytxt']) - self.cb_txtoutput.set_active (self.p['txtoutput']) - self.tg_expander.set_active (self.p['expander']) + self.cb_digest.set_active(self.p['digest']) + self.tg_defkey.set_active(self.p['defkey']) + self.ent_defkey.set_text(self.p['defkeytxt']) + self.cb_txtoutput.set_active(self.p['txtoutput']) + self.tg_expander.set_active(self.p['expander']) # Sign/Verify Mode - self.tg_svoutfiles.set_active (self.p['svoutfiles']) - self.cb_text_sigmode.set_active (self.p['text_sigmode']) - self.cb_file_sigmode.set_active (self.p['file_sigmode']) + self.tg_svoutfiles.set_active(self.p['svoutfiles']) + self.cb_text_sigmode.set_active(self.p['text_sigmode']) + self.cb_file_sigmode.set_active(self.p['file_sigmode']) # Display - self.tg_taskstatus.set_active (self.p['taskstatus']) - self.tg_verbose.set_active (self.p['verbose']) - self.tg_wrap.set_active (self.p['wrap']) - self.tg_opc_slider.set_active (self.p['opc_slider']) - self.sp_opacity.set_value (self.p['opacity']) - self.sp_msgfntsize.set_value (self.p['msgfntsize']) - self.sp_errfntsize.set_value (self.p['errfntsize']) - self.btn_color_fg.set_color (gtk.gdk.color_parse(self.p['color_fg'])) - self.btn_color_bg.set_color (gtk.gdk.color_parse(self.p['color_bg'])) - - + self.tg_taskstatus.set_active(self.p['taskstatus']) + self.tg_verbose.set_active(self.p['verbose']) + self.tg_wrap.set_active(self.p['wrap']) + self.tg_opc_slider.set_active(self.p['opc_slider']) + self.sp_opacity.set_value(self.p['opacity']) + self.sp_msgfntsize.set_value(self.p['msgfntsize']) + self.sp_errfntsize.set_value(self.p['errfntsize']) + + fg_color = Gdk.Color(0, 0, 0) + fg_color.parse(self.p['color_fg']) + + bg_color = Gdk.Color(0, 0, 0) + bg_color.parse(self.p['color_bg']) + + self.btn_color_fg.set_color(fg_color) + self.btn_color_bg.set_color(bg_color) + def capture_current_prefs(self): """Capture current state of widgets in prefs window & save as preferences.""" self.p = { # Main Operation Mode - 'opmode' : self.cb_opmode.get_active(), + 'opmode': self.cb_opmode.get_active(), # Engine - 'backend' : self.cb_backend.get_active(), + 'backend': self.cb_backend.get_active(), # Enc/Dec Mode - 'enctype' : self.cb_enctype.get_active(), - 'advanced' : self.tg_advanced.get_active(), - 'enctoself' : self.tg_enctoself.get_active(), - 'cipher' : self.cb_cipher.get_active(), - 'addsig' : self.tg_addsig.get_active(), + 'enctype': self.cb_enctype.get_active(), + 'advanced': self.tg_advanced.get_active(), + 'enctoself': self.tg_enctoself.get_active(), + 'cipher': self.cb_cipher.get_active(), + 'addsig': self.tg_addsig.get_active(), # Mode-Independent - 'digest' : self.cb_digest.get_active(), - 'defkey' : self.tg_defkey.get_active(), - 'defkeytxt' : self.ent_defkey.get_text(), - 'txtoutput' : self.cb_txtoutput.get_active(), - 'expander' : self.tg_expander.get_active(), + 'digest': self.cb_digest.get_active(), + 'defkey': self.tg_defkey.get_active(), + 'defkeytxt': self.ent_defkey.get_text(), + 'txtoutput': self.cb_txtoutput.get_active(), + 'expander': self.tg_expander.get_active(), # Sign/Verify Mode - 'svoutfiles' : self.tg_svoutfiles.get_active(), + 'svoutfiles': self.tg_svoutfiles.get_active(), 'text_sigmode': self.cb_text_sigmode.get_active(), 'file_sigmode': self.cb_file_sigmode.get_active(), # Display - 'taskstatus' : self.tg_taskstatus.get_active(), - 'verbose' : self.tg_verbose.get_active(), - 'wrap' : self.tg_wrap.get_active(), - 'opc_slider' : self.tg_opc_slider.get_active(), - 'opacity' : self.sp_opacity.get_value(), - 'msgfntsize' : self.sp_msgfntsize.get_value(), - 'errfntsize' : self.sp_errfntsize.get_value(), - 'color_fg' : self.btn_color_fg.get_color().to_string(), - 'color_bg' : self.btn_color_bg.get_color().to_string()} + 'taskstatus': self.tg_taskstatus.get_active(), + 'verbose': self.tg_verbose.get_active(), + 'wrap': self.tg_wrap.get_active(), + 'opc_slider': self.tg_opc_slider.get_active(), + 'opacity': self.sp_opacity.get_value(), + 'msgfntsize': self.sp_msgfntsize.get_value(), + 'errfntsize': self.sp_errfntsize.get_value(), + 'color_fg': self.btn_color_fg.get_color().to_string(), + 'color_bg': self.btn_color_bg.get_color().to_string()} return self.p - - + # Called by Save button def save_prefs(self): """Attempt to save user prefs to homedir prefs file.""" @@ -266,44 +266,37 @@ def save_prefs(self): self.infobar('prefs_save_failed', cfg.USERPREF_FILE) return False return True - - + # Called by Cancel button def action_cancel_prefs(self, w): """Close prefs window without doing anything.""" self.window.destroy() - - + # Called by Revert button def action_revert_prefs(self, w): """Reset state of widgets in prefs window via external preferences file, if avail.""" self.__init__() self.populate_pref_window_prefs() self.infobar('prefs_reverted') - - + # Called by Defaults button def action_default_prefs(self, w): """Reset state of widgets in prefs window to predefined defaults.""" self.__init__(reset_defaults=True) self.populate_pref_window_prefs() self.infobar('prefs_reset_to_defaults') - - + def action_tg_enctoself(self, w): """Show some info when user enables enctoself toggle.""" if w.get_active(): self.infobar('prefs_notice_enctoself') - - + def action_tg_addsig(self, w): """Show some info when user enables addsig toggle.""" if w.get_active(): self.infobar('prefs_notice_addsig') - - + def action_cb_enctype(self, w): """Show some info when user chooses 'Both' in enctype combobox.""" if w.get_active() == 2: self.infobar('prefs_notice_enc_both') - diff --git a/pyrite.desktop b/pyrite.desktop index 435173e..490d05c 100644 --- a/pyrite.desktop +++ b/pyrite.desktop @@ -1,6 +1,6 @@ [Desktop Entry] Name=Pyrite -Comment=OpenSSL & GnuPG (gpg/gpg2) encryption/signing front-end +Comment=OpenSSL & GnuPG (gpg) encryption/signing front-end Exec=pyrite Terminal=false Type=Application diff --git a/pyrite.py b/pyrite.py index 8c33798..9854182 100755 --- a/pyrite.py +++ b/pyrite.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,20 +15,10 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ -# -# TODO: -# * Icons for for encrypt, decrypt, sign, verify buttons, application -# * Undo stack. Blech. Kill me. -# * Update notifications -# * BUG: First drag/drop onto FileChooserButton fails; 2nd, 3rd, etc succeed. -# It's a GTK+ issue. Reported. bugzilla.gnome.org/show_bug.cgi?id=669718 -# -#------------------------------------------------------------------------------ import argparse from sys import argv + import modules.core # Parse command-line arguments @@ -77,15 +62,14 @@ args = parser.parse_args() # If no cmdline options specified, let's save some cycles later -if len(argv) == 1: args = None - +if len(argv) == 1: + args = None if __name__ == "__main__": - + FeS2 = modules.core.Pyrite(args) try: FeS2.main() except KeyboardInterrupt: - print + print() exit() - diff --git a/ui/about.glade b/ui/about.glade index e62dae1..1c2fdff 100644 --- a/ui/about.glade +++ b/ui/about.glade @@ -1,16 +1,15 @@ - - + - False - 5 - True - dialog - True - Pyrite + False + 5 + True + dialog + True + Pyrite Copyright © 2012, 2013 Ryan Sawhill Aroha - GnuPG (gpg/gpg2) encrypting, decrypting, signing, and verifying + GnuPG (gpg) encrypting, decrypting, signing, and verifying http://github.com/ryran/pyrite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,23 +24,24 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://gnu.org/licenses/gpl.html>. Ryan Sawhill Aroha <rsaw@redhat.com> - We need translators! + We need translators! We need someone to design some good icons! + image-missing - + True - False + False 2 - + True - False - end + False + end False True - end + end 0 diff --git a/ui/main.glade b/ui/main.glade index ea88f4c..8753c74 100644 --- a/ui/main.glade +++ b/ui/main.glade @@ -1,55 +1,54 @@ - - + True - False + False gtk-clear True - False + False gtk-zoom-in True - False + False gtk-zoom-out True - False + False gtk-execute True - False + False gtk-clear True - False + False gtk-revert-to-saved True - False + False gtk-apply True - False + False gtk-open True - False + False gtk-save True - False + False gtk-save-as @@ -143,117 +142,117 @@ - False + False Pyrite - center + center True - False + False True - False + False - False + False True - False + False _File - True + True True - False + False C_lear - False + False True - False - True - Clear all text/file buffers - True + False + True + Clear all text/file buffers + True image6 - False - True - + False + True + _Open Text File as Message - False + False True - False - True - Open text file in Message area - True + False + True + Open text file in Message area + True img_open - False - True - + False + True + _Save Copy of Message - False + False True - False - Save Message to text file - True + False + Save Message to text file + True img_saveas - False - True - + False + True + - False + False True - False + False Use OpenSSL as Engine - False + False True - False - True - Switch between using OpenSSL or GnuPG as the backend - True + False + True + Switch between using OpenSSL or GnuPG as the backend + True image9 - False - True - + False + True + - False + False True - False + False gtk-quit - False + False True - False - True - True - True - + False + True + True + True + @@ -262,103 +261,103 @@ - False + False True - False + False Edit - True + True True - False + False gtk-undo - False + False True False - False - True - True - True + False + True + True + True gtk-redo - False + False True False - False - True - True - True + False + True + True + True - False + False True - False + False gtk-cut - False + False True - False - True - True - True + False + True + True + True gtk-copy - False + False True - False - True - True - True + False + True + True + True gtk-paste - False + False True - False - True - True - True + False + True + True + True - False + False True - False + False gtk-preferences - False + False True - False - True - True - True - True - + False + True + True + True + True + @@ -367,86 +366,86 @@ - False + False True - False + False _View - True + True True - False + False - False + False True - False - True - Toggles line-wrapping in Message area + False + True + Toggles line-wrapping in Message area This will not add newline characters to Message Text _Wrapping - True + True True - False + False True - False - True - Show/hide side pane containing gpg/openssl cmd stderr (success/failure messages) + False + True + Show/hide side pane containing gpg/openssl cmd stderr (success/failure messages) _Task Status Side Panel - True + True True - False + False True - False - True - Enable/disable verbose status output from gpg (displayed in side panel) + False + True + Enable/disable verbose status output from gpg (displayed in side panel) _Verbose Output in Task Status - True + True - False + False True - False + False Increase Font Size - False + False True - False - True + False + True image7 - False - True - + False + True + Decrease Font Size - False + False True - False - True + False + True image8 - False - True - + False + True + @@ -455,24 +454,24 @@ This will not add newline characters to Message - False + False True - False + False Help - True + True True - False + False gtk-about - False + False True - False - True - True - True + False + True + True + True @@ -490,12 +489,12 @@ This will not add newline characters to Message True - False + False 3 True - False + False False @@ -507,23 +506,22 @@ This will not add newline characters to Message True - False - edge + False _Encrypt - False + False True - True - True - True - <i>Ctrl+E</i> + True + False + True + True + <i>Ctrl+E</i> img_encrypt none - True - False - + True + False @@ -534,18 +532,18 @@ This will not add newline characters to Message _Decrypt - False + False True - True - True - True - <i>Ctrl+D</i> + True + False + True + True + <i>Ctrl+D</i> img_decrypt none - True - False - + True + False @@ -563,7 +561,7 @@ This will not add newline characters to Message True - False + False @@ -576,16 +574,16 @@ This will not add newline characters to Message C_lear - False + False True - True - True - True - Clear all text/file buffers + True + False + True + True + Clear all text/file buffers img_clear none - True - False + True @@ -596,25 +594,25 @@ This will not add newline characters to Message - 70 - True - 0 - False - left + 70 + True + 0 + False + left False True 6 - end + end 4 True - False + False @@ -626,8 +624,8 @@ This will not add newline characters to Message - False - 0.02 + False + 0.02 True @@ -638,31 +636,31 @@ This will not add newline characters to Message True - False + False False True 2 - end + end 6 - False - True - True - True - Pause processing + False + True + False + True + True + Pause processing none - False True - False + False gtk-media-pause @@ -670,24 +668,24 @@ This will not add newline characters to Message False True - end + end 7 - False - True - True - True - Cancel processing + False + True + False + True + True + Cancel processing none - False True - False + False gtk-cancel @@ -695,7 +693,7 @@ This will not add newline characters to Message False True - end + end 8 @@ -709,12 +707,12 @@ This will not add newline characters to Message True - False + False 1 True - False + False False @@ -726,17 +724,17 @@ This will not add newline characters to Message Sign/Verif_y Mode - False + False True - True - False - Sign-only / verify-only mode + True + False + False + Sign-only / verify-only mode For adding a signature to a message/file without encrypting it or for verifying a signed message/file that isn't encrypted - True - False + True True - True + True toggle_mode_encdec @@ -750,16 +748,16 @@ For adding a signature to a message/file without encrypting it or for verifying Choose Output Filenames - False - True - False - True - When signing external files, the output filenames are automatically chosen by gpg -- output is saved to the same directory as the input file and an extension is added based on the options used + False + True + False + False + True + When signing external files, the output filenames are automatically chosen by gpg -- output is saved to the same directory as the input file and an extension is added based on the options used Check this if you wish to choose the output filename yourself (e.g., because the input file is in a directory you can't write to) - True - False - True + True + True False @@ -771,7 +769,7 @@ Check this if you wish to choose the output filename yourself (e.g., because the True - False + False False @@ -783,16 +781,16 @@ Check this if you wish to choose the output filename yourself (e.g., because the Enc/Dec _Mode - False + False True - True - False - True - Encrypt / decrypt / encrypt + sign mode - True - False + True + False + False + True + Encrypt / decrypt / encrypt + sign mode + True True - True + True False @@ -804,17 +802,17 @@ Check this if you wish to choose the output filename yourself (e.g., because the _Symmetric - False + False True - True - False - True - Symmetric encryption/decryption + True + False + False + True + Symmetric encryption/decryption Requires specifying a passphrase which is used as a shared key (for both encryption & decryption) - True - False - True + True + True @@ -827,17 +825,17 @@ Requires specifying a passphrase which is used as a shared key (for both encrypt _Asymmetric - False + False True - True - False - True - Asymmetric encryption/decryption + True + False + False + True + Asymmetric encryption/decryption Requires specifying recipients whose public keys will be used for encryption; or for decryption, it requires access to your gpg secret key - True - False - True + True + True @@ -850,17 +848,17 @@ Requires specifying recipients whose public keys will be used for encryption; or Adva_nced - False + False True - True - False - True - Allow mixing simple symmetric encryption with asymmetric encryption and/or signing + True + False + False + True + Allow mixing simple symmetric encryption with asymmetric encryption and/or signing When creating a signed + symmetrically-encrypted message, anything in the passphrase entry box will be ignored -- gpg-agent will need to ask for both the symmetric encryption key (passphrase) and [potentially] the passphrase to your secret key - True - False - True + True + True @@ -880,12 +878,12 @@ When creating a signed + symmetrically-encrypted message, anything in the passph True - False + False 1 True - False + False False @@ -898,11 +896,11 @@ When creating a signed + symmetrically-encrypted message, anything in the passph True False - False + False _Passphrase: - True - True - entry_pass + True + True + entry_pass False @@ -913,9 +911,9 @@ When creating a signed + symmetrically-encrypted message, anything in the passph True - True - True - Symmetric encryption/decryption key + True + True + Symmetric encryption/decryption key Max length limited only by available memory @@ -929,17 +927,13 @@ Example: You encrypt a message with your public key + symmetrically with a passp When you go to decrypt said message, you could leave the passphrase box empty (in which case gpg-agent will ask you for your private key passphrase); you could enter the symmetric passphrase you used, or you could enter your private key passphrase (both these options will bypass gpg-agent) False - - 10 - True - etched-in - True - gtk-dialog-authentication - True - False - True - True - Clear entry field + + 10 + True + etched-in + gtk-dialog-authentication + False + Clear entry field @@ -952,7 +946,7 @@ When you go to decrypt said message, you could leave the passphrase box empty (i True - False + False @@ -966,11 +960,11 @@ When you go to decrypt said message, you could leave the passphrase box empty (i True False - False + False _Recipients: - True - True - entry_recip + True + True + entry_recip False @@ -981,23 +975,19 @@ When you go to decrypt said message, you could leave the passphrase box empty (i True - True - True - Keys to use for asymmetric encryption + True + True + Keys to use for asymmetric encryption Use a semicolon to separate recipients - - 10 - True - etched-in - True - False - gtk-orientation-portrait - True - False - True - True - Clear entry field + + 10 + True + etched-in + False + gtk-orientation-portrait + False + Clear entry field @@ -1010,20 +1000,20 @@ Use a semicolon to separate recipients Enc. To Se_lf - False + False True False - True - False - True - Tells gpg to encrypt the message with the public key that corresponds to the first secret key in your keyring + True + False + False + True + Tells gpg to encrypt the message with the public key that corresponds to the first secret key in your keyring This is done in addition to any other recipients, or if in Advanced mode and performing symmetric encryption with a passphrase, then in addition to that Note for power users: if "Change Default Key" in the signature options toolbar is enabled, the contents of its entry box are used as self, instead of the first secret key in your keyring - True - False - True + True + True False @@ -1035,7 +1025,7 @@ Note for power users: if "Change Default Key" in the signature options toolbar i True - False + False @@ -1048,10 +1038,10 @@ Note for power users: if "Change Default Key" in the signature options toolbar i True - False + False _Cipher: - True - combobox_cipher + True + combobox_cipher False @@ -1062,9 +1052,10 @@ Note for power users: if "Change Default Key" in the signature options toolbar i True - False - True - [Not used when decrypting, verifying in gpg mode] + False + False + True + [Not used when decrypting, verifying in gpg mode] Configures symmetric encryption cipher algorithm @@ -1077,7 +1068,6 @@ This is used for both encryption and decryption in openssl-mode When decrypting, openssl needs to be told what cipher the input was encrypted with (unlike gpg) liststore_ciphers 0 - False @@ -1103,21 +1093,21 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi True - True + True 522 - True + True True - False + False True - False + False True - False + False False @@ -1127,19 +1117,19 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi - False + False True - True - True - True - Open text file in Message area + True + False + True + True + Open text file in Message area none - False True - False + False gtk-open @@ -1152,19 +1142,19 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi - False + False True - True - True - True - Save Message to text file + True + False + True + True + Save Message to text file none - False True - False + False gtk-save-as @@ -1177,19 +1167,19 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi - False + False True - True - True - True - Copy Message to clipboard + True + False + True + True + Copy Message to clipboard none - False True - False + False gtk-select-all @@ -1203,7 +1193,7 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi True - False + False False @@ -1214,21 +1204,21 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi - False + False True False - True - True - True - Undo the last action in Message area + True + False + True + True + Undo the last action in Message area none - False - top + top True - False + False gtk-undo @@ -1241,21 +1231,21 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi - False + False True False - True - True - True - Redo the last undone action in Message area + True + False + True + True + Redo the last undone action in Message area none - False - top + top True - False + False gtk-redo @@ -1277,33 +1267,33 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi True - False - 3 - 0 + False + 3 + 0 True - False + False True - True + True True - False + False True - False - True - Choose input file to pass directly to gpg/openssl instead of loading into Message area + False + False + True + Choose input file to pass directly to gpg/openssl instead of loading into Message area This is the way to go when dealing with binary or very large files Drag/drop of files onto this button is supported BUGALERT: The first drag/drop after opening Pyrite will not work! -- do it a 2nd time and all will be fine - False Choose gpg input file... @@ -1317,7 +1307,7 @@ BUGALERT: The first drag/drop after opening Pyrite will not work! -- do it a 2nd True - False + False @@ -1330,13 +1320,14 @@ BUGALERT: The first drag/drop after opening Pyrite will not work! -- do it a 2nd Generate _Text Output - False + False True False - True - False - True - [Not used when decrypting, verifying in gpg-mode] + True + False + False + True + [Not used when decrypting, verifying in gpg-mode] Tells gpg/openssl to output plaintext instead of binary data when encrypting and signing @@ -1347,10 +1338,9 @@ When operating on files directly, this is set based on whether the file is detec OpenSSL Note: This is used for both encryption and decryption in openssl-mode When decrypting, openssl needs to know if the input is base64 or binary (unlike gpg), so when decrypting files in openssl mode, just let Pyrite auto-detect the input file type and auto-set this toggle appropriately - True - False + True True - True + True False @@ -1364,10 +1354,10 @@ When decrypting, openssl needs to know if the input is base64 or binary (unlike True - False + False Inp_ut File For Direct Operation - True - expander_filemode + True + expander_filemode @@ -1377,14 +1367,14 @@ When decrypting, openssl needs to know if the input is base64 or binary (unlike False True - end + end 0 True - False + False @@ -1392,25 +1382,23 @@ When decrypting, openssl needs to know if the input is base64 or binary (unlike False True - end + end 1 True - True - automatic - automatic + True True - True - True - True - Type or paste input text here + True + True + True + Type or paste input text here Drag/drop of text files also supported - word + word @@ -1418,7 +1406,7 @@ Drag/drop of text files also supported True True - end + end 2 @@ -1427,11 +1415,11 @@ Drag/drop of text files also supported True - False + False <i>Message _Input/Output</i> - True - True - textview1 + True + True + textview1 @@ -1450,22 +1438,20 @@ Drag/drop of text files also supported True - False - 3 - 0 + False + 3 + 0 True - True - automatic - automatic + True True False - True - word - False + True + word + False @@ -1473,10 +1459,10 @@ Drag/drop of text files also supported True - False + False <i>Task Status</i> - True - True + True + True @@ -1495,12 +1481,12 @@ Drag/drop of text files also supported True - False + False 1 True - False + False False @@ -1512,20 +1498,20 @@ Drag/drop of text files also supported Add Si_gnature: - False + False True False - True - False - True - [Not used when decrypting, verifying] + True + False + False + True + [Not used when decrypting, verifying] Tells gpg to use your secret key to sign the input This will likely require you to interact with gpg-agent - True - False - True + True + True @@ -1537,9 +1523,10 @@ This will likely require you to interact with gpg-agent False - False - True - [Not used when decrypting, verifying] + False + False + True + [Not used when decrypting, verifying] This allows you to choose the signature type for signing in Sign/Verify mode @@ -1553,7 +1540,6 @@ Detached: Creates a separate signature that does not contain the message -- in order to verify a message/file that has a detached signature, you will need to ensure the message and signature are both in files (with the same name, except for the extra extension of the sig file) in the same directory liststore_sigmodes 0 - False @@ -1571,7 +1557,7 @@ Creates a separate signature that does not contain the message -- in order to ve True - False + False @@ -1583,10 +1569,10 @@ Creates a separate signature that does not contain the message -- in order to ve - False + False D_igest: - True - combobox_digest + True + combobox_digest False @@ -1596,16 +1582,16 @@ Creates a separate signature that does not contain the message -- in order to ve - False - True - [Not used when decrypting, verifying] + False + False + True + [Not used when decrypting, verifying] Configures message digest algorithm (used for hashing message, i.e., creating your signature) With "Default", gpg decides the algorithm based on local system settings, weighing them against the preferences of your secret key liststore_digest 0 - False @@ -1623,7 +1609,7 @@ With "Default", gpg decides the algorithm based on local system settings, weighi True - False + False @@ -1636,17 +1622,17 @@ With "Default", gpg decides the algorithm based on local system settings, weighi Change Default _Key: - False + False True - True - False - True - Tell gpg which secret key to use -- under common circumstances, this will only affect: (1) signing; (2) the calculation of "self" when using the "Enc. To Self" feature + True + False + False + True + Tell gpg which secret key to use -- under common circumstances, this will only affect: (1) signing; (2) the calculation of "self" when using the "Enc. To Self" feature This is only useful if you have multiple secret keys in your keyring - True - False - True + True + True @@ -1657,23 +1643,19 @@ This is only useful if you have multiple secret keys in your keyring - True - True - Key identifier of the non-default key to use for signing + True + True + Key identifier of the non-default key to use for signing Input is passed to gpg "--local-user" option - - 11 - True - etched-in - True - False - gtk-orientation-portrait - True - False - True - True - Clear entry field + + 11 + True + etched-in + False + gtk-orientation-portrait + False + Clear entry field @@ -1693,11 +1675,11 @@ Input is passed to gpg "--local-user" option True - False + False - 16 - False + 16 + False False @@ -1709,7 +1691,7 @@ Input is passed to gpg "--local-user" option True - False + False True diff --git a/ui/preferences.glade b/ui/preferences.glade index e85d77d..a86ac7a 100644 --- a/ui/preferences.glade +++ b/ui/preferences.glade @@ -1,34 +1,33 @@ - - + 2 50 - 1 - 4 + 1 + 4 2 100 - 1 - 4 + 1 + 4 1 100 100 - 1 - 4 + 1 + 4 True - False + False gtk-justify-fill True - False + False gtk-justify-fill @@ -128,13 +127,10 @@ - gpg2 + gpg - gpg - - - openssl + openssl @@ -187,48 +183,48 @@ - False - 12 + False + 12 Pyrite Preferences - center - True - dialog + center + True + dialog True - False + False 12 True - True + True True - False + False True - False - 8 - 5 - 6 + False + 8 + 5 + 6 True - False + False - 2 - 3 - - 10 + 2 + 3 + + 10 True - False + False liststore_major_opmodes @@ -238,32 +234,32 @@ - 4 - 5 - GTK_FILL - - 10 + 4 + 5 + GTK_FILL + + 10 True - False - 0 + False Operation Mode: - True + True + 0 - 3 - 4 - GTK_FILL - + 3 + 4 + GTK_FILL + True - False + False liststore_engines @@ -273,24 +269,24 @@ - 1 - 2 - GTK_FILL - + 1 + 2 + GTK_FILL + True - False - 0 + False Backend Engine Primary Choice: - True + True + 0 - GTK_FILL - - 10 + GTK_FILL + + 10 @@ -303,7 +299,7 @@ True - False + False False @@ -314,106 +310,106 @@ True - False + False True - False + False True - False - 8 - 5 - 2 - 6 - 6 + False + 8 + 5 + 2 + 6 + 6 Advanced - False + False True - True - False + True + False 0 - True + True - 2 - 2 - 3 - GTK_FILL - - 10 + 2 + 2 + 3 + GTK_FILL + + 10 True - False - 0 + False <b>Encrypt/Decrypt Mode Defaults</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + Encrypt To Self - False + False True - True - False + True + False 0 - True + True - 4 - 5 - GTK_FILL - - 10 + 4 + 5 + GTK_FILL + + 10 Add Signature - False + False True - True - False + True + False 0 - True + True - 1 - 2 - 4 - 5 - GTK_FILL - + 1 + 2 + 4 + 5 + GTK_FILL + True - False + False True - False + False True - False - 0 + False Symmetric Cipher Algorithm: + 0 False @@ -432,7 +428,7 @@ True - False + False liststore_ciphers @@ -449,26 +445,26 @@ - 2 - 3 - 4 - + 2 + 3 + 4 + True - False + False True - False + False True - False - 0 + False Initial Encryption Type: + 0 False @@ -487,7 +483,7 @@ True - False + False liststore_enctypes @@ -505,10 +501,10 @@ - 2 - 1 - 2 - + 2 + 1 + 2 + @@ -521,7 +517,7 @@ True - False + False False @@ -532,45 +528,45 @@ True - False - 8 - 5 - 2 - 6 - 6 + False + 8 + 5 + 2 + 6 + 6 True - False - 0 + False <b>Mode-Independent Defaults</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + True - False - 0 + False Digest Hash Algorithm: + 0 - 1 - 2 - GTK_FILL - - 10 + 1 + 2 + GTK_FILL + + 10 True - False + False liststore_digest @@ -580,75 +576,72 @@ - 1 - 2 - 1 - 2 - GTK_FILL - + 1 + 2 + 1 + 2 + GTK_FILL + Change Default Key: - False + False True - True - False + True + False 0 - True + True - 2 - 3 - GTK_FILL - - 10 + 2 + 3 + GTK_FILL + + 10 True - True - - 13 - True - etched-in - True - False - False - False - True - True + True + + 13 + True + etched-in + False + False + False - 1 - 2 - 2 - 3 - GTK_FILL - + 1 + 2 + 2 + 3 + GTK_FILL + True - False - 0 + False Text Output With Files: + 0 - 3 - 4 - GTK_FILL - - 10 + 3 + 4 + GTK_FILL + + 10 True - False + False liststore_txtoutput @@ -658,31 +651,31 @@ - 1 - 2 - 3 - 4 - GTK_FILL - + 1 + 2 + 3 + 4 + GTK_FILL + Expand Input File Expander - False + False True - True - False + True + False 0 - True + True - 2 - 4 - 5 - GTK_FILL - - 10 + 2 + 4 + 5 + GTK_FILL + + 10 @@ -702,7 +695,7 @@ True - False + False False @@ -713,82 +706,82 @@ True - False + False True - False - 8 - 4 - 2 - 6 + False + 8 + 4 + 2 + 6 True - False - 0 + False <b>Sign/Verify Mode Defaults</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + Choose Output Filenames - False + False True - True - False + True + False 0 - True + True - 2 - 1 - 2 - GTK_FILL - - 10 + 2 + 1 + 2 + GTK_FILL + + 10 True - False - 0 + False Initial Sign Type For Text: + 0 - 2 - 3 - GTK_FILL - - 10 + 2 + 3 + GTK_FILL + + 10 True - False - 0 + False Initial Sign Type For Files: + 0 - 3 - 4 - GTK_FILL - - 10 + 3 + 4 + GTK_FILL + + 10 True - False + False liststore_sigmodes @@ -798,18 +791,18 @@ - 1 - 2 - 2 - 3 - GTK_FILL - + 1 + 2 + 2 + 3 + GTK_FILL + True - False + False liststore_sigmodes @@ -819,12 +812,12 @@ - 1 - 2 - 3 - 4 - GTK_FILL - + 1 + 2 + 3 + 4 + GTK_FILL + @@ -837,7 +830,7 @@ True - False + False False @@ -848,62 +841,62 @@ True - False - 8 - 7 - 2 - 6 - 6 + False + 8 + 7 + 2 + 6 + 6 True - False - 0 + False <b>Display Options</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + Text Wrapping - False + False True - True - False + True + False 0 - True + True - 2 - 2 - 3 - GTK_FILL - - 10 + 2 + 2 + 3 + GTK_FILL + + 10 True - False + False True - False + False Task Status - False + False True - True - False + True + False 0 - True + True False @@ -922,12 +915,12 @@ Verbose Task Status - False + False True - True - False + True + False 0 - True + True False @@ -938,27 +931,27 @@ - 2 - 1 - 2 - + 2 + 1 + 2 + True - False + False True - False + False 6 True - False - 0 + False Message: + 0 False @@ -969,17 +962,14 @@ True - True - - etched-in - True - False - False - False - True - True + True + + etched-in + False + False + False adj_msgfntsz - True + True True True @@ -1000,14 +990,14 @@ True - False + False 6 True - False - 0 + False Status: + 0 False @@ -1018,17 +1008,14 @@ True - True - - etched-in - True - False - False - False - True - True + True + + etched-in + False + False + False adj_errfntsz - True + True True True @@ -1047,56 +1034,56 @@ - 2 - 5 - 6 - + 2 + 5 + 6 + True - False - 0 + False Font Sizes: + 0 - 2 - 4 - 5 - GTK_FILL - - 10 + 2 + 4 + 5 + GTK_FILL + + 10 Show Opacity Slider - False + False True - True - False + True + False 0 - True + True - 3 - 4 - GTK_FILL - - 10 + 3 + 4 + GTK_FILL + + 10 True - False + False True - False - 0 + False Opacity: + 0 False @@ -1107,17 +1094,14 @@ True - True - - etched-in - True - False - False - False - True - True + True + + etched-in + False + False + False adj_opacity - True + True True @@ -1128,22 +1112,22 @@ - 1 - 2 - 3 - 4 + 1 + 2 + 3 + 4 True - False + False True - False - 0 + False Message Area Colors: + 0 False @@ -1155,16 +1139,16 @@ True - False + False 4 - False + False True - True - True - True - Foreground (Text) + True + True + True + Foreground (Text) Pick a Foreground (Text) Color #000000000000 @@ -1176,12 +1160,12 @@ - False + False True - True - True - True - Background + True + True + True + Background Pick a Background Color #ffffffffffff @@ -1200,11 +1184,11 @@ - 2 - 6 - 7 - GTK_FILL - GTK_FILL + 2 + 6 + 7 + GTK_FILL + GTK_FILL @@ -1233,279 +1217,261 @@ True - False + False Application Startup Defaults - False + False True False - False - 8 - 8 - 2 - 4 - 6 + False + 8 + 8 + 2 + 4 + 6 True - False - 0 + False <b>Custom GnuPG Arguments</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + When Encrypting: - False + False True - True - False + True + False 0 - True + True - 1 - 2 - GTK_FILL - - 12 + 1 + 2 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 1 - 2 - GTK_FILL - + 1 + 2 + 1 + 2 + GTK_FILL + When Decrypting: - False + False True - True - False + True + False 0 - True + True - 2 - 3 - GTK_FILL - - 12 + 2 + 3 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 2 - 3 - GTK_FILL - + 1 + 2 + 2 + 3 + GTK_FILL + When Sign-Only: - False + False True - True - False + True + False 0 - True + True - 3 - 4 - GTK_FILL - - 12 + 3 + 4 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 3 - 4 - GTK_FILL - + 1 + 2 + 3 + 4 + GTK_FILL + When Verifying: - False + False True - True - False + True + False 0 - True + True - 4 - 5 - GTK_FILL - - 12 + 4 + 5 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 4 - 5 - GTK_FILL - + 1 + 2 + 4 + 5 + GTK_FILL + True - False - 0 + False <b>Custom OpenSSL Arguments</b> - True + True + 0 - 2 - 5 - 6 - GTK_FILL - + 2 + 5 + 6 + GTK_FILL + When Encrypting: - False + False True - True - False + True + False 0 - True + True - 6 - 7 - GTK_FILL - - 12 + 6 + 7 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 6 - 7 - GTK_FILL - + 1 + 2 + 6 + 7 + GTK_FILL + True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 7 - 8 - GTK_FILL - + 1 + 2 + 7 + 8 + GTK_FILL + When Decrypting: - False + False True - True - False + True + False 0 - True + True - 7 - 8 - GTK_FILL - - 12 + 7 + 8 + GTK_FILL + + 12 @@ -1516,12 +1482,12 @@ True - False + False Advanced Options 1 - False + False @@ -1534,21 +1500,21 @@ True - False + False True - False - start + False + start Defaults - False + False True - True - True - True - Reset all preferences to built-in defaults + True + True + True + Reset all preferences to built-in defaults image2 @@ -1561,14 +1527,14 @@ gtk-revert-to-saved - False + False True False - True - True - True - Revert all preferences to values set in user preferences file - True + True + True + True + Revert all preferences to values set in user preferences file + True @@ -1590,18 +1556,18 @@ True - False - end + False + end gtk-cancel - False + False True - True - True - True - Cancel without making any changes - True + True + True + True + Cancel without making any changes + True @@ -1613,13 +1579,13 @@ gtk-save - False + False True - True - True - True - Save all settings out to a pref file in your home, but don't change anything in the current session - True + True + True + True + Save all settings out to a pref file in your home, but don't change anything in the current session + True False @@ -1630,13 +1596,13 @@ gtk-apply - False + False True - True - True - True - Save settings to a user pref file and apply them to current session - True + True + True + True + Save settings to a user pref file and apply them to current session + True False @@ -1648,7 +1614,7 @@ False True - end + end 2 @@ -1662,8 +1628,8 @@ True - False - immediate + False + immediate