diff options
Diffstat (limited to 'kgpg')
83 files changed, 16567 insertions, 0 deletions
diff --git a/kgpg/AUTHORS b/kgpg/AUTHORS new file mode 100644 index 0000000..32f771a --- /dev/null +++ b/kgpg/AUTHORS @@ -0,0 +1 @@ +y0k0 <bj@altern.org> diff --git a/kgpg/ChangeLog b/kgpg/ChangeLog new file mode 100644 index 0000000..7cf0cf2 --- /dev/null +++ b/kgpg/ChangeLog @@ -0,0 +1,310 @@ +Version 1.2.1 + +Bugfixes: +-Don't crash on keyserver operation +-Don't mix gpg output comments in decrypted text +-Disabling/enabling a key now works +-Fix some UTF-8 issues +-Setting Trust now works correctly + + +Version 1.2 + +-You can now choose encoding when saving/loading text in editor +-New option to hide/show expired/disabled keys in key manager +-Add color for revoked keys +-Make colors configurable +-Rewrote text signing and decryption processes. +-User can now choose the left click behaviour (open key manager or editor) +-Fixed bug in text encryption (gpg errors were included in encrypted text) +-System tray icon animates itself when KGpg is processing a task +-Added a Tooltip to applet's icon to say if KGpg is busy and what it is doing +-shredding doesn't freeze the ui anymore +-encrypting several files now processes one file after another instead of all at once, keeping the interface much more responsive +-verifying a signed text now tells if the key is trusted or not +-multi file decryption now works +-dropping a signed text over the applet automatically verfies it +-If there is a public key in clipboard, trying to decrypt it asks if user wants to import it +-Can now change the editor font +-Can now store more than 3 keyservers +-added sign clipboard +-added incremental search line in Key Manager and Public Key selection dialog +-allow selecting several key for import in the search results of key server operation +-added entry to open editor from key manager +-fixed popup never disappearing when a wrong passphrase was entered 3 times. +-fixed "import missing key" always disabled with non english languages +-comments exported in public keys should be fixed (I cannot reproduce) +-added statusbar with feedback info + + +Version 1.1 + +-photo id's are now displayed inside the key list view +-support for multiple photo id's +-fixed bug hiding key when user answered no to delete secret key +-improved feedback on key creation +-added select all action to kgpg editor +-fixed utf8 problem with some key names +-fixed problem with quotes when signing from the editor +-revocation certificate: create & print +-animated logo while key creation is in progress +-added a search function to find a key in the keyring +-splitted email & key name in two different columns for easier sorting +-folder encryption (initial support) +-integrate KAddress Book facilities (export key to address book) +-key import gives more infos +-use of gpg-agent can be enabled/disabled from settings dialog +-fixed message after exporting a key to keyserver +-changed default keyservers +-rewrote settings dialog to use kautoconfigdialog +-key signing now lets you select how carefully you checked that the key really belongs to the person +-improved keyserver operations +-when verifying a text/file and signature is missing, ask user to import missing key from keyserver +-new in keymanager: import missing signatures +-changed applet behaviour to follow KDE ui styleguides +-default key & keyserver are now stored in gpg's configuration file. +-moved keyserver management into Kgpg's configuration dialog +-added checkbox to stop asking autostart when user closes kgpg +-added multi file encryption +-toolbar in key manager can now be configured +-added gpg-agent support +-speed up key manager +-fix display of keys with local characters encodings +-added trust color to keymanager +-added option to save files as .pgp instead of .gpg +-new key properties dialog, allows to change expiration, ownertrust, passphrase +-allow multi key operations in keymanager: deleting, exporting and signing of several keys at once is now possible + + +Version 1.0.0 +-fixed message box when verifying a signature with a non english gpg +-only one key manager can now be opened (Olivier Goffart) +-fixed orphaned gpg threads when opening private key selection dialog +-fixed crash on remote file drops +-added warning on remote file decryption +-fix decryption of non ascii armored files in kgpg's editor +-fix deletion of temporary files created when dropping remote files in KGpg +-added honor-http-proxy to keyserver dialog to allow passing through firewalls (Fabian Wenzel <f.wenzel@gmx.net>) + +version 0.9.5 +-added keyboard shortcuts to key manager +-added popup dialog indicating that a file en/decryption is in progress +-added "on the fly" custom option for encryption +-rewrote & improved (speed, security) enc/decryption/signing functions +-fixed bugs in keyserver searching (display of mail adresses, command lines interpreted as keys) +-rearranged option dialog +-fixed special characters problem in key generation wizard +-fixed bug preventing servicemenus to appear on some systems +-when encryption/decryption fails, you can now see the log output in an error box +-fixed problem when opening a public key +-hide expired secret keys from encryption/signing selection dialog +-new icons based on icons from malte_gell@t-online.de (Malte Gell) +-many small GUI improvements +-kgpg has now been turned to a system tray applet + + +version 0.9.4 + +-fixed crash when decrypting from Kgpg's editor file menu +-added GUI keyserver support (manage keyserver, key import/export/search) +-show photo/toolbar in key manager is now saved & restored +-new command line mode to open keyserver dialog +-fixed problems with keys having no e-mail adress +-new button to show/hide options in the key selection dialog +-added gpg option to hide user id in encrypted blocks +-fixed small bug preventing key generation with expiration date in years + +version 0.9.3 + +-automatic mimetype detection & installation (for encrypted files and signature files) +-new in options dialog: easy install/remove of service menus to sign / decrypt a file +-new command line mode to verify a signature: Left click on a .sig file to check signature validity +-fixed clipboard encryption +-disabled html display in Kgpg's editor +-a few small bugfixes +-password length for a new key must now be greater than 5 characters. +-in decryption dialog, password only ask for keys for which you have a secret key. +-fixed error message appearing when encryption was successful +-fixed key export (export failed in some cases) + +version 0.9.2 + +-fixed bug preventing encryption when several options were checked +-fixed signing of keys whith expiration date +-some keys (created with pgp 7.x) were not displayed in Key manager. fixed +-added new config options: add/remove decrypt menu, choose between displaying E-Mail or Key name first in lists + +version 0.9.1.1 + +-fixed bug preventing correct encryption of texts with " (Olivier Goffart <ogoffart@tiscalinet.be>) + +version 0.9.1 + +-compilation fixes +-corrected file extension with ASCII encryption (now is .asc) +-Kgpg now listens to GnuPG's status messages, which greatly improves reliability +-signing keys and signature deletion can now be performed through GUI +-Drag & Drop support in key manager: drop a key to import, drag a key into a text editor or on your desktop to export +-Support for Photo ID +-now displays signatures revocation certificates +-many small improvements/fixes +-fixed bug preventing secret key export + +version 0.9 + +-fixed security bug in key generation wizard +-fixed detection of file shredding results +-rewrote key manager & key selection dialog +-MD5 sum checking rewritten for easier use +-centralised all encrypt/decrypt functions into one library file (kgpginterface) for easy reuse +-fixed bug with filenames containing whitespaces +-key manager can now be used as a standalone application +-added new -s 'filename' option on command line to decrypt a file & open it in kgpg +-added italian translation + +version 0.8.2 + +-fixed debian rules permissions +-fixed makefile for installation in a user chosen directory + +version 0.8.1 + +-fixed compilation bug + +version 0.8 + +-i18n fixes +-added option to send key by e-mail in export key dialog +-added new option to easily decrypt clipboard content -> kgpg can be added as a + klipper action (see kgpg's handbook for more infos about activating this option) +-added support for symetrical encryption for files +-corrected bug when kgpg was called from konqueror (when left-clicking on a gpg file, + kgpg did not always close itself correctly after file decryption) +-removed "decrypt file" entry in konqueror service menu. Now, use left-click or "Open + with kgpg" on an encrypted file to decrypt. +-added a Handbook (documentation) +-fixed Makefile + added files for debian compilation (thanks Ralf Nolden <nolden@kde.org>) +-added option to Edit a key (console mode) in key management +-added a link to GnuPG man page in help menu + +version 0.7: + +-fixed tips database installation (hopefully) +-pgp compatibility: --pgp6 is now used if gpg version>=1.2.0 +-code cleanup +-many small usability bugfixes +-added "sign/verify" button to clearsign/verify a text in the editor +-corrected lots of bugs in the way "new file", "save" and "save as" behaved +-added "save as" icon in toolbar +-switched display of key id's to short id's for more convenience +-only trusted keys can now be set to default key + + +version 0.6.1: + +-corrected a compilation problem with KDE prior to KDE 3.1 beta + + +version 0.6: + +-default key is now in bold +-signing a key now asks if you want your signature to be exportable +-md5 checksum now uses gpg instead of md5sum +-key info now tells if a signature is local or not, and if there is a subkey +-new encryption option for pgp 5.x compatibility +-various crash fixes (mostly related to the default options dialog) +-new dialog for key generation, automatically pops up on first run if no key is found. +-made ready for internationalization. added french & german translation (courtesty Christoph +Thielecke <crissi99@gmx.de> +-added KTips + +version 0.5.1 + +-fixed bug preventing secret key import +-fixed messy code preventing key signing + + +version 0.5 + +-fixed possible crash with key names containing "pub" +-default keys are now displayed with a red icon +-expired/revoked key are now hidden from encryption dialog +-untrusted keys are now hidden when required +-added new configuration icon +-most key operation are now based on key id and not on email adress, which should solve problems +with same name keys + + +version 0.4.3 + +-speed improvements +-encryption/decryption from konqueror is more straightforward +-ability to define special key for file encryption +-enable default key definition to ensure messages are also encrypted with your key +-you now have 3 trials in case you type a wrong passphrase +-fixed possible crash when no key selected for encryption +-fixed multi key encryption bug +-added what's this help texts in main dialogs + + +version 0.4.2 + +-you can now choose location to export a public key +-key management window now displays the key owner name in statusbar +-key info now displays key type (RSA, DSA, ...) +-fixed crash when decrypting message encrypted with several keys +-allow encryption with multiple keys + +version 0.4.1: + +-Bugfix release: +-corrected error when encrypting a text with "$" from the editor +-refresh key list after key generation +-you can now choose a location for decrypting a file + +version 0.4 + +-Big changes: +-kgpg can now be used from inside konqueror using a new menu entry allowing you to encrypt/decrypt +files. +-dropped file mode. All file operations can now be performed through konqueror +-a few minor improvements & code cleaning + + +version 0.3.1 +-Added option to shred source file after encryption +-File signature options: Create a detached signature, verify a signed file, checking file MD5 sum +-added icons in keys lists, toolbar & popup menu in key management window. +-export secret key + + +version 0.3 +-Drag&drop now works !!! You can drop local or REMOTE text files in the editor to have them +decrypted automatically +-More infos on keys: now displays key signatures, key ID,... +-New key managment features: enables you to sign keys and generate new keys. +-Some minor improvements +-New icon + +version 0.2.1 + +-In the file browser, you can now double click on a file to encrypt/decrypt it +-You can drag a file in the editor window to open/decrypt it +-Now displays keys trust and validity +-New option to allow encryption with untrusted keys +-Choose if you want armored encryption or not +-Export your public keys +-And many small interface improvements + +version 0.2 + +-Completeley rewrote GUI +-bugfix for messages > 130 characters +-added import/delete keys +-new file mode to encrypt/decrypt files +-ability to open/save files from the editor + + +version 0.1 + +-initial release diff --git a/kgpg/INSTALL b/kgpg/INSTALL new file mode 100644 index 0000000..f895580 --- /dev/null +++ b/kgpg/INSTALL @@ -0,0 +1,160 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code + 2. ./configure + 3. make + 4. make install (as root) + +To uninstall: make uninstall + +You can remove the program binaries and object files from the + source code directory by typing `make clean'. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/kgpg/Makefile.am b/kgpg/Makefile.am new file mode 100644 index 0000000..6b1628d --- /dev/null +++ b/kgpg/Makefile.am @@ -0,0 +1,46 @@ +SUBDIRS = icons +bin_PROGRAMS = kgpg + +## INCLUDES were found outside kdevelop specific part + +INCLUDES = $(all_includes) + +kgpg_SOURCES = kgpgoptions.cpp listkeys.cpp popuppublic.cpp kgpgview.cpp \ + kgpg.cpp main.cpp keygener.cpp kgpginterface.cpp keyservers.cpp keyserver.ui \ + searchres.ui kgpgeditor.cpp detailedconsole.cpp kgpglibrary.cpp kgpgwizard.ui \ + keyproperties.ui conf_encryption.ui conf_decryption.ui conf_gpg.ui dcopiface.skel \ + keyinfowidget.cpp groupedit.ui kgpgrevokewidget.ui newkey.ui adduid.ui keyexport.ui \ + sourceselect.ui kgpgsettings.kcfgc conf_servers.ui conf_ui2.ui conf_misc.ui +kgpg_LDADD = $(LIB_KIO) $(LIB_KABC) -lkutils -lkdeprint + +pics_DATA= kgpg_anim.gif kgpg_docked.png kgpg_docked.gif kgpg_blank.png kgpg_fill.png +picsdir=$(kde_datadir)/kgpg/pics + +servicedir = $(kde_datadir)/konqueror/servicemenus +service_DATA = encryptfile.desktop encryptfolder.desktop + +autostartdir = $(datadir)/autostart +autostart_DATA = kgpg.desktop + +xdg_apps_DATA = kgpg.desktop +kde_kcfg_DATA = kgpg.kcfg + +METASOURCES = AUTO + +# the library search path. +kgpg_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +appsdir = $(kde_datadir)/kgpg +apps_DATA = kgpg.rc listkeys.rc tips + +KDE_ICON = kgpg + +messages: rc.cpp + $(PREPARETIPS) > tips.cpp + LIST=`find . -name \*.h -o -name \*.hh -o -name \*.H -o -name \*.hxx -o -name \*.hpp -o -name \*.cpp -o -name \*.cc -o -name \*.cxx -o -name \*.ecpp -o -name \*.C`; \ + if test -n "$$LIST"; then \ + $(XGETTEXT) $$LIST -o $(podir)/kgpg.pot; \ + fi + rm -f tips.cpp + + diff --git a/kgpg/adduid.ui b/kgpg/adduid.ui new file mode 100644 index 0000000..b7e5b1b --- /dev/null +++ b/kgpg/adduid.ui @@ -0,0 +1,64 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>AddUid</class> +<widget class="QWidget"> + <property name="name"> + <cstring>AddUid</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>357</width> + <height>170</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KLineEdit" row="1" column="0"> + <property name="name"> + <cstring>kLineEdit1</cstring> + </property> + </widget> + <widget class="KLineEdit" row="3" column="0"> + <property name="name"> + <cstring>kLineEdit2</cstring> + </property> + </widget> + <widget class="KLineEdit" row="5" column="0"> + <property name="name"> + <cstring>kLineEdit3</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Name (minimum 5 characters):</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Email:</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Comment (optional):</string> + </property> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kgpg/conf_decryption.ui b/kgpg/conf_decryption.ui new file mode 100644 index 0000000..bec30e9 --- /dev/null +++ b/kgpg/conf_decryption.ui @@ -0,0 +1,69 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>Decryption</class> +<widget class="QWidget"> + <property name="name"> + <cstring>Decryption</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>388</width> + <height>233</height> + </rect> + </property> + <property name="caption"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KLineEdit" row="1" column="0"> + <property name="name"> + <cstring>kcfg_CustomDecrypt</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer3_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>155</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1_4_2</cstring> + </property> + <property name="text"> + <string>Custom decryption command:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Custom Decryption Command:</b><br /> + <p>This option allows the user to specify a custom command to be executed by GPG when decryption occurs. (This is recommended for advanced users only).</p> + </qt></string> + </property> + </widget> + </grid> +</widget> +<slots> + <slot>use_agent_toggled( bool isOn )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kgpg/conf_encryption.ui b/kgpg/conf_encryption.ui new file mode 100644 index 0000000..c4d9f7f --- /dev/null +++ b/kgpg/conf_encryption.ui @@ -0,0 +1,321 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>Encryption</class> +<author>bj@altern.org</author> +<widget class="QWidget"> + <property name="name"> + <cstring>Encryption</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>538</width> + <height>389</height> + </rect> + </property> + <property name="caption"> + <string>Encryption</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kcfg_PgpCompatibility</cstring> + </property> + <property name="text"> + <string>PGP 6 compatibility</string> + </property> + <property name="accel"> + <string>Alt+6</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>PGP 6 compatibility:</b><br /> + <p>Checking this option forces GnuPG to output encrypted packets that are as compliant with PGP (Pretty Good Privacy) 6 standards as possible thus allowing GnuPG users to inter operate with PGP 6 users.</p></qt></string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kcfg_AsciiArmor</cstring> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>ASCII armored encryption</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>ASCII armored encryption:</b> <br /> + <p>Checking this option outputs all encrypted files in a format that can be opened by a text editor and as such the output is suitable for placing in the body of an e-mail message.</p></qt></string> + </property> + </widget> + <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kcfg_HideUserID</cstring> + </property> + <property name="text"> + <string>Hide user id</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Hide user ID:</b><br /> + <p>Checking this option will remove the keyid of the recipient from all encrypted packets. The advantage: traffic analysis of the encrypted packets cannot be performed as easily because the recipient is unknown. The disadvantage: the receiver of the encrypted packets is forced to try all secret keys before being able to decrypt the packets. This can be a lengthy process depending on the number of secret keys the receiver holds.</p></qt></string> + </property> + </widget> + <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kcfg_ShredSource</cstring> + </property> + <property name="text"> + <string>Shred source file</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Shred source file:</b><br /> + <p>Checking this option will shred (overwrite several times before erasing) the files you have encrypted. This way, it is almost impossible that the source file is recovered. But <b>you must be aware that this is not 100% secure</b> on all file systems, and that parts of the file may have been saved in a temporary file or in the spooler of your printer if you previously opened it in an editor or tried to print it. Only works on files (not on folders).</p></qt></string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kcfg_AllowUntrustedKeys</cstring> + </property> + <property name="text"> + <string>Allow encryption with untrusted keys</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Allow encryption with untrusted keys:</b> <br /> + <p>When importing a public key, the key is usually marked as untrusted and as such cannot be used unless it is signed by the default key (Thus, making it 'trusted'). Checking this box enables any key to be used even if it is untrusted.</p></qt></string> + </property> + </widget> + <spacer row="9" column="0"> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>72</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="7" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_AllowCustomEncryptionOptions</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Custom encryption command:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Custom encryption command:</b> <br /> + <p>When activated, an entry field will be shown in the key selection dialog, enabling you to enter a custom command for encryption. This option is recommended for experienced users only.</p></qt></string> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>kcfg_CustomEncryptionOptions</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox" row="8" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kcfg_PgpExtension</cstring> + </property> + <property name="text"> + <string>Use *.pgp extension for encrypted files</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Use *.pgp extension for encrypted files:</b><br /> + <p>Checking this option will append a .pgp extension to all encrypted files instead of a .gpg extension. This option will maintain compatibility with users of PGP (Pretty Good Privacy) software.</p></qt></string> + </property> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Encrypt files with:</string> + </property> + </widget> + <widget class="KLineEdit" row="6" column="1"> + <property name="name"> + <cstring>kcfg_FileKey</cstring> + </property> + <property name="frameShape"> + <enum>Panel</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Encrypt files with:</b><br /> +<p>Checking this option and selecting a key will force any file encryption operation to use the selected key. KGpg will not query for a recipient and the default key will be bypassed.</p></qt></string> + </property> + </widget> + <widget class="QToolButton" row="6" column="2"> + <property name="name"> + <cstring>clear_fkey</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + <widget class="KPushButton" row="6" column="3"> + <property name="name"> + <cstring>change_fkey</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Change...</string> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Always encrypt with:</string> + </property> + </widget> + <widget class="KLineEdit" row="5" column="1"> + <property name="name"> + <cstring>alwaysKey</cstring> + </property> + <property name="frameShape"> + <enum>Panel</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Always encrypt with:</b><br /> +<p>This ensures all files/messages will also be encrypted with the chosen key. However, if the "Encrypt files with:" option is selected that chosen key will override the "Always encrypt with:" selection.</p></qt></string> + </property> + </widget> + <widget class="KPushButton" row="5" column="3"> + <property name="name"> + <cstring>change_akey</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Change...</string> + </property> + </widget> + <widget class="QToolButton" row="5" column="2"> + <property name="name"> + <cstring>clear_akey</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>kcfg_AllowCustomEncryptionOptions</sender> + <signal>toggled(bool)</signal> + <receiver>Encryption</receiver> + <slot>allow_custom_option_toggled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>kcfg_AsciiArmor</tabstop> + <tabstop>kcfg_AllowUntrustedKeys</tabstop> + <tabstop>kcfg_PgpCompatibility</tabstop> + <tabstop>kcfg_HideUserID</tabstop> + <tabstop>kcfg_ShredSource</tabstop> + <tabstop>alwaysKey</tabstop> + <tabstop>change_akey</tabstop> + <tabstop>kcfg_FileKey</tabstop> + <tabstop>change_fkey</tabstop> + <tabstop>kcfg_AllowCustomEncryptionOptions</tabstop> + <tabstop>kcfg_CustomEncryptionOptions</tabstop> + <tabstop>kcfg_PgpExtension</tabstop> +</tabstops> +<includes> + <include location="local" impldecl="in implementation">conf_encryption.ui.h</include> +</includes> +<slots> + <slot>allow_custom_option_toggled( bool isOn )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kgpg/conf_encryption.ui.h b/kgpg/conf_encryption.ui.h new file mode 100644 index 0000000..15310b6 --- /dev/null +++ b/kgpg/conf_encryption.ui.h @@ -0,0 +1,22 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ + + +void Encryption::allow_custom_option_toggled( bool isOn) +{ +kcfg_CustomEncryptionOptions->setEnabled(isOn); +} diff --git a/kgpg/conf_gpg.ui b/kgpg/conf_gpg.ui new file mode 100644 index 0000000..9cbf931 --- /dev/null +++ b/kgpg/conf_gpg.ui @@ -0,0 +1,219 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>GPGConf</class> +<widget class="QWidget"> + <property name="name"> + <cstring>GPGConf</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>550</width> + <height>315</height> + </rect> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Global Settings:</b><br /> + <p></p> + </qt></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>GnuPG Home</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1_5_2</cstring> + </property> + <property name="text"> + <string>Configuration file:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_5_2_2</cstring> + </property> + <property name="text"> + <string>Home location:</string> + </property> + </widget> + <widget class="KLineEdit" row="0" column="1"> + <property name="name"> + <cstring>gpg_conf_path</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>Panel</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton" row="1" column="3"> + <property name="name"> + <cstring>changeHome</cstring> + </property> + <property name="text"> + <string>Change...</string> + </property> + </widget> + <widget class="KLineEdit" row="1" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>gpg_home_path</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>Panel</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <spacer row="0" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>190</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <spacer row="3" column="0"> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>54</height> + </size> + </property> + </spacer> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>use_agent</cstring> + </property> + <property name="text"> + <string>&Use GnuPG agent</string> + </property> + </widget> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>groupBox2_2</cstring> + </property> + <property name="title"> + <string>Additional Keyring</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>kcfg_PubKeyring</cstring> + </property> + <property name="text"> + <string>Pu&blic:</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>kcfg_PrivKeyring</cstring> + </property> + <property name="text"> + <string>Private:</string> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="1" rowspan="2" colspan="1"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KURLRequester"> + <property name="name"> + <cstring>kcfg_PubKeyringUrl</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>kcfg_PrivKeyringUrl</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </vbox> + </widget> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>kcfg_OnlyAdditional</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Use only this keyring</string> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kgpg/conf_misc.ui b/kgpg/conf_misc.ui new file mode 100644 index 0000000..bfeb9c8 --- /dev/null +++ b/kgpg/conf_misc.ui @@ -0,0 +1,413 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>MiscConf</class> +<widget class="QWidget"> + <property name="name"> + <cstring>MiscConf</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>454</width> + <height>334</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>miscWidget</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Global Settings</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>kcfg_AutoStart</cstring> + </property> + <property name="text"> + <string>Start KGpg automatically at login</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Start KGpg automatically at KDE startup:</b><br /> +<p>If checked KGpg will start automatically each time that KDE starts up.</p></qt></string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>kcfg_UseMouseSelection</cstring> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Use mouse selection instead of clipboard</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Use mouse selection instead of clipboard:</b> <br /> + <p>If checked, clipboard operations in KGpg will use the selection clipboard, that means highlighting a text to copy, and middle button (or right+left together) to paste. If this option is not checked, the clipboard will work with Key shortcuts (Ctrl-c, Ctrl-v).</p></qt> </string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0"> + <property name="name"> + <cstring>kcfg_RemoteFileWarn</cstring> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Display warning before creating temporary files +(only occurs on remote files operations)</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Display warning before creating temporary files:</b><br /> + <p></p></qt></string> + </property> + </widget> + <widget class="QGroupBox" row="3" column="0"> + <property name="name"> + <cstring>groupShred</cstring> + </property> + <property name="title"> + <string>Shredder</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>91</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>pushShredder</cstring> + </property> + <property name="text"> + <string>Install Shredder</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>KGpg allows you to create a shredder on your desktop. +It will shred (overwrite several times before erasing) the +files you drop on it, making it almost impossible to recover +the original file.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignJustify|AlignTop</set> + </property> + </widget> + <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>shredInfo</cstring> + </property> + <property name="text"> + <string>textLabel5</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + </grid> + </widget> + <spacer row="4" column="0"> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>71</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>Applet && Menus</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Left mouse click opens (restart KGpg to apply):</string> + </property> + </widget> + <widget class="QComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>Key Manager</string> + </property> + </item> + <item> + <property name="text"> + <string>Editor</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_LeftClick</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <spacer row="3" column="0"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>91</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>groupBox11</cstring> + </property> + <property name="title"> + <string>Konqueror Service Menus</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Sign file service menu:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Sign file service menu:</b><br /> + <p></p> + </qt></string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Decrypt file service menu:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Decrypt file service menu:</b><br /> + <p></p> + </qt></string> + </property> + </widget> + <widget class="KComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>Disable</string> + </property> + </item> + <item> + <property name="text"> + <string>Enable with All Files</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_SignMenu</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>Disable</string> + </property> + </item> + <item> + <property name="text"> + <string>Enable with All Files</string> + </property> + </item> + <item> + <property name="text"> + <string>Enable with Encrypted Files</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_DecryptMenu</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>System Tray Applet</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1_3_2</cstring> + </property> + <property name="text"> + <string>Event on unencrypted file drop:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Event on unencrypted file drop:</b><br /> + <p></p> + </qt></string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_2_2</cstring> + </property> + <property name="text"> + <string>Event on encrypted file drop:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Event on encrypted file drop:</b><br /> + <p></p> + </qt></string> + </property> + </widget> + <widget class="KComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>Encrypt</string> + </property> + </item> + <item> + <property name="text"> + <string>Sign</string> + </property> + </item> + <item> + <property name="text"> + <string>Ask</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_UnencryptedDropEvent</cstring> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>Decrypt & Save</string> + </property> + </item> + <item> + <property name="text"> + <string>Decrypt & Open in Editor</string> + </property> + </item> + <item> + <property name="text"> + <string>Ask</string> + </property> + </item> + <property name="name"> + <cstring>kcfg_EncryptedDropEvent</cstring> + </property> + </widget> + </grid> + </widget> + </grid> + </widget> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kgpg/conf_servers.ui b/kgpg/conf_servers.ui new file mode 100644 index 0000000..022eca7 --- /dev/null +++ b/kgpg/conf_servers.ui @@ -0,0 +1,118 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ServerConf</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ServerConf</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>427</width> + <height>248</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KPushButton" row="0" column="1"> + <property name="name"> + <cstring>server_default</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Set as Default</string> + </property> + </widget> + <widget class="KPushButton" row="1" column="1"> + <property name="name"> + <cstring>server_add</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Add...</string> + </property> + </widget> + <widget class="KPushButton" row="2" column="1"> + <property name="name"> + <cstring>server_del</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Delete</string> + </property> + </widget> + <widget class="KListBox" row="0" column="0" rowspan="4" colspan="1"> + <property name="name"> + <cstring>ServerBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLayoutWidget" row="4" column="0"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_4</cstring> + </property> + <property name="text"> + <string><b>INFORMATION</b>: +Only the default server will be stored in GnuPG's configuration file, +all others will be stored for use by KGpg only.</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>kcfg_UseProxy</cstring> + </property> + <property name="text"> + <string>Honor HTTP proxy when available</string> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kpushbutton.h</includehint> + <includehint>klistbox.h</includehint> +</includehints> +</UI> diff --git a/kgpg/conf_ui2.ui b/kgpg/conf_ui2.ui new file mode 100644 index 0000000..98e622b --- /dev/null +++ b/kgpg/conf_ui2.ui @@ -0,0 +1,178 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>UIConf</class> +<widget class="QWidget"> + <property name="name"> + <cstring>UIConf</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>541</width> + <height>439</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>tabWidget3</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Key Colors</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton" row="2" column="1"> + <property name="name"> + <cstring>kcfg_ColorUnknown</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel1_3_3</cstring> + </property> + <property name="text"> + <string>Unknown keys:</string> + </property> + </widget> + <widget class="KColorButton" row="1" column="1"> + <property name="name"> + <cstring>kcfg_ColorRev</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>30</red> + <green>30</green> + <blue>30</blue> + </color> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1_4</cstring> + </property> + <property name="text"> + <string>Trusted keys:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel1_4_2</cstring> + </property> + <property name="text"> + <string>Expired/disabled keys:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_2_3</cstring> + </property> + <property name="text"> + <string>Revoked keys:</string> + </property> + </widget> + <widget class="KColorButton" row="3" column="1"> + <property name="name"> + <cstring>kcfg_ColorBad</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>172</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton" row="0" column="1"> + <property name="name"> + <cstring>kcfg_ColorGood</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>144</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + </widget> + <spacer row="4" column="0"> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>210</height> + </size> + </property> + </spacer> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>140</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>Editor Font</string> + </attribute> + </widget> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/kgpg/dcopiface.h b/kgpg/dcopiface.h new file mode 100644 index 0000000..d9b3455 --- /dev/null +++ b/kgpg/dcopiface.h @@ -0,0 +1,35 @@ +/*************************************************************************** + kgpg.h - description + ------------------- + begin : Mon Jul 21 2003 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KGPGDCOPIF_H +#define KGPGDCOPIF_H + +#include <dcopobject.h> + +class KeyInterface : virtual public DCOPObject +{ + K_DCOP + k_dcop: + virtual void showKeyInfo(QString keyID) =0; + virtual bool importRemoteKey(QString keyID)=0; + virtual void showOptions()=0; + virtual void showKeyServer()=0; + virtual void showKeyManager()=0; +}; + +#endif // KGPGDCOPIF_H + diff --git a/kgpg/detailedconsole.cpp b/kgpg/detailedconsole.cpp new file mode 100644 index 0000000..985ca01 --- /dev/null +++ b/kgpg/detailedconsole.cpp @@ -0,0 +1,65 @@ +/*************************************************************************** + detailledconsole.cpp - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include <qlayout.h> +#include <qlabel.h> +#include <qvgroupbox.h> +#include <qtextedit.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <klistbox.h> +#include <kglobal.h> + +#include "kgpgoptions.h" +#include "detailedconsole.h" + + +KDetailedConsole::KDetailedConsole(QWidget *parent, const char *name,const QString &boxLabel,const QString &errormessage) + : KDialogBase(parent,name,true,i18n("Sorry"),KDialogBase::Details|KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok) +{ + QWidget *page = new QWidget( this ); + setMainWidget(page); + QVBoxLayout *vbox=new QVBoxLayout(page,0, spacingHint() ); + + QLabel *lab1=new QLabel(page); + lab1->setText(boxLabel); + + QVGroupBox *detailsGroup = new QVGroupBox( i18n("Details"), page); + (void) new QLabel(errormessage,detailsGroup); + //labdetails->setMinimumSize(labdetails->sizeHint()); + setDetailsWidget(detailsGroup); + vbox->addWidget(lab1); + +} + +KDetailedConsole::~KDetailedConsole() +{} + +KDetailedInfo::KDetailedInfo(QWidget *parent, const char *name , const QString &boxLabel,const QString &errormessage,QStringList keysList) + : KDialogBase(Swallow, i18n("Info"),KDialogBase::Details|KDialogBase::Ok, KDialogBase::Ok,parent,name,true) +{ + bool checkboxResult; + KMessageBox::createKMessageBox(this, QMessageBox::Information, + boxLabel, keysList,QString::null,&checkboxResult, 0,errormessage); +} + +KDetailedInfo::~KDetailedInfo() +{} + +//#include "detailedconsole.moc" diff --git a/kgpg/detailedconsole.h b/kgpg/detailedconsole.h new file mode 100644 index 0000000..5d0e669 --- /dev/null +++ b/kgpg/detailedconsole.h @@ -0,0 +1,43 @@ +/*************************************************************************** + detailledconsole.h - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KDETAILED_H +#define KDETAILED_H + +#include <kdialogbase.h> + +class KDetailedConsole : public KDialogBase +{ +public: + + KDetailedConsole(QWidget *parent=0, const char *name=0,const QString &boxLabel=QString::null,const QString &errormessage=QString::null); + ~KDetailedConsole(); + +}; + + +class KDetailedInfo : public KDialogBase +{ +public: + + KDetailedInfo(QWidget *parent=0, const char *name=0,const QString &boxLabel=QString::null,const QString &errormessage=QString::null,QStringList keysList=QStringList()); + ~KDetailedInfo(); + +}; + +#endif // KDETAILED_H + diff --git a/kgpg/encryptfile.desktop b/kgpg/encryptfile.desktop new file mode 100644 index 0000000..c117c30 --- /dev/null +++ b/kgpg/encryptfile.desktop @@ -0,0 +1,62 @@ +[Desktop Entry] +ServiceTypes=all/allfiles +ExcludeServiceTypes=kdedevice/* +Actions=encrypt + +[Desktop Action encrypt] +Name=Encrypt File +Name[ar]=تشفير ملف +Name[bg]=Шифроване на файл +Name[br]=E&nrinegañ ar restr +Name[bs]=Šifriraj datoteku +Name[ca]=Xifra fitxer +Name[cs]=Zašifrovat soubor +Name[cy]=Cêl-ysgrifo Ffeil +Name[da]=Indkod fil +Name[de]=Datei verschlüsseln +Name[el]=Κρυπτογράφηση αρχείου +Name[eo]=Ĉifri dosieron +Name[es]=Cifrar archivo +Name[et]=Krüpti fail +Name[eu]=Fitxategiak Zifratu +Name[fa]=رمزبندی پرونده +Name[fi]=Salaa tiedosto +Name[fr]=Chiffrer le fichier +Name[ga]=Criptigh Comhad +Name[he]=הצפן קובץ +Name[hi]=एनक्रिप्ट फ़ाइल +Name[hu]=Fájl titkosítása +Name[is]=Dulrita skrá +Name[it]=Cifratura file +Name[ja]=ファイルを暗号化 +Name[ka]=დაილის დაშიფრვა +Name[kk]=Файлды шифрлау +Name[km]=អ៊ិនគ្រីបឯកសារ +Name[lt]=Šifruoti bylą +Name[mk]=Криптирај датотеки +Name[nb]=Krypter fil +Name[nds]=Dateiverslöteln +Name[ne]=फाइल गुप्तीकरण गर्नुहोस् +Name[nl]=Bestand versleutelen +Name[nn]=Krypter fil +Name[pa]=ਇੰਕਰਿਪਟ ਫਾਇਲ +Name[pl]=Zaszyfruj plik +Name[pt]=Cifrar Ficheiro +Name[pt_BR]=Criptografar Arquivo +Name[ro]=Criptează fişierul +Name[ru]=Зашифровать файл +Name[sk]=Šifrovať súbor +Name[sl]=Šifriraj datoteko +Name[sr]=Шифруј фајл +Name[sr@Latn]=Šifruj fajl +Name[sv]=Kryptera fil +Name[ta]=சங்கேத கோப்பு +Name[tg]=Рамзкунонии Файл +Name[tr]=Dosya Şifrele +Name[uk]=Зашифрувати файл +Name[wa]=Ecripter fitchî +Name[zh_CN]=加密文件 +Name[zh_TW]=加密檔案 +Icon=kgpg +Exec=kgpg -e %F + diff --git a/kgpg/encryptfolder.desktop b/kgpg/encryptfolder.desktop new file mode 100644 index 0000000..60083ba --- /dev/null +++ b/kgpg/encryptfolder.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +ServiceTypes=inode/directory +Actions=encrypt + +[Desktop Action encrypt] +Name=Archive & Encrypt Folder +Name[ar]=أرشفة و تشفير مجلّد +Name[bg]=Архивиране и шифроване на директория +Name[bs]=Arhiviraj i šifriraj direktorij +Name[ca]=Arxiva i xifra la carpeta +Name[cs]=Archivovat a zašifrovat složku +Name[da]=Arkivér & kryptér mappe +Name[de]=Ordner packen und verschlüsseln +Name[el]=Αρχειοθέτηση & κρυπτογράφηση φακέλου +Name[eo]=Arkivigi kaj ĉifri dosierujon +Name[es]=Archivar y cifrar carpeta +Name[et]=Arhiveeri ja krüpti kataloog +Name[eu]=Artxibatu eta enkriptatu karpeta +Name[fa]=بایگانی و رمزبندی پوشه +Name[fi]=Pakkaa ja salaa kansio +Name[fr]=Archiver puis chiffrer le dossier +Name[ga]=Cuir Fillteán i gCartlann & Criptigh É +Name[he]=כלי להצפנה וכיווץ תקייה +Name[hu]=Könyvtár titkosítása és archiválása +Name[is]=Pakka og dulrita möppu +Name[it]=Archivia e cifra cartella +Name[ja]=フォルダをアーカイブ化 & 暗号化 +Name[ka]=არქივი და დაშიფრვის საქაღალდე +Name[kk]=Қапшықты архивтеп шифрлау +Name[km]=ថតប័ណ្ណសារ & អ៊ិនគ្រីប +Name[lt]=Archyvuoti ir šifruoti aplanką +Name[nb]=Arkiver og krypter mappe +Name[nds]=Ornern komprimeren un verslöteln +Name[ne]=फोल्डरलाई सङ्ग्रह र गुप्तीकरण गर्नुहोस् +Name[nl]=Map archiveren en versleutelen +Name[nn]=Arkiver og krypter mappe +Name[pa]=ਆਕੀਵੀ & ਇੰਕਰਿਪਟ ਫੋਲਡਰ +Name[pl]=Zarchiwizuj i zaszyfruj katalog +Name[pt]=Arquivar e Cifrar a Pasta +Name[pt_BR]=Arquivar & Criptografar Pasta +Name[ru]=Архивировать и зашифровать папку +Name[sk]=Archivovať a šifrovať priečinok +Name[sl]=Arhiviranje in ši&friranje imenika +Name[sr]=Архивирај и шифруј фасциклу +Name[sr@Latn]=Arhiviraj i šifruj fasciklu +Name[sv]=Arkivera och kryptera katalog +Name[tr]=Arşiv ve Klasör Şifrele +Name[uk]=Зробити архів теки і зашифрувати +Name[zh_CN]=存档并加密文件夹 +Name[zh_TW]=壓縮並加密資料夾 +Icon=kgpg +Exec=kgpg -e %F diff --git a/kgpg/groupedit.ui b/kgpg/groupedit.ui new file mode 100644 index 0000000..ca96e4b --- /dev/null +++ b/kgpg/groupedit.ui @@ -0,0 +1,212 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>groupEdit</class> +<widget class="QWidget"> + <property name="name"> + <cstring>groupEdit</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>557</width> + <height>259</height> + </rect> + </property> + <property name="caption"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="KListView" row="1" column="0" rowspan="1" colspan="4"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Email</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Id</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>availableKeys</cstring> + </property> + <property name="acceptDrops"> + <bool>true</bool> + </property> + <property name="selectionMode" stdset="0"> + <enum>Extended</enum> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="showSortIndicator"> + <bool>true</bool> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + <property name="dragEnabled"> + <bool>false</bool> + </property> + <property name="alternateBackground"> + <color> + <red>238</red> + <green>246</green> + <blue>255</blue> + </color> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Available Trusted Keys</string> + </property> + </widget> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>buttonAdd</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QPushButton" row="2" column="2"> + <property name="name"> + <cstring>buttonRemove</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer row="2" column="3"> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>71</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KActiveLabel" row="2" column="0"> + <property name="name"> + <cstring>kActiveLabel1</cstring> + </property> + <property name="text"> + <string><b>Keys in the Group</b></string> + </property> + </widget> + <widget class="KListView" row="3" column="0" rowspan="1" colspan="4"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Email</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Id</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>groupKeys</cstring> + </property> + <property name="acceptDrops"> + <bool>true</bool> + </property> + <property name="selectionMode" stdset="0"> + <enum>Extended</enum> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="showSortIndicator"> + <bool>true</bool> + </property> + <property name="itemMargin"> + <number>1</number> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + <property name="dragEnabled"> + <bool>false</bool> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kactivelabel.h</includehint> +</includehints> +</UI> diff --git a/kgpg/hi16-app-kgpg.png b/kgpg/hi16-app-kgpg.png Binary files differnew file mode 100644 index 0000000..4102aab --- /dev/null +++ b/kgpg/hi16-app-kgpg.png diff --git a/kgpg/hi22-app-kgpg.png b/kgpg/hi22-app-kgpg.png Binary files differnew file mode 100644 index 0000000..fb3e9de --- /dev/null +++ b/kgpg/hi22-app-kgpg.png diff --git a/kgpg/hi32-app-kgpg.png b/kgpg/hi32-app-kgpg.png Binary files differnew file mode 100644 index 0000000..82225f0 --- /dev/null +++ b/kgpg/hi32-app-kgpg.png diff --git a/kgpg/hi48-app-kgpg.png b/kgpg/hi48-app-kgpg.png Binary files differnew file mode 100644 index 0000000..a01145e --- /dev/null +++ b/kgpg/hi48-app-kgpg.png diff --git a/kgpg/icons/Makefile.am b/kgpg/icons/Makefile.am new file mode 100644 index 0000000..f45690c --- /dev/null +++ b/kgpg/icons/Makefile.am @@ -0,0 +1,2 @@ +kgpgiconsdir = $(kde_datadir)/kgpg/icons +kgpgicons_ICON = AUTO diff --git a/kgpg/icons/cr16-action-kgpg_key1.png b/kgpg/icons/cr16-action-kgpg_key1.png Binary files differnew file mode 100644 index 0000000..ee3b21c --- /dev/null +++ b/kgpg/icons/cr16-action-kgpg_key1.png diff --git a/kgpg/icons/cr16-action-kgpg_key2.png b/kgpg/icons/cr16-action-kgpg_key2.png Binary files differnew file mode 100644 index 0000000..ad4e016 --- /dev/null +++ b/kgpg/icons/cr16-action-kgpg_key2.png diff --git a/kgpg/icons/cr16-action-kgpg_key3.png b/kgpg/icons/cr16-action-kgpg_key3.png Binary files differnew file mode 100644 index 0000000..ae788ca --- /dev/null +++ b/kgpg/icons/cr16-action-kgpg_key3.png diff --git a/kgpg/icons/cr16-action-kgpg_key4.png b/kgpg/icons/cr16-action-kgpg_key4.png Binary files differnew file mode 100644 index 0000000..2e4e11a --- /dev/null +++ b/kgpg/icons/cr16-action-kgpg_key4.png diff --git a/kgpg/icons/cr22-action-kgpg_edit.png b/kgpg/icons/cr22-action-kgpg_edit.png Binary files differnew file mode 100644 index 0000000..96ba433 --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_edit.png diff --git a/kgpg/icons/cr22-action-kgpg_export.png b/kgpg/icons/cr22-action-kgpg_export.png Binary files differnew file mode 100644 index 0000000..b2e56ff --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_export.png diff --git a/kgpg/icons/cr22-action-kgpg_gen.png b/kgpg/icons/cr22-action-kgpg_gen.png Binary files differnew file mode 100644 index 0000000..d48fbe2 --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_gen.png diff --git a/kgpg/icons/cr22-action-kgpg_identity.png b/kgpg/icons/cr22-action-kgpg_identity.png Binary files differnew file mode 100644 index 0000000..c41101c --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_identity.png diff --git a/kgpg/icons/cr22-action-kgpg_import.png b/kgpg/icons/cr22-action-kgpg_import.png Binary files differnew file mode 100644 index 0000000..096e22b --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_import.png diff --git a/kgpg/icons/cr22-action-kgpg_info.png b/kgpg/icons/cr22-action-kgpg_info.png Binary files differnew file mode 100644 index 0000000..eef8be6 --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_info.png diff --git a/kgpg/icons/cr22-action-kgpg_photo.png b/kgpg/icons/cr22-action-kgpg_photo.png Binary files differnew file mode 100644 index 0000000..a370bd0 --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_photo.png diff --git a/kgpg/icons/cr22-action-kgpg_show.png b/kgpg/icons/cr22-action-kgpg_show.png Binary files differnew file mode 100644 index 0000000..3e3e122 --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_show.png diff --git a/kgpg/icons/cr22-action-kgpg_sign.png b/kgpg/icons/cr22-action-kgpg_sign.png Binary files differnew file mode 100644 index 0000000..3580184 --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_sign.png diff --git a/kgpg/icons/cr22-action-kgpg_term.png b/kgpg/icons/cr22-action-kgpg_term.png Binary files differnew file mode 100644 index 0000000..126fb73 --- /dev/null +++ b/kgpg/icons/cr22-action-kgpg_term.png diff --git a/kgpg/keyexport.ui b/kgpg/keyexport.ui new file mode 100644 index 0000000..35f4128 --- /dev/null +++ b/kgpg/keyexport.ui @@ -0,0 +1,142 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>KeyExport</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KeyExport</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>370</width> + <height>167</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>350</width> + <height>0</height> + </size> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>exportAttributes</cstring> + </property> + <property name="text"> + <string>Export attributes (photo id)</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QButtonGroup" row="0" column="0"> + <property name="name"> + <cstring>buttonGroup2</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>checkMail</cstring> + </property> + <property name="text"> + <string>Email</string> + </property> + </widget> + <widget class="QRadioButton" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>checkServer</cstring> + </property> + <property name="text"> + <string>Default key server</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>checkClipboard</cstring> + </property> + <property name="text"> + <string>Clipboard</string> + </property> + </widget> + <widget class="KURLRequester" row="3" column="1"> + <property name="name"> + <cstring>newFilename</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton" row="3" column="0"> + <property name="name"> + <cstring>checkFile</cstring> + </property> + <property name="text"> + <string>File:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>checkFile</sender> + <signal>toggled(bool)</signal> + <receiver>KeyExport</receiver> + <slot>checkFile_toggled(bool)</slot> + </connection> +</connections> +<includes> + <include location="local" impldecl="in implementation">keyexport.ui.h</include> +</includes> +<slots> + <slot>checkFile_toggled( bool isOn )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kgpg/keyexport.ui.h b/kgpg/keyexport.ui.h new file mode 100644 index 0000000..89ef491 --- /dev/null +++ b/kgpg/keyexport.ui.h @@ -0,0 +1,21 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ +//(C) 2002 Jean-Baptiste Mardelle <bj@altern.org> + +void KeyExport::checkFile_toggled( bool isOn) +{ +newFilename->setEnabled(isOn); +} diff --git a/kgpg/keygener.cpp b/kgpg/keygener.cpp new file mode 100644 index 0000000..739bb55 --- /dev/null +++ b/kgpg/keygener.cpp @@ -0,0 +1,176 @@ +/*************************************************************************** + keygen.cpp - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/////////////////////////////////////////////// code for new key generation + + +#include <qwhatsthis.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qvbox.h> +#include <kcombobox.h> +#include <klineedit.h> +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <qhbuttongroup.h> +#include <qvbuttongroup.h> +#include <kmessagebox.h> +#include <klocale.h> + +#include "keygener.h" + +/////////////////////// main window +keyGenerate::keyGenerate(QWidget *parent, const char *name):KDialogBase( parent, name, true,i18n("Key Generation"),Apply | Ok | Cancel) +{ + expert=false; + setButtonApply(i18n("Expert Mode")); + + QWidget *page = new QWidget(this); + QVBoxLayout *vbox=new QVBoxLayout(page); + + QVButtonGroup *bgroup1=new QVButtonGroup(i18n("Generate Key Pair"),page); + + (void) new QLabel(i18n("Name:"),bgroup1); + kname=new KLineEdit("",bgroup1); + kname->setFocus(); + (void) new QLabel(i18n("Email:"),bgroup1); + mail=new KLineEdit("",bgroup1); + + (void) new QLabel(i18n("Comment (optional):"),bgroup1); + comment=new KLineEdit("",bgroup1); + + (void) new QLabel(i18n("Expiration:"),bgroup1); + QHButtonGroup *bgroup=new QHButtonGroup(bgroup1); + numb=new KLineEdit("0",bgroup); + numb->setMaxLength(4); + numb->setDisabled(true); + keyexp = new KComboBox(bgroup); + keyexp->insertItem(i18n("Never"),0); + keyexp->insertItem(i18n("Days"),1); + keyexp->insertItem(i18n("Weeks"),2); + keyexp->insertItem(i18n("Months"),3); + keyexp->insertItem(i18n("Years"),4); + keyexp->setMinimumSize(keyexp->sizeHint()); + connect(keyexp,SIGNAL(activated(int)),this,SLOT(activateexp(int))); + + (void) new QLabel(i18n("Key size:"),bgroup1); + keysize = new KComboBox(bgroup1); + keysize->insertItem("768"); + keysize->insertItem("1024"); + keysize->insertItem("2048"); + keysize->insertItem("4096"); + keysize->setCurrentItem("1024"); + keysize->setMinimumSize(keysize->sizeHint()); + + (void) new QLabel(i18n("Algorithm:"),bgroup1); + keykind = new KComboBox(bgroup1); + keykind->insertItem("DSA & ElGamal"); + keykind->insertItem("RSA"); + keykind->setMinimumSize(keykind->sizeHint()); + + vbox->addWidget(bgroup1); + page->show(); + page->resize(page->maximumSize()); + setMainWidget(page); +} + +void keyGenerate::slotOk() +{ + if (QString(kname->text()).stripWhiteSpace().isEmpty()) { + KMessageBox::sorry(this,i18n("You must give a name.")); + return; + } + QString vmail=mail->text(); + if (vmail.isEmpty()) + { + if (KMessageBox::warningContinueCancel(this,i18n("You are about to create a key with no email address"))!=KMessageBox::Continue) return; + } + else if ((vmail.find(" ")!=-1) || (vmail.find(".")==-1) || (vmail.find("@")==-1)) { + KMessageBox::sorry(this,i18n("Email address not valid")); + return; + } + accept(); +} + +void keyGenerate::slotApply() +{ + expert=true; + accept(); +} + +void keyGenerate::activateexp(int state) +{ + if (state==0) + numb->setDisabled(true); + else + numb->setDisabled(false); +} + +bool keyGenerate::getmode() +{ + return(expert); +} + + +QString keyGenerate::getkeytype() +{ + return(keykind->currentText()); +} + +QString keyGenerate::getkeysize() +{ + return(keysize->currentText()); +} + +int keyGenerate::getkeyexp() +{ + return(keyexp->currentItem()); +} + +QString keyGenerate::getkeynumb() +{ + if (numb->text()!=NULL) + return(numb->text()); + else + return (""); +} + +QString keyGenerate::getkeyname() +{ + if (kname->text()!=NULL) + return(kname->text()); + else + return (""); +} + +QString keyGenerate::getkeymail() +{ + if (mail->text()!=NULL) + return(mail->text()); + else + return (""); +} + +QString keyGenerate::getkeycomm() +{ + if (comment->text()!=NULL) + return(comment->text()); + else + return (""); +} + +#include "keygener.moc" diff --git a/kgpg/keygener.h b/kgpg/keygener.h new file mode 100644 index 0000000..0c1cd89 --- /dev/null +++ b/kgpg/keygener.h @@ -0,0 +1,50 @@ +/*************************************************************************** + keygen.h - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef KEYGEN_H +#define KEYGEN_H + +#include <kdialogbase.h> + +class KComboBox; +class KLineEdit; + +class keyGenerate : public KDialogBase +{ + Q_OBJECT +public: + keyGenerate(QWidget *parent=0, const char *name=0); + + KComboBox *keykind,*keysize,*keyexp; + KLineEdit *numb,*comment,*kname,*mail; + bool expert; + +public slots: + void slotOk(); + void slotApply(); + void activateexp(int state); + bool getmode(); + QString getkeycomm(); + QString getkeynumb(); + QString getkeymail(); + QString getkeyname(); + QString getkeysize(); + QString getkeytype(); + int getkeyexp(); +}; + +#endif // KEYGEN_H + diff --git a/kgpg/keyinfowidget.cpp b/kgpg/keyinfowidget.cpp new file mode 100644 index 0000000..4704eba --- /dev/null +++ b/kgpg/keyinfowidget.cpp @@ -0,0 +1,465 @@ +/*************************************************************************** + keyinfowidget.cpp - description + ------------------- + begin : Mon Nov 18 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your gpgOutpution) any later version. * + * * + ***************************************************************************/ + +#include <klocale.h> +#include <kprocess.h> +#include <qdatetime.h> +#include <qfile.h> +#include <kprocio.h> +#include <kpassivepopup.h> +#include <kaction.h> +#include <qregexp.h> +#include <ktempfile.h> +#include <qimage.h> +#include <kdatepicker.h> +#include <qpushbutton.h> +#include <kcombobox.h> +#include <qlabel.h> +#include <kiconloader.h> +#include <qcheckbox.h> +#include <qlayout.h> +#include <kactivelabel.h> +#include <klineedit.h> +#include <ktrader.h> +#include <kservice.h> +#include <kmessagebox.h> + +#include "keyinfowidget.h" +#include "keyproperties.h" +#include "kgpgsettings.h" +#include "kgpginterface.h" + +KgpgKeyInfo::KgpgKeyInfo(QWidget *parent, const char *name,QString sigkey):KDialogBase( Swallow, i18n("Key Properties"), Close, Close, parent, name,true) +{ + + FILE *pass; + char line[200]=""; + QString gpgOutput,fullID; + hasPhoto=false; + bool isSecret=false; + keyWasChanged=false; + + prop=new KeyProperties(); + setMainWidget(prop); + QString gpgcmd="gpg --no-tty --no-secmem-warning --with-colon --list-secret-key "+KShellProcess::quote(sigkey); + pass=popen(QFile::encodeName(gpgcmd),"r"); + while ( fgets( line, sizeof(line), pass)) { + gpgOutput=line; + if (gpgOutput.startsWith("sec")) isSecret=true; + } + pclose(pass); + + if (!isSecret) { + prop->changeExp->hide(); + prop->changePass->hide(); + } + loadKey(sigkey); + + if (hasPhoto) { + KgpgInterface *photoProcess=new KgpgInterface(); + photoProcess->KgpgGetPhotoList(displayedKeyID); + connect(photoProcess,SIGNAL(signalPhotoList(QStringList)),this,SLOT(slotSetMainPhoto(QStringList))); + } + else + prop->comboId->setEnabled(false); + + connect(prop->changeExp,SIGNAL(clicked()),this,SLOT(slotChangeExp())); + connect(this,SIGNAL(closeClicked()),this,SLOT(slotPreOk())); + connect(prop->changePass,SIGNAL(clicked()),this,SLOT(slotChangePass())); + connect(prop->comboId,SIGNAL(activated (const QString &)),this,SLOT(reloadMainPhoto(const QString &))); + connect(prop->cbDisabled,SIGNAL(toggled(bool)),this,SLOT(slotDisableKey(bool))); + connect(prop->kCOwnerTrust,SIGNAL(activated (int)),this,SLOT(slotChangeTrust(int))); + connect(this,SIGNAL(changeMainPhoto(const QPixmap&)),this,SLOT(slotSetPhoto(const QPixmap&))); + + //prop->setMinimumSize(prop->sizeHint()); +} + +void KgpgKeyInfo::slotDisableKey(bool isOn) +{ +KProcess kp; + + kp<<"gpg" + <<"--no-tty" + <<"--edit-key" + <<displayedKeyID; +if (isOn) kp<<"disable"; +else kp<<"enable"; + kp<<"save"; + kp.start(KProcess::Block); +loadKey(displayedKeyID); +keyWasChanged=true; +} + +void KgpgKeyInfo::loadKey(QString Keyid) +{ +QColor trustColor; +QString fingervalue=QString::null; +FILE *pass; +char line[200]=""; +QString gpgOutput,fullID; + +QString gpgcmd="gpg --no-tty --no-secmem-warning --with-colon --with-fingerprint --list-key "+KShellProcess::quote(Keyid); + + pass=popen(QFile::encodeName(gpgcmd),"r"); + while ( fgets( line, sizeof(line), pass)) { + gpgOutput=QString::fromUtf8(line); + if (gpgOutput.startsWith("uat")) + hasPhoto=true; + if (gpgOutput.startsWith("pub")) { + QString algo=gpgOutput.section(':',3,3); + switch( algo.toInt() ) { + case 1: + algo="RSA"; + break; + case 16: + case 20: + algo="ElGamal"; + break; + case 17: + algo="DSA"; + break; + default: + algo=QString("#" + algo); + break; + } + prop->tLAlgo->setText(algo); + + const QString trust=gpgOutput.section(':',1,1); + QString tr; + switch( trust[0] ) { + case 'o': + tr= i18n("Unknown"); + trustColor=KGpgSettings::colorUnknown(); + break; + case 'i': + tr= i18n("Invalid"); + trustColor=KGpgSettings::colorBad(); + break; + case 'd': + tr=i18n("Disabled"); + trustColor=KGpgSettings::colorBad(); + prop->cbDisabled->setChecked(true); + break; + case 'r': + tr=i18n("Revoked"); + trustColor=KGpgSettings::colorRev(); + break; + case 'e': + tr=i18n("Expired"); + trustColor=KGpgSettings::colorBad(); + break; + case 'q': + tr=i18n("Undefined"); + trustColor=KGpgSettings::colorUnknown(); + break; + case 'n': + tr=i18n("None"); + trustColor=KGpgSettings::colorUnknown(); + break; + case 'm': + tr=i18n("Marginal"); + trustColor=KGpgSettings::colorBad(); + break; + case 'f': + tr=i18n("Full"); + trustColor=KGpgSettings::colorGood(); + break; + case 'u': + tr=i18n("Ultimate"); + trustColor=KGpgSettings::colorGood(); + break; + default: + tr="?"; + trustColor=KGpgSettings::colorUnknown(); + break; + } + + if (gpgOutput.section(':',11,11).find("D",0,true)!=-1) // disabled key + { + tr=i18n("Disabled"); + trustColor=KGpgSettings::colorBad(); + prop->cbDisabled->setChecked(true); + } + + prop->kLTrust->setText(tr); + prop->pixmapTrust->setPaletteBackgroundColor(trustColor); + + fullID=gpgOutput.section(':',4,4); + displayedKeyID=fullID.right(8); + prop->tLID->setText(fullID); + + QString fullname=gpgOutput.section(':',9,9); + + QDate date = QDate::fromString(gpgOutput.section(':',5,5), Qt::ISODate); + prop->tLCreation->setText(KGlobal::locale()->formatDate(date)); + + if (gpgOutput.section(':',6,6).isEmpty()) expirationDate=i18n("Unlimited"); + else + { + date = QDate::fromString(gpgOutput.section(':',6,6), Qt::ISODate); + expirationDate=KGlobal::locale()->formatDate(date); + } + prop->tLExpiration->setText(expirationDate); + + prop->tLLength->setText(gpgOutput.section(':',2,2)); + + const QString otrust=gpgOutput.section(':',8,8); + int ownerTrust=0; + + /* Don't know=1; Do NOT trust=2; Marginally=3; Fully=4; Ultimately=5; */ + + switch( otrust[0] ) { + case 'f': + ownerTrust=3; + break; + case 'u': + ownerTrust=4; + break; + case 'm': + ownerTrust=2; + break; + case 'n': + ownerTrust=1; + break; + default: + ownerTrust=0; + break; + } + prop->kCOwnerTrust->setCurrentItem(ownerTrust); + + if (fullname.find("<")!=-1) { + QString kmail=fullname; + if (fullname.find(")")!=-1) + kmail=kmail.section(')',1); + kmail=kmail.section('<',1); + kmail.truncate(kmail.length()-1); + if (kmail.find("<")!=-1) //////// several email addresses in the same key + { + kmail=kmail.replace(">",";"); + kmail.remove("<"); + } + prop->tLMail->setText("<qt><a href=mailto:"+kmail+">"+kmail+"</a></qt>"); + } else + prop->tLMail->setText(i18n("none")); + + QString kname=fullname.section('<',0,0); + if (fullname.find("(")!=-1) { + kname=kname.section('(',0,0); + QString comment=fullname.section('(',1,1); + comment=comment.section(')',0,0); + prop->tLComment->setText(KgpgInterface::checkForUtf8(comment)); + } else + prop->tLComment->setText(i18n("none")); + + prop->tLName->setText("<qt><b>"+KgpgInterface::checkForUtf8(kname).replace(QRegExp("<"),"<")+"</b></qt>"); + + } + if (gpgOutput.startsWith("fpr") && (fingervalue.isNull())) { + fingervalue=gpgOutput.section(':',9,9); + // format fingervalue in 4-digit groups + uint len = fingervalue.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4*(n+1) < len; n++) + fingervalue.insert(5*n+4, ' '); + prop->lEFinger->setText(fingervalue); + } + } + pclose(pass); +} + +void KgpgKeyInfo::slotSetMainPhoto(QStringList list) +{ +prop->comboId->insertStringList(list); +reloadMainPhoto(prop->comboId->currentText()); +} + +void KgpgKeyInfo::reloadMainPhoto(const QString &uid) +{ + + kgpginfotmp=new KTempFile(); + kgpginfotmp->setAutoDelete(true); + QString pgpgOutput="cp %i "+kgpginfotmp->name(); + KProcIO *p=new KProcIO(); + *p<<"gpg"<<"--no-tty"<<"--show-photos"<<"--photo-viewer"<<QFile::encodeName(pgpgOutput); + *p<<"--edit-key"<<displayedKeyID<<"uid"<<uid<<"showphoto"; + QObject::connect(p, SIGNAL(readReady(KProcIO *)),this, SLOT(finishphotoreadprocess(KProcIO *))); + QObject::connect(p, SIGNAL(processExited(KProcess *)),this, SLOT(slotMainImageRead(KProcess *))); + p->start(KProcess::NotifyOnExit,true); + +} + + +void KgpgKeyInfo::slotMainImageRead(KProcess *p) +{ + p->deleteLater(); + QPixmap pixmap; + pixmap.load(kgpginfotmp->name()); + emit changeMainPhoto(pixmap); + kgpginfotmp->unlink(); +} + + +KgpgKeyInfo::~KgpgKeyInfo() +{ +} + +void KgpgKeyInfo::slotSetPhoto(const QPixmap &pix) +{ +QImage dup=pix.convertToImage(); +QPixmap dup2; +dup2.convertFromImage(dup.scale(prop->pLPhoto->width(),prop->pLPhoto->height(),QImage::ScaleMin)); +prop->pLPhoto->setPixmap(dup2); +} + + + + +void KgpgKeyInfo::finishphotoreadprocess(KProcIO *p) +{ + QString required=QString::null; + while (p->readln(required,true)!=-1) + if (required.find("keyedit.prompt")!=-1) { + p->writeStdin("quit"); + p->closeWhenDone(); + + } +} + + +void KgpgKeyInfo::openPhoto() +{ + KTrader::OfferList offers = KTrader::self()->query("image/jpeg", "Type == 'Application'"); + KService::Ptr ptr = offers.first(); + //KMessageBox::sorry(0,ptr->desktopEntryName()); + KProcIO *p=new KProcIO(); + *p<<"gpg"<<"--show-photos"<<"--photo-viewer"<<QFile::encodeName(ptr->desktopEntryName()+" %i")<<"--list-keys"<<displayedKeyID; + p->start(KProcess::DontCare,true); +} + +void KgpgKeyInfo::slotChangeExp() +{ +chdate=new KDialogBase( this, "choose_date", true,i18n("Choose New Expiration"),KDialogBase::Ok | KDialogBase::Cancel); +QWidget *page = new QWidget(chdate); +kb= new QCheckBox(i18n("Unlimited"),page ); + +if (prop->tLExpiration->text()==i18n("Unlimited")) +{ +kdt= new KDatePicker( page ); +kb->setChecked(true); +kdt->setEnabled(false); +} +else +kdt= new KDatePicker(page,KGlobal::locale()->readDate(prop->tLExpiration->text())); +QVBoxLayout *vbox=new QVBoxLayout(page,3); +vbox->addWidget(kdt); +vbox->addWidget(kb); +connect(kb,SIGNAL(toggled(bool)),this,SLOT(slotEnableDate(bool))); +connect(chdate,SIGNAL(okClicked()),this,SLOT(slotChangeDate())); +connect(kdt,SIGNAL(dateChanged(QDate)),this,SLOT(slotCheckDate(QDate))); +connect(kdt,SIGNAL(dateEntered(QDate)),this,SLOT(slotCheckDate(QDate))); + +chdate->setMainWidget(page); +chdate->show(); +} + +void KgpgKeyInfo::slotCheckDate(QDate date) +{ +chdate->enableButtonOK(date>=QDate::currentDate ()); +} + +void KgpgKeyInfo::slotChangeDate() +{ +KgpgInterface *KeyExpirationProcess=new KgpgInterface(); + if (kb->isChecked()) + KeyExpirationProcess->KgpgKeyExpire(displayedKeyID,QDate::currentDate(),true); + else + KeyExpirationProcess->KgpgKeyExpire(displayedKeyID,kdt->date(),false); + connect(KeyExpirationProcess,SIGNAL(expirationFinished(int)),this,SLOT(slotInfoExpirationChanged(int))); +} + +void KgpgKeyInfo::slotEnableDate(bool isOn) +{ +if (isOn) +{ +kdt->setEnabled(false); +chdate->enableButtonOK(true); +} +else +{ +kdt->setEnabled(true); +chdate->enableButtonOK(kdt->date()>=QDate::currentDate ()); +} +} + +void KgpgKeyInfo::slotinfoimgread(KProcess *) +{ + QPixmap pixmap; + pixmap.load(kgpginfotmp->name()); + emit signalPhotoId(pixmap); + kgpginfotmp->unlink(); +} + +void KgpgKeyInfo::slotChangePass() +{ + KgpgInterface *ChangeKeyPassProcess=new KgpgInterface(); + ChangeKeyPassProcess->KgpgChangePass(displayedKeyID); + connect(ChangeKeyPassProcess,SIGNAL(passwordChanged()),this,SLOT(slotInfoPasswordChanged())); +} + +void KgpgKeyInfo::slotChangeTrust(int newTrust) +{ + KgpgInterface *KeyTrustProcess=new KgpgInterface(); + KeyTrustProcess->KgpgTrustExpire(displayedKeyID,newTrust); + connect(KeyTrustProcess,SIGNAL(trustfinished()),this,SLOT(slotInfoTrustChanged())); +} + + +void KgpgKeyInfo::slotInfoPasswordChanged() +{ +KPassivePopup::message(i18n("Passphrase for the key was changed"),QString::null,KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop),this); +} + +void KgpgKeyInfo::slotInfoTrustChanged() +{ +keyWasChanged=true; +loadKey(displayedKeyID); +//KPassivePopup::message(i18n("Owner trust of the key was changed"),QString::null,KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop),this,0,600); +} + +void KgpgKeyInfo::slotInfoExpirationChanged(int res) +{ +QString infoMessage,infoText; +if (res==3) +{ +keyWasChanged=true; +if (kb->isChecked()) prop->tLExpiration->setText(i18n("Unlimited")); +else prop->tLExpiration->setText(KGlobal::locale()->formatDate(kdt->date())); +} +if (res==2) { +infoMessage=i18n("Could not change expiration");infoText=i18n("Bad passphrase"); +KPassivePopup::message(infoMessage,infoText,KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop),this); +} +} + + +void KgpgKeyInfo::slotPreOk() +{ +if (keyWasChanged) emit keyNeedsRefresh(); +accept(); +} + +#include "keyinfowidget.moc" diff --git a/kgpg/keyinfowidget.h b/kgpg/keyinfowidget.h new file mode 100644 index 0000000..af8ba64 --- /dev/null +++ b/kgpg/keyinfowidget.h @@ -0,0 +1,84 @@ +/*************************************************************************** + keyinfowidget.h - description + ------------------- + begin : Thu Jul 4 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KEYINFOWIDGET_H +#define KEYINFOWIDGET_H + +#include <kdialogbase.h> +#include <qpixmap.h> + +class KTempFile; +class QLabel; +class KDialogBase; +class QCheckBox; +class KDatePicker; +class KeyProperties; +class KProcess; +class KProcIO; + +class KgpgKeyInfo : public KDialogBase +{ + Q_OBJECT + +public: + + KgpgKeyInfo( QWidget *parent = 0, const char *name = 0,QString sigkey=0); + ~KgpgKeyInfo(); + KeyProperties *prop; + +private slots: + void slotinfoimgread(KProcess *); + void slotChangePass(); + void slotPreOk(); + void slotChangeExp(); + void slotEnableDate(bool isOn); + void slotChangeDate(); + void slotCheckDate(QDate date); + void openPhoto(); + void slotSetPhoto(const QPixmap &pix); + void finishphotoreadprocess(KProcIO *p); + void slotMainImageRead(KProcess *); + void slotSetMainPhoto(QStringList list); + void reloadMainPhoto(const QString &uid); + void slotInfoPasswordChanged(); + void slotInfoExpirationChanged(int res); + void slotInfoTrustChanged(); + void slotChangeTrust(int newTrust); + void loadKey(QString Keyid); + void slotDisableKey(bool isOn); + +private: + KTempFile *kgpginfotmp; + QLabel *keyinfoPhoto; + QString displayedKeyID; + QString expirationDate; + bool hasPhoto,keyWasChanged; + KDialogBase *chdate; + QCheckBox *kb; + KDatePicker *kdt; + int counter; + +signals: + + void signalPhotoId(const QPixmap&); + void changeMainPhoto(const QPixmap&); + void keyNeedsRefresh(); + +}; + +#endif // KEYINFOWIDGET_H + diff --git a/kgpg/keyproperties.ui b/kgpg/keyproperties.ui new file mode 100644 index 0000000..4a44ea9 --- /dev/null +++ b/kgpg/keyproperties.ui @@ -0,0 +1,507 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KeyProperties</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KeyProperties</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>431</width> + <height>350</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>Key Properties</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLayoutWidget" row="0" column="3" rowspan="7" colspan="1"> + <property name="name"> + <cstring>layout39</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>pLPhoto</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>120</width> + <height>140</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>140</height> + </size> + </property> + <property name="paletteBackgroundColor"> + <color> + <red>200</red> + <green>200</green> + <blue>200</blue> + </color> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="lineWidth"> + <number>2</number> + </property> + <property name="text"> + <string>No Photo</string> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Photo:</b><br /> + <p>A photo can be included with a public key for extra security. The photo can be used as an additional method of authenticating the key. However, it should not be relied upon as the only form of authentication.</p> + </qt></string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Photo Id:</string> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>comboId</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="7" column="3" rowspan="4" colspan="1"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>cbDisabled</cstring> + </property> + <property name="text"> + <string>Disable key</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>changeExp</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Change Expiration...</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>changePass</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Change Passphrase...</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLabel" row="9" column="0"> + <property name="name"> + <cstring>labelLength</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Length:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>labelCreation</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Creation:</string> + </property> + </widget> + <widget class="QLabel" row="7" column="0"> + <property name="name"> + <cstring>labelID</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Key ID:</string> + </property> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>tLTrust_2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Owner trust:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>tLMail2_2</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Email:</string> + </property> + </widget> + <widget class="QLabel" row="8" column="0"> + <property name="name"> + <cstring>labelAlgo</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Algorithm:</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>labelExpiration</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Expiration:</string> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>txtTrust</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Trust:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>tLComment2_2</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Comment:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>tLName2_2</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="KLineEdit" row="11" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>lEFinger</cstring> + </property> + <property name="frame"> + <bool>true</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel" row="10" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>tLID_2</cstring> + </property> + <property name="text"> + <string>Fingerprint:</string> + </property> + </widget> + <widget class="KActiveLabel" row="2" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tLComment</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="5" column="2"> + <property name="name"> + <cstring>pixmapTrust</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + <widget class="KActiveLabel" row="1" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tLMail</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KActiveLabel" row="7" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tLID</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KActiveLabel" row="4" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tLExpiration</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KComboBox" row="6" column="1" rowspan="1" colspan="2"> + <item> + <property name="text"> + <string>Don't Know</string> + </property> + </item> + <item> + <property name="text"> + <string>Do NOT Trust</string> + </property> + </item> + <item> + <property name="text"> + <string>Marginally</string> + </property> + </item> + <item> + <property name="text"> + <string>Fully</string> + </property> + </item> + <item> + <property name="text"> + <string>Ultimately</string> + </property> + </item> + <property name="name"> + <cstring>kCOwnerTrust</cstring> + </property> + </widget> + <widget class="QLabel" row="5" column="1"> + <property name="name"> + <cstring>kLTrust</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="9" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tLLength</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="8" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tLAlgo</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KActiveLabel" row="3" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tLCreation</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KActiveLabel" row="0" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>tLName</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kactivelabel.h</includehint> + <includehint>kactivelabel.h</includehint> + <includehint>kactivelabel.h</includehint> + <includehint>kactivelabel.h</includehint> + <includehint>kactivelabel.h</includehint> + <includehint>kactivelabel.h</includehint> +</includehints> +</UI> diff --git a/kgpg/keyserver.ui b/kgpg/keyserver.ui new file mode 100644 index 0000000..44d42c9 --- /dev/null +++ b/kgpg/keyserver.ui @@ -0,0 +1,336 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>keyServerWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>keyServerWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>465</width> + <height>252</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>tabWidget2</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Import</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="2" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="text"> + <string>Text to search or ID of the key to import:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Text to search or ID of the key to import:</b><br /> + <p>There are multiple ways to search for a key, you can use a text or partial text search (example: entering Phil or Zimmerman will bring up all keys in which Phil or Zimmerman shows up) or you can search by the ID's of the key. Key ID's are strings of letters and numbers that uniquely identify a key (example: searching for 0xED7585F4 would bring up the key associated with that ID).</p> + </qt></string> + </property> + </widget> + <widget class="KComboBox" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kCBimportks</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string><b>Key Server Drop Down Dialog:</b> +Allows the user to select the Key Server which will be used to import PGP/GnuPG keys into the local keyring.</string> + </property> + </widget> + <widget class="KLineEdit" row="3" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>kLEimportid</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Key server:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Key Server:</b><br /> <p>A Key Server is a centralized repository of PGP/GnuPG keys connected to the Internet which can be conveniently accessed in order to obtain or deposit keys. Select from the drop down list to specify which key server should be used.</p> <p>Often these keys are held by people whom the user has never met and as such the authenticity is dubious at best. Refer to the GnuPG manual covering "Web-of-Trust" relationships to find out how GnuPG works around the problem of verifying authenticity.</p> </qt></string> + </property> + </widget> + <widget class="QPushButton" row="6" column="0"> + <property name="name"> + <cstring>Buttonsearch</cstring> + </property> + <property name="text"> + <string>&Search</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton" row="6" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>Buttonimport</cstring> + </property> + <property name="text"> + <string>&Import</string> + </property> + </widget> + <spacer row="5" column="0"> + <property name="name"> + <cstring>spacer2_2_3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <spacer row="5" column="3"> + <property name="name"> + <cstring>spacer2_2_2_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="6" column="3"> + <property name="name"> + <cstring>spacer4_2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>160</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>cBproxyI</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Honor HTTP proxy:</string> + </property> + </widget> + <widget class="KLineEdit" row="4" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>kLEproxyI</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Export</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="7" column="0"> + <property name="name"> + <cstring>Buttonexport</cstring> + </property> + <property name="text"> + <string>&Export</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Export:</b><br /> + <p>Depressing this key will export the specified key to the specified server.</p> + </qt></string> + </property> + </widget> + <spacer row="7" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer4_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>250</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KComboBox" row="1" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>kCBexportks</cstring> + </property> + </widget> + <widget class="KComboBox" row="3" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>kCBexportkey</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Key server:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Key to be exported:</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Key to be exported:</b><br /> + <p>This allows the user to specify the key from the drop down list that will be exported to the key server selected.</p> + </qt></string> + </property> + </widget> + <spacer row="6" column="0"> + <property name="name"> + <cstring>spacer2_4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + <spacer row="6" column="2"> + <property name="name"> + <cstring>spacer2_3_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>30</height> + </size> + </property> + </spacer> + <widget class="KLineEdit" row="5" column="2"> + <property name="name"> + <cstring>kLEproxyE</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>cBproxyE</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Honor HTTP proxy:</string> + </property> + </widget> + <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>exportAttributes</cstring> + </property> + <property name="text"> + <string>Export attributes (photo id)</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kgpg/keyservers.cpp b/kgpg/keyservers.cpp new file mode 100644 index 0000000..1afd9d3 --- /dev/null +++ b/kgpg/keyservers.cpp @@ -0,0 +1,574 @@ +/*************************************************************************** + keyservers.cpp - description + ------------------- + begin : Tue Nov 26 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <stdlib.h> + +#include <qfile.h> +#include <qcheckbox.h> +#include <kapplication.h> +#include <kiconloader.h> +#include <kcombobox.h> +#include <kdialogbase.h> +#include <kmessagebox.h> +#include <qtextcodec.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qdialog.h> +#include <qpushbutton.h> +#include <qbuttongroup.h> +#include <qhbuttongroup.h> +#include <qvbuttongroup.h> +#include <qregexp.h> +#include <qcursor.h> + +#include <klocale.h> +#include <kprocess.h> +#include <kprocio.h> +#include <klistview.h> +#include <kstatusbar.h> +#include <kconfig.h> +#include <klineedit.h> +#include <ksimpleconfig.h> +#include <kaction.h> +#include <kdebug.h> + + +#include "kgpgsettings.h" +#include "searchres.h" +#include "detailedconsole.h" +#include "keyservers.h" + +keyServer::keyServer(QWidget *parent, const char *name,bool modal,bool autoClose):KDialogBase( Swallow, i18n("Key Server"), Close, Close, parent, name,modal) +{ + autoCloseWindow=autoClose; + config=new KSimpleConfig ("kgpgrc"); + page=new keyServerWidget(); + setMainWidget(page); + + syncCombobox(); + page->kLEimportid->setFocus(); + + connect(page->Buttonimport,SIGNAL(clicked()),this,SLOT(slotImport())); + connect(page->Buttonsearch,SIGNAL(clicked()),this,SLOT(slotSearch())); + connect(page->Buttonexport,SIGNAL(clicked()),this,SLOT(slotPreExport())); + connect(this,SIGNAL(okClicked()),this,SLOT(slotOk())); + + connect(page->cBproxyI,SIGNAL(toggled(bool)),this,SLOT(slotEnableProxyI(bool))); + connect(page->cBproxyE,SIGNAL(toggled(bool)),this,SLOT(slotEnableProxyE(bool))); + + connect(page->kLEimportid, SIGNAL( textChanged ( const QString & )), this, SLOT( slotTextChanged( const QString &))); + page->cBproxyI->setChecked(KGpgSettings::useProxy()); + page->cBproxyE->setChecked(KGpgSettings::useProxy()); + const char *httpproxy = getenv("http_proxy"); + if (httpproxy) { + page->cBproxyI->setEnabled(true); + page->cBproxyE->setEnabled(true); + page->kLEproxyI->setText(httpproxy); + page->kLEproxyE->setText(httpproxy); + } + + + KProcIO *encid=new KProcIO(QTextCodec::codecForLocale()); + *encid << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-keys"; + QObject::connect(encid, SIGNAL(readReady(KProcIO *)),this, SLOT(slotprocread(KProcIO *))); + encid->start(KProcess::NotifyOnExit,true); + page->Buttonimport->setEnabled( !page->kLEimportid->text().isEmpty()); + page->Buttonsearch->setEnabled( !page->kLEimportid->text().isEmpty()); +setMinimumSize(sizeHint()); +} + + +keyServer::~keyServer() +{} + + +void keyServer::slotTextChanged( const QString &text) +{ + page->Buttonimport->setEnabled( !text.isEmpty()); + page->Buttonsearch->setEnabled( !text.isEmpty()); + +} +void keyServer::slotEnableProxyI(bool on) +{ + page->kLEproxyI->setEnabled(on); +} + +void keyServer::slotEnableProxyE(bool on) +{ + page->kLEproxyE->setEnabled(on); +} + + + +void keyServer::slotprocread(KProcIO *p) +{ + ///////////////////////////////////////////////////////////////// extract encryption keys + bool dead; + QString tst; + //QPixmap pixkeySingle(KGlobal::iconLoader()->loadIcon("kgpg_key1",KIcon::Small,20)); + while (p->readln(tst)!=-1) { + //tst=tst.stripWhiteSpace(); + if (tst.startsWith("pub")) { + const QString trust=tst.section(':',1,1); + QString id=QString("0x"+tst.section(':',4,4).right(8)); + switch( trust[0] ) { + case 'i': + dead=true; + break; + case 'd': + dead=true; + break; + case 'r': + dead=true; + break; + case 'e': + dead=true; + break; + default: + dead=false; + break; + } + tst=tst.section(':',9,9); + if (tst.length()>35) { + tst.remove(35,tst.length()); + tst+="..."; + } + if ((!dead) && (!tst.isEmpty())) +// page->kCBexportkey->insertItem(pixkeySingle,id+": "+tst); + page->kCBexportkey->insertItem(id+": "+tst); + } + } +} + +void keyServer::slotSearch() +{ + if (page->kCBimportks->currentText().isEmpty()) + return; + + if (page->kLEimportid->text().isEmpty()) { + KMessageBox::sorry(this,i18n("You must enter a search string.")); + return; + } + + //listpop = new KeyServer( this,"result",WType_Dialog | WShowModal); + + dialogServer=new KDialogBase(KDialogBase::Swallow, i18n("Import Key From Keyserver"), KDialogBase::Ok | KDialogBase::Close,KDialogBase::Ok,this,0,true); + + dialogServer->setButtonText(KDialogBase::Ok,i18n("&Import")); + dialogServer->enableButtonOK(false); + listpop=new searchRes(); + listpop->kLVsearch->setColumnWidthMode(0,QListView::Manual); + listpop->kLVsearch->setColumnWidthMode(1,QListView::Manual); + listpop->kLVsearch->setColumnWidth(0,150); + listpop->kLVsearch->setColumnWidth(1,130); + listpop->statusText->setText(i18n("Connecting to the server...")); + connect(listpop->kLVsearch,SIGNAL(selectionChanged()),this,SLOT(transferKeyID())); + connect(dialogServer,SIGNAL(okClicked()),this,SLOT(preimport())); + connect(listpop->kLVsearch,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)),dialogServer,SIGNAL(okClicked())); + + connect(dialogServer,SIGNAL(closeClicked()),this,SLOT(handleQuit())); + connect( listpop , SIGNAL( destroyed() ) , this, SLOT( abortSearch())); + count=0; + cycle=false; + readmessage=QString::null; + searchproc=new KProcIO(QTextCodec::codecForLocale()); + QString keyserv=page->kCBimportks->currentText(); + *searchproc<<"gpg"<<"--utf8-strings"; + if (page->cBproxyI->isChecked()) { + searchproc->setEnvironment("http_proxy",page->kLEproxyI->text()); + *searchproc<< "--keyserver-options"<<"honor-http-proxy"; + } else + *searchproc<< "--keyserver-options"<<"no-honor-http-proxy"; + *searchproc<<"--keyserver"<<keyserv<<"--command-fd=0"<<"--status-fd=2"<<"--search-keys"<<page->kLEimportid->text().stripWhiteSpace(); + + keyNumbers=0; + QObject::connect(searchproc, SIGNAL(processExited(KProcess *)),this, SLOT(slotsearchresult(KProcess *))); + QObject::connect(searchproc, SIGNAL(readReady(KProcIO *)),this, SLOT(slotsearchread(KProcIO *))); + searchproc->start(KProcess::NotifyOnExit,true); + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + dialogServer->setMainWidget(listpop); + listpop->setMinimumSize(listpop->sizeHint()); + listpop->setMinimumWidth(550); + dialogServer->exec(); +} + +void keyServer::handleQuit() +{ + if (searchproc->isRunning()) + { + QApplication::restoreOverrideCursor(); + disconnect(searchproc,0,0,0); + searchproc->kill(); + } + dialogServer->close(); +} + + +void keyServer::abortSearch() +{ + if (dialogServer) { + delete dialogServer; + dialogServer=0L; + } +} + +void keyServer::preimport() +{ + transferKeyID(); + if (listpop->kLEID->text().isEmpty()) { + KMessageBox::sorry(this,i18n("You must choose a key.")); + return; + } + page->kLEimportid->setText(listpop->kLEID->text()); + dialogServer->close(); + slotImport(); +} + +void keyServer::transferKeyID() +{ + if (!listpop->kLVsearch->firstChild()) + return; + QString kid,keysToSearch; + listpop->kLEID->clear(); + QPtrList< QListViewItem >searchList=listpop->kLVsearch->selectedItems(); + + for ( uint i = 0; i < searchList.count(); ++i ) + { + if ( searchList.at(i) ) + keysToSearch.append(" "+searchList.at(i)->text(3)); + } +// kdDebug(2100)<<keysToSearch<<endl; + listpop->kLEID->setText(keysToSearch.stripWhiteSpace()); +} + +void keyServer::slotsearchresult(KProcess *) +{ + QString nb; + dialogServer->enableButtonOK(true); + QApplication::restoreOverrideCursor(); + nb=nb.setNum(keyNumbers); + //listpop->kLVsearch->setColumnText(0,i18n("Found %1 matching keys").arg(nb)); + listpop->statusText->setText(i18n("Found %1 matching keys").arg(nb)); + + if (listpop->kLVsearch->firstChild()!=NULL) { + listpop->kLVsearch->setSelected(listpop->kLVsearch->firstChild(),true); + listpop->kLVsearch->setCurrentItem(listpop->kLVsearch->firstChild()); + transferKeyID(); + } +} + +void keyServer::slotsearchread(KProcIO *p) +{ + QString required; + QString keymail,keyname; + while (p->readln(required,true)!=-1) { + //required=QString::fromUtf8(required); + + if (required.find("keysearch.prompt")!=-1) { + if (count<4) + p->writeStdin("N"); + else { + p->writeStdin("Q"); + p->closeWhenDone(); + } + required=QString::null; + } + + if (required.find("GOT_IT")!=-1) { + count++; + required=QString::null; + } + + if (required.find("(")==0) { + cycle=true; + QString fullname=required.remove(0,required.find(")")+1).stripWhiteSpace(); + if (fullname.find("<")!=-1) { + keymail=fullname.section('<',-1,-1); + if (keymail.endsWith(">")) keymail.truncate(keymail.length()-1); + keyname=fullname.section('<',0,0); + } else { + keymail=QString::null; + keyname=fullname; + } + kitem=new KListViewItem(listpop->kLVsearch,keyname,keymail,QString::null,QString::null); + keyNumbers++; + count=0; + required=QString::null; + } + + if ((cycle) && (!required.isEmpty())) { + QString subkey=required.stripWhiteSpace(); + if (subkey.find(" key ")!=-1 && subkey.at(0).isDigit ()) + { + QString kid=subkey.section(",",0,0).stripWhiteSpace(); + kid=kid.right(8); + kitem->setText(3,kid); + QString creation=subkey.section("created",1,1); + if (creation.startsWith(":")) creation=creation.right(creation.length()-1); + kitem->setText(2,creation); + cycle=false; + } + else + { + if (subkey.find("<")!=-1) { + keymail=subkey.section('<',-1,-1); + if (keymail.endsWith(">")) keymail.truncate(keymail.length()-1); + keyname=subkey.section('<',0,0); + } else { + keymail=QString::null; + keyname=subkey; + } + KListViewItem *subk = new KListViewItem(kitem,keyname,keymail,QString::null,QString::null); + subk->setSelectable(false); + } + required=QString::null; + } + } +} + +void keyServer::slotPreExport() +{ + slotExport(QStringList(page->kCBexportkey->currentText().section(':', 0, 0))); +} + +void keyServer::slotExport(QStringList keyIds) +{ + if (page->kCBexportks->currentText().isEmpty()) + return; + readmessage=QString::null; + exportproc=new KProcIO(QTextCodec::codecForLocale()); + QString keyserv=page->kCBexportks->currentText(); + + *exportproc<<"gpg"<<"--utf8-strings"; + if (!page->exportAttributes->isChecked()) + *exportproc<<"--export-options"<<"no-include-attributes"; + + if (page->cBproxyE->isChecked()) { + exportproc->setEnvironment("http_proxy",page->kLEproxyE->text()); + *exportproc<< "--keyserver-options"<<"honor-http-proxy"; + } else + *exportproc<< "--keyserver-options"<<"no-honor-http-proxy"; + *exportproc << "--status-fd=2" << "--keyserver" << keyserv << "--send-keys" << keyIds; + + QObject::connect(exportproc, SIGNAL(processExited(KProcess *)),this, SLOT(slotexportresult(KProcess *))); + QObject::connect(exportproc, SIGNAL(readReady(KProcIO *)),this, SLOT(slotimportread(KProcIO *))); + exportproc->start(KProcess::NotifyOnExit,true); + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + importpop = new QDialog( this,0,true,Qt::WDestructiveClose); + QVBoxLayout *vbox=new QVBoxLayout(importpop,3); + QLabel *tex=new QLabel(importpop); + tex->setText(i18n("<b>Connecting to the server...</b>")); + QPushButton *Buttonabort=new QPushButton(i18n("&Abort"),importpop); + vbox->addWidget(tex); + vbox->addWidget(Buttonabort); + importpop->setMinimumWidth(250); + importpop->adjustSize(); + importpop->show(); + connect(importpop,SIGNAL(destroyed ()),this,SLOT(abortExport())); + connect(Buttonabort,SIGNAL(clicked ()),importpop,SLOT(close())); +} + +void keyServer::abortExport() +{ + QApplication::restoreOverrideCursor(); + if (exportproc->isRunning()) + { + disconnect(exportproc,0,0,0); + exportproc->kill(); + } +} + +void keyServer::slotexportresult(KProcess*) +{ + QApplication::restoreOverrideCursor(); + KMessageBox::information(0,readmessage); + if (importpop) + delete importpop; +} + + +void keyServer::slotImport() +{ + if (page->kCBimportks->currentText().isEmpty()) + return; + if (page->kLEimportid->text().isEmpty()) { + KMessageBox::sorry(this,i18n("You must enter a search string.")); + return; + } + readmessage=QString::null; + importproc=new KProcIO(QTextCodec::codecForLocale()); + QString keyserv=page->kCBimportks->currentText(); + + *importproc<<"gpg"<<"--utf8-strings"; + if (page->cBproxyI->isChecked()) { + importproc->setEnvironment("http_proxy",page->kLEproxyI->text()); + *importproc<< "--keyserver-options"<<"honor-http-proxy"; + } else + *importproc<< "--keyserver-options"<<"no-honor-http-proxy"; + + *importproc<<"--status-fd=2"<<"--keyserver"<<keyserv<<"--recv-keys"; + QString keyNames=page->kLEimportid->text(); + keyNames=keyNames.stripWhiteSpace(); + keyNames=keyNames.simplifyWhiteSpace(); + while (!keyNames.isEmpty()) { + QString fkeyNames=keyNames.section(' ',0,0); + keyNames.remove(0,fkeyNames.length()); + keyNames=keyNames.stripWhiteSpace(); + *importproc<<QFile::encodeName(fkeyNames); + } + + QObject::connect(importproc, SIGNAL(processExited(KProcess *)),this, SLOT(slotimportresult(KProcess *))); + QObject::connect(importproc, SIGNAL(readReady(KProcIO *)),this, SLOT(slotimportread(KProcIO *))); + importproc->start(KProcess::NotifyOnExit,true); + importproc->closeWhenDone(); + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + importpop = new QDialog( this,0,true,Qt::WDestructiveClose); + QVBoxLayout *vbox=new QVBoxLayout(importpop,3); + QLabel *tex=new QLabel(importpop); + tex->setText(i18n("<b>Connecting to the server...</b>")); + QPushButton *Buttonabort=new QPushButton(i18n("&Abort"),importpop); + vbox->addWidget(tex); + vbox->addWidget(Buttonabort); + importpop->setMinimumWidth(250); + importpop->adjustSize(); + importpop->show(); + connect(Buttonabort,SIGNAL(clicked()),importpop,SLOT(close())); + connect(importpop,SIGNAL(destroyed ()),this,SLOT(abortImport())); +} + +void keyServer::abortImport() +{ + QApplication::restoreOverrideCursor(); + if (importproc->isRunning()) + { + disconnect(importproc,0,0,0); + importproc->kill(); + emit importFinished(QString::null); + } + if (autoCloseWindow) close(); +} + +void keyServer::slotimportresult(KProcess*) +{ + QApplication::restoreOverrideCursor(); + QString importedNb,importedNbSucess,importedNbProcess,resultMessage, parsedOutput,importedNbUnchanged,importedNbSig; + QString notImportesNbSec,importedNbMissing,importedNbRSA,importedNbUid,importedNbSub,importedNbRev,readNbSec; + QString importedNbSec,dupNbSec; + + parsedOutput=readmessage; + QStringList importedKeys; + + while (parsedOutput.find("IMPORTED")!=-1) { + parsedOutput.remove(0,parsedOutput.find("IMPORTED")+8); + importedKeys+=parsedOutput.section("\n",0,0).stripWhiteSpace(); + } + + if (readmessage.find("IMPORT_RES")!=-1) { + importedNb=readmessage.section("IMPORT_RES",-1,-1); + importedNb=importedNb.stripWhiteSpace(); + importedNbProcess=importedNb.section(" ",0,0); + importedNbMissing=importedNb.section(" ",1,1); + importedNbSucess=importedNb.section(" ",2,2); + importedNbRSA=importedNb.section(" ",3,3); + importedNbUnchanged=importedNb.section(" ",4,4); + importedNbUid=importedNb.section(" ",5,5); + importedNbSub=importedNb.section(" ",6,6); + importedNbSig=importedNb.section(" ",7,7); + importedNbRev=importedNb.section(" ",8,8); + readNbSec=importedNb.section(" ",9,9); + importedNbSec=importedNb.section(" ",10,10); + dupNbSec=importedNb.section(" ",11,11); + notImportesNbSec=importedNb.section(" ",12,12); + resultMessage=i18n("<qt>%n key processed.<br></qt>","<qt>%n keys processed.<br></qt>",importedNbProcess.toULong()); + if (importedNbUnchanged!="0") + resultMessage+=i18n("<qt>One key unchanged.<br></qt>","<qt>%n keys unchanged.<br></qt>",importedNbUnchanged.toULong()); + if (importedNbSig!="0") + resultMessage+=i18n("<qt>One signature imported.<br></qt>","<qt>%n signatures imported.<br></qt>",importedNbSig.toULong()); + if (importedNbMissing!="0") + resultMessage+=i18n("<qt>One key without ID.<br></qt>","<qt>%n keys without ID.<br></qt>",importedNbMissing.toULong()); + if (importedNbRSA!="0") + resultMessage+=i18n("<qt>One RSA key imported.<br></qt>","<qt>%n RSA keys imported.<br></qt>",importedNbRSA.toULong()); + if (importedNbUid!="0") + resultMessage+=i18n("<qt>One user ID imported.<br></qt>","<qt>%n user IDs imported.<br></qt>",importedNbUid.toULong()); + if (importedNbSub!="0") + resultMessage+=i18n("<qt>One subkey imported.<br></qt>","<qt>%n subkeys imported.<br></qt>",importedNbSub.toULong()); + if (importedNbRev!="0") + resultMessage+=i18n("<qt>One revocation certificate imported.<br></qt>","<qt>%n revocation certificates imported.<br></qt>",importedNbRev.toULong()); + if (readNbSec!="0") + resultMessage+=i18n("<qt>One secret key processed.<br></qt>","<qt>%n secret keys processed.<br></qt>",readNbSec.toULong()); + if (importedNbSec!="0") + resultMessage+=i18n("<qt><b>One secret key imported.</b><br></qt>","<qt><b>%n secret keys imported.</b><br></qt>",importedNbSec.toULong()); + if (dupNbSec!="0") + resultMessage+=i18n("<qt>One secret key unchanged.<br></qt>","<qt>%n secret keys unchanged.<br></qt>",dupNbSec.toULong()); + if (notImportesNbSec!="0") + resultMessage+=i18n("<qt>One secret key not imported.<br></qt>","<qt>%n secret keys not imported.<br></qt>",notImportesNbSec.toULong()); + if (importedNbSucess!="0") + resultMessage+=i18n("<qt><b>One key imported:</b><br></qt>","<qt><b>%n keys imported:</b><br></qt>",importedNbSucess.toULong()); + } else + resultMessage=i18n("No key imported... \nCheck detailed log for more infos"); + + QString lastID=QString("0x"+importedKeys.last().section(" ",0,0).right(8)); + if (!lastID.isEmpty()) + { + //kdDebug(2100)<<"++++++++++imported key"<<lastID<<endl; + emit importFinished(lastID); + } + + if (importpop) + importpop->hide(); + (void) new KDetailedInfo(0,"import_result",resultMessage,readmessage,importedKeys); + + if (importpop) + delete importpop; + if (autoCloseWindow) close(); +} + +void keyServer::slotimportread(KProcIO *p) +{ + QString required; + while (p->readln(required,true)!=-1) + readmessage+=required+"\n"; +} + +void keyServer::syncCombobox() +{ + config->setGroup("Servers"); + QString serverList=config->readEntry("Server_List"); + + QString optionsServer=KgpgInterface::getGpgSetting("keyserver", KGpgSettings::gpgConfigPath()); + + page->kCBexportks->clear(); + page->kCBimportks->clear(); + + if (!optionsServer.isEmpty()) { + page->kCBexportks->insertItem(optionsServer); + page->kCBimportks->insertItem(optionsServer); + } + else if ( serverList.isEmpty() ) + serverList = "hkp://wwwkeys.eu.pgp.net,hkp://search.keyserver.net,hkp://wwwkeys.pgp.net,hkp://pgp.dtype.org,hkp://wwwkeys.us.pgp.net"; // same as ini kgpgoptions.cpp + + page->kCBexportks->insertStringList(QStringList::split(",",serverList)); + page->kCBimportks->insertStringList(QStringList::split(",",serverList)); +} + +void keyServer::slotOk() +{ + accept(); +} + + +#include "keyservers.moc" diff --git a/kgpg/keyservers.h b/kgpg/keyservers.h new file mode 100644 index 0000000..e17af85 --- /dev/null +++ b/kgpg/keyservers.h @@ -0,0 +1,81 @@ +/*************************************************************************** + keyservers.h - description + ------------------- + begin : Tue Nov 26 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KEYSERVERS_H +#define KEYSERVERS_H + +#include <kdialogbase.h> +#include "keyserver.h" + +class KListViewItem; +class KSimpleConfig; +class KProcIO; +class KProcess; + +class searchRes; + +class keyServer : public KDialogBase +{ + Q_OBJECT +public: + keyServer(QWidget *parent=0, const char *name=0,bool modal=false,bool autoClose=false); + ~keyServer(); + keyServerWidget *page; + +public slots: + void abortImport(); + void abortExport(); + void abortSearch(); + void transferKeyID(); + void slotsearchread(KProcIO *p); + void slotOk(); + void syncCombobox(); + void slotImport(); + void slotSearch(); + void slotimportresult(KProcess*); + void slotexportresult(KProcess*); + void slotimportread(KProcIO *p); + void slotprocread(KProcIO *p); + void slotPreExport(); + void slotExport(QStringList keyIds); + void preimport(); + void slotsearchresult(KProcess *); + void slotEnableProxyI(bool on); + void slotEnableProxyE(bool on); + void handleQuit(); + void slotTextChanged( const QString &text); + +private: + + QDialog *importpop; + KSimpleConfig *config; + uint keyNumbers; + QString readmessage; + KProcIO *importproc,*exportproc; + KProcIO *searchproc; + searchRes *listpop; + int count; + bool cycle,autoCloseWindow; + KListViewItem *kitem; + KDialogBase *dialogServer; + +signals: + void importFinished(QString); +}; + +#endif // KEYSERVERS_H + diff --git a/kgpg/kgpg.cpp b/kgpg/kgpg.cpp new file mode 100644 index 0000000..a14ab64 --- /dev/null +++ b/kgpg/kgpg.cpp @@ -0,0 +1,1057 @@ +/*************************************************************************** + kgpg.cpp - description + ------------------- + begin : Mon Nov 18 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <stdlib.h> + +#include <qlabel.h> +#include <qclipboard.h> +#include <qfile.h> +#include <qpopupmenu.h> +#include <qwidget.h> +#include <qcheckbox.h> +#include <qmovie.h> +#include <qcstring.h> +#include <qhbuttongroup.h> +#include <kglobal.h> +#include <kactivelabel.h> +#include <kdeversion.h> +#include <klocale.h> +#include <kconfig.h> +#include <kapplication.h> +#include <kmessagebox.h> +#include <kcombobox.h> +#include <qregexp.h> +#include <kcmdlineargs.h> +#include <qtooltip.h> +#include <kdebug.h> +#include <kurlrequesterdlg.h> +#include <klineedit.h> +#include <kio/renamedlg.h> +#include <kpassivepopup.h> +#include <qlayout.h> +#include <qbuttongroup.h> +#include <kiconloader.h> +#include <ktempfile.h> +#include <kwin.h> +#include <kprocess.h> +#include <kprocio.h> +#include <kaboutapplication.h> +#include <kurlrequester.h> +#include <ktip.h> +#include <kurldrag.h> +#include <ktar.h> +#include <kzip.h> +#include <dcopclient.h> +#include <kstandarddirs.h> +#include <kfiledialog.h> +#include <kpopupmenu.h> +#include <qcursor.h> +#include <kdesktopfile.h> + +#include "kgpgeditor.h" + +#include "kgpg.h" +#include "kgpgsettings.h" +#include "listkeys.h" +#include "keyserver.h" +#include "keyservers.h" +#include "popuppublic.h" +#include "kgpgview.h" +#include "kgpglibrary.h" +#include "kgpgwizard.h" + +MyView::MyView( QWidget *parent, const char *name ) + : QLabel( parent, name ) +{ + setBackgroundMode( X11ParentRelative ); + openTasks=0; + + KAction *saveDecrypt=new KAction(i18n("&Decrypt && Save File"),"decrypted",0,this, SLOT(decryptDroppedFile()),this,"decrypt_file"); + KAction *showDecrypt=new KAction(i18n("&Show Decrypted File"),"edit",0,this, SLOT(showDroppedFile()),this,"show_file"); + KAction *encrypt=new KAction(i18n("&Encrypt File"),"encrypted",0,this, SLOT(encryptDroppedFile()),this,"encrypt_file"); + KAction *sign=new KAction(i18n("&Sign File"), "signature",0,this, SLOT(signDroppedFile()),this,"sign_file"); + //QToolTip::add(this,i18n("KGpg drag & drop encryption applet")); + + readOptions(); + resize(24,24); + setPixmap( KSystemTray::loadIcon("kgpg_docked")); + setAcceptDrops(true); + + droppopup=new QPopupMenu(); + showDecrypt->plug(droppopup); + saveDecrypt->plug(droppopup); + + udroppopup=new QPopupMenu(); + encrypt->plug(udroppopup); + sign->plug(udroppopup); + QToolTip::add(this, i18n("KGpg - encryption tool")); +} + +MyView::~MyView() +{ + + delete droppopup; + droppopup = 0; + delete udroppopup; + udroppopup = 0; +} + + +void MyView::clipEncrypt() +{ + popupPublic *dialoguec=new popupPublic(0, "public_keys", 0,false,goDefaultKey); + connect(dialoguec,SIGNAL(selectedKey(QStringList,QStringList,bool,bool)),this,SLOT(encryptClipboard(QStringList,QStringList,bool,bool))); + dialoguec->exec(); + delete dialoguec; +} + +void MyView::clipDecrypt() +{ + QString clippie=kapp->clipboard()->text(clipboardMode).stripWhiteSpace(); + droppedtext(clippie,false); +} + +void MyView::clipSign(bool openEditor) +{ + QString clippie=kapp->clipboard()->text(clipboardMode).stripWhiteSpace(); + if (!clippie.isEmpty()) { + KgpgApp *kgpgtxtedit = new KgpgApp(0, "editor",WDestructiveClose,goDefaultKey); + connect(this,SIGNAL(setFont(QFont)),kgpgtxtedit,SLOT(slotSetFont(QFont))); + connect(kgpgtxtedit,SIGNAL(encryptFiles(KURL::List)),this,SLOT(encryptFiles(KURL::List))); + if (!openEditor) + connect(kgpgtxtedit->view,SIGNAL(verifyFinished()),kgpgtxtedit,SLOT(closeWindow())); + kgpgtxtedit->view->editor->setText(clippie); + kgpgtxtedit->view->clearSign(); + kgpgtxtedit->show(); + + } else + KMessageBox::sorry(this,i18n("Clipboard is empty.")); +} + +void MyView::encryptDroppedFolder() +{ + compressionScheme=0; + kgpgfoldertmp=new KTempFile(QString::null); + kgpgfoldertmp->setAutoDelete(true); + if (KMessageBox::warningContinueCancel(0,i18n("<qt>KGpg will now create a temporary archive file:<br><b>%1</b> to process the encryption. The file will be deleted after the encryption is finished.</qt>").arg(kgpgfoldertmp->name()),i18n("Temporary File Creation"),KStdGuiItem::cont(),"FolderTmpFile")==KMessageBox::Cancel) + return; + + dialogue=new popupPublic(0,"Public keys",droppedUrls.first().fileName(),true,goDefaultKey); + + QHButtonGroup *bGroup = new QHButtonGroup(dialogue->plainPage()); + (void) new QLabel(i18n("Compression method for archive:"),bGroup); + KComboBox *optionbx=new KComboBox(bGroup); + optionbx->insertItem(i18n("Zip")); + optionbx->insertItem(i18n("Gzip")); + optionbx->insertItem(i18n("Bzip2")); + bGroup->show(); + connect(dialogue,SIGNAL(keyListFilled ()),dialogue,SLOT(slotSetVisible())); + connect(optionbx,SIGNAL(activated (int)),this,SLOT(slotSetCompression(int))); + connect(dialogue,SIGNAL(selectedKey(QStringList,QStringList,bool,bool)),this,SLOT(startFolderEncode(QStringList,QStringList,bool,bool))); + dialogue->CBshred->setEnabled(false); + dialogue->exec(); + dialogue=0L; +} + +void MyView::slotSetCompression(int cp) +{ +compressionScheme=cp; +} + +void MyView::startFolderEncode(QStringList selec,QStringList encryptOptions,bool ,bool symetric) +{ +QString extension; + +if (compressionScheme==0) + extension=".zip"; + else if (compressionScheme==1) + extension=".tar.gz"; + else + extension=".tar.bz2"; + +if (encryptOptions.find("armor")!=encryptOptions.end () ) + extension+=".asc"; + else if (KGpgSettings::pgpExtension()) + extension+=".pgp"; + else + extension+=".gpg"; + +KURL encryptedFile(droppedUrls.first().path()+extension); +QFile encryptedFolder(droppedUrls.first().path()+extension); +if (encryptedFolder.exists()) { + dialogue->hide(); + KIO::RenameDlg *over=new KIO::RenameDlg(0,i18n("File Already Exists"),QString::null,encryptedFile.path(),KIO::M_OVERWRITE); + if (over->exec()==QDialog::Rejected) + { + delete over; + return; + } + encryptedFile=over->newDestURL(); + delete over; + dialogue->show(); /////// strange, but if dialogue is hidden, the passive popup is not displayed... + } + +pop = new KPassivePopup(); + pop->setView(i18n("Processing folder compression and encryption"),i18n("Please wait..."),KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop)); + pop->setAutoDelete(false); + pop->show(); + kapp->processEvents(); + dialogue->slotAccept(); + dialogue=0L; + + KArchive *arch; + if (compressionScheme==0) + arch=new KZip(kgpgfoldertmp->name()); + else if (compressionScheme==1) + arch=new KTar(kgpgfoldertmp->name(), "application/x-gzip"); + else + arch=new KTar(kgpgfoldertmp->name(), "application/x-bzip2"); + + if (!arch->open( IO_WriteOnly )) { + KMessageBox::sorry(0,i18n("Unable to create temporary file")); + delete arch; + return; + } + arch->addLocalDirectory (droppedUrls.first().path(),droppedUrls.first().fileName()); + arch->close(); + delete arch; + + KgpgInterface *folderprocess=new KgpgInterface(); + folderprocess->KgpgEncryptFile(selec,KURL(kgpgfoldertmp->name()),encryptedFile,encryptOptions,symetric); + connect(folderprocess,SIGNAL(encryptionfinished(KURL)),this,SLOT(slotFolderFinished(KURL))); + connect(folderprocess,SIGNAL(errormessage(QString)),this,SLOT(slotFolderFinishedError(QString))); +} + +void MyView::slotFolderFinished(KURL) +{ + delete pop; + delete kgpgfoldertmp; +} + +void MyView::slotFolderFinishedError(QString errmsge) +{ + delete pop; + delete kgpgfoldertmp; + KMessageBox::sorry(0,errmsge); +} + +void MyView::busyMessage(QString mssge,bool reset) +{ +if (reset) openTasks=0; +if (!mssge.isEmpty()) +{ +openTasks++; +QToolTip::remove(this); +QToolTip::add(this, mssge); +setMovie(QMovie(locate("appdata","pics/kgpg_docked.gif"))); +} +else openTasks--; + +//kdDebug(2100) << "Emit message: "<<openTasks<<endl; + +if (openTasks<=0) +{ +setPixmap( KSystemTray::loadIcon("kgpg_docked")); +QToolTip::remove(this); +QToolTip::add(this, i18n("KGpg - encryption tool")); +openTasks=0; +} +} + +void MyView::encryptDroppedFile() +{ + QStringList opts; + KgpgLibrary *lib=new KgpgLibrary(this,KGpgSettings::pgpExtension()); + connect(lib,SIGNAL(systemMessage(QString,bool)),this,SLOT(busyMessage(QString,bool))); + if (KGpgSettings::fileKey()!=QString::null) { + if (KGpgSettings::allowUntrustedKeys()) + opts<<"--always-trust"; + if (KGpgSettings::asciiArmor()) + opts<<"--armor"; + if (KGpgSettings::hideUserID()) + opts<<"--throw-keyid"; + if (KGpgSettings::pgpCompatibility()) + opts<<"--pgp6"; + lib->slotFileEnc(droppedUrls,opts,QStringList::split(" ",KGpgSettings::fileKey()),goDefaultKey); + } else + lib->slotFileEnc(droppedUrls,QString::null,QString::null,goDefaultKey); +} + +void MyView::encryptFiles(KURL::List urls) +{ +droppedUrls=urls; +encryptDroppedFile(); +} + +void MyView::shredDroppedFile() +{ +KDialogBase *shredConfirm=new KDialogBase( this, "confirm_shred", true,i18n("Shred Files"),KDialogBase::Ok | KDialogBase::Cancel); +QWidget *page = new QWidget(shredConfirm); +shredConfirm->setMainWidget(page); +QBoxLayout *layout=new QBoxLayout(page,QBoxLayout::TopToBottom,0); +layout->setAutoAdd(true); + +(void) new KActiveLabel( i18n("Do you really want to <a href=\"whatsthis:%1\">shred</a> these files?").arg(i18n( "<qt><p>You must be aware that <b>shredding is not secure</b> on all file systems, and that parts of the file may have been saved in a temporary file or in the spooler of your printer if you previously opened it in an editor or tried to print it. Only works on files (not on folders).</p></qt>")),page); +KListBox *lb=new KListBox(page); +lb->insertStringList(droppedUrls.toStringList()); +if (shredConfirm->exec()==QDialog::Accepted) + { + KgpgLibrary *lib=new KgpgLibrary(this); + connect(lib,SIGNAL(systemMessage(QString,bool)),this,SLOT(busyMessage(QString,bool))); + lib->shredprocessenc(droppedUrls); + } +delete shredConfirm; +} + + +void MyView::slotVerifyFile() +{ + /////////////////////////////////// check file signature + if (droppedUrl.isEmpty()) + return; + + QString sigfile=QString::null; + ////////////////////////////////////// try to find detached signature. + if (!droppedUrl.fileName().endsWith(".sig")) { + sigfile=droppedUrl.path()+".sig"; + QFile fsig(sigfile); + if (!fsig.exists()) { + sigfile=droppedUrl.path()+".asc"; + QFile fsig(sigfile); + ////////////// if no .asc or .sig signature file included, assume the file is internally signed + if (!fsig.exists()) + sigfile=QString::null; + } + } else { + sigfile=droppedUrl.path(); + droppedUrl=KURL(sigfile.left(sigfile.length()-4)); + } + + ///////////////////////// pipe gpg command + KgpgInterface *verifyFileProcess=new KgpgInterface(); + verifyFileProcess->KgpgVerifyFile(droppedUrl,KURL(sigfile)); + connect (verifyFileProcess,SIGNAL(verifyquerykey(QString)),this,SLOT(importSignature(QString))); +} + +void MyView::importSignature(QString ID) +{ + keyServer *kser=new keyServer(0,"server_dialog",false); + kser->page->kLEimportid->setText(ID); + kser->slotImport(); +} + +void MyView::signDroppedFile() +{ + ////////////////////////////////////// create a detached signature for a chosen file + if (droppedUrl.isEmpty()) + return; + + QString signKeyID; + ////////////////// select a private key to sign file --> listkeys.cpp + KgpgSelKey *opts=new KgpgSelKey(0,"select_secret"); + if (opts->exec()==QDialog::Accepted) + signKeyID=opts->getkeyID(); + else { + delete opts; + return; + } + delete opts; + QStringList Options; + if (KGpgSettings::asciiArmor()) + Options<<"--armor"; + if (KGpgSettings::pgpCompatibility()) + Options<<"--pgp6"; + KgpgInterface *signFileProcess=new KgpgInterface(); + signFileProcess->KgpgSignFile(signKeyID,droppedUrl,Options); +} + +void MyView::decryptDroppedFile() +{ + //bool isFolder=false; // droppedUrls + KURL swapname; + + if (!droppedUrls.first().isLocalFile()) { + showDroppedFile(); + decryptNextFile(); + } + + QString oldname=droppedUrls.first().fileName(); + if (oldname.endsWith(".gpg") || oldname.endsWith(".asc") || oldname.endsWith(".pgp")) + oldname.truncate(oldname.length()-4); + else + oldname.append(".clear"); + /* + if (oldname.endsWith(".tar.gz")) { + isFolder=true; + kgpgFolderExtract=new KTempFile(QString::null,".tar.gz"); + kgpgFolderExtract->setAutoDelete(true); + swapname=KURL(kgpgFolderExtract->name()); + if (KMessageBox::warningContinueCancel(0,i18n("<qt>The file to decrypt is an archive. KGpg will create a temporary unencrypted archive file:<br><b>%1</b> before processing the archive extraction. This temporary file will be deleted after the decryption is finished.</qt>").arg(kgpgFolderExtract->name()),i18n("Temporary File Creation"),KStdGuiItem::cont(),"FolderTmpDecFile")==KMessageBox::Cancel) + return; + } else*/ { + swapname=KURL(droppedUrls.first().directory(0,0)+oldname); + QFile fgpg(swapname.path()); + if (fgpg.exists()) { + KIO::RenameDlg *over=new KIO::RenameDlg(0,i18n("File Already Exists"),QString::null,swapname.path(),KIO::M_OVERWRITE); + if (over->exec()==QDialog::Rejected) + { + delete over; + decryptNextFile(); + return; + } + swapname=over->newDestURL(); + delete over; + } + } + KgpgLibrary *lib=new KgpgLibrary(this); + lib->slotFileDec(droppedUrls.first(),swapname,KGpgSettings::customDecrypt()); + connect(lib,SIGNAL(importOver(QStringList)),this,SIGNAL(importedKeys(QStringList))); + connect(lib,SIGNAL(systemMessage(QString,bool)),this,SLOT(busyMessage(QString,bool))); +// if (isFolder) + connect(lib,SIGNAL(decryptionOver()),this,SLOT(decryptNextFile())); + +} + +void MyView::decryptNextFile() +{ +if (droppedUrls.count()>1) +{ +droppedUrls.pop_front(); +decryptDroppedFile(); +} +} + +void MyView::unArchive() +{ + KTar compressedFolder(kgpgFolderExtract->name(),"application/x-gzip"); + if (!compressedFolder.open( IO_ReadOnly )) { + KMessageBox::sorry(0,i18n("Unable to read temporary archive file")); + return; + } + const KArchiveDirectory *archiveDirectory=compressedFolder.directory(); + //KURL savePath=KURL::getURL(droppedUrl,this,i18n("")); + KURLRequesterDlg *savePath=new KURLRequesterDlg(droppedUrl.directory(false),i18n("Extract to: "),0,"extract"); + savePath->fileDialog()->setMode(KFile::Directory); + if (!savePath->exec()==QDialog::Accepted) { + delete kgpgFolderExtract; + return; + } + archiveDirectory->KArchiveDirectory::copyTo(savePath->selectedURL().path()); + compressedFolder.close(); + delete savePath; + delete kgpgFolderExtract; +} + + +void MyView::showDroppedFile() +{ +kdDebug(2100)<<"------Show dropped file"<<endl; + KgpgApp *kgpgtxtedit = new KgpgApp(0, "editor",WDestructiveClose,goDefaultKey); + kgpgtxtedit->view->editor->slotDroppedFile(droppedUrls.first()); + connect(kgpgtxtedit,SIGNAL(encryptFiles(KURL::List)),this,SLOT(encryptFiles(KURL::List))); + connect(this,SIGNAL(setFont(QFont)),kgpgtxtedit,SLOT(slotSetFont(QFont))); + connect(kgpgtxtedit,SIGNAL(refreshImported(QStringList)),this,SIGNAL(importedKeys(QStringList))); + connect(kgpgtxtedit->view->editor,SIGNAL(refreshImported(QStringList)),this,SIGNAL(importedKeys(QStringList))); + kgpgtxtedit->show(); +} + + +void MyView::droppedfile (KURL::List url) +{ + droppedUrls=url; + droppedUrl=url.first(); + if (KMimeType::findByURL(droppedUrl)->name()=="inode/directory") { + encryptDroppedFolder(); + //KMessageBox::sorry(0,i18n("Sorry, only file operations are currently supported.")); + return; + } + if (!droppedUrl.isLocalFile()) { + showDroppedFile(); + return; + } + + if ((droppedUrl.path().endsWith(".asc")) || (droppedUrl.path().endsWith(".pgp")) || (droppedUrl.path().endsWith(".gpg"))) { + switch (KGpgSettings::encryptedDropEvent()) { + case KGpgSettings::EnumEncryptedDropEvent::DecryptAndSave: + decryptDroppedFile(); + break; + case KGpgSettings::EnumEncryptedDropEvent::DecryptAndOpen: + showDroppedFile(); + break; + case KGpgSettings::EnumEncryptedDropEvent::Ask: + droppopup->exec(QCursor::pos ()); + kdDebug(2100)<<"Drop menu--------"<<endl; + break; + } + } else if (droppedUrl.path().endsWith(".sig")) { + slotVerifyFile(); + } else + switch (KGpgSettings::unencryptedDropEvent()) { + case KGpgSettings::EnumUnencryptedDropEvent::Encrypt: + encryptDroppedFile(); + break; + case KGpgSettings::EnumUnencryptedDropEvent::Sign: + signDroppedFile(); + break; + case KGpgSettings::EnumUnencryptedDropEvent::Ask: + udroppopup->exec(QCursor::pos ()); + break; + } +} + + +void MyView::droppedtext (QString inputText,bool allowEncrypt) +{ + + if (inputText.startsWith("-----BEGIN PGP MESSAGE")) { + KgpgApp *kgpgtxtedit = new KgpgApp(0, "editor",WDestructiveClose,goDefaultKey); + connect(kgpgtxtedit,SIGNAL(encryptFiles(KURL::List)),this,SLOT(encryptFiles(KURL::List))); + connect(this,SIGNAL(setFont(QFont)),kgpgtxtedit,SLOT(slotSetFont(QFont))); + kgpgtxtedit->view->editor->setText(inputText); + kgpgtxtedit->view->slotdecode(); + kgpgtxtedit->show(); + return; + } + if (inputText.startsWith("-----BEGIN PGP PUBLIC KEY")) { + int result=KMessageBox::warningContinueCancel(0,i18n("<p>The dropped text is a public key.<br>Do you want to import it ?</p>"),i18n("Warning")); + if (result==KMessageBox::Cancel) + return; + else { + KgpgInterface *importKeyProcess=new KgpgInterface(); + importKeyProcess->importKey(inputText); + connect(importKeyProcess,SIGNAL(importfinished(QStringList)),this,SIGNAL(importedKeys(QStringList))); + return; + } + } + if (inputText.startsWith("-----BEGIN PGP SIGNED MESSAGE")) { + clipSign(false); + return; + } + if (allowEncrypt) clipEncrypt(); + else KMessageBox::sorry(this,i18n("No encrypted text found.")); +} + + +void MyView::dragEnterEvent(QDragEnterEvent *e) +{ + e->accept (KURLDrag::canDecode(e) || QTextDrag::canDecode (e)); +} + + +void MyView::dropEvent (QDropEvent *o) +{ + KURL::List list; + QString text; + if ( KURLDrag::decode( o, list ) ) + droppedfile(list); + else if ( QTextDrag::decode(o, text) ) + { + QApplication::clipboard()->setText(text,clipboardMode); + droppedtext(text); + } +} + + +void MyView::readOptions() +{ + clipboardMode=QClipboard::Clipboard; + if ( KGpgSettings::useMouseSelection() && kapp->clipboard()->supportsSelection()) + clipboardMode=QClipboard::Selection; + + if (KGpgSettings::firstRun()) { + firstRun(); + } else { + QString path = KGpgSettings::gpgConfigPath(); + if (path.isEmpty()) { + if (KMessageBox::questionYesNo(0,i18n("<qt>You have not set a path to your GnuPG config file.<br>This may cause some surprising results in KGpg's execution.<br>Would you like to start KGpg's Wizard to fix this problem?</qt>"),QString::null,i18n("Start Wizard"),i18n("Do Not Start"))==KMessageBox::Yes) + startWizard(); + } else { + QStringList groups=KgpgInterface::getGpgGroupNames(path); + if (!groups.isEmpty()) + KGpgSettings::setGroups(groups.join(",")); + } + } +} + + +void MyView::firstRun() +{ + KProcIO *p=new KProcIO(); + *p<<"gpg"<<"--no-tty"<<"--list-secret-keys"; + p->start(KProcess::Block); //// start gnupg so that it will create a config file + startWizard(); +} + + +static QString getGpgHome() +{ + char *env=getenv("GNUPGHOME"); + QString gpgHome(env ? env : QDir::homeDirPath()+"/.gnupg/"); + + gpgHome.replace("//", "/"); + + if(!gpgHome.endsWith("/")) + gpgHome.append('/'); + + KStandardDirs::makeDir(gpgHome, 0700); + return gpgHome; +} + + +void MyView::startWizard() +{ + kdDebug(2100)<<"Starting Wizard"<<endl; + wiz=new KgpgWizard(0,"wizard"); + QString gpgHome(getGpgHome()); + QString confPath=gpgHome+"options"; + if (!QFile(confPath).exists()) { + confPath=gpgHome+"gpg.conf"; + if (!QFile(confPath).exists()) { + if (KMessageBox::questionYesNo(this,i18n("<qt><b>The GnuPG configuration file was not found</b>. Please make sure you have GnuPG installed. Should KGpg try to create a config file ?</qt>"),QString::null,i18n("Create Config"),i18n("Do Not Create"))==KMessageBox::Yes) { + confPath=gpgHome+"options"; + QFile file(confPath); + if ( file.open( IO_WriteOnly ) ) { + QTextStream stream( &file ); + stream <<"# GnuPG config file created by KGpg"<< "\n"; + file.close(); + } + } else { + wiz->text_optionsfound->setText(i18n("<qt><b>The GnuPG configuration file was not found</b>. Please make sure you have GnuPG installed and give the path to the config file.</qt>")); + confPath=QString::null; + } + } + } + + int gpgVersion=KgpgInterface::getGpgVersion(); + if (gpgVersion<120) wiz->txtGpgVersion->setText(i18n("Your GnuPG version seems to be older than 1.2.0. Photo Id's and Key Groups will not work properly. Please consider upgrading GnuPG (http://gnupg.org).")); + else wiz->txtGpgVersion->setText(QString::null); + + wiz->kURLRequester1->setURL(confPath); + /* + wiz->kURLRequester2->setURL(KGlobalSettings::desktopPath()); + wiz->kURLRequester2->setMode(2);*/ + + FILE *fp,*fp2; + QString tst,tst2,name,trustedvals="idre-"; + QString firstKey=QString::null; + char line[300]; + bool counter=false; + + fp = popen("gpg --display-charset=utf-8 --no-tty --with-colon --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp)) { + tst=QString::fromUtf8(line); + if (tst.startsWith("sec")) { + name=KgpgInterface::checkForUtf8(tst.section(':',9,9)); + if (!name.isEmpty()) { + fp2 = popen("gpg --display-charset=utf-8 --no-tty --with-colon --list-keys "+QFile::encodeName(tst.section(':',4,4)), "r"); + while ( fgets( line, sizeof(line), fp2)) { + tst2=QString::fromUtf8(line); + if (tst2.startsWith("pub") && (trustedvals.find(tst2.section(':',1,1))==-1)) { + counter=true; + wiz->CBdefault->insertItem(tst.section(':',4,4).right(8)+": "+name); + if (firstKey.isEmpty()) + firstKey=tst.section(':',4,4).right(8)+": "+name; + break; + } + } + pclose(fp2); + } + } + } + pclose(fp); + wiz->CBdefault->setCurrentItem(firstKey); + //connect(wiz->pushButton4,SIGNAL(clicked()),this,SLOT(slotGenKey())); + if (!counter) + connect(wiz->finishButton(),SIGNAL(clicked()),this,SLOT(slotGenKey())); + else { + wiz->textGenerate->hide(); + wiz->setTitle(wiz->page_4,i18n("Step Three: Select your Default Private Key")); + connect(wiz->finishButton(),SIGNAL(clicked()),this,SLOT(slotSaveOptionsPath())); + } + connect(wiz->nextButton(),SIGNAL(clicked()),this,SLOT(slotWizardChange())); + connect( wiz , SIGNAL( destroyed() ) , this, SLOT( slotWizardClose())); + connect(wiz,SIGNAL(helpClicked()),this,SLOT(help())); + + wiz->setFinishEnabled(wiz->page_4,true); + wiz->show(); +} + +void MyView::slotWizardChange() +{ + QString tst,name; + char line[300]; + FILE *fp; + + if (wiz->indexOf(wiz->currentPage())==2) { + QString defaultID=KgpgInterface::getGpgSetting("default-key",wiz->kURLRequester1->url()); + if (defaultID.isEmpty()) + return; + fp = popen("gpg --display-charset=utf-8 --no-tty --with-colon --list-secret-keys "+QFile::encodeName(defaultID), "r"); + while ( fgets( line, sizeof(line), fp)) { + tst=QString::fromUtf8(line); + if (tst.startsWith("sec")) { + name=KgpgInterface::checkForUtf8(tst.section(':',9,9)); + wiz->CBdefault->setCurrentItem(tst.section(':',4,4).right(8)+": "+name); + } + } + pclose(fp); + } +} + +void MyView::installShred() +{ + KURL path; + path.setPath(KGlobalSettings::desktopPath()); + path.addPath("shredder.desktop"); + KDesktopFile configl2(path.path(), false); + if (configl2.isImmutable() ==false) { + configl2.setGroup("Desktop Entry"); + configl2.writeEntry("Type", "Application"); + configl2.writeEntry("Name",i18n("Shredder")); + configl2.writeEntry("Icon","editshred"); + configl2.writeEntry("Exec","kgpg -X %U"); + } +} + +void MyView::slotSaveOptionsPath() +{ +qWarning("Save wizard settings..."); + if (wiz->checkBox1->isChecked()) installShred(); + + KGpgSettings::setAutoStart( wiz->checkBox2->isChecked() ); + + KGpgSettings::setGpgConfigPath( wiz->kURLRequester1->url() ); + KGpgSettings::setFirstRun( false ); + + QString defaultID=wiz->CBdefault->currentText().section(':',0,0); +/* if (!defaultID.isEmpty()) { + KGpgSettings::setDefaultKey(defaultID); + }*/ + + KGpgSettings::writeConfig(); + + emit updateDefault("0x"+defaultID); + if (wiz) + delete wiz; +} + +void MyView::slotWizardClose() +{ + wiz=0L; +} + +void MyView::slotGenKey() +{ + slotSaveOptionsPath(); + emit createNewKey(); +} + +void MyView::about() +{ + KAboutApplication dialog(kapp->aboutData());//_aboutData); + dialog.exec(); +} + +void MyView::help() +{ + kapp->invokeHelp(0,"kgpg"); +} + +kgpgapplet::kgpgapplet(QWidget *parent, const char *name) + : KSystemTray(parent,name) +{ + w=new MyView(this); + w->show(); + KPopupMenu *conf_menu=contextMenu(); + KgpgEncryptClipboard = new KAction(i18n("&Encrypt Clipboard"), "kgpg", 0,w, SLOT(clipEncrypt()),actionCollection(),"clip_encrypt"); + KgpgDecryptClipboard = new KAction(i18n("&Decrypt Clipboard"), 0, 0,w, SLOT(clipDecrypt()),actionCollection(),"clip_decrypt"); + KgpgSignClipboard = new KAction(i18n("&Sign/Verify Clipboard"), "signature", 0,w, SLOT(clipSign()),actionCollection(),"clip_sign"); + KAction *KgpgOpenEditor; + if (KGpgSettings::leftClick()==KGpgSettings::EnumLeftClick::KeyManager) + KgpgOpenEditor = new KAction(i18n("&Open Editor"), "edit", 0,parent, SLOT(slotOpenEditor()),actionCollection(),"kgpg_editor"); + else + KgpgOpenEditor = new KAction(i18n("&Open Key Manager"), "kgpg", 0,this, SLOT(slotOpenKeyManager()),actionCollection(),"kgpg_editor"); + + KAction *KgpgOpenServer = new KAction(i18n("&Key Server Dialog"), "network", 0,this, SLOT(slotOpenServerDialog()),actionCollection(),"kgpg_server"); + KAction *KgpgPreferences=KStdAction::preferences(this, SLOT(showOptions()), actionCollection()); + + connect (conf_menu,SIGNAL(aboutToShow()),this,SLOT(checkMenu())); + + KgpgEncryptClipboard->plug(conf_menu); + KgpgDecryptClipboard->plug(conf_menu); + KgpgSignClipboard->plug(conf_menu); + KgpgOpenEditor->plug(conf_menu); + KgpgOpenServer->plug(conf_menu); + conf_menu->insertSeparator(); + KgpgPreferences->plug(conf_menu); +} + + +void kgpgapplet::checkMenu() +{ + KgpgDecryptClipboard->setEnabled(false); + if ((kapp->clipboard()->text(w->clipboardMode).isEmpty())) + { + KgpgEncryptClipboard->setEnabled(false); + KgpgSignClipboard->setEnabled(false); + } + else + { + KgpgEncryptClipboard->setEnabled(true); + if (kapp->clipboard()->text(w->clipboardMode).stripWhiteSpace().startsWith("-----BEGIN")) + KgpgDecryptClipboard->setEnabled(true); + KgpgSignClipboard->setEnabled(true); + } +} + +void kgpgapplet::showOptions() +{ +QByteArray data; +if (!kapp->dcopClient()->send("kgpg", "KeyInterface", "showOptions()",data)) +kdDebug(2100) <<"there was some error using DCOP."<<endl; +} + +void kgpgapplet::slotOpenKeyManager() +{ +QByteArray data; +if (!kapp->dcopClient()->send("kgpg", "KeyInterface", "showKeyManager()",data)) +kdDebug(2100) <<"there was some error using DCOP."<<endl; +} + +void kgpgapplet::slotOpenServerDialog() +{ +QByteArray data; +if (!kapp->dcopClient()->send("kgpg", "KeyInterface", "showKeyServer()",data)) +kdDebug(2100) <<"there was some error using DCOP."<<endl; +} + + + +kgpgapplet::~kgpgapplet() +{ + delete w; + w = 0L; +} + +KgpgAppletApp::KgpgAppletApp() + : KUniqueApplication()//, kgpg_applet( 0 ) +{ + + running=false; +} + + +KgpgAppletApp::~KgpgAppletApp() +{ + delete s_keyManager; + s_keyManager=0L; + delete kgpg_applet; + kgpg_applet = 0L; +} + +void KgpgAppletApp::slotHandleQuit() +{ +s_keyManager->keysList2->saveLayout(KGlobal::config(),"KeyView"); + KGpgSettings::setPhotoProperties(s_keyManager->photoProps->currentItem()); + KGpgSettings::setShowTrust(s_keyManager->sTrust->isChecked()); + KGpgSettings::setShowExpi(s_keyManager->sExpi->isChecked()); + KGpgSettings::setShowCreat(s_keyManager->sCreat->isChecked()); + KGpgSettings::setShowSize(s_keyManager->sSize->isChecked()); + KGpgSettings::writeConfig(); + KSimpleConfig ("kgpgrc").sync(); + quit(); +} + +void KgpgAppletApp::wizardOver(QString defaultKeyId) +{ + if (defaultKeyId.length()==10) + s_keyManager->slotSetDefaultKey(defaultKeyId); + s_keyManager->show(); + s_keyManager->raise(); +} + +int KgpgAppletApp::newInstance() +{ + kdDebug(2100)<<"New instance"<<endl; + args = KCmdLineArgs::parsedArgs(); + if (running) { + kdDebug(2100)<<"Already running"<<endl; + kgpg_applet->show(); + } else { + kdDebug(2100) << "Starting KGpg"<<endl; + running=true; + + s_keyManager=new listKeys(0, "key_manager"); + + QString gpgPath= KGpgSettings::gpgConfigPath(); + if (!gpgPath.isEmpty() && KURL(gpgPath).directory(false)!=QDir::homeDirPath()+"/.gnupg/") + setenv("GNUPGHOME", QFile::encodeName(KURL::fromPathOrURL(gpgPath).directory(false)), 1); + + s_keyManager->refreshkey(); + + if (KGpgSettings::leftClick()==KGpgSettings::EnumLeftClick::KeyManager) + kgpg_applet=new kgpgapplet(s_keyManager,"kgpg_systrayapplet"); + else + { + kgpg_applet=new kgpgapplet(s_keyManager->s_kgpgEditor,"kgpg_systrayapplet"); + } + connect(s_keyManager,SIGNAL(encryptFiles(KURL::List)),kgpg_applet->w,SLOT(encryptFiles(KURL::List))); + connect(s_keyManager,SIGNAL(installShredder()),kgpg_applet->w,SLOT(installShred())); + connect(s_keyManager->s_kgpgEditor,SIGNAL(encryptFiles(KURL::List)),kgpg_applet->w,SLOT(encryptFiles(KURL::List))); + + connect( kgpg_applet, SIGNAL(quitSelected()), this, SLOT(slotHandleQuit())); + connect(s_keyManager,SIGNAL(readAgainOptions()),kgpg_applet->w,SLOT(readOptions())); + connect(kgpg_applet->w,SIGNAL(updateDefault(QString)),this,SLOT(wizardOver(QString))); + connect(kgpg_applet->w,SIGNAL(createNewKey()),s_keyManager,SLOT(slotgenkey())); + connect(s_keyManager,SIGNAL(fontChanged(QFont)),kgpg_applet->w,SIGNAL(setFont(QFont))); + connect(kgpg_applet->w,SIGNAL(importedKeys(QStringList)),s_keyManager->keysList2,SLOT(slotReloadKeys(QStringList))); + kgpg_applet->show(); + + + if (!gpgPath.isEmpty()) { + if ((KgpgInterface::getGpgBoolSetting("use-agent",gpgPath)) && (!getenv("GPG_AGENT_INFO"))) + KMessageBox::sorry(0,i18n("<qt>The use of <b>GnuPG Agent</b> is enabled in GnuPG's configuration file (%1).<br>" + "However, the agent does not seem to be running. This could result in problems with signing/decryption.<br>" + "Please disable GnuPG Agent from KGpg settings, or fix the agent.</qt>").arg(gpgPath)); + } + + } + goHome=s_keyManager->actionCollection()->action("go_default_key")->shortcut(); + kgpg_applet->w->goDefaultKey=goHome; + + //////////////////////// parsing of command line args + if (args->isSet("k")!=0) { + s_keyManager->show(); + KWin::setOnDesktop( s_keyManager->winId() , KWin::currentDesktop() ); //set on the current desktop + KWin::deIconifyWindow( s_keyManager->winId()); //de-iconify window + s_keyManager->raise(); // set on top + } else + if (args->count()>0) { + kdDebug(2100) << "KGpg: found files"<<endl; + + urlList.clear(); + + for (int ct=0;ct<args->count();ct++) + urlList.append(args->url(ct)); + + if (urlList.empty()) + return 0; + + kgpg_applet->w->droppedUrl=urlList.first(); + + bool directoryInside=false; + QStringList lst=urlList.toStringList(); + for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) { + if (KMimeType::findByURL(KURL( *it ))->name()=="inode/directory") + directoryInside=true; + } + + if ((directoryInside) && (lst.count()>1)) { + KMessageBox::sorry(0,i18n("Unable to perform requested operation.\nPlease select only one folder, or several files, but do not mix files and folders.")); + return 0; + } + + kgpg_applet->w->droppedUrls=urlList; + + if (args->isSet("e")!=0) { + if (!directoryInside) + kgpg_applet->w->encryptDroppedFile(); + else + kgpg_applet->w->encryptDroppedFolder(); + } else if (args->isSet("X")!=0) { + if (!directoryInside) + kgpg_applet->w->shredDroppedFile(); + else + KMessageBox::sorry(0,i18n("Cannot shred folder.")); + } else if (args->isSet("s")!=0) { + if (!directoryInside) + kgpg_applet->w->showDroppedFile(); + else + KMessageBox::sorry(0,i18n("Cannot decrypt and show folder.")); + } else if (args->isSet("S")!=0) { + if (!directoryInside) + kgpg_applet->w->signDroppedFile(); + else + KMessageBox::sorry(0,i18n("Cannot sign folder.")); + } else if (args->isSet("V")!=0) { + if (!directoryInside) + kgpg_applet->w->slotVerifyFile(); + else + KMessageBox::sorry(0,i18n("Cannot verify folder.")); + } else if (kgpg_applet->w->droppedUrl.fileName().endsWith(".sig")) + kgpg_applet->w->slotVerifyFile(); + else + kgpg_applet->w->decryptDroppedFile(); + } + return 0; +} + + + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +void MyView::encryptClipboard(QStringList selec,QStringList encryptOptions,bool,bool symmetric) +{ + if (kapp->clipboard()->text(clipboardMode).isEmpty()) { + KPassivePopup::message(i18n("Clipboard is empty."),QString::null,KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop),this); + return; + } + if (KGpgSettings::pgpCompatibility()) + encryptOptions<<"--pgp6"; + encryptOptions<<"--armor"; + + if (symmetric) selec.clear(); + KgpgInterface *txtEncrypt=new KgpgInterface(); + connect (txtEncrypt,SIGNAL(txtencryptionfinished(QString)),this,SLOT(slotSetClip(QString))); + connect (txtEncrypt,SIGNAL(txtencryptionstarted()),this,SLOT(slotPassiveClip())); + txtEncrypt->KgpgEncryptText(kapp->clipboard()->text(clipboardMode),selec,encryptOptions); +} + +void MyView::slotPassiveClip() +{ +QString newtxt=kapp->clipboard()->text(clipboardMode); +if (newtxt.length()>300) + newtxt=QString(newtxt.left(250).stripWhiteSpace())+"...\n"+QString(newtxt.right(40).stripWhiteSpace()); + + newtxt.replace(QRegExp("<"),"<"); ///// disable html tags + newtxt.replace(QRegExp("\n"),"<br>"); + +pop = new KPassivePopup( this); + pop->setView(i18n("Encrypted following text:"),newtxt,KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop)); + pop->setTimeout(3200); + pop->show(); + QRect qRect(QApplication::desktop()->screenGeometry()); + int iXpos=qRect.width()/2-pop->width()/2; + int iYpos=qRect.height()/2-pop->height()/2; + pop->move(iXpos,iYpos); +} + +void MyView::slotSetClip(QString newtxt) +{ + if (newtxt.isEmpty()) return; + QApplication::clipboard()->setText(newtxt,clipboardMode);//,QClipboard::Clipboard); QT 3.1 only +} + + + +///////////////////////////////////////////////////////////////////////////// + +#include "kgpg.moc" + + diff --git a/kgpg/kgpg.desktop b/kgpg/kgpg.desktop new file mode 100644 index 0000000..e5b844f --- /dev/null +++ b/kgpg/kgpg.desktop @@ -0,0 +1,123 @@ +# KDE Config File +[Desktop Entry] +Type=Application +Exec=kgpg %U +Icon=kgpg +DocPath=kgpg/index.html +MimeType=application/pgp-encrypted;application/pgp-signature;application/pgp-keys; +GenericName=Encryption Tool +GenericName[ar]=أداة للتشفير +GenericName[bg]=Програма за шифроване +GenericName[br]=Ostilh enrinegadur +GenericName[bs]=Alat za šifrovanje +GenericName[ca]=Eina de xifrat +GenericName[cs]=Šifrovací nástroj +GenericName[cy]=Erfyn Cêl-ysgrifo +GenericName[da]=Krypteringsværktøj +GenericName[de]=Verschlüsselungsprogramm +GenericName[el]=Εργαλείο κρυπτογράφησης +GenericName[eo]=Ilo por Ĉifrado +GenericName[es]=Herramienta de cifrado +GenericName[et]=Krüptimisvahend +GenericName[eu]=Zifraketa Tresna +GenericName[fa]=میلۀ رمزبندی +GenericName[fi]=Salaustyökalu +GenericName[fr]=Outil de cryptage +GenericName[ga]=Uirlis Chriptithe +GenericName[he]=כלי הצפנה +GenericName[hi]=एनक्रिप्शन औज़ार +GenericName[hu]=Titkosítóeszköz +GenericName[is]=Dulritunartól +GenericName[it]=Strumento di crittografia +GenericName[ja]=暗号化ツール +GenericName[ka]=დაშიფვრის ხელსაწყო +GenericName[kk]=Шифрлау құралы +GenericName[km]=ឧបករណ៍អ៊ិនគ្រីប +GenericName[lt]=Šifravimo įrankis +GenericName[mk]=Алатка за криптирање +GenericName[nb]=Krypteringsverktøy +GenericName[nds]=Verslötel-Warktüüch +GenericName[ne]=गुप्तीकरण उपकरण +GenericName[nl]=Cryptografisch programma +GenericName[nn]=Krypteringsverktøy +GenericName[pa]=ਇੰਕਰਿਪਸ਼ਨ ਸੰਦ +GenericName[pl]=Narzędzie do szyfrowania +GenericName[pt]=Ferramenta de Cifra +GenericName[pt_BR]=Ferramenta de Criptografia +GenericName[ro]=Utilitar de criptare +GenericName[ru]=Шифрование +GenericName[sk]=Šifrovací nástroj +GenericName[sl]=Šifrirno orodje +GenericName[sr]=Алат за шифровање +GenericName[sr@Latn]=Alat za šifrovanje +GenericName[sv]=Krypteringsverktyg +GenericName[ta]=சங்கேத கருவி +GenericName[tg]=Асбоби Рамзкунонӣ +GenericName[tr]=Şifreleme Aracı +GenericName[uk]=Засіб для шифрування +GenericName[zh_CN]=加密工具 +GenericName[zh_TW]=加密工具 +Comment=A GnuPG frontend +Comment[ar]=واجهة لـ GnuPG +Comment[bg]=Клиент за GnuPG +Comment[bs]=Alat za GnuPG +Comment[ca]=Un entorn gràfic per GnuPG +Comment[cs]=Rozhraní pro GnuPG +Comment[cy]=Blaen-wyneb GnuPG +Comment[da]=En GnuPG-forende +Comment[de]=Eine Benutzeroberfläche für GnuPG +Comment[el]=Λογισμικό κρυπτογράφησης (GnuPG) +Comment[eo]=Fasado por GnuPG +Comment[es]=Interfaz para GnuPG +Comment[et]=GnuPG kasutajaliides +Comment[eu]=GnuPGren bitarteko bat +Comment[fa]=GnuPGنرمافزار نهایی +Comment[fi]=GnuPG-käyttöliittymä +Comment[fr]=Une interface à GnuPG +Comment[ga]=Comhéadan do GnuPG +Comment[he]=מנשק גרפי של GnuPG +Comment[hi]=एक ग्नू-पीजी फ्रन्टएण्ड +Comment[hu]=Grafikus kezelőprogram a GnuPG-hez +Comment[is]=Viðmót á GnuPG +Comment[it]=Interfaccia grafica per GnuPG +Comment[ja]=GnuPG のフロントエンド +Comment[ka]=GnuPG გრაფიკული გარსი +Comment[kk]=GnuPG интерфейсі +Comment[km]=កម្មវិធីខាងមុខ GnuPG +Comment[lt]=GnuPG naudotojo sąsaja +Comment[nb]=En GnuPG grenseflate +Comment[nds]=En GnuPG-Böversiet +Comment[ne]=GnuPG फ्रन्टेन्ड +Comment[nl]=Een programma om GnuPG-cryptografie en -ondertekening te gebruiken +Comment[nn]=Ei GnuPG-grenseflate +Comment[pa]=GnuPG ਮੁੱਖੜਾ +Comment[pl]=Interfejs do GnuPG +Comment[pt]=Uma interface para o GnuPG +Comment[pt_BR]=Uma interface para o GnuPG +Comment[ro]=Interfaţă grafică pentru GnuPG +Comment[ru]=Управление ключами GPG +Comment[sk]=Rozhranie pre GnuPG +Comment[sl]=Vmesnik za GnuPG +Comment[sr]=Интерфејс за GnuPG +Comment[sr@Latn]=Interfejs za GnuPG +Comment[sv]=Gränssnitt till GnuPG +Comment[ta]=GnuPG முன் அமைப்பு +Comment[tg]=Пешохири GnuPG +Comment[tr]=Bir GnuPG arayüzü +Comment[uk]=Інтерфейс до GnuPG +Comment[uz]=GnuPG uchun grafik interfeys +Comment[uz@cyrillic]=GnuPG учун график интерфейс +Comment[wa]=Ene eterface po GnuPG +Comment[zh_CN]=GnuPG 前端 +Comment[zh_TW]=GnuPG 前端軟體 +Terminal=false +Name=KGpg +Name[hi]=के-जीपीजी +Name[nl]=KGPG +Name[sv]=Kgpg +Name[ta]= KGpg + +X-KDE-autostart-after=panel +X-KDE-autostart-condition=kgpgrc:User Interface:AutoStart:false + +Categories=Qt;KDE;Utility;X-KDE-Utilities-PIM; diff --git a/kgpg/kgpg.h b/kgpg/kgpg.h new file mode 100644 index 0000000..aff3d18 --- /dev/null +++ b/kgpg/kgpg.h @@ -0,0 +1,168 @@ +/*************************************************************************** + kgpg.h - description + ------------------- + begin : Mon Nov 18 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KGPGAPPLET_H +#define KGPGAPPLET_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <kaction.h> +#include <ksystemtray.h> +#include <kuniqueapplication.h> +#include <kurl.h> +#include <kshortcut.h> + +#include <qlabel.h> +#include <qstringlist.h> +#include <qclipboard.h> + + +class QPopupMenu; +class KTempFile; +class KAboutData; +class KPassivePopup; +class KgpgWizard; +class popupPublic; + +class MyView : public QLabel +{ + + Q_OBJECT + +public: + MyView( QWidget *parent = 0, const char *name = 0); + ~MyView(); + + KURL droppedUrl; + KURL::List droppedUrls; + KTempFile *kgpgfoldertmp; + KShortcut goDefaultKey; + QClipboard::Mode clipboardMode; + +private: + QPopupMenu *droppopup,*udroppopup; + KAboutData *_aboutData; + QStringList customDecrypt; + KgpgWizard *wiz; + KPassivePopup *pop; + KTempFile *kgpgFolderExtract; + int compressionScheme,openTasks; + popupPublic *dialogue; + +public slots: + void busyMessage(QString mssge,bool reset=false); + void encryptDroppedFile(); + void decryptDroppedFile(); + void slotVerifyFile(); + void signDroppedFile(); + void showDroppedFile (); + void clipDecrypt(); + void clipSign(bool openEditor=true); + void clipEncrypt(); + void shredDroppedFile(); + void encryptDroppedFolder(); + void startFolderEncode(QStringList selec,QStringList encryptOptions,bool ,bool symetric); + void slotFolderFinished(KURL); + void slotFolderFinishedError(QString errmsge); + void encryptFiles(KURL::List urls); + void installShred(); + +private slots: + void slotWizardClose(); + void startWizard(); + void slotWizardChange(); + void slotSaveOptionsPath(); + void slotGenKey(); + void importSignature(QString ID); + void slotSetClip(QString newtxt); + void slotPassiveClip(); + void encryptClipboard(QStringList selec,QStringList encryptOptions,bool,bool symmetric); + void help(); + void about(); + void firstRun(); + void readOptions(); + void droppedfile (KURL::List); + void droppedtext (QString inputText, bool allowEncrypt=true); + void unArchive(); + void slotSetCompression(int cp); + void decryptNextFile(); + +protected: + virtual void dragEnterEvent(QDragEnterEvent *); + virtual void dropEvent (QDropEvent*); + +protected slots: + + +signals: + void setFont(QFont); + void readAgain2(); + void createNewKey(); + void updateDefault(QString); + void importedKeys(QStringList); +}; + +class kgpgapplet : public KSystemTray//KUniqueApplication +{ + Q_OBJECT + +public: + kgpgapplet( QWidget *parent = 0, const char *name = 0); + /** destructor */ + ~kgpgapplet(); + MyView *w; + +private: + KSystemTray *kgpgapp; + KAction *KgpgEncryptClipboard, *KgpgDecryptClipboard, *KgpgSignClipboard; + +private slots: + void slotOpenKeyManager(); + void slotOpenServerDialog(); + void showOptions(); + void checkMenu(); +}; + +class KCmdLineArgs; + +class KgpgAppletApp : public KUniqueApplication +{ + Q_OBJECT + friend class kgpgapplet; +public: + KgpgAppletApp(); + ~KgpgAppletApp(); + int newInstance (); + KURL::List urlList; + bool running; + KShortcut goHome; + +protected: + KCmdLineArgs *args; +private: + kgpgapplet *kgpg_applet; + class listKeys *s_keyManager; + +private slots: + void slotHandleQuit(); + void wizardOver(QString defaultKeyId); +}; + +#endif // KGPGAPPLET_H + diff --git a/kgpg/kgpg.kcfg b/kgpg/kgpg.kcfg new file mode 100644 index 0000000..a7ade9f --- /dev/null +++ b/kgpg/kgpg.kcfg @@ -0,0 +1,206 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 + http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > + <kcfgfile name="kgpgrc"/> + <group name="Decryption"> + <entry name="CustomDecrypt" type="String" key="custom_decrypt"> + <label>Custom decryption command.</label> + </entry> + </group> + + <group name="Encryption"> + <entry name="CustomEncryptionOptions" type="String" key="custom_option"> + <label>Custom encryption options</label> + </entry> + <entry name="AllowCustomEncryptionOptions" type="Bool" key="allow_custom_option"> + <label>Allow custom encryption options</label> + <default>false</default> + </entry> + <entry name="FileKey" type="String" key="file_key"> + <label>File encryption key.</label> + </entry> + <entry name="AsciiArmor" type="Bool" key="Ascii_armor"> + <label>Use ASCII armored encryption.</label> + <default>true</default> + </entry> + <entry name="AllowUntrustedKeys" type="Bool" key="Allow_untrusted_keys"> + <label>Allow encryption with untrusted keys.</label> + <default>false</default> + </entry> + <entry name="HideUserID" type="Bool" key="Hide_user_ID"> + <label>Hide the user ID.</label> + <default>false</default> + </entry> + <entry name="ShredSource" type="Bool" key="shred_source"> + <label>Shred the source file after encryption.</label> + <default>false</default> + </entry> + <entry name="PgpCompatibility" type="Bool" key="PGP_compatibility"> + <label>Enable PGP 6 compatibility.</label> + <default>false</default> + </entry> + <entry name="PgpExtension" type="Bool" key="Pgp_extension"> + <label>Use *.pgp extension for encrypted files.</label> + <default>false</default> + </entry> + </group> + + <group name="GPG Settings"> + <entry name="GpgConfigPath" type="Path" key="gpg_config_path"> + <label>The path of the gpg configuration file.</label> + </entry> + <entry name="Groups" type="String"> + <label>GPG groups</label> + </entry> + <entry name="OnlyAdditional" type="Bool"> + <label>Use only the additional keyring, not the default one.</label> + <default>false</default> + </entry> + <entry name="PubKeyring" type="Bool"> + <label>Enable additional public keyring.</label> + <default>false</default> + </entry> + <entry name="PrivKeyring" type="Bool"> + <label>Enable additional private keyring.</label> + <default>false</default> + </entry> + <entry name="PubKeyringUrl" type="Path"> + <label>The path of the additional public keyring.</label> + </entry> + <entry name="PrivKeyringUrl" type="Path"> + <label>The path of the additional private keyring.</label> + </entry> + </group> + + <group name="General Options"> + <entry name="PhotoProperties" type="Enum" key="photo properties"> + <choices> + <choice name="Disable"/> + <choice name="Small"/> + <choice name="Medium"/> + <choice name="Big"/> + </choices> + <default>Disable</default> + </entry> + <entry name="FirstRun" type="Bool" key="First run"> + <label>Is the first time the application runs.</label> + <default>true</default> + </entry> + <entry name="EditorGeometry" type="Size" key="Geometry"> + <label>The size of the editor window.</label> + </entry> + <entry name="ShowTrust" type="Bool" key="show_trust"> + <label>Show the trust value in key manager.</label> + <default>true</default> + </entry> + <entry name="ShowExpi" type="Bool" key="show_expi"> + <label>Show the expiration value in key manager.</label> + <default>true</default> + </entry> + <entry name="ShowSize" type="Bool" key="show_size"> + <label>Show the size value in key manager.</label> + <default>true</default> + </entry> + <entry name="ShowCreat" type="Bool" key="show_creat"> + <label>Show the creation value in key manager.</label> + <default>true</default> + </entry> + </group> + + <group name="User Interface"> + <entry name="UseMouseSelection" type="Bool" key="selection_clipboard"> + <label>Use the mouse selection instead of the clipboard.</label> + <default>false</default> + </entry> + <entry name="AutoStart" type="Bool"> + <label>Start KGpg automatically at KDE startup.</label> + <default>false</default> + </entry> + <entry name="RemoteFileWarn" type="Bool" key="remote_file_warn"> + <label>Display a warning before creating temporary files during remote file operations.</label> + <default>false</default> + </entry> + <entry name="LeftClick" type="Enum" key="left_click"> + <label>Choose default left-click behavior</label> + <choices> + <choice name="KeyManager"/> + <choice name="Editor"/> + </choices> + </entry> + <entry name="EncryptedDropEvent" type="Enum" key="encrypted_drop_event"> + <label>Handle encrypted drops</label> + <choices> + <choice name="DecryptAndSave"/> + <choice name="DecryptAndOpen"/> + <choice name="Ask"/> + </choices> + </entry> + <entry name="UnencryptedDropEvent" type="Enum" key="unencrypted_drop_event"> + <label>Handle unencrypted drops</label> + <choices> + <choice name="Encrypt"/> + <choice name="Sign"/> + <choice name="Ask"/> + </choices> + </entry> + <entry name="SignMenu" type="Enum" key="sign_menu"> + <label>Show the "sign file" service menu.</label> + <choices> + <choice name="Disabled"/> + <choice name="AllFiles"/> + </choices> + <default>Disabled</default> + </entry> + <entry name="DecryptMenu" type="Enum" key="decrypt_menu"> + <label>Show the "decrypt file" service menu.</label> + <choices> + <choice name="Disabled"/> + <choice name="AllFiles"/> + <choice name="EncryptedFiles"/> + </choices> + <default>Disabled</default> + </entry> + </group> + + <group name="TipOfDay"> + <entry name="ShowTipOfDay" type="Bool" key="RunOnStart"> + <label>Show tip of the day.</label> + <default>true</default> + </entry> + </group> + +<group name="Key Colors"> + <entry name="ColorGood" type="Color" key="color_good"> + <label>Color used for trusted keys.</label> + <default>144,255,0</default> + </entry> + <entry name="ColorRev" type="Color" key="color_revoked"> + <label>Color used for revoked keys.</label> + <default>30,30,30</default> + </entry> + <entry name="ColorUnknown" type="Color" key="color_unknown"> + <label>Color used for unknown keys.</label> + <default>255,255,255</default> + </entry> + <entry name="ColorBad" type="Color" key="color_bad"> + <label>Color used for untrusted keys.</label> + <default>172,0,0</default> + </entry> + </group> + + <group name="Text Font"> + <entry name="Font" type="Font" key="KEditFont"> + <label>Font</label> + <default code="true">KGlobalSettings::fixedFont()</default> + </entry> + </group> + +<group name="Key Servers"> + <entry name="UseProxy" type="Bool" key="use_proxy"> + <label>Use HTTP proxy when available.</label> + <default>false</default> + </entry> + </group> +</kcfg> diff --git a/kgpg/kgpg.rc b/kgpg/kgpg.rc new file mode 100644 index 0000000..5b72f56 --- /dev/null +++ b/kgpg/kgpg.rc @@ -0,0 +1,27 @@ +<!DOCTYPE kpartgui> +<kpartgui name="kgpg" version="33"> +<MenuBar> + <Menu name="file"> + <Action name="file_new_window"/> + <Action name="file_encrypt"/> + <Action name="file_decrypt"/> + <Separator/> + <Action name="key_manage"/> + </Menu> + + <Menu name="view"><text>&View</text> + <Action name="charsets"/> + </Menu> + + <Menu name="signature"><text>Si&gnature</text> + <Action name="sign_generate"/> + <Action name="sign_verify"/> + <Action name="sign_check"/> + </Menu> + + <Menu name="settings"><text>&Settings</text> + <Action name="kgpg_config" /> + </Menu> + +</MenuBar> +</kpartgui> diff --git a/kgpg/kgpg_anim.gif b/kgpg/kgpg_anim.gif Binary files differnew file mode 100644 index 0000000..d296d2e --- /dev/null +++ b/kgpg/kgpg_anim.gif diff --git a/kgpg/kgpg_blank.png b/kgpg/kgpg_blank.png Binary files differnew file mode 100644 index 0000000..c326d0b --- /dev/null +++ b/kgpg/kgpg_blank.png diff --git a/kgpg/kgpg_docked.gif b/kgpg/kgpg_docked.gif Binary files differnew file mode 100644 index 0000000..1fe5ac4 --- /dev/null +++ b/kgpg/kgpg_docked.gif diff --git a/kgpg/kgpg_docked.png b/kgpg/kgpg_docked.png Binary files differnew file mode 100644 index 0000000..ddcee25 --- /dev/null +++ b/kgpg/kgpg_docked.png diff --git a/kgpg/kgpg_fill.png b/kgpg/kgpg_fill.png Binary files differnew file mode 100644 index 0000000..576bbea --- /dev/null +++ b/kgpg/kgpg_fill.png diff --git a/kgpg/kgpgeditor.cpp b/kgpg/kgpgeditor.cpp new file mode 100644 index 0000000..9db9ce3 --- /dev/null +++ b/kgpg/kgpgeditor.cpp @@ -0,0 +1,554 @@ +/*************************************************************************** + kgpgeditor.cpp - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <stdlib.h> + +#include <kaction.h> +#include <kfiledialog.h> +#include <klocale.h> +#include <dcopclient.h> +#include <qpaintdevicemetrics.h> +#include <qcstring.h> + +#include <kencodingfiledialog.h> + +#include <qradiobutton.h> +#include <qclipboard.h> +#include <qtextcodec.h> +#include <qpainter.h> +#include <kprinter.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <klineedit.h> +#include <qcheckbox.h> +#include <kurlrequester.h> +#include <ktempfile.h> +#include <kio/netaccess.h> +#include <kio/renamedlg.h> +#include <kedittoolbar.h> + + +#include "kgpgsettings.h" +#include "kgpgeditor.h" +#include "sourceselect.h" +#include "keyexport.h" +#include "keyserver.h" +#include "keyservers.h" +#include "kgpg.h" +#include "kgpgview.h" +#include "listkeys.h" +#include "kgpglibrary.h" + +KgpgApp::KgpgApp(QWidget *parent, const char *name, WFlags f,KShortcut goHome,bool mainWindow):KMainWindow(parent, name,f) +{ + isMainWindow=mainWindow; + textEncoding=QString::null; + readOptions(); + goDefaultKey=goHome; + // call inits to invoke all other construction parts + + initActions(); + initView(); + + slotSetFont(KGpgSettings::font()); + setupGUI(( ToolBar | Keys | StatusBar | Save | Create ), "kgpg.rc"); + setAutoSaveSettings("Editor",true); + +} + +KgpgApp::~KgpgApp() +{ +delete view; +} + +void KgpgApp::slotOptions() +{ +QByteArray data; +if (!kapp->dcopClient()->send("kgpg", "KeyInterface", "showOptions()",data)) +kdDebug(2100) <<"there was some error using DCOP."<<endl; +} + +void KgpgApp::slotKeyManager() +{ +QByteArray data; +if (!kapp->dcopClient()->send("kgpg", "KeyInterface", "showKeyManager()",data)) +kdDebug(2100) <<"there was some error using DCOP."<<endl; +} + +void KgpgApp::closeEvent ( QCloseEvent * e ) +{ + if (!isMainWindow) + { + kapp->ref(); + KMainWindow::closeEvent( e ); + } + else e->accept(); +} + +void KgpgApp::closeWindow() +{ +if (view->windowAutoClose) close(); +kdDebug(2100) << "Close requested"<<endl; +} + +void KgpgApp::saveOptions() +{ + KGpgSettings::setEditorGeometry(size()); + KGpgSettings::setFirstRun(false); + KGpgSettings::writeConfig(); +} + +void KgpgApp::readOptions(bool doresize) +{ + customDecrypt=QStringList::split(QString(" "), KGpgSettings::customDecrypt().simplifyWhiteSpace()); + + if (doresize) { + QSize size= KGpgSettings::editorGeometry(); + if (!size.isEmpty()) + resize(size); + } + +} + +void KgpgApp::initActions() +{ + KStdAction::openNew(this, SLOT(slotFileNew()), actionCollection()); + KStdAction::open(this, SLOT(slotFileOpen()), actionCollection()); + KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection()); + KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection()); + KStdAction::cut(this, SLOT(slotEditCut()), actionCollection()); + KStdAction::copy(this, SLOT(slotEditCopy()), actionCollection()); + KStdAction::paste(this, SLOT(slotEditPaste()), actionCollection()); + KStdAction::selectAll(this, SLOT(slotSelectAll()), actionCollection()); + KStdAction::preferences(this, SLOT(slotOptions()), actionCollection(),"kgpg_config"); + + //KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection()); + //KStdAction::configureToolbars(this, SLOT(slotConfigureToolbars()), actionCollection()); + + fileSave = KStdAction::save(this, SLOT(slotFileSave()), actionCollection()); + (void) new KAction(i18n("&Encrypt File..."), "encrypted", 0,this, SLOT(slotFilePreEnc()), actionCollection(),"file_encrypt"); + (void) new KAction(i18n("&Decrypt File..."), "decrypted", 0,this, SLOT(slotFilePreDec()), actionCollection(),"file_decrypt"); + (void) new KAction(i18n("&Open Key Manager"), "kgpg", 0,this, SLOT(slotKeyManager()), actionCollection(),"key_manage"); + editUndo = KStdAction::undo(this, SLOT(slotundo()), actionCollection()); + editRedo = KStdAction::redo(this, SLOT(slotredo()), actionCollection()); + //(void) new KAction(i18n("&Manage Keys"), "kgpg_manage", CTRL+Key_K,this, SLOT(slotManageKey()), actionCollection(),"keys_manage"); + (void) new KAction(i18n("&Generate Signature..."),0, this, SLOT(slotPreSignFile()), actionCollection(), "sign_generate"); + (void) new KAction(i18n("&Verify Signature..."),0, this, SLOT(slotPreVerifyFile()), actionCollection(), "sign_verify"); + (void) new KAction(i18n("&Check MD5 Sum..."), 0,this, SLOT(slotCheckMd5()), actionCollection(), "sign_check"); + KStdAction::print(this, SLOT(slotFilePrint()), actionCollection()); + + // comment out for now, only confusing + //encodingAction=new KToggleAction(i18n("&Unicode (utf-8) Encoding"), 0, 0,this, SLOT(slotSetCharset()),actionCollection(),"charsets"); +} + +void KgpgApp::slotSetFont(QFont myFont) +{ +view->editor->setFont (myFont); +} + + +void KgpgApp::slotSetCharset() +{ +//////// work in progress +//if (encodingAction->isChecked()) +//view->editor->setText(QString::fromUtf8(view->editor->text().ascii())); +//else +{ +if (checkEncoding(QTextCodec::codecForLocale ())) return; +view->editor->setText(view->editor->text().utf8()); +} +} + +void KgpgApp::initView() +{ + //////////////////////////////////////////////////////////////////// + // create the main widget here that is managed by KTMainWindow's view-region and + // connect the widget to your document to display document contents. + + view = new KgpgView(this,0); + // doc->addView(view); + connect(view,SIGNAL(resetEncoding(bool)),this,SLOT(slotResetEncoding(bool))); + setCentralWidget(view); + setCaption(i18n("Untitled"),false); /// doc->URL().fileName(),false); + +} + +void KgpgApp::slotFileQuit() +{ + saveOptions(); + exit(1); +} + +void KgpgApp::slotResetEncoding(bool enc) +{ +//kdDebug(2100)<<"Resetting encoding--------------------"<<endl; +//encodingAction->setChecked(enc); +//if (enc) slotSetCharset(); +} + +void KgpgApp::slotFileNew() +{ + ////// delete all text from editor + + view->editor->setText(QString::null); + editRedo->setEnabled(false); + editUndo->setEnabled(false); + setCaption(i18n("Untitled"), false); + fileSave->setEnabled(false); + Docname=QString::null; + slotResetEncoding(false); +} + +void KgpgApp::slotFilePreEnc() +{ + QStringList opts; + KURL::List urls=KFileDialog::getOpenURLs(QString::null, + i18n("*|All Files"), this, i18n("Open File to Encode")); + if (urls.isEmpty()) + return; + emit encryptFiles(urls); +} + +void KgpgApp::slotFilePreDec() +{ + + KURL url=KFileDialog::getOpenURL(QString::null, + i18n("*|All Files"), this, i18n("Open File to Decode")); + + if (url.isEmpty()) + return; + QString oldname=url.fileName(); + + QString newname; + + if (oldname.endsWith(".gpg") || oldname.endsWith(".asc") || oldname.endsWith(".pgp")) + oldname.truncate(oldname.length()-4); + else + oldname.append(".clear"); + oldname.prepend(url.directory(0,0)); + + KDialogBase *popn=new KDialogBase( KDialogBase::Swallow, i18n("Decrypt File To"), KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, this, "file_decrypt",true); + + SrcSelect *page=new SrcSelect(); + popn->setMainWidget(page); + page->newFilename->setURL(oldname); + page->newFilename->setMode(KFile::File); + page->newFilename->setCaption(i18n("Save File")); + + page->checkClipboard->setText(i18n("Editor")); + page->resize(page->minimumSize()); + popn->resize(popn->minimumSize()); + if (popn->exec()==QDialog::Accepted) { + if (page->checkFile->isChecked()) + newname=page->newFilename->url(); + } else { + delete popn; + return; + } + delete popn; + + + if (!newname.isEmpty()) { + QFile fgpg(newname); + if (fgpg.exists()) { + KIO::RenameDlg *over=new KIO::RenameDlg(0,i18n("File Already Exists"),QString::null,newname,KIO::M_OVERWRITE); + if (over->exec()==QDialog::Rejected) + { + delete over; + return; + } + newname=over->newDestURL().path(); + delete over; + } + KgpgLibrary *lib=new KgpgLibrary(this); + lib->slotFileDec(url,KURL(newname), customDecrypt); + connect(lib,SIGNAL(importOver(QStringList)),this,SIGNAL(refreshImported(QStringList))); + } else + openEncryptedDocumentFile(url); +} + +void KgpgApp::slotFileOpen() +{ + KEncodingFileDialog::Result loadResult; + loadResult=KEncodingFileDialog::getOpenURLAndEncoding(QString::null,QString::null,QString::null,this); + KURL url=loadResult.URLs.first(); + textEncoding=loadResult.encoding; + + if(!url.isEmpty()) { + openDocumentFile(url,textEncoding); + Docname=url; + fileSave->setEnabled(false); + //fileSaveAs->setEnabled(true); + setCaption(url.fileName(), false); + } + +} + +bool KgpgApp::checkEncoding(QTextCodec *codec) +{ + ///////////// KGlobal::locale()->encoding()->name() +return codec->canEncode(view->editor->text()); +} + +void KgpgApp::slotFileSave() +{ + QString filn=Docname.path(); + if (filn.isEmpty()) { + slotFileSaveAs(); + return; + } + QTextCodec*cod=QTextCodec::codecForName (textEncoding.ascii()); + // slotStatusMsg(i18n("Saving file...")); + if (!checkEncoding(cod)) { + KMessageBox::sorry(this,i18n("The document could not been saved, as the selected encoding cannot encode every unicode character in it.")); + return; + } + + KTempFile tmpfile; + if (Docname.isLocalFile()) { + QFile f(filn); + if ( !f.open( IO_WriteOnly ) ) { + KMessageBox::sorry(this,i18n("The document could not be saved, please check your permissions and disk space.")); + return; + } + QTextStream t( &f ); + t.setCodec(cod); + //t.setEncoding( QTextStream::Latin1 ); + t << view->editor->text();//.utf8(); + f.close(); + } + else { + /*FIXME use following code: + QFile f( fName ); +00983 if ( !f.open( IO_ReadOnly ) ) +00984 return; +00985 QFileInfo info ( f ); +00986 smModificationTime = new QTime( info.lastModified().time() ); +00987 QTextStream t(&f); +00988 t.setEncoding( QTextStream::Latin1 ); +00989 QString s = t.readLine(); +00990 f.close(); + +*/ + QTextStream *stream = tmpfile.textStream(); + stream->setCodec(cod); + *stream << view->editor->text();//.utf8(); + tmpfile.close(); + if(!KIO::NetAccess::upload(tmpfile.name(), Docname,this)) { + KMessageBox::sorry(this,i18n("The document could not be saved, please check your permissions and disk space.")); + tmpfile.unlink(); + return; + } + tmpfile.unlink(); + } + + fileSave->setEnabled(false); + setCaption(Docname.fileName(),false); +} + + +void KgpgApp::slotFileSaveAs() +{ + + //KURL url=KFileDialog::getSaveURL(QDir::currentDirPath(),i18n("*|All Files"), this, i18n("Save As")); + KEncodingFileDialog::Result saveResult; + saveResult=KEncodingFileDialog::getSaveURLAndEncoding (QString::null,QString::null,QString::null,this); + KURL url=saveResult.URLs.first(); + QString selectedEncoding=saveResult.encoding; + + if(!url.isEmpty()) { + if (url.isLocalFile()) + { + QString filn=url.path(); + QFile f(filn); + if (f.exists()) { + QString message=i18n("Overwrite existing file %1?").arg(url.fileName()); + int result=KMessageBox::warningContinueCancel(this,QString(message),i18n("Warning"),i18n("Overwrite")); + if (result==KMessageBox::Cancel) + return; + } + f.close(); + } + else if (KIO::NetAccess::exists(url,false,this)) + { + QString message=i18n("Overwrite existing file %1?").arg(url.fileName()); + int result=KMessageBox::warningContinueCancel(this,QString(message),i18n("Warning"),i18n("Overwrite")); + if (result==KMessageBox::Cancel) + return; + } + Docname=url; + textEncoding=selectedEncoding; + slotFileSave(); + } +} + +void KgpgApp::openDocumentFile(const KURL& url,QString encoding) +{ +QString tempOpenFile; + ///////////////////////////////////////////////// +if( KIO::NetAccess::download( url, tempOpenFile,this ) ) { + QFile qfile(tempOpenFile); + if (qfile.open(IO_ReadOnly)) { + QTextStream t( &qfile ); + t.setCodec(QTextCodec::codecForName (encoding.ascii())); + view->editor->setText(t.read()); + qfile.close(); + fileSave->setEnabled(false); + editRedo->setEnabled(false); + editUndo->setEnabled(false); + } +} +} + +void KgpgApp::slotFilePrint() +{ + KPrinter prt; + //kdDebug(2100)<<"Printing..."<<endl; + if (prt.setup(this)) { + QPainter painter(&prt); + QPaintDeviceMetrics metrics(painter.device()); + painter.drawText( 0, 0, metrics.width(), metrics.height(), AlignLeft|AlignTop|DontClip,view->editor->text() ); + } +} + +void KgpgApp::slotEditCut() +{ + view->editor->cut(); +} + +void KgpgApp::slotEditCopy() +{ + view->editor->copy(); +} + +void KgpgApp::slotEditPaste() +{ + view->editor->paste(); +} + +void KgpgApp::slotSelectAll() +{ + view->editor->selectAll(); +} + +void KgpgApp::slotundo() +{ + view->editor->undo(); + editRedo->setEnabled(true); +} + +void KgpgApp::slotredo() +{ + view->editor->redo(); +} + +///////////// file signature slots + + +void KgpgApp::slotCheckMd5() +{ + ///////////////////////////////////////////////////////////////////////// display md5 sum for a chosen file + + KURL url=KFileDialog::getOpenURL(QString::null, + i18n("*|All Files"), this, i18n("Open File to Verify")); + if (!url.isEmpty()) { + + Md5Widget *mdwidget=new Md5Widget(this,0,url); + mdwidget->exec(); + delete mdwidget; + // KMessageBox::information(this,QString("MD5 sum for "+url.fileName()+" is:\n"+checkfile.hexDigest().data())); + } +} + + +void KgpgApp::slotPreSignFile() +{ + ////////////////////////////////////// create a detached signature for a chosen file + KURL url=KFileDialog::getOpenURL(QString::null,i18n("*|All Files"), this, i18n("Open File to Sign")); + if (!url.isEmpty()) + slotSignFile(url); +} + +void KgpgApp::slotSignFile(KURL url) +{ + ////////////////////////////////////// create a detached signature for a chosen file + QString signKeyID; + if (!url.isEmpty()) { + ////////////////// select a private key to sign file --> listkeys.cpp + KgpgSelKey *opts=new KgpgSelKey(this,"select_secret"); + if (opts->exec()==QDialog::Accepted) + signKeyID=opts->getkeyID(); + else { + delete opts; + return; + } + delete opts; + QString Options; + if (KGpgSettings::asciiArmor()) + Options="--armor"; + if (KGpgSettings::pgpCompatibility()) + Options+="--pgp6"; + KgpgInterface *signFileProcess=new KgpgInterface(); + signFileProcess->KgpgSignFile(signKeyID,url,Options); + } +} + +void KgpgApp::slotPreVerifyFile() +{ + KURL url=KFileDialog::getOpenURL(QString::null, + i18n("*|All Files"), this, i18n("Open File to Verify")); + slotVerifyFile(url); +} + +void KgpgApp::slotVerifyFile(KURL url) +{ + /////////////////////////////////// check file signature + QString sigfile=QString::null; + if (!url.isEmpty()) { + ////////////////////////////////////// try to find detached signature. + if (!url.fileName().endsWith(".sig")) { + sigfile=url.path()+".sig"; + QFile fsig(sigfile); + if (!fsig.exists()) { + sigfile=url.path()+".asc"; + QFile fsig(sigfile); + ////////////// if no .asc or .sig signature file included, assume the file is internally signed + if (!fsig.exists()) + sigfile=QString::null; + } + } + ///////////////////////// pipe gpg command + KgpgInterface *verifyFileProcess=new KgpgInterface(); + verifyFileProcess->KgpgVerifyFile(url,KURL(sigfile)); + connect (verifyFileProcess,SIGNAL(verifyquerykey(QString)),this,SLOT(importSignatureKey(QString))); + } +} + +void KgpgApp::importSignatureKey(QString ID) +{ + keyServer *kser=new keyServer(0,"server_dialog",false); + kser->page->kLEimportid->setText(ID); + kser->slotImport(); +} + +void KgpgApp::openEncryptedDocumentFile(const KURL& url) +{ + view->editor->slotDroppedFile(url); +} + + +#include "kgpgeditor.moc" diff --git a/kgpg/kgpgeditor.h b/kgpg/kgpgeditor.h new file mode 100644 index 0000000..0e8cda9 --- /dev/null +++ b/kgpg/kgpgeditor.h @@ -0,0 +1,123 @@ +/*************************************************************************** + kgpgeditor.h - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KGPGEDITOR_H +#define KGPGEDITOR_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <kmainwindow.h> + +#include <qstringlist.h> +#include <kurl.h> + +class KPassivePopup; +class KComboBox; +class KToggleAction; +class KAction; +class KgpgView; + +class KgpgApp : public KMainWindow +{ + Q_OBJECT + + friend class KgpgView; + +public: + /** construtor of KgpgApp, calls all init functions to create the application. + */ + KgpgApp(QWidget *parent=0, const char *name=0,WFlags f = 0,KShortcut goHome=QKeySequence(CTRL+Qt::Key_Home),bool mainWindow=false); + ~KgpgApp(); + /** opens a file specified by commandline option + */ + void openDocumentFile(const KURL& url,QString encoding=QString::null); + void openEncryptedDocumentFile(const KURL& url); + /** returns a pointer to the current document connected to the KTMainWindow instance and is used by + * the View class to access the document object's methods + */ + KURL Docname; + int version; + QString messages; + KgpgView *view; + KShortcut goDefaultKey; + + +protected: + void readOptions(bool doresize=true); + void saveOptions(); + void initActions(); + void initView(); + void closeEvent( QCloseEvent * e ); + +private slots: + //void slotOptions(); + void slotFileQuit(); + void slotFileNew(); + void slotResetEncoding(bool enc); + void slotFilePreEnc(); + void slotFilePreDec(); + void slotFileOpen(); + void slotFileSave(); + void slotFileSaveAs(); + void slotFilePrint(); + void slotEditCut(); + void slotEditCopy(); + void slotEditPaste(); + void slotSelectAll(); + void slotCheckMd5(); + + void slotPreSignFile(); + void slotSignFile(KURL url); + void slotVerifyFile(KURL url); + void slotPreVerifyFile(); + void importSignatureKey(QString ID); + + void slotundo(); + void slotredo(); + void slotSetCharset(); + bool checkEncoding(QTextCodec *codec); + void slotOptions(); + void slotKeyManager(); + + +public slots: + void slotSetFont(QFont myFont); + void closeWindow(); + + +private: + + QStringList customDecrypt; + //KToggleAction *encodingAction ; + KURL urlselected; + KAction* fileSave, *editUndo, *editRedo; + KComboBox *fontCombo; + bool isMainWindow; + QString textEncoding; + +signals: + +void refreshImported(QStringList); +void openChangeFont(); +void openConfigDialog(); +void encryptFiles(KURL::List fileList); +}; + +#endif // KGPGEDITOR_H + diff --git a/kgpg/kgpginterface.cpp b/kgpg/kgpginterface.cpp new file mode 100644 index 0000000..5286c3c --- /dev/null +++ b/kgpg/kgpginterface.cpp @@ -0,0 +1,2166 @@ +/*************************************************************************** + kgpginterface.cpp - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <stdio.h> + +#include <qdialog.h> +#include <qclipboard.h> +#include <qlayout.h> +#include <qregexp.h> +#include <qstring.h> +#include <qlabel.h> +#include <qapplication.h> +#include <kio/netaccess.h> +#include <qcheckbox.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <kpassdlg.h> +#include <kmdcodec.h> +#include <klineedit.h> +#include <kcharsets.h> +#include <kpassivepopup.h> +#include <kiconloader.h> +#include <kaction.h> +#include <qtextcodec.h> +#include <kprocess.h> +#include <kprocio.h> +#include <kconfig.h> +#include <qfile.h> +#include <kled.h> +#include <kdebug.h> +#include <ktempfile.h> + +#include "kgpginterface.h" +#include "listkeys.h" +#include "detailedconsole.h" + +KgpgInterface::KgpgInterface() +{} + + +int KgpgInterface::getGpgVersion() +{ +FILE *fp; + QString readResult,gpgString; + char buffer[200]; + bool readLine=true; + + QString gpgcmd="gpg --version"; + + fp = popen(QFile::encodeName(gpgcmd), "r"); + while ( fgets( buffer, sizeof(buffer), fp)) { + readResult=buffer; + if (readLine) { + gpgString=readResult.stripWhiteSpace().section(' ',-1); + readLine=false; + } + } + pclose(fp); + return (100*gpgString.section('.',0,0).toInt()+10*gpgString.section('.',1,1).toInt()+gpgString.section('.',2,2).toInt()); +} + +void KgpgInterface::updateIDs(QString txtString) +{ + int cut=txtString.find(' ',22,false); + txtString.remove(0,cut); + if (txtString.find("(",0,false)!=-1) + txtString=txtString.section('(',0,0)+txtString.section(')',-1); + txtString.replace(QRegExp("<"),"<"); + if (userIDs.find(txtString)==-1) + { + if (!userIDs.isEmpty()) + userIDs+=i18n(" or "); + userIDs+=txtString; + } +} + +void KgpgInterface::KgpgEncryptFile(QStringList encryptKeys,KURL srcUrl,KURL destUrl, QStringList Options, bool symetrical) +{ + sourceFile=srcUrl; + message=QString::null; + + KProcIO *proc=new KProcIO(QTextCodec::codecForLocale()); + *proc<<"gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--utf8-strings"; + for ( QStringList::Iterator it = Options.begin(); it != Options.end(); ++it ) + if (!QFile::encodeName(*it).isEmpty()) *proc<< QFile::encodeName(*it); + + *proc<<"--output"<<QFile::encodeName(destUrl.path()); + + if (!symetrical) { + *proc<<"-e"; + for ( QStringList::Iterator it = encryptKeys.begin(); it != encryptKeys.end(); ++it ) + *proc<<"--recipient"<< *it; + } else //////////// symetrical encryption, prompt for password + *proc<<"-c"; + + *proc<<QFile::encodeName(srcUrl.path()); + + ///////// when process ends, update dialog infos + QObject::connect(proc, SIGNAL(processExited(KProcess *)),this,SLOT(encryptfin(KProcess *))); + QObject::connect(proc,SIGNAL(readReady(KProcIO *)),this,SLOT(readencprocess(KProcIO *))); + proc->start(KProcess::NotifyOnExit,true); +} + + +KgpgInterface::~KgpgInterface() +{} + + +void KgpgInterface::encryptfin(KProcess *) +{ + if (message.find("END_ENCRYPTION")!=-1) + emit encryptionfinished(sourceFile); + else { + emit errormessage(message); + } +} + +void KgpgInterface::readencprocess(KProcIO *p) +{ + QString required; + while (p->readln(required,true)!=-1) { + if (required.find("BEGIN_ENCRYPTION",0,false)!=-1) + emit processstarted(sourceFile.path()); + if (required.find("GET_")!=-1) { + if (required.find("openfile.overwrite.okay")!=-1) + p->writeStdin("Yes"); + else if ((required.find("passphrase.enter")!=-1)) { + QCString passphrase; + int code=KPasswordDialog::getNewPassword(passphrase,i18n("Enter passphrase for your file (symmetrical encryption):")); + if (code!=QDialog::Accepted) { + p->deleteLater(); + emit processaborted(true); + return; + } + p->writeStdin(passphrase,true); + } else { + p->writeStdin("quit"); + p->closeWhenDone(); + } + } + message+=required+"\n"; + } +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////// File decryption + +void KgpgInterface::KgpgDecryptFile(KURL srcUrl,KURL destUrl,QStringList Options) +{ + message=QString::null; + step=3; + decryptUrl=srcUrl.path(); + userIDs=QString::null; + anonymous=false; + + KProcIO *proc=new KProcIO(QTextCodec::codecForLocale()); + + *proc<<"gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--utf8-strings"; + + for ( QStringList::Iterator it = Options.begin(); it != Options.end(); ++it ) + if (!QFile::encodeName(*it).isEmpty()) *proc<< QFile::encodeName(*it); + + if (!destUrl.fileName().isEmpty()) // a filename was entered + *proc<<"-o"<<QFile::encodeName(destUrl.path()); + + *proc<<"-d"<<QFile::encodeName(srcUrl.path()); + + QObject::connect(proc, SIGNAL(processExited(KProcess *)),this,SLOT(decryptfin(KProcess *))); + QObject::connect(proc,SIGNAL(readReady(KProcIO *)),this,SLOT(readdecprocess(KProcIO *))); + proc->start(KProcess::NotifyOnExit,true); +} + +void KgpgInterface::decryptfin(KProcess *) +{ + if ((message.find("DECRYPTION_OKAY")!=-1) && (message.find("END_DECRYPTION")!=-1)) //&& (message.find("GOODMDC")!=-1) + emit decryptionfinished(); + else + emit errormessage(message); +} + + +void KgpgInterface::readdecprocess(KProcIO *p) +{ + QString required; + while (p->readln(required,true)!=-1) { + if (required.find("BEGIN_DECRYPTION",0,false)!=-1) + emit processstarted(decryptUrl); + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if (required.find("ENC_TO")!=-1) { + if (required.find("0000000000000000")!=-1) + anonymous=true; + } + if (required.find("GET_")!=-1) { + if (required.find("openfile.overwrite.okay")!=-1) + p->writeStdin("Yes"); + else if ((required.find("passphrase.enter")!=-1)) { + if (userIDs.isEmpty()) + userIDs=i18n("[No user id found]"); + userIDs.replace(QRegExp("<"),"<"); + QCString passphrase; + QString passdlgmessage; + if (anonymous) + passdlgmessage=i18n("<b>No user id found</b>. Trying all secret keys.<br>"); + if ((step<3) && (!anonymous)) + passdlgmessage=i18n("<b>Bad passphrase</b>. You have %1 tries left.<br>").arg(step); + + passdlgmessage+=i18n("Enter passphrase for <b>%1</b>").arg(userIDs); + int code=KPasswordDialog::getPassword(passphrase,passdlgmessage); + if (code!=QDialog::Accepted) { + p->deleteLater(); + emit processaborted(true); + return; + } + p->writeStdin(passphrase,true); + userIDs=QString::null; + if (step>1) step--; + else step=3; + } else { + p->writeStdin("quit"); + p->closeWhenDone(); + } + } + message+=required+"\n"; + } +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////// Text encryption + + +void KgpgInterface::KgpgEncryptText(QString text,QStringList userIDs, QStringList Options) +{ + message=QString::null; + //QTextCodec *codec = KGlobal::charsets()->codecForName(KGlobal::locale()->encoding()); + QTextCodec *codec =QTextCodec::codecForLocale (); + if (codec->canEncode(text)) txtToEncrypt=text; + else txtToEncrypt=text.utf8(); + + KProcIO *proc=new KProcIO(QTextCodec::codecForLocale()); + *proc<<"gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--command-fd=0"<<"--status-fd=1"<<"--utf8-strings"; + + for ( QStringList::Iterator it = Options.begin(); it != Options.end(); ++it ) + if (!QFile::encodeName(*it).isEmpty()) *proc<< QFile::encodeName(*it); + + if (!userIDs.isEmpty()) + { + *proc<<"-e"; + for ( QStringList::Iterator it = userIDs.begin(); it != userIDs.end(); ++it ) + *proc<<"--recipient"<< *it; + } + else + *proc<<"-c"; + + ///////// when process ends, update dialog infos + + QObject::connect(proc, SIGNAL(processExited(KProcess *)),this,SLOT(txtencryptfin(KProcess *))); + QObject::connect(proc,SIGNAL(readReady(KProcIO *)),this,SLOT(txtreadencprocess(KProcIO *))); + proc->start(KProcess::NotifyOnExit,false); + emit txtencryptionstarted(); +} + + +void KgpgInterface::txtencryptfin(KProcess *) +{ + if (!message.isEmpty()) + emit txtencryptionfinished(message); + else + emit txtencryptionfinished(QString::null); +} + +void KgpgInterface::txtreadencprocess(KProcIO *p) +{ + QString required; + while (p->readln(required,true)!=-1) { + if (required.find("BEGIN_ENCRYPTION",0,false)!=-1) + { + p->writeStdin(txtToEncrypt,false); + txtToEncrypt=QString::null; + p->closeWhenDone(); + } + else + if ((required.find("passphrase.enter")!=-1)) + { + QCString passphrase; + QString passdlgmessage=i18n("Enter passphrase (symmetrical encryption)"); + int code=KPasswordDialog::getNewPassword(passphrase,passdlgmessage); + if (code!=QDialog::Accepted) + { + p->deleteLater(); + return; + } + p->writeStdin(passphrase,true); + } + else + if (!required.startsWith("[GNUPG:]")) message+=required+"\n"; + } +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Text decryption + +void KgpgInterface::KgpgDecryptText(QString text,QStringList Options) +{ + gpgOutput=QString::null; + log=QString::null; + + message=QString::null; + userIDs=QString::null; + step=3; + anonymous=false; + decfinished=false; + decok=false; + badmdc=false; + KProcess *proc=new KProcess(); + *proc<<"gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--command-fd=0"<<"--status-fd=2"<<"--no-batch"<<"--utf8-strings"; + for ( QStringList::Iterator it = Options.begin(); it != Options.end(); ++it ) + if (!QFile::encodeName(*it).isEmpty()) *proc<< QFile::encodeName(*it); + *proc<<"-d"; + + ///////// when process ends, update dialog infos + + QObject::connect(proc, SIGNAL(processExited(KProcess *)),this,SLOT(txtdecryptfin(KProcess *))); + connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)),this, SLOT(getOutput(KProcess *, char *, int))); + connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)),this, SLOT(getCmdOutput(KProcess *, char *, int))); + proc->start(KProcess::NotifyOnExit,KProcess::All); + proc->writeStdin(text.utf8(), text.length()); +} + +void KgpgInterface::txtdecryptfin(KProcess *) +{ +if ((decok) && (!badmdc)) +emit txtdecryptionfinished(message); + +else if (badmdc) +{ +KMessageBox::sorry(0,i18n("Bad MDC detected. The encrypted text has been manipulated.")); +emit txtdecryptionfailed(log); +} +else +emit txtdecryptionfailed(log); +} + + +void KgpgInterface::getOutput(KProcess *, char *data, int ) +{ + message.append(QString::fromUtf8(data)); +} + + +void KgpgInterface::getCmdOutput(KProcess *p, char *data, int ) +{ + gpgOutput.append(QString::fromUtf8(data)); + log.append(data); + + int pos; + while ((pos=gpgOutput.find("\n"))!=-1) + { + QString required=gpgOutput.left(pos); + gpgOutput.remove(0,pos+2); + + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if (required.find("ENC_TO")!=-1) + { + if (required.find("0000000000000000")!=-1) + anonymous=true; + } + + if (required.find("GET_")!=-1) + { + if ((required.find("passphrase.enter")!=-1)) + { + if (userIDs.isEmpty()) + userIDs=i18n("[No user id found]"); + QCString passphrase; + QString passdlgmessage; + if (anonymous) + passdlgmessage=i18n("<b>No user id found</b>. Trying all secret keys.<br>"); + if ((step<3) && (!anonymous)) + passdlgmessage=i18n("<b>Bad passphrase</b>. You have %1 tries left.<br>").arg(step); + passdlgmessage+=i18n("Enter passphrase for <b>%1</b>").arg(userIDs); + int code=KPasswordDialog::getPassword(passphrase,passdlgmessage); + if (code!=QDialog::Accepted) + { + p->deleteLater(); + emit processaborted(true); + return; + } + passphrase.append("\n"); + p->writeStdin(passphrase,passphrase.length()); + userIDs=QString::null; + if (step>1) step--; + else step=3; + } + else + { + p->writeStdin("quit",4); + p->closeStdin(); + } + } + + if (required.find("BEGIN_DECRYPTION")!=-1) + { + p->closeStdin(); + required=QString::null; + } + + if (required.find("END_DECRYPTION")!=-1) decfinished=true; + if (required.find("DECRYPTION_OKAY")!=-1) decok=true; + if (required.find("DECRYPTION_FAILED")!=-1) decok=false; + if (required.find("BADMDC")!=-1) badmdc=true; + } +} +////////////////////////////////////////////////////////////////////////////////////////////////////////// Text signing + + +void KgpgInterface::KgpgSignText(QString text,QString userIDs, QStringList Options) +{ + message=QString::null; + step=4; + QString txtprocess; + QTextCodec *codec =QTextCodec::codecForLocale (); + if (codec->canEncode(text)) txtprocess=text; + else txtprocess=text.utf8(); + + KProcIO *proc=new KProcIO(QTextCodec::codecForLocale()); + *proc<<"gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--command-fd=0"<<"--status-fd=1"<<"--utf8-strings"; + + for ( QStringList::Iterator it = Options.begin(); it != Options.end(); ++it ) + if (!QFile::encodeName(*it).isEmpty()) *proc<< QFile::encodeName(*it); + *proc<<"--clearsign"<<"-u"<<userIDs; + + ///////// when process ends, update dialog infos + + QObject::connect(proc, SIGNAL(processExited(KProcess *)),this,SLOT(txtsignfin(KProcess *))); + QObject::connect(proc,SIGNAL(readReady(KProcIO *)),this,SLOT(txtsignprocess(KProcIO *))); + + //emit txtsigningstarted(); + + proc->start(KProcess::NotifyOnExit,false); + /*if (useAgent) + { + kdDebug(2100)<<"Using Agent+++++++++++++"<<endl; + //KMessageBox::sorry(0,"using agent"); + proc->writeStdin(txtprocess,true); + proc->closeWhenDone(); + } + else*/ + message=txtprocess; +} + + +void KgpgInterface::txtsignfin(KProcess *) +{ + if (!message.isEmpty()) + emit txtSignOver(message); + else + emit txtSignOver(QString::null); +} + +void KgpgInterface::txtsignprocess(KProcIO *p) +{ + QString required; + while (p->readln(required,true)!=-1) { +// kdDebug(2100)<<"SIGNING: "<<required<<endl; + + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if (required.find("GOOD_PASSPHRASE")!=-1) + { + p->writeStdin(message,true); + message=QString::null; + p->closeWhenDone(); + } + + if ((required.find("passphrase.enter")!=-1)) + { + if (step>1) step--; + else step=3; + if (userIDs.isEmpty()) + userIDs=i18n("[No user id found]"); + QCString passphrase; + QString passdlgmessage; + if (step<3) + passdlgmessage=i18n("<b>Bad passphrase</b>. You have %1 tries left.<br>").arg(step); + passdlgmessage+=i18n("Enter passphrase for <b>%1</b>").arg(userIDs); + int code=KPasswordDialog::getPassword(passphrase,passdlgmessage); + if (code!=QDialog::Accepted) + { + p->deleteLater(); + return; + } + p->writeStdin(passphrase,true); + } + else + if (!required.startsWith("[GNUPG:]")) message+=required+"\n"; + } +} + + +//////////////////////////////////////////////// decrypt file to text + +void KgpgInterface::KgpgDecryptFileToText(KURL srcUrl,QStringList Options) +{ + + message=QString::null; + userIDs=QString::null; + step=3; + anonymous=false; +decfinished=false; +decok=false; +badmdc=false; + + KProcess *proc=new KProcess(); + *proc<<"gpg"<<"--no-tty"<<"--utf8-strings"<<"--no-secmem-warning"<<"--command-fd=0"<<"--status-fd=2"<<"--no-batch"<<"-o"<<"-"; + for ( QStringList::Iterator it = Options.begin(); it != Options.end(); ++it ) { + if (!QFile::encodeName(*it).isEmpty()) *proc<< QFile::encodeName(*it); + } + *proc<<"-d"<<QFile::encodeName(srcUrl.path()); + + ///////// when process ends, update dialog infos + + connect(proc, SIGNAL(processExited(KProcess *)),this,SLOT(txtdecryptfin(KProcess *))); + connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)),this, SLOT(getOutput(KProcess *, char *, int))); + connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)),this, SLOT(getCmdOutput(KProcess *, char *, int))); + proc->start(KProcess::NotifyOnExit,KProcess::All); +} + + +/////////////////////////////////////////////////////// verify text + + +void KgpgInterface::KgpgVerifyText(QString text) +{ + + QTextCodec *codec =QTextCodec::codecForLocale (); + if (!codec->canEncode(text)) text=text.utf8(); + signmiss=false; + signID=QString::null; + message=QString::null; + KProcIO *verifyproc=new KProcIO(QTextCodec::codecForLocale()); + *verifyproc<<"gpg"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--utf8-strings"<<"--verify"; + connect(verifyproc, SIGNAL(processExited(KProcess *)),this, SLOT(slotverifyresult(KProcess *))); + connect(verifyproc, SIGNAL(readReady(KProcIO *)),this, SLOT(slotverifyread(KProcIO *))); + verifyproc->start(KProcess::NotifyOnExit,true); + verifyproc->writeStdin (text); + verifyproc->closeWhenDone(); +} + + +void KgpgInterface::slotverifyresult(KProcess*) +{ +if (signmiss) emit missingSignature(signID); + else { + if (signID.isEmpty()) signID=i18n("No signature found."); + emit verifyOver(signID,message); + } +//kdDebug(2100) << "GPG VERIFY OVER________"<<endl; +} + +void KgpgInterface::slotverifyread(KProcIO *p) +{ +QString required; + while (p->readln(required,true)!=-1) + { + message+=required+"\n"; + required=required.section("]",1,-1).stripWhiteSpace(); + if (required.startsWith("GOODSIG")) + { + QString userName=required.section(" ",2,-1).replace(QRegExp("<"),"<"); + userName=checkForUtf8(userName); + signID=i18n("<qt>Good signature from:<br><b>%1</b><br>Key ID: %2</qt>").arg(userName).arg("0x"+required.section(" ",1,1).right(8)); + } + if (required.startsWith("BADSIG")) + { + signID=i18n("<qt><b>Bad signature</b> from:<br>%1<br>Key ID: %2<br><br><b>Text is corrupted.</b></qt>").arg(required.section(" ",2,-1).replace(QRegExp("<"),"<")).arg("0x"+required.section(" ",1,1).right(8)); + } + if (required.startsWith("NO_PUBKEY")) + { + signID="0x"+required.section(" ",1,1).right(8); + signmiss=true; + } + if (required.startsWith("UNEXPECTED") || required.startsWith("NODATA")) + signID=i18n("No signature found."); + if (required.startsWith("TRUST_UNDEFINED")) + signID+=i18n("The signature is valid, but the key is untrusted"); + if (required.startsWith("TRUST_ULTIMATE")) + signID+=i18n("The signature is valid, and the key is ultimately trusted"); + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// MD5 + +Md5Widget::Md5Widget(QWidget *parent, const char *name,KURL url):KDialogBase( parent, name, true,i18n("MD5 Checksum"),Apply | Close) +{ + setButtonApply(i18n("Compare MD5 with Clipboard")); + mdSum=QString::null; + QFile f(url.path()); + f.open( IO_ReadOnly); + KMD5 checkfile; + checkfile.reset(); + checkfile.update(f); + mdSum=checkfile.hexDigest().data(); + f.close(); + QWidget *page = new QWidget(this); + + resize( 360, 150 ); + QGridLayout *MyDialogLayout = new QGridLayout( page, 1, 1, 5, 6, "MyDialogLayout"); + + QLabel *TextLabel1 = new QLabel( page, "TextLabel1" ); + TextLabel1->setText(i18n("MD5 sum for <b>%1</b> is:").arg(url.fileName())); + MyDialogLayout->addWidget( TextLabel1, 0, 0 ); + + KLineEdit *KRestrictedLine1 = new KLineEdit(mdSum,page); + KRestrictedLine1->setReadOnly(true); + KRestrictedLine1->setPaletteBackgroundColor(QColor(255,255,255)); + MyDialogLayout->addWidget( KRestrictedLine1, 1, 0 ); + + + QHBoxLayout *Layout4 = new QHBoxLayout( 0, 0, 6, "Layout4"); + + KLed1=new KLed(QColor(80,80,80),KLed::Off,KLed::Sunken,KLed::Circular,page,"KLed1"); + KLed1->off(); + KLed1->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, KLed1->sizePolicy().hasHeightForWidth() ) ); + Layout4->addWidget( KLed1 ); + + TextLabel1_2 = new QLabel( page, "TextLabel1_2" ); + TextLabel1_2->setText(i18n( "<b>Unknown status</b>" ) ); + Layout4->addWidget( TextLabel1_2 ); + + MyDialogLayout->addLayout( Layout4, 2, 0 ); + QSpacerItem* spacer = new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ); + MyDialogLayout->addItem( spacer, 3, 0 ); + + page->show(); + page->resize(page->minimumSize()); + setMainWidget(page); + + +} + +Md5Widget::~Md5Widget() +{} + +void Md5Widget::slotApply() +{ + QClipboard *cb = QApplication::clipboard(); + QString text; + // Copy text from the clipboard (paste) + text = cb->text(QClipboard::Clipboard); + if ( !text.isEmpty() ) { + text=text.stripWhiteSpace(); + while (text.find(' ')!=-1) + text.remove(text.find(' '),1); + if (text==mdSum) { + TextLabel1_2->setText(i18n("<b>Correct checksum</b>, file is ok.")); + KLed1->setColor(QColor(0,255,0)); + KLed1->on(); + }//KMessageBox::sorry(0,"OK"); + else if (text.length()!=mdSum.length()) + KMessageBox::sorry(0,i18n("Clipboard content is not a MD5 sum.")); + else { + TextLabel1_2->setText(i18n("<b>Wrong checksum, FILE CORRUPTED</b>")); + KLed1->setColor(QColor(255,0,0)); + KLed1->on(); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// signatures + + +void KgpgInterface::KgpgSignFile(QString keyID,KURL srcUrl,QStringList Options) +{ + ////////////////////////////////////// create a detached signature for a chosen file + message=QString::null; + step=3; + ///////////// create gpg command + KProcIO *proc=new KProcIO(QTextCodec::codecForLocale()); + keyID=keyID.stripWhiteSpace(); + *proc<<"gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--utf8-strings"<<"--status-fd=2"<<"--command-fd=0"<<"-u"<<keyID.local8Bit(); + for ( QStringList::Iterator it = Options.begin(); it != Options.end(); ++it ) + if (!QFile::encodeName(*it).isEmpty()) *proc<< QFile::encodeName(*it); + + *proc<<"--output"<<QFile::encodeName(srcUrl.path()+".sig"); + *proc<<"--detach-sig"<<QFile::encodeName(srcUrl.path()); + + QObject::connect(proc, SIGNAL(processExited(KProcess *)),this,SLOT(signfin(KProcess *))); + QObject::connect(proc,SIGNAL(readReady(KProcIO *)),this,SLOT(readsignprocess(KProcIO *))); + proc->start(KProcess::NotifyOnExit,true); +} + + + +void KgpgInterface::signfin(KProcess *) +{ + if (message.find("SIG_CREATED")!=-1) + KMessageBox::information(0,i18n("The signature file %1 was successfully created.").arg(file.fileName())); + else if (message.find("BAD_PASSPHRASE")!=-1) + KMessageBox::sorry(0,i18n("Bad passphrase, signature was not created.")); + else + KMessageBox::sorry(0,message); + emit signfinished(); +} + + +void KgpgInterface::readsignprocess(KProcIO *p) +{ + QString required; + while (p->readln(required,true)!=-1) { + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if (required.find("GET_")!=-1) { + if (required.find("openfile.overwrite.okay")!=-1) + p->writeStdin("Yes"); + else if ((required.find("passphrase.enter")!=-1)) { + if (userIDs.isEmpty()) + userIDs=i18n("[No user id found]"); + QCString passphrase; + QString passdlgmessage; + if (step<3) + passdlgmessage=i18n("<b>Bad passphrase</b>. you have %1 tries left.<br>").arg(step); + passdlgmessage+=i18n("Enter passphrase for <b>%1</b>").arg(userIDs); + int code=KPasswordDialog::getPassword(passphrase,passdlgmessage); + if (code!=QDialog::Accepted) { + p->deleteLater(); + emit signfinished(); + return; + } + p->writeStdin(passphrase,true); + userIDs=QString::null; + if (step>1) step--; + else step=3; + } else { + p->writeStdin("quit"); + p->closeWhenDone(); + } + } + message+=required+"\n"; + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +void KgpgInterface::KgpgVerifyFile(KURL sigUrl,KURL srcUrl) +{ + ////////////////////////////////////// verify signature for a chosen file + message=QString::null; + signID=QString::null; + signmiss=false; + ///////////// create gpg command + KProcIO *proc=new KProcIO(QTextCodec::codecForLocale()); + file=sigUrl; + *proc<<"gpg"<<"--no-tty"<<"--utf8-strings"<<"--no-secmem-warning"<<"--status-fd=2"<<"--verify"; + if (!srcUrl.isEmpty()) + *proc<<QFile::encodeName(srcUrl.path()); + *proc<<QFile::encodeName(sigUrl.path()); + + QObject::connect(proc, SIGNAL(processExited(KProcess *)),this,SLOT(verifyfin(KProcess *))); + QObject::connect(proc,SIGNAL(readReady(KProcIO *)),this,SLOT(readprocess(KProcIO *))); + proc->start(KProcess::NotifyOnExit,true); +} + + +void KgpgInterface::readprocess(KProcIO *p) +{ +QString required; + while (p->readln(required,true)!=-1) + { + message+=required+"\n"; + if (required.find("GET_")!=-1) { + p->writeStdin("quit"); + p->closeWhenDone(); + } + required=required.section("]",1,-1).stripWhiteSpace(); + if (required.startsWith("UNEXPECTED") || required.startsWith("NODATA")) + signID=i18n("No signature found."); + if (required.startsWith("GOODSIG")) + { + signID=i18n("<qt>Good signature from:<br><b>%1</b><br>Key ID: %2</qt>").arg(required.section(" ",2,-1).replace(QRegExp("<"),"<")).arg("0x"+required.section(" ",1,1).right(8)); + } + if (required.startsWith("BADSIG")) + { + signID=i18n("<qt><b>BAD signature</b> from:<br> %1<br>Key id: %2<br><br>" + "<b>The file is corrupted!</b></qt>").arg(required.section(" ",2,-1).replace(QRegExp("<"),"<")).arg("0x"+required.section(" ",1,1).right(8)); + } + if (required.startsWith("NO_PUBKEY")) + { + signmiss=true; + signID="0x"+required.section(" ",1,1).right(8); + } + if (required.startsWith("TRUST_UNDEFINED")) + signID+=i18n("The signature is valid, but the key is untrusted"); + if (required.startsWith("TRUST_ULTIMATE")) + signID+=i18n("The signature is valid, and the key is ultimately trusted"); + } +} + + +void KgpgInterface::verifyfin(KProcess *) +{ + if (!signmiss) { + if (signID.isEmpty()) signID=i18n("No signature found."); + (void) new KDetailedInfo(0,"verify_result",signID,message); + } + else { + if (KMessageBox::questionYesNo(0,i18n("<qt><b>Missing signature:</b><br>Key id: %1<br><br>" + "Do you want to import this key from a keyserver?</qt>").arg(signID),file.fileName(),QString::null, i18n("Import"), i18n("Do Not Import"))==KMessageBox::Yes) + emit verifyquerykey(signID); + } + emit verifyfinished(); +} + + + +//////////////////////////////////////////////////////////// sign a key + +void KgpgInterface::KgpgSignKey(QString keyID,QString signKeyID,QString signKeyMail,bool local,int checking) +{ + signKeyMail.replace(QRegExp("<"),"<"); + konsChecked=checking; + konsLocal=local; + konsSignKey=signKeyID; + konsKeyID=keyID; + errMessage=QString::null; + if (checkuid(keyID)>0) + { + openSignConsole(); + return; + } + + signSuccess=0; + step=1; + output=QString::null; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<<"gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--utf8-strings"<<"--command-fd=0"<<"--status-fd=2"<<"-u"<<signKeyID; + *conprocess<<"--edit-key"<<keyID; + if (local) *conprocess<<"lsign"; + else *conprocess<<"sign"; + QObject::connect(conprocess,SIGNAL(readReady(KProcIO *)),this,SLOT(sigprocess(KProcIO *))); + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(signover(KProcess *))); + conprocess->start(KProcess::NotifyOnExit,true); +} + +void KgpgInterface::sigprocess(KProcIO *p) +{ + QString required=QString::null; + + while (p->readln(required,true)!=-1) + { + + output+=required+"\n"; + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if (signSuccess==4) { + if (required.find("GET_")!=-1) + p->writeStdin("quit"); + p->closeWhenDone(); + return; + } + + if ((required.find("GOOD_PASSPHRASE")!=-1)) { + signSuccess=3; + step=2; + } + + if (required.find("sign_uid.expire")!=-1) { + p->writeStdin("Never"); + required=QString::null; + } + if (required.find("sign_uid.class")!=-1) { + p->writeStdin(QString::number(konsChecked)); + required=QString::null; + } + if (required.find("sign_uid.okay")!=-1) { + p->writeStdin("Y"); + required=QString::null; + } + + if (required.find("sign_all.okay")!=-1) { + p->writeStdin("Y"); + required=QString::null; + } + + if (required.find("passphrase.enter")!=-1) { + QCString signpass; + int code=KPasswordDialog::getPassword(signpass,i18n("<qt>%1 Enter passphrase for <b>%2</b>:</qt>") + .arg(errMessage).arg(userIDs)); + if (code!=QDialog::Accepted) { + signSuccess=4; ///// aborted by user mode + required=QString::null; + p->writeStdin("quit"); + p->closeWhenDone(); + return; + } + p->writeStdin(signpass,true); + required=QString::null; + // step=2; + } + if ((step==2) && (required.find("keyedit.prompt")!=-1)) { + p->writeStdin("save"); + required=QString::null; + } + if (required.find("BAD_PASSPHRASE")!=-1) { + errMessage=i18n("<b>Bad passphrase</b>. Try again.</br>"); + required=QString::null; + signSuccess=2; ///// bad passphrase + } + if (required.find("GET_")!=-1) /////// gpg asks for something unusal, turn to konsole mode + { + if (signSuccess!=2) + signSuccess=1; ///// switching to console mode + p->writeStdin("quit"); + p->closeWhenDone(); + + } + } +} + + +void KgpgInterface::signover(KProcess *) +{ + if (signSuccess>1) + emit signatureFinished(signSuccess); //// signature successful or bad passphrase + else { + KDetailedConsole *q=new KDetailedConsole(0,"sign_error",i18n("<qt>Signing key <b>%1</b> with key <b>%2</b> failed.<br>" + "Do you want to try signing the key in console mode?</qt>").arg(konsKeyID).arg(konsSignKey),output); + if (q->exec()==QDialog::Accepted) + openSignConsole(); + else + emit signatureFinished(0); + } +} + +void KgpgInterface::openSignConsole() +{ + KProcess conprocess; + KConfig *config = KGlobal::config(); + config->setGroup("General"); + conprocess<< config->readPathEntry("TerminalApplication","konsole"); + conprocess<<"-e"<<"gpg"; + conprocess<<"--no-secmem-warning"<<"--expert"<<"-u"<<konsSignKey; + if (!konsLocal) + conprocess<<"--sign-key"<<konsKeyID; + else + conprocess<<"--lsign-key"<<konsKeyID; + conprocess.start(KProcess::Block); + emit signatureFinished(3); + +} + +//////////////////////////////////////////////////////////////////////////// delete signature + + +void KgpgInterface::KgpgDelSignature(QString keyID,QString signKeyID) +{ + if (checkuid(keyID)>0) { + KMessageBox::sorry(0,i18n("This key has more than one user ID.\nEdit the key manually to delete signature.")); + return; + } + + message=signKeyID.remove(0,2); + deleteSuccess=false; + step=0; + + FILE *fp; + QString encResult; + char buffer[200]; + signb=0; + sigsearch=0; + + QString gpgcmd="gpg --no-tty --no-secmem-warning --with-colon --list-sigs "+keyID; + fp = popen(QFile::encodeName(gpgcmd), "r"); + while ( fgets( buffer, sizeof(buffer), fp)) { + encResult=buffer; + if (encResult.startsWith("sig")) { + if (encResult.find(message)!=-1) + break; + signb++; + } else if (encResult.startsWith("rev")) + signb++; + } + pclose(fp); + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<<"gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--utf8-strings"<<"--command-fd=0"<<"--status-fd=2"; + *conprocess<<"--edit-key"<<keyID<<"uid 1"<<"delsig"; + QObject::connect(conprocess,SIGNAL(readReady(KProcIO *)),this,SLOT(delsigprocess(KProcIO *))); + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(delsignover(KProcess *))); + conprocess->start(KProcess::NotifyOnExit,true); +} + + +void KgpgInterface::delsigprocess(KProcIO *p) +{ + + QString required=QString::null; + while (p->readln(required,true)!=-1) + { + if (required.find("keyedit.delsig")!=-1){ + + if ((sigsearch==signb) && (step==0)) { + p->writeStdin("Y"); + step=1; + } else + p->writeStdin("n"); + sigsearch++; + required=QString::null; + } + if ((step==1) && (required.find("keyedit.prompt")!=-1)) { + p->writeStdin("save"); + required=QString::null; + deleteSuccess=true; + } + if (required.find("GET_LINE")!=-1) { + p->writeStdin("quit"); + p->closeWhenDone(); + deleteSuccess=false; + } + } +} + +void KgpgInterface::delsignover(KProcess *) +{ + emit delsigfinished(deleteSuccess); +} + +/////////////////////////////////////////////////// check if a key has more than one id + +int KgpgInterface::checkuid(QString KeyID) +{ + FILE *fp; + QString encResult; + char buffer[200]; + int uidcnt=0; + + QString gpgcmd="gpg --no-tty --no-secmem-warning --with-colon --list-sigs "+KeyID; + ////////// encode with untrusted keys or armor if checked by user + fp = popen(QFile::encodeName(gpgcmd), "r"); + while (fgets(buffer, sizeof(buffer), fp)) { + encResult=buffer; + if (encResult.startsWith("uid")) + uidcnt++; + } + pclose(fp); + return uidcnt; +} + + +/////////////////////////////////////////////////////////////// change key expiration + + +void KgpgInterface::KgpgKeyExpire(QString keyID,QDate date,bool unlimited) +{ + expSuccess=0; + step=0; + if (unlimited) + expirationDelay=0; + else + expirationDelay=QDate::currentDate().daysTo(date); + output=QString::null; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<<"gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--command-fd=0"<<"--status-fd=2"<<"--utf8-strings"; + *conprocess<<"--edit-key"<<keyID<<"expire"; + QObject::connect(conprocess,SIGNAL(readReady(KProcIO *)),this,SLOT(expprocess(KProcIO *))); + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(expover(KProcess *))); + conprocess->start(KProcess::NotifyOnExit,KProcess::AllOutput); + +} + +void KgpgInterface::expprocess(KProcIO *p) +{ + QString required=QString::null; + + while (p->readln(required,true)!=-1) { + output+=required+"\n"; + + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if ((required.find("GOOD_PASSPHRASE")!=-1)) { + expSuccess=3; + step=2; + } + + if (required.find("keygen.valid")!=-1) { + p->writeStdin(QString::number(expirationDelay)); + required=QString::null; + } + + if (required.find("passphrase.enter")!=-1) { + QCString signpass; + int code=KPasswordDialog::getPassword(signpass,i18n("<qt>Enter passphrase for <b>%1</b>:</qt>").arg(userIDs)); + if (code!=QDialog::Accepted) { + expSuccess=3; ///// aborted by user mode + p->writeStdin("quit"); + p->closeWhenDone(); + return; + } + p->writeStdin(signpass,true); + required=QString::null; + // step=2; + } + if ((step==2) && (required.find("keyedit.prompt")!=-1)) { + p->writeStdin("save"); + p->closeWhenDone(); + required=QString::null; + } + if ((step==2) && (required.find("keyedit.save.okay")!=-1)) { + p->writeStdin("YES"); + p->closeWhenDone(); + required=QString::null; + } + if (required.find("BAD_PASSPHRASE")!=-1) { + p->writeStdin("quit"); + p->closeWhenDone(); + expSuccess=2; ///// bad passphrase + } + if ((required.find("GET_")!=-1) && (expSuccess!=2)) /////// gpg asks for something unusal, turn to konsole mode + { + expSuccess=1; ///// switching to console mode + p->writeStdin("quit"); + p->closeWhenDone(); + + } + } +} + + + +void KgpgInterface::expover(KProcess *) +{ + if ((expSuccess==3) || (expSuccess==2)) + emit expirationFinished(expSuccess); //// signature successful or bad passphrase + else { + KDetailedConsole *q=new KDetailedConsole(0,"sign_error",i18n("<qt><b>Changing expiration failed.</b><br>" + "Do you want to try changing the key expiration in console mode?</qt>"),output); + if (q->exec()==QDialog::Accepted) + KMessageBox::sorry(0,"work in progress..."); + //openSignConsole(); + else + emit expirationFinished(0); + } +} + + +/////////////////////////////////////////////////////////////// change key trust + + +void KgpgInterface::KgpgTrustExpire(QString keyID,int keyTrust) +{ + trustValue=keyTrust+1; +/* Don't know=1; Do NOT trust=2; Marginally=3; Fully=4; Ultimately=5; */ + + output=QString::null; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<<"gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--command-fd=0"<<"--status-fd=2"<<"--utf8-strings"; + *conprocess<<"--edit-key"<<keyID<<"trust"; + QObject::connect(conprocess,SIGNAL(readReady(KProcIO *)),this,SLOT(trustprocess(KProcIO *))); + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(trustover(KProcess *))); + conprocess->start(KProcess::NotifyOnExit,true); + +} + +void KgpgInterface::trustprocess(KProcIO *p) +{ + QString required=QString::null; + while (p->readln(required,true)!=-1) { + output+=required+"\n"; + if (required.find("edit_ownertrust.set_ultimate.okay")!=-1) { + p->writeStdin("YES"); + required=QString::null; + } + + if (required.find("edit_ownertrust.value")!=-1) { + p->writeStdin(QString::number(trustValue)); + required=QString::null; + } + + if (required.find("keyedit.prompt")!=-1) { + p->writeStdin("save"); + p->closeWhenDone(); + required=QString::null; + } + + if (required.find("GET_")!=-1) /////// gpg asks for something unusal, turn to konsole mode + { + expSuccess=1; ///// switching to console mode + p->writeStdin("quit"); + p->closeWhenDone(); + + } + } +} + + + +void KgpgInterface::trustover(KProcess *) +{ + emit trustfinished(); +} + + +/////////////////////////////////////////////////////////////// change passphrase + + +void KgpgInterface::KgpgChangePass(QString keyID) +{ + step=1; + output=QString::null; + message=QString::null; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<<"gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--no-use-agent"<<"--command-fd=0"<<"--status-fd=2"<<"--utf8-strings"; + *conprocess<<"--edit-key"<<keyID<<"passwd"; + QObject::connect(conprocess,SIGNAL(readReady(KProcIO *)),this,SLOT(passprocess(KProcIO *))); + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(passover(KProcess *))); + conprocess->start(KProcess::NotifyOnExit,KProcess::AllOutput); + +} + +void KgpgInterface::passprocess(KProcIO *p) +{ + QString required=QString::null; + + while (p->readln(required,true)!=-1) { + output+=required+"\n"; + + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if ((step>2) && (required.find("keyedit.prompt")!=-1)) { + if (step==3) + { + emit passwordChanged(); + p->writeStdin("save"); + } + else p->writeStdin("quit"); + required=QString::null; + } + + if ((required.find("GOOD_PASSPHRASE")!=-1) && (step==2)) + step=3; + + if ((required.find("BAD_PASSPHRASE")!=-1) && (step==2)) { + step=1; + message=i18n("<b>Bad passphrase</b>. Try again<br>"); + } + + if ((required.find("passphrase.enter")!=-1)) { + if (userIDs.isEmpty()) + userIDs=i18n("[No user id found]"); + userIDs.replace(QRegExp("<"),"<"); + + if (step==1) { + QCString passphrase; + int code=KPasswordDialog::getPassword(passphrase,i18n("<qt>%1 Enter passphrase for <b>%2</b></qt>") + .arg(message).arg(userIDs)); + if (code!=QDialog::Accepted) { + p->writeStdin("quit"); + // p->closeWhenDone(); + emit processaborted(true); + p->deleteLater(); + return; + } + p->writeStdin(passphrase,true); + step=2; + } + + if (step==3) { + QCString passphrase; + int code=KPasswordDialog::getNewPassword(passphrase,i18n("<qt>Enter new passphrase for <b>%1</b><br>If you forget this passphrase, all your encrypted files and messages will be lost !<br></qt>").arg(userIDs)); + if (code!=QDialog::Accepted) { + step=4; + p->writeStdin("quit"); + p->writeStdin("quit"); + p->closeWhenDone(); + emit processaborted(true); + return; + } + p->writeStdin(passphrase,true); + userIDs=QString::null; + } + + required=QString::null; + } + + + if (required.find("GET_")!=-1) /////// gpg asks for something unusal, turn to konsole mode + { + p->writeStdin("quit"); + p->closeWhenDone(); + + } + } +} + + + +void KgpgInterface::passover(KProcess *) +{ + //emit trustfinished(); +} + + + +////////////////////////////////////////////////////////////// key export + +QString KgpgInterface::getKey(QStringList IDs, bool attributes) +{ + keyString=QString::null; + KProcIO *proc=new KProcIO(QTextCodec::codecForLocale()); + *proc<< "gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--utf8-strings"; + *proc<<"--export"<<"--armor"; + if (!attributes) + *proc<<"--export-options"<<"no-include-attributes"; + + for ( QStringList::Iterator it = IDs.begin(); it != IDs.end(); ++it ) + *proc << *it; + QObject::connect(proc, SIGNAL(readReady(KProcIO *)),this, SLOT(slotReadKey(KProcIO *))); + proc->start(KProcess::Block,false); + return keyString; +} + + +void KgpgInterface::slotReadKey(KProcIO *p) +{ + QString outp; + while (p->readln(outp)!=-1) + if (!outp.startsWith("gpg:")) keyString+=outp+"\n"; +} + + +////////////////////////////////////////////////////////////// key import + +void KgpgInterface::importKeyURL(KURL url) +{ + ///////////// import a key + + if( KIO::NetAccess::download( url, tempKeyFile,0) ) { + message=QString::null; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--status-fd=2"<<"--utf8-strings"<<"--import"; + *conprocess<<"--allow-secret-key-import"; + *conprocess<<tempKeyFile; + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(importURLover(KProcess *))); + QObject::connect(conprocess, SIGNAL(readReady(KProcIO *)),this, SLOT(importprocess(KProcIO *))); + conprocess->start(KProcess::NotifyOnExit,true); + } +} + +void KgpgInterface::importKey(QString keystr) +{ + ///////////// import a key + message=QString::null; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--status-fd=2"<<"--import"; + *conprocess<<"--allow-secret-key-import"; + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(importover(KProcess *))); + QObject::connect(conprocess, SIGNAL(readReady(KProcIO *)),this, SLOT(importprocess(KProcIO *))); + conprocess->start(KProcess::NotifyOnExit,true); + conprocess->writeStdin(keystr, true); + conprocess->closeWhenDone(); +} + +void KgpgInterface::importover(KProcess *) +{ +QStringList importedKeysIds; +QStringList messageList; +QString resultMessage; +bool secretImport=false; +kdDebug(2100)<<"Importing is over"<<endl; + QString parsedOutput=message; + QStringList importedKeys; + + while (parsedOutput.find("IMPORTED")!=-1) { + parsedOutput.remove(0,parsedOutput.find("IMPORTED")+8); + importedKeys<<parsedOutput.section("\n",0,0).stripWhiteSpace(); + importedKeysIds<<parsedOutput.stripWhiteSpace().section(' ',0,0); + } + + + if (message.find("IMPORT_RES")!=-1) { + parsedOutput=message.section("IMPORT_RES",-1,-1).stripWhiteSpace(); + messageList=QStringList::split(" ",parsedOutput,true); + + resultMessage=i18n("<qt>%n key processed.<br></qt>","<qt>%n keys processed.<br></qt>",messageList[0].toULong()); + if (messageList[4]!="0") + resultMessage+=i18n("<qt>One key unchanged.<br></qt>","<qt>%n keys unchanged.<br></qt>",messageList[4].toULong()); + if (messageList[7]!="0") + resultMessage+=i18n("<qt>One signature imported.<br></qt>","<qt>%n signatures imported.<br></qt>",messageList[7].toULong()); + if (messageList[1]!="0") + resultMessage+=i18n("<qt>One key without ID.<br></qt>","<qt>%n keys without ID.<br></qt>",messageList[1].toULong()); + if (messageList[3]!="0") + resultMessage+=i18n("<qt>One RSA key imported.<br></qt>","<qt>%n RSA keys imported.<br></qt>",messageList[3].toULong()); + if (messageList[5]!="0") + resultMessage+=i18n("<qt>One user ID imported.<br></qt>","<qt>%n user IDs imported.<br></qt>",messageList[5].toULong()); + if (messageList[6]!="0") + resultMessage+=i18n("<qt>One subkey imported.<br></qt>","<qt>%n subkeys imported.<br></qt>",messageList[6].toULong()); + if (messageList[8]!="0") + resultMessage+=i18n("<qt>One revocation certificate imported.<br></qt>","<qt>%n revocation certificates imported.<br></qt>",messageList[8].toULong()); + if (messageList[9]!="0") + { + resultMessage+=i18n("<qt>One secret key processed.<br></qt>","<qt>%n secret keys processed.<br></qt>",messageList[9].toULong()); + secretImport=true; + } + if (messageList[10]!="0") + resultMessage+=i18n("<qt><b>One secret key imported.</b><br></qt>","<qt><b>%n secret keys imported.</b><br></qt>",messageList[10].toULong()); + if (messageList[11]!="0") + resultMessage+=i18n("<qt>One secret key unchanged.<br></qt>","<qt>%n secret keys unchanged.<br></qt>",messageList[11].toULong()); + if (messageList[12]!="0") + resultMessage+=i18n("<qt>One secret key not imported.<br></qt>","<qt>%n secret keys not imported.<br></qt>",messageList[12].toULong()); + if (messageList[2]!="0") + resultMessage+=i18n("<qt><b>One key imported:</b><br></qt>","<qt><b>%n keys imported:</b><br></qt>",messageList[2].toULong()); + + if (secretImport) resultMessage+=i18n("<qt><br><b>You have imported a secret key.</b> <br>" + "Please note that imported secret keys are not trusted by default.<br>" + "To fully use this secret key for signing and encryption, you must edit the key (double click on it) and set its trust to Full or Ultimate.</qt>"); + } else + resultMessage=i18n("No key imported... \nCheck detailed log for more infos"); + + if (messageList[8]!="0") importedKeysIds="ALL"; + if ((messageList[9]!="0") && (importedKeysIds.isEmpty())) // orphaned secret key imported + emit refreshOrphaned(); + emit importfinished(importedKeysIds); + + (void) new KDetailedInfo(0,"import_result",resultMessage,message,importedKeys); +} + +void KgpgInterface::importURLover(KProcess *p) +{ + KIO::NetAccess::removeTempFile(tempKeyFile); + importover(p); + //KMessageBox::information(0,message); + //emit importfinished(); +} + +void KgpgInterface::importprocess(KProcIO *p) +{ + QString outp; + while (p->readln(outp)!=-1) { + if (outp.find("http-proxy")==-1) + message+=outp+"\n"; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////// User ID's + + +void KgpgInterface::KgpgAddUid(QString keyID,QString name,QString email,QString comment) +{ +uidName=name; +uidComment=comment; +uidEmail=email; +output=QString::null; +addSuccess=true; + + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"<<"--no-tty"<<"--status-fd=2"<<"--command-fd=0"<<"--utf8-strings"; + *conprocess<<"--edit-key"<<keyID<<"adduid"; + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(adduidover(KProcess *))); + QObject::connect(conprocess, SIGNAL(readReady(KProcIO *)),this, SLOT(adduidprocess(KProcIO *))); + conprocess->start(KProcess::NotifyOnExit,true); +} + +void KgpgInterface::adduidover(KProcess *) +{ +if (addSuccess) emit addUidFinished(); +else emit addUidError(output); +} + +void KgpgInterface::adduidprocess(KProcIO *p) +{ + QString required=QString::null; + while (p->readln(required,true)!=-1) { + output+=required+"\n"; + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if (required.find("keygen.name")!=-1) { + p->writeStdin(uidName); + required=QString::null; + } + + if (required.find("keygen.email")!=-1) { + p->writeStdin(uidEmail); + required=QString::null; + } + + if (required.find("keygen.comment")!=-1) { + p->writeStdin(uidComment); + required=QString::null; + } + + if (required.find("passphrase.enter")!=-1) { + QCString delpass; + int code=KPasswordDialog::getPassword(delpass,i18n("<qt>Enter passphrase for <b>%1</b>:</qt>") + .arg(userIDs)); + if (code!=QDialog::Accepted) { + //addSuccess=false; + p->writeStdin("quit"); + p->closeWhenDone(); + return; + } + p->writeStdin(delpass,true); + required=QString::null; + + } + + if (required.find("keyedit.prompt")!=-1) { + p->writeStdin("save"); + required=QString::null; + } + + if ((required.find("GET_")!=-1)) /////// gpg asks for something unusal, turn to konsole mode + { + kdDebug(2100)<<"unknown request"<<endl; + addSuccess=false; ///// switching to console mode + p->writeStdin("quit"); + p->closeWhenDone(); + } + } +} + + + + + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// photo id's + +void KgpgInterface::KgpgGetPhotoList(QString keyID) +{ +photoList.clear(); +output=QString::null; +photoCount=1; +userIDs=keyID; + + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"<<"--no-tty"<<"--status-fd=2"<<"--command-fd=0"; + *conprocess<<"--with-colon"<<"--list-keys"<<keyID; + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(photoreadover(KProcess *))); + QObject::connect(conprocess, SIGNAL(readReady(KProcIO *)),this, SLOT(photoreadprocess(KProcIO *))); + conprocess->start(KProcess::NotifyOnExit,true); +} + +void KgpgInterface::photoreadprocess(KProcIO *p) +{ + QString required=QString::null; + while (p->readln(required,true)!=-1) { + output+=required+"\n"; + if (required.startsWith("uat") || required.startsWith("uid")) photoCount++; +} +} + + +void KgpgInterface::photoreadover(KProcess *) +{ +for (int i=1;i<photoCount+1;i++) +if (isPhotoId(i)) photoList+=QString::number(i); + +emit signalPhotoList(photoList); +} + +bool KgpgInterface::isPhotoId(int uid) +{ +KTempFile *kgpginfotmp=new KTempFile(); + kgpginfotmp->setAutoDelete(true); + QString pgpgOutput="cp %i "+kgpginfotmp->name(); + +KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"<<"--no-tty"<<"--status-fd=2"<<"--command-fd=0"<<"--utf8-strings"; + *conprocess<<"--photo-viewer"<<QFile::encodeName(pgpgOutput)<<"--edit-key"<<userIDs<<"uid"<<QString::number(uid)<<"showphoto"; + conprocess->start(KProcess::Block); + if (kgpginfotmp->file()->size()>0) + { + kgpginfotmp->unlink(); + return true; + } + kgpginfotmp->unlink(); + return false; +} + +void KgpgInterface::KgpgDeletePhoto(QString keyID,QString uid) +{ + delSuccess=true; + output=QString::null; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"<<"--no-tty"<<"--status-fd=2"<<"--command-fd=0"<<"--utf8-strings"; + *conprocess<<"--edit-key"<<keyID<<"uid"<<uid<<"deluid"; + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(delphotoover(KProcess *))); + QObject::connect(conprocess, SIGNAL(readReady(KProcIO *)),this, SLOT(delphotoprocess(KProcIO *))); + conprocess->start(KProcess::NotifyOnExit,true); +} + +void KgpgInterface::delphotoover(KProcess *) +{ +if (delSuccess) emit delPhotoFinished(); +else emit delPhotoError(output); +} + +void KgpgInterface::delphotoprocess(KProcIO *p) +{ + QString required=QString::null; + while (p->readln(required,true)!=-1) { + output+=required+"\n"; + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if (required.find("keyedit.remove.uid.okay")!=-1) { + p->writeStdin("YES"); + required=QString::null; + } + + if (required.find("passphrase.enter")!=-1) { + QCString delpass; + int code=KPasswordDialog::getPassword(delpass,i18n("<qt>Enter passphrase for <b>%1</b>:</qt>").arg(userIDs)); + if (code!=QDialog::Accepted) { + //deleteSuccess=false; + p->writeStdin("quit"); + p->closeWhenDone(); + return; + } + p->writeStdin(delpass,true); + required=QString::null; + + } + + if (required.find("keyedit.prompt")!=-1) { + p->writeStdin("save"); + required=QString::null; + } + + if ((required.find("GET_")!=-1)) /////// gpg asks for something unusal, turn to konsole mode + { + kdDebug(2100)<<"unknown request"<<endl; + delSuccess=false; + p->writeStdin("quit"); + p->closeWhenDone(); + + } + } +} + + +void KgpgInterface::KgpgAddPhoto(QString keyID,QString imagePath) +{ +photoUrl=imagePath; +output=QString::null; +addSuccess=true; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"<<"--no-tty"<<"--status-fd=2"<<"--command-fd=0"<<"--utf8-strings"; + *conprocess<<"--edit-key"<<keyID<<"addphoto"; + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(addphotoover(KProcess *))); + QObject::connect(conprocess, SIGNAL(readReady(KProcIO *)),this, SLOT(addphotoprocess(KProcIO *))); + conprocess->start(KProcess::NotifyOnExit,true); +} + +void KgpgInterface::addphotoover(KProcess *) +{ +if (addSuccess) emit addPhotoFinished(); +else emit addPhotoError(output); +} + +void KgpgInterface::addphotoprocess(KProcIO *p) +{ + QString required=QString::null; + while (p->readln(required,true)!=-1) { + output+=required+"\n"; + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if (required.find("photoid.jpeg.add")!=-1) { + p->writeStdin(photoUrl); + required=QString::null; + } + + if (required.find("photoid.jpeg.size")!=-1) { + if (KMessageBox::questionYesNo(0,i18n("This image is very large. Use it anyway?"), QString::null, i18n("Use Anyway"), i18n("Do Not Use"))==KMessageBox::Yes) + p->writeStdin("Yes"); + else + { + p->writeStdin("No"); + p->writeStdin(""); + p->writeStdin("quit"); + } + required=QString::null; + } + + if (required.find("passphrase.enter")!=-1) { + QCString delpass; + int code=KPasswordDialog::getPassword(delpass,i18n("<qt>Enter passphrase for <b>%1</b>:</qt>").arg(userIDs)); + if (code!=QDialog::Accepted) { + //deleteSuccess=false; + p->writeStdin("quit"); + p->closeWhenDone(); + return; + } + p->writeStdin(delpass,true); + required=QString::null; + + } + + if (required.find("keyedit.prompt")!=-1) { + p->writeStdin("save"); + required=QString::null; + } + + if ((required.find("GET_")!=-1)) /////// gpg asks for something unusal, turn to konsole mode + { + kdDebug(2100)<<"unknown request"<<endl; + p->writeStdin("quit"); + addSuccess=false; + p->closeWhenDone(); + + } + } +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// key revocation + +void KgpgInterface::KgpgRevokeKey(QString keyID,QString revokeUrl,int reason,QString description) +{ + revokeReason=reason; + revokeSuccess=false; + revokeDescription=description; + certificateUrl=revokeUrl; + output=QString::null; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"<<"--no-tty"<<"--status-fd=2"<<"--logger-fd=2"<<"--command-fd=0"<<"--utf8-strings"; + if (!revokeUrl.isEmpty()) + *conprocess<<"-o"<<revokeUrl; + *conprocess<<"--gen-revoke"<<keyID; + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(revokeover(KProcess *))); + QObject::connect(conprocess, SIGNAL(readReady(KProcIO *)),this, SLOT(revokeprocess(KProcIO *))); + conprocess->start(KProcess::NotifyOnExit,true); +} + +void KgpgInterface::revokeover(KProcess *) +{ + if (!revokeSuccess) + KMessageBox::detailedSorry(0,i18n("Creation of the revocation certificate failed..."),output); + else { + output=output.section("-----BEGIN",1); + output.prepend("-----BEGIN"); + output=output.section("BLOCK-----",0); + emit revokecertificate(output); + if (!certificateUrl.isEmpty()) + emit revokeurl(certificateUrl); + } +} + +void KgpgInterface::revokeprocess(KProcIO *p) +{ + QString required=QString::null; + while (p->readln(required,true)!=-1) { + output+=required+"\n"; + + if (required.find("USERID_HINT",0,false)!=-1) + updateIDs(required); + + if ((required.find("GOOD_PASSPHRASE")!=-1)) + revokeSuccess=true; + + if ((required.find("gen_revoke.okay")!=-1) || (required.find("ask_revocation_reason.okay")!=-1) || (required.find("openfile.overwrite.okay")!=-1)) { + p->writeStdin("YES"); + required=QString::null; + } + + if (required.find("ask_revocation_reason.code")!=-1) { + p->writeStdin(QString::number(revokeReason)); + required=QString::null; + } + + if (required.find("passphrase.enter")!=-1) { + QCString signpass; + int code=KPasswordDialog::getPassword(signpass,i18n("<qt>Enter passphrase for <b>%1</b>:</qt>").arg(userIDs)); + if (code!=QDialog::Accepted) { + expSuccess=3; ///// aborted by user mode + p->writeStdin("quit"); + p->closeWhenDone(); + return; + } + p->writeStdin(signpass,true); + required=QString::null; + + } + if (required.find("ask_revocation_reason.text")!=-1) { + // kdDebug(2100)<<"description"<<endl; + p->writeStdin(revokeDescription); + revokeDescription=QString::null; + required=QString::null; + } + if ((required.find("GET_")!=-1)) /////// gpg asks for something unusal, turn to konsole mode + { + kdDebug(2100)<<"unknown request"<<endl; + expSuccess=1; ///// switching to console mode + p->writeStdin("quit"); + p->closeWhenDone(); + + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// parsing of ./gnupg/options file + +QString KgpgInterface::getGpgSetting(QString name,QString configFile) +{ + name=name.stripWhiteSpace()+" "; + QFile qfile(QFile::encodeName(configFile)); + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + if (result.stripWhiteSpace().startsWith(name)) { + result=result.stripWhiteSpace(); + result.remove(0,name.length()); + result=result.stripWhiteSpace(); + return result.section(" ",0,0); + } + result=t.readLine(); + } + qfile.close(); + } + return QString::null; +} + +QString KgpgInterface::getGpgMultiSetting(QString name,QString configFile) +{ +// get GnuPG setting for item that can have multiple entries (eg. encrypt-to) + +QString parsedResult=QString::null; + + name=name.stripWhiteSpace()+" "; + QFile qfile(QFile::encodeName(configFile)); + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + if (result.stripWhiteSpace().startsWith(name)) { + result=result.stripWhiteSpace(); + result.remove(0,name.length()); + if (parsedResult!=QString::null) + parsedResult+=" "+result.stripWhiteSpace(); + else + parsedResult+=result.stripWhiteSpace(); + //return result.section(" ",0,0); + } + result=t.readLine(); + } + qfile.close(); + } + return parsedResult; +} + +void KgpgInterface::delGpgGroup(QString name, QString configFile) +{ + QString textToWrite; + QFile qfile(QFile::encodeName(configFile)); + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + if (result.stripWhiteSpace().startsWith("group ")) { + QString result2=result.stripWhiteSpace(); + result2.remove(0,6); + result2=result2.stripWhiteSpace(); + if (result2.startsWith(name) && (result2.remove(0,name.length()).stripWhiteSpace().startsWith("="))) + result=QString::null; + } + if (result!=QString::null) textToWrite+=result+"\n"; + result=t.readLine(); + } + qfile.close(); + if (qfile.open(IO_WriteOnly)) { + QTextStream t( &qfile); + t << textToWrite; + qfile.close(); + } + } +} + +void KgpgInterface::setGpgGroupSetting(QString name,QStringList values, QString configFile) +{ + QString textToWrite; + bool found=false; + QFile qfile(QFile::encodeName(configFile)); + kdDebug(2100)<<"Changing group: "<<name<<endl; + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + if (result.stripWhiteSpace().startsWith("group ")) { + QString result2=result.stripWhiteSpace(); + result2.remove(0,6); + result2=result2.stripWhiteSpace(); + if (result2.startsWith(name) && (result2.remove(0,name.length()).stripWhiteSpace().startsWith("="))) { +// kdDebug(2100)<<"Found group: "<<name<<endl; + //kdDebug(2100)<<"New values: "<<values<<endl; + result=QString("group %1=%2").arg(name).arg(values.join(" ")); + found=true; + } + } + textToWrite+=result+"\n"; + result=t.readLine(); + } + qfile.close(); + if (!found) + textToWrite+="\n"+QString("group %1=%2").arg(name).arg(values.join(" ")); + + if (qfile.open(IO_WriteOnly)) { + QTextStream t( &qfile); + t << textToWrite; + qfile.close(); + } + } +} + + + +QStringList KgpgInterface::getGpgGroupSetting(QString name,QString configFile) +{ + + QFile qfile(QFile::encodeName(configFile)); + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + result=result.stripWhiteSpace(); + if (result.startsWith("group ")) { + kdDebug(2100)<<"Found 1 group"<<endl; + result.remove(0,6); + if (result.stripWhiteSpace().startsWith(name)) { + kdDebug(2100)<<"Found group: "<<name<<endl; + result=result.section('=',1); + result=result.section('#',0,0); + return QStringList::split (" ",result); + } + } + result=t.readLine(); + } + qfile.close(); + } + return QString::null; +} + +QStringList KgpgInterface::getGpgGroupNames(QString configFile) +{ + QStringList groups; + QFile qfile(QFile::encodeName(configFile)); + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + result=result.stripWhiteSpace(); + if (result.startsWith("group ")) { + result.remove(0,6); + groups<<result.section("=",0,0).stripWhiteSpace(); + } + result=t.readLine(); + } + qfile.close(); + } + return groups; +} + + +bool KgpgInterface::getGpgBoolSetting(QString name,QString configFile) +{ + name=name; + QFile qfile(QFile::encodeName(configFile)); + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + if (result.stripWhiteSpace().startsWith(name)) { + return true; + } + result=t.readLine(); + } + qfile.close(); + } + return false; +} + +void KgpgInterface::setGpgSetting(QString name,QString value,QString url) +{ + name=name+" "; + QString textToWrite; + bool found=false; + QFile qfile(QFile::encodeName(url)); + + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + if (result.stripWhiteSpace().startsWith(name)) { + if (!value.isEmpty()) + result=name+" "+value; + else + result=QString::null; + found=true; + } + if (result!=QString::null) textToWrite+=result+"\n"; + result=t.readLine(); + } + qfile.close(); + if ((!found) && (!value.isEmpty())) + textToWrite+="\n"+name+" "+value; + + if (qfile.open(IO_WriteOnly)) { + QTextStream t( &qfile); + t << textToWrite; + qfile.close(); + } + } +} + + +void KgpgInterface::setGpgMultiSetting(QString name,QStringList values,QString url) +{ + name=name+" "; + QString textToWrite; + bool found=false; + QFile qfile(QFile::encodeName(url)); + + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + if (!result.stripWhiteSpace().startsWith(name)) + textToWrite+=result+"\n"; + result=t.readLine(); + } + qfile.close(); + + while (!values.isEmpty()) + { + textToWrite+="\n"+name+" "+values.first(); + values.pop_front(); + } + + if (qfile.open(IO_WriteOnly)) { + QTextStream t( &qfile); + t << textToWrite; + qfile.close(); + } + } +} + +void KgpgInterface::setGpgBoolSetting(QString name,bool enable,QString url) +{ + QString textToWrite; + bool found=false; + QFile qfile(QFile::encodeName(url)); + + if (qfile.open(IO_ReadOnly) && (qfile.exists())) { + QString result; + QTextStream t( &qfile ); + result=t.readLine(); + while (result!=NULL) { + if (result.stripWhiteSpace().startsWith(name)) { + if (enable) + result=name; + else + result=QString::null; + found=true; + } + if (result!=QString::null) textToWrite+=result+"\n"; + result=t.readLine(); + } + qfile.close(); + if ((!found) && (enable)) + textToWrite+=name; + + if (qfile.open(IO_WriteOnly)) { + QTextStream t( &qfile); + t << textToWrite; + qfile.close(); + } + } +} + +QString KgpgInterface::checkForUtf8bis(QString txt) +{ + if (strchr (txt.ascii(), 0xc3) || (txt.find("\\x")!=-1)) + txt=checkForUtf8(txt); + else { + txt=checkForUtf8(txt); + txt=QString::fromUtf8(txt.ascii()); + } + return txt; +} + + +QString KgpgInterface::checkForUtf8(QString txt) +{ + // code borrowed from gpa + const char *s; + + /* Make sure the encoding is UTF-8. + * Test structure suggested by Werner Koch */ + if (txt.isEmpty()) + return QString::null; + + for (s = txt.ascii(); *s && !(*s & 0x80); s++) + ; + if (*s && !strchr (txt.ascii(), 0xc3) && (txt.find("\\x")==-1)) + return txt; + + /* The string is not in UTF-8 */ + //if (strchr (txt.ascii(), 0xc3)) return (txt+" +++"); + if (txt.find("\\x")==-1) + return QString::fromUtf8(txt.ascii()); + // if (!strchr (txt.ascii(), 0xc3) || (txt.find("\\x")!=-1)) { + for ( int idx = 0 ; (idx = txt.find( "\\x", idx )) >= 0 ; ++idx ) { + char str[2] = "x"; + str[0] = (char) QString( txt.mid( idx + 2, 2 ) ).toShort( 0, 16 ); + txt.replace( idx, 4, str ); + } + if (!strchr (txt.ascii(), 0xc3)) + return QString::fromUtf8(txt.ascii()); + else + return QString::fromUtf8(QString::fromUtf8(txt.ascii()).ascii()); // perform Utf8 twice, or some keys display badly + + return txt; +} + + +#include "kgpginterface.moc" diff --git a/kgpg/kgpginterface.h b/kgpg/kgpginterface.h new file mode 100644 index 0000000..4fb21b2 --- /dev/null +++ b/kgpg/kgpginterface.h @@ -0,0 +1,404 @@ +/*************************************************************************** + kgpginterface.h - description + ------------------- + begin : Sat Jun 29 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KGPGINTERFACE_H +#define KGPGINTERFACE_H + + +#include <qobject.h> +#include <kdialogbase.h> +#include <kurl.h> +#include <qdatetime.h> + +class QLabel; +class KProcIO; +class KProcess; +class KLed; + +/** + * Encrypt a file using gpg. + */ + +class KgpgInterface : public QObject +{ + + Q_OBJECT + +public: + /** + * Initialize the class + */ + KgpgInterface(); + + /* + * Destructor for the class. + */ + ~KgpgInterface(); + +public slots: + + /**Encrypt file function + * @param userIDs the recipients key id's. + * @param srcUrl Kurl of the file to encrypt. + * @param destUrl Kurl for the encrypted file. + * @param Options String with the wanted gpg options. ex: "--armor" + * @param symetrical bool whether the encryption should be symmetrical. + */ + void KgpgEncryptFile(QStringList encryptKeys,KURL srcUrl,KURL destUrl,QStringList Options=QString::null,bool symetrical=false); + + /**Encrypt file function + * @param userIDs the key user identification. + * @param srcUrl Kurl of the file to decrypt. + * @param destUrl Kurl for the decrypted file. + * @param chances int number of trials left for decryption (used only as an info displayed in the password dialog) + */ + void KgpgDecryptFile(KURL srcUrl,KURL destUrl,QStringList Options=QStringList()); + + /**Sign file function + * @param keyID QString the signing key ID. + * @param srcUrl Kurl of the file to sign. + * @param Options String with the wanted gpg options. ex: "--armor" + */ + void KgpgSignFile(QString keyID,KURL srcUrl,QStringList Options=QStringList()); + + /**Verify file function + * @param sigUrl Kurl of the signature file. + * @param srcUrl Kurl of the file to be verified. If empty, gpg will try to find it using the signature file name (by removing the .sig extensio) + */ + void KgpgVerifyFile(KURL sigUrl,KURL srcUrl=KURL()) ; + + void KgpgVerifyText(QString text); + void slotverifyread(KProcIO *p); + void slotverifyresult(KProcess*); + + + /**Import key function + * @param url Kurl the url of the key file. Allows public & secret key import. + */ + void importKeyURL(KURL url); + /**Import key function + * @param keystr QString containing th key. Allows public & secret key import. + */ + void importKey(QString keystr); + + /**Key signature function + * @param keyID QString the ID of the key to be signed + * @param signKeyID QString the ID of the signing key + * @param signKeyMail QString the name of the signing key (only used to prompt user for passphrase) + * @param local bool should the signature be local + */ + void KgpgSignKey(QString keyID,QString signKeyID,QString signKeyMail=QString::null,bool local=false,int checking=0); + + /**Key signature deletion function + * @param keyID QString the ID of the key + * @param signKeyID QString the ID of the signature key + */ + void KgpgDelSignature(QString keyID,QString signKeyID); + + /**Encrypt text function + * @param text QString text to be encrypted. + * @param userIDs the recipients key id's. + * @param Options String with the wanted gpg options. ex: "--armor" + * returns the encrypted text or empty string if encyption failed + */ + void KgpgEncryptText(QString text,QStringList userIDs, QStringList Options=QString::null); + + /**Decrypt text function + * @param text QString text to be decrypted. + * @param userID QString the name of the decryption key (only used to prompt user for passphrase) + */ + //static QString KgpgDecryptText(QString text,QString userID); + void KgpgDecryptText(QString text,QStringList Options=QString::null); + void txtdecryptfin(KProcess *); + + /**Extract list of photographic user id's + * @param keyID the recipients key id's. + */ + void KgpgGetPhotoList(QString keyID); + + void getOutput(KProcess *, char *data, int ); + void getCmdOutput(KProcess *p, char *data, int ); + + QString getKey(QStringList IDs, bool attributes); + + void KgpgKeyExpire(QString keyID,QDate date,bool unlimited); + void KgpgTrustExpire(QString keyID,int keyTrust); + void KgpgChangePass(QString keyID); + + void KgpgRevokeKey(QString keyID,QString revokeUrl,int reason,QString description); + void revokeover(KProcess *); + void revokeprocess(KProcIO *p); + void KgpgDeletePhoto(QString keyID,QString uid); + void KgpgAddPhoto(QString keyID,QString imagePath); + + void KgpgAddUid(QString keyID,QString name,QString email,QString comment); + + void KgpgDecryptFileToText(KURL srcUrl,QStringList Options); + void KgpgSignText(QString text,QString userIDs, QStringList Options); + + static QString getGpgSetting(QString name,QString configFile); + static QString getGpgMultiSetting(QString name,QString configFile); + static void setGpgSetting(QString name,QString ID,QString url); + static void setGpgMultiSetting(QString name,QStringList values,QString url); + static bool getGpgBoolSetting(QString name,QString configFile); + static void setGpgBoolSetting(QString name,bool enable,QString url); + static QStringList getGpgGroupNames(QString configFile); + static QStringList getGpgGroupSetting(QString name,QString configFile); + static void setGpgGroupSetting(QString name,QStringList values, QString configFile); + static void delGpgGroup(QString name, QString configFile); + static QString checkForUtf8(QString txt); + static QString checkForUtf8bis(QString txt); + static int getGpgVersion(); + + + +private slots: + + void openSignConsole(); + /** + * Checks output of the signature process + */ + void signover(KProcess *); + /** + * Read output of the signature process + */ + void sigprocess(KProcIO *p); + + /** + * Checks if the encrypted file was saved. + */ + void encryptfin(KProcess *); + + /** + * Checks if the decrypted file was saved. + */ + void decryptfin(KProcess *); + + /** + * Checks if the signing was successful. + */ + void signfin(KProcess *p); + + /** + * Checks the number of uid's for a key-> if greater than one, key signature will switch to konsole mode + */ + int checkuid(QString KeyID); + + /** + * Reads output of the delete signature process + */ + void delsigprocess(KProcIO *p); + /** + * Checks output of the delete signature process + */ + void delsignover(KProcess *p); + /** + * Checks output of the import process + */ + void importURLover(KProcess *p); + void importover(KProcess *); + /** + * Read output of the import process + */ + void importprocess(KProcIO *p); + /** + * Reads output of the current process + allow overwriting of a file + */ + void readprocess(KProcIO *p); + /** + * Reads output of the current encryption process + allow overwriting of a file + */ + void readencprocess(KProcIO *p); + /** + * Reads output of the current signing process + allow overwriting of a file + */ + void readsignprocess(KProcIO *p); + /** + * Reads output of the current decryption process + allow overwriting of a file + */ + void readdecprocess(KProcIO *p); + /** + * Checks output of the verify process + */ + void verifyfin(KProcess *p); + + void expprocess(KProcIO *p); + void expover(KProcess*); + void trustprocess(KProcIO *p); + void passprocess(KProcIO *p); + void trustover(KProcess *); + void passover(KProcess *); + + void txtreadencprocess(KProcIO *p); + + void txtencryptfin(KProcess *); + + void delphotoover(KProcess *); + void delphotoprocess(KProcIO *p); + void addphotoover(KProcess *); + void addphotoprocess(KProcIO *p); + + void adduidover(KProcess *); + void adduidprocess(KProcIO *p); + + void slotReadKey(KProcIO *p); + void photoreadover(KProcess *); + void photoreadprocess(KProcIO *p); + bool isPhotoId(int uid); + void updateIDs(QString txtString); + + void txtsignprocess(KProcIO *p); + void txtsignfin(KProcess *); + + //void txtdecryptfin(KProcess *); + + +signals: + + void missingSignature(QString); + void verifyOver(QString,QString); + + /** + * emitted when a txt decryption failed. returns log output + */ + void txtdecryptionfailed(QString); + /** + * emitted when a txt encryption starts. + */ + void txtencryptionstarted(); + + /** + * emitted when a txt decryption finished. returns decrypted text + */ + void txtdecryptionfinished(QString); + /** + * emitted when a txt encryption finished. returns encrypted text + */ + void txtencryptionfinished(QString); + /** + * emitted when an error occurred + */ + void errormessage(QString); + /** + * true if encryption successful, false on error. + */ + void encryptionfinished(KURL); + /** + * true if key signature deletion successful, false on error. + */ + void delsigfinished(bool); + + /** + * Signature process result: 0=successful, 1=error, 2=bad passphrase + */ + void signatureFinished(int); + /** + * emitted when user cancels process + */ + void processaborted(bool); + /** + * emitted when the process starts + */ + void processstarted(QString); + /** + * true if decryption successful, false on error. + */ + void decryptionfinished(); + /** + * emitted if bad passphrase was giver + */ + void badpassphrase(bool); + /** + * true if import successful, false on error. + */ + void importfinished(QStringList); + /** + * true if verify successful, false on error. + */ + void verifyfinished(); + /** + * emmitted if signature key is missing & user want to import it from keyserver + */ + void verifyquerykey(QString ID); + /** + * true if signature successful, false on error. + */ + void signfinished(); + void delPhotoFinished(); + void delPhotoError(QString); + + void addPhotoFinished(); + void addPhotoError(QString); + void refreshOrphaned(); + + void addUidFinished(); + void addUidError(QString); + + void trustfinished(); + void revokecertificate(QString); + void revokeurl(QString); + void expirationFinished(int); + void signalPhotoList(QStringList); + void passwordChanged(); + + void txtSignOver(QString); + + +private: + /** + * @internal structure for communication + */ + QString message,tempKeyFile,userIDs,output,keyString,txtToEncrypt,log; + QCString passphrase; + bool deleteSuccess,konsLocal,anonymous,decfinished,decok,badmdc,revokeSuccess,addSuccess,delSuccess; + bool signmiss; + QString signID; + int signSuccess,expSuccess,trustValue,konsChecked; + int step,signb,sigsearch,expirationDelay; + QString konsSignKey, konsKeyID,errMessage; + int revokeReason,photoCount; + QString revokeDescription,certificateUrl,photoUrl; + QStringList photoList; + QString uidName, uidEmail, uidComment; + KURL sourceFile; + QString decryptUrl; + + QString gpgOutput; + + /** + * @internal structure for the file information + */ + KURL file; + +}; + +class Md5Widget :public KDialogBase +{ + Q_OBJECT +public: + Md5Widget(QWidget *parent=0, const char *name=0,KURL url=KURL()); + ~Md5Widget(); +public slots: + void slotApply(); +private: + QString mdSum; + KLed *KLed1; + QLabel *TextLabel1_2; +}; + +#endif // KGPGINTERFACE_HKGPGINTERFACE_H + diff --git a/kgpg/kgpglibrary.cpp b/kgpg/kgpglibrary.cpp new file mode 100644 index 0000000..55455f9 --- /dev/null +++ b/kgpg/kgpglibrary.cpp @@ -0,0 +1,245 @@ +/*************************************************************************** + kgpglibrary.cpp - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qhbox.h> +#include <qvbox.h> + +#include <klocale.h> +#include <kapplication.h> +#include <kconfig.h> +#include <kmessagebox.h> +#include <krun.h> +#include <qfile.h> +#include <kpassivepopup.h> +#include <kiconloader.h> +#include "kgpglibrary.h" +#include "popuppublic.h" +#include "kgpginterface.h" +#include <kio/renamedlg.h> + +KgpgLibrary::KgpgLibrary(QWidget *parent, bool pgpExtension) +{ + if (pgpExtension) + extension=".pgp"; + else + extension=".gpg"; + popIsActive=false; + panel=parent; +} + +KgpgLibrary::~KgpgLibrary() +{} + + +void KgpgLibrary::slotFileEnc(KURL::List urls,QStringList opts,QStringList defaultKey,KShortcut goDefaultKey) +{ + ///////////////////////////////////////////////////////////////////////// encode file file + if (!urls.empty()) { + urlselecteds=urls; + if (defaultKey.isEmpty()) { + QString fileNames=urls.first().fileName(); + if (urls.count()>1) fileNames+=",..."; + popupPublic *dialogue=new popupPublic(0,"Public keys",fileNames,true,goDefaultKey); + connect(dialogue,SIGNAL(selectedKey(QStringList,QStringList,bool,bool)),this,SLOT(startencode(QStringList,QStringList,bool,bool))); + dialogue->exec(); + delete dialogue; + } else + startencode(defaultKey,opts,false,false); + } +} + +void KgpgLibrary::startencode(QStringList encryptKeys,QStringList encryptOptions,bool shred,bool symetric) +{ + popIsActive=false; + //KURL::List::iterator it; + //filesToEncode=urlselecteds.count(); + _encryptKeys=encryptKeys; + _encryptOptions=encryptOptions; + _shred=shred; + _symetric=symetric; + fastencode(urlselecteds.first(),encryptKeys,encryptOptions,symetric); +} + + +void KgpgLibrary::fastencode(KURL &fileToCrypt,QStringList selec,QStringList encryptOptions,bool symetric) +{ + ////////////////// encode from file + if ((selec.isEmpty()) && (!symetric)) { + KMessageBox::sorry(0,i18n("You have not chosen an encryption key.")); + return; + } + urlselected=fileToCrypt; + KURL dest; + if (encryptOptions.find("--armor")!=encryptOptions.end()) + dest.setPath(urlselected.path()+".asc"); + else + dest.setPath(urlselected.path()+extension); + + QFile fgpg(dest.path()); + + if (fgpg.exists()) { + KIO::RenameDlg *over=new KIO::RenameDlg(0,i18n("File Already Exists"),QString::null,dest.path(),KIO::M_OVERWRITE); + if (over->exec()==QDialog::Rejected) + { + delete over; + emit systemMessage(QString::null,true); + return; + } + dest=over->newDestURL(); + delete over; + } + int filesToEncode=urlselecteds.count(); + if (filesToEncode>1) + emit systemMessage(i18n("<b>%1 Files left.</b>\nEncrypting </b>%2").arg(filesToEncode).arg(urlselecteds.first().path())); + else emit systemMessage(i18n("<b>Encrypting </b>%2").arg(urlselecteds.first().path())); + KgpgInterface *cryptFileProcess=new KgpgInterface(); + pop = new KPassivePopup(panel); + cryptFileProcess->KgpgEncryptFile(selec,urlselected,dest,encryptOptions,symetric); + if (!popIsActive) + { + //connect(cryptFileProcess,SIGNAL(processstarted(QString)),this,SLOT(processpopup2(QString))); + popIsActive=true; + } + connect(cryptFileProcess,SIGNAL(encryptionfinished(KURL)),this,SLOT(processenc(KURL))); + connect(cryptFileProcess,SIGNAL(errormessage(QString)),this,SLOT(processencerror(QString))); +} + +void KgpgLibrary::processpopup2(QString fileName) +{ + + //pop->setTimeout(0); + pop->setView(i18n("Processing encryption (%1)").arg(fileName),i18n("Please wait..."),KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop)); + pop->show(); + /*QRect qRect(QApplication::desktop()->screenGeometry()); + int iXpos=qRect.width()/2-pop->width()/2; + int iYpos=qRect.height()/2-pop->height()/2; + pop->move(iXpos,iYpos);*/ + +} + +void KgpgLibrary::shredpreprocessenc(KURL fileToShred) +{ + popIsActive=false; + emit systemMessage(QString::null); + shredprocessenc(fileToShred); +} + +void KgpgLibrary::shredprocessenc(KURL::List filesToShred) +{ +emit systemMessage(i18n("Shredding %n file","Shredding %n files",filesToShred.count())); + +KIO::Job *job; +job = KIO::del( filesToShred, true ); +connect( job, SIGNAL( result( KIO::Job * ) ),SLOT( slotShredResult( KIO::Job * ) ) ); +} + +void KgpgLibrary::slotShredResult( KIO::Job * job ) +{ + emit systemMessage(QString::null); + if (job && job->error()) + { + job->showErrorDialog( (QWidget*)parent() ); + emit systemMessage(QString::null,true); + KPassivePopup::message(i18n("KGpg Error"),i18n("Process halted, not all files were shredded."),KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop),panel,"kgpg_error",0); + } +} + + +void KgpgLibrary::processenc(KURL) +{ + emit systemMessage(QString::null); + if (_shred) shredprocessenc(urlselecteds.first()); + urlselecteds.pop_front (); + if (urlselecteds.count()>0) + fastencode(urlselecteds.first(),_encryptKeys,_encryptOptions,_symetric); +} + +void KgpgLibrary::processencerror(QString mssge) +{ + popIsActive=false; + emit systemMessage(QString::null,true); + KMessageBox::detailedSorry(panel,i18n("<b>Process halted</b>.<br>Not all files were encrypted."),mssge); +} + + + +void KgpgLibrary::slotFileDec(KURL srcUrl,KURL destUrl,QStringList customDecryptOption) +{ + ////////////////////////////////////////////////////////////////// decode file from konqueror or menu + KgpgInterface *decryptFileProcess=new KgpgInterface(); + pop = new KPassivePopup(); + urlselected=srcUrl; + decryptFileProcess->KgpgDecryptFile(srcUrl,destUrl,customDecryptOption); + connect(decryptFileProcess,SIGNAL(processaborted(bool)),this,SLOT(processdecover())); + connect(decryptFileProcess,SIGNAL(processstarted(QString)),this,SLOT(processpopup(QString))); + connect(decryptFileProcess,SIGNAL(decryptionfinished()),this,SLOT(processdecover())); + connect(decryptFileProcess,SIGNAL(errormessage(QString)),this,SLOT(processdecerror(QString))); +} + +void KgpgLibrary::processpopup(QString fileName) +{ + emit systemMessage(i18n("Decrypting %1").arg(fileName)); + pop->setTimeout(0); + pop->setView(i18n("Processing decryption"),i18n("Please wait..."),KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop)); + pop->show(); + QRect qRect(QApplication::desktop()->screenGeometry()); + int iXpos=qRect.width()/2-pop->width()/2; + int iYpos=qRect.height()/2-pop->height()/2; + pop->move(iXpos,iYpos); +} + +void KgpgLibrary::processdecover() +{ + emit systemMessage(QString::null); + delete pop; + emit decryptionOver(); +} + + +void KgpgLibrary::processdecerror(QString mssge) +{ + delete pop; + emit systemMessage(QString::null); + ///// test if file is a public key + QFile qfile(QFile::encodeName(urlselected.path())); + if (qfile.open(IO_ReadOnly)) { + QTextStream t( &qfile ); + QString result(t.read()); + qfile.close(); + ////////////// if pgp data found, decode it + if (result.startsWith("-----BEGIN PGP PUBLIC KEY BLOCK")) {////// dropped file is a public key, ask for import + int result=KMessageBox::warningContinueCancel(0,i18n("<p>The file <b>%1</b> is a public key.<br>Do you want to import it ?</p>").arg(urlselected.path()),i18n("Warning")); + if (result==KMessageBox::Cancel) + return; + else { + KgpgInterface *importKeyProcess=new KgpgInterface(); + importKeyProcess->importKeyURL(urlselected); + connect(importKeyProcess,SIGNAL(importfinished(QStringList)),this,SIGNAL(importOver(QStringList))); + return; + } + } else if (result.startsWith("-----BEGIN PGP PRIVATE KEY BLOCK")) {////// dropped file is a public key, ask for import + qfile.close(); + KMessageBox::information(0,i18n("<p>The file <b>%1</b> is a private key block. Please use KGpg key manager to import it.</p>").arg(urlselected.path())); + return; + } + } + KMessageBox::detailedSorry(0,i18n("Decryption failed."),mssge); +} + + + +#include "kgpglibrary.moc" diff --git a/kgpg/kgpglibrary.h b/kgpg/kgpglibrary.h new file mode 100644 index 0000000..1892f5f --- /dev/null +++ b/kgpg/kgpglibrary.h @@ -0,0 +1,81 @@ +/*************************************************************************** + kgpglibrary.h - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef KGPGLIBRARY_H +#define KGPGLIBRARY_H + +#include <qobject.h> +#include <kurl.h> +#include <kshortcut.h> +#include <kio/job.h> + +class KPassivePopup; +class KProgress; + +class KgpgLibrary : public QObject +{ + + Q_OBJECT + +public: + /** + * Initialize the class + */ + KgpgLibrary(QWidget *parent=0,bool pgpExtension=false); + ~KgpgLibrary(); + + KURL::List urlselecteds; + +public slots: + void slotFileEnc(KURL::List urls=KURL(""),QStringList opts=QString::null,QStringList defaultKey=QString::null,KShortcut goDefaultKey=QKeySequence(CTRL+Qt::Key_Home)); + void slotFileDec(KURL srcUrl,KURL destUrl,QStringList customDecryptOption=QStringList()); + void shredprocessenc(KURL::List filesToShred); + +private slots: + void startencode(QStringList encryptKeys,QStringList encryptOptions,bool shred,bool symetric); + void fastencode(KURL &fileToCrypt,QStringList selec,QStringList encryptOptions,bool symetric); +// void startencode(QString &selec,QString encryptOptions,bool shred,bool symetric); + void slotShredResult( KIO::Job * job ); + void shredpreprocessenc(KURL fileToShred); + void processenc(KURL); + void processdecover(); + void processdecerror(QString mssge); + void processencerror(QString mssge); + void processpopup(QString fileName); + void processpopup2(QString fileName); + +private: + QString customDecrypt,tempFile,extension; + KURL urlselected; + KPassivePopup *pop; + KProgress *shredProgressBar; + bool popIsActive; + QWidget *panel; + QStringList _encryptKeys; + QStringList _encryptOptions; + bool _shred; + bool _symetric; + +signals: + void decryptionOver(); + void importOver(QStringList); + void systemMessage(QString,bool reset=false); +}; + +#endif // KGPGLIBRARY_H + diff --git a/kgpg/kgpgoptions.cpp b/kgpg/kgpgoptions.cpp new file mode 100644 index 0000000..a45e8a6 --- /dev/null +++ b/kgpg/kgpgoptions.cpp @@ -0,0 +1,601 @@ +/*************************************************************************** + kgpgoptions.cpp - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/////////////////////////////////////////////// code for the option dialog box + +#include <config.h> +#include <qlayout.h> +#include <qtabwidget.h> +#include <qlabel.h> +#include <qtoolbutton.h> +#include <qfile.h> +#include <kconfig.h> +#include <kdeversion.h> +#include <klocale.h> +#include <kprocio.h> +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qpushbutton.h> +#include <qfont.h> +#include <kaction.h> +#include <kmessagebox.h> +#include <klineedit.h> +#include <kcombobox.h> +#include <kurlrequester.h> +#include <kiconloader.h> +#include <kfiledialog.h> +#include <kinputdialog.h> +#include <kfontdialog.h> +#include <kdesktopfile.h> +#include <kstandarddirs.h> +#include <kcolorbutton.h> +#include <stdlib.h> +#include <kdebug.h> +#include <kactivelabel.h> + +#include "kgpgoptions.h" +#include "kgpgsettings.h" +#include "listkeys.h" + +#include "conf_decryption.h" +#include "conf_encryption.h" +#include "conf_gpg.h" +#include "conf_servers.h" +#include "conf_ui2.h" +#include "conf_misc.h" + +class QTabWidget; + +/////////////////////// main window + +kgpgOptions::kgpgOptions(QWidget *parent, const char *name) + : KConfigDialog( parent, name, KGpgSettings::self()) +{ + defaultServerList="hkp://wwwkeys.eu.pgp.net "; + defaultServerList+=i18n("(Default)"); + defaultServerList+=",hkp://search.keyserver.net,hkp://wwwkeys.pgp.net,hkp://pgp.dtype.org,hkp://wwwkeys.us.pgp.net"; + config = new KConfig ("kgpgrc"); + config->setGroup("Servers"); + serverList=QStringList::split (",",config->readEntry("Server_List",defaultServerList)); + keyServer = KgpgInterface::getGpgSetting("keyserver", KGpgSettings::gpgConfigPath()); + + if (!keyServer.isEmpty()) serverList.prepend(keyServer+" "+i18n("(Default)")); + + defaultHomePath=QDir::homeDirPath()+"/.gnupg/"; + if (QFile(defaultHomePath+"options").exists()) defaultConfigPath="options"; + else + { + if (QFile(defaultHomePath+"gpg.conf").exists()) defaultConfigPath="gpg.conf"; + else defaultConfigPath=QString::null; + } + +kdDebug(2100)<<"Adding pages"<<endl; + page1=new Encryption(); + page2=new Decryption(); + page3=new UIConf(); + page4=new GPGConf(); + page6=new ServerConf(); + page7=new MiscConf(); + QBoxLayout *fontLayout=new QBoxLayout(page3->tabWidget3->page(1),QBoxLayout::TopToBottom,10); + kfc=new KFontChooser(page3->tabWidget3->page(1),"kcfg_Font",false,QStringList(),false); + fontLayout->addWidget(kfc); + + page7->shredInfo->setText(i18n( "<qt><p>You must be aware that <b>shredding is not secure</b> on all file systems, and that parts of the file may have been saved in a temporary file or in the spooler of your printer if you previously opened it in an editor or tried to print it. Only works on files (not on folders).</p></qt>")); + page7->groupShred->adjustSize(); + pixkeySingle=KGlobal::iconLoader()->loadIcon("kgpg_key1",KIcon::Small,20); + pixkeyDouble=KGlobal::iconLoader()->loadIcon("kgpg_key2",KIcon::Small,20); + addPage(page1, i18n("Encryption"), "encrypted"); + addPage(page2, i18n("Decryption"), "decrypted"); + addPage(page3, i18n("Appearance"), "looknfeel"); + addPage(page4, i18n("GnuPG Settings"), "kgpg"); + addPage(page6, i18n("Key Servers"), "network"); + addPage(page7, i18n("Misc"), "misc"); + + page1->clear_akey->setIconSet(QIconSet(QPixmap(SmallIcon("clear_left")))); + page1->clear_fkey->setIconSet(QIconSet(QPixmap(SmallIcon("clear_left")))); + + // The following widgets are managed manually. + connect(page1->change_fkey, SIGNAL(clicked()), this, SLOT(insertFileKey())); + connect(page1->clear_fkey, SIGNAL(clicked()), page1->kcfg_FileKey, SLOT(clear())); + connect(page1->change_akey, SIGNAL(clicked()), this, SLOT(insertAlwaysKey())); + connect(page1->clear_akey, SIGNAL(clicked()), page1->alwaysKey, SLOT(clear())); + connect(page1->alwaysKey, SIGNAL(textChanged(const QString&)), this, SLOT(updateButtons())); + connect(page4->gpg_conf_path, SIGNAL(textChanged(const QString&)), this, SLOT(updateButtons())); + connect(page4->gpg_home_path, SIGNAL(textChanged(const QString&)), this, SLOT(updateButtons())); + connect(page4->use_agent, SIGNAL(toggled(bool)), this, SLOT(updateButtons())); + connect(page4->changeHome, SIGNAL(clicked()), this, SLOT(slotChangeHome())); + connect(page4->kcfg_PubKeyring, SIGNAL(toggled (bool)), page4->kcfg_PubKeyringUrl, SLOT(setEnabled(bool))); + connect(page4->kcfg_PubKeyring, SIGNAL(toggled (bool)), this, SLOT(checkAdditionalState(bool))); + connect(page4->kcfg_PrivKeyring, SIGNAL(toggled (bool)), page4->kcfg_PrivKeyringUrl, SLOT(setEnabled(bool))); + connect(page4->kcfg_PrivKeyring, SIGNAL(toggled (bool)), this, SLOT(checkAdditionalState(bool))); + connect(page6->server_add, SIGNAL(clicked()), this, SLOT(slotAddKeyServer())); + connect(page6->server_del, SIGNAL(clicked()), this, SLOT(slotDelKeyServer())); + connect(page6->server_default, SIGNAL(clicked()), this, SLOT(slotDefaultKeyServer())); + connect(page6->ServerBox, SIGNAL(currentChanged ( QListBoxItem *)), this, SLOT(updateButtons())); + connect(page7->pushShredder, SIGNAL(clicked ()), this, SIGNAL(installShredder())); + + //connect(this, SIGNAL(settingsChanged()), SLOT(updateSettings())); + + keyGood=KGpgSettings::colorGood(); + keyUnknown=KGpgSettings::colorUnknown(); + keyRev=KGpgSettings::colorRev(); + keyBad=KGpgSettings::colorBad(); +} + + +kgpgOptions::~kgpgOptions() +{ +delete config; +} + + +void kgpgOptions::checkAdditionalState(bool) +{ +// enable / disable the "use only this keyring" option depending on the other checkboxes state + +if (page4->kcfg_PubKeyring->isOn() && page4->kcfg_PrivKeyring->isOn()) +page4->kcfg_OnlyAdditional->setEnabled(true); +else +page4->kcfg_OnlyAdditional->setEnabled(false); +} + +void kgpgOptions::insertFileKey() +{ + QString signKeyID; + ///// open key selection dialog + KgpgSelKey *opts=new KgpgSelKey(this,0,true,page1->kcfg_FileKey->text()); + + if (opts->exec()==QDialog::Accepted) { + page1->kcfg_FileKey->setText(opts->getkeyID()); + } else { + delete opts; + return; + } + delete opts; +} + +void kgpgOptions::insertAlwaysKey() +{ + QString signKeyID; + ///// open key selection dialog + KgpgSelKey *opts=new KgpgSelKey(this,0,true,page1->alwaysKey->text()); + + if (opts->exec()==QDialog::Accepted) { + page1->alwaysKey->setText(opts->getkeyID()); + } else { + delete opts; + return; + } + delete opts; +} + +void kgpgOptions::slotChangeHome() +{ +QString gpgHome=KFileDialog::getExistingDirectory(page4->gpg_home_path->text(),this,i18n("New GnuPG Home Location")); +if (gpgHome.isEmpty()) return; +if (!gpgHome.endsWith("/")) gpgHome.append("/"); + QString confPath="options"; + if (!QFile(gpgHome+confPath).exists()) { + confPath="gpg.conf"; + if (!QFile(gpgHome+confPath).exists()) + { + if (KMessageBox::questionYesNo(this,i18n("No configuration file was found in the selected location.\nDo you want to create it now ?\n\nWithout configuration file, neither KGpg nor Gnupg will work properly."),i18n("No Configuration File Found"),i18n("Create"),i18n("Ignore"))==KMessageBox::Yes) ////////// Try to create config File by running gpg once + { + KProcIO *p=new KProcIO(); + *p<<"gpg"<<"--homedir"<<gpgHome<<"--no-tty"<<"--list-secret-keys"; + p->start(KProcess::Block); //// start gnupg so that it will create a config file + confPath="gpg.conf"; + QFile confFile(gpgHome+confPath); + if (!confFile.open(IO_WriteOnly)) + {KMessageBox::sorry(this,i18n("Cannot create configuration file. Please check if destination media is mounted and if you have write access")); + return; + } + else + { + QTextStream stream( &confFile ); + stream<<"# Config file created by KGpg\n\n"; + confFile.close(); + } + } + else confPath=QString::null; + } + } + page4->gpg_conf_path->setText(confPath); + page4->gpg_home_path->setText(gpgHome); +} + +void kgpgOptions::updateWidgets() +{ +QString pubKeyring,privKeyring; + + gpgConfigPath = KGpgSettings::gpgConfigPath(); + page4->gpg_conf_path->setText(KURL(gpgConfigPath).fileName()); + page4->gpg_home_path->setText(KURL(gpgConfigPath).directory(false)); + + pubKeyring=KgpgInterface::getGpgSetting("keyring", gpgConfigPath); + if (pubKeyring!="") + { + page4->kcfg_PubKeyringUrl->setURL(pubKeyring); + page4->kcfg_PubKeyring->setChecked(true); + } + else page4->kcfg_PubKeyring->setChecked(false); + + privKeyring=KgpgInterface::getGpgSetting("secret-keyring", gpgConfigPath); + if (privKeyring!="") + { + page4->kcfg_PrivKeyringUrl->setURL(privKeyring); + page4->kcfg_PrivKeyring->setChecked(true); + } + else page4->kcfg_PrivKeyring->setChecked(false); + + page4->kcfg_OnlyAdditional->setChecked(KgpgInterface::getGpgBoolSetting("no-default-keyring", gpgConfigPath)); + + // fill some values from kgpg's config file + + useAgent = KgpgInterface::getGpgBoolSetting("use-agent", gpgConfigPath); + defaultUseAgent = false; + + page1->alwaysKey->setText(KgpgInterface::getGpgMultiSetting("encrypt-to", gpgConfigPath)); + alwaysKeyID = page1->alwaysKey->text(); + + page4->use_agent->setChecked( useAgent ); + + keyServer = KgpgInterface::getGpgSetting("keyserver", gpgConfigPath); + defaultKeyServer = "hkp://wwwkeys.pgp.net"; + + if (keyServer.isEmpty()) + keyServer = defaultKeyServer; + + page6->ServerBox->clear(); + page6->ServerBox->insertStringList(serverList); + + + kdDebug(2100)<<"Finishing options"<<endl; +} + +void kgpgOptions::updateWidgetsDefault() +{ + + page1->alwaysKey->clear(); + page1->kcfg_FileKey->clear(); + + page4->use_agent->setChecked( defaultUseAgent ); + + page4->gpg_conf_path->setText(defaultConfigPath); + page4->gpg_home_path->setText(defaultHomePath); + + page4->kcfg_PubKeyringUrl->setURL(QString::null); + page4->kcfg_PubKeyring->setChecked(false); + page4->kcfg_PrivKeyringUrl->setURL(QString::null); + page4->kcfg_PrivKeyring->setChecked(false); + page4->kcfg_OnlyAdditional->setChecked(false); + + + page6->ServerBox->clear(); + page6->ServerBox->insertStringList(QStringList::split(",",defaultServerList)); + + kdDebug(2100)<<"Finishing default options"<<endl; +} + +bool kgpgOptions::isDefault() +{ + if (!page1->alwaysKey->text().isEmpty()) + return false; + + if (page4->gpg_conf_path->text()!=defaultConfigPath) + return false; + + if (page4->gpg_home_path->text()!=defaultHomePath) + return false; + + if (page4->use_agent->isChecked() != defaultUseAgent) + return false; + + QString currList; + for (uint i=0;i<page6->ServerBox->count();i++) + currList+=page6->ServerBox->text(i)+","; + currList.truncate(currList.length()-1); + if (currList!=defaultServerList) return false; + + return true; +} + +bool kgpgOptions::hasChanged() +{ + + if (page1->alwaysKey->text()!= alwaysKeyID) + return true; + + if (page4->gpg_conf_path->text() != KURL(gpgConfigPath).fileName()) + return true; + if (page4->gpg_home_path->text() != KURL(gpgConfigPath).directory(false)) + return true; + + if (page4->use_agent->isChecked() != useAgent) + return true; + + QStringList currList; + for (uint i=0;i<page6->ServerBox->count();i++) + currList.append(page6->ServerBox->text(i)); + if (currList!=serverList) return true; + + return false; +} + +void kgpgOptions::updateSettings() +{ + // Update config path first! + + KGpgSettings::setGpgConfigPath( page4->gpg_home_path->text()+page4->gpg_conf_path->text() ); + KGpgSettings::writeConfig(); //Don't forget to write the config file + if (page4->gpg_home_path->text()!=KURL(gpgConfigPath).directory(false)) + { + if (page4->gpg_home_path->text()!=defaultHomePath) + setenv("GNUPGHOME", QFile::encodeName(page4->gpg_home_path->text()), 1); + else setenv("GNUPGHOME","",1); + emit homeChanged(); + gpgConfigPath = KGpgSettings::gpgConfigPath(); + } + + bool emitReload=false; + + if (page4->kcfg_OnlyAdditional->isChecked()!=KgpgInterface::getGpgBoolSetting("no-default-keyring", gpgConfigPath)) emitReload=true; + KgpgInterface::setGpgBoolSetting("no-default-keyring",page4->kcfg_OnlyAdditional->isChecked(), gpgConfigPath); + + if (page4->kcfg_PubKeyring->isChecked()) + { + if (page4->kcfg_PubKeyringUrl->url()!=KgpgInterface::getGpgSetting("keyring", gpgConfigPath)) emitReload=true; + KgpgInterface::setGpgSetting("keyring",page4->kcfg_PubKeyringUrl->url(), gpgConfigPath); + } + else + { + if (KgpgInterface::getGpgSetting("keyring", gpgConfigPath)!="") emitReload=true; + KgpgInterface::setGpgSetting("keyring",QString::null, gpgConfigPath); + } + + if (page4->kcfg_PrivKeyring->isChecked()) + { + if (page4->kcfg_PrivKeyringUrl->url()!=KgpgInterface::getGpgSetting("secret-keyring", gpgConfigPath)) emitReload=true; + KgpgInterface::setGpgSetting("secret-keyring",page4->kcfg_PrivKeyringUrl->url(), gpgConfigPath); + } + else + { + if (KgpgInterface::getGpgSetting("secret-keyring", gpgConfigPath)!="") emitReload=true; + KgpgInterface::setGpgSetting("secret-keyring",QString::null, gpgConfigPath); + } + + emit changeFont(kfc->font()); + /////////////// install service menus + + if (page7->kcfg_SignMenu->currentItem()==KGpgSettings::EnumSignMenu::AllFiles) + slotInstallSign("all/allfiles"); + else + slotRemoveMenu("signfile.desktop"); + if (page7->kcfg_DecryptMenu->currentItem()==KGpgSettings::EnumDecryptMenu::AllFiles) + slotInstallDecrypt("all/allfiles"); + else if (page7->kcfg_DecryptMenu->currentItem()==KGpgSettings::EnumDecryptMenu::EncryptedFiles) + slotInstallDecrypt("application/pgp-encrypted,application/pgp-signature,application/pgp-keys"); + else + slotRemoveMenu("decryptfile.desktop"); + + KgpgInterface::setGpgMultiSetting("encrypt-to",QStringList::split(" ",page1->alwaysKey->text()),KGpgSettings::gpgConfigPath()); + alwaysKeyID = page1->alwaysKey->text(); + + useAgent = page4->use_agent->isChecked(); + + if (useAgent) + { + KgpgInterface::setGpgBoolSetting("use-agent",true, KGpgSettings::gpgConfigPath()); + KgpgInterface::setGpgBoolSetting("no-use-agent",false, KGpgSettings::gpgConfigPath()); + } + else + { + // KgpgInterface::setGpgBoolSetting("no-use-agent",true, KGpgSettings::gpgConfigPath()); + KgpgInterface::setGpgBoolSetting("use-agent",false, KGpgSettings::gpgConfigPath()); + } + + ////////////////// save key servers + + + QString currList; + serverList=QStringList (); + for (uint i=0;i<page6->ServerBox->count();i++) + { + QString currItem=page6->ServerBox->text(i); + if (currItem.find(" ")!=-1) // it is the default keyserver + keyServer=currItem.section(" ",0,0); + else + { + serverList.append(currItem); + } + } + + KgpgInterface::setGpgSetting("keyserver",keyServer, KGpgSettings::gpgConfigPath()); + serverList.prepend(keyServer+" "+i18n("(Default)")); + currList=serverList.join(","); + + if (keyGood!=page3->kcfg_ColorGood->color()) + emit refreshTrust(GoodColor,page3->kcfg_ColorGood->color()); + if (keyBad!=page3->kcfg_ColorBad->color()) emit refreshTrust(BadColor,page3->kcfg_ColorBad->color()); + if (keyUnknown!=page3->kcfg_ColorUnknown->color()) emit refreshTrust(UnknownColor,page3->kcfg_ColorUnknown->color()); + if (keyRev!=page3->kcfg_ColorRev->color()) emit refreshTrust(RevColor,page3->kcfg_ColorRev->color()); + + +// KGpgSettings::writeConfig(); + config->setGroup("Servers"); + config->writeEntry("Server_List",currList); + emit settingsUpdated(); + if (emitReload) emit reloadKeyList(); +} + + +void kgpgOptions::slotInstallSign(QString mimetype) +{ + + QString path=locateLocal("data","konqueror/servicemenus/signfile.desktop"); + KDesktopFile configl2(path, false); + if (configl2.isImmutable() ==false) { + configl2.setGroup("Desktop Entry"); + configl2.writeEntry("ServiceTypes", mimetype); + configl2.writeEntry("Actions", "sign"); + configl2.setGroup("Desktop Action sign"); + configl2.writeEntry("Name",i18n("Sign File")); + //configl2.writeEntry("Icon", "sign_file"); + configl2.writeEntry("Exec","kgpg -S %F"); + //KMessageBox::information(this,i18n("Decrypt file option is now added in Konqueror's menu.")); + } +} + +void kgpgOptions::slotInstallDecrypt(QString mimetype) +{ + + QString path=locateLocal("data","konqueror/servicemenus/decryptfile.desktop"); + KDesktopFile configl2(path, false); + if (configl2.isImmutable() ==false) { + configl2.setGroup("Desktop Entry"); + configl2.writeEntry("ServiceTypes", mimetype); + configl2.writeEntry("Actions", "decrypt"); + configl2.setGroup("Desktop Action decrypt"); + configl2.writeEntry("Name",i18n("Decrypt File")); + //configl2.writeEntry("Icon", "decrypt_file"); + configl2.writeEntry("Exec","kgpg %U"); + //KMessageBox::information(this,i18n("Decrypt file option is now added in Konqueror's menu.")); + } +} + + +void kgpgOptions::slotRemoveMenu(QString menu) +{ + + QString path=locateLocal("data","konqueror/servicemenus/"+menu); + QFile qfile(path); + if (qfile.exists()) + qfile.remove(); + { + //if (!qfile.remove()) KMessageBox::sorry(this,i18n("Cannot remove service menu. Check permissions")); + //else KMessageBox::information(this,i18n("Service menu 'Decrypt File' has been removed.")); + } + //else KMessageBox::sorry(this,i18n("No service menu found")); + +} + +QString kgpgOptions::namecode(QString kid) +{ + + for ( uint counter = 0; counter<names.count(); counter++ ) + if (QString(ids[counter].right(8))==kid) + return names[counter]; + + return QString::null; +} + + +QString kgpgOptions::idcode(QString kname) +{ + for ( uint counter = 0; counter<names.count(); counter++ ) + if (names[counter]==kname) + return QString(ids[counter].right(8)); + return QString::null; +} + + +void kgpgOptions::listkey() +{ + + //////// update display of keys in main management window + FILE *fp; + QString tst,name,trustedvals="idre-",issec; + int counter=0; + char line[300]; + + FILE *fp2; + + fp2 = popen("gpg --no-secmem-warning --no-tty --with-colon --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp2)) { + QString lineRead=line; + if (lineRead.startsWith("sec")) + issec+=lineRead.section(':',4,4); + } + pclose(fp2); + + + fp = popen("gpg --no-tty --with-colon --list-keys", "r"); + while ( fgets( line, sizeof(line), fp)) { + tst=line; + if (tst.startsWith("pub")) { + name=KgpgInterface::checkForUtf8(tst.section(':',9,9)); + if ((!name.isEmpty()) && (trustedvals.find(tst.section(':',1,1))==-1)) { + counter++; + //name=name.section('<',-1,-1); + // name=name.section('>',0,0); + names+=name; + ids+=tst.section(':',4,4); + if (tst.section(':',4,4).right(8)==alwaysKeyID) + alwaysKeyName=tst.section(':',4,4).right(8)+":"+name; + if (issec.find(tst.section(':',4,4).right(8),0,FALSE)!=-1) + { +//*** page1->file_key->insertItem(pixkeyDouble,tst.section(':',4,4).right(8)+":"+name); +//*** page1->always_key->insertItem(pixkeyDouble,tst.section(':',4,4).right(8)+":"+name); + } + else + { +//*** page1->file_key->insertItem(pixkeySingle,tst.section(':',4,4).right(8)+":"+name); +//*** page1->always_key->insertItem(pixkeySingle,tst.section(':',4,4).right(8)+":"+name); + } + } + } + } + pclose(fp); + if (counter==0) { + ids+="0"; +//*** page1->file_key->insertItem(i18n("none")); +//*** page1->always_key->insertItem(i18n("none")); + } +} + +void kgpgOptions::slotAddKeyServer() +{ +QString newServer=KInputDialog::getText(i18n("Add New Key Server"),i18n("Server URL:")); +if (!newServer.isEmpty()) +page6->ServerBox->insertItem(newServer.stripWhiteSpace()); +page6->ServerBox->setSelected(page6->ServerBox->findItem(newServer.stripWhiteSpace()),true); +} + +void kgpgOptions::slotDelKeyServer() +{ +bool defaultDeleted=false; +if (page6->ServerBox->currentText().find(" ")!=-1) defaultDeleted=true; +page6->ServerBox->removeItem(page6->ServerBox->currentItem()); +page6->ServerBox->setSelected(0,true); +if (defaultDeleted) page6->ServerBox->changeItem(page6->ServerBox->currentText().section(" ",0,0)+" "+i18n("(Default)"),0); +} + +void kgpgOptions::slotDefaultKeyServer() +{ +uint curr=page6->ServerBox->currentItem(); +page6->ServerBox->changeItem(page6->ServerBox->currentText ().section(" ",0,0)+" "+i18n("(Default)"),curr); + +for (uint i=0;i<page6->ServerBox->count();i++) +{ +if (i!=curr) +page6->ServerBox->changeItem(page6->ServerBox->text(i).section(" ",0,0),i); +} +page6->ServerBox->setSelected(curr,true); +} + +#include "kgpgoptions.moc" + diff --git a/kgpg/kgpgoptions.h b/kgpg/kgpgoptions.h new file mode 100644 index 0000000..05a7b32 --- /dev/null +++ b/kgpg/kgpgoptions.h @@ -0,0 +1,106 @@ +/*************************************************************************** + kgpgoptions.h - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef KGPGOPTIONS_H +#define KGPGOPTIONS_H + +#include <kconfigdialog.h> + +#define GoodColor 0 +#define BadColor 1 +#define UnknownColor 2 +#define RevColor 3 + +class KConfig; +class Encryption; +class Decryption; +class UIConf; +class GPGConf; +class ServerConf; +class ColorsConf; +class MiscConf; +class KFontChooser; +class KConfig; +class KSimpleConfig; + +class kgpgOptions : public KConfigDialog +{ + Q_OBJECT +public: + kgpgOptions(QWidget *parent=0, const char *name=0); + ~kgpgOptions(); + QStringList names,ids; + Encryption *page1; + Decryption *page2; + UIConf *page3; + GPGConf *page4; + ServerConf *page6; + MiscConf *page7; + KFontChooser *kfc; + +private: + KConfig *config; + QString alwaysKeyID,alwaysKeyName; + bool firstDisplay; + + QPixmap pixkeySingle,pixkeyDouble; + QString fileEncryptionKey; + QString gpgConfigPath; + QString keyServer,defaultServerList; + QString defaultKeyServer; + QFont startFont; + bool useAgent; + bool defaultUseAgent; + bool encryptToAlways; + bool defaultEncryptToAlways; + QStringList serverList; + QString defaultConfigPath,defaultHomePath; + QColor keyGood,keyBad,keyUnknown,keyRev; + +private: + bool hasChanged(); + bool isDefault(); + +private slots: + void checkAdditionalState(bool); + void slotAddKeyServer(); + void slotDelKeyServer(); + void slotDefaultKeyServer(); + void updateWidgets(); + void updateWidgetsDefault(); + void updateSettings(); + void insertAlwaysKey(); + void insertFileKey(); + + void listkey(); + QString namecode(QString kid); + QString idcode(QString kname); + void slotInstallDecrypt(QString mimetype); + void slotInstallSign(QString mimetype); + void slotRemoveMenu(QString menu); + void slotChangeHome(); +signals: + void updateDisplay(); + void settingsUpdated(); + void changeFont(QFont); + void homeChanged(); + void refreshTrust(int, QColor); + void installShredder(); + void reloadKeyList(); +}; + +#endif // KGPGOPTIONS_H + diff --git a/kgpg/kgpgrevokewidget.ui b/kgpg/kgpgrevokewidget.ui new file mode 100644 index 0000000..0884276 --- /dev/null +++ b/kgpg/kgpgrevokewidget.ui @@ -0,0 +1,152 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>KgpgRevokeWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KgpgRevokeWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>459</width> + <height>230</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>keyID</cstring> + </property> + <property name="text"> + <string>key id</string> + </property> + <property name="alignment"> + <set>AlignVCenter</set> + </property> + </widget> + <widget class="QCheckBox" row="5" column="0"> + <property name="name"> + <cstring>cbPrint</cstring> + </property> + <property name="text"> + <string>Print certificate</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Create revocation certificate for</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Description:</string> + </property> + </widget> + <widget class="QComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>No Reason</string> + </property> + </item> + <item> + <property name="text"> + <string>Key Has Been Compromised</string> + </property> + </item> + <item> + <property name="text"> + <string>Key is Superseded</string> + </property> + </item> + <item> + <property name="text"> + <string>Key is No Longer Used</string> + </property> + </item> + <property name="name"> + <cstring>comboBox1</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Reason for revocation:</string> + </property> + </widget> + <widget class="QCheckBox" row="4" column="0"> + <property name="name"> + <cstring>cbSave</cstring> + </property> + <property name="text"> + <string>Save certificate:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" row="7" column="0"> + <property name="name"> + <cstring>cbImport</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Import into keyring</string> + </property> + </widget> + <widget class="QTextEdit" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textDescription</cstring> + </property> + </widget> + <widget class="KURLRequester" row="4" column="1"> + <property name="name"> + <cstring>kURLRequester1</cstring> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>cbSave</sender> + <signal>toggled(bool)</signal> + <receiver>KgpgRevokeWidget</receiver> + <slot>cbSave_toggled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>comboBox1</tabstop> + <tabstop>textDescription</tabstop> + <tabstop>cbSave</tabstop> + <tabstop>cbPrint</tabstop> + <tabstop>cbImport</tabstop> + <tabstop>kURLRequester1</tabstop> +</tabstops> +<includes> + <include location="local" impldecl="in implementation">kgpgrevokewidget.ui.h</include> +</includes> +<slots> + <slot>cbSave_toggled( bool isOn )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kgpg/kgpgrevokewidget.ui.h b/kgpg/kgpgrevokewidget.ui.h new file mode 100644 index 0000000..6d13319 --- /dev/null +++ b/kgpg/kgpgrevokewidget.ui.h @@ -0,0 +1,21 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ +//(C) 2002 Jean-Baptiste Mardelle <bj@altern.org> + +void KgpgRevokeWidget::cbSave_toggled( bool isOn) +{ +kURLRequester1->setEnabled(isOn); +} diff --git a/kgpg/kgpgsettings.kcfgc b/kgpg/kgpgsettings.kcfgc new file mode 100644 index 0000000..afbe628 --- /dev/null +++ b/kgpg/kgpgsettings.kcfgc @@ -0,0 +1,9 @@ +# Code generation options for kconfig_compiler +File=kgpg.kcfg +ClassName=KGpgSettings +Singleton=true +Mutators=true +# Inherits=KConfigSkeleton +IncludeFiles=kgpginterface.h +# MemberVariables=public +CustomAdditions=true
\ No newline at end of file diff --git a/kgpg/kgpgsettings_addons.h b/kgpg/kgpgsettings_addons.h new file mode 100644 index 0000000..6b2e8f5 --- /dev/null +++ b/kgpg/kgpgsettings_addons.h @@ -0,0 +1,41 @@ +/*************************************************************************** + kgpgsettings_addons.h - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2003Waldo Bastian + email : bastian@kde.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +public: + static + QString defaultKey() + { + if (self()->mDefaultKey.isEmpty()) + { + self()->mDefaultKey = KgpgInterface::getGpgSetting("default-key", gpgConfigPath()); + if (!self()->mDefaultKey.isEmpty()) + self()->mDefaultKey.prepend("0x"); + } + return self()->mDefaultKey; + } + + static + void setDefaultKey(const QString &_defaultKey) + { + self()->mDefaultKey = _defaultKey; + KgpgInterface::setGpgSetting("default-key",_defaultKey.right(8),gpgConfigPath()); + if (!_defaultKey.startsWith("0x")) + self()->mDefaultKey.prepend("0x"); + } + +private: + QString mDefaultKey; diff --git a/kgpg/kgpgview.cpp b/kgpg/kgpgview.cpp new file mode 100644 index 0000000..c9bff6a --- /dev/null +++ b/kgpg/kgpgview.cpp @@ -0,0 +1,409 @@ +/*************************************************************************** + kgpgview.cpp - description + ------------------- + begin : Tue Jul 2 12:31:38 GMT 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +////////////////////////////////////////////////////////////// code for the main view (editor) + +// include files for Qt +//#include <qprinter.h> + +// application specific includes + +#include <qscrollview.h> +#include <qregexp.h> + +#include <kio/netaccess.h> +#include <klocale.h> +#include <kstdaction.h> +#include <kurldrag.h> + +#include <kmessagebox.h> +#include <qfile.h> +#include <qlayout.h> +#include <kbuttonbox.h> +#include <unistd.h> +#include <kaction.h> +#include <klineedit.h> +#include <qtextcodec.h> + + +#include "kgpgsettings.h" +#include "kgpginterface.h" +#include "kgpgview.h" +#include "keyservers.h" +#include "keyserver.h" +#include "kgpg.h" +#include "kgpgeditor.h" +#include "listkeys.h" +#include "popuppublic.h" +#include "detailedconsole.h" + +//////////////// configuration for editor + +MyEditor::MyEditor( QWidget *parent, const char *name ) + : KTextEdit( parent, name ) +{ + setTextFormat(PlainText); + setCheckSpellingEnabled (true); + setAcceptDrops(true); +} + +void MyEditor::contentsDragEnterEvent( QDragEnterEvent *e ) +{ + //////////////// if a file is dragged into editor ... + e->accept (KURLDrag::canDecode(e) || QTextDrag::canDecode (e)); + //e->accept (QTextDrag::canDecode (e)); +} + + + + +void MyEditor::contentsDropEvent( QDropEvent *e ) +{ + ///////////////// decode dropped file + KURL::List list; + QString text; + if ( KURLDrag::decode( e, list ) ) + slotDroppedFile(list.first()); + else if ( QTextDrag::decode(e, text) ) + insert(text); +} + +void MyEditor::slotDroppedFile(KURL url) +{ + ///////////////// decide what to do with dropped file + QString text; + if (!tempFile.isEmpty()) { + KIO::NetAccess::removeTempFile(tempFile); + tempFile=QString::null; + } + + if (url.isLocalFile()) + tempFile = url.path(); + else { + if (KMessageBox::warningContinueCancel(0,i18n("<qt><b>Remote file dropped</b>.<br>The remote file will now be copied to a temporary file to process requested operation. This temporary file will be deleted after operation.</qt>"),0,KStdGuiItem::cont(),"RemoteFileWarning")!=KMessageBox::Continue) + return; + if (!KIO::NetAccess::download (url, tempFile,this)) { + KMessageBox::sorry(this,i18n("Could not download file.")); + return; + } + } + + + ///////////// if dropped filename ends with gpg, pgp or asc, try to decode it + if ((tempFile.endsWith(".gpg")) || (tempFile.endsWith(".asc")) || (tempFile.endsWith(".pgp"))) { + slotDecodeFile(tempFile); + } + else slotCheckContent(tempFile); +} + + +bool MyEditor::slotCheckContent(QString fileToCheck, bool checkForPgpMessage) +{ +QFile qfile(fileToCheck); + if (qfile.open(IO_ReadOnly)) { + ////////// open file + + QTextStream t( &qfile ); + QString result(t.read()); + ////////////// if pgp data found, decode it + if ((checkForPgpMessage) && (result.startsWith("-----BEGIN PGP MESSAGE"))) { + qfile.close(); + slotDecodeFile(fileToCheck); + return true; + } else + if (result.startsWith("-----BEGIN PGP PUBLIC KEY BLOCK")) {////// dropped file is a public key, ask for import + qfile.close(); + int result=KMessageBox::warningContinueCancel(this,i18n("<p>The file <b>%1</b> is a public key.<br>Do you want to import it ?</p>").arg(fileToCheck),i18n("Warning")); + if (result==KMessageBox::Cancel) { + KIO::NetAccess::removeTempFile(fileToCheck); + return true; + } else { + KgpgInterface *importKeyProcess=new KgpgInterface(); + importKeyProcess->importKeyURL(KURL(fileToCheck)); + connect(importKeyProcess,SIGNAL(importfinished(QStringList)),this,SLOT(slotProcessResult(QStringList))); + return true; + } + } else { + if (result.startsWith("-----BEGIN PGP PRIVATE KEY BLOCK")) { + qfile.close(); + KMessageBox::information(0,i18n("This file is a private key.\nPlease use kgpg key management to import it.")); + KIO::NetAccess::removeTempFile(fileToCheck); + return true; + } + + setText(result); + qfile.close(); + KIO::NetAccess::removeTempFile(fileToCheck); + } + } + return false; +} + + +void MyEditor::editorUpdateDecryptedtxt(QString newtxt) +{ + setText(newtxt); +} + +void MyEditor::editorFailedDecryptedtxt(QString newtxt) +{ + if (!slotCheckContent(tempFile,false)) + KMessageBox::detailedSorry(this,i18n("Decryption failed."),newtxt); +} + + +void MyEditor::slotDecodeFile(QString fname) +{ + //////////////// decode file from given url into editor + QFile qfile(QFile::encodeName(fname)); + if (qfile.open(IO_ReadOnly)) { + KgpgInterface *txtDecrypt=new KgpgInterface(); + connect (txtDecrypt,SIGNAL(txtdecryptionfinished(QString)),this,SLOT(editorUpdateDecryptedtxt(QString))); + connect (txtDecrypt,SIGNAL(txtdecryptionfailed(QString)),this,SLOT(editorFailedDecryptedtxt(QString))); + txtDecrypt->KgpgDecryptFileToText(KURL(fname),QStringList::split(QString(" "),KGpgSettings::customDecrypt().simplifyWhiteSpace())); + } else + KMessageBox::sorry(this,i18n("Unable to read file.")); +} + + +void MyEditor::slotProcessResult(QStringList iKeys) +{ + emit refreshImported(iKeys); + KIO::NetAccess::removeTempFile(tempFile); + tempFile=QString::null; +} + + +////////////////////////// main view configuration + +KgpgView::KgpgView(QWidget *parent, const char *name) : QWidget(parent, name) +{ + editor=new MyEditor(this); + windowAutoClose=true; + + ///// layout + + QVBoxLayout *vbox=new QVBoxLayout(this,3); + + editor->setReadOnly( false ); + editor->setUndoRedoEnabled(true); + editor->setUndoDepth(5); + + setAcceptDrops(true); + + KButtonBox *boutonbox=new KButtonBox(this,KButtonBox::Horizontal,15,12); + boutonbox->addStretch(1); + + bouton0=boutonbox->addButton(i18n("S&ign/Verify"),this,SLOT(clearSign()),TRUE); + bouton1=boutonbox->addButton(i18n("En&crypt"),this,SLOT(popuppublic()),TRUE); + bouton2=boutonbox->addButton(i18n("&Decrypt"),this,SLOT(slotdecode()),TRUE); + + QObject::connect(editor,SIGNAL(textChanged()),this,SLOT(modified())); + + boutonbox->layout(); + editor->resize(editor->maximumSize()); + vbox->addWidget(editor); + vbox->addWidget(boutonbox); +} + + +void KgpgView::modified() +{ + /////////////// notify for changes in editor window + KgpgApp *win=(KgpgApp *) parent(); + if (win->fileSave->isEnabled()==false) { + QString capt=win->Docname.fileName(); + if (capt.isEmpty()) + capt=i18n("untitled"); + win->setCaption(capt,true); + win->fileSave->setEnabled(true); + win->editUndo->setEnabled(true); + } + +} + +void KgpgView::slotAskForImport(QString ID) +{ +if (KMessageBox::questionYesNo(0,i18n("<qt><b>Missing signature:</b><br>Key id: %1<br><br>" + "Do you want to import this key from a keyserver?</qt>").arg(ID),i18n("Missing Key"), QString::null, i18n("Import"), i18n("Do Not Import"))==KMessageBox::Yes) { + keyServer *kser=new keyServer(0,"server_dialog",false,true); + kser->page->kLEimportid->setText(ID); + kser->slotImport(); + windowAutoClose=false; + } + else emit verifyFinished(); +} + +void KgpgView::slotVerifyResult(QString mssge,QString log) +{ +emit verifyFinished(); +//KMessageBox::information(0,mssge); +(void) new KDetailedInfo(0,"verify_result",mssge,log); +} + +void KgpgView::clearSign() +{ + QString mess=editor->text(); + if (mess.startsWith("-----BEGIN PGP SIGNED")) { + ////////////////////// this is a signed message, verify it + KgpgInterface *verifyProcess=new KgpgInterface(); + connect(verifyProcess,SIGNAL(missingSignature(QString)),this,SLOT(slotAskForImport(QString))); + connect(verifyProcess,SIGNAL(verifyOver(QString,QString)),this,SLOT(slotVerifyResult(QString,QString))); + verifyProcess->KgpgVerifyText(mess); + } + else { + ///// Sign the text in Editor + QString signKeyID; + ///// open key selection dialog + KgpgSelKey *opts=new KgpgSelKey(this,0); + + if (opts->exec()==QDialog::Accepted) { + signKeyID=opts->getkeyID(); + } else { + delete opts; + return; + } + delete opts; + + KgpgInterface *signProcess=new KgpgInterface(); + connect(signProcess,SIGNAL(txtSignOver(QString)),this,SLOT(slotSignResult(QString))); + QStringList options=NULL; + if (KGpgSettings::pgpCompatibility()) + options<<"--pgp6"; + signProcess->KgpgSignText(mess,signKeyID,options); +} +} + + +void KgpgView::slotSignResult(QString signResult) +{ +if (signResult.isEmpty()) +KMessageBox::sorry(this,i18n("Signing not possible: bad passphrase or missing key")); +else +{ + editor->setText(signResult); + emit resetEncoding(false); + + KgpgApp *win=(KgpgApp *) parent(); + win->editRedo->setEnabled(false); + win->editUndo->setEnabled(false); +} +} + + + +void KgpgView::popuppublic() +{ + ///// popup dialog to select public key for encryption + + //////// open dialog --> popuppublic.cpp + popupPublic *dialogue=new popupPublic(this, "public_keys", 0,false,((KgpgApp *) parent())->goDefaultKey); + connect(dialogue,SIGNAL(selectedKey(QStringList,QStringList,bool,bool)),this,SLOT(encodetxt(QStringList,QStringList,bool,bool))); + dialogue->exec(); + delete dialogue; +} + + +////////////////////////////////////////////////////////////////////////////////////// decode + +void KgpgView::slotdecode() +{ + /////////////// decode data from the editor. triggered by the decode button + + QString dests,encUsers; + messages=QString::null; + + //QString resultat=KgpgInterface::KgpgDecryptText(editor->text(),encUsers); + KgpgInterface *txtDecrypt=new KgpgInterface(); + connect (txtDecrypt,SIGNAL(txtdecryptionfinished(QString)),this,SLOT(updateDecryptedtxt(QString))); + connect (txtDecrypt,SIGNAL(txtdecryptionfailed(QString)),this,SLOT(failedDecryptedtxt(QString))); + txtDecrypt->KgpgDecryptText(editor->text(),QStringList::split(QString(" "),KGpgSettings::customDecrypt().simplifyWhiteSpace())); + + /* + KgpgApp *win=(KgpgApp *) parent(); + if (!resultat.isEmpty()) { + editor->setText(resultat); + win->editRedo->setEnabled(false); + win->editUndo->setEnabled(false); + }*/ +} + +void KgpgView::updateDecryptedtxt(QString newtxt) +{ + //kdDebug(2100)<<"UTF8 Test Result--------------"<<KgpgView::checkForUtf8()<<endl; + editor->setText(newtxt); + emit resetEncoding(false); +} + +bool KgpgView::checkForUtf8(QString text) +{ //// try to guess if the decrypted text uses utf-8 encoding + QTextCodec *codec =QTextCodec::codecForLocale (); + if (codec->canEncode(text)) return true; + return false; +} + +void KgpgView::failedDecryptedtxt(QString newtxt) +{ + KMessageBox::detailedSorry(this,i18n("Decryption failed."),newtxt); +} + + +void KgpgView::encodetxt(QStringList selec,QStringList encryptOptions,bool, bool symmetric) +{ + ////////////////// encode from editor + if (KGpgSettings::pgpCompatibility()) + encryptOptions<<"--pgp6"; + + if (symmetric) selec.clear(); + + KgpgInterface *txtCrypt=new KgpgInterface(); + connect (txtCrypt,SIGNAL(txtencryptionfinished(QString)),this,SLOT(updatetxt(QString))); + txtCrypt->KgpgEncryptText(editor->text(),selec,encryptOptions); + //KMessageBox::sorry(0,"OVER"); + + //KgpgInterface::KgpgEncryptText(editor->text(),selec,encryptOptions); + //if (!resultat.isEmpty()) editor->setText(resultat); + //else KMessageBox::sorry(this,i18n("Decryption failed.")); +} + +void KgpgView::updatetxt(QString newtxt) +{ + if (!newtxt.isEmpty()) + editor->setText(newtxt); + else + KMessageBox::sorry(this,i18n("Encryption failed.")); +} + + +KgpgView::~KgpgView() +{ +delete editor; +} + +/* +void KgpgView::print(QPrinter *pPrinter) +{ + QPainter printpainter; + printpainter.begin(pPrinter); + + // TODO: add your printing code here + + printpainter.end(); +} +*/ +#include "kgpgview.moc" + diff --git a/kgpg/kgpgview.h b/kgpg/kgpgview.h new file mode 100644 index 0000000..d6183bb --- /dev/null +++ b/kgpg/kgpgview.h @@ -0,0 +1,121 @@ +/************************************************************************** + kgpgview.h - description + ------------------- + begin : Tue Jul 2 12:31:38 GMT 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef KGPGVIEW_H +#define KGPGVIEW_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <ktextedit.h> +#include <kurl.h> + +class QDragEnterEvent; + +//class KgpgDoc; + +/** The KgpgView class provides the view widget for the KgpgApp instance. + * The View instance inherits QWidget as a base class and represents the view object of a KTMainWindow. As KgpgView is part of the + * docuement-view model, it needs a reference to the document object connected with it by the KgpgApp class to manipulate and display + * the document structure provided by the KgpgDoc class. + * + * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team. + * @version KDevelop version 0.4 code generation + */ + +class MyEditor : public KTextEdit +{ + Q_OBJECT + +public: + MyEditor( QWidget *parent = 0, const char *name = 0); +private: + QString message,messages,tempFile; +public slots: + void slotDecodeFile(QString); + void slotDroppedFile(KURL url); + void slotProcessResult(QStringList iKeys); + bool slotCheckContent(QString fileToCheck, bool checkForPgpMessage=true); + +protected: + void contentsDragEnterEvent( QDragEnterEvent *e ); + void contentsDropEvent( QDropEvent *e ); + +private slots: + void editorUpdateDecryptedtxt(QString newtxt); + void editorFailedDecryptedtxt(QString newtxt); + +signals: + void refreshImported(QStringList); +}; + + +class KgpgView : public QWidget +{ + Q_OBJECT + friend class MyEditor; +public: + /** Constructor for the main view */ + KgpgView(QWidget *parent = 0, const char *name=0); + /** Destructor for the main view */ + ~KgpgView(); + + /** returns a pointer to the document connected to the view instance. Mind that this method requires a KgpgApp instance as a parent + * widget to get to the window document pointer by calling the KgpgApp::getDocument() method. + * + * @see KgpgApp#getDocument + */ + // KgpgDoc *getDocument() const; + + // QTextEdit *editor; + + MyEditor *editor; + KURL fselected; + bool windowAutoClose; + + /** contains the implementation for printing functionality */ + // void print(QPrinter *pPrinter); + + QPushButton *bouton1,*bouton2,*bouton0; +private: + QString messages; + +public slots: + void slotdecode(); + void clearSign(); + +private slots: + void slotVerifyResult(QString mssge,QString log); + void slotSignResult(QString signResult); + void slotAskForImport(QString ID); + void popuppublic(); + void modified(); + void encodetxt(QStringList selec,QStringList encryptOptions,bool, bool symmetric); + void updatetxt(QString); + void updateDecryptedtxt(QString newtxt); + void failedDecryptedtxt(QString newtxt); + bool checkForUtf8(QString text); + +signals: + void resetEncoding(bool); + void verifyFinished(); + void verifyDetach(); +}; + +#endif // KGPGVIEW_H + diff --git a/kgpg/kgpgwizard.ui b/kgpg/kgpgwizard.ui new file mode 100644 index 0000000..36d1501 --- /dev/null +++ b/kgpg/kgpgwizard.ui @@ -0,0 +1,405 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KgpgWizard</class> +<widget class="QWizard"> + <property name="name"> + <cstring>KgpgWizard</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>559</width> + <height>356</height> + </rect> + </property> + <property name="caption"> + <string>KGpg Wizard</string> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>page</cstring> + </property> + <attribute name="title"> + <string>Introduction</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0" rowspan="3" colspan="1"> + <property name="name"> + <cstring>pixmapLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="pixmap"> + <pixmap>image0</pixmap> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string><h1>Welcome to the KGpg Wizard</h1> +This wizard will first setup some basic configuration options required for KGpg to work properly. Next, it will allow you to create your own key pair, enabling you to encrypt your files and emails.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer17</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>41</height> + </size> + </property> + </spacer> + <widget class="KActiveLabel" row="1" column="1"> + <property name="name"> + <cstring>txtGpgVersion</cstring> + </property> + <property name="text"> + <string>You have GnuPG version:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>page</cstring> + </property> + <attribute name="title"> + <string>Step One: Communication with GnuPG</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>text_optionsfound</cstring> + </property> + <property name="text"> + <string>Unless you want to try some unusual settings, just click on the "next" button.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <widget class="QLabel" row="0" column="1"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>KGpg needs to know where your GnuPG configuration file is stored.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <spacer row="4" column="1"> + <property name="name"> + <cstring>spacer2_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>60</height> + </size> + </property> + </spacer> + <widget class="KURLRequester" row="3" column="1"> + <property name="name"> + <cstring>kURLRequester1</cstring> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string><br>Path to your GnuPG options file:</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="5" colspan="1"> + <property name="name"> + <cstring>pixmapLabel1_2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="pixmap"> + <pixmap>image1</pixmap> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>page</cstring> + </property> + <attribute name="title"> + <string>Step Two: Install a Shredder on your Desktop</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>checkBox1</cstring> + </property> + <property name="text"> + <string>Install shredder on my desktop</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="3" colspan="1"> + <property name="name"> + <cstring>pixmapLabel1_3</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="pixmap"> + <pixmap>image1</pixmap> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <spacer row="2" column="1"> + <property name="name"> + <cstring>spacer18</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string><qt>This will install a shredder icon on your desktop.<br> +The shredder securely deletes files (overwriting them 35 times) dropped on to it. +Remember that if you download a file or open one in an editor, parts of the file may be saved in a temporary location. Shredding will not erase these temporary files. +<br><b>Shredding may not be 100% secure if you use a journaling file system.</b></qt></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignJustify|AlignTop</set> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>page</cstring> + </property> + <attribute name="title"> + <string>Step Three: Ready to Create your Key Pair</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>checkBox2</cstring> + </property> + <property name="text"> + <string>Start KGpg automatically at KDE startup.</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>30</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="text"> + <string>Your default key:</string> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>CBdefault</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>textGenerate</cstring> + </property> + <property name="text"> + <string>KGpg will now launch the key generation dialog to create your own key pair for encryption and decryption.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="4" colspan="1"> + <property name="name"> + <cstring>pixmapLabel1_4</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="pixmap"> + <pixmap>image1</pixmap> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + </grid> + </widget> +</widget> +<customwidgets> +</customwidgets> +<images> + <image name="image0"> + <data format="XPM.GZ" length="78260">789cedbd5b7322c9b2eff9be3fc5b21d6fdbc6e270bfd8d83c8090900081d005098dcd435cf27e4502093836df7d22d2dda3aad7d2daab57155ddd670e8dd1513f323332c3c3e3ef1e9190fa1ffff5b797bbdbbffdd7fff88ff7add846ea6f2a146f7ffb2fbdcbb2c3fffdfffc5ffff33ffeb3de6cfcadd1a8fdaddea835ffd6f8cfffe33ffed3177f537f63b55e4dd57b151f881b35cbe10370bd56afd87f2586ed7a8ddcaa55c7ab2131ec1f3e3aaeb607f7c48d7ec578be7a0ff64f72cbf51a5d4f58009b4fe0fa4262d85f6f1cc3f93d62b8bea2838cd7e7ed89e178553886e37d6238defb705c5daf9f1237eb15678eabedfa1519dba34ac750ff9118ea675bc7d5f149400cf5ab0b6485f50d1c437d8a18ea0b9a8eabfa588318ea4b53c7d5f68c0137d09edea7e3aa7e7e4d0cfb97605fe70fdea3e36a7f7d4446fbea07c770bd0b62bcde2d31d4eff9c8683fafef188ed7c4d83fcc31d8ff9e18eaf367c4adaafdc91a19ed296f1d57f5cb3931d4cf5b8eabfa44410cf6643bc770fd19319c2fb8762caaf35f0193bd95700ced93c438be068eabfaf923319c9f5f38aeb66f426238ffc6735c9d3f6e12b7abf1af46c8d83fba460ce74ffa8ee1fc1d626cff8563d87e438ce7ff700ced9f11c3f937d78eabed01f66f83c6c32531b6b74b0cf5f3a1e3ea7859b7dc70e3211c3b86fea911437dde01d8d99f1163ff371c43fb1e8871fc371dc3781b12c3f5898e63b83e3c3fd9571d1c43fd541fd9f71b57db559b18ea0f53c755fde93531d8371d3baeb66f2e9171fc68e918ce4ff5a3bd03df31b4ef8318ceefed1c57f5876e7fecdfdc319cff99b8536d0f0a64ec9ff88618cfd722467b068eabfa223abfc2f6ae1d57db8b57e026f607138eabed7c408cc7fb8ee178e8cf3ef5bf2e9149bf22c7e05f9c18ec2767c8686fb5770cf515c468ef9ae36a7bb12486ebd70764b497ee1263bc983b86fe1c13a31ead88b17f2e1c833e60fd4d6cafe711a33fbe3b86fa2f89713c5e3906fb4e88e17c41cf31f8cb1119eda502c7d0ff543ff977420cf54563c7d576362046ff6a3986f3dd23a37d833d31d4c7a78eabfdb32631d457bc10779b553cc4fe6d2ad89e3c01b7c87f2a7b34ebd4bf45cd31c4d38018ec272f90b17fe59018edd3740cc77788f1f82930f597ca1d437bdbc4d85f2362687ff9828cfeace978f2e79163e8ff1a31eac1c231d8db1d8ffdd5770c7a302386fef1a97eca7f3e1d833da87ed2ff7bc7d5f162408ce7ab3b06ff3910637fae1d57dbd52532da33168e217e917d486f9863885f6fc4587feeb8da9ed3f914f84f3e762cabfad01f5ad81f7ed7319cff8318ea676bc7105f0ec4507ff14cdc6f55fd83e76be1f8c872c760bf36315e9f765c5d5f04fed8a77894be13837d825b64ec2fd52246ffe83986f63489a17d251d8ffeaefb8e418f7262ecffba6318af0fc4603fe1f687fa75064ce3a1b82486faf23631dabfe7188eff2406fb6d9e90717c788563183f4b62a8bf0c1d833edc13c3f98a07c7e0af747dd85ff9b563387e460cfdc5a87e1a2f8c18ceaf3a8ee1f83d31ea3fd58fe38345c8687f392146bde93b8678cc89d17edf18ce372786fa43184f462fa17e3123c6783d750cf1644d8cf5af1c83bd96c478fdcc31f887478cfe8cfed722bdfa2086e3f9d131d4df26067ba773c7557d2224ee555cf8c8684fafee18da43edc578927d3aae8e0f6f897bd57685fedb42fd48468eabfd73b2a782fd731c7f6d6c7f2e91db707de93d31e84352e979cbc523bf8f4cf9c38d63e8cf3b628cefefc0349ea4700cfb1f8861ffb840a6f81138aef6f74a62d89f8d1c83debd10837d750f19af7f533a067dc988514fdbc4601fbd40a67c933b06ff1e10c3f162488cfa390576fe1b3b86f8322346ffcd1d833fbc12637b3c64d2933931d6ffe618ecb12646fdeb3a86fea7f3a3bd8a4fc7903f61ffb6d05e7c458cf9d18b63686f498cfe3d770cf66e13e378d93886f1f7818cf64d07c4707c42ed477f0f72c7d5f1e51331f8bbd7750cfe4dd7abfaaaf2b71d308d8768420cf58b2bc7d5f1892286fa23e918b6fbc4307e421c3fed361ccf4b62385e648e617c33e43eee9f1363fd2d62a83f1e236b3c1ff657a70eedcb2f8945b5bd84fe10345ecb1b62cc5f42601a9f719718e707b7c8e86f8a3b067f6e1063fed8750ce3e90e19fd29f789617f3d740cdb3d62d4ef09325e7f4efbe3f5875dc7d0be8418c74f0aece2c79218f31fdf316cef11a3bec68e415f07c8680ff98da1bd8218ae2fd93806fb66c4381e6e89c13ff41819f58b058e617c4b626cffc031e82b5d2fdaaf6c12e3787b24c678b24246fb8a0931eac7d8316c277b517e7beb18cedf27c6f67d10833fc7747e05fecb70ff36fa9bd838063d4a88b1bfbe31e8434a8cfdd523c67836750ce31fafbfddc6f9e71331d42f33c7902fec88517f94e3aa3dc19a18ec59148ec15f9ac4703dfe95e3ea7a9223b1a8b840fb1b3da8eae3778e411fde88e17c89700cf65d11a33e5c3986fa47c4a00f198ee7b686fafd8018ea0fc68e418f0ec4a8476bc755fd1bec8f4e1df60f4262bc1ebcfe0eda2b15c4e80f75c7557d598b18ec93557ade6e907e0475c730fed7c8a40f9f8e617cde0253fc0d1a8e61fc3f11637e7f740cfeb644c6f11e4d8971bef9ec18b6d3f1186fe30bc7305eb6c4d0dfe11019db97bf3b86f9152786fad23e31c6bb2b62b0a77a4426bdcf1cc37cfb8318fb83ae87c6a70476e3f3da318c8f1b62b81eb5710ce32b2186ebcbeac458bf8fdcc6fafb8e41ef8ec4985f848ea1fe0e31c66fb457bb8ffad126c678d2750c7a4cc7e3f8ca5f89e17a23621c1fc19218ecc5fb8e21ffbf2086f645816318efcfc4e0cf29dacf8c17c85f6e1d57f5e91531d4a7b78eabe3839418c7f33d32ea0fa7fa707c05d27175bc4fe76fc3f1f9b363d00beccf0eea09fb745c6d8f1ac4b07f4c8ced4dc17e2e3e67303e855b1f13c4e8cf0a99e6bf9218e30d730cf9c71332e5a33b629cbf3d3b86f1181383bfa83a32e9c39e188e175bc7e04f2fc470bc06ff76f12afa24c6e37b8e217f9912833fc557c4d0ff1bee18f2c38818ec5fb8e3c1bee20619c78bfa20c6fcc747eee3f87a730cedd1c4383e7a8e414f07c4b81ed4770cf35bba3e8c47cc43d658dfc6319c2f25c6fade1c837ee5c4509fffe018fcd9d587f1644b0cfe1b637f77eab8fe3b740cf6b92286f3cbc2318cff27621cff6e7f381f77fb83fd59898c7a54be11e37a4cee18fa9b1343fbb23d31d417be13437bd24764b4afbf745cd5a7fac4b8bea71c57f579f7c4505ff0e418c6e703b184f14df643fb971bc7d5f9363b623c5fc731f863440ce7f3a463689f470ce74bde1cebaafe317017ed9b1d88a1be64470cc7cbbde3eaf87881dc57edcaffabf96ec7c5cfe49618e3d53786789023e3f897dc31c4df39318eff2b6037febbc4e87f1bc710cf5e89315fcd1c83ffdd10633ed9730cf12046c6f199ee9169bc751cc37853c478bf22750cf9dc3d31ce3f9ac09d3aeae19418f58c1163be32710cd72f88313f4d88d15f86c8385e58418ce3b1e718c6df8618f52523463d7c730cf10cdbdf21fdf289a17ebf700cf53f1043fdf29218e3f7c131f8ef1d31f8e366e818fc95ce8ff6d70d62f4970b621c5f4762cca7878eabfa38b597f44d3b86f17d4d0ce321467fe8a2bd378c18c77fe0188e9f11c3f17c8b8cf6e429311c1f158e21de7bc4707c70e1b81a8f29b6af8bf6dc648e417fa83eb427ff700ce79f13437d09d58fedf570bcf4b03d79a53f1d177fa30531d83f0a91b13f18d8ef5b3c481d833f4f8861fcb13132f96b4e8ceb3bb78e213e7262f4d76bc7e0af2532faab77458cf9ec8763c83fddfe982fdc3b067d3e10e37cd343467ff422625c6f5e39ae8e9777c4e89f4bc790bfd3f9d15ffdc431e4b7efc4d09fece8b8daaec17f8d5ee3f9178e219e3d10e3786c3806bd9a10a39e1c1d833fd589e1fcfe9363989fbaf381ff08b44f17fbcf5b39067b6c88b1ff3262a85fbf3886f13023c6f1f8e6b8f25f1fed43feef537bd0ff3db71df5a44d0cf585c271559f66c8687f7f478cf54d1d43fb0b62a84fbf3b86ebdb1343fc8cd07e34be822e311ceffb8e617cae8815c463ec8f1ed9e3c131ec8ffed6ebc3fe9b6a3c779b34deb267648c0759808ce3210b89713cac1cc3fab026c6f9cb1532fabbda1163ff3f3986f5903930f9ab2f1dc3f1afc438dec7c4703e593aaeec57de21637bbc0131cebfbb8e211fe6c4505f76498c7af9ee18f472478cf9dcab63e8df0b64b49fa6fad07edec631e8cd9418ce9fce1c83bf1d8971bd79eb18b63362ecff1e32da37a0e3494f9e1d83bf52fb28de3588b17ddc71d5be02fbbb47e3bf410cdb458b18fc3bc890d17efe9a18e3cbc471757c5827c6f1513a8678f7864cf16b418cf9ae745cedafa87ecc5745d371b5dd7b40c6f6f2bd63185f2131ecafaafb0f5d49fe5c3c11a3ff43ff49d2d7e2c331f8f31d31eaeb0532faab7a26c6f5e317c7102f47c4e82f9163d0b33131d847bd11a31e05c8e88f2a740cfe42f5537cbb750cf1ff1199c6f3b36318cf35623cbee518f4cded0ffe135e3a06ff80fe943d1cffba438cf18911e3f88f1dc3f88f88311f1b3886f8b121467b3c39aefa379a23d37c71468cf3c59663a82f25c6f8d1760cfeea1183ffa53b64f4579e10e37cca6d077fcb57c814df3f88e1f8483b86f147f6407f4d415f649ff24fcf318cb706319cdf6b3aaeb6734dac613c2a646c9ffc2486e3c30331ecafabfee8b978e1bd02d3f8c83f8871fd3c21c6f5b25b64f4ff2c2386fe1775c7e05f8fc4a84f0364f4777ded18f2b98018f38fb663c8b7c6c4505fe1f687fe9074bde8ffe91331ce374ac7d07f2131d677e318f498ae9ff407eb73fede25c6f9fade31f8e39c18fa3b538eabfa32b4770feda7b68ec1fe8fc498df6862a82fed3986781713a3ffa2fd7a684ffde818ecd521c6f1f9e018ce1f12a37f6f1d57e70bdcf1703eb6770c7a8efdd1c3fe0825318ee78018d7730bc7a01f07626cefd031f8fb33318e97b663186f4d601a6ff99563c82739311ccf3f1d43fb707cd0f8e28a18f70f88617c25688f3eda8787c4b07fae1cc3f698188e67d8de3eb66753e9454f52fe5eac90b13f83d831c4837b64f4f78d760cfdb923c67cbeee18f28d1498fcbb281d43fc5a12a3bf788e617ddc31e6cb2fc834bf50c4181fa93ed287b663e8ff07628c0f37c8d8fe3226c678f08d617c8f88b1ff7bc460dff20a99d6f7ee1c837f72621c0f74fde88f45cb31f8cb2731e637978e413fb0fe3e7d7fc131ce1f6f1d837db6c418cf32c750df8018cea752c7103f57c4e05ffe1099f2ed4f625caf6c11e378a3eb437f1723c7e0bf3e31d49f4e90d1bec18c18b64bba1eb40f8f88613b17c002dbe35f12e376e6d8abda5be5affd16f97ff98e8cfd93a7c0e4bff98618f5a6eb18fa77400cc76f1432fa67c21d83bf7788617f45f5d1fde6a36398af3f13633c108e21bf8891293e4d88713decc331b467498cd77be7b8aaafcc81c9bf62498ceb5713c7b07f490cf697587f1fdb1fee1c837fce88717eb2720cf1ad460cfe12bafad01fdf90697ea58931df0889d15e6e7fd4ef6762a89fd1f9d0df920299f2db0531ae87341c43bc708cf38b2931d457a2bd04cdff5f89617f9112c3fe31436e83bf06d5fd8bbe22bdd52d60d2db4d828cf6cc707ff21fef1299e68b3131e62b9fc4a897ca31f4ef35318e2f180faa4f7affee18c6d33d31eaf12731ea51e918fcf7488cf975c731e4036b64f4a7b2ef18eea7d0f194bfbbed587f408cd77f874cf9a0e718c6279d8ffca7e118fcf38218e341e118f4b38d8cf6157362acefd631d8571263fbb563c8cfa6c4e01f39f6b740fbaa8818e34b4a0cf5c55bc7509f63a84fb8fac0dff41b32cd0fae8831bfd83b86fe6911437dded671559f8ffe20047059f99770fa53ee1cc3f58d815dbc4a88d1de2364f2f72bc7d03f7362d83fdb3886faf1fcd4bfeadd31f4df8c18f5ecc631b43746a6fb752131ec9fdc3886f5ba0762b04fd804a6fe4aae1d833ed489b1bd978ea17d3131c637e9b8b26f3845a6f5974bc760cf16311cbfd9220bb4e7b563d87f498cfed4770cf1fc408c7af581eca13d168e21df61c470fee5d671757cd105961de01cea77fa90d790b1bfcb2931daabe518fa6b848cfd5dd68971ff47c7d05eaa1ffd3162c4383f5e3986fe782786f614d0bf6efca97bc7b0bf24c6f1f2824ce32d2246ff7b730cc7bbed78bcdb0ef692d7c8d45f13c760ff3b625c0fb841f670fc4c89d1de0dc7102f9f88e1f800fa57c906da67e418da1312c3f5c56de40e5edfad63589f3c1263fcacf446baf19c6c91d1fe4213e3f8ba0026fb6fa463188f7362d85f8d91d19e791719ed97448e21ded78861ff6ce418daf78a8cf6923b62dcdf6d87fd930760b297f824c6fe491c43ff627bc95e3927c6fc65e818f6ff20f63a95fe617b24b647dd10633e7e410cfb87cfc8347e5f88313f6f11c3fe1ba85f3bfdbb021675d81edd21d3f14d62dc0ee7d7d43ed926c6f669c7104f56c478fea5e36a7b46fb637ba37762f4df9d63e8bf2932f5df9618f3b323319caf7c760cf38b1eb0a2fef31d43fdf7c4b07f3247267f6f38aeb6a7d5f8526df2873842c6fdb33bc7507f8c4ce3fbd671b57db32186ebcf1e91b1bdf903318ea7bd63a83f20c6fe12c0d4def0d531f8df1331ec9f968ea17f26c8d89ea8e618e2c105311c9f978e21de5d23637b9381e36a7b9411e3f5f61c83ffd0f50b1feaa7fd3de44aff9526fbe71d64bcbecd8818ed3940c6f3c50a19ed97a5c4b05d258ec11fbac064bf6c488cfec61d57dbc58118ae376a2193ff8c88b1fd2f8e21be5e2053fc16c438fe7b8ee17ccfc8d89e7c478cf5ef89d17e5b608dedf196c458ffdc31f4c72b31b6a7f277edfc358c91496f268e21df7c04267bc97b64b447e418fbe7dd31d8bf818ce7cbeb8ea1fd4fc8d4fe3931eccfbe31d4f7490ced895f80c91ee507311c9f3c3a86feb82286e3b31e325e6fb12086ede5d0b15f1d9f2063ffca0762f457688f47fe148f90b1fe8d40a6f1b22086f3c977646c7f123a86f33d12637fe6c0d45e1910c3f6a444c6f38b05316c170fc878fd423986eb63c4d0fe708d8cd7275e1c83bf5c037be47fd578f03ad4be68848cfb8b1531f6e727305dbfa839aece1f5f2253ffd41cc3f56d90f1faa33762d8bf908eabfdf33d325e0f7b24c6f30bc750bf06a6f6150d62acbfeeb8da7f53c52bcff5479422e3f5b30532f5bfefb83ade13c8783d2a760cf543fb9cbdc52331d637765ced1f5d2353ffdf3baeb68b25325e4fa81cc3f65764d2a36abeee3bfb474b643cdeff44c6ebcd7360ba1e758d4cd7b3770cfbe3f1743decc131b47f804cfdb5765c6d4f57c03ef9d39d6318cf97c8e44f63c7d5f6b2d207dfa7ebcd17c8b8ddaf23e3f5480f19cfcfc01e3e9d8fdd21e3f1ec1e99ec2b917de0e59633f316ffbb97d6165c7069deec7ff712fde24fef93bf42897ef1a7f7c95fa13cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc5592fbe2acf7a71d68bafcab35e9cf5e2abf2ac1767bdf8aa3cebc52fd40bc535f7b86fde41c5218ffe0a3ef08bf522e6094f79c6735ef0926ff81b7fe75bbee31ffc93eff9e1afe10bbf402f62d3f2231ff021bfe0237ec9aff8d8fceb9adf98d7844ff98cdff2395ffcf9bef007ebc51d5ff27bfec01ff9135ff167fe62ca357fe5355ee70ddee42d639536eff02eeff13ee3dcfb2bf8c4c9f522658c0963830ebf649229a699c77c16b090452c66094b59c67256b0926dd81b7b675bb6631f7cc63ed99e1dfe7cdf38915e287664033664176cc42ed99569ebd8bcafd90d9bb0299bb15b36670b76c796ecbe7a3fb047f6c456ec99bd98633ed89abd72fd67fbc6cfeb05abb1ba694b8335598bb559c7d8a0cb7aaccf626136b25b21d8bd90fff4a584169ef04520421189981d44f2bfaa5e8854642217852885f105f166deef626bacb0131fe253ec7fdbf2afad623e3d88a31888a1b81023335afea418f3537a118a4b71c576bc26c6e29a69712d6ec4444cc54cdc8ab958883bd34ef3164b712f1ec4a378122bf16cca17b116afff60999af1a1ba6888a6a9f74ff18d9fd08bc0fe6565d1115dd1137dd6117dc925338d925249cdeea4675ebe0c64282319cb443099ca4ce6b290a5dc88a37c93ef4643beb38739662b77f2438c4c46f627f8c68fea85fc947b7930b1f35e1e45df7885940339941772242fe5951c8b173697d7f2c658e1526ce4444ee54cde56afb99c9bc8da940b3196777229efe5c377def1221fe59388e5ead7fbc68fea857c9607f922d7f2554c8c3f48e31135599753b1950dd9942dd9961dd9953da6645f713953cc5a41092595b27f4953f9e6a50d05ec46852a628fce3b962a56894ae5ea7f0dbd50a9caf885ec1b9d302f16abdcb4b350a51caa8d7a53eff2466dd58e79463d6636b7501fc607d6ea53e56aaf0ebca10eea685ea51aa8a1ba502375a9aed4585dd3581142dda8895cfdf5f5424dc595e8a899f101a96e4d1be7a68f17ca37decfd49d5aaa7bf5c066ea513da9957a562f6aad5e554dbcabba9ca8866aca217b572d633df8af342f65ff2aaeeaaa9e8b2c0bd5d7fcafaf179ab126bfd72631b051c3f472616ce1a9a396a6f7375a692ddeb4a77d1de850d574a4636d3de35a8c7522263ad599ce75a14bb444a137d5f166c4c8a37e634bb0867ed75bbdfb6beb85fed09f664ef12ca67a2f993ea8a13eaa42cef5400ff5851ee94b7da5c7fa5adfe8899eea999462ab567acfa6fad61c33d70b7d676cb1d4b9f50dde3047de57d62cf4839c8bae7e14185bf4935ee9e7bfae5ec8957e615bb9363a10b0a93ae8b569c7857ed5355e63a9aeeb06f37553b7ec5fba15ef2c54022287ac6969f6ee1adbe52ad73d16e99eb1485f171ef7981961c69ed5ab64a10e3ccc554d585666cefb17d50b4fb3ad69f59bd8e9b9e7591fd76bfdeaf95ee085b26b74e2ca8bbcd84bbc54a766f40c588bdf9bdcfc43e4f6fffcd1cbd4d144d48697abb95e7a85571ab5c9cd9edaf8d6ada9edc1d823f736262a5731c57bf3debdbfa85e783bef434e5860328691f769c2a3b5c3de3b48e91dbd8137f42ebc9177e95dc9116fb00b6fccdfbc6bef46b4bc09db7b536fe6dd7a7311780bfea894c7ec1c5e7779dbc41569e2edb0d20ee31d72e1995cadf28ca577ef3dfc25f5626bbca225762ce63533ce1fd4d17b5403ef5177bd276fa55ebc67efc55b7baf72ead5bcbad7f09a5ecb44c6dfe690ca6b7b1dafcb84d7b3f1c7c493b6b148a1a4d7c771a2d5c0e7268baf54436e7dc683bfa05e5cf9c671d99b898d0c46b7e9c7d278f84c367c93709b044afb9ed7e70fa6ff9b6696f54fea3139a5e7fb7ec0046fd94cc3e8ae5113ded6033fac7ca3d42687f3a36a9c3cf05b3ffeabe9859ff8a99fe9a59feb5cde7afbca1a46f578cd2ff4b55ffa1bff4d264af207ffddff1df589d4dff91f7c6c6308fb309ed1540739afbcc3c45b738627ffd3465736f73a6afa57d20b7fcf3efc036fb1d8e6dbc61225f4a1c7c4d83f7a437fe00ffd0b7f64fc9dfddebef02ff9c2bf32d628784b1746378c8acaba7ef5435bb73af8633b9ff5affd1b7fe24fff3a7ae107fe4c797ac0a652787babf795e62bdef66fd5833ff717fe9d995b487ff9efcc31fd7b335a1eac0af136af9b5c7e68e635f3cae34c8e6e66754f36bafa8ffed31fbf2efa7bf542aefc952faa4c31b7f1cff69b799b7fb1c47f96777aeabf30a37ee2eadfcf07fc3563feab288c67d4aa0ca4acb20d5f6f78d3afd93cd4af7bb77ee38f9e9ffc5ebdd02ffcc2fb50479323346dbf553e51a8a1dff45b7edbef987c226091df3579e20ff489f7eef74c7ceeaadcef9b18c4ab3cc3b35e17f080b13b761f88401acdf84be845a0bc0f1bfb036d4635cc21ac5f0ce422f0d48377e55de97de007010f7fa84fe22034d94653e54164b2d1ae1e805f98f3c8200e12bbae11a44166f4e52fa017416e46c842954161b51ef200fd2ae74129637dcd3ac1c6c4970faff9a37dc2fde0cdc4a8c264a1fbe05d1d4c5eee075b7316c16e829dcdbb820fe39bd19faf17c167b037b6b03330097e61236a70d087e0180c82a199bb9b6c926f7f662d2ab8e08f66f6da0d2239350a3a375987cd4187e693911c0797c1553016977fbe5ef8cbe0da687d8337821be3c9ca5ac5aec4b0693009a6ec5a8e4cee780c663fd537b1c945b75ecfd8233363e5d69ea5cac76f837960d745f7c19dd7f923d7417f9f5e04cbe09e3f586d331940b35a9fb32b0f826d8287e0514cb464bbe0e9a7ef7d7d042ba3cc4339359a713099686935c9c4ef2278960f6c19bc04ebe0f5cfd50bd3df47ef23a80575dde335338f5a540a7f604d93798f65236804cda0e5af7fb66ffcad696b5b175258fde46db6b37ee1ed65ddcc819fd88310667be7cfd58ba01bf44c5eb8145ccdac5f98716cd72a4ba3f17d13361a6686b20dd9cf7faf42ae42c1cdfcd74455336fd7dd2a766fac355818ca50853af4fce0cfd58ba013fa6cc842d165b1b2ebb630972cc52c0ccc45367cce76662e7982be095ec34832cfe45caa613ca361f4f3c1db1bcfa8794f61cc96de344cf8e2cfd30b131bd2303591742207726dfdc2e4156624ab015f85998a449dbdb356d03d4ddff8bb30379ed197239383166a1fdad8bdf67c168565b8915ef816beff897ae1855b31507339115bb9964c1daa9cd38c12c9c31d7bd21d3d0c3f7e3286b8524d833cfc3417c6ac6f187fa866adfa3528f4850cfc7ab80f94ff07cd59ffb55e84075eb2cbf0c8dec241386491b1c5a69a2f0c58125e84a3f09235c32bf979a23e0a3d294ad91733c1f5321cdb3c03149425facdd8e23a58f38f3fe69edaefd00b1ddef02b2f606f622b26c1777a114ec2a9ff18cef8d853a7ea1b7ef0d7e1adecf327c17d93912bbbd663b271e38bb9df0ee7ec315c84773cfc73f4225c8a8cdf87f75a8831ebb3296f860fe1a3f58bf0295c85cf5a9979c8d3e9fa88d5bc5bd1957d16872f269e1ce08ea3dec8b93c86fb701dbe86b5b0fe47cc59ffb55e840d5ef07b39626fc1468cf96be51743bb16257661331061cbef898bd3f59189acedb0636253cc267a21a7bc65f219630d6f1f76c5518ec35ed8577dffcfd28b3ce2462f0231161b7b4fc446391bf7e524629150e3601fc9489dae8f221d79b2af85ee8969e51976197563236bf018f962a1dfa2e08ff80ee0bfd68bf010be47dc0ba48c4231d67b7da8ee08dbdc33d713194491f7e4d5bdf6a9fac8bf14a988a2d8e8e754ccf4adb6a3c4ae970c4dcedf8f9228b5a3c46b9c7ecefafbf20bf6e1d97be6d7ea43adcc9ca4acfcc2f7fac120caa23c98861f5171ba3e92aba88c36aac3a6622a27aa59ad9457f9a7c9cf3bd15bf41e6dbddb70f9ebf5c2cc473ad14e05d147b0893ec556e5726e66ecbe9d417aabe02ada87a118847761e3547d64e6a2417450b3e8c8e268a0f2685865199e5a98f239ba8846d16574e5bd7bad5fad17763e128d795ba7625c7d8f6254f9ac5d5b288365388aaea31b2f8c265c9fae8ffc6954841dd98fa67a61e4e380d6f754c1a6d1ccf8e26d34f7ee4f3d67fd3df3111e7963b63357b6883ee5abc9c56bd57d91425d18f5bc8b96d17df4103d464fa7eb23334a56416e6349f4cc223955acf20ce38bc1adf71cbdc86db4e66f62f4abf5c296d12bdb9a39eaa3d88889ec2b06f746d450cb70a7e2a86674a31e04271dbf2a6a181f689afc732a474154dd8380396b4f34a256d48e3a3c3ded6f0e7edf7aa7bfe4377c1d75c5c478469f7d5473b3eabea75a463de9b3dba81ff353f651cca2227a8885e88a99c9759be118d6de8d7f746219ab58c94eac456cb4e597ea0517b1c787c61f56ea514a36d5521d2bbf28958cfd3888f2e8c2e41893489fae8fd8210e7919b4d994bd19c38441e4569cbb7e1147711c2771eaef4dfef94bf5c2ae2bc4197f14db7018e76c6ac6efb19aab966a10175ecb8c1211977c1a6f4e397ec343fc16711b4b449745c18d92d59dec859c9b7c7717bfc75b3d1211f77fb55e189fdd8942aec3a15a997cb0ab34dc1fb1df528c3fa25afce9b7d865bc3f65bc1789efcb83b2dfa59de985ceaadcdfc412fd1a1f54188ee263388b07def47473d6df7b7f241e8a22be307ad1658114463d8fd5f81de8576f188fe24b19195b5cfdf8fd91af4a1ec5e3f85aaea3671359cd28d1f736aa0687f8866de2493c0d2ffcdbf844eb26bf5f2f4c997a3bdeb17ea1562ca439825d7352793855717ccb0a638df9a9fa08756a61329bb5cd3ffd51b5fe696668c141093d8fefe453bc54cb60ecef7fad5e54b16415f85a445db512535d547d84be6174dd7e4762a3f7e6ca4e184b96dbf8217e541d3f1733336785bb11ca7e932928e2a77812eee3a7300902fffed7ea85e9a3157f348a1eb0be9e2b7b7fd987fbaa66fc3e87aff18b7a3733fad929638979eb782dba9289a9c9b8982eaa8cf7559572cefaea3d7e8d6bf22e788aebbf562f4c1f35e266a56413b19323d34725e482de3efc8c5b6c11b7d58e4fc2f64973c188f1b81334d89b5d838fedcab8303d50adc1c73df119f7d5929761fd17eb85884326f8059b86437663625c64ae6858cd980ac5121ebeb279c2c241224ef97d4c9124325111573393d508e3195dfbeda56aeda4c6bc709768fd98789e3acd9cf5dff9be56e227017f0e877a6fb4ac5fdd512daa3527cd7ae16b1226913c26b1bf3e652ee8b5d86792246992f17bf6ae6bf6bb8366741e9514d3f8235ecab7601ade05dd5fab17a65cb00bd6d442ada4d499c98a8d2d92bc9abd2f922229fd48ed924df276ca5c50aebcb6de46abe49d5d2ae57ddabb9770675b1ffc22d9da5822ae921ddfff4abdb065f261f4f32dcec5442fe07b18c6167665b666b29fe7e45376d84b248dae9f3096b003f7a3327e8b77fca2b2856f7c439b738fa24fd54d741824fbe4c0f6bf522f6c991c03fbfb80390b4c2ed8ad626af51d7fafcfded47d3248862ce593e4e2a4b184d9df1805dd64945cdad5f7ea9c6656985cb1281927d7c94d3249a6fce3d7ea855d574866bc99dc9a1cc3c69286cd2f608dcb0b646cd4736ee62517b13e692c811cd48fd7d1d88c0f81bfd058787d39631dd3030b3d5259f094dcfd52bd30a5cad856ca64c962336f351960f58d91d2aef725f7c943f21806629c3c25ab53f90495269e3c272f2686acd1177d394fd62c88e6d185ffcc8fbcb4a3e457ea85b9a65793e835e4c0f8c524a92959cda41726d7f0d934a9278d60a7ae92a6373ba54fd8927f26ada46defe27a9f26e73df2073d50cc1f99cc731a4c8c8e65bf5a2fb84c3ad12ea8991c23606f72a4ecfd01f85eea504bf5907423113cb356d2e327bc5f5295f677de1fbc9df4ed77113c6e660185dab3d0bb8a07294f59fa8bf30b5b9a18d1f7188b5329d7a932d77581df4c35b93153c975344ab54ca37aea9d562f184f7dd64a83d064e466fede4c43330f6062a25e8c25a2e0cdcc577f6d7e5195c127bfe035b9568fd633aa5fd0e1f73de5288da3f7f8dd2fd244afa2d529f5c27bf0ea69ca2e25531d955b6be84cf03463dd340fde12c517fffcf8b4f87ddf0bfd81dfa786f25214c62f06c9ad98aabd19251ad6a8655df6c27d5ac6526cd2cd6972c16f65fa96b4bd0ffea00ee9bb99013455ce9fa4892d69926ed3dd3f3f2edea71ffcd67fd25bfd745abdb0a5ff2e0ac1a3a9d50cb5c75cdccce0bdbd19379f514b46e99e4ff9fca47a61caf42d3db0862882a62878d3cc8d2ef8557af426fae3bf3b2e50a2ed5f05a13c18ab0dc25a30fe67fbffc8ef53d3a1b7f34a2de2dcccde79354a8a606be7f0baabc3f4221de9cbf45265a7be7f61fa789d5e05bd74ccafd3ebf4269da4d37ff57d4f5932c637e220bd74c65afc32bd4de7f1e0547a51fd6660c9b63a65815cf39a1925baf20bdf0fe5ad18a78be025bd13fd74e94d4f1c4b8c33f250a5e97dfa9074ecb70efebbfdfda95ca58f622006e9135ba6abf4d968dc95e9ab17b6f69a27d20b53faefe99a7792db689abeea5cd6291754c3f03ebe8b5ed29aba33b1a4fec77e7ffbabd2df06af69236da62dd6f27b619eb6595fefd38eba968d284cbbf226eda5fdafd7657ff4f91719b7ab5cf677aac61635faee8c7ecd98373433e9a7682e367cf6f3b9e0ef2bfda9fef09ae954a5e22aaadba736b1167bd3f334131bfbab7ad661a9fa102c13a291c94464eaabb9f48f3eff2218f0cbc0b7f73bed0a8b9c1bbdb0cf2e18282966c975a6e309db649e88bcd3f77df4ddef483c95faeb74c8b77c138ca34334c97c79543b566481b88ebaa29f85c61f16e140beb2aeec86ad2cf25a59ccd65fadcbfef8f372b2843f5abf10f6ded101be6166ef1ee94330cdd26091652c8964224feb03f6bbc17143c47ce1fbc6026596b375f0c66759a1debd67568877d6119efda52cebb28d0aa375d4914769a27c56ca38db646fd97bb6e5b3a4732abdb065b6131d638b9d5e845d5dd01d3e13530ee1841f62957dc894cf4efdac023fc93eb37d76d02f59ae3f592bfc107e1606d3b8f44bc9cdb8d81b7fcc58a176b2971db3413664457414e3a0343d74e16fb351f6c66530ce2e4fa7175c24929951a2562c66539557bfbf5e5719e880bd6757f16bb295463ff5ea74eb9f46a3de8c161cc39610aac75239328a35c9c6d975facc3626078ded8a9b7d9a4276a3ae3c9d4dd8329b9af17293bcfbad7893cd3299dd66f36c1ba46c7d3abdb0a589dc8f62ab85c94117ace9f5ed77daecf732b4cc16d99d0cb3a5c990b7223e8d4f64f7ec837d640fd98d388a7df4e617a22bdeb3c7ec497c66abec99bdb150ccb21739cdd669e63da5ba7a6ed122dc997e5964affa39adc92b759fd5c2d0a8e7176be73ff37c2dfdc12e8d970ee5404e7457b1ca16d53c8d0559234bd96df49035b3160f7fd627b2b637661f812fd77221d76ce33d074353e6493778898368ce6e5860ecd2510fac2fa63a356377927593c7ea776a5759cf7e4724bb138de486ddca1be31763fe16ffc37ce9e79eaf65474934b5ebe27a597d2bb5c05f03edb37ece73263e72914b91fe58fdfc909b6958cac4304db266e0e71e8bed73fd729f45ea495de5411e26c37066d4729a477a9ac77992a7ec263ab2a9cfbd309bcb0f36cfb33ccf0bf69097516246c955f696186b647b7e3c9d5e54e5d1cc59c7f6ae228b3ccf7e2bc07e2f237c5003d197ed789a6fd4155beb7feffbdb51f09ad582d72037739a49b48bc6e6d5cfdf846f4662ac17da7881f18fbef18b9ec91bfae1d058e29db5439e6f85cc77d94acc8c8e8ccc8c7e937f84b36017e5629d7fe6fb709a1fb2c2fa457e145789f7f7b1e4679fc7975ef3719ce7037d5bfdfa0a9e5f51e8d77c987ee6172aca47f2985ffeab6722e557ace635f5b3fe48ef3c959bd6e7d76992dfc49d7c1276f269f8c49f45379f19dfdfca753ee32bf96af2875027d1c2f4c456f4f35b71cce7f922fe64572c94d3e05dcda341769346d936f9941ebb8feed35ab60d43e31317f95dbe1457c6da27d30b5b8a32f02bcf9849669f53602d617d43d6f2fb4ce70ff963fec4d66af2dfd593af1295f8f973fe925773f02c9199b1c06bd811be7df11793c3aec2017bb34f6312e37060b2c9441ec5c4448dea3ba026abd804717c97d7fc9ac926a672c8db6a6e9f07277b5127590811e5793d6f842b93776eb222dbca386fe6ad53ea852d8366de36b6e81aaf151ad632ecaf07e7a6af3af128ef861f26187efcb3e3d3bb781f9b38195cf9f5bc97f70b6eac20c2a724133e7bb17e60daf32a8f4c99599f7d36d1ab6f06bfb186f10ffe04f7e00b51adbf9ae6d9a751c8a9dfb72b80418d8dd42c9c78abe44625858cd24266af69cde49e8dfcae50e2caff287ef36cc89f7f7ea77d42a3c9f8dfec2a97aed6c44d9ee11b7b5c169e49c27d716566d6ffe4f8e0b3f0f925bf2c82500b5984451476c24e1117317f0907ca8c0936156396164930550fe2dad8c07885697fd76e531dd591ccc4b0a557d8df489ab9c0d0cc9af75aaa5ccd83b6c97a98518e9eec442f429908aba29722358adad14ac64556e445714abd586e4d2a5588b1bad5c69975d76f7a7bfd5aad8d1f8a52c5721cafbefa1d3a3f149be22d34f98294a9643d6f54bc67a1d1c75731f6e6a25b54bac062b163bd6297446c910c0bfb4d5bb3bdf814dde828fbc59ebd1b5fcc74666cd0b29ea0e65254bf1bad15073ee6e3a01d3458578f8aa358fb75f610df4749d80acb342e06b297f87c66e65527d30b2ef4b3f721cd7fd1d4aa7731d40f955f784af3553e2f2e8ad1dffd86609e08fe164df834dab10f33b2247b335a681f6337ad7edd37f3cd88f373eb13561d583798466fec5e88b46bf2acaefddcf8c3a2b8544dfbcc8ce2ca8e08deb69630be305773e32373cb811fb4655f6ca4999be63bf6205e6410f7b34dc8e341312eae8b1b7e2c26a7d40b2ec24b51481e4d53a917aa69b2f1029eb717bce749f2c9736f16a4e943de2ca641ee758d67ced2840d8adb2433a3e15394516cbc7e6bfb9aaf8b395f47b1b1c04bd5f7462ff43c0b4da6228b455c9aed7bb9500dfbbb775d54bf7136afe2ce7a82ca8b43b10c6a86efe173af17d48a87d0b4dbc612e317cbf833d819bdb8281e8ba7c80b3c3ef39353ea855d87d4f75aa84733e407d23e876d80bf8ada17ab64a0d2ecb3782e5e8a359ff0abe2954f8a5bb5117e712bbae180bf70932b44dcfcdf6a43d7fa04bdd0374626b32e4523bd63899ab37768a78959f6392acda266adc06bf6778bd63ef0f9b7377b37f3a576e415c7a25e348448164593dd1637b257b48a76bc4a3efce5e9f4c2c602d50efd7090dcca75d8557b630d4f154547e77e116e8aaeb88d3b45afe89bfeee16ccb4d2c486f8c28c8717ab0b6a567ccab5e57c66b4c0f847f1c962cba69c060d5ef30ac98c8f30db56ab0b952dea660cb4ed6f1579650dfafcefcbe2a07bf6d991c15dc94b568ab4f45aa5940dfb5363e31f617aeb2f4fa717b6f4a6ac61347e2607da6ad7c1e618a5a7f626077f60f7a5efe7c6f3b98918a6f78d30ace125365e284ad135bef1626303f882b1d1d4fa83bd638bfd9ddbf10ffd5c3d15624e9fdb7719fcbd2f7cff56f332346ad42ba32c92db6814beaab1ff9c8cb322ea94713ce033bd0a5e4fa71726c7c8d820f0c5ce64c333737d2d98a1c93a5f650df610eebd90bfb269999879422ec665ea853215d73626f06735031fb07e62c6365333fe24fb65a672afac9e57e7fa38b8d15dbdfce60bc55da597b57fe613b6b4f751c24f79d461368b8392279fe1c81f178fd1accc937a5994259f6497a7d30b5b961b7e617a7aaa1776cd4f0fac5e787db52fdff23dbb0f57f91b9b46dcc4ccb5897117e57bfa59da2caa8a156a063ac1d7fecac495be642646ccedaffbc10f6c5ca8fed5ace284f112d5fcef7ce1b76f7b44682268b9339175517e843dd18893f2b3dc878b6c531e82b7f2783abdb0a57f643b332e27c1bb5778056fda672f9a3c43a8a7a86df47b1994aafa6d217f2e07c95eb6c59a1f4c62b1e6cf720d7a21fb3e0fda71d7f6a49adb1851985e8fbbbc66e6c0b9f109c3ffbd0ffc636946ab7da65b6632b3bc78cc86e5305f941776be1ab1729445ecb6bc1457f195fe389d5e9846ee59437db248cecccc88057665dcae7d4a31f38ee55598b1ae9c588f571d934f5e45b7e5583e99c86ffda22f1756196cde68236250437f689ade27bd687e8b1dffcedb3e05d11e69f2cf24f0c2918d25850c479111a3729fbdc5836c5b5e8bc07b3f955e8894bf659ec931849cea83b86663d38a07253d930347f60932d74998d4a5b4e3bcd8abcfa021efe2d7686e73479f9bf68a2a43c2f10da5f18966796375c158e8e6dff185af4a334bdba65db9938f762d23f90c581665b7f1249679a047490cf39213e845e4d5eddf93086a721e44f6bbdaecc6f6a8caabbcd14c58e25b21c583776532cbd8e41033336f49ed7382adf7436bab279a567d693d03fcc2daa3f2961ff0877ff08f9a5cfb66769a9a70221ebd65d82b27ea3e6a97533367ddf0325de6ab53e84539e337de22f78aa5d29e1fdc88999ef3959943e676e41b1f387a2f7eddbc5a62cbe2b06b7327bdc87d6b093952bc8a8dede0a6bcd57d392ce7dff769512bee7ed627aa31320abbac9b2fa3cb7221fda21ebdc4b18ae475560413fd9cdca42647fa69bd884c36dd886fbc90a5a91911665c76594fcc20e69979639faf4c3edd2eefb416fd2a6760a001c6378c25740f4ac34373cdf2effbd3aae56f3ffb7bfeddef9a3c964b318adee5385cb3c770941fcbfbf2a18ccbc7b0553ea56f22f939bd88eaacc1af649ef272553e173bbd8c0692d93e37f9f324f74dcb5f8d17dce9bc7cd1b9d50b6b8bd2c4def4552fcc1c32b6bf4d0ebbf6f9387216dcda674afdac0f506914eb7b5eca7516da15bff2953d94b53830aa590f67d9451e46b390ab76f0fa337a91bef1b128f88af58b5dbe15fb60649fef22fb760e61628a7d9e239323d3f339bd6c366d3fb3f73574cfbed04732c8217e345efc9eb764d94df098bd85bd28577169e6ae21f7c7e12e9ac532134cf0f4c7f522c822630936321a190a5edecbb72c947d3de4359b7bea5b39b1bf7650dce48f85f109aeedb35f16e5dae4624bf3790394937c05d8c49393f8c457a59a8b9dec857d19aa58ec552cc3ecc244d67a364b8c7f944db6fd51bd2874540feed5dcb6a3ca8c5726a7b67dcecad0e60c36e560a1f103dbef0bd0046b0da322a00f23fbaa4aa63eede7f665d729ff20bf68d8a7dcb05e704c74d663f7f93e2fb359d90a795ecbef8241d9e60f3fa6174156e4ac61e6805ddbab55dfda672197dccc1dcb4e69fcc1e75637ec73c079cde8c1127cc0ec63ac63d79eecf3d22ddb97d115a3a0ec5d35aaf947f7b43e61b270fb9cd4a6ee869facebb7ed4a70d9630fb21d25f1d6cc4bfae2184c373c653fa6171bc66cfb1776ee0071c1ae35caa16a1657769d1163c5d08e0e9dc9a9f509f485a95d91b3eb92faa00f76ae41fe01b1a55aa13b993ff0a692e6ffc0a687582fe5c94df0e27f86eb8d907a234d16bedba88d0e54b0fe31bd88f71bcfc60a33bf7882f9826a1557b6d530ee759686ba6f9faba71ad61ae65f1cf28934b49680f549fb4ac3ef7463748a1cd3e9c3c16670ac89197d4b777d2ec669e4b7e360e3b36594a665f6963564275f6e82f02e18ff985e44c5260cda66fc33fbec12c81bac25aa676f7635ac4a2fdd7a53f57c78fbb9c9a56c4635adfe9e807df59d0f55fb59bda8328d9ff207fb8cd1a4cf5bf6b9febcf9ed73735533b62906f25a8ec51dbb8f6a9b68136f12d98de79b345eff985e6cb28d6983fd4d713e33737153faf619218d2a3af6ad0f98fc62910fab35a991f18dbe190f7b986f58dfa96c437dd8fd3ea6588bfcb06fb4e1ef13f84d5b1ab5fc6ebbb5859d978493609ad6e24b76c7eefccf2851efd1dc6ffbadf08edffea05e14d1cefefd11fb137c88055643ab7b9cd59ad4a6041da9f421b716b25986f9b7c9b2abb79b7354d738ffe61b95ba0e7f349e386df8f26df360318e1e92fd66235ed872f3968e64bc79f7565147afc2bb1fcd2fbce326e497c6efeffc91c92466e423fcc9feb2f65bde60f30d8c21539597b74647bef56546ba6163c837dff87e2debe7630858c872d991cce418c7b80c5b512a7df6b8d9a671380bfbb14cde37bb1fcd2ffce5e6835f1a65b65a31a956a3faa6b4792633f1a57a1b6bf4edca047b37e3a4696306c410d74fc653e8dfdfeb86559653c410a319bff193a066fb271cb0d4d3f23afe4cbaea3ee49bcfb0a5eeb3fbecf0a3f39174987c6cbc2a8f9898f1bfb4b96458e515463f9ee5c49461a51f4b7b6fcb96b6cf297f9033aba3c647ecec03742427dff85a2fec9cecbbf588a6899687df93577cffb9d7b3b921b38b16d32c0aaef2451266c3ecb6bcdceccdd47df7e3f391609ca641bbca9f73f301b36b13d5bdddbecd2321c7c4bcb39a6f58cdb051d3a846d5ef102fecdc544b7b0fb48a34d53e763df35fc612fb57269bffbebf80666c0ed9562cf24fb6f496e1be48a3c4ebf0ec27d62f16f95a141bbb36958ba99d67d85c53df99b190c19cf45bde60ac6295d3ae5740ee39f530aa0637f66e30f806c414f01d5e3f65eef99bb5f4257f162c5fa6173696b0655e4f8671bfdc96c79f59bf48bc34f5169bb28a9c53881830b3a05cd2fa03fcfb7b3da83e2fec28b13e023ee17243339a4ea317ffc42f6c54efb39eff6c32ae8190e9caff4c1e12bdd96d863fb37ee13fb0dde6828f79ddf874ef7b5f30b3f2d0ce53aa7be0a3ef7d044ac8bb14b73e82eb9c7b39b36565b746355ff903e6aa501a5d3bea511cdbbfd82964be90c166e4b39fd10b5386c59c5f7b0bab0b2c345af9f97ddfdbd9da373ff8f66f7c4f21dfa2feda5cca99bd97f1dd31dd6ffd19d4eceb04b1a58a2b26b28e65637365e6abcb72cceeb25e3edf8c373fbbde79dc5c17f7c543d5d7d96ffbfebbd2f6f16f724be30f01f842a51b764cd42b5d1bfdd6774e3b57adfe55379abde4abcd4da13693b257fd65b97d36f199bcfcc9f5cefe2614051f9b31dedb94b60ddfd626be9f7f7e7fff5361ebed3a163c0bdcbeed9ca59ac37eb7ffcffa81999d5539869d9f7c3727999b286f63c954dd8b7b3b4aa26b334ac641f0b3f7473633d6c8bdef7d016285d18b11b1bd2f6ab5b59cdb593c6cb7afcdadf97464e7aed067660e6b676db9f9dc2ae8cfdc0fb199e6c16f9ac8dbfec73ca338d8fb25f27233978ff077e536bed7e0db9fbd3f12f4f845d086fb9cdf7cc27e830ad7aae6f03daa6a3d139e3b5fab3233d00c3bcbcf5137fa9565a6b03eeae62cff4e4cf99df986cd3ff9cade2f918f3696d851c2d3cde267ef8f6497de4e1426e712f609e7dfad43bc5731645aad61fd9d7ed84c5dc1f72aa6dfdd0fa9d63b8c8f64d5dfc4e3952f0dbdf277fb42957bfd1edf09cc4835f3a7eee66eb38458e2d7e57391fdfcfdd4609504de82e205e411b61df46f9a63d83b472eef703e0499951c1657555ce997b7d55f4bcced3a58e51d27f70b1b8f4cbc5a047c73bf79c877f8f7063f368f3f7f3f35f4836b3e2e3b763e6134e0498e82fab73ca36a6f43f6edca1fcc4fe0f3dfea8b8dcae56d392f6fabb1c5e10e926a9c3ebfa0fbb666cebadeac8ac7e8c5af577f9773e4bdfffcfd546fb2f9b03946d5df3d93552c6cfb3daffa356dcde65cd5dc15d733a8cf695dfcef728e65b5efb71cc3f5e5f7b9c869f24f937d76232f6fe48b6a5d6717cf4ef0fd8b78f3cc76fc863f9a11fb18a67ac01b7aa0dac05486a92dfff1f32ff66b1a2f7ea8f8411dd9ce63bc65ffaabd2d894f51f2667af0eac9fbe6dd9f469af1b47eaaef5ffcffa1fccffff7fffc8fff0f4b7fcac3</data> + </image> + <image name="image1"> + <data format="XPM.GZ" length="79396">789cedbd59732339b2eff97e3e45dbc1dbb1315c52a4b8d8d83c68a5b84994445112c7e6014bec3b1791e2b5f9ee0384bb23b3faa8bbab32d95975e7b264acc89f18810838dcffee4090a1fff15f7f7b9b4dfff65fffe33fd61bb189d4df5428567ffb2fbdcdb2cffffbfff9bffee77ffc67b375f6b7b3b3c6df9a67ddf6dfcefef3fff88ffff4c5dfd4df58a3d750cd5ecd9fc4670dcbe11970b3d1acd96f10c3fbfa1db9dda88f570762d83f6c39aedf0fe6c467fd9a2f907bb07f32b2dc6cd0f5841b60f31bb8be9018f6d7a56338bf2286eb2b17c8787dde8e188e57b963385e13c3f1ded6717dbd7e4adc6ad69c11b76bd64b64ec8f2a1c43fb7b62689f6d1dd7ed2717c4d0be2256d8dea763684f10437b41d771dd1e6b11437be9d871fd7e86ed9da13dbd0fc775fbfc8e18f62f7b353b7ff09e1dd7fbeb4f64b4af7e720cd73b25c6ebfd2006fb791e32dacfeb3b86e325318e0f730cd7372486ebd58fc4d0be3f712c6a7b64c8685f39725c9f4f8e89e17cbcedb86e5fe4c4605ff6e1b87e3fe4c4d8bfd4717dfec09defbc8ec704dba7f150dc31f49f1163fc1d1cd7e7e37362b81e7ee518de3f2786eba9bac478fed8717d7dea1219c74f3788e1fce9ce31b44fed617cb06bc7f0fe9018cebfda3a86f1a0feb6e1fc2bb77fa7bebe402353bcb488b1bf3d62689f5f3aaedb93b55e9db97809678eebf6bc0631b4e7ed81c9feb24f8cfe70e618faf74c8cfdbf2286eb0953c7f5f5887362b0bf7c4346fbaa9d6368bf458cedb71d839e3a86f329b73f9c6f45d7db86f3a57dc760ff1e31d87b758b8cf1a69963b89e0e315c4f103806fda1ebc7f1f0368eebf38509315c4ff9e218aed7b587d7d3740cf15322e3f85553623c3fd917e34ff88eebe3a301319c3f2b88e17ce53d700bc78f49c7f5f1fc8218ed79edb87ebf84ebef937fe80299f42f760cfec789c19e72888cf6571f8ea1bd9c18ed7fe618f4f08218f3d31e19eda5bbc4986f268e617c07c4707cf0460cfd5d5d1383bd62b07fbf85fdf53431faebc631b47f438cf17aeb18ec3b2286f385d231f8cf1d32da4b798e61fca93dd2972131b4173d39aedf6797c438fe5bc7e06f3de26eab3e7f1319ed1d1c88a17d3e765c1f9f53ffd19ff33bc7e02f136268bfa2f7d1be6904dc26ffaae3a7d5a4f12f1f1c433c3062b0afbc40c6f1970762b45fd3311cdf20c6e3ef80693c55e618fadf27c6f1bc26067b54cfc8e8ef9a8e277fbf740cfed12046fdb8770ce3bf2686f6f357c7f5fb71428cfa312306fbfa747d546f6d1d837d26c4d89f27c7a0df0762387fcc1c83bf2d89d19fa68e21bf5e21a37de3dc311c9f12a3be7c3a067fdc1043fbc5d271fd7ef1410cfd5d1d1ccbfa7d4ddcabdf4f6f80db385e7ed771dd5ef24c0ce7634bc7905f77c470be724cdc57f5f8dd22e3786413c760cf36311c9f0f88e1faaa3a7e5b4eaf74df31f813d8cbe94b191363bdb144467ff372c770fc8c18eb23e118f2d18818f3d51531da234226ff61c4988fdb8e217ea97df48f78ee18f488ae1ffb2707c4188f5dc790cfdcfe387e9c18fd6fe718e2078f6fa3bdc49818f3ddc431e8f13b31b6bf705cbf9f85c4680fe118f44f12c3f86637c430be31bd4ff17d490cedf18363389f470cfe2c02e27ebbf6ef6764b4afd7740cfda1fea1de662f8eebf6c257e25ecd0afdab8df1949c398678da12437f0af48f73ea3ff6f7fc1cdacb2262b8dea8d6b77693eab7f49918ec1d3c20933f9d39aedbf77ac4a8171531f63f43467fe14d62d4cfc031c4a3db1ff5e51a98f2afdf2386f7f58763f0ef4b64aa2f3bc4a84f1e31eac5c6716d1f4ded637f5789e3faf82a24c6f3a3fd283e04730cf1312586fdc508d8f97be218f4d9bd0ff629c68ea1ff3931fae7d271fdbe56c8a42f53623cdfda31e8e78218ce273a8ea1bd67621c8fc831d89b11833d195d3fda8b53fb549fbc3986787b2046fb148e61bcbac4d07efa480cfe1edd2153fe3a2386e3934f62ac9fae1cd7e31dd0f9307e3c3a9f82f8c8c8de4ad41c0f8129bea23931b42f6e1cd7ed273b62683f79715cbf1f65c470bee4e0b8ce5f11473e87f678490ced89d431e807faf7791ff7cf89e1fd74450ce78b717ccf3570f804dc3987fe16cc717d3d29d84b50fcfb7d645a5f181363be3a3886f7b7c0546f4b418cfb4bc7504f5d23a3bf7a3e31ecef158e217fdd10833fc917c7e01f6b64f42771818cfea1211e05c563de45c6f8919f8e213e3831ae674c1dc3fbb7c8a8272c740cfd97c438df183a06ff5f10437fd41c19ed2d687fb4b7b8750cef7bc4988f3f1c43fc3688d11ed89f731c0f513a06fba6c4584f0d1d43bcdd1263bc7e10833f277d628ca70df239ea419b18c72f710cf9f79918da0f946388e70631e643c7989f2f1dd7d7e3d3f5a2bf276fc4b2e612fdcbc453dd1e9f3986f85a11637c6f1d437e3e23c6f8168eebf387f7c470fe32725cbf9fed91359ccf0f88e17cc1d031e8cd2b319ecf735cb7b7720ce75b69e04e138e0f2262d4831d32da333d10c3fbeccc71dd7ebe2506fb55753e383f233da8ae1d433cde0253fc27b963a87f1f91295ff588617fd5700cf9b9498cf9f90119e32b1f3986f8bc20c6f9f1d031f8fb1899ea959e63d07f9f188eafbe31e43fbc7ecacfd92d31fa53df318cdf3531dadb43c6fe472fc438ffbb2486e3334d8cf900fb4bfa92bf3b06fb2e88f1fadf8831bfb61d433dfa844cf3c38963184f6a0ff367dc755cfb0753c04e5f068ec13e5d62d4bbd2318c47807c8ec7f71c837fec89b1fe74fb63bef68851ef56c87dd4b70e31ce277a8e41df3262acbf77c4584fe37852bc06cfc4604fc61dc3fce192188fa7ebc1f84c136288a70c8f37f10af5cad431d4af0b62684faf1dd7f62f57c4d07e903986f845ffed603dc1a97d8cf7403a06fd1c12c3f1c58618aeb76821a37dd8de71bd7f2c8861ff244246bdcaeb7c732e285e831631faeb1c19fd2fbc26c6f807ff14543f071d62ac9f5f1c433c5c10837f44b43fea4934710cf5c98c18f62f7a8e61fc3932ea49b623067ba45dc7757f031f19afdfff20c6fa6d4e0cfbeb1898e2271a12c3f161450ce7cb578eebe3c51d32c68fda10a3fd34721fe3ad720cf1e21163bcf41d831e6f89d13e43c7103f2fc4d03f86fd3fd7d8deca319c2f23c6f59a37c7609f2931e643f05793cff07eceb563e8af63684f668ee1fa56c4e8bfd8ff0eea4945fba39eb0c2717d7c9c1243bc867b62ccef0932d60ffecc31e86d9718ceef49c7b0bef5480ced05afc4a817b1635d5f1fdaab837a54a58eebf3ad36c478be8e63f0979018f4c313c470be30765c9f2fb92756e775fbe86f5dd4a3ec9518eb919d63a8179f88a13df9410cedc54de4beaadfcfea7cd171f938cf8029de8ba963c85797c818dfe98563a8bf27c430beea1999e6ab1bc790ef5f89513f768e613c97c8a44f3bc750afaf89d19fde1d833f05c0940f459718e32b24c6f5ad27c7f5f1559b18ebbbc231e48735318c878e90319e53bc1e179f5dc7109f9a18eb7f9f18f3530bb8d3c4fa6b448cf614c4b85efe440cd7cb2bc7503f7f1283bf78387e149fac24c6f83e770cf3ef6b62cccf3931b4cf0b62b087df41267de3c478bd8563689ffa8bf1bd9a12437fe49563888705319c2f5a3b86fadded0ff196a3ff74d0fefa8c18e7b397c418ef1b6238ff8aeca7717eaf88a17d6fe0b88eaf780cdcc5f1481831ea4f488cc74f1cd7c7733c7f97ec9b12637f2f1dd7ef577d62682f5e3baedb0b6e88410fd20632da77e53b86fedd13c3f9f88763b81ef73eb4973491c91e77c03decaf067bb8f979ca1c437e71efc378c457c818ef9213e37c76e618e205fae7f279ec3b867a66458cfefdea18f2df8018e7c3ee7888c772490cf61260ef6ff9b0e318f42320c67cf68c8cf1935f3b86fa76428cfe72e318f42627c6f82a9131be3cda1fe34b6c1d43be7a25c6f9f61d31b45fb489b17d0f19e3c50b89b19e881dd7edc92931e6e737c7506f3c10e37add9818ce172e1d83bf48e02eda37578e213f3c12c3f9e4d2318c678f18f3f32731fa73e618eaeb1531f8efeac9711d3f4223e3f8792f8ea1ff0531c6937b1fd707df1d43ffde8871fda4725c9fcf5f23e3f8f82362ac27568e21feaf8851ef3e1cd7ed853e31c4ab42ffede278f85b626c7fec18fcaf4b8cf6891dd7ed6bba1eac5ffcbde3fafd08f289203d080531ead5c431f4df2746bd8a8935e80dfa638ff4aee3b83e3ec5f1eaf561ffbcf6cf6ecbad472f8931ff6c80297ed91019f39f8c89511f0262ac77ef9031de644a8cfaf14e8ceb6b23c7107fb43fc6935a13e3fa55e518d6b724b08b8737623c5f460ce7f31362ac1fd78e61bde18218d7a3ee91b1ffde8118ae27fb700cf1bd2746ff2f89e17cd9ca31f8db0b319ccfbf4246fbe96b628cb7d231cc17a7c478ff413986f6e97a313efc1631facbbb63c8d7b7c498cf0a64b47770498cf67c750cf506b58ff1b272c7e3fcfe11b887f6f7cf88e17cded031e4eb1c99ecb524c6fc3a720cfede2486f622e618e2ef8a18e2217d42a67cfe408ceb0b1f8e61bed02646fdb8730cfa48fdc178f3a87dec3fdf3b067b3b86fd57b5de7425c5539e20e3f8eb0019e3211b3886fcd620c678c4f7293f24a963f0e73931e6874b64f477b520c678ba2686f1963931faf73931f457558e411f3d64ec4f7cef18fceb9618d703df1c43bddb22c6f15a13a37db78e61feda2086f12ae87ad07edeab63d0932631fa77db31d4abefc4a8df53628c5fe618f41bfbd7437dd21d62cccf1b62acef43c790cf2431aebf5d11a3ff9f3986fe3262f47fb45f0fc72b5c10e3fd940b62684fb488c19fd317648a878a18ded774fde8ef058e478fea972d311c1f158e215e2262383e13c07dec1ff71c43fcbaf7512f5ac4703cd78ebd7a7ff4cf3efa9fdc12c3f1e18018f657f5f8f6bee58f5b625c8f9e22533c7062183f75efb8de5fbd20a37f7b0b62cc7fdc31cc3706c4303e95760cedf9c8e49f743d58af68f73eae8760fbe45f2b498cf92f750cf54d498cf58d720cfa3747a6feae1cc3f137c4a80757c4986fdcfba8072fc4301efa1c19eda3e78e416f5ac4180f2f8e411f36c4e86f9a18eba72bc7f5f9bd1819e33f0c88315e3262eccfd431c4e79a18fd3521c6f5257c9ffcb9108e21bf3591d11e5c11c3f5f28018fc33c5fef551df78480cfbe7b7c4180fb1e3fa787640c6fa54c3f192eab1fc0c98eaa3e2d531ac972c91e9f34163625cef6b10e3f82c1c43febe40a6f9574c8cf5cb9b63f0df7362bc5f3027067bea0132c643f94c8cfefb4e0cfd951130c5837a20c6fb272dc7e0cf0362f4df866318df4b62acf7f17c3db44fdc2346ff6d13637c2e88b1de7c700cf9232646bdbd43467b551e31de0ffec6a0276e7fcc17ca31e48b4f62f0978a98d6731f1c433c6862bcffb324c6f9db9c18f5953986f55dd71e9c2f467feba3be161931f487dd3b86f87e22c678ba700cf3bb15318ef7dc31c4fb3931ce9f668eebf8f0713cfb54cfbf12c3f923458cf54d8f18dae73b62685fa23f52bcf18818cec7410fa420ffb921c6f719b1d7a9fdb9b647bf4df3f172848cf11224c418bf05328e5fd521c6fcb2700cf9ba498cfede06a678083c62d4d7d231d817cf4ffe5e3489b1de081d437cdd11437b5221e3f5e79e63d08f73623cff16993e9fb022467db8720c7afb498cf5fa3531fa7f0c4cfe575d10a3bfcd1cd7c7ab8418e71323c7f5f8491caf3ef63f3c3886f8e1c478ffc52786eb53743de84fdcbd8ffe8afdedd37c4f13a3fd26c4d8fecc71dd7ea188d11e57c470be60edb83e5f3246a6f5aa7762ac1f9b8e411f1931cee7c81ee8ffd52db0a0faee9d18ebb13afefacaf96b4e0cfbe72fc0e49ff99e18f59f3b86fd67c8f4f99d1531fabbe718ae3f43a6f9df8118ebcf6b648c2f754e8ceb692362f41f883f457a97df1363fd36740cf9e18e188fcf1dd7d7b37a2686ebc9b6c438ff7c47c6fe562dc7a0670131f6bf700ce3352186f6abc431d873410ce70b1b8eebf12b9e90a93ea3fed2fadcda31e4a35762385fe91343fbace9b86e3fd6c8686f3125c6f69963c89fd43ec67b211dd7ede50fc002edaf0262b4ff1b31de4fbc2386f6d4d071dd9eae9069fe714d8cf5684e0cc78bc431f40ffd4f08d0ffb08e57e1f459b78169beb812c878befc0299eaa10fc7600fda1ff35375e918f2e91698fc2bef3886faa44246bdaff6c4580f6862385e7c22e378471131b63f760ced3f20e3f8463d62d42ff73efa7fc3311c4fede1f8461298c633e938867c7a4e8cfdbf2586e3454c8ce33147a6f8183b86fe3d12c3f8fa1bc7757b2bb49f10a8cf1dc7b03ed422c678481d433d551263bcb71dd7ed7b6b62b8de00c7477868efc231ccf7c93e1eea3f730cf986fae3417be51bb0ec0057d09e227f2aa13f4eaffc0131c6cfc131e8cd3932da33178e417f1f88d19e0a19fd29d1c4b8feb1700cf1774b8ceb6d1132f9ff3786f6bac4b8ff9b63b02fee4ffe14e6c4a88f7362ccdf9218ec95627b4e0f4ac770bd8e717de4ce717dfeec8c18da9337c8e82f719f188e8f9e913dcc67f43efa4371700c7abc20c67af49318fd09fc41c933acf7278eebe31f37c4b07f922077f0fa968e21fe1431deafa8fd413abd29f6c8146f03c7f5fbd59218e3e10a19fda39a11a3fe53fbf4f9938018fd27710c7ae0f6c7f178745cdba77c02a6f14fde8971ff0bc750dfe0f5d0f856ca31f8d71b328ea70c1c43fb43626cbf720cc73b46fbfbc838bef10b31c6fb9363c8dff7c4e8af787e1adff08218f52c24467fd4c838bef92531dabf4f8cfb6f1c83de44c8d85f3520c67abb4d0cfb871d64ec5fb024c6f9589318f6afeafa4f6af29fe41119c75728c7d0fe1898c6b73a27c6f9ec2b32d5ef37c468cf01325e5f72458cfe5e3986f86e12837df21cd8d81bfab3760cf54b490cfb470fc868ffea8318fbf78d213fee8971be3927f66bceae91713ca25b629c4f3788e1f878818cfd952b62f4f72762685fc1f86985fd8b2ac7500f9d13c3fea940c6fe54af8ec11febfca5ce9d7e0f808dfe427f1bc0643fe918de8f77c8d83f79e618e6437b62cc7f8f8e410ffac8145fd41e8e679402537f93b563b89e2762b4e78363580f9c11e3f8f490d11e31770cd71312a33f3d13c3f1215ebfa2f15c3a067b1d88f17a226238be6c39f6ebf6a93d0f38abf543397f8b3f91b1fd5c13a33d27c8180fd12b31fa67e6188e87fe39ff294ac710bf37c478fd5bc7106f9218ae37ec23a3bdfc67c760cf3631f43fa2f3a33d045eafc2ebcf9bc438fe2362b417f89fd678bdde8c18ebcd376268bf7a715c1f5fd6fea89d3fe757c8140f37c470fd0531da3b7b770ce35322e3f5aa8818ce1f57c064cf6ce418ecd324467bec1dd7d79b6e91d1bed9d2319c5f21e3f5a5e78ec11fbac4d8fe0b32d9bb4f8cf58a700cfa4fd78ffd49f07c64ffaa24c678f9740cf6dc13e3f81d90c93f68ff0ebc1fa4c8e8ef72468cfe50ebb1f65c3e2b91f17afd3930d9773521c6f87d41c6f3cb07646affcc31d877400cc7179fc834be783dd4ff22710cf7131e88d17e73c730be2132c64770e7b87e5f3c23e3f509e918fadf43c6f1136f8ec11ed89e87d793d7fee975c81ec52d329e3f7e44c6fe2697c8d8dfeac6717d7db202a6feca4762783fba40267bfbc4a81f1fc8d89f64428cfe7aefb8debf7a47c6fe9567c4d81ef68ffa5b3e12e3f5d7f9c5f3487fa319308d8f583806fb2f91f17acb5764b44774e3b87e7f95033b7bb789617ff6e218f67f4046fb9733c770fe4764b2c73b328d473dfefe377b7f22e3f16c868cfd8d6364bc5e1502d3f5a85b64bc1e31770cf1db42a6eb79720cfdb944c6eb0b43c790df52609fecfde018e27f808ce7af0e8ee1fc703e9ffa173591f1fcfe0e19cf579d0153ff04be4ffd6173643c5e7ac8783cc3f3d1f58919321dff888cc7b367641ff871c3997989ffddb7d6165c70695eec7ff72dfac59f3e267f852dfac59f3e267f85ed492f4e7af1d5f6a41727bdf86a7bd28b935e7cb53de9c5492fbeda9ef4e2a4175f6d4f7a71d28bafb627bd38e9c557db935e9cf4e2abed492f4e7af1d5f6a41727bdf86a7bd28b935e7cb53de9c5492fbeda9ef4e2a4175f6d4f7a71d28bafb627bd38e9c557db935e9cf4e2abed492f4e7af1d5f6a41727bdf86a7bd28b935e7cb53de9c5492fbeda9ef4e2a4175f6d4f7a71d28bafb627bd38e9c557db935e9cf4e2abed492f4e7af1d5f6a41727bdf86a7bd28b935e7cb53de9c5492fbeda9ef4e2a4175f6d4f7a71d28bafb627bd38e9c557db935e9cf4e2abed492f4e7af1d5f6a41727bdf86a7bd28b935e7cb53de9c5492fbeda9ef4e2a4175f6d4f7a71d28bafb627bd38e9c557db935e9cf4e2abed492f4e7af1d5f6a41727bdf86a7bd28b935e7cb53de9c5492fbeda9ef4e217ea85e29a7bdc37afa0e690477f051ff8c57a11f384a73ce3392f78c92bbee26bbee15bfec1777ccf3fff1abef00bf422363d3ff00b7ec9aff835bfe1b77c60fe75c787e667c4c77cc2a7fc9e3ffcf9bef06fd68b197fe44ffc99cff90b5ff057fe66b6ef7cc91bbcc9cf788bb7f939eff02eeff13ee38c71efafe01347d78b9409268d0dbafc8629a699c77c16b090452c66094b59c67256b092556cc5d66cc3b6ec83edf884edd9273bfcf9be7124bd50ec825db22b76cd6ed82d1b98bede99d7908dd8984dd894ddb30736638fec893dd7af397b610bf6caded8bb3966c796acc1f59fed1b3faf17acc9ce4c5f5aaccdce5987758d0d7aac6fde4a0413c258e1c5d8e0f91ffd082994d0c213be084428227610f1ffaa7a2112918a4ce4a21025bb139579adc4da586123b6e243ecfeaeefffc02a622f3ec5415c884b7165a2e54fca313fa517a1b81637ec8337c4ad18304f0cc49d188a91188b89988a7bf1607a3933af47f1249ec55cbc88857835db37f624deffde3262c9ee454334c59969f74ff18d9fd08b40b4ecdff2161dd1153dd1173dc92593424aa9a4668fd233ca3093fee34606329491103296894c65267359884f59caca68c86fbc46aee45a6ec495a9c8fe04dff851bd905bf9217726773ec9bdb1c48029f9290ff2425eca2b795d8ffd83bc91b7c60a57a294037927877254ff8ce5d864d6969c885b3995f7f2417e6711f1261fe59388e4f3aff78d1fd50b39973bf92217f2550c8d3f48e3116ff25dde89b55cca866cca33d9926d792e3bb22b7bc60e7d6b0565128e124a2aa5b4f991863c3652be0a8cc2923d9e54a82215cbe7ff35f442252ae557b26b74c2fcb04465a69fb92ae44195aa32fe7fab566acd7ca31e635b5ba88df18185daaa4c7da81d3f533bb5373f85fa540775a12ed595ba5637ea167d63c65ed440ddc9e7bfbe5ea8a1b811e76a647c40aab1e9e3c48cf15469e3fd4cddab0735538f6caa9ed4b39aab17b550afea4dbd8b955aca816aa8a63cb08d3a33d613f54f617e846aa9b6fdcbbda41ce25e7555efafaf17aacfdafc499b09a8cd1a669473630ba5f69a99d12fb4d052542604b4f6b4af031dea4847c63306e256c762a8139dea4ce7ba404be4baac8f371123f7ba12a01e8f7aa5d77af3d7d60bbdd51f664ef12a467a2799deab83fe54b91ceb83bed097fa4a5feb1b7dab07fa4e0ff5488fa5146b35d73b36d11373cc54dfeb07638b99ceac6f70f3d28fb53573fd64fefdace7e209bc43bfe8857efdebea857cd66f6c2b1746074236513bfd6efa71a197bac11b2cd34d7dc602ddd26dfb9774c58a458a43e6906f9a99bdbbc67699ca748fc5ba672cd2d7b9c73d66226c6fdab13f058bb4a742a83d3ce1491eff55f5c2536c6b7abd161b3df5b4f571fdae97f64fa27a816c1b9d1878a11779b197e8c444cfa7f0f993a9cd7722b3ffe7732f557b9351cfbc4c4df4cccbbdc2a84d66f694c6b746a6b527638fcc2bc51c728a57792b6ffdd7d40b6fe36de58085a662b8f43ecc54c2da61e7eda5f43ebd8377e15d7a57deb577232ff919bbf66ef9ca1b7877ded01bb14f6fec4dbca9a9d67def9ecf95f0989dc3eb2eef98bcc24cbe3dd4da61bc434ebc877a0ef7eccdbc47efe92fa917669ecddb62c312de30b1fda4f6deb3faf49e75d79b7b2fdec27bf5debc776f29efbc86d7f4cebc96d73699f1b735a4f2cebd8ed765d2ebd9fc63f289a9bc74ae98d7c73891ead3e7620aaa21573ee3c15f502f6e7d21195b1baf80eb2ecc3816c6c34772e94bf3a37ced7b5e9f3f7b53af656659ffa01d53537abeef074cf2b6ad348cee1a35e11d7df0c3da370abd14433faa6de1f1a9ff4b6ad03fa2177ee2a7bec9007eae3339f276b5358ceaf1865fe8815ffa95bf929162fcd95ffbbfa33d91f85bff830f6c0ef136c6339a6a27c7b577987c6bce30f777f50ceec1eba8e15f492ffc3ddbf99fbccd125b6f1b4b1430869ea92a7ca314fe857fe95ff9d7bca5fabf772cfc1bfee0df1a6be4bcad73a31b4645a5d1623fb46dab9d3fb0f359ffce1ffa237ffcd7d10b3ff027661a71601329bc9dd5fb5af305eff853f5e85dfaf7fe83995b307ff647e698fea3899627ab42bcc39ba6963f9879cdb8f63853a38bd2af67f6fedc7ff9f7af8bfe5ebd90cffec2879a39b3f9cf8e9b79997fb1d47ff5dff4c87f3713adbeb8f9e3f580bf64c26f88dc7846a3ae408abadad0bae42dbf69eb50e97953ffecdf3d3ff9bd7ae1b7f895b73579636366db63f4895c1dd895dff6cffd8ea9273c16fb5d5327fec098782bbf67f27357657edfe4205ed719ca7a5dc003663ce3311081349af197d08b40795b9bfb036da21ae610d62f3ee524f04c84dc7837811f0441c8c31f1a9338884cb5d15259109b6ab4ab0fe017e63c2c4882d4ae6b0459901b7df90be84550980899aa2228add6431da097721c5432d403d60d5626bf7c78ad1f1d93601d6c4c8eca4d15fa116cd5ced4e53af83067e16c14eca4c79e83bdf1cde8cfd78be03338185bd8191803bfb01935b8d0fbe032b80aaecddc7d62aaedcdcfac4505377c6e66afdd2096774641c7a6eab035e8c1fce656cc834170170cc5f59faf17fe2c1819ad3fe367c1d878726d15bb12c326c12498b2a1bc34b5e321b8ffa9b1894d2dbaf57ac61ea98995077b96ba1e1f05b3c0e412b10b9ebccebf731df4f7e945f01cccf9b3d5365301b4eaf539bbf2c0d92a78091662a819fb085e7ffaded747f06694f920ef8c66ec4d255a584d32f93b0fdee54ccc8265d0089a7fae5e98f13e78dbe02c68e91e6f9879d4b456f88ba02d97c1b97975826ed0f3973f3b36fec6f4d5cce2a5b0fac93b21b77ee1ede4bb17f8f5bdb6a011b23f572f42119a79839e09a646d62f4c1cdb1aa0d02c54a1964b3343d986decf7fae423e873e1fc94b9355cdbc5d77ebdc5d5a6bb0280cc2308cc2d80ffe5cbd08599884298bf4334b94f58bbc9e4b16621c66616e66659c7d98b9e411c626688685649ea9b994a9bacc9c6faf9fbc9df18c376f1e9662e68dc38a3ffc797a617243aa5a26930ee4a75c58bf3075858964f5c917e14a05a2c136ec3c3cd2d8f8db706d3ca32b2f4d0d9aab8f70637ce3dd33755cb80d3fd853b80bf77fa25e78e1a738a8891c88b55c48bb52f704b305c9c34378a13bfa22bcfcc91ce2b66a185e85d78249667dc3f8433d6bd5cba0d497d267f3f02650e1ed9fa517e18097ec36bc63eb70188e586c6c51d6f3854f9686e370124e593bbc97db238d51e889f04176c558303d0b67b6ce000565a9aea4173e060dfef1efb9a7f63bf442874ffcd6f3d95aacc530e87cd38bf0399c872fe1820f3c79acb1e19ffe327c955dfe22989f07b1329a61ab71e38b997f1ebeb197f03d5cf2f0cfd18bb02152fe14363517b7e61713de0acfc296f58bb01d9e871d2dcc3ce4f57863c49ade547464972561d7e4931ddc71d4a51ccb7d7813f6c27ec423f6ef98b3fe6bbd88042ff893bc64eb60256ef9b2f68b835d8b129b480622527e4f5c1e6f8ce473a423cfe4a6848df5bdbce36d53cf186b78bbc88f02318fc228525dffcfd28b3c8a8d5e84c62f4a7b4fc466399bf7e5204aa254dd0487288bf2e38d515444a5ec6aae7b62547b86bd0957dacc1a2ca24adceb2a5afd3b3e03f8aff5221c44eb28f67c29a38db8d53bbdafef08dbda338bb6d28f3ebcb9d7f4ce8f3546fe8d484418ed8c7e8ec4584fccf964bd5e7250e682a37df469a3c43b3bfe9cf5f7d5176ce769311403b551733327296abfd05e3fb88a0ed145300d2fa3cbe38d918992abe85ab5d9448ce44035eb95f2bafe34f5792bba896e23ed4dc3c6afd70b13252c1a282fba0b56d150acede70b3cebb76606e9bd0477d128ccc5215c46471b2333170da2b11a4513964453e37df77595a1d4d46c5fa28768163db2dc5b79ed5fad17763e123df18e4ec46dfd398acbda67cbfade270f27e2297af682686e6fbb1f6b8cfc71741979b21bbde87b16eb3d5a5fa99c4da285f1c5d7e8cd7b3cf69cf5f7cc47a277ef36e4e6ca96d150be9a5afcadbe2f92ab0ba39e8da8199d45ada81d9d1f6f8c4cc6f4c32b9b4ba20eb36b3bfdda338c2f060fde6bd495aba8c757e2ea57eb85dd467db63573d427518aa1992bf4e1de883a9899ea4185310fae621684478d5f150b3689a5a93fcdcc3588eb7b103067ed8b66ac621d7b3c3dee770e7edf7aa73fe343fe1efb621807b2eb6deab9597ddf330ee3288ed97d9cc4e931c728cea24bff2dcef5b3189b5ab719ce60edddf8473b2ee232ae642b5e89c868cb2fd50b2ee23537734793439ea46413cdd4bef68b42b178136fe38f78676a8c79541c6f8cd821def332e8b3095b9baa2b0a62b7e2dcf58bf833dec587f8c2df9b68faa57a61d715e24b3e17eb70145fb189bcb3eb0ab52d3ee36b91a8d0545c0f7c1cdf1c337ec3417c1bc53697e867160763c5ea3bd95339169bf0100fe23b7d25c260fdabf5c2f8ec50e472118ed4dcd4835d25e1fe88fd94623c3293c6a5df66b7f1f898f95ec4f144ee545b744cc575afd3baf637b9442fe3697c1f4ee2877021e7def87873d6df7b7fc4fb14793c337ae1b3500aa39efb3a7e3ff5d2bb881fc55206c6164f3f7e7fe4ab6df41e3fc773b9883a26b39a28d18f36ab0617ec9cade2977811bfc66ff1fbafd60bb34dbd0def5abf507316d11cc1ae39a92c9c9b5cb264a5b1c6916bc1b8692a9b775b7ffad7f5faa799a105178aeb697ce63fc7adb81d0cfdfdafd58b3a972c8240f3d8577331d2793d46e81b46d7cfd98357ea9db9b223e692c74ddc89bbaaede7626ce6ac703742d84f320565dc8bfbe14dc2c32ab1f7ea7fa95e703361e273a3e8a130a3a29a768ce0beaa5e2632ec272ad166463f39662e312f9d78a2239918998a8be9bcae7897aa30fac9139df84920a7c16b12fe5abd78dc245112abb6c9f743b19197668c0aa805bd5d78ed6fe2384992948f227dd45a30622cc9820e5bdb35f824e7678a9b11a8d7e093427c24651cf232a97eb15e8878cf243719351c31334a416caee850cf9872d94f56c99a3d249b70986c8ff9794c11271fc92e8ad5c85435a6e83019ac50a25e3b79637e7848f67a9e7c7af23873d63ff279ade4905cf0d770a47746cbfaf51dd5bc5e7392ac6fa2e432b992fbe4da5f1eb316f4da6c9fdc24b7c9803fb18d6ed8cf0e9ae8dc2b1337c95ddc4a86c1345c86bf582fccf6815db3b6e66a2ea54e4d556c6c918cead9fb241927133f52eb649adc1fb31694cfc9835e27b368cc6e95f0eca710f0ceb6defb45f2687389b8499ef8fe57ea85dd26cf463fd7f19518ea7bf81c86b1855d996d283fec2473d962efc98bd1f523e6127608d6d1557c1b0ff9796d0b6d7c439a735f9ab9914af661962c92d7e4e157ea459d4bde025b774e4d36199bd8ddd367fcbd3e5b27efc93269b08c8f9223af2bd8ef188522394bead5f7fa9c665698b4599c9c279da49bf4923efff8b57a61d71552ce5b29333586cd2567b6be80352ecf97217b488599975cc5aba3e6927a1bac138f5d9af8e0f80d8da9d79743d655b354ea2b95a62afde9efb7fed1cf83ab946da54c3d969879ebce5c99a8e768b91ca57e1aa4619889db344a8ffed9fee4234d4c8785fd5e42ed8b5a8ed38c85d15bbcf35ff98197ecf3d7ea0567699e5c041df969fc62909a397b3d939e9a5ac36393b48cce829dba4eab203ca64fd82ddfa5ab746defe27a1fa6e6ddf3677d907dff3aee85f36062742cfbd57ac165ba8906c199a93142b69697c6333ef173a9f613dd8fe9364a8377769e7e70753c9fa8b71f6cc976bc93eeec67113c6e6601b9fa60917723e7e93efd4c8ff07df83ffafd11ff9171cf1483e9855ca497e6bacef193a9f6537d9da413cdf4ab8c63965e1d572f184baf8d8d6f22df545ca96aa6b7661ec0c4d05b184b0c828d99affedafaa2de069ffc8a37e4423d59cfa8bf41879ff79497e95d741b0ffc221dea453a3aa65e784f5e3335358664aaad326b0d9d0a964e582f9d069b64c71ffe892fdfffbecf85fec0f753c3f441e4c62f3e5353fba90f132512d6a8e5bb3c0f6fd2595c88327d3c4e2df86d9b3ea56b6fcb9fd52e7d363380a6caf88b5cb0cb7498ced3977f7c5c3c4e177ceabfe8b57e39ae5ed8adbf16b960d18bd50cf581b5b899c17b3b1337afb14adfd2773ee6f747d50bb335d658b296c883aec879cbcc8daef96dda489b7afbcf8e0b9468fbb7412477c66a67110f86ff68ff1ff97e6ab8f2365ea1797ca5a7b25747491e7cd839bceea6adb49d9eebebb4a3d263dfbf3075af97764399f6f85ddacf78c632f1af3eef297326789549f6942976ce6f329d79997f2cbda8bf3330635b9db0502e78c34489acfd42fba11c89db2c0896aa277a59e81d75fdb3de463c5449166571ba096ffff9fefe583e6789388883f2c52c4bb3cc68dcb53fcd72b6f45a47d20bb3f5d759c1bba98993acd4997ca75a501dc2667c1675b34addc72c5bfd7b3fbffdd5d6b76bf677d93adbb073bf17ae334f70bdcbb66c2e97d126fb48baf14db6fb7a5df6479f7f91eded2a97fd9eaab1c51b7d76462fb34fef226ef9cfd19b28f9e4e76bc1dfb7f5c77aebb532a112711333fbd42676ced67a9a4e4469bf55cfba2c531b21b283686617c936bbfc6a2efda3cfbfc8aef84d10d8fb9d7685458e8d5ed867177c2a26c6e95b761dbfb055762342ef88f72f701b7df73d124fc5fe325cf10daf8261348ee6d9addc27292b752006b16f227560fc61190ee52bebc976a4b24a24d91d5b7eb52efbe3cfcbc9867c6efd428ce45dfddc02bb2e5ea84fbd0fa6d92878ccc62c4d5e928fe3fa80fd6c701289883ff8beb140994dd832d8f049364db4f7ca4ab1625da1ed3765598fade2fbec3ef6e45e4a93e51f64983d64b3ec317be29374732cbdb0dbec599c1b5b6cf47de4eb9ceef0999cb20b9fbd755c657319f3c9b19f55e027d94bb6c85efd5636d11f26331c84970d82a97af04bc94d5cec8c3fbeb13249e5793ccadeb3252ba389b80d2a33420d35cc9ac61a67c1306b1d4f2f8c5fb4d96d1028bb363e5159fdfdebf7ba023db04d709ef8c9a39cc64c2f8eb7fe99ed93add18243a4d88beab04c5e1ac51a64e75927cbd8cad4a0895d71b34f53c8baeada6864cfe48f3e2bb36eb8f4dbde59ceb38b9ce5227b0a32b63c9e5ed86d2eed3d56cd4d0d3a09da5edf7ea6cd7e2e4333e320fa71937ba6429e8b23e592dc673bb6cb83ac2b3ec52ebaf10bfd2c56799847e2238ff384ad5924c6792aeff22c9d7873fd6abfc128eec3439ee7455e8aabbc92d76aa6e2304fb6f9ea987ac1a5deb25b761e8ee4a71c18fd045bd4f33416e6eb6cc4eea356bec9b7fca7ef5fe41fde2ddb05815cc889a9bb57de6b706db645ba0d96f1367a6366de6cecb2538f828b91b6f96d98eff3cffa7b6a7779fd19915c8b66d265f7f2d6f8c590af12713cbdb05b1b25d18b5d17d7b3fa53a9397e1be823bfc82ff32bb1cdaff31b91fc58fbfc33bfcd07e9a7b84887f95d10e44396d8e7fae5f693d8cfea3a1fe793a4112e445f8cf2a91ee5f7f9433e63f6735e139f7b41b4901bf6903f8a5dfe24bdfc39dae73cd1d92c9f674fd9821f8ea717f5f660e6ac037b5791c59eb69f0ab09fcb08edb31e7af22c5ee42fea9a2df5f60fdd0b8f8266be089ae19599d38ca241f4143de5aff99bf0a4fdfcc1bd9eb291f18faef18bbec9193c1c194bbcb34ebecc1bec396fe6b1181b1db93433fa323f0b17c12efe604f792b6f87f3fc3c9b5abfc83be226f9fcfb5cf2b3cfe34bfb7c105fe55d3da9bf7d05cfafc8f532efa5af795f050597fb82fdab672215a2905e4bbfea6da13c59e8e8a9f0d26161924611445e1186f6392c9d2232bebf968b22e2f6f94d8368a3e3686946622d7a451c054522766259987258de055b3589a659371d644fc9dc7e8f317cc9abec29cc8d4f348aacc8c58db9b8a3e985dd860f41507bc65832fb9c026b09eb1bf2ad28b2eba22caa62c596eaee9fb553ac935d94159b625b7c444fe9301bcac458601779a2fee1b6865d8443b6b64f6312b7e1d05493a9dc8ba1c91a23fb19505355ac82243e2bf67ed3541377f2c03b6a629f076732ab9717ec25fe283e8b43786eeace876c5a5cc8b0b82cae8ea917761b748b6b35d7cfc66b85b185c46f0f8ecd58dd14b7c520bc2ceef8c73f3abe50f1387ee287e08ecd83cf62588c222fbf0edbc94078ecddfa81e9cfabe95f47dca617f6dfc5b898186b18ffe02f700fbe98d6ebaf32beaa9f4671e7f7ed0a6070c66ed4c8d43a2ff95c45d14df419dd14f77915a9e2c1f8c54cdcf81fc5e311f5c26ced131a4dc5bfb6ab5cba5e1337758636f6b82a9e541855e226fb87c79bde3ff31b7e53ccc3883d679be225f28c472c8a057f0b87cae802337512cb8a57534d3d8a81b181f18a622c3af63dd5566dc94c0e9b79b9fd8ea4c96507336bfed04c656a12f44dd5c38c729ccb56d415923d0a19758bb75cc89616c62fde8b65f19bfbb03ffffcce3815b9b85563cd7daebbeccadbe965bd36be2b9a712ce6c5d957df43e79f45ab6887977920657ac1fac579d1c98c2f181db82dba461b7a5617582236ac1fb76510c745bfe4d62fc46dc944279ac86e29d8c6f862aa53638333eb096a2245fdbdd1862942077c10f4830eebe9ab52b1273353f5e2f3681fa952979ea9cccf9383a9ddaf8ea7175c94beb795e6bfe8c5aa7719e8a7da2f94927c51246558467ff71d827b533daea2391f4703b6339125d9da68a17d8cdd44744ced38f217c61663eb13561d582f984637a66e7ac93e4c9dd5b1bf37fe302963d5b4cfcc28131b11bc632d617c61a226c64726968320e8cbae28e5d2d49b4de98937e99769f6106a392fb332d73e3f94c531f5c258a314a6048d5ed20b7daf9aa61acfe1797bc1367f48e63c2fab72e50d8a46b90eafbc6eb12c37e9b0dc961fc9a05894467da39df1fab51d6bfe5eeef87bb4331678afc7dee8859e668372cf9ecb4ff560de1772a2ecb7f2263aafbfe36c7eca83f5049595b2bc088c7f9497f07baf179c9557e1b0bcb6b984cdc54c980c6be6aa8df2a6bc2d07e51d9ff8c931f5c2ae439643cdd593e6a602bdb34f92c26f457d94a364e99d672fe5b89c94533ee2b7e53d1f951faa145ef9213ae190bff177d98d62f37fab0d1deb13f483be7129c6e98368aa1e4bd5846da09f2667d9e7a834cb076b05deb0df5bb4f681df7f7bb18d992f75a2b254e5ac34be9517e513bb2f9fe579392f782292677f763cbdb0b92068972fe130657211f9eac35843a9bc5ce8cc2fcad7f2ad7c4fb2725936cc78770ad35f9b1be299898777ab0b6a549ae32c1791d18a9ee89446f12c9bed24e8f086974b667c84d9be5a5da86dd13431d0b7df55e40d6b0dfafddf6f4ba97bf6d991c153d92ccfca56d91649792e9765a77ccf1ad926d3feec787a61b76597b58cc68fe5a7f18fcc7e12d30fcb9efa10dbb2cf9e2b5e8c8de7c7266398d137c2b0801f517a41f8203ac637de6c6e005f3036b2738e89bd638be39dd9f88771ae9f0a31a1dfdb57c5fede17be7fa949258c1a9d57b2527215cd92b5baf15f2b9d4d63aff2e49c4ff43a681e4f2f4c8d9197db20101b31323561a3feeea0ad31de8d7a3ed8ef947a015fb249e59b7982c93955e0053216039b13f8ab1a810f583f31f972a246fc4576ab50655e513fafce8d7130d65d3dfbe60be5a1d6cbb37fe413766befa384d7729fb6721e6fcb66320f27c179795345559c96a55f257c94b58ea717765bd9e7792ecc1ceddeaef9e983d50bafaf3eaa2c6fb3c7f03c7f6393283639736172dc6595a7af7ecb5691d607d4087482bffb769ed195cce48889fd763ff881cd0bf5bf9a759e305ea29affcc177efbb2478443e31945a9c47d55569568c687e4ae5a85efd943b50e36d5e6787a61b7c13bfb30713908b65eeee5bc659fbd68ea0cae9e632d66712ba84c8dc8cd3cf3b5da268bcacc96bcb58c4dedf82a17a017b2ebf3a09fd423a9263647940f6a92d8e709cd54667cc2f03ff781ffbe35d16a9fe9969aca2c2d6fb265f9c9e6d5cece57cba76a6fc2eb5e96e2267ed2dbe3e90567f198b5d496c5726866462cb0cf1ab46b9f4c8cbdcfea335cb19e1c588f576d534f5e47afd5c17f3699dffa45574eac32d8ba31a82b26f487a6197dd28be6b7dcf1475ef62988f648537fa681174e6c2e896ec249945417d52a9b49337baf2e855f5d1d4b2f44c2ed9a772e85bcd37b316077a617cf8a79a6068ea6c175e227976929a58df352a86dd091d33c8fde6cede873d35f51574818dfb0353ed1acaead2e180b8dff882f7cb535b3b475f621d7d58d5dcb48e601cbaa9cc52fd5453e4eef926b98971c412f22af69ff9e447026c7416c3fabcd4676445556d78d4c8878c99ec5b377632acbc4d41063336f49ec7382adf7436feb279ad663693d03fcc2daa3f6961ff087ffe61f0db9f08beca96c470731f7665555dd26efb1ae06d9347be0651616eb63e84575c787de7d3e2c2f94f4bc602cc67acaed1c32b3916f7c60efbdd9b980df166b9644bead9df47d3eb2969097b257e7c64e30ae86ba2f0fd5e8fb312d1fcac3cffa441d239791cf7a455e8dab1b363391d2ae262a48fc6c1a4cc4553e4f3fed036f7e522fa274c85ad5d4334e974ecd9c91d57f4b600c39cfcc1bbbdcce283ad5bd96a257d70c0c34c0f886b184eec1d6b0ed33fbfbf1b46af9dbdffd3dffee5743eefd37be8b6ec53cecb197709277f4b07aa8bc6a16a9a0489f44fc737a1133d6e2b7324df7d563f514b7f52c3216b163eee772908f4ccf97c60b1e74563debccea85b5453517a3acd4f7660e99d8ef2647be7d3e8e1c060ff699523feb03b4358af53dcfe4221bd815bfeac5ccd296f1367b8a92709135f24915853a6807cd9fd18bf4890f446e469e578bbcc1e6c1ad7dbe8becda3984c929f6798ecc44c1a5e929fed86adafeceded7d03dfb833e92420df1a3f9e2f7bc24cbbac122335a117fa8b07acd2e42ed0fc243b4a82eb20393d1e58feb4590b34b91b31ba3919160d55e96d94076f5056fd8da534f4c6f9f4dbf7ba67eb4cffbec99d7a59c5473538bcdccdca201ca49be026cf2c9517ce2abad9a888d3c8fa2c78d0ac54e858f9bac515d44a68049cb7051bdb1ed8fea45f118b360ae26b61f7565bc3035b51d7356095b330866bf3d68fcc08efb0434c15ac3a808e8c3a5fda9b74c6dedefed8f5da7fc37f9855de719b07e7099ecf3839923bd4761ceab65a88b7d91055745973fff985e0479f1c15a660e68674ff518d7cf422e7823e8578daa2999cfad6ed8e780f386d18319f880d9c758c7ae3dd9e7a52bb488d115a3a06ca31af5fca37b5c9f3055b8d5db96ee86d7ace79fdb95e0ea4c7ad547b48fefccbca4253e8369d54e3f7f4c2f12ab990d5b2f525eb06b8df2a09a6562d71931571c6c74e854de599f405fb8b32b72765d52eff5dece35c83f20b7d42b7447f307de5266168b6cae95f5d37dd20d96d559d84b2ea5aeced97d5514cdaa13a8a0f1637a118fabaecd15667ef102f305755626b6d710f73a4d6f75df3e574f35ac35cc3b3da827d25b6b09589fb43fe9ed77ba71798c1ad3e9c3ce5670411b2bfa336d6a5c719b0e643bde563d318b3ecb76362b1e64abc8bd45b80c863fa617559f9f077d13ffcc3ebb04ea066b89fad99b5d0dabd233b7de543f1fdefeded452b6a2baabff9e80fdf9e643f57e562fea4ae3a7fcc13e6334ddf1b67daebf7dda36fdde5cd588ad565cde88b9fd9b39315f3175be122bb9522bbdf27e4c2f56fe2a303a606c5044662e6eb659a8eaf8373ed0b73e60ea8b49deabd7a42e8d6ff44d3c7cc07cc3fa4e6d1b1ac3eef739c55ae4877da3057f9f805dd92dffcd9cd6dac2ce4bc2e7609a5762c91ec5ac3a5b85ab287af3cffd76b8e4d31fd38b551c0decdf1f31b922865c6035b4bec759af49adb0beacf521b316b25586f9b7a9b2eb979b73d4d738f9e61bb5ba1e7e349f386df8f265eb60711bb556e92a136f62b6cad37319ae0aef25f6f4225aff687db12af939bf317effe05fcb81a91dd147f88bfd66edb7bac1d61b9843ee54560d8d8e7c1bcb9474c3e6906fbef1fd5ad6cfe710b090e5ca5c91a931f6ea21526c667e5e56d56a152ea2a8ba58ad579b1fad2ffcd96acb6f8c325bad18d4ab515d39a8eb4c66f24bfd32d6b0339206db983869da9c0139c48d93f114faf7f7ba6195e51839c468c66ffc2438b3e3130e5916df18cd581665f21eead547a492f7dc5fed7e743e12ae92e7aa5bd71103653387a925ed67f87d6ef4a32307661bd5fa31b3f7b6ecd68e39d50f726875d4f8889d7d808e64e41b5feb859d937db71ed132d972f77bea8aef7feff56c6d68c62e0da659b5dab37972992d7326cb34f70fce2f7e603e120cd371d0afebe7cc3e4bd0ae4dd4f776bbb68e841a13ebce7abe6135c3664da31af5b843beb07353cdec3dd03ad3d4fbd8f5cc7f994b6a7bfc717f01cd28eeb227719fb7c4cc9b8537c55bb4f73aabcf9f58bf78581d44beba905d3f17233bcfb0b5a67e30b190c29cf45bdd60ac62957366734aad8e771e66d5606cef06836f404e01dfe1cd63d69ebf594b9ff157218a3c6ddb5c2266f12069946938ad7e582fec36f94cc7defd2aa933e71d640c9859502d69fd01fefdbd1ed4bfcf6d94581f019f70b5a189a6e3e8c53ff00b9bd5bbacefbfc6dbd5257bced2ea2c0d92fd6ab3bafa99f50bff897dacaef980378d4ff7bef705332b8fec3ca5ae382fbff711d842dd257bd647709df3430eedb6b65ba39eaffc1be6aab035bab6d757f14eccea4ffaeda4bfbaf1d9cfe885d9863ee777debdd5051619addc7e3ff676b6f6cd0fbefd1b5f77506fd178ad6ee5d0decbf8ee98eeb7f10cceeccf11724b9d57a4fd7b5bcbd5203f987aebc01ef34391acee929f5def3cac86ab5179558f75fadbb1ff6e6bc7f837b5a5f1071f7ca1d60d1b13cd5ad72e7feb3bc79dabd6ff6a1acd9ef1c56a9c2f5793eaacfecb72f3ac67fc62fa73eb9d8cf37391f38189f1de2ab17df8b636f1fdfcf3fbfb9f0a7b6fd7b1e059e0f665e72cf51cf6bbfd7fd60fccecacae31ecfce4bb39c9c46479934b56f7612e9e6c94ac1e4c94dc05e1cfde1f59cd582b1f7eef0b902b8c5e5c12dbfba2565bab919dc5c3fbf667f5687e7b69e7ae3066660e6b676d99f9bd55d09fb91f622bcd1dbbe26754737eff7e29edfd92d554dd5437f03791aa9e77c67f4e2fcc3694fc2ae8c37dce6f3e613f41856b5513f81c55bd9e09cf9d87ca0c34c3cef233d48d7e6d993b581f7573963f92537e67bd61eb4f5edf2f918f3697d828e1e9eae967ef8f642d6f2372537309fb84f3efd621b6750eb9abd7b0fe4e3f6ca56eb736137f773fa45eef303e92dabf8967d749ed6713bde277fb02fc35acdfe13bc199caccfca9b77a5ecd2197b0b99caf5e7efe7e6af0965c78f7942fa08eb0fda07fd31cc3de39727587f321a8ace4a14ceabcd2af86f55f4bccec3a58ed1d47f70b9b8f4cbe9aac16abd7d55bdec4bf37b85dbdfffcfdd43009467c5035ec7cc268c0525e06ad6f7546dd5f3347b32b7f303f81dfff565f6c56ae86d5a81ad6eba17807c97e2eebd8f505ddb73573d6c5aa51de445d36afff2ee795b7faf9fba96973b5b535463dde3d53554c6cff3d5d7f9bb6616bae7aee8aeb1934e6b42efe7735c7acdef75b8de1c6f2fb5ae438f5a7a93e7b51591c581d27feb6ac8ef0f98b78d534f5e796cf4dc4ce5767fac0cd4bb58069bb3ab3dbfffefb2ff66b192f7eaef959ed43ee31de665bd8121f63cb5be5d46baed6ab56781b158c799fc7fafcc5ff1fb6fff9fffe9ffff1ff01d65fbc39</data> + </image> +</images> +<slots> + <slot>finishButton_clicked()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kactivelabel.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kgpg/listkeys.cpp b/kgpg/listkeys.cpp new file mode 100644 index 0000000..2a10a1c --- /dev/null +++ b/kgpg/listkeys.cpp @@ -0,0 +1,3149 @@ +/*************************************************************************** + listkeys.cpp - description + ------------------- + begin : Thu Jul 4 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +////////////////////////////////////////////////////// code for the key management + +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + +#include <qdir.h> +#include <qfile.h> +#include <qlayout.h> +#include <qvariant.h> +#include <qregexp.h> +#include <qpainter.h> +#include <qvbox.h> +#include <qclipboard.h> +#include <qkeysequence.h> +#include <qtextcodec.h> +#include <kstatusbar.h> +#include <qtimer.h> +#include <qpaintdevicemetrics.h> +#include <qtooltip.h> +#include <qheader.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kprocess.h> +#include <kprocio.h> +#include <qwidget.h> +#include <kaction.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qtoolbutton.h> +#include <qradiobutton.h> +#include <qpopupmenu.h> + +#include <kurlrequester.h> +#include <kio/netaccess.h> +#include <kurl.h> +#include <kfiledialog.h> +#include <kshortcut.h> +#include <kstdaccel.h> +#include <klocale.h> +#include <ktip.h> +#include <krun.h> +#include <kprinter.h> +#include <kurldrag.h> +#include <kwin.h> +#include <dcopclient.h> +#include <klineedit.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kabc/stdaddressbook.h> +#include <kabc/addresseedialog.h> +#include <kdesktopfile.h> +#include <kmimetype.h> +#include <kstandarddirs.h> +#include <qcombobox.h> +#include <qtabwidget.h> +#include <kinputdialog.h> +#include <kpassdlg.h> +#include <kpassivepopup.h> +#include <kfinddialog.h> +#include <kfind.h> +#include <dcopref.h> + +#include "newkey.h" +#include "kgpg.h" +#include "kgpgeditor.h" +#include "kgpgview.h" +#include "listkeys.h" +#include "keyexport.h" +#include "sourceselect.h" +#include "adduid.h" +#include "groupedit.h" +#include "kgpgrevokewidget.h" +#include "keyservers.h" +#include "keyserver.h" +#include "kgpginterface.h" +#include "kgpgsettings.h" +#include "keygener.h" +#include "kgpgoptions.h" +#include "keyinfowidget.h" + +////////////// KListviewItem special + +class UpdateViewItem : public KListViewItem +{ +public: + UpdateViewItem(QListView *parent, QString name,QString email, QString tr, QString val, QString size, QString creat, QString id,bool isdefault,bool isexpired); + UpdateViewItem(QListViewItem *parent=0, QString name=QString::null,QString email=QString::null, QString tr=QString::null, QString val=QString::null, QString size=QString::null, QString creat=QString::null, QString id=QString::null); + virtual void paintCell(QPainter *p, const QColorGroup &cg,int col, int width, int align); + virtual int compare( QListViewItem * item, int c, bool ascending ) const; + virtual QString key( int column, bool ) const; + bool def,exp; +}; + +UpdateViewItem::UpdateViewItem(QListView *parent, QString name,QString email, QString tr, QString val, QString size, QString creat, QString id,bool isdefault,bool isexpired) + : KListViewItem(parent) +{ + def=isdefault; + exp=isexpired; + setText(0,name); + setText(1,email); + setText(2,tr); + setText(3,val); + setText(4,size); + setText(5,creat); + setText(6,id); +} + +UpdateViewItem::UpdateViewItem(QListViewItem *parent, QString name,QString email, QString tr, QString val, QString size, QString creat, QString id) + : KListViewItem(parent) +{ + setText(0,name); + setText(1,email); + setText(2,tr); + setText(3,val); + setText(4,size); + setText(5,creat); + setText(6,id); +} + + +void UpdateViewItem::paintCell(QPainter *p, const QColorGroup &cg,int column, int width, int alignment) +{ + QColorGroup _cg( cg ); + if (depth()==0) + { + if ((def) && (column<2)) { + QFont font(p->font()); + font.setBold(true); + p->setFont(font); + } + else if ((exp) && (column==3)) _cg.setColor( QColorGroup::Text, Qt::red ); + } + else + if (column<2) { + QFont font(p->font()); + font.setItalic(true); + p->setFont(font); + } + + + KListViewItem::paintCell(p,_cg, column, width, alignment); +} + +#include <iostream> +using namespace std; + +int UpdateViewItem :: compare( QListViewItem * item, int c, bool ascending ) const +{ + int rc = 0; + if ((c==3) || (c==5)) { + QDate d = KGlobal::locale()->readDate(text(c)); + QDate itemDate = KGlobal::locale()->readDate(item->text(c)); + bool itemDateValid = itemDate.isValid(); + if (d.isValid()) { + if (itemDateValid) { + if (d < itemDate) + rc = -1; + else if (d > itemDate) + rc = 1; + } else + rc = -1; + } else if (itemDateValid) + rc = 1; + return rc; + } + if (c==2) /* sorting by pixmap */ + { + const QPixmap* pix = pixmap(c); + const QPixmap* itemPix = item->pixmap(c); + int serial,itemSerial; + if (!pix) + serial=0; + else + serial=pix->serialNumber(); + if (!itemPix) + itemSerial=0; + else + itemSerial=itemPix->serialNumber(); + if (serial<itemSerial) + rc=-1; + else if (serial>itemSerial) + rc=1; + return rc; + } + return QListViewItem::compare(item,c,ascending); +} + +QString UpdateViewItem::key( int column, bool ) const +{ + return text( column ).lower(); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////// Secret key selection dialog, used when user wants to sign a key +KgpgSelKey::KgpgSelKey(QWidget *parent, const char *name,bool allowMultipleSelection, QString preselected): +KDialogBase( parent, name, true,i18n("Private Key List"),Ok | Cancel) +{ + QString keyname; + page = new QWidget(this); + QLabel *labeltxt; + KIconLoader *loader = KGlobal::iconLoader(); + keyPair=loader->loadIcon("kgpg_key2",KIcon::Small,20); + + setMinimumSize(350,100); + keysListpr = new KListView( page ); + keysListpr->setRootIsDecorated(true); + keysListpr->addColumn( i18n( "Name" )); + keysListpr->addColumn( i18n( "Email" )); + keysListpr->addColumn( i18n( "ID" )); + keysListpr->setShowSortIndicator(true); + keysListpr->setFullWidth(true); + keysListpr->setAllColumnsShowFocus(true); + if (allowMultipleSelection) keysListpr->setSelectionMode(QListView::Extended); + + labeltxt=new QLabel(i18n("Choose secret key:"),page); + vbox=new QVBoxLayout(page); + + if (preselected==QString::null) preselected = KGpgSettings::defaultKey(); + + FILE *fp,*fp2; + QString fullname,tst,tst2; + char line[300]; + + bool selectedok=false; + bool warn=false; + KListViewItem *item; + + fp = popen("gpg --no-tty --with-colons --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp)) { + tst=QString::fromUtf8(line); + if (tst.startsWith("sec")) { + QStringList keyString=QStringList::split(":",tst,true); + QString val=keyString[6]; + QString id=QString("0x"+keyString[4].right(8)); + if (val.isEmpty()) + val=i18n("Unlimited"); + fullname=keyString[9]; + + fp2 = popen(QFile::encodeName(QString("gpg --no-tty --with-colons --list-key %1").arg(KShellProcess::quote(id))), "r"); + bool dead=true; + while ( fgets( line, sizeof(line), fp2)) { + tst2=QString::fromUtf8(line); + if (tst2.startsWith("pub")) { + const QString trust2=tst2.section(':',1,1); + switch( trust2[0] ) { + case 'f': + dead=false; + break; + case 'u': + dead=false; + break; + case '-': + if (tst2.section(':',11,11).find('D')==-1) warn=true; + break; + default: + break; + } + if (tst2.section(':',11,11).find('D')!=-1) + dead=true; + break; + } + } + pclose(fp2); + if (!fullname.isEmpty() && (!dead)) { + QString keyMail,keyName; + if (fullname.find("<")!=-1) { + keyMail=fullname.section('<',-1,-1); + keyMail.truncate(keyMail.length()-1); + keyName=fullname.section('<',0,0); + } else { + keyMail=QString::null; + keyName=fullname; + } + + keyName=KgpgInterface::checkForUtf8(keyName); + + + item=new KListViewItem(keysListpr,keyName,keyMail,id); + //KListViewItem *sub= new KListViewItem(item,i18n("ID: %1, trust: %2, expiration: %3").arg(id).arg(trust).arg(val)); + KListViewItem *sub= new KListViewItem(item,i18n("Expiration:"),val); + sub->setSelectable(false); + item->setPixmap(0,keyPair); + if (preselected.find(id,0,false)!=-1) { + keysListpr->setSelected(item,true); + keysListpr->setCurrentItem(item); + selectedok=true; + } + } + } + } + pclose(fp); + + if (warn) + { + KMessageBox::information(this,i18n("<qt><b>Some of your secret keys are untrusted.</b><br>Change their trust if you want to use them for signing.</qt>"),QString::null,"warnUntrusted"); + } + QObject::connect(keysListpr,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)),this,SLOT(slotpreOk())); + QObject::connect(keysListpr,SIGNAL(clicked(QListViewItem *)),this,SLOT(slotSelect(QListViewItem *))); + + + if (!selectedok) + { + keysListpr->setSelected(keysListpr->firstChild(),true); + keysListpr->setCurrentItem(keysListpr->firstChild()); + } + + vbox->addWidget(labeltxt); + vbox->addWidget(keysListpr); + setMainWidget(page); +} + + +void KgpgSelKey::slotpreOk() +{ + if (keysListpr->currentItem()->depth()!=0) + return; + else + slotOk(); +} + +void KgpgSelKey::slotOk() +{ + if (keysListpr->currentItem()==NULL) + reject(); + else + accept(); +} + +void KgpgSelKey::slotSelect(QListViewItem *item) +{ + if (item==NULL) + return; + if (item->depth()!=0) { + keysListpr->setSelected(item->parent(),true); + keysListpr->setCurrentItem(item->parent()); + } +} + + +QString KgpgSelKey::getkeyID() +{ + ///// emit selected key + if (keysListpr->currentItem()==NULL) + return(QString::null); + QString result; + QPtrList< QListViewItem > list = keysListpr->selectedItems(false); + QListViewItem *item; + for ( item = list.first(); item; item = list.next() ) + { + result.append(item->text(2)); + if (item!=list.getLast()) result.append(" "); + } + return(result); +} + +QString KgpgSelKey::getkeyMail() +{ + QString username; + ///// emit selected key + if (keysListpr->currentItem()==NULL) + return(QString::null); + else { + username=keysListpr->currentItem()->text(0); + //username=username.section(' ',0,0); + username=username.stripWhiteSpace(); + return(username); + } +} + + + +///////////////////////////////////////////////////////////////////////////////////////////// + +KeyView::KeyView( QWidget *parent, const char *name ) + : KListView( parent, name ) +{ + KIconLoader *loader = KGlobal::iconLoader(); + + pixkeyOrphan=loader->loadIcon("kgpg_key4",KIcon::Small,20); + pixkeyGroup=loader->loadIcon("kgpg_key3",KIcon::Small,20); + pixkeyPair=loader->loadIcon("kgpg_key2",KIcon::Small,20); + pixkeySingle=loader->loadIcon("kgpg_key1",KIcon::Small,20); + pixsignature=loader->loadIcon("signature",KIcon::Small,20); + pixuserid=loader->loadIcon("kgpg_identity",KIcon::Small,20); + pixuserphoto=loader->loadIcon("kgpg_photo",KIcon::Small,20); + pixRevoke=loader->loadIcon("stop",KIcon::Small,20); + QPixmap blankFrame; + blankFrame.load(locate("appdata", "pics/kgpg_blank.png")); + + trustunknown.load(locate("appdata", "pics/kgpg_fill.png")); + trustunknown.fill(KGpgSettings::colorUnknown()); + bitBlt(&trustunknown,0,0,&blankFrame,0,0,50,15); + + trustbad.load(locate("appdata", "pics/kgpg_fill.png")); + trustbad.fill(KGpgSettings::colorBad());//QColor(172,0,0)); + bitBlt(&trustbad,0,0,&blankFrame,0,0,50,15); + + trustrevoked.load(locate("appdata", "pics/kgpg_fill.png")); + trustrevoked.fill(KGpgSettings::colorRev());//QColor(30,30,30)); + bitBlt(&trustrevoked,0,0,&blankFrame,0,0,50,15); + + trustgood.load(locate("appdata", "pics/kgpg_fill.png")); + trustgood.fill(KGpgSettings::colorGood());//QColor(144,255,0)); + bitBlt(&trustgood,0,0,&blankFrame,0,0,50,15); + + connect(this,SIGNAL(expanded (QListViewItem *)),this,SLOT(expandKey(QListViewItem *))); + header()->setMovingEnabled(false); + setAcceptDrops(true); + setDragEnabled(true); +} + + + +void KeyView::droppedfile (KURL url) +{ + if (KMessageBox::questionYesNo(this,i18n("<p>Do you want to import file <b>%1</b> into your key ring?</p>").arg(url.path()), QString::null, i18n("Import"), i18n("Do Not Import"))!=KMessageBox::Yes) + return; + + KgpgInterface *importKeyProcess=new KgpgInterface(); + importKeyProcess->importKeyURL(url); + connect(importKeyProcess,SIGNAL(importfinished(QStringList)),this,SLOT(slotReloadKeys(QStringList))); +} + +void KeyView::contentsDragMoveEvent(QDragMoveEvent *e) +{ + e->accept (KURLDrag::canDecode(e)); +} + +void KeyView::contentsDropEvent (QDropEvent *o) +{ + KURL::List list; + if ( KURLDrag::decode( o, list ) ) + droppedfile(list.first()); +} + +void KeyView::startDrag() +{ + FILE *fp; + char line[200]=""; + QString keyid=currentItem()->text(6); + if (!keyid.startsWith("0x")) + return; + QString gpgcmd="gpg --display-charset=utf-8 --no-tty --export --armor "+KShellProcess::quote(keyid.local8Bit()); + + QString keytxt; + fp=popen(QFile::encodeName(gpgcmd),"r"); + while ( fgets( line, sizeof(line), fp)) /// read output + if (!QString(line).startsWith("gpg:")) + keytxt+=QString::fromUtf8(line); + pclose(fp); + + QDragObject *d = new QTextDrag( keytxt, this ); + d->dragCopy(); + // do NOT delete d. +} + + +mySearchLine::mySearchLine(QWidget *parent, KeyView *listView, const char *name) +:KListViewSearchLine(parent,listView,name) +{ +searchListView=listView; +setKeepParentsVisible(false); +} + +mySearchLine::~ mySearchLine() +{} + + +bool mySearchLine::itemMatches(const QListViewItem *item, const QString & s) const +{ +if (item->depth()!=0) return true; +else return KListViewSearchLine::itemMatches(item,s); +} + + + +void mySearchLine::updateSearch(const QString& s) +{ + KListViewSearchLine::updateSearch(s); + if (searchListView->displayOnlySecret || !searchListView->displayDisabled) + { + int disabledSerial=searchListView->trustbad.serialNumber(); + QListViewItem *item=searchListView->firstChild(); + while (item) + { + if (item->isVisible() && !(item->text(6).isEmpty())) + { + if (searchListView->displayOnlySecret && searchListView->secretList.find(item->text(6))==-1) + item->setVisible(false); + if (!searchListView->displayDisabled && item->pixmap(2)) + if (item->pixmap(2)->serialNumber()==disabledSerial) + item->setVisible(false); + } + item=item->nextSibling(); + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////// main window for key management + +listKeys::listKeys(QWidget *parent, const char *name) : DCOPObject( "KeyInterface" ), KMainWindow(parent, name,0) +{ + //KWin::setType(Qt::WDestructiveClose); + + keysList2 = new KeyView(this); + keysList2->photoKeysList=QString::null; + keysList2->groupNb=0; + keyStatusBar=NULL; + readOptions(); + + if (showTipOfDay) + installEventFilter(this); + setCaption(i18n("Key Management")); + + (void) new KAction(i18n("&Open Editor"), "edit",0,this, SLOT(slotOpenEditor()),actionCollection(),"kgpg_editor"); + KAction *exportPublicKey = new KAction(i18n("E&xport Public Keys..."), "kgpg_export", KStdAccel::shortcut(KStdAccel::Copy),this, SLOT(slotexport()),actionCollection(),"key_export"); + KAction *deleteKey = new KAction(i18n("&Delete Keys"),"editdelete", Qt::Key_Delete,this, SLOT(confirmdeletekey()),actionCollection(),"key_delete"); + signKey = new KAction(i18n("&Sign Keys..."), "kgpg_sign", 0,this, SLOT(signkey()),actionCollection(),"key_sign"); + KAction *delSignKey = new KAction(i18n("Delete Sign&ature"),"editdelete", 0,this, SLOT(delsignkey()),actionCollection(),"key_delsign"); + KAction *infoKey = new KAction(i18n("&Edit Key"), "kgpg_info", Qt::Key_Return,this, SLOT(listsigns()),actionCollection(),"key_info"); + KAction *importKey = new KAction(i18n("&Import Key..."), "kgpg_import", KStdAccel::shortcut(KStdAccel::Paste),this, SLOT(slotPreImportKey()),actionCollection(),"key_import"); + KAction *setDefaultKey = new KAction(i18n("Set as De&fault Key"),0, 0,this, SLOT(slotSetDefKey()),actionCollection(),"key_default"); + importSignatureKey = new KAction(i18n("Import Key From Keyserver"),"network", 0,this, SLOT(preimportsignkey()),actionCollection(),"key_importsign"); + importAllSignKeys = new KAction(i18n("Import &Missing Signatures From Keyserver"),"network", 0,this, SLOT(importallsignkey()),actionCollection(),"key_importallsign"); + refreshKey = new KAction(i18n("&Refresh Keys From Keyserver"),"reload", 0,this, SLOT(refreshKeyFromServer()),actionCollection(),"key_server_refresh"); + + KAction *createGroup=new KAction(i18n("&Create Group with Selected Keys..."), 0, 0,this, SLOT(createNewGroup()),actionCollection(),"create_group"); + KAction *delGroup= new KAction(i18n("&Delete Group"), 0, 0,this, SLOT(deleteGroup()),actionCollection(),"delete_group"); + KAction *editCurrentGroup= new KAction(i18n("&Edit Group"), 0, 0,this, SLOT(editGroup()),actionCollection(),"edit_group"); + + KAction *newContact=new KAction(i18n("&Create New Contact in Address Book"), "kaddressbook", 0,this, SLOT(addToKAB()),actionCollection(),"add_kab"); + (void) new KAction(i18n("&Go to Default Key"), "gohome",QKeySequence(CTRL+Qt::Key_Home) ,this, SLOT(slotGotoDefaultKey()),actionCollection(),"go_default_key"); + + KStdAction::quit(this, SLOT(quitApp()), actionCollection()); + KStdAction::find(this, SLOT(findKey()), actionCollection()); + KStdAction::findNext(this, SLOT(findNextKey()), actionCollection()); + (void) new KAction(i18n("&Refresh List"), "reload", KStdAccel::reload(),this, SLOT(refreshkey()),actionCollection(),"key_refresh"); + KAction *openPhoto= new KAction(i18n("&Open Photo"), "image", 0,this, SLOT(slotShowPhoto()),actionCollection(),"key_photo"); + KAction *deletePhoto= new KAction(i18n("&Delete Photo"), "delete", 0,this, SLOT(slotDeletePhoto()),actionCollection(),"delete_photo"); + KAction *addPhoto= new KAction(i18n("&Add Photo"), 0, 0,this, SLOT(slotAddPhoto()),actionCollection(),"add_photo"); + + KAction *addUid= new KAction(i18n("&Add User Id"), 0, 0,this, SLOT(slotAddUid()),actionCollection(),"add_uid"); + KAction *delUid= new KAction(i18n("&Delete User Id"), 0, 0,this, SLOT(slotDelUid()),actionCollection(),"del_uid"); + + KAction *editKey = new KAction(i18n("Edit Key in &Terminal"), "kgpg_term", QKeySequence(ALT+Qt::Key_Return),this, SLOT(slotedit()),actionCollection(),"key_edit"); + KAction *exportSecretKey = new KAction(i18n("Export Secret Key..."), 0, 0,this, SLOT(slotexportsec()),actionCollection(),"key_sexport"); + KAction *revokeKey = new KAction(i18n("Revoke Key..."), 0, 0,this, SLOT(revokeWidget()),actionCollection(),"key_revoke"); + + KAction *deleteKeyPair = new KAction(i18n("Delete Key Pair"), 0, 0,this, SLOT(deleteseckey()),actionCollection(),"key_pdelete"); + KAction *generateKey = new KAction(i18n("&Generate Key Pair..."), "kgpg_gen", KStdAccel::shortcut(KStdAccel::New),this, SLOT(slotgenkey()),actionCollection(),"key_gener"); + + KAction *regeneratePublic = new KAction(i18n("&Regenerate Public Key"), 0, 0,this, SLOT(slotregenerate()),actionCollection(),"key_regener"); + + (void) new KAction(i18n("&Key Server Dialog"), "network", 0,this, SLOT(showKeyServer()),actionCollection(),"key_server"); + KStdAction::preferences(this, SLOT(showOptions()), actionCollection(),"options_configure"); + (void) new KAction(i18n("Tip of the &Day"), "idea", 0,this, SLOT(slotTip()), actionCollection(),"help_tipofday"); + (void) new KAction(i18n("View GnuPG Manual"), "contents", 0,this, SLOT(slotManpage()),actionCollection(),"gpg_man"); + + (void) new KToggleAction(i18n("&Show only Secret Keys"), "kgpg_show", 0,this, SLOT(slotToggleSecret()),actionCollection(),"show_secret"); + keysList2->displayOnlySecret=false; + + (void) new KToggleAction(i18n("&Hide Expired/Disabled Keys"),0, 0,this, SLOT(slotToggleDisabled()),actionCollection(),"hide_disabled"); + keysList2->displayDisabled=true; + + sTrust=new KToggleAction(i18n("Trust"),0, 0,this, SLOT(slotShowTrust()),actionCollection(),"show_trust"); + sSize=new KToggleAction(i18n("Size"),0, 0,this, SLOT(slotShowSize()),actionCollection(),"show_size"); + sCreat=new KToggleAction(i18n("Creation"),0, 0,this, SLOT(slotShowCreat()),actionCollection(),"show_creat"); + sExpi=new KToggleAction(i18n("Expiration"),0, 0,this, SLOT(slotShowExpi()),actionCollection(),"show_expi"); + + + photoProps = new KSelectAction(i18n("&Photo ID's"),"kgpg_photo", actionCollection(), "photo_settings"); + connect(photoProps, SIGNAL(activated(int)), this, SLOT(slotSetPhotoSize(int))); + + // Keep the list in kgpg.kcfg in sync with this one! + QStringList list; + list.append(i18n("Disable")); + list.append(i18n("Small")); + list.append(i18n("Medium")); + list.append(i18n("Large")); + photoProps->setItems(list); + + int pSize = KGpgSettings::photoProperties(); + photoProps->setCurrentItem( pSize ); + slotSetPhotoSize(pSize); + + keysList2->setRootIsDecorated(true); + keysList2->addColumn( i18n( "Name" ),200); + keysList2->addColumn( i18n( "Email" ),200); + keysList2->addColumn( i18n( "Trust" ),60); + keysList2->addColumn( i18n( "Expiration" ),100); + keysList2->addColumn( i18n( "Size" ),100); + keysList2->addColumn( i18n( "Creation" ),100); + keysList2->addColumn( i18n( "Id" ),100); + keysList2->setShowSortIndicator(true); + keysList2->setAllColumnsShowFocus(true); + keysList2->setFullWidth(true); + keysList2->setAcceptDrops (true) ; + keysList2->setSelectionModeExt(KListView::Extended); + + + popup=new QPopupMenu(); + exportPublicKey->plug(popup); + deleteKey->plug(popup); + signKey->plug(popup); + infoKey->plug(popup); + editKey->plug(popup); + refreshKey->plug(popup); + setDefaultKey->plug(popup); + popup->insertSeparator(); + importAllSignKeys->plug(popup); + + popupsec=new QPopupMenu(); + exportPublicKey->plug(popupsec); + signKey->plug(popupsec); + infoKey->plug(popupsec); + editKey->plug(popupsec); + refreshKey->plug(popupsec); + setDefaultKey->plug(popupsec); + popupsec->insertSeparator(); + importAllSignKeys->plug(popupsec); + popupsec->insertSeparator(); + addPhoto->plug(popupsec); + addUid->plug(popupsec); + exportSecretKey->plug(popupsec); + deleteKeyPair->plug(popupsec); + revokeKey->plug(popupsec); + + popupgroup=new QPopupMenu(); + editCurrentGroup->plug(popupgroup); + delGroup->plug(popupgroup); + + popupout=new QPopupMenu(); + importKey->plug(popupout); + generateKey->plug(popupout); + + popupsig=new QPopupMenu(); + importSignatureKey->plug(popupsig); + delSignKey->plug(popupsig); + + popupphoto=new QPopupMenu(); + openPhoto->plug(popupphoto); + deletePhoto->plug(popupphoto); + + popupuid=new QPopupMenu(); + delUid->plug(popupuid); + + popuporphan=new QPopupMenu(); + regeneratePublic->plug(popuporphan); + deleteKeyPair->plug(popuporphan); + + editCurrentGroup->setEnabled(false); + delGroup->setEnabled(false); + createGroup->setEnabled(false); + infoKey->setEnabled(false); + editKey->setEnabled(false); + signKey->setEnabled(false); + refreshKey->setEnabled(false); + exportPublicKey->setEnabled(false); + newContact->setEnabled(false); + + setCentralWidget(keysList2); + keysList2->restoreLayout(KGlobal::config(), "KeyView"); + + QObject::connect(keysList2,SIGNAL(returnPressed(QListViewItem *)),this,SLOT(listsigns())); + QObject::connect(keysList2,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)),this,SLOT(listsigns())); + QObject::connect(keysList2,SIGNAL(selectionChanged ()),this,SLOT(checkList())); + QObject::connect(keysList2,SIGNAL(contextMenuRequested(QListViewItem *,const QPoint &,int)), + this,SLOT(slotmenu(QListViewItem *,const QPoint &,int))); + QObject::connect(keysList2,SIGNAL(destroyed()),this,SLOT(annule())); + + + /////////////// get all keys data + keyStatusBar=statusBar(); + + setupGUI(KMainWindow::Create | Save | ToolBar | StatusBar | Keys, "listkeys.rc"); + toolBar()->insertLineSeparator(); + + QToolButton *clearSearch = new QToolButton(toolBar()); + clearSearch->setTextLabel(i18n("Clear Search"), true); + clearSearch->setIconSet(SmallIconSet(QApplication::reverseLayout() ? "clear_left" + : "locationbar_erase")); + (void) new QLabel(i18n("Search: "),toolBar()); + listViewSearch = new mySearchLine(toolBar(),keysList2); + connect(clearSearch, SIGNAL(pressed()), listViewSearch, SLOT(clear())); + + + (void)new KAction(i18n("Filter Search"), Qt::Key_F6, listViewSearch, SLOT(setFocus()),actionCollection(), "search_focus"); + + sTrust->setChecked(KGpgSettings::showTrust()); + sSize->setChecked(KGpgSettings::showSize()); + sCreat->setChecked(KGpgSettings::showCreat()); + sExpi->setChecked(KGpgSettings::showExpi()); + + statusbarTimer = new QTimer(this); + + keyStatusBar->insertItem("",0,1); + keyStatusBar->insertFixedItem(i18n("00000 Keys, 000 Groups"),1,true); + keyStatusBar->setItemAlignment(0, AlignLeft); + keyStatusBar->changeItem("",1); + QObject::connect(keysList2,SIGNAL(statusMessage(QString,int,bool)),this,SLOT(changeMessage(QString,int,bool))); + QObject::connect(statusbarTimer,SIGNAL(timeout()),this,SLOT(statusBarTimeout())); + + s_kgpgEditor= new KgpgApp(parent, "editor",WType_Dialog,actionCollection()->action("go_default_key")->shortcut(),true); + connect(s_kgpgEditor,SIGNAL(refreshImported(QStringList)),keysList2,SLOT(slotReloadKeys(QStringList))); + connect(this,SIGNAL(fontChanged(QFont)),s_kgpgEditor,SLOT(slotSetFont(QFont))); + connect(s_kgpgEditor->view->editor,SIGNAL(refreshImported(QStringList)),keysList2,SLOT(slotReloadKeys(QStringList))); +} + + +listKeys::~listKeys() +{} + +void listKeys::showKeyManager() +{ +show(); +} + +void listKeys::slotOpenEditor() +{ + KgpgApp *kgpgtxtedit = new KgpgApp(this, "editor",WType_TopLevel | WDestructiveClose,actionCollection()->action("go_default_key")->shortcut()); + connect(kgpgtxtedit,SIGNAL(refreshImported(QStringList)),keysList2,SLOT(slotReloadKeys(QStringList))); + connect(kgpgtxtedit,SIGNAL(encryptFiles(KURL::List)),this,SIGNAL(encryptFiles(KURL::List))); + connect(this,SIGNAL(fontChanged(QFont)),kgpgtxtedit,SLOT(slotSetFont(QFont))); + connect(kgpgtxtedit->view->editor,SIGNAL(refreshImported(QStringList)),keysList2,SLOT(slotReloadKeys(QStringList))); + kgpgtxtedit->show(); +} + +void listKeys::statusBarTimeout() +{ + keyStatusBar->changeItem("",0); +} + +void listKeys::changeMessage(QString msg, int nb, bool keep) +{ + statusbarTimer->stop(); + if ((nb==0) & (!keep)) + statusbarTimer->start(10000, true); + keyStatusBar->changeItem(" "+msg+" ",nb); +} + + +void KeyView::slotRemoveColumn(int d) +{ + hideColumn(d); + header()->setResizeEnabled(false,d); + header()->setStretchEnabled(true,6); +} + +void KeyView::slotAddColumn(int c) +{ + header()->setResizeEnabled(true,c); + adjustColumn(c); +} + +void listKeys::slotShowTrust() +{ + if (sTrust->isChecked()) + keysList2->slotAddColumn(2); + else + keysList2->slotRemoveColumn(2); +} + +void listKeys::slotShowExpi() +{ + if (sExpi->isChecked()) + keysList2->slotAddColumn(3); + else + keysList2->slotRemoveColumn(3); +} + +void listKeys::slotShowSize() +{ + if (sSize->isChecked()) + keysList2->slotAddColumn(4); + else + keysList2->slotRemoveColumn(4); +} + +void listKeys::slotShowCreat() +{ + if (sCreat->isChecked()) + keysList2->slotAddColumn(5); + else + keysList2->slotRemoveColumn(5); +} + + +bool listKeys::eventFilter( QObject *, QEvent *e ) +{ + if ((e->type() == QEvent::Show) && (showTipOfDay)) { + KTipDialog::showTip(this, QString("kgpg/tips"), false); + showTipOfDay=false; + } + return FALSE; +} + + +void listKeys::slotToggleSecret() +{ + QListViewItem *item=keysList2->firstChild(); + if (!item) + return; + + keysList2->displayOnlySecret=!keysList2->displayOnlySecret; + listViewSearch->updateSearch(listViewSearch->text()); +} + +void listKeys::slotToggleDisabled() +{ + QListViewItem *item=keysList2->firstChild(); + if (!item) + return; + + keysList2->displayDisabled=!keysList2->displayDisabled; + listViewSearch->updateSearch(listViewSearch->text()); +} + +void listKeys::slotGotoDefaultKey() +{ + QListViewItem *myDefaulKey = keysList2->findItem(KGpgSettings::defaultKey(),6); + keysList2->clearSelection(); + keysList2->setCurrentItem(myDefaulKey); + keysList2->setSelected(myDefaulKey,true); + keysList2->ensureItemVisible(myDefaulKey); +} + + + +void listKeys::refreshKeyFromServer() +{ + if (keysList2->currentItem()==NULL) + return; + QString keyIDS; + keysList=keysList2->selectedItems(); + bool keyDepth=true; + for ( uint i = 0; i < keysList.count(); ++i ) + if ( keysList.at(i) ) { + if ((keysList.at(i)->depth()!=0) || (keysList.at(i)->text(6).isEmpty())) + keyDepth=false; + else + keyIDS+=keysList.at(i)->text(6)+" "; + } + if (!keyDepth) { + KMessageBox::sorry(this,i18n("You can only refresh primary keys. Please check your selection.")); + return; + } + kServer=new keyServer(0,"server_dialog",false); + kServer->page->kLEimportid->setText(keyIDS); + kServer->slotImport(); + connect( kServer, SIGNAL( importFinished(QString) ) , this, SLOT(refreshFinished())); +} + + +void listKeys::refreshFinished() +{ + if (kServer) + kServer=0L; + + for ( uint i = 0; i < keysList.count(); ++i ) + if (keysList.at(i)) + keysList2->refreshcurrentkey(keysList.at(i)); +} + + +void listKeys::slotDelUid() +{ + QListViewItem *item=keysList2->currentItem(); + while (item->depth()>0) + item=item->parent(); + + KProcess *conprocess=new KProcess(); + KConfig *config = KGlobal::config(); + config->setGroup("General"); + *conprocess<< config->readPathEntry("TerminalApplication","konsole"); + *conprocess<<"-e"<<"gpg"; + *conprocess<<"--edit-key"<<item->text(6)<<"uid"; + conprocess->start(KProcess::Block); + keysList2->refreshselfkey(); +} + + +void listKeys::slotregenerate() +{ + FILE *fp; + QString tst; + char line[300]; + QString cmd="gpg --display-charset=utf-8 --no-secmem-warning --export-secret-key "+keysList2->currentItem()->text(6)+" | gpgsplit --no-split --secret-to-public | gpg --import"; + + fp = popen(QFile::encodeName(cmd), "r"); + while ( fgets( line, sizeof(line), fp)) { + tst+=QString::fromUtf8(line); + } + pclose(fp); + QString regID=keysList2->currentItem()->text(6); + keysList2->takeItem(keysList2->currentItem()); + keysList2->refreshcurrentkey(regID); +} + +void listKeys::slotAddUid() +{ + addUidWidget=new KDialogBase(KDialogBase::Swallow, i18n("Add New User Id"), KDialogBase::Ok | KDialogBase::Cancel,KDialogBase::Ok,this,0,true); + addUidWidget->enableButtonOK(false); + AddUid *keyUid=new AddUid(); + addUidWidget->setMainWidget(keyUid); + //keyUid->setMinimumSize(keyUid->sizeHint()); + keyUid->setMinimumWidth(300); + connect(keyUid->kLineEdit1,SIGNAL(textChanged ( const QString & )),this,SLOT(slotAddUidEnable(const QString & ))); + if (addUidWidget->exec()!=QDialog::Accepted) + return; + KgpgInterface *addUidProcess=new KgpgInterface(); + addUidProcess->KgpgAddUid(keysList2->currentItem()->text(6),keyUid->kLineEdit1->text(),keyUid->kLineEdit2->text(),keyUid->kLineEdit3->text()); + connect(addUidProcess,SIGNAL(addUidFinished()),keysList2,SLOT(refreshselfkey())); + connect(addUidProcess,SIGNAL(addUidError(QString)),this,SLOT(slotGpgError(QString))); +} + +void listKeys::slotAddUidEnable(const QString & name) +{ + addUidWidget->enableButtonOK(name.length()>4); +} + + +void listKeys::slotAddPhoto() +{ + QString mess=i18n("The image must be a JPEG file. Remember that the image is stored within your public key." + "If you use a very large picture, your key will become very large as well! Keeping the image " + "close to 240x288 is a good size to use."); + + if (KMessageBox::warningContinueCancel(this,mess)!=KMessageBox::Continue) + return; + + QString imagePath=KFileDialog::getOpenFileName (QString::null,"image/jpeg",this); + if (imagePath.isEmpty()) + return; + KgpgInterface *addPhotoProcess=new KgpgInterface(); + addPhotoProcess->KgpgAddPhoto(keysList2->currentItem()->text(6),imagePath); + connect(addPhotoProcess,SIGNAL(addPhotoFinished()),this,SLOT(slotUpdatePhoto())); + connect(addPhotoProcess,SIGNAL(addPhotoError(QString)),this,SLOT(slotGpgError(QString))); +} + +void listKeys::slotGpgError(QString errortxt) +{ + KMessageBox::detailedSorry(this,i18n("Something unexpected happened during the requested operation.\nPlease check details for full log output."),errortxt); +} + + +void listKeys::slotDeletePhoto() +{ + if (KMessageBox::warningContinueCancel(this,i18n("<qt>Are you sure you want to delete Photo id <b>%1</b><br>from key <b>%2 <%3></b> ?</qt>").arg(keysList2->currentItem()->text(6)).arg(keysList2->currentItem()->parent()->text(0)).arg(keysList2->currentItem()->parent()->text(1)),i18n("Warning"),KGuiItem(i18n("Delete"),"editdelete"))!=KMessageBox::Continue) + return; + + KgpgInterface *delPhotoProcess=new KgpgInterface(); + delPhotoProcess->KgpgDeletePhoto(keysList2->currentItem()->parent()->text(6),keysList2->currentItem()->text(6)); + connect(delPhotoProcess,SIGNAL(delPhotoFinished()),this,SLOT(slotUpdatePhoto())); + connect(delPhotoProcess,SIGNAL(delPhotoError(QString)),this,SLOT(slotGpgError(QString))); +} + +void listKeys::slotUpdatePhoto() +{ + keysList2->refreshselfkey(); +} + + +void listKeys::slotSetPhotoSize(int size) +{ + switch( size) { + case 1: + showPhoto=true; + keysList2->previewSize=22; + break; + case 2: + showPhoto=true; + keysList2->previewSize=42; + break; + case 3: + showPhoto=true; + keysList2->previewSize=65; + break; + default: + showPhoto=false; + break; + } + keysList2->displayPhoto=showPhoto; + + ///////////////////////////// refresh keys with photo id + + QListViewItem *newdef = keysList2->firstChild(); + while (newdef) { + //if ((keysList2->photoKeysList.find(newdef->text(6))!=-1) && (newdef->childCount ()>0)) + if (newdef->childCount ()>0) { + bool hasphoto=false; + QListViewItem *newdefChild = newdef->firstChild(); + while (newdefChild) { + if (newdefChild->text(0)==i18n("Photo id")) { + hasphoto=true; + break; + } + newdefChild = newdefChild->nextSibling(); + } + if (hasphoto) { + while (newdef->firstChild()) + delete newdef->firstChild(); + keysList2->expandKey(newdef); + } + } + newdef = newdef->nextSibling(); + } +} + +void listKeys::findKey() +{ + KFindDialog fd(this,"find_dialog",0,""); + if ( fd.exec() != QDialog::Accepted ) + return; + searchString=fd.pattern(); + searchOptions=fd.options(); + findFirstKey(); +} + +void listKeys::findFirstKey() +{ + if (searchString.isEmpty()) + return; + bool foundItem=true; + QListViewItem *item=keysList2->firstChild(); + if (!item) + return; + QString searchText=item->text(0)+" "+item->text(1)+" "+item->text(6); + + + // + KFind *m_find = new KFind(searchString, searchOptions,this); + m_find->setData(searchText); + while (m_find->find()==KFind::NoMatch) { + if (!item->nextSibling()) { + foundItem=false; + break; + } else { + item = item->nextSibling(); + searchText=item->text(0)+" "+item->text(1)+" "+item->text(6); + m_find->setData(searchText); + } + } + delete m_find; + + if (foundItem) { + + keysList2->clearSelection(); + keysList2->setCurrentItem(item); + keysList2->setSelected(item,true); + keysList2->ensureItemVisible(item); + } else + KMessageBox::sorry(this,i18n("<qt>Search string '<b>%1</b>' not found.").arg(searchString)); +} + +void listKeys::findNextKey() +{ + //kdDebug(2100)<<"find next"<<endl; + if (searchString.isEmpty()) { + findKey(); + return; + } + bool foundItem=true; + QListViewItem *item=keysList2->currentItem(); + if (!item) + return; + while(item->depth() > 0) + item = item->parent(); + item=item->nextSibling(); + QString searchText=item->text(0)+" "+item->text(1)+" "+item->text(6); + //kdDebug(2100)<<"Next string:"<<searchText<<endl; + //kdDebug(2100)<<"Search:"<<searchString<<endl; + //kdDebug(2100)<<"OPts:"<<searchOptions<<endl; + KFind *m_find = new KFind(searchString, searchOptions,this); + m_find->setData(searchText); + while (m_find->find()==KFind::NoMatch) { + if (!item->nextSibling()) { + foundItem=false; + break; + } else { + item = item->nextSibling(); + searchText=item->text(0)+" "+item->text(1)+" "+item->text(6); + m_find->setData(searchText); + //kdDebug(2100)<<"Next string:"<<searchText<<endl; + } + } + delete m_find; + if (foundItem) { + keysList2->clearSelection(); + keysList2->setCurrentItem(item); + keysList2->setSelected(item,true); + keysList2->ensureItemVisible(item); + } else + findFirstKey(); +} + + + + +void listKeys::addToKAB() +{ + KABC::Key key; + if (!keysList2->currentItem()) return; + //QString email=extractKeyMail(keysList2->currentItem()).stripWhiteSpace(); + QString email=keysList2->currentItem()->text(1); + + KABC::AddressBook *ab = KABC::StdAddressBook::self(); + if ( !ab->load() ) { + KMessageBox::sorry(this,i18n("Unable to contact the address book. Please check your installation.")); + return; + } + + KABC::Addressee::List addresseeList = ab->findByEmail(email); + kapp->startServiceByDesktopName( "kaddressbook" ); + DCOPRef call( "kaddressbook", "KAddressBookIface" ); + if( !addresseeList.isEmpty() ) { + call.send( "showContactEditor(QString)", addresseeList.first().uid() ); + } + else { + call.send( "addEmail(QString)", QString (keysList2->currentItem()->text(0))+" <"+email+">" ); + } +} + +/* +void listKeys::allToKAB() +{ + KABC::Key key; + QString email; + QStringList keylist; + KABC::Addressee a; + + KABC::AddressBook *ab = KABC::StdAddressBook::self(); + if ( !ab->load() ) { + KMessageBox::sorry(this,i18n("Unable to contact the address book. Please check your installation.")); + return; + } + + QListViewItem * myChild = keysList2->firstChild(); + while( myChild ) { + //email=extractKeyMail(myChild).stripWhiteSpace(); + email=myChild->text(1); + KABC::Addressee::List addressees = ab->findByEmail( email ); + if (addressees.count()==1) { + a=addressees.first(); + KgpgInterface *ks=new KgpgInterface(); + key.setTextData(ks->getKey(myChild->text(6),true)); + a.insertKey(key); + ab->insertAddressee(a); + keylist<<myChild->text(6)+": "+email; + } + // doSomething( myChild ); + myChild = myChild->nextSibling(); + } + KABC::StdAddressBook::save(); + if (!keylist.isEmpty()) + KMessageBox::informationList(this,i18n("The following keys were exported to the address book:"),keylist); + else + KMessageBox::sorry(this,i18n("No entry matching your keys were found in the address book.")); +} +*/ + +void listKeys::slotManpage() +{ + kapp->startServiceByDesktopName("khelpcenter", QString("man:/gpg"), 0, 0, 0, "", true); +} + +void listKeys::slotTip() +{ + KTipDialog::showTip(this, QString("kgpg/tips"), true); +} + +void listKeys::closeEvent ( QCloseEvent * e ) +{ + //kapp->ref(); // prevent KMainWindow from closing the app + //KMainWindow::closeEvent( e ); + e->accept(); + // hide(); + // e->ignore(); +} + +void listKeys::showKeyServer() +{ + keyServer *ks=new keyServer(this); + connect(ks,SIGNAL( importFinished(QString) ) , keysList2, SLOT(refreshcurrentkey(QString))); + ks->exec(); + if (ks) + delete ks; + refreshkey(); +} + + +void listKeys::checkList() +{ + QPtrList<QListViewItem> exportList=keysList2->selectedItems(); + if (exportList.count()>1) + { + stateChanged("multi_selected"); + for ( uint i = 0; i < exportList.count(); ++i ) + { + if (exportList.at(i) && !(exportList.at(i)->isVisible())) + exportList.at(i)->setSelected(false); + } + } + else { + if (keysList2->currentItem()->text(6).isEmpty()) + stateChanged("group_selected"); + else + stateChanged("single_selected"); + + } + int serial=keysList2->currentItem()->pixmap(0)->serialNumber(); + if (serial==keysList2->pixkeySingle.serialNumber()) { + if (keysList2->currentItem()->depth()==0) + changeMessage(i18n("Public Key"),0); + else + changeMessage(i18n("Sub Key"),0); + } else if (serial==keysList2->pixkeyPair.serialNumber()) + changeMessage(i18n("Secret Key Pair"),0); + else if (serial==keysList2->pixkeyGroup.serialNumber()) + changeMessage(i18n("Key Group"),0); + else if (serial==keysList2->pixsignature.serialNumber()) + changeMessage(i18n("Signature"),0); + else if (serial==keysList2->pixuserid.serialNumber()) + changeMessage(i18n("User ID"),0); + else if (keysList2->currentItem()->text(0)==i18n("Photo id")) + changeMessage(i18n("Photo ID"),0); + else if (serial==keysList2->pixRevoke.serialNumber()) + changeMessage(i18n("Revocation Signature"),0); + else if (serial==keysList2->pixkeyOrphan.serialNumber()) + changeMessage(i18n("Orphaned Secret Key"),0); + +} + +void listKeys::annule() +{ + ///////// close window + close(); +} + +void listKeys::quitApp() +{ + ///////// close window + exit(1); +} + +void listKeys::readOptions() +{ + + clipboardMode=QClipboard::Clipboard; + if (KGpgSettings::useMouseSelection() && (kapp->clipboard()->supportsSelection())) + clipboardMode=QClipboard::Selection; + + /////// re-read groups in case the config file location was changed + QStringList groups=KgpgInterface::getGpgGroupNames(KGpgSettings::gpgConfigPath()); + KGpgSettings::setGroups(groups.join(",")); + keysList2->groupNb=groups.count(); + if (keyStatusBar) + changeMessage(i18n("%1 Keys, %2 Groups").arg(keysList2->childCount()-keysList2->groupNb).arg(keysList2->groupNb),1); + + showTipOfDay= KGpgSettings::showTipOfDay(); +} + + +void listKeys::showOptions() +{ + if (KConfigDialog::showDialog("settings")) + return; + kgpgOptions *optionsDialog=new kgpgOptions(this,"settings"); + connect(optionsDialog,SIGNAL(settingsUpdated()),this,SLOT(readAllOptions())); + connect(optionsDialog,SIGNAL(homeChanged()),this,SLOT(refreshkey())); + connect(optionsDialog,SIGNAL(reloadKeyList()),this,SLOT(refreshkey())); + connect(optionsDialog,SIGNAL(refreshTrust(int,QColor)),keysList2,SLOT(refreshTrust(int,QColor))); + connect(optionsDialog,SIGNAL(changeFont(QFont)),this,SIGNAL(fontChanged(QFont))); + connect(optionsDialog,SIGNAL(installShredder()),this,SIGNAL(installShredder())); + optionsDialog->exec(); + delete optionsDialog; +} + +void listKeys::readAllOptions() +{ + readOptions(); + emit readAgainOptions(); +} + +void listKeys::slotSetDefKey() +{ + slotSetDefaultKey(keysList2->currentItem()); +} + +void listKeys::slotSetDefaultKey(QString newID) +{ + QListViewItem *newdef = keysList2->findItem(newID,6); + if (newdef) + slotSetDefaultKey(newdef); +} + +void listKeys::slotSetDefaultKey(QListViewItem *newdef) +{ + //kdDebug(2100)<<"------------------start ------------"<<endl; + if ((!newdef) || (newdef->pixmap(2)==NULL)) + return; + //kdDebug(2100)<<newdef->text(6)<<endl; + //kdDebug(2100)<<KGpgSettings::defaultKey()<<endl; + if (newdef->text(6)==KGpgSettings::defaultKey()) + return; + if (newdef->pixmap(2)->serialNumber()!=keysList2->trustgood.serialNumber()) { + KMessageBox::sorry(this,i18n("Sorry, this key is not valid for encryption or not trusted.")); + return; + } + + QListViewItem *olddef = keysList2->findItem(KGpgSettings::defaultKey(),6); + + KGpgSettings::setDefaultKey(newdef->text(6)); + KGpgSettings::writeConfig(); + if (olddef) + keysList2->refreshcurrentkey(olddef); + keysList2->refreshcurrentkey(newdef); + keysList2->ensureItemVisible(keysList2->currentItem()); +} + + + +void listKeys::slotmenu(QListViewItem *sel, const QPoint &pos, int ) +{ + //////////// popup a different menu depending on which key is selected + if (sel!=NULL) { + if (keysList2->selectedItems().count()>1) { + QPtrList<QListViewItem> exportList=keysList2->selectedItems(); + bool keyDepth=true; + for ( uint i = 0; i < exportList.count(); ++i ) + if ( exportList.at(i) ) + if (exportList.at(i)->depth()!=0) + keyDepth=false; + if (!keyDepth) { + signKey->setEnabled(false); + refreshKey->setEnabled(false); + popupout->exec(pos); + return; + } else { + signKey->setEnabled(true); + refreshKey->setEnabled(true); + } + } + + if (sel->depth()!=0) { + //kdDebug(2100)<<sel->text(0)<<endl; + if ((sel->text(4)=="-") && (sel->text(6).startsWith("0x"))) { + if ((sel->text(2)=="-") || (sel->text(2)==i18n("Revoked"))) { + if ((sel->text(0).startsWith("[")) && (sel->text(0).endsWith("]"))) ////// ugly hack to detect unknown keys + importSignatureKey->setEnabled(true); + else + importSignatureKey->setEnabled(false); + popupsig->exec(pos); + return; + } + } else if (sel->text(0)==i18n("Photo id")) + popupphoto->exec(pos); + else if (sel->text(6)==("-")) + popupuid->exec(pos); + } else { + keysList2->setSelected(sel,TRUE); + if (keysList2->currentItem()->text(6).isEmpty()) + popupgroup->exec(pos); + else { + if ((keysList2->secretList.find(sel->text(6))!=-1) && (keysList2->selectedItems().count()==1)) + popupsec->exec(pos); + else + if ((keysList2->orphanList.find(sel->text(6))!=-1) && (keysList2->selectedItems().count()==1)) + popuporphan->exec(pos); + else + popup->exec(pos); + } + return; + } + } else + popupout->exec(pos); +} + + + +void listKeys::slotrevoke(QString keyID,QString revokeUrl,int reason,QString description) +{ + revKeyProcess=new KgpgInterface(); + revKeyProcess->KgpgRevokeKey(keyID,revokeUrl,reason,description); +} + + +void listKeys::revokeWidget() +{ + KDialogBase *keyRevokeWidget=new KDialogBase(KDialogBase::Swallow, i18n("Create Revocation Certificate"), KDialogBase::Ok | KDialogBase::Cancel,KDialogBase::Ok,this,0,true); + + KgpgRevokeWidget *keyRevoke=new KgpgRevokeWidget(); + + keyRevoke->keyID->setText(keysList2->currentItem()->text(0)+" ("+keysList2->currentItem()->text(1)+") "+i18n("ID: ")+keysList2->currentItem()->text(6)); + keyRevoke->kURLRequester1->setURL(QDir::homeDirPath()+"/"+keysList2->currentItem()->text(1).section('@',0,0)+".revoke"); + keyRevoke->kURLRequester1->setMode(KFile::File); + + keyRevoke->setMinimumSize(keyRevoke->sizeHint()); + keyRevoke->show(); + keyRevokeWidget->setMainWidget(keyRevoke); + + if (keyRevokeWidget->exec()!=QDialog::Accepted) + return; + if (keyRevoke->cbSave->isChecked()) { + slotrevoke(keysList2->currentItem()->text(6),keyRevoke->kURLRequester1->url(),keyRevoke->comboBox1->currentItem(),keyRevoke->textDescription->text()); + if (keyRevoke->cbPrint->isChecked()) + connect(revKeyProcess,SIGNAL(revokeurl(QString)),this,SLOT(doFilePrint(QString))); + if (keyRevoke->cbImport->isChecked()) + connect(revKeyProcess,SIGNAL(revokeurl(QString)),this,SLOT(slotImportRevoke(QString))); + } else { + slotrevoke(keysList2->currentItem()->text(6),QString::null,keyRevoke->comboBox1->currentItem(),keyRevoke->textDescription->text()); + if (keyRevoke->cbPrint->isChecked()) + connect(revKeyProcess,SIGNAL(revokecertificate(QString)),this,SLOT(doPrint(QString))); + if (keyRevoke->cbImport->isChecked()) + connect(revKeyProcess,SIGNAL(revokecertificate(QString)),this,SLOT(slotImportRevokeTxt(QString))); + } +} + + +void listKeys::slotImportRevoke(QString url) +{ + KgpgInterface *importKeyProcess=new KgpgInterface(); + importKeyProcess->importKeyURL(KURL::fromPathOrURL( url )); + connect(importKeyProcess,SIGNAL(importfinished(QStringList)),keysList2,SLOT(refreshselfkey())); +} + +void listKeys::slotImportRevokeTxt(QString revokeText) +{ + KgpgInterface *importKeyProcess=new KgpgInterface(); + importKeyProcess->importKey(revokeText); + connect(importKeyProcess,SIGNAL(importfinished(QStringList)),keysList2,SLOT(refreshselfkey())); +} + +void listKeys::slotexportsec() +{ + ////////////////////// export secret key + QString warn=i18n("Secret keys SHOULD NOT be saved in an unsafe place.\n" + "If someone else can access this file, encryption with this key will be compromised!\nContinue key export?"); + int result=KMessageBox::questionYesNo(this,warn,i18n("Warning"), i18n("Export"), i18n("Do Not Export")); + if (result!=KMessageBox::Yes) + return; + + QString sname=keysList2->currentItem()->text(1).section('@',0,0); + sname=sname.section('.',0,0); + if (sname.isEmpty()) + sname=keysList2->currentItem()->text(0).section(' ',0,0); + sname.append(".asc"); + sname.prepend(QDir::homeDirPath()+"/"); + KURL url=KFileDialog::getSaveURL(sname,"*.asc|*.asc Files", this, i18n("Export PRIVATE KEY As")); + + if(!url.isEmpty()) { + QFile fgpg(url.path()); + if (fgpg.exists()) + fgpg.remove(); + + KProcIO *p=new KProcIO(QTextCodec::codecForLocale()); + *p<<"gpg"<<"--no-tty"<<"--output"<<QFile::encodeName(url.path())<<"--armor"<<"--export-secret-keys"<<keysList2->currentItem()->text(6); + p->start(KProcess::Block); + + if (fgpg.exists()) + KMessageBox::information(this,i18n("Your PRIVATE key \"%1\" was successfully exported.\nDO NOT leave it in an insecure place.").arg(url.path())); + else + KMessageBox::sorry(this,i18n("Your secret key could not be exported.\nCheck the key.")); + } + +} + + +void listKeys::slotexport() +{ + ///////////////////// export key + if (keysList2->currentItem()==NULL) + return; + if (keysList2->currentItem()->depth()!=0) + return; + + + QPtrList<QListViewItem> exportList=keysList2->selectedItems(); + if (exportList.count()==0) + return; + + QString sname; + + if (exportList.count()==1) { + sname=keysList2->currentItem()->text(1).section('@',0,0); + sname=sname.section('.',0,0); + if (sname.isEmpty()) + sname=keysList2->currentItem()->text(0).section(' ',0,0); + } else + sname="keyring"; + sname.append(".asc"); + sname.prepend(QDir::homeDirPath()+"/"); + + KDialogBase *dial=new KDialogBase( KDialogBase::Swallow, i18n("Public Key Export"), KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, this, "key_export",true); + + KeyExport *page=new KeyExport(); + dial->setMainWidget(page); + page->newFilename->setURL(sname); + page->newFilename->setCaption(i18n("Save File")); + page->newFilename->setMode(KFile::File); + page->show(); + + if (dial->exec()==QDialog::Accepted) { + ////////////////////////// export to file + QString expname; + bool exportAttr=page->exportAttributes->isChecked(); + if (page->checkServer->isChecked()) { + keyServer *expServer=new keyServer(0,"server_export",false); + expServer->page->exportAttributes->setChecked(exportAttr); + QStringList exportKeysList; + for ( uint i = 0; i < exportList.count(); ++i ) + if ( exportList.at(i) ) + exportKeysList << exportList.at(i)->text(6).stripWhiteSpace(); + expServer->slotExport(exportKeysList); + return; + } + KProcIO *p=new KProcIO(QTextCodec::codecForLocale()); + *p<<"gpg"<<"--no-tty"; + if (page->checkFile->isChecked()) { + expname=page->newFilename->url().stripWhiteSpace(); + if (!expname.isEmpty()) { + QFile fgpg(expname); + if (fgpg.exists()) + fgpg.remove(); + *p<<"--output"<<QFile::encodeName(expname)<<"--export"<<"--armor"; + if (!exportAttr) + *p<<"--export-options"<<"no-include-attributes"; + + for ( uint i = 0; i < exportList.count(); ++i ) + if ( exportList.at(i) ) + *p<<(exportList.at(i)->text(6)).stripWhiteSpace(); + + + p->start(KProcess::Block); + if (fgpg.exists()) + KMessageBox::information(this,i18n("Your public key \"%1\" was successfully exported\n").arg(expname)); + else + KMessageBox::sorry(this,i18n("Your public key could not be exported\nCheck the key.")); + } + } else { + + QStringList klist; + + for ( uint i = 0; i < exportList.count(); ++i ) + if ( exportList.at(i) ) + klist.append(exportList.at(i)->text(6).stripWhiteSpace()); + + KgpgInterface *kexp=new KgpgInterface(); + + QString result=kexp->getKey(klist,exportAttr); + if (page->checkClipboard->isChecked()) + slotProcessExportClip(result); + //connect(kexp,SIGNAL(publicKeyString(QString)),this,SLOT(slotProcessExportClip(QString))); + else + slotProcessExportMail(result); + //connect(kexp,SIGNAL(publicKeyString(QString)),this,SLOT(slotProcessExportMail(QString))); + + } + } + delete dial; +} + + + +void listKeys::slotProcessExportMail(QString keys) +{ + /// start default Mail application + kapp->invokeMailer(QString::null, QString::null, QString::null, QString::null, + keys, //body + QString::null, + QString::null); // attachments +} + +void listKeys::slotProcessExportClip(QString keys) +{ + kapp->clipboard()->setText(keys,clipboardMode); +} + + +void listKeys::showKeyInfo(QString keyID) +{ + KgpgKeyInfo *opts=new KgpgKeyInfo(this,"key_props",keyID); + opts->show(); +} + + +void listKeys::slotShowPhoto() +{ + KTrader::OfferList offers = KTrader::self()->query("image/jpeg", "Type == 'Application'"); + KService::Ptr ptr = offers.first(); + //KMessageBox::sorry(0,ptr->desktopEntryName()); + KProcIO *p=new KProcIO(QTextCodec::codecForLocale()); + *p<<"gpg"<<"--no-tty"<<"--photo-viewer"<<QFile::encodeName(ptr->desktopEntryName()+" %i")<<"--edit-key"<<keysList2->currentItem()->parent()->text(6)<<"uid"<<keysList2->currentItem()->text(6)<<"showphoto"<<"quit"; + p->start(KProcess::DontCare,true); +} + +void listKeys::listsigns() +{ + //kdDebug(2100)<<"Edit -------------------------------"<<endl; + if (keysList2->currentItem()==NULL) + return; + if (keysList2->currentItem()->depth()!=0) { + if (keysList2->currentItem()->text(0)==i18n("Photo id")) { + ////////////////////////// display photo + slotShowPhoto(); + } + return; + } + + if (keysList2->currentItem()->pixmap(0)->serialNumber()==keysList2->pixkeyOrphan.serialNumber()) { + if (KMessageBox::questionYesNo(this,i18n("This key is an orphaned secret key (secret key without public key.) It is currently not usable.\n\n" + "Would you like to regenerate the public key?"), QString::null, i18n("Generate"), i18n("Do Not Generate"))==KMessageBox::Yes) + slotregenerate(); + return; + } + + ///////////// open a key info dialog (KgpgKeyInfo, see begining of this file) + QString key=keysList2->currentItem()->text(6); + if (!key.isEmpty()) { + KgpgKeyInfo *opts=new KgpgKeyInfo(this,"key_props",key); + connect(opts,SIGNAL(keyNeedsRefresh()),keysList2,SLOT(refreshselfkey())); + opts->exec(); + } else + editGroup(); +} + +void listKeys::groupAdd() +{ + QPtrList<QListViewItem> addList=gEdit->availableKeys->selectedItems(); + for ( uint i = 0; i < addList.count(); ++i ) + if ( addList.at(i) ) { + gEdit->groupKeys->insertItem(addList.at(i)); + } +} + +void listKeys::groupRemove() +{ + QPtrList<QListViewItem> remList=gEdit->groupKeys->selectedItems(); + for ( uint i = 0; i < remList.count(); ++i ) + if ( remList.at(i) ) { + gEdit->availableKeys->insertItem(remList.at(i)); + } +} + +void listKeys::deleteGroup() +{ + if (!keysList2->currentItem() || !keysList2->currentItem()->text(6).isEmpty()) + return; + + int result=KMessageBox::warningContinueCancel(this,i18n("<qt>Are you sure you want to delete group <b>%1</b> ?</qt>").arg(keysList2->currentItem()->text(0)),i18n("Warning"),KGuiItem(i18n("Delete"),"editdelete")); + if (result!=KMessageBox::Continue) + return; + KgpgInterface::delGpgGroup(keysList2->currentItem()->text(0), KGpgSettings::gpgConfigPath()); + QListViewItem *item=keysList2->currentItem()->nextSibling(); + delete keysList2->currentItem(); + if (!item) + item=keysList2->lastChild(); + keysList2->setCurrentItem(item); + keysList2->setSelected(item,true); + + QStringList groups=KgpgInterface::getGpgGroupNames(KGpgSettings::gpgConfigPath()); + KGpgSettings::setGroups(groups.join(",")); + keysList2->groupNb=groups.count(); + changeMessage(i18n("%1 Keys, %2 Groups").arg(keysList2->childCount()-keysList2->groupNb).arg(keysList2->groupNb),1); +} + +void listKeys::groupChange() +{ + QStringList selected; + QListViewItem *item=gEdit->groupKeys->firstChild(); + while (item) { + selected+=item->text(2); + item=item->nextSibling(); + } + KgpgInterface::setGpgGroupSetting(keysList2->currentItem()->text(0),selected,KGpgSettings::gpgConfigPath()); +} + +void listKeys::createNewGroup() +{ + QStringList badkeys,keysGroup; + + if (keysList2->selectedItems().count()>0) { + QPtrList<QListViewItem> groupList=keysList2->selectedItems(); + bool keyDepth=true; + for ( uint i = 0; i < groupList.count(); ++i ) + if ( groupList.at(i) ) { + if (groupList.at(i)->depth()!=0) + keyDepth=false; + else if (groupList.at(i)->text(6).isEmpty()) + keyDepth=false; + else if (groupList.at(i)->pixmap(2)) { + if (groupList.at(i)->pixmap(2)->serialNumber()==keysList2->trustgood.serialNumber()) + keysGroup+=groupList.at(i)->text(6); + else + badkeys+=groupList.at(i)->text(0)+" ("+groupList.at(i)->text(1)+") "+groupList.at(i)->text(6); + } + + } + if (!keyDepth) { + KMessageBox::sorry(this,i18n("<qt>You cannot create a group containing signatures, subkeys or other groups.</qt>")); + return; + } + QString groupName=KInputDialog::getText(i18n("Create New Group"),i18n("Enter new group name:"),QString::null,0,this); + if (groupName.isEmpty()) + return; + if (!keysGroup.isEmpty()) { + if (!badkeys.isEmpty()) + KMessageBox::informationList(this,i18n("Following keys are not valid or not trusted and will not be added to the group:"),badkeys); + KgpgInterface::setGpgGroupSetting(groupName,keysGroup,KGpgSettings::gpgConfigPath()); + QStringList groups=KgpgInterface::getGpgGroupNames(KGpgSettings::gpgConfigPath()); + KGpgSettings::setGroups(groups.join(",")); + keysList2->refreshgroups(); + QListViewItem *newgrp = keysList2->findItem(groupName,0); + + keysList2->clearSelection(); + keysList2->setCurrentItem(newgrp); + keysList2->setSelected(newgrp,true); + keysList2->ensureItemVisible(newgrp); + keysList2->groupNb=groups.count(); + changeMessage(i18n("%1 Keys, %2 Groups").arg(keysList2->childCount()-keysList2->groupNb).arg(keysList2->groupNb),1); + } else + KMessageBox::sorry(this,i18n("<qt>No valid or trusted key was selected. The group <b>%1</b> will not be created.</qt>").arg(groupName)); + } +} + +void listKeys::groupInit(QStringList keysGroup) +{ + kdDebug(2100)<<"preparing group"<<endl; + QStringList lostKeys; + bool foundId; + + for ( QStringList::Iterator it = keysGroup.begin(); it != keysGroup.end(); ++it ) { + + QListViewItem *item=gEdit->availableKeys->firstChild(); + foundId=false; + while (item) { + kdDebug(2100)<<"Searching in key: "<<item->text(0)<<endl; + if (QString(*it).right(8).lower()==item->text(2).right(8).lower()) { + gEdit->groupKeys->insertItem(item); + foundId=true; + break; + } + item=item->nextSibling(); + } + if (!foundId) + lostKeys+=QString(*it); + } + if (!lostKeys.isEmpty()) + KMessageBox::informationList(this,i18n("Following keys are in the group but are not valid or not in your keyring. They will be removed from the group."),lostKeys); +} + +void listKeys::editGroup() +{ + if (!keysList2->currentItem() || !keysList2->currentItem()->text(6).isEmpty()) + return; + QStringList keysGroup; + //KDialogBase *dialogGroupEdit=new KDialogBase( this, "edit_group", true,i18n("Group Properties"),KDialogBase::Ok | KDialogBase::Cancel); + KDialogBase *dialogGroupEdit=new KDialogBase(KDialogBase::Swallow, i18n("Group Properties"), KDialogBase::Ok | KDialogBase::Cancel,KDialogBase::Ok,this,0,true); + + gEdit=new groupEdit(); + gEdit->buttonAdd->setPixmap(KGlobal::iconLoader()->loadIcon("down",KIcon::Small,20)); + gEdit->buttonRemove->setPixmap(KGlobal::iconLoader()->loadIcon("up",KIcon::Small,20)); + + connect(gEdit->buttonAdd,SIGNAL(clicked()),this,SLOT(groupAdd())); + connect(gEdit->buttonRemove,SIGNAL(clicked()),this,SLOT(groupRemove())); + // connect(dialogGroupEdit->okClicked(),SIGNAL(clicked()),this,SLOT(groupChange())); + connect(gEdit->availableKeys,SIGNAL(doubleClicked (QListViewItem *, const QPoint &, int)),this,SLOT(groupAdd())); + connect(gEdit->groupKeys,SIGNAL(doubleClicked (QListViewItem *, const QPoint &, int)),this,SLOT(groupRemove())); + QListViewItem *item=keysList2->firstChild(); + if (item==NULL) + return; + if (item->pixmap(2)) { + if (item->pixmap(2)->serialNumber()==keysList2->trustgood.serialNumber()) + (void) new KListViewItem(gEdit->availableKeys,item->text(0),item->text(1),item->text(6)); + } + while (item->nextSibling()) { + item=item->nextSibling(); + if (item->pixmap(2)) { + if (item->pixmap(2)->serialNumber()==keysList2->trustgood.serialNumber()) + (void) new KListViewItem(gEdit->availableKeys,item->text(0),item->text(1),item->text(6)); + } + } + keysGroup=KgpgInterface::getGpgGroupSetting(keysList2->currentItem()->text(0),KGpgSettings::gpgConfigPath()); + groupInit(keysGroup); + dialogGroupEdit->setMainWidget(gEdit); + gEdit->availableKeys->setColumnWidth(0,200); + gEdit->availableKeys->setColumnWidth(1,200); + gEdit->availableKeys->setColumnWidth(2,100); + gEdit->availableKeys->setColumnWidthMode(0,QListView::Manual); + gEdit->availableKeys->setColumnWidthMode(1,QListView::Manual); + gEdit->availableKeys->setColumnWidthMode(2,QListView::Manual); + + gEdit->groupKeys->setColumnWidth(0,200); + gEdit->groupKeys->setColumnWidth(1,200); + gEdit->groupKeys->setColumnWidth(2,100); + gEdit->groupKeys->setColumnWidthMode(0,QListView::Manual); + gEdit->groupKeys->setColumnWidthMode(1,QListView::Manual); + gEdit->groupKeys->setColumnWidthMode(2,QListView::Manual); + + gEdit->setMinimumSize(gEdit->sizeHint()); + gEdit->show(); + if (dialogGroupEdit->exec()==QDialog::Accepted) + groupChange(); + delete dialogGroupEdit; +} + +void listKeys::signkey() +{ + /////////////// sign a key + if (keysList2->currentItem()==NULL) + return; + if (keysList2->currentItem()->depth()!=0) + return; + + signList=keysList2->selectedItems(); + bool keyDepth=true; + for ( uint i = 0; i < signList.count(); ++i ) + if ( signList.at(i) ) + if (signList.at(i)->depth()!=0) + keyDepth=false; + if (!keyDepth) { + KMessageBox::sorry(this,i18n("You can only sign primary keys. Please check your selection.")); + return; + } + + + if (signList.count()==1) { + FILE *pass; + char line[200]=""; + QString opt,fingervalue; + QString gpgcmd="gpg --no-tty --no-secmem-warning --with-colons --fingerprint "+KShellProcess::quote(keysList2->currentItem()->text(6)); + pass=popen(QFile::encodeName(gpgcmd),"r"); + while ( fgets( line, sizeof(line), pass)) { + opt=QString::fromUtf8(line); + if (opt.startsWith("fpr")) { + fingervalue=opt.section(':',9,9); + // format fingervalue in 4-digit groups + uint len = fingervalue.length(); + if ((len > 0) && (len % 4 == 0)) + for (uint n = 0; 4*(n+1) < len; n++) + fingervalue.insert(5*n+4, ' '); + } + } + pclose(pass); + opt= i18n("<qt>You are about to sign key:<br><br>%1<br>ID: %2<br>Fingerprint: <br><b>%3</b>.<br><br>" + "You should check the key fingerprint by phoning or meeting the key owner to be sure that someone " + "is not trying to intercept your communications</qt>").arg(keysList2->currentItem()->text(0)+" ("+keysList2->currentItem()->text(1)+")").arg(keysList2->currentItem()->text(6)).arg(fingervalue); + + if (KMessageBox::warningContinueCancel(this,opt)!=KMessageBox::Continue) + return; + + } else { + QStringList signKeyList; + for ( uint i = 0; i < signList.count(); ++i ) + if ( signList.at(i) ) + signKeyList+=signList.at(i)->text(0)+" ("+signList.at(i)->text(1)+")"+": "+signList.at(i)->text(6); + if (KMessageBox::warningContinueCancelList(this,i18n("<qt>You are about to sign the following keys in one pass.<br><b>If you have not carefully checked all fingerprints, the security of your communications may be compromised.</b></qt>"),signKeyList)!=KMessageBox::Continue) + return; + } + + + ////////////////// open a secret key selection dialog (KgpgSelKey, see begining of this file) + KgpgSelKey *opts=new KgpgSelKey(this); + + QLabel *signCheck = new QLabel("<qt>"+i18n("How carefully have you checked that the key really " + "belongs to the person with whom you wish to communicate:", + "How carefully have you checked that the %n keys really " + "belong to the people with whom you wish to communicate:",signList.count()),opts->page); + opts->vbox->addWidget(signCheck); + QComboBox *signTrust=new QComboBox(opts->page); + signTrust->insertItem(i18n("I Will Not Answer")); + signTrust->insertItem(i18n("I Have Not Checked at All")); + signTrust->insertItem(i18n("I Have Done Casual Checking")); + signTrust->insertItem(i18n("I Have Done Very Careful Checking")); + opts->vbox->addWidget(signTrust); + + QCheckBox *localSign = new QCheckBox(i18n("Local signature (cannot be exported)"),opts->page); + opts->vbox->addWidget(localSign); + + QCheckBox *terminalSign = new QCheckBox(i18n("Do not sign all user id's (open terminal)"),opts->page); + opts->vbox->addWidget(terminalSign); + if (signList.count()!=1) + terminalSign->setEnabled(false); + + opts->setMinimumHeight(300); + + if (opts->exec()!=QDialog::Accepted) { + delete opts; + return; + } + + globalkeyID=QString(opts->getkeyID()); + globalkeyMail=QString(opts->getkeyMail()); + globalisLocal=localSign->isChecked(); + globalChecked=signTrust->currentItem(); + keyCount=0; + delete opts; + globalCount=signList.count(); + if (!terminalSign->isChecked()) + signLoop(); + else { + KProcess kp; + + KConfig *config = KGlobal::config(); + config->setGroup("General"); + kp<< config->readPathEntry("TerminalApplication","konsole"); + kp<<"-e" + <<"gpg" + <<"--no-secmem-warning" + <<"-u" + <<globalkeyID + <<"--edit-key" + <<signList.at(0)->text(6); + if (globalisLocal) + kp<<"lsign"; + else + kp<<"sign"; + kp.start(KProcess::Block); + keysList2->refreshcurrentkey(keysList2->currentItem()); + } +} + +void listKeys::signLoop() +{ + if (keyCount<globalCount) { + kdDebug(2100)<<"Sign process for key: "<<keyCount<<" on a total of "<<signList.count()<<endl; + if ( signList.at(keyCount) ) { + KgpgInterface *signKeyProcess=new KgpgInterface(); + QObject::connect(signKeyProcess,SIGNAL(signatureFinished(int)),this,SLOT(signatureResult(int))); + signKeyProcess->KgpgSignKey(signList.at(keyCount)->text(6),globalkeyID,globalkeyMail,globalisLocal,globalChecked); + } + } +} + +void listKeys::signatureResult(int success) +{ + if (success==3) + keysList2->refreshcurrentkey(signList.at(keyCount)); + + else if (success==2) + KMessageBox::sorry(this,i18n("<qt>Bad passphrase, key <b>%1</b> not signed.</qt>").arg(signList.at(keyCount)->text(0)+i18n(" (")+signList.at(keyCount)->text(1)+i18n(")"))); + + keyCount++; + signLoop(); +} + + +void listKeys::importallsignkey() +{ + if (keysList2->currentItem()==NULL) + return; + if (! keysList2->currentItem()->firstChild()) { + keysList2->currentItem()->setOpen(true); + keysList2->currentItem()->setOpen(false); + } + QString missingKeysList; + QListViewItem *current = keysList2->currentItem()->firstChild(); + while (current) { + if ((current->text(0).startsWith("[")) && (current->text(0).endsWith("]"))) ////// ugly hack to detect unknown keys + missingKeysList+=current->text(6)+" "; + current = current->nextSibling(); + } + if (!missingKeysList.isEmpty()) + importsignkey(missingKeysList); + else + KMessageBox::information(this,i18n("All signatures for this key are already in your keyring")); +} + + +void listKeys::preimportsignkey() +{ + if (keysList2->currentItem()==NULL) + return; + else + importsignkey(keysList2->currentItem()->text(6)); +} + +bool listKeys::importRemoteKey(QString keyID) +{ + + kServer=new keyServer(0,"server_dialog",false,true); + kServer->page->kLEimportid->setText(keyID); + kServer->page->Buttonimport->setDefault(true); + kServer->page->tabWidget2->setTabEnabled(kServer->page->tabWidget2->page(1),false); + kServer->show(); + kServer->raise(); + connect( kServer, SIGNAL( importFinished(QString) ) , this, SLOT( dcopImportFinished())); + + return true; +} + + + +void listKeys::dcopImportFinished() +{ + if (kServer) + kServer=0L; + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << true; + kapp->dcopClient()->emitDCOPSignal("keyImported(bool)", params); + refreshkey(); +} + +void listKeys::importsignkey(QString importKeyId) +{ + /////////////// sign a key + kServer=new keyServer(0,"server_dialog",false); + kServer->page->kLEimportid->setText(importKeyId); + //kServer->Buttonimport->setDefault(true); + kServer->slotImport(); + //kServer->show(); + connect( kServer, SIGNAL( importFinished(QString) ) , this, SLOT( importfinished())); +} + + +void listKeys::importfinished() +{ + if (kServer) + kServer=0L; + refreshkey(); +} + + +void listKeys::delsignkey() +{ + /////////////// sign a key + if (keysList2->currentItem()==NULL) + return; + if (keysList2->currentItem()->depth()>1) { + KMessageBox::sorry(this,i18n("Edit key manually to delete this signature.")); + return; + } + + QString signID,parentKey,signMail,parentMail; + + ////////////////// open a key selection dialog (KgpgSelKey, see begining of this file) + parentKey=keysList2->currentItem()->parent()->text(6); + signID=keysList2->currentItem()->text(6); + parentMail=keysList2->currentItem()->parent()->text(0)+" ("+keysList2->currentItem()->parent()->text(1)+")"; + signMail=keysList2->currentItem()->text(0)+" ("+keysList2->currentItem()->text(1)+")"; + + if (parentKey==signID) { + KMessageBox::sorry(this,i18n("Edit key manually to delete a self-signature.")); + return; + } + QString ask=i18n("<qt>Are you sure you want to delete signature<br><b>%1</b> from key:<br><b>%2</b>?</qt>").arg(signMail).arg(parentMail); + + if (KMessageBox::questionYesNo(this,ask,QString::null,KStdGuiItem::del(),KStdGuiItem::cancel())!=KMessageBox::Yes) + return; + KgpgInterface *delSignKeyProcess=new KgpgInterface(); + delSignKeyProcess->KgpgDelSignature(parentKey,signID); + connect(delSignKeyProcess,SIGNAL(delsigfinished(bool)),this,SLOT(delsignatureResult(bool))); +} + +void listKeys::delsignatureResult(bool success) +{ + if (success) { + QListViewItem *top=keysList2->currentItem(); + while (top->depth()!=0) + top=top->parent(); + while (top->firstChild()!=0) + delete top->firstChild(); + keysList2->refreshcurrentkey(top); + } else + KMessageBox::sorry(this,i18n("Requested operation was unsuccessful, please edit the key manually.")); +} + +void listKeys::slotedit() +{ + if (!keysList2->currentItem()) + return; + if (keysList2->currentItem()->depth()!=0) + return; + if (keysList2->currentItem()->text(6).isEmpty()) + return; + + KProcess kp; + + KConfig *config = KGlobal::config(); + config->setGroup("General"); + kp<< config->readPathEntry("TerminalApplication","konsole"); + kp<<"-e" + <<"gpg" + <<"--no-secmem-warning" + <<"--utf8-strings" + <<"--edit-key" + <<keysList2->currentItem()->text(6) + <<"help"; + kp.start(KProcess::Block); + keysList2->refreshcurrentkey(keysList2->currentItem()); +} + + +void listKeys::slotgenkey() +{ + ////////// generate key + keyGenerate *genkey=new keyGenerate(this,0); + if (genkey->exec()==QDialog::Accepted) { + if (!genkey->getmode()) /// normal mode + { + //// extract data + QString ktype=genkey->getkeytype(); + QString ksize=genkey->getkeysize(); + int kexp=genkey->getkeyexp(); + QString knumb=genkey->getkeynumb(); + newKeyName=genkey->getkeyname(); + newKeyMail=genkey->getkeymail(); + QString kcomment=genkey->getkeycomm(); + delete genkey; + + //genkey->delayedDestruct(); + QCString password; + bool goodpass=false; + while (!goodpass) + { + int code=KPasswordDialog::getNewPassword(password,i18n("<b>Enter passphrase for %1</b>:<br>Passphrase should include non alphanumeric characters and random sequences").arg(newKeyName+" <"+newKeyMail+">")); + if (code!=QDialog::Accepted) + return; + if (password.length()<5) + KMessageBox::sorry(this,i18n("This passphrase is not secure enough.\nMinimum length= 5 characters")); + else + goodpass=true; + } + + pop = new KPassivePopup((QWidget *)parent(),"new_key"); + pop->setTimeout(0); + + QWidget *wid=new QWidget(pop); + QVBoxLayout *vbox=new QVBoxLayout(wid,3); + + QVBox *passiveBox=pop->standardView(i18n("Generating new key pair."),QString::null,KGlobal::iconLoader()->loadIcon("kgpg",KIcon::Desktop),wid); + + + QMovie anim; + anim=QMovie(locate("appdata", "pics/kgpg_anim.gif")); + + QLabel *tex=new QLabel(wid); + QLabel *tex2=new QLabel(wid); + tex->setAlignment(AlignHCenter); + tex->setMovie(anim); + tex2->setText(i18n("\nPlease wait...")); + vbox->addWidget(passiveBox); + vbox->addWidget(tex); + vbox->addWidget(tex2); + + pop->setView(wid); + + pop->show(); + changeMessage(i18n("Generating New Key..."),0,true); + + QRect qRect(QApplication::desktop()->screenGeometry()); + int iXpos=qRect.width()/2-pop->width()/2; + int iYpos=qRect.height()/2-pop->height()/2; + pop->move(iXpos,iYpos); + pop->setAutoDelete(false); + KProcIO *proc=new KProcIO(QTextCodec::codecForLocale()); + message=QString::null; + //*proc<<"gpg"<<"--no-tty"<<"--no-secmem-warning"<<"--batch"<<"--passphrase-fd"<<res<<"--gen-key"<<"-a"<<"kgpg.tmp"; + *proc<<"gpg"<<"--no-tty"<<"--status-fd=2"<<"--no-secmem-warning"<<"--batch"<<"--gen-key"<<"--utf8-strings"; + ///////// when process ends, update dialog infos + QObject::connect(proc, SIGNAL(processExited(KProcess *)),this, SLOT(genover(KProcess *))); + proc->start(KProcess::NotifyOnExit,true); + + if (ktype=="RSA") + proc->writeStdin("Key-Type: 1"); + else + { + proc->writeStdin("Key-Type: DSA"); + proc->writeStdin("Subkey-Type: ELG-E"); + proc->writeStdin(QString("Subkey-Length:%1").arg(ksize)); + } + proc->writeStdin(QString("Passphrase:%1").arg(password)); + proc->writeStdin(QString("Key-Length:%1").arg(ksize)); + proc->writeStdin(QString("Name-Real:%1").arg(newKeyName)); + if (!newKeyMail.isEmpty()) + proc->writeStdin(QString("Name-Email:%1").arg(newKeyMail)); + if (!kcomment.isEmpty()) + proc->writeStdin(QString("Name-Comment:%1").arg(kcomment)); + if (kexp==0) + proc->writeStdin(QString("Expire-Date:0")); + if (kexp==1) + proc->writeStdin(QString("Expire-Date:%1").arg(knumb)); + if (kexp==2) + proc->writeStdin(QString("Expire-Date:%1w").arg(knumb)); + + if (kexp==3) + proc->writeStdin(QString("Expire-Date:%1m").arg(knumb)); + + if (kexp==4) + proc->writeStdin(QString("Expire-Date:%1y").arg(knumb)); + proc->writeStdin("%commit"); + QObject::connect(proc,SIGNAL(readReady(KProcIO *)),this,SLOT(readgenprocess(KProcIO *))); + proc->closeWhenDone(); + } else ////// start expert (=konsole) mode + { + KProcess kp; + + KConfig *config = KGlobal::config(); + config->setGroup("General"); + kp<< config->readPathEntry("TerminalApplication","konsole"); + kp<<"-e" + <<"gpg" + <<"--gen-key"; + kp.start(KProcess::Block); + refreshkey(); + } + } +} + +void listKeys::readgenprocess(KProcIO *p) +{ + QString required; + while (p->readln(required,true)!=-1) { + if (required.find("KEY_CREATED")!=-1) + newkeyFinger=required.stripWhiteSpace().section(' ',-1); + message+=required+"\n"; + } + + // sample: [GNUPG:] KEY_CREATED B 156A4305085A58C01E2988229282910254D1B368 +} + +void listKeys::genover(KProcess *) +{ + newkeyID=QString::null; + continueSearch=true; + KProcIO *conprocess=new KProcIO(QTextCodec::codecForLocale()); + *conprocess<< "gpg"; + *conprocess<<"--no-secmem-warning"<<"--with-colons"<<"--fingerprint"<<"--list-keys"<<newKeyName; + QObject::connect(conprocess,SIGNAL(readReady(KProcIO *)),this,SLOT(slotReadFingerProcess(KProcIO *))); + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(newKeyDone(KProcess *))); + conprocess->start(KProcess::NotifyOnExit,true); +} + + +void listKeys::slotReadFingerProcess(KProcIO *p) +{ + QString outp; + while (p->readln(outp)!=-1) { + if (outp.startsWith("pub") && (continueSearch)) { + newkeyID=outp.section(':',4,4).right(8).prepend("0x"); + + } + if (outp.startsWith("fpr")) { + if (newkeyFinger.lower()==outp.section(':',9,9).lower()) + continueSearch=false; + // kdDebug(2100)<<newkeyFinger<<" test:"<<outp.section(':',9,9)<<endl; + } + } +} + + +void listKeys::newKeyDone(KProcess *) +{ + changeMessage(i18n("Ready"),0); + // refreshkey(); + if (newkeyID.isEmpty()) { + delete pop; + KMessageBox::detailedSorry(this,i18n("Something unexpected happened during the key pair creation.\nPlease check details for full log output."),message); + refreshkey(); + return; + } + keysList2->refreshcurrentkey(newkeyID); + changeMessage(i18n("%1 Keys, %2 Groups").arg(keysList2->childCount()-keysList2->groupNb).arg(keysList2->groupNb),1); + KDialogBase *keyCreated=new KDialogBase( this, "key_created", true,i18n("New Key Pair Created"), KDialogBase::Ok); + newKey *page=new newKey(keyCreated); + page->TLname->setText("<b>"+newKeyName+"</b>"); + page->TLemail->setText("<b>"+newKeyMail+"</b>"); + if (!newKeyMail.isEmpty()) + page->kURLRequester1->setURL(QDir::homeDirPath()+"/"+newKeyMail.section("@",0,0)+".revoke"); + else + page->kURLRequester1->setURL(QDir::homeDirPath()+"/"+newKeyName.section(" ",0,0)+".revoke"); + page->TLid->setText("<b>"+newkeyID+"</b>"); + page->LEfinger->setText(newkeyFinger); + page->CBdefault->setChecked(true); + page->show(); + //page->resize(page->maximumSize()); + keyCreated->setMainWidget(page); + delete pop; + keyCreated->exec(); + + QListViewItem *newdef = keysList2->findItem(newkeyID,6); + if (newdef) + if (page->CBdefault->isChecked()) + slotSetDefaultKey(newdef); + else { + keysList2->clearSelection(); + keysList2->setCurrentItem(newdef); + keysList2->setSelected(newdef,true); + keysList2->ensureItemVisible(newdef); + } + if (page->CBsave->isChecked()) { + slotrevoke(newkeyID,page->kURLRequester1->url(),0,i18n("backup copy")); + if (page->CBprint->isChecked()) + connect(revKeyProcess,SIGNAL(revokeurl(QString)),this,SLOT(doFilePrint(QString))); + } else if (page->CBprint->isChecked()) { + slotrevoke(newkeyID,QString::null,0,i18n("backup copy")); + connect(revKeyProcess,SIGNAL(revokecertificate(QString)),this,SLOT(doPrint(QString))); + } +} + +void listKeys::doFilePrint(QString url) +{ + QFile qfile(url); + if (qfile.open(IO_ReadOnly)) { + QTextStream t( &qfile ); + doPrint(t.read()); + } else + KMessageBox::sorry(this,i18n("<qt>Cannot open file <b>%1</b> for printing...</qt>").arg(url)); +} + +void listKeys::doPrint(QString txt) +{ + KPrinter prt; + //kdDebug(2100)<<"Printing..."<<endl; + if (prt.setup(this)) { + QPainter painter(&prt); + QPaintDeviceMetrics metrics(painter.device()); + painter.drawText( 0, 0, metrics.width(), metrics.height(), AlignLeft|AlignTop|DontClip,txt ); + } +} + +void listKeys::deleteseckey() +{ + //////////////////////// delete a key + QString res=keysList2->currentItem()->text(0)+" ("+keysList2->currentItem()->text(1)+")"; + int result=KMessageBox::warningContinueCancel(this, + i18n("<p>Delete <b>SECRET KEY</b> pair <b>%1</b>?</p>Deleting this key pair means you will never be able to decrypt files encrypted with this key again.").arg(res), + i18n("Warning"), + KGuiItem(i18n("Delete"),"editdelete")); + if (result!=KMessageBox::Continue) + return; + + KProcess *conprocess=new KProcess(); + KConfig *config = KGlobal::config(); + config->setGroup("General"); + *conprocess<< config->readPathEntry("TerminalApplication","konsole"); + *conprocess<<"-e"<<"gpg" + <<"--no-secmem-warning" + <<"--delete-secret-key"<<keysList2->currentItem()->text(6); + QObject::connect(conprocess, SIGNAL(processExited(KProcess *)),this, SLOT(reloadSecretKeys())); + conprocess->start(KProcess::NotifyOnExit,KProcess::AllOutput); +} + +void listKeys::reloadSecretKeys() +{ + FILE *fp; + char line[300]; + keysList2->secretList=QString::null; + fp = popen("gpg --no-secmem-warning --no-tty --with-colons --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp)) { + QString lineRead=QString::fromUtf8(line); + if (lineRead.startsWith("sec")) + keysList2->secretList+="0x"+lineRead.section(':',4,4).right(8)+","; + } + pclose(fp); + deletekey(); +} + +void listKeys::confirmdeletekey() +{ + if (keysList2->currentItem()->depth()!=0) { + if ((keysList2->currentItem()->depth()==1) && (keysList2->currentItem()->text(4)=="-") && (keysList2->currentItem()->text(6).startsWith("0x"))) + delsignkey(); + return; + } + if (keysList2->currentItem()->text(6).isEmpty()) { + deleteGroup(); + return; + } + if (((keysList2->secretList.find(keysList2->currentItem()->text(6))!=-1) || (keysList2->orphanList.find(keysList2->currentItem()->text(6))!=-1)) && (keysList2->selectedItems().count()==1)) + deleteseckey(); + else { + QStringList keysToDelete; + QString secList; + QPtrList<QListViewItem> exportList=keysList2->selectedItems(); + bool secretKeyInside=false; + for ( uint i = 0; i < exportList.count(); ++i ) + if ( exportList.at(i) ) { + if (keysList2->secretList.find(exportList.at(i)->text(6))!=-1) { + secretKeyInside=true; + secList+=exportList.at(i)->text(0)+" ("+exportList.at(i)->text(1)+")<br>"; + exportList.at(i)->setSelected(false); + } else + keysToDelete+=exportList.at(i)->text(0)+" ("+exportList.at(i)->text(1)+")"; + } + + if (secretKeyInside) { + int result=KMessageBox::warningContinueCancel(this,i18n("<qt>The following are secret key pairs:<br><b>%1</b>They will not be deleted.<br></qt>").arg(secList)); + if (result!=KMessageBox::Continue) + return; + } + if (keysToDelete.isEmpty()) + return; + int result=KMessageBox::warningContinueCancelList(this,i18n("<qt><b>Delete the following public key?</b></qt>","<qt><b>Delete the following %n public keys?</b></qt>",keysToDelete.count()),keysToDelete,i18n("Warning"),KStdGuiItem::del()); + if (result!=KMessageBox::Continue) + return; + else + deletekey(); + } +} + +void listKeys::deletekey() +{ + QPtrList<QListViewItem> exportList=keysList2->selectedItems(); + if (exportList.count()==0) + return; + KProcess gp; + gp << "gpg" + << "--no-tty" + << "--no-secmem-warning" + << "--batch" + << "--yes" + << "--delete-key"; + for ( uint i = 0; i < exportList.count(); ++i ) + if ( exportList.at(i) ) + gp<<(exportList.at(i)->text(6)).stripWhiteSpace(); + gp.start(KProcess::Block); + + for ( uint i = 0; i < exportList.count(); ++i ) + if ( exportList.at(i) ) + keysList2->refreshcurrentkey(exportList.at(i)); + if (keysList2->currentItem()) { + QListViewItem * myChild = keysList2->currentItem(); + while(!myChild->isVisible()) { + myChild = myChild->nextSibling(); + if (!myChild) + break; + } + if (!myChild) { + QListViewItem * myChild = keysList2->firstChild(); + while(!myChild->isVisible()) { + myChild = myChild->nextSibling(); + if (!myChild) + break; + } + } + if (myChild) { + myChild->setSelected(true); + keysList2->setCurrentItem(myChild); + } + } + else stateChanged("empty_list"); + changeMessage(i18n("%1 Keys, %2 Groups").arg(keysList2->childCount()-keysList2->groupNb).arg(keysList2->groupNb),1); +} + + +void listKeys::slotPreImportKey() +{ + KDialogBase *dial=new KDialogBase( KDialogBase::Swallow, i18n("Key Import"), KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, this, "key_import",true); + + SrcSelect *page=new SrcSelect(); + dial->setMainWidget(page); + page->newFilename->setCaption(i18n("Open File")); + page->newFilename->setMode(KFile::File); + page->resize(page->minimumSize()); + dial->resize(dial->minimumSize()); + + if (dial->exec()==QDialog::Accepted) { + if (page->checkFile->isChecked()) { + QString impname=page->newFilename->url().stripWhiteSpace(); + if (!impname.isEmpty()) { + changeMessage(i18n("Importing..."),0,true); + ////////////////////////// import from file + KgpgInterface *importKeyProcess=new KgpgInterface(); + importKeyProcess->importKeyURL(KURL::fromPathOrURL( impname )); + connect(importKeyProcess,SIGNAL(importfinished(QStringList)),keysList2,SLOT(slotReloadKeys(QStringList))); + connect(importKeyProcess,SIGNAL(refreshOrphaned()),keysList2,SLOT(slotReloadOrphaned())); + } + } else { + QString keystr = kapp->clipboard()->text(clipboardMode); + if (!keystr.isEmpty()) { + changeMessage(i18n("Importing..."),0,true); + KgpgInterface *importKeyProcess=new KgpgInterface(); + importKeyProcess->importKey(keystr); + connect(importKeyProcess,SIGNAL(importfinished(QStringList)),keysList2,SLOT(slotReloadKeys(QStringList))); + connect(importKeyProcess,SIGNAL(refreshOrphaned()),keysList2,SLOT(slotReloadOrphaned())); + } + } + } + delete dial; +} + + +void KeyView::expandGroup(QListViewItem *item) +{ + + QStringList keysGroup=KgpgInterface::getGpgGroupSetting(item->text(0),KGpgSettings::gpgConfigPath()); + kdDebug(2100)<<keysGroup<<endl; + for ( QStringList::Iterator it = keysGroup.begin(); it != keysGroup.end(); ++it ) { + UpdateViewItem *item2=new UpdateViewItem(item,QString(*it),QString::null,QString::null,QString::null,QString::null,QString::null,QString::null); + item2->setPixmap(0,pixkeyGroup); + item2->setExpandable(false); + } +} + +QPixmap KeyView::slotGetPhoto(QString photoId,bool mini) +{ + KTempFile *phototmp=new KTempFile(); + QString popt="cp %i "+phototmp->name(); + KProcIO *p=new KProcIO(QTextCodec::codecForLocale()); + *p<<"gpg"<<"--show-photos"<<"--photo-viewer"<<QFile::encodeName(popt)<<"--list-keys"<<photoId; + p->start(KProcess::Block); + + QPixmap pixmap; + + pixmap.load(phototmp->name()); + QImage dup=pixmap.convertToImage(); + QPixmap dup2; + if (!mini) + dup2.convertFromImage(dup.scale(previewSize+5,previewSize,QImage::ScaleMin)); + else + dup2.convertFromImage(dup.scale(22,22,QImage::ScaleMin)); + phototmp->unlink(); + delete phototmp; + return dup2; +} + +void KeyView::expandKey(QListViewItem *item) +{ + + if (item->childCount()!=0) + return; // key has already been expanded + FILE *fp; + QString cycle; + QStringList tst; + char tmpline[300]; + UpdateViewItem *itemsub=NULL; + UpdateViewItem *itemuid=NULL; + UpdateViewItem *itemsig=NULL; + UpdateViewItem *itemrev=NULL; + QPixmap keyPhotoId; + int uidNumber=2; + bool dropFirstUid=false; + + kdDebug(2100)<<"Expanding Key: "<<item->text(6)<<endl; + + cycle="pub"; + bool noID=false; + fp = popen(QFile::encodeName(QString("gpg --no-secmem-warning --no-tty --with-colons --list-sigs "+item->text(6))), "r"); + + while ( fgets( tmpline, sizeof(tmpline), fp)) { + QString line = QString::fromUtf8( tmpline ); + tst=QStringList::split(":",line,true); + if ((tst[0]=="pub") && (tst[9].isEmpty())) /// Primary User Id is separated from public key + uidNumber=1; + if (tst[0]=="uid" || tst[0]=="uat") { + if (dropFirstUid) { + dropFirstUid=false; + } else { + gpgKey uidKey=extractKey(line); + + if (tst[0]=="uat") { + kdDebug(2100)<<"Found photo at uid "<<uidNumber<<endl; + itemuid= new UpdateViewItem(item,i18n("Photo id"),QString::null,QString::null,"-","-","-",QString::number(uidNumber)); + if (displayPhoto) { + kgpgphototmp=new KTempFile(); + kgpgphototmp->setAutoDelete(true); + QString pgpgOutput="cp %i "+kgpgphototmp->name(); + KProcIO *p=new KProcIO(QTextCodec::codecForLocale()); + *p<<"gpg"<<"--no-tty"<<"--photo-viewer"<<QFile::encodeName(pgpgOutput); + *p<<"--edit-key"<<item->text(6)<<"uid"<<QString::number(uidNumber)<<"showphoto"<<"quit"; + p->start(KProcess::Block); + QPixmap pixmap; + pixmap.load(kgpgphototmp->name()); + QImage dup=pixmap.convertToImage(); + QPixmap dup2; + dup2.convertFromImage(dup.scale(previewSize+5,previewSize,QImage::ScaleMin)); + itemuid->setPixmap(0,dup2); + delete kgpgphototmp; + //itemuid->setPixmap(0,keyPhotoId); + } else + itemuid->setPixmap(0,pixuserphoto); + itemuid->setPixmap(2,uidKey.trustpic); + cycle="uid"; + } else { + kdDebug(2100)<<"Found uid at "<<uidNumber<<endl; + itemuid= new UpdateViewItem(item,uidKey.gpgkeyname,uidKey.gpgkeymail,QString::null,"-","-","-","-"); + itemuid->setPixmap(2,uidKey.trustpic); + if (noID) { + item->setText(0,uidKey.gpgkeyname); + item->setText(1,uidKey.gpgkeymail); + noID=false; + } + itemuid->setPixmap(0,pixuserid); + cycle="uid"; + } + } + uidNumber++; + } else + if (tst[0]=="rev") { + gpgKey revKey=extractKey(line); + if (cycle=="uid" || cycle=="uat") + itemrev= new UpdateViewItem(itemuid,revKey.gpgkeyname,revKey.gpgkeymail+i18n(" [Revocation signature]"),"-","-","-",revKey.gpgkeycreation,revKey.gpgkeyid); + else if (cycle=="pub") { //////////////public key revoked + itemrev= new UpdateViewItem(item,revKey.gpgkeyname,revKey.gpgkeymail+i18n(" [Revocation signature]"),"-","-","-",revKey.gpgkeycreation,revKey.gpgkeyid); + dropFirstUid=true; + } else if (cycle=="sub") + itemrev= new UpdateViewItem(itemsub,revKey.gpgkeyname,revKey.gpgkeymail+i18n(" [Revocation signature]"),"-","-","-",revKey.gpgkeycreation,revKey.gpgkeyid); + itemrev->setPixmap(0,pixRevoke); + } else + + + if (tst[0]=="sig") { + gpgKey sigKey=extractKey(line); + + if (tst[10].endsWith("l")) + sigKey.gpgkeymail+=i18n(" [local]"); + + if (cycle=="pub") + itemsig= new UpdateViewItem(item,sigKey.gpgkeyname,sigKey.gpgkeymail,"-",sigKey.gpgkeyexpiration,"-",sigKey.gpgkeycreation,sigKey.gpgkeyid); + if (cycle=="sub") + itemsig= new UpdateViewItem(itemsub,sigKey.gpgkeyname,sigKey.gpgkeymail,"-",sigKey.gpgkeyexpiration,"-",sigKey.gpgkeycreation,sigKey.gpgkeyid); + if (cycle=="uid") + itemsig= new UpdateViewItem(itemuid,sigKey.gpgkeyname,sigKey.gpgkeymail,"-",sigKey.gpgkeyexpiration,"-",sigKey.gpgkeycreation,sigKey.gpgkeyid); + + itemsig->setPixmap(0,pixsignature); + } else + if (tst[0]=="sub") { + gpgKey subKey=extractKey(line); + itemsub= new UpdateViewItem(item,i18n("%1 subkey").arg(subKey.gpgkeyalgo),QString::null,QString::null,subKey.gpgkeyexpiration,subKey.gpgkeysize,subKey.gpgkeycreation,subKey.gpgkeyid); + itemsub->setPixmap(0,pixkeySingle); + itemsub->setPixmap(2,subKey.trustpic); + cycle="sub"; + + } + } + pclose(fp); +} + + +void listKeys::refreshkey() +{ + keysList2->refreshkeylist(); + listViewSearch->updateSearch(listViewSearch->text()); +} + +void KeyView::refreshkeylist() +{ + emit statusMessage(i18n("Loading Keys..."),0,true); + kapp->processEvents(); + //////// update display of keys in main management window + kdDebug(2100)<<"Refreshing key list"<<endl; + QString tst; + char line[300]; + UpdateViewItem *item=NULL; + bool noID=false; + bool emptyList=true; + QString openKeys; + + // get current position. + QListViewItem *current = currentItem(); + if(current != NULL) { + while(current->depth() > 0) { + current = current->parent(); + } + takeItem(current); + } + + // refill + clear(); + FILE *fp2,*fp; + QStringList issec; + secretList=QString::null; + orphanList=QString::null; + fp2 = popen("gpg --no-secmem-warning --no-tty --with-colons --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp2)) { + QString lineRead=QString::fromUtf8(line); + kdDebug(2100) << k_funcinfo << "Read one secret key line: " << lineRead << endl; + if (lineRead.startsWith("sec")) + issec<<lineRead.section(':',4,4).right(8); + } + pclose(fp2); + + QString defaultKey = KGpgSettings::defaultKey(); + fp = popen("gpg --no-secmem-warning --no-tty --with-colons --list-keys", "r"); + while ( fgets( line, sizeof(line), fp)) { + tst=QString::fromUtf8(line); + kdDebug(2100) << k_funcinfo << "Read one public key line: " << tst << endl; + if (tst.startsWith("pub")) { + emptyList=false; + noID=false; + gpgKey pubKey=extractKey(tst); + + bool isbold=false; + bool isexpired=false; + if (pubKey.gpgkeyid==defaultKey) + isbold=true; + if (pubKey.gpgkeytrust==i18n("Expired")) + isexpired=true; + if (pubKey.gpgkeyname.isEmpty()) + noID=true; + + item=new UpdateViewItem(this,pubKey.gpgkeyname,pubKey.gpgkeymail,QString::null,pubKey.gpgkeyexpiration,pubKey.gpgkeysize,pubKey.gpgkeycreation,pubKey.gpgkeyid,isbold,isexpired); + + item->setPixmap(2,pubKey.trustpic); + item->setExpandable(true); + + + QStringList::Iterator ite; + ite=issec.find(pubKey.gpgkeyid.right(8)); + if (ite!=issec.end()) { + item->setPixmap(0,pixkeyPair); + secretList+=pubKey.gpgkeyid; + issec.remove(*ite); + } else item->setPixmap(0,pixkeySingle); + + if (openKeys.find(pubKey.gpgkeyid)!=-1) + item->setOpen(true); + } + + } + pclose(fp); + if (!issec.isEmpty()) + insertOrphanedKeys(issec); + if (emptyList) { + kdDebug(2100)<<"No key found"<<endl; + emit statusMessage(i18n("Ready"),0); + return; + } + kdDebug(2100)<<"Checking Groups"<<endl; + QStringList groups=KgpgInterface::getGpgGroupNames(KGpgSettings::gpgConfigPath()); + groupNb=groups.count(); + for ( QStringList::Iterator it = groups.begin(); it != groups.end(); ++it ) + if (!QString(*it).isEmpty()) { + item=new UpdateViewItem(this,QString(*it),QString::null,QString::null,QString::null,QString::null,QString::null,QString::null,false,false); + item->setPixmap(0,pixkeyGroup); + item->setExpandable(false); + } + kdDebug(2100)<<"Finished Groups"<<endl; + + QListViewItem *newPos=0L; + if(current != NULL) { + // select previous selected + if (!current->text(6).isEmpty()) + newPos = findItem(current->text(6), 6); + else + newPos = findItem(current->text(0), 0); + delete current; + } + + if (newPos != 0L) { + setCurrentItem(newPos); + setSelected(newPos, true); + ensureItemVisible(newPos); + } else { + setCurrentItem(firstChild()); + setSelected(firstChild(),true); + } + + emit statusMessage(i18n("%1 Keys, %2 Groups").arg(childCount()-groupNb).arg(groupNb),1); + emit statusMessage(i18n("Ready"),0); + kdDebug(2100)<<"Refresh Finished"<<endl; +} + +void KeyView::insertOrphan(QString currentID) +{ + FILE *fp; + char line[300]; + UpdateViewItem *item=NULL; + bool keyFound=false; + fp = popen("gpg --no-secmem-warning --no-tty --with-colons --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp)) { + QString lineRead=QString::fromUtf8(line); + if ((lineRead.startsWith("sec")) && (lineRead.section(':',4,4).right(8))==currentID.right(8)) { + gpgKey orphanedKey=extractKey(lineRead); + keyFound=true; + bool isbold=false; + bool isexpired=false; + // if (orphanedKey.gpgkeyid==defaultKey) + // isbold=true; + if (orphanedKey.gpgkeytrust==i18n("Expired")) + isexpired=true; + // if (orphanedKey.gpgkeyname.isEmpty()) + // noID=true; + + item=new UpdateViewItem(this,orphanedKey.gpgkeyname,orphanedKey.gpgkeymail,QString::null,orphanedKey.gpgkeyexpiration,orphanedKey.gpgkeysize,orphanedKey.gpgkeycreation,orphanedKey.gpgkeyid,isbold,isexpired); + item->setPixmap(0,pixkeyOrphan); + } + } + pclose(fp); + if (!keyFound) { + orphanList.remove(currentID); + setSelected(currentItem(),true); + return; + } + clearSelection(); + setCurrentItem(item); + setSelected(item,true); +} + +void KeyView::insertOrphanedKeys(QStringList orphans) +{ + FILE *fp; + char line[300]; + fp = popen("gpg --no-secmem-warning --no-tty --with-colons --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp)) { + QString lineRead=QString::fromUtf8(line); + if ((lineRead.startsWith("sec")) && (orphans.find(lineRead.section(':',4,4).right(8))!=orphans.end())) { + gpgKey orphanedKey=extractKey(lineRead); + + bool isbold=false; + bool isexpired=false; + // if (orphanedKey.gpgkeyid==defaultKey) + // isbold=true; + if (orphanedKey.gpgkeytrust==i18n("Expired")) + isexpired=true; + // if (orphanedKey.gpgkeyname.isEmpty()) + // noID=true; + orphanList+=orphanedKey.gpgkeyid+","; + UpdateViewItem *item=new UpdateViewItem(this,orphanedKey.gpgkeyname,orphanedKey.gpgkeymail,QString::null,orphanedKey.gpgkeyexpiration,orphanedKey.gpgkeysize,orphanedKey.gpgkeycreation,orphanedKey.gpgkeyid,isbold,isexpired); + item->setPixmap(0,pixkeyOrphan); + } + } + pclose(fp); +} + +void KeyView::refreshgroups() +{ + QListViewItem *item=firstChild(); + while (item) { + if (item->text(6).isEmpty()) { + QListViewItem *item2=item->nextSibling(); + delete item; + item=item2; + } else + item=item->nextSibling(); + } + + QStringList groups=KgpgInterface::getGpgGroupNames(KGpgSettings::gpgConfigPath()); + groupNb=groups.count(); + for ( QStringList::Iterator it = groups.begin(); it != groups.end(); ++it ) + if (!QString(*it).isEmpty()) { + item=new UpdateViewItem(this,QString(*it),QString::null,QString::null,QString::null,QString::null,QString::null,QString::null,false,false); + item->setPixmap(0,pixkeyGroup); + item->setExpandable(false); + } + emit statusMessage(i18n("%1 Keys, %2 Groups").arg(childCount()-groupNb).arg(groupNb),1); + emit statusMessage(i18n("Ready"),0); +} + +void KeyView::refreshselfkey() +{ + kdDebug(2100)<<"Refreshing key"<<endl; + if (currentItem()->depth()==0) + refreshcurrentkey(currentItem()); + else + refreshcurrentkey(currentItem()->parent()); +} + +void KeyView::slotReloadKeys(QStringList keyIDs) +{ + if (keyIDs.isEmpty()) + return; + if (keyIDs.first()=="ALL") + { + refreshkeylist(); + return; + } + for ( QStringList::Iterator it = keyIDs.begin(); it != keyIDs.end(); ++it ) { + refreshcurrentkey(*it); + } + kdDebug(2100)<<"Refreshing key:--------"<<(keyIDs.last()).right(8).prepend("0x")<<endl; + ensureItemVisible(this->findItem((keyIDs.last()).right(8).prepend("0x"),6)); + emit statusMessage(i18n("%1 Keys, %2 Groups").arg(childCount()-groupNb).arg(groupNb),1); + emit statusMessage(i18n("Ready"),0); +} + +void KeyView::slotReloadOrphaned() +{ + QStringList issec; + FILE *fp,*fp2; + char line[300]; + + fp2 = popen("gpg --no-secmem-warning --no-tty --with-colons --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp2)) { + QString lineRead=QString::fromUtf8(line); + if (lineRead.startsWith("sec")) + issec<<"0x"+lineRead.section(':',4,4).right(8); + } + pclose(fp2); + + fp = popen("gpg --no-secmem-warning --no-tty --with-colons --list-keys", "r"); + while ( fgets( line, sizeof(line), fp)) { + QString lineRead=QString::fromUtf8(line); + if (lineRead.startsWith("pub")) + issec.remove("0x"+lineRead.section(':',4,4).right(8)); + } + pclose(fp); + + QStringList::Iterator it; + + for ( it = issec.begin(); it != issec.end(); ++it ) { + if (findItem(*it,6)==0) { + insertOrphan(*it); + orphanList+=*it+","; + } + } + setSelected(findItem(*it,6),true); + emit statusMessage(i18n("%1 Keys, %2 Groups").arg(childCount()-groupNb).arg(groupNb),1); + emit statusMessage(i18n("Ready"),0); +} + +void KeyView::refreshcurrentkey(QString currentID) +{ + if (currentID.isNull()) return; + UpdateViewItem *item=NULL; + QString issec=QString::null; + FILE *fp,*fp2; + char line[300]; + + fp2 = popen("gpg --no-secmem-warning --no-tty --with-colons --list-secret-keys", "r"); + while ( fgets( line, sizeof(line), fp2)) { + QString lineRead=QString::fromUtf8(line); + if (lineRead.startsWith("sec")) + issec+=lineRead.section(':',4,4); + } + pclose(fp2); + + QString defaultKey = KGpgSettings::defaultKey(); + + QString tst; + bool keyFound=false; + QString cmd="gpg --no-secmem-warning --no-tty --with-colons --list-keys "+currentID; + fp = popen(QFile::encodeName(cmd), "r"); + while ( fgets( line, sizeof(line), fp)) { + tst=QString::fromUtf8(line); + if (tst.startsWith("pub")) { + gpgKey pubKey=extractKey(tst); + keyFound=true; + bool isbold=false; + bool isexpired=false; + if (pubKey.gpgkeyid==defaultKey) + isbold=true; + if (pubKey.gpgkeytrust==i18n("Expired")) + isexpired=true; + item=new UpdateViewItem(this,pubKey.gpgkeyname,pubKey.gpgkeymail,QString::null,pubKey.gpgkeyexpiration,pubKey.gpgkeysize,pubKey.gpgkeycreation,pubKey.gpgkeyid,isbold,isexpired); + item->setPixmap(2,pubKey.trustpic); + item->setVisible(true); + item->setExpandable(true); + if (issec.find(pubKey.gpgkeyid.right(8),0,FALSE)!=-1) { + item->setPixmap(0,pixkeyPair); + secretList+=pubKey.gpgkeyid; + } else { + item->setPixmap(0,pixkeySingle); + } + } + } + pclose(fp); + + if (!keyFound) { + if (orphanList.find(currentID)==-1) + orphanList+=currentID+","; + insertOrphan(currentID); + return; + } + if (orphanList.find(currentID)!=-1) + orphanList.remove(currentID); + + clearSelection(); + setCurrentItem(item); + +} + +void KeyView::refreshcurrentkey(QListViewItem *current) +{ + if (!current) + return; + bool keyIsOpen=false; + QString keyUpdate=current->text(6); + if (keyUpdate.isEmpty()) + return; + if (current->isOpen()) + keyIsOpen=true; + delete current; + refreshcurrentkey(keyUpdate); + if (currentItem()) + if (currentItem()->text(6)==keyUpdate) + currentItem()->setOpen(keyIsOpen); +} + + +void KeyView::refreshTrust(int color,QColor newColor) +{ +if (!newColor.isValid()) return; +QPixmap blankFrame,newtrust; +int trustFinger=0; +blankFrame.load(locate("appdata", "pics/kgpg_blank.png")); +newtrust.load(locate("appdata", "pics/kgpg_fill.png")); +newtrust.fill(newColor); +bitBlt(&newtrust,0,0,&blankFrame,0,0,50,15); +switch (color) +{ +case GoodColor: +trustFinger=trustgood.serialNumber(); +trustgood=newtrust; +break; +case BadColor: +trustFinger=trustbad.serialNumber(); +trustbad=newtrust; +break; +case UnknownColor: +trustFinger=trustunknown.serialNumber(); +trustunknown=newtrust; +break; +case RevColor: +trustFinger=trustrevoked.serialNumber(); +trustrevoked=newtrust; +break; +} +QListViewItem *item=firstChild(); + while (item) { + if (item->pixmap(2)) + { + if (item->pixmap(2)->serialNumber()==trustFinger) item->setPixmap(2,newtrust); + } + item=item->nextSibling(); + } +} + +gpgKey KeyView::extractKey(QString keyColon) +{ + QStringList keyString=QStringList::split(":",keyColon,true); + gpgKey ret; + + ret.gpgkeysize=keyString[2]; + ret.gpgkeycreation=keyString[5]; + if(!ret.gpgkeycreation.isEmpty()) { + QDate date = QDate::fromString(ret.gpgkeycreation, Qt::ISODate); + ret.gpgkeycreation=KGlobal::locale()->formatDate(date, true); + } + QString tid=keyString[4]; + ret.gpgkeyid=QString("0x"+tid.right(8)); + ret.gpgkeyexpiration=keyString[6]; + if (ret.gpgkeyexpiration.isEmpty()) + ret.gpgkeyexpiration=i18n("Unlimited"); + else { + QDate date = QDate::fromString(ret.gpgkeyexpiration, Qt::ISODate); + ret.gpgkeyexpiration=KGlobal::locale()->formatDate(date, true); + } + QString fullname=keyString[9]; + if (fullname.find("<")!=-1) { + ret.gpgkeymail=fullname.section('<',-1,-1); + ret.gpgkeymail.truncate(ret.gpgkeymail.length()-1); + ret.gpgkeyname=fullname.section('<',0,0); + //ret.gpgkeyname=ret.gpgkeyname.section('(',0,0); + } else { + ret.gpgkeymail=QString::null; + ret.gpgkeyname=fullname; + //ret.gpgkeyname=fullname.section('(',0,0); + } + + //ret.gpgkeyname=KgpgInterface::checkForUtf8(ret.gpgkeyname); // FIXME lukas + + QString algo=keyString[3]; + if (!algo.isEmpty()) + switch( algo.toInt() ) { + case 1: + algo=i18n("RSA"); + break; + case 16: + case 20: + algo=i18n("ElGamal"); + break; + case 17: + algo=i18n("DSA"); + break; + default: + algo=QString("#" + algo); + break; + } + ret.gpgkeyalgo=algo; + + const QString trust=keyString[1]; + switch( trust[0] ) { + case 'o': + ret.gpgkeytrust=i18n("Unknown"); + ret.trustpic=trustunknown; + break; + case 'i': + ret.gpgkeytrust=i18n("Invalid"); + ret.trustpic=trustbad; + break; + case 'd': + ret.gpgkeytrust=i18n("Disabled"); + ret.trustpic=trustbad; + break; + case 'r': + ret.gpgkeytrust=i18n("Revoked"); + ret.trustpic=trustrevoked; + break; + case 'e': + ret.gpgkeytrust=i18n("Expired"); + ret.trustpic=trustbad; + break; + case 'q': + ret.gpgkeytrust=i18n("Undefined"); + ret.trustpic=trustunknown; + break; + case 'n': + ret.gpgkeytrust=i18n("None"); + ret.trustpic=trustunknown; + break; + case 'm': + ret.gpgkeytrust=i18n("Marginal"); + ret.trustpic=trustbad; + break; + case 'f': + ret.gpgkeytrust=i18n("Full"); + ret.trustpic=trustgood; + break; + case 'u': + ret.gpgkeytrust=i18n("Ultimate"); + ret.trustpic=trustgood; + break; + default: + ret.gpgkeytrust=i18n("?"); + ret.trustpic=trustunknown; + break; + } + if (keyString[11].find('D')!=-1) { + ret.gpgkeytrust=i18n("Disabled"); + ret.trustpic=trustbad; + } + + return ret; +} + +#include "listkeys.moc" diff --git a/kgpg/listkeys.h b/kgpg/listkeys.h new file mode 100644 index 0000000..b2610db --- /dev/null +++ b/kgpg/listkeys.h @@ -0,0 +1,302 @@ +/*************************************************************************** + listkeys.h - description + ------------------- + begin : Thu Jul 4 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef LISTKEYS_H +#define LISTKEYS_H + +#include <kdialogbase.h> +#include <klistview.h> +#include <kmainwindow.h> +#include <klistviewsearchline.h> + +#include <kactionclasses.h> +#include <qclipboard.h> + +#include "dcopiface.h" + +#include <qptrlist.h> +#include <qstringlist.h> +#include <kurl.h> + +#include <qcheckbox.h> +#include <kmainwindow.h> + +class QPushButton; +class QPopupMenu; +class QLabel; +class QCheckbox; +class KStatusBar; +class KPassivePopup; +class KProcess; +class KProcIO; +class QEvent; +class KTempFile; +class KgpgApp; +class keyServer; +class groupEdit; +class KgpgInterface; +class KSelectAction; + +struct gpgKey +{ + QString gpgkeymail; + QString gpgkeyname; + QString gpgkeyid; + QString gpgkeytrust; + QString gpgkeyvalidity; + QString gpgkeysize; + QString gpgkeycreation; + QString gpgkeyexpiration; + QString gpgkeyalgo; + QPixmap trustpic; +}; + +class KgpgSelKey : public KDialogBase +{ + Q_OBJECT + +public: + KgpgSelKey( QWidget *parent = 0, const char *name = 0,bool allowMultipleSelection=false, QString preselected=QString::null); + KListView *keysListpr; + QPixmap keyPair; + QCheckBox *local; + QVBoxLayout *vbox; + QWidget *page; +private slots: + void slotOk(); + void slotpreOk(); + void slotSelect(QListViewItem *item); + +public slots: + QString getkeyID(); + QString getkeyMail(); +}; + + + +class KeyView : public KListView +{ + Q_OBJECT + friend class listKeys; +public: + KeyView( QWidget *parent = 0, const char *name = 0); + bool displayPhoto,displayOnlySecret,displayDisabled; + int previewSize; + QString secretList; + QPixmap trustbad; + +private: + + QString orphanList; + QString photoKeysList; + QPixmap pixkeyPair, pixkeySingle, pixkeyGroup, pixsignature, pixuserid, pixuserphoto; + QPixmap trustunknown, trustrevoked, trustgood, pixRevoke, pixkeyOrphan; + QListViewItem *itemToOpen; + KTempFile *kgpgphototmp; + int groupNb; + +public slots: + void slotRemoveColumn(int d); + void slotAddColumn(int c); + +private slots: + void refreshTrust(int color,QColor newColor); + void droppedfile (KURL); + void refreshkeylist(); + gpgKey extractKey(QString keyColon); + void expandKey(QListViewItem *item); + void expandGroup(QListViewItem *item); + void refreshcurrentkey(QListViewItem *current); + void refreshcurrentkey(QString currentID); + void refreshselfkey(); + void refreshgroups(); + void insertOrphanedKeys(QStringList orpans); + void insertOrphan(QString currentID); + QPixmap slotGetPhoto(QString photoId,bool mini=false); + void slotReloadKeys(QStringList keyIDs); + void slotReloadOrphaned(); + +signals: + void statusMessage(QString,int,bool keep=false); + +protected: + virtual void startDrag(); + virtual void contentsDragMoveEvent(QDragMoveEvent *e); + virtual void contentsDropEvent (QDropEvent*); +}; + +class mySearchLine: public KListViewSearchLine +{ + Q_OBJECT +public: + mySearchLine(QWidget *parent = 0, KeyView *listView = 0, const char *name = 0); + virtual ~mySearchLine(); +private: + KeyView *searchListView; + +public slots: +virtual void updateSearch(const QString &s = QString::null); +protected: +virtual bool itemMatches(const QListViewItem *item, const QString & s) const; +}; + + +class listKeys : public KMainWindow, virtual public KeyInterface +{ + friend class KeyView; + Q_OBJECT + +public: + listKeys(QWidget *parent=0, const char *name=0); + ~listKeys(); + QLabel *keyPhoto; + KeyView *keysList2; + QPopupMenu *popup,*popupsec,*popupout,*popupsig,*popupgroup,*popupphoto,*popupuid,*popuporphan; + QString message; + QStringList keynames; + KPassivePopup *pop; + KToggleAction *sTrust,*sCreat,*sExpi,*sSize; + KSelectAction *photoProps; + KStatusBar *keyStatusBar; + KgpgApp *s_kgpgEditor; + +private: + QPushButton *bouton1,*bouton2,*bouton0; + QString tempKeyFile,newKeyMail,newKeyName,newkeyFinger,newkeyID; + KListViewSearchLine* listViewSearch; + bool continueSearch; + bool showPhoto; + keyServer *kServer; + KTempFile *kgpgtmp; + KAction *importSignatureKey,*importAllSignKeys,*signKey,*refreshKey; + QPtrList<QListViewItem> signList,keysList; + uint globalCount,keyCount; + int globalChecked; + bool globalisLocal,showTipOfDay; + QString globalkeyMail,globalkeyID,searchString; + long searchOptions; + groupEdit *gEdit; + KgpgInterface *revKeyProcess; + KDialogBase *addUidWidget; + QClipboard::Mode clipboardMode; + QTimer *statusbarTimer; + + +protected: + void closeEvent( QCloseEvent * e ); + bool eventFilter( QObject *, QEvent *e ); + +public slots: + void slotgenkey(); + void refreshkey(); + void readAllOptions(); + void showKeyInfo(QString keyID); + void findKey(); + void findFirstKey(); + void findNextKey(); + void slotSetDefaultKey(QString newID); + +private slots: + void quitApp(); + void slotOpenEditor(); + void changeMessage(QString,int, bool keep=false); + void statusBarTimeout(); + void slotShowTrust(); + void slotShowSize(); + void slotShowCreat(); + void slotShowExpi(); + void slotToggleSecret(); + void slotToggleDisabled(); + void slotGotoDefaultKey(); + void slotDelUid(); + void slotAddUid(); + void slotAddUidEnable(const QString & name); + void slotGpgError(QString errortxt); + void slotUpdatePhoto(); + void slotDeletePhoto(); + void slotAddPhoto(); + void slotSetPhotoSize(int size); + void slotShowPhoto(); + void readgenprocess(KProcIO *p); + void newKeyDone(KProcess *); + void slotrevoke(QString keyID,QString revokeUrl,int reason,QString description); + void revokeWidget(); + void doFilePrint(QString url); + void doPrint(QString txt); + void checkList(); + void signLoop(); + void slotManpage(); + void slotTip(); + void showKeyServer(); + void showKeyManager(); + void slotReadFingerProcess(KProcIO *p); + void slotProcessExportMail(QString keys); + void slotProcessExportClip(QString keys); + void readOptions(); + void genover(KProcess *p); + void showOptions(); + void slotSetDefKey(); + void slotSetDefaultKey(QListViewItem *newdef); + void annule(); + void confirmdeletekey(); + void deletekey(); + void deleteseckey(); + void signkey(); + void delsignkey(); + void preimportsignkey(); + bool importRemoteKey(QString keyID); + void importsignkey(QString importKeyId); + void importallsignkey(); + void importfinished(); + void signatureResult(int success); + void delsignatureResult(bool); + void listsigns(); + void slotexport(); + void slotexportsec(); + void slotmenu(QListViewItem *,const QPoint &,int); + void slotPreImportKey(); + void slotedit(); + void addToKAB(); + // void allToKAB(); + void editGroup(); + void groupAdd(); + void groupRemove(); + void groupInit(QStringList keysGroup); + void groupChange(); + void createNewGroup(); + void deleteGroup(); + void slotImportRevoke(QString url); + void slotImportRevokeTxt(QString revokeText); + void refreshKeyFromServer(); + void refreshFinished(); + void slotregenerate(); + void reloadSecretKeys(); + void dcopImportFinished(); + +signals: + void readAgainOptions(); + void certificate(QString); + void closeAsked(); + void fontChanged(QFont); + void encryptFiles(KURL::List); + void installShredder(); + +}; + + +#endif // LISTKEYS_H + diff --git a/kgpg/listkeys.rc b/kgpg/listkeys.rc new file mode 100644 index 0000000..a2dff30 --- /dev/null +++ b/kgpg/listkeys.rc @@ -0,0 +1,137 @@ +<!DOCTYPE kpartgui> +<kpartgui name="listkeys" version="33"> + +<MenuBar> + <Menu name="managekeys"><text>&Keys</text> + <Action name="key_info"/> + <Action name="key_server_refresh"/> + <Action name="key_sign"/> + <Action name="key_edit"/> + <Action name="key_gener"/> + <Separator /> + <Action name="key_export"/> + <Action name="key_import"/> + <Action name="add_kab"/> + </Menu> + + <Menu name="edit"> + <Action name="go_default_key"/> + </Menu> + + <Menu name="view"><text>&View</text> + <Action name="show_secret"/> + <Action name="hide_disabled"/> + <Menu name="show_details"><text>&Show Details</text> + <Action name="show_trust"/> + <Action name="show_expi"/> + <Action name="show_size"/> + <Action name="show_creat"/> + </Menu> + <Action name="photo_settings" /> + <Action name="key_refresh"/> + </Menu> + + <Menu name="groups"><text>&Groups</text> + <Action name="create_group"/> + <Action name="edit_group"/> + <Action name="delete_group"/> + </Menu> + + + + + + <Menu name="file"> + <Action name="key_server"/> + <Action name="kgpg_editor"/> + </Menu> + + <Menu name="help"> + <Action name="help_tipofday"/> + <Action name="gpg_man"/> + </Menu> +</MenuBar> + + +<ToolBar name="mainToolBar" position="top"> + <Action name="key_info"/> + <Action name="key_sign"/> + <Separator/> + <Action name="key_import"/> + <Action name="key_export"/> + <Action name="key_server"/> +</ToolBar> + +<State name="group_selected"> + <enable> + <Action name="edit_group"/> + <Action name="delete_group"/> + </enable> + <disable> + <Action name="add_kab"/> + <Action name="key_server_refresh"/> + <Action name="create_group"/> + <Action name="key_info"/> + <Action name="key_sign"/> + <Action name="key_edit"/> + <Action name="key_export"/> + <Action name="key_import"/> + </disable> +</State> + +<State name="single_selected"> + <disable> + <Action name="edit_group"/> + <Action name="delete_group"/> + </disable> + <enable> + <Action name="key_server_refresh"/> + <Action name="add_kab"/> + <Action name="key_sign"/> + <Action name="key_export"/> + <Action name="key_import"/> + <Action name="key_default"/> + <Action name="key_edit"/> + <Action name="key_info"/> + <Action name="key_importallsign"/> + <Action name="create_group"/> + </enable> +</State> + +<State name="multi_selected"> + <disable> + <Action name="add_kab"/> + <Action name="edit_group"/> + <Action name="delete_group"/> + <Action name="key_default"/> + <Action name="key_edit"/> + <Action name="key_info"/> + <Action name="key_importallsign"/> + </disable> + <enable> + <Action name="key_server_refresh"/> + <Action name="key_sign"/> + <Action name="key_export"/> + <Action name="key_import"/> + <Action name="create_group"/> + </enable> +</State> + +<State name="empty_list"> + <disable> + <Action name="edit_group"/> + <Action name="delete_group"/> + <Action name="key_default"/> + <Action name="key_edit"/> + <Action name="key_info"/> + <Action name="key_importallsign"/> + <Action name="key_server_refresh"/> + <Action name="key_sign"/> + <Action name="key_export"/> + <Action name="key_import"/> + <Action name="create_group"/> + <Action name="add_kab"/> + </disable> +</State> + +</kpartgui> diff --git a/kgpg/main.cpp b/kgpg/main.cpp new file mode 100644 index 0000000..622739f --- /dev/null +++ b/kgpg/main.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + main.cpp - description + ------------------- + begin : Mon Jul 8 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qstring.h> +#include <kmessagebox.h> + + +#include <kuniqueapplication.h> +#include <dcopclient.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include "kgpg.h" + +static const char description[] = + I18N_NOOP("Kgpg - simple gui for gpg\n\nKgpg was designed to make gpg very easy to use.\nI tried to make it as secure as possible.\nHope you enjoy it."); + +static const char version[] = "1.2.2"; + +static KCmdLineOptions options[] = + { + { "e", I18N_NOOP("Encrypt file"), 0 }, + { "k", I18N_NOOP("Open key manager"), 0 }, + { "s", I18N_NOOP("Show encrypted file"), 0 }, + { "S", I18N_NOOP("Sign file"), 0 }, + { "V", I18N_NOOP("Verify signature"), 0 }, + { "X", I18N_NOOP("Shred file"), 0 }, + { "+[File]", I18N_NOOP("File to open"), 0 }, + KCmdLineLastOption + // INSERT YOUR COMMANDLINE OPTIONS HERE + }; + +int main(int argc, char *argv[]) +{ + + KAboutData about("kgpg", I18N_NOOP("KGpg"), version, description, + KAboutData::License_GPL, "(C) 2003 Jean-Baptiste Mardelle"); + about.addAuthor( "Jean-Baptiste Mardelle", 0, "bj@altern.org" ); + KCmdLineArgs::init(argc, argv, &about); + KCmdLineArgs::addCmdLineOptions(options); + KUniqueApplication::addCmdLineOptions(); + + + //KMessageBox::sorry(0,"nombre: "+QString::number(i)); + + if (!KUniqueApplication::start()) + return 0; + + //KgpgAppletApp *app; + KApplication *app; + app=new KgpgAppletApp; + return app->exec(); + + /* + + KUniqueApplication app; + + // register ourselves as a dcop client + //app.dcopClient()->registerAs(app.name(), false); + + + kgpgapplet widget;// = new kgpgapplet("kgpg"); + widget.show(); + return app.exec();*/ +} diff --git a/kgpg/newkey.ui b/kgpg/newkey.ui new file mode 100644 index 0000000..ad6b0aa --- /dev/null +++ b/kgpg/newkey.ui @@ -0,0 +1,196 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>newKey</class> +<widget class="QWidget"> + <property name="name"> + <cstring>newKey</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>625</width> + <height>328</height> + </rect> + </property> + <property name="caption"> + <string>New Key Pair Created</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox2</cstring> + </property> + <property name="title"> + <string>New Key Created</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>You have successfully created the following key:</string> + </property> + </widget> + <widget class="QCheckBox" row="6" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>CBdefault</cstring> + </property> + <property name="text"> + <string>Set as your default key</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><b>Set as your default key:</b><br /> + <p>Checking this option sets the newly created key pair as the default key pair.</p> + </qt></string> + </property> + </widget> + <widget class="KLineEdit" row="5" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>LEfinger</cstring> + </property> + <property name="frame"> + <bool>true</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="text"> + <string>Fingerprint:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Email:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel5</cstring> + </property> + <property name="text"> + <string>Key ID:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>TLname</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>textLabel7</string> + </property> + </widget> + <widget class="QLabel" row="2" column="1"> + <property name="name"> + <cstring>TLemail</cstring> + </property> + <property name="text"> + <string>textLabel8</string> + </property> + </widget> + <widget class="QLabel" row="3" column="1"> + <property name="name"> + <cstring>TLid</cstring> + </property> + <property name="text"> + <string>textLabel10</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Revocation Certificate</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>It is recommended to save or print a revocation certificate in case your key is compromised.</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>CBprint</cstring> + </property> + <property name="text"> + <string>Print</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>CBsave</cstring> + </property> + <property name="text"> + <string>Save as:</string> + </property> + </widget> + <widget class="KURLRequester" row="1" column="1"> + <property name="name"> + <cstring>kURLRequester1</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>CBsave</sender> + <signal>toggled(bool)</signal> + <receiver>newKey</receiver> + <slot>CBsave_toggled(bool)</slot> + </connection> +</connections> +<includes> + <include location="local" impldecl="in implementation">newkey.ui.h</include> +</includes> +<slots> + <slot>CBsave_toggled( bool isOn )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kgpg/newkey.ui.h b/kgpg/newkey.ui.h new file mode 100644 index 0000000..e920edd --- /dev/null +++ b/kgpg/newkey.ui.h @@ -0,0 +1,21 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ +//(C) 2002 Jean-Baptiste Mardelle <bj@altern.org> + +void newKey::CBsave_toggled( bool isOn) +{ +kURLRequester1->setEnabled(isOn); +} diff --git a/kgpg/popuppublic.cpp b/kgpg/popuppublic.cpp new file mode 100644 index 0000000..167423c --- /dev/null +++ b/kgpg/popuppublic.cpp @@ -0,0 +1,480 @@ +/*************************************************************************** + popuppublic.cpp - description + ------------------- + begin : Sat Jun 29 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +//////////////////////////////////////////////////////// code for choosing a public key from a list for encryption +#include <qlayout.h> +#include <qpushbutton.h> +#include <qptrlist.h> +#include <qwhatsthis.h> +#include <qpainter.h> +#include <qiconset.h> +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qhbuttongroup.h> +#include <qtoolbutton.h> +#include <qtextcodec.h> + +#include <kdeversion.h> +#include <klistview.h> +#include <kprocess.h> +#include <kprocio.h> +#include <klocale.h> +#include <kaccel.h> +#if KDE_IS_VERSION( 3, 2, 90 ) +#include <klistviewsearchline.h> +#endif +#include <kactivelabel.h> +#include <kaction.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <klineedit.h> + + +#include "popuppublic.h" +#include "kgpgsettings.h" +#include "kgpgview.h" +#include "kgpg.h" + +///////////////// klistviewitem special + +class UpdateViewItem2 : public KListViewItem +{ +public: + UpdateViewItem2(QListView *parent, QString name,QString mail,QString id,bool isDefault); + virtual void paintCell(QPainter *p, const QColorGroup &cg,int col, int width, int align); + virtual QString key(int c,bool ) const; + bool def; +}; + +UpdateViewItem2::UpdateViewItem2(QListView *parent, QString name,QString mail,QString id,bool isDefault) + : KListViewItem(parent) +{ +def=isDefault; + setText(0,name); + setText(1,mail); + setText(2,id); +} + + +void UpdateViewItem2::paintCell(QPainter *p, const QColorGroup &cg,int column, int width, int alignment) +{ + if ((def) && (column<2)) { + QFont font(p->font()); + font.setBold(true); + p->setFont(font); + } + KListViewItem::paintCell(p, cg, column, width, alignment); +} + +QString UpdateViewItem2 :: key(int c,bool ) const +{ + return text(c).lower(); +} + +/////////////// main view + +popupPublic::popupPublic(QWidget *parent, const char *name,QString sfile,bool filemode,KShortcut goDefaultKey): +KDialogBase( Plain, i18n("Select Public Key"), Details | Ok | Cancel, Ok, parent, name,true) +{ + + QWidget *page = plainPage(); + QVBoxLayout *vbox=new QVBoxLayout(page,0,spacingHint()); + vbox->setAutoAdd(true); + + setButtonText(KDialogBase::Details,i18n("Options")); + + if (KGpgSettings::allowCustomEncryptionOptions()) + customOptions=KGpgSettings::customEncryptionOptions(); + + KIconLoader *loader = KGlobal::iconLoader(); + + keyPair=loader->loadIcon("kgpg_key2",KIcon::Small,20); + keySingle=loader->loadIcon("kgpg_key1",KIcon::Small,20); + keyGroup=loader->loadIcon("kgpg_key3",KIcon::Small,20); + + if (filemode) setCaption(i18n("Select Public Key for %1").arg(sfile)); + fmode=filemode; + + QHButtonGroup *hBar=new QHButtonGroup(page); + //hBar->setFrameStyle(QFrame::NoFrame); + hBar->setMargin(0); + +#if KDE_IS_VERSION( 3, 2, 90 ) + QToolButton *clearSearch = new QToolButton(hBar); + clearSearch->setTextLabel(i18n("Clear Search"), true); + clearSearch->setIconSet(SmallIconSet(QApplication::reverseLayout() ? "clear_left" + : "locationbar_erase")); + (void) new QLabel(i18n("Search: "),hBar); + KListViewSearchLine* listViewSearch = new KListViewSearchLine(hBar); + connect(clearSearch, SIGNAL(pressed()), listViewSearch, SLOT(clear())); +#endif + + keysList = new KListView( page ); + keysList->addColumn(i18n("Name")); + keysList->addColumn(i18n("Email")); + keysList->addColumn(i18n("ID")); + +#if KDE_IS_VERSION( 3, 2, 90 ) + listViewSearch->setListView(keysList); +#endif + + keysList->setRootIsDecorated(false); + page->setMinimumSize(540,200); + keysList->setShowSortIndicator(true); + keysList->setFullWidth(true); + keysList->setAllColumnsShowFocus(true); + keysList->setSelectionModeExt(KListView::Extended); + keysList->setColumnWidthMode(0,QListView::Manual); + keysList->setColumnWidthMode(1,QListView::Manual); + keysList->setColumnWidth(0,210); + keysList->setColumnWidth(1,210); + + boutonboxoptions=new QButtonGroup(5,Qt::Vertical ,page,0); + + KActionCollection *actcol=new KActionCollection(this); + (void) new KAction(i18n("&Go to Default Key"),goDefaultKey, this, SLOT(slotGotoDefaultKey()),actcol,"go_default_key"); + + + CBarmor=new QCheckBox(i18n("ASCII armored encryption"),boutonboxoptions); + CBuntrusted=new QCheckBox(i18n("Allow encryption with untrusted keys"),boutonboxoptions); + CBhideid=new QCheckBox(i18n("Hide user id"),boutonboxoptions); + setDetailsWidget(boutonboxoptions); + QWhatsThis::add + (keysList,i18n("<b>Public keys list</b>: select the key that will be used for encryption.")); + QWhatsThis::add + (CBarmor,i18n("<b>ASCII encryption</b>: makes it possible to open the encrypted file/message in a text editor")); + QWhatsThis::add + (CBhideid,i18n("<b>Hide user ID</b>: Do not put the keyid into encrypted packets. This option hides the receiver " + "of the message and is a countermeasure against traffic analysis. It may slow down the decryption process because " + "all available secret keys are tried.")); + QWhatsThis::add + (CBuntrusted,i18n("<b>Allow encryption with untrusted keys</b>: when you import a public key, it is usually " + "marked as untrusted and you cannot use it unless you sign it in order to make it 'trusted'. Checking this " + "box enables you to use any key, even if it has not be signed.")); + + if (filemode) { + QWidget *parentBox=new QWidget(boutonboxoptions); + QHBoxLayout *shredBox=new QHBoxLayout(parentBox,0); + //shredBox->setFrameStyle(QFrame::NoFrame); + //shredBox->setMargin(0); + CBshred=new QCheckBox(i18n("Shred source file"),parentBox); + QWhatsThis::add + (CBshred,i18n("<b>Shred source file</b>: permanently remove source file. No recovery will be possible")); + + QString shredWhatsThis = i18n( "<qt><b>Shred source file:</b><br /><p>Checking this option will shred (overwrite several times before erasing) the files you have encrypted. This way, it is almost impossible that the source file is recovered.</p><p><b>But you must be aware that this is not secure</b> on all file systems, and that parts of the file may have been saved in a temporary file or in the spooler of your printer if you previously opened it in an editor or tried to print it. Only works on files (not on folders).</p></qt>"); + KActiveLabel *warn= new KActiveLabel( i18n("<a href=\"whatsthis:%1\">Read this before using shredding</a>").arg(shredWhatsThis),parentBox ); + shredBox->addWidget(CBshred); + shredBox->addWidget(warn); + } + + CBsymmetric=new QCheckBox(i18n("Symmetrical encryption"),boutonboxoptions); + QWhatsThis::add + (CBsymmetric,i18n("<b>Symmetrical encryption</b>: encryption does not use keys. You just need to give a password " + "to encrypt/decrypt the file")); + QObject::connect(CBsymmetric,SIGNAL(toggled(bool)),this,SLOT(isSymetric(bool))); + + CBarmor->setChecked( KGpgSettings::asciiArmor() ); + CBuntrusted->setChecked( KGpgSettings::allowUntrustedKeys() ); + CBhideid->setChecked( KGpgSettings::hideUserID() ); + if (filemode) CBshred->setChecked( KGpgSettings::shredSource() ); + + if (KGpgSettings::allowCustomEncryptionOptions()) { + QHButtonGroup *bGroup = new QHButtonGroup(page); + //bGroup->setFrameStyle(QFrame::NoFrame); + (void) new QLabel(i18n("Custom option:"),bGroup); + KLineEdit *optiontxt=new KLineEdit(bGroup); + optiontxt->setText(customOptions); + QWhatsThis::add + (optiontxt,i18n("<b>Custom option</b>: for experienced users only, allows you to enter a gpg command line option, like: '--armor'")); + QObject::connect(optiontxt,SIGNAL(textChanged ( const QString & )),this,SLOT(customOpts(const QString & ))); + } + QObject::connect(keysList,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)),this,SLOT(slotOk())); +// QObject::connect(this,SIGNAL(okClicked()),this,SLOT(crypte())); + QObject::connect(CBuntrusted,SIGNAL(toggled(bool)),this,SLOT(refresh(bool))); + + char line[200]="\0"; + FILE *fp2; + seclist=QString::null; + + fp2 = popen("gpg --no-secmem-warning --no-tty --with-colon --list-secret-keys ", "r"); + while ( fgets( line, sizeof(line), fp2)) + { + QString readLine=QString::fromUtf8(line); + if (readLine.startsWith("sec")) seclist+=", 0x"+readLine.section(":",4,4).right(8); + } + pclose(fp2); + + trusted=CBuntrusted->isChecked(); + + refreshkeys(); + setMinimumSize(550,200); + updateGeometry(); + keysList->setFocus(); + show(); +} + +popupPublic::~popupPublic() +{} + + +void popupPublic::slotAccept() +{ +accept(); +} + +void popupPublic::enable() +{ + QListViewItem *current = keysList->firstChild(); + if (current==NULL) + return; + current->setVisible(true); + while ( current->nextSibling() ) { + current = current->nextSibling(); + current->setVisible(true); + } + keysList->ensureItemVisible(keysList->currentItem()); +} + +void popupPublic::sort() +{ + bool reselect=false; + QListViewItem *current = keysList->firstChild(); + if (current==NULL) + return; + + if ((untrustedList.find(current->text(2))!=untrustedList.end()) && (!current->text(2).isEmpty())){ + if (current->isSelected()) { + current->setSelected(false); + reselect=true; + } + current->setVisible(false); + } + + while ( current->nextSibling() ) { + current = current->nextSibling(); + if ((untrustedList.find(current->text(2))!=untrustedList.end()) && (!current->text(2).isEmpty())) { + if (current->isSelected()) { + current->setSelected(false); + reselect=true; + } + current->setVisible(false); + } + } + + if (reselect || !keysList->currentItem()->isVisible()) { + QListViewItem *firstvisible; + firstvisible=keysList->firstChild(); + while (firstvisible->isVisible()!=true) { + firstvisible=firstvisible->nextSibling(); + if (firstvisible==NULL) + return; + } + keysList->setSelected(firstvisible,true); + keysList->setCurrentItem(firstvisible); + keysList->ensureItemVisible(firstvisible); + } +} + +void popupPublic::isSymetric(bool state) +{ + keysList->setEnabled(!state); + CBuntrusted->setEnabled(!state); + CBhideid->setEnabled(!state); +} + + +void popupPublic::customOpts(const QString &str) +{ + customOptions=str; +} + +void popupPublic::slotGotoDefaultKey() +{ + QListViewItem *myDefaulKey = keysList->findItem(KGpgSettings::defaultKey(),2); + keysList->clearSelection(); + keysList->setCurrentItem(myDefaulKey); + keysList->setSelected(myDefaulKey,true); + keysList->ensureItemVisible(myDefaulKey); +} + +void popupPublic::refresh(bool state) +{ + if (state) + enable(); + else + sort(); +} + +void popupPublic::refreshkeys() +{ + keysList->clear(); + QStringList groups= QStringList::split(",", KGpgSettings::groups()); + if (!groups.isEmpty()) + { + for ( QStringList::Iterator it = groups.begin(); it != groups.end(); ++it ) + { + if (!QString(*it).isEmpty()) + { + UpdateViewItem2 *item=new UpdateViewItem2(keysList,QString(*it),QString::null,QString::null,false); + item->setPixmap(0,keyGroup); + } + } + } + KProcIO *encid=new KProcIO(QTextCodec::codecForLocale()); + *encid << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-keys"; + ///////// when process ends, update dialog infos + QObject::connect(encid, SIGNAL(processExited(KProcess *)),this, SLOT(slotpreselect())); + QObject::connect(encid, SIGNAL(readReady(KProcIO *)),this, SLOT(slotprocread(KProcIO *))); + encid->start(KProcess::NotifyOnExit,true); +} + +void popupPublic::slotpreselect() +{ +QListViewItem *it=NULL; +if (!keysList->firstChild()) return; + if (fmode) it=keysList->findItem(KGpgSettings::defaultKey(),2); +if (!trusted) + sort(); +if (fmode) +{ + keysList->clearSelection(); + keysList->setSelected(it,true); + keysList->setCurrentItem(it); + keysList->ensureItemVisible(it); +} +emit keyListFilled(); +} + +void popupPublic::slotSetVisible() +{ + keysList->ensureItemVisible(keysList->currentItem()); +} + +void popupPublic::slotprocread(KProcIO *p) +{ + ///////////////////////////////////////////////////////////////// extract encryption keys + bool dead; + QString tst,keyname,keymail; + + QString defaultKey = KGpgSettings::defaultKey().right(8); + + while (p->readln(tst)!=-1) { + if (tst.startsWith("pub")) { + QStringList keyString=QStringList::split(":",tst,true); + dead=false; + const QString trust=keyString[1]; + QString val=keyString[6]; + QString id=QString("0x"+keyString[4].right(8)); + if (val.isEmpty()) + val=i18n("Unlimited"); + QString tr; + switch( trust[0] ) { + case 'o': + untrustedList<<id; + break; + case 'i': + dead=true; + break; + case 'd': + dead=true; + break; + case 'r': + dead=true; + break; + case 'e': + dead=true; + break; + case 'q': + untrustedList<<id; + break; + case 'n': + untrustedList<<id; + break; + case 'm': + untrustedList<<id; + break; + case 'f': + break; + case 'u': + break; + default: + untrustedList<<id; + break; + } + if (keyString[11].find('D')!=-1) dead=true; + tst=keyString[9]; + if (tst.find("<")!=-1) { + keymail=tst.section('<',-1,-1); + keymail.truncate(keymail.length()-1); + keyname=tst.section('<',0,0); + //if (keyname.find("(")!=-1) + // keyname=keyname.section('(',0,0); + } else { + keymail=QString::null; + keyname=tst;//.section('(',0,0); + } + if ((!dead) && (!tst.isEmpty())) { + bool isDefaultKey=false; + if (id.right(8)==defaultKey) isDefaultKey=true; + UpdateViewItem2 *item=new UpdateViewItem2(keysList,keyname,keymail,id,isDefaultKey); + //KListViewItem *sub= new KListViewItem(item,i18n("ID: %1, trust: %2, validity: %3").arg(id).arg(tr).arg(val)); + //sub->setSelectable(false); + if (seclist.find(tst,0,FALSE)!=-1) + item->setPixmap(0,keyPair); + else + item->setPixmap(0,keySingle); + } + } + } +} + + +void popupPublic::slotOk() +{ + ////// emit selected data +kdDebug(2100)<<"Ok pressed"<<endl; + QStringList selectedKeys; + QString userid; + QPtrList<QListViewItem> list=keysList->selectedItems(); + + for ( uint i = 0; i < list.count(); ++i ) + if ( list.at(i) && list.at(i)->isVisible()) { + if (!list.at(i)->text(2).isEmpty()) selectedKeys<<list.at(i)->text(2); + else selectedKeys<<list.at(i)->text(0); + } + if (selectedKeys.isEmpty() && !CBsymmetric->isChecked()) + return; + if (CBsymmetric->isChecked()) selectedKeys=NULL; +kdDebug(2100)<<"Selected Key:"<<selectedKeys<<endl; + QStringList returnOptions; + if (CBuntrusted->isChecked()) + returnOptions<<"--always-trust"; + if (CBarmor->isChecked()) + returnOptions<<"--armor"; + if (CBhideid->isChecked()) + returnOptions<<"--throw-keyid"; + if ((KGpgSettings::allowCustomEncryptionOptions()) && (!customOptions.stripWhiteSpace().isEmpty())) + returnOptions.operator+ (QStringList::split(QString(" "),customOptions.simplifyWhiteSpace())); + //hide(); + if (fmode) + emit selectedKey(selectedKeys,returnOptions,CBshred->isChecked(),CBsymmetric->isChecked()); + else + emit selectedKey(selectedKeys,returnOptions,false,CBsymmetric->isChecked()); + accept(); +} + +#include "popuppublic.moc" diff --git a/kgpg/popuppublic.h b/kgpg/popuppublic.h new file mode 100644 index 0000000..e0d2bb5 --- /dev/null +++ b/kgpg/popuppublic.h @@ -0,0 +1,76 @@ +/*************************************************************************** + popuppublic.h - description + ------------------- + begin : Sat Jun 29 2002 + copyright : (C) 2002 by Jean-Baptiste Mardelle + email : bj@altern.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef POPUPPUBLIC_H +#define POPUPPUBLIC_H + +#include <kdialogbase.h> + +//#include <kiconloader.h> +#include <kshortcut.h> + + +class QPushButton; +class QCheckBox; +class KListView; +class QButtonGroup; +class KProcIO; + +class popupPublic : public KDialogBase //QDialog +{ + Q_OBJECT +public: + + popupPublic(QWidget *parent=0, const char *name=0,QString sfile="",bool filemode=false,KShortcut goDefaultKey=QKeySequence(CTRL+Qt::Key_Home)); + ~popupPublic(); + KListView *keysList; + QCheckBox *CBarmor,*CBuntrusted,*CBshred,*CBsymmetric,*CBhideid; + bool fmode,trusted; + QPixmap keyPair,keySingle,keyGroup; + QString seclist; + QStringList untrustedList; + +private: + KConfig *config; + QButtonGroup *boutonboxoptions; + QString customOptions; + +private slots: + void customOpts(const QString &); + void slotprocread(KProcIO *); + void slotpreselect(); + void refreshkeys(); + void refresh(bool state); + void isSymetric(bool state); + void sort(); + void enable(); + void slotGotoDefaultKey(); + +public slots: +void slotAccept(); +void slotSetVisible(); + +protected slots: +virtual void slotOk(); + +signals: + void selectedKey(QStringList ,QStringList,bool,bool); + void keyListFilled(); + +}; + +#endif // POPUPPUBLIC_H + diff --git a/kgpg/searchres.ui b/kgpg/searchres.ui new file mode 100644 index 0000000..0c81fcd --- /dev/null +++ b/kgpg/searchres.ui @@ -0,0 +1,124 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>searchRes</class> +<widget class="QWidget"> + <property name="name"> + <cstring>searchRes</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>415</width> + <height>305</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>statusText</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Key to import:</string> + </property> + </widget> + <widget class="KLineEdit" row="2" column="1"> + <property name="name"> + <cstring>kLEID</cstring> + </property> + </widget> + <widget class="KListView" row="1" column="0" rowspan="1" colspan="2"> + <column> + <property name="text"> + <string>Name</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Email</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Creation</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>ID</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>kLVsearch</cstring> + </property> + <property name="selectionMode" stdset="0"> + <enum>Extended</enum> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="showSortIndicator"> + <bool>true</bool> + </property> + <property name="rootIsDecorated"> + <bool>true</bool> + </property> + <property name="resizeMode"> + <enum>LastColumn</enum> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + <property name="itemsMovable"> + <bool>false</bool> + </property> + </widget> + </grid> +</widget> +<tabstops> + <tabstop>kLVsearch</tabstop> + <tabstop>kLEID</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/kgpg/sourceselect.ui b/kgpg/sourceselect.ui new file mode 100644 index 0000000..faf0dee --- /dev/null +++ b/kgpg/sourceselect.ui @@ -0,0 +1,112 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>SrcSelect</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SrcSelect</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>350</width> + <height>93</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>350</width> + <height>0</height> + </size> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup" row="0" column="0"> + <property name="name"> + <cstring>buttonGroup2</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="2" column="0"> + <property name="name"> + <cstring>checkFile</cstring> + </property> + <property name="text"> + <string>File:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="KURLRequester" row="2" column="1"> + <property name="name"> + <cstring>newFilename</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>checkClipboard</cstring> + </property> + <property name="text"> + <string>Clipboard</string> + </property> + </widget> + </grid> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>31</height> + </size> + </property> + </spacer> + </grid> +</widget> +<connections> + <connection> + <sender>checkFile</sender> + <signal>toggled(bool)</signal> + <receiver>SrcSelect</receiver> + <slot>checkFile_toggled(bool)</slot> + </connection> +</connections> +<slots> + <slot>checkFile_toggled( bool isOn )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kgpg/tips b/kgpg/tips new file mode 100644 index 0000000..cc3f0bf --- /dev/null +++ b/kgpg/tips @@ -0,0 +1,44 @@ +<tip category="Kgpg|app"> +<html> +<p>If you want to decrypt a text file, simply drag and drop it into the editor window. Kgpg will do the rest. Even remote files can be dropped.</p> +<p>Drag a public key into the editor window and kgpg will automatically import it if you want.</p> +</html> +<tip category="Kgpg|app"> +<html> +<p>The easiest way to encrypt a file: simply right click on the file, and you have an encrypt option in the contextual menu. +This works in <strong>konqueror</strong> or on your Desktop!</p> +</html> +</tip> +<tip category="Kgpg|app"> +<html> +<p>If you want to encrypt a message for several persons, just select several encryption keys by pressing the "Ctrl" key.</p> +</html> +</tip> +<tip category="Kgpg|app"> +<html> +<p><strong>You don't know anything about encryption?</strong><br> +No problem, simply create yourself a key pair in the key management window. Then, export your public key & mail it to your friends.<br> +Ask them to do the same & import their public keys. Finally, to send an encrypted message, type it in the Kgpg editor, then click "encrypt". Choose +your friend key and click "encrypt" again. The message will be encrypted, ready to be sent by email.</p> +</html> +</tip> +<tip category="Kgpg|app"> +<html> +<p>To perform an operation on a key, open the key management window & right click on the key. A popup menu with all available options will appear.</p> +</html> +</tip> +<tip category="Kgpg|app"> +<html> +<p>Decrypt a file with a single mouse click on it. You will then be prompted for password & that's all!</p> +</html> +</tip> +<tip category="Kgpg|app"> +<html> +<p>If you only want to open the key manager, type "kgpg -k" in the command line prompt.</p> +</html> +</tip> +<tip category="Kgpg|app"> +<html> +<p>Typing "kgpg -s filename" will decrypt the file filename and open it in Kgpg's editor.</p> +</html> +</tip> |