summaryrefslogtreecommitdiffstats
path: root/libkpgp/kpgpbase2.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /libkpgp/kpgpbase2.cpp
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'libkpgp/kpgpbase2.cpp')
-rw-r--r--libkpgp/kpgpbase2.cpp1105
1 files changed, 1105 insertions, 0 deletions
diff --git a/libkpgp/kpgpbase2.cpp b/libkpgp/kpgpbase2.cpp
new file mode 100644
index 000000000..c4fd0358f
--- /dev/null
+++ b/libkpgp/kpgpbase2.cpp
@@ -0,0 +1,1105 @@
+/*
+ kpgpbase2.cpp
+
+ Copyright (C) 2001,2002 the KPGP authors
+ See file AUTHORS.kpgp for details
+
+ This file is part of KPGP, the KDE PGP/GnuPG support library.
+
+ KPGP 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "kpgpbase.h"
+#include "kpgp.h"
+
+#include <string.h> /* strncmp */
+#include <assert.h>
+
+#include <qdatetime.h>
+
+#include <klocale.h>
+#include <kprocess.h>
+#include <kdebug.h>
+
+#define PGP2 "pgp"
+
+namespace Kpgp {
+
+Base2::Base2()
+ : Base()
+{
+}
+
+
+Base2::~Base2()
+{
+}
+
+
+int
+Base2::encrypt( Block& block, const KeyIDList& recipients )
+{
+ return encsign( block, recipients, 0 );
+}
+
+
+int
+Base2::clearsign( Block& block, const char *passphrase )
+{
+ return encsign( block, KeyIDList(), passphrase );
+}
+
+
+int
+Base2::encsign( Block& block, const KeyIDList& recipients,
+ const char *passphrase )
+{
+ QCString cmd;
+ int exitStatus = 0;
+
+ if(!recipients.isEmpty() && passphrase != 0)
+ cmd = PGP2 " +batchmode +language=en +verbose=1 -seat";
+ else if(!recipients.isEmpty())
+ cmd = PGP2 " +batchmode +language=en +verbose=1 -eat";
+ else if(passphrase != 0)
+ cmd = PGP2 " +batchmode +language=en +verbose=1 -sat";
+ else
+ {
+ kdDebug(5100) << "kpgpbase: Neither recipients nor passphrase specified." << endl;
+ return OK;
+ }
+
+ if(passphrase != 0)
+ cmd += addUserId();
+
+ if(!recipients.isEmpty()) {
+ if(Module::getKpgp()->encryptToSelf())
+ {
+ cmd += " 0x";
+ cmd += Module::getKpgp()->user();
+ }
+
+ for( KeyIDList::ConstIterator it = recipients.begin();
+ it != recipients.end(); ++it ) {
+ cmd += " 0x";
+ cmd += (*it);
+ }
+ }
+ cmd += " -f";
+
+ clear();
+ input = block.text();
+ exitStatus = run(cmd.data(), passphrase);
+ if( !output.isEmpty() )
+ block.setProcessedText( output );
+ block.setError( error );
+
+ if(exitStatus != 0)
+ status = ERROR;
+
+#if 0
+ // #### FIXME: As we check the keys ourselves the following problems
+ // shouldn't occur. Therefore I don't handle them for now.
+ // IK 01/2002
+ if(!recipients.isEmpty())
+ {
+ int index = 0;
+ bool bad = FALSE;
+ unsigned int num = 0;
+ QCString badkeys = "";
+ if (error.find("Cannot find the public key") != -1)
+ {
+ index = 0;
+ num = 0;
+ while((index = error.find("Cannot find the public key",index))
+ != -1)
+ {
+ bad = TRUE;
+ index = error.find('\'',index);
+ int index2 = error.find('\'',index+1);
+ if (num++)
+ badkeys += ", ";
+ badkeys += error.mid(index, index2-index+1);
+ }
+ if(bad)
+ {
+ badkeys.stripWhiteSpace();
+ if(num == recipients.count())
+ errMsg = i18n("Could not find public keys matching the userid(s)\n"
+ "%1;\n"
+ "the message is not encrypted.")
+ .arg( badkeys.data() );
+ else
+ errMsg = i18n("Could not find public keys matching the userid(s)\n"
+ "%1;\n"
+ "these persons will not be able to read the message.")
+ .arg( badkeys.data() );
+ status |= MISSINGKEY;
+ status |= ERROR;
+ }
+ }
+ if (error.find("skipping userid") != -1)
+ {
+ index = 0;
+ num = 0;
+ while((index = error.find("skipping userid",index))
+ != -1)
+ {
+ bad = TRUE;
+ int index2 = error.find('\n',index+16);
+ if (num++)
+ badkeys += ", ";
+ badkeys += error.mid(index+16, index2-index-16);
+ index = index2;
+ }
+ if(bad)
+ {
+ badkeys.stripWhiteSpace();
+ if(num == recipients.count())
+ errMsg = i18n("Public keys not certified with trusted signature "
+ "for userid(s)\n"
+ "%1.\n"
+ "The message is not encrypted.")
+ .arg( badkeys.data() );
+ else
+ errMsg = i18n("Public keys not certified with trusted signature "
+ "for userid(s)\n"
+ "%1;\n"
+ "these persons will not be able to read the message.")
+ .arg( badkeys.data() );
+ status |= BADKEYS;
+ status |= ERROR;
+ return status;
+ }
+ }
+ }
+#endif
+ if(passphrase != 0)
+ {
+ if(error.find("Pass phrase is good") != -1)
+ {
+ //kdDebug(5100) << "Base: Good Passphrase!" << endl;
+ status |= SIGNED;
+ }
+ if( error.find("Bad pass phrase") != -1)
+ {
+ errMsg = i18n("Bad passphrase; could not sign.");
+ status |= BADPHRASE;
+ status |= ERR_SIGNING;
+ status |= ERROR;
+ }
+ }
+ if (error.find("Signature error") != -1)
+ {
+ errMsg = i18n("Signing failed: please check your PGP User Identity, "
+ "the PGP setup, and the key rings.");
+ status |= NO_SEC_KEY;
+ status |= ERR_SIGNING;
+ status |= ERROR;
+ }
+ if (error.find("Encryption error") != -1)
+ {
+ errMsg = i18n("Encryption failed: please check your PGP setup "
+ "and the key rings.");
+ status |= NO_SEC_KEY;
+ status |= BADKEYS;
+ status |= ERROR;
+ }
+
+ //kdDebug(5100) << "status = " << status << endl;
+ block.setStatus( status );
+ return status;
+}
+
+
+int
+Base2::decrypt( Block& block, const char *passphrase )
+{
+ int index, index2;
+ int exitStatus = 0;
+
+ clear();
+ input = block.text();
+ exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
+ if( !output.isEmpty() )
+ block.setProcessedText( output );
+ block.setError( error );
+
+ // pgp2.6 has sometimes problems with the ascii armor pgp5.0 produces
+ // this hack can solve parts of the problem
+ if(error.find("ASCII armor corrupted.") != -1)
+ {
+ kdDebug(5100) << "removing ASCII armor header" << endl;
+ int index1 = input.find("-----BEGIN PGP SIGNED MESSAGE-----");
+ if(index1 != -1)
+ index1 = input.find("-----BEGIN PGP SIGNATURE-----", index1);
+ else
+ index1 = input.find("-----BEGIN PGP MESSAGE-----");
+ index1 = input.find('\n', index1);
+ index2 = input.find("\n\n", index1);
+ input.remove(index1, index2 - index1);
+ exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
+ if( !output.isEmpty() )
+ block.setProcessedText( output );
+ block.setError( error );
+ }
+
+ if(exitStatus == -1) {
+ errMsg = i18n("error running PGP");
+ status = RUN_ERR;
+ block.setStatus( status );
+ return status;
+ }
+
+ /* Example No.1 (PGP 2.6.3in):
+ * File is encrypted. Secret key is required to read it.
+ * Key for user ID: Test Key (only for testing) <testkey@ingo-kloecker.de>
+ * 1024-bit key, key ID E2D074D3, created 2001/09/09
+ *
+ * Error: Bad pass phrase.
+ *
+ * This message can only be read by:
+ * Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
+ * Test Key (only for testing) <testkey@ingo-kloecker.de>
+ *
+ * You do not have the secret key needed to decrypt this file.
+ */
+ /* Example No.2 (PGP 2.6.3in):
+ * File is encrypted. Secret key is required to read it.
+ * This message can only be read by:
+ * Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
+ *
+ * You do not have the secret key needed to decrypt this file.
+ */
+ if(error.find("File is encrypted.") != -1)
+ {
+ //kdDebug(5100) << "kpgpbase: message is encrypted" << endl;
+ status |= ENCRYPTED;
+ if((index = error.find("Key for user ID:")) != -1)
+ {
+ // Find out the key for which the phrase is needed
+ index += 17;
+ index2 = error.find('\n', index);
+ block.setRequiredUserId( error.mid(index, index2 - index) );
+ //kdDebug(5100) << "Base: key needed is \"" << block.requiredUserId() << "\"!\n";
+
+ if((passphrase != 0) && (error.find("Bad pass phrase") != -1))
+ {
+ errMsg = i18n("Bad passphrase; could not decrypt.");
+ kdDebug(5100) << "Base: passphrase is bad" << endl;
+ status |= BADPHRASE;
+ status |= ERROR;
+ }
+ }
+ else
+ {
+ // no secret key fitting this message
+ status |= NO_SEC_KEY;
+ status |= ERROR;
+ errMsg = i18n("You do not have the secret key needed to decrypt this message.");
+ kdDebug(5100) << "Base: no secret key for this message" << endl;
+ }
+ // check for persons
+#if 0
+ // ##### FIXME: This information is anyway currently not used
+ // I'll change it to always determine the recipients.
+ index = error.find("can only be read by:");
+ if(index != -1)
+ {
+ index = error.find('\n',index);
+ int end = error.find("\n\n",index);
+
+ mRecipients.clear();
+ while( (index2 = error.find('\n',index+1)) <= end )
+ {
+ QCString item = error.mid(index+1,index2-index-1);
+ item.stripWhiteSpace();
+ mRecipients.append(item);
+ index = index2;
+ }
+ }
+#endif
+ }
+
+ // handle signed message
+
+ // Examples (made with PGP 2.6.3in)
+ /* Example No. 1 (signed with unknown key):
+ * File has signature. Public key is required to check signature.
+ *
+ * Key matching expected Key ID 12345678 not found in file '/home/user/.pgp/pubring.pgp'.
+ *
+ * WARNING: Can't find the right public key-- can't check signature integrity.
+ */
+ /* Example No. 2 (bad signature):
+ * File has signature. Public key is required to check signature.
+ * ..
+ * WARNING: Bad signature, doesn't match file contents!
+ *
+ * Bad signature from user "Joe User <joe@foo.bar>".
+ * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
+ */
+ /* Example No. 3.1 (good signature with untrusted key):
+ * File has signature. Public key is required to check signature.
+ * .
+ * Good signature from user "Joe User <joe@foo.bar>".
+ * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
+ *
+ * WARNING: Because this public key is not certified with a trusted
+ * signature, it is not known with high confidence that this public key
+ * actually belongs to: "Joe User <joe@foo.bar>".
+ */
+ /* Example No. 3.2 (good signature with untrusted key):
+ * File has signature. Public key is required to check signature.
+ * .
+ * Good signature from user "Joe User <joe@foo.bar>".
+ * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
+ *
+ * WARNING: Because this public key is not certified with enough trusted
+ * signatures, it is not known with high confidence that this public key
+ * actually belongs to: "Joe User <joe@foo.bar>".
+ */
+ /* Example No. 4 (good signature with revoked key):
+ * File has signature. Public key is required to check signature.
+ * .
+ * Good signature from user "Joe User <joe@foo.bar>".
+ * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
+ *
+ *
+ * Key for user ID: Joe User <joe@foo.bar>
+ * 1024-bit key, key ID 12345678, created 2001/09/09
+ * Key has been revoked.
+ *
+ * WARNING: This key has been revoked by its owner,
+ * possibly because the secret key was compromised.
+ * This could mean that this signature is a forgery.
+ */
+ /* Example No. 5 (good signature with trusted key):
+ * File has signature. Public key is required to check signature.
+ * .
+ * Good signature from user "Joe User <joe@foo.bar>".
+ * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
+ */
+
+ if((index = error.find("File has signature")) != -1)
+ {
+ // move index to start of next line
+ index = error.find('\n', index+18) + 1;
+ //kdDebug(5100) << "Base: message is signed" << endl;
+ status |= SIGNED;
+ // get signature date and signature key ID
+ if ((index2 = error.find("Signature made", index)) != -1) {
+ index2 += 15;
+ int index3 = error.find("using", index2);
+ block.setSignatureDate( error.mid(index2, index3-index2-1) );
+ kdDebug(5100) << "Message was signed on '" << block.signatureDate() << "'\n";
+ index3 = error.find("key ID ", index3) + 7;
+ block.setSignatureKeyId( error.mid(index3,8) );
+ kdDebug(5100) << "Message was signed with key '" << block.signatureKeyId() << "'\n";
+ }
+ else {
+ // if pgp can't find the keyring it unfortunately doesn't print
+ // the signature date and key ID
+ block.setSignatureDate( "" );
+ block.setSignatureKeyId( "" );
+ }
+
+ if( ( index2 = error.find("Key matching expected", index) ) != -1)
+ {
+ status |= UNKNOWN_SIG;
+ status |= GOODSIG;
+ int index3 = error.find("Key ID ", index2) + 7;
+ block.setSignatureKeyId( error.mid(index3,8) );
+ block.setSignatureUserId( QString::null );
+ }
+ else if( (index2 = error.find("Good signature from", index)) != -1 )
+ {
+ status |= GOODSIG;
+ // get signer
+ index = error.find('"',index2+19);
+ index2 = error.find('"', index+1);
+ block.setSignatureUserId( error.mid(index+1, index2-index-1) );
+ }
+ else if( (index2 = error.find("Bad signature from", index)) != -1 )
+ {
+ status |= ERROR;
+ // get signer
+ index = error.find('"',index2+19);
+ index2 = error.find('"', index+1);
+ block.setSignatureUserId( error.mid(index+1, index2-index-1) );
+ }
+ else if( error.find("Keyring file", index) != -1 )
+ {
+ // #### fix this hack
+ status |= UNKNOWN_SIG;
+ status |= GOODSIG; // this is a hack...
+ // determine file name of missing keyring file
+ index = error.find('\'', index) + 1;
+ index2 = error.find('\'', index);
+ block.setSignatureUserId( i18n("The keyring file %1 does not exist.\n"
+ "Please check your PGP setup.").arg(error.mid(index, index2-index)) );
+ }
+ else
+ {
+ status |= ERROR;
+ block.setSignatureUserId( i18n("Unknown error") );
+ }
+ }
+ //kdDebug(5100) << "status = " << status << endl;
+ block.setStatus( status );
+ return status;
+}
+
+
+Key*
+Base2::readPublicKey( const KeyID& keyID,
+ const bool readTrust /* = false */,
+ Key* key /* = 0 */ )
+{
+ int exitStatus = 0;
+
+ status = 0;
+ exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kvc -f 0x" +
+ keyID, 0, true );
+
+ if(exitStatus != 0) {
+ status = ERROR;
+ return 0;
+ }
+
+ key = parsePublicKeyData( output, key );
+
+ if( key == 0 )
+ {
+ return 0;
+ }
+
+ if( readTrust )
+ {
+ exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kc -f",
+ 0, true );
+
+ if(exitStatus != 0) {
+ status = ERROR;
+ return 0;
+ }
+
+ parseTrustDataForKey( key, error );
+ }
+
+ return key;
+}
+
+
+KeyList
+Base2::publicKeys( const QStringList & patterns )
+{
+ return doGetPublicKeys( PGP2 " +batchmode +language=en +verbose=0 -kvc -f",
+ patterns );
+}
+
+KeyList
+Base2::doGetPublicKeys( const QCString & cmd, const QStringList & patterns )
+{
+ int exitStatus = 0;
+ KeyList publicKeys;
+
+ status = 0;
+ if ( patterns.isEmpty() ) {
+ exitStatus = run( cmd, 0, true );
+
+ if ( exitStatus != 0 ) {
+ status = ERROR;
+ return KeyList();
+ }
+
+ // now we need to parse the output for public keys
+ publicKeys = parseKeyList( output, false );
+ }
+ else {
+ typedef QMap<QCString, Key*> KeyMap;
+ KeyMap map;
+
+ for ( QStringList::ConstIterator it = patterns.begin();
+ it != patterns.end(); ++it ) {
+ exitStatus = run( cmd + " " + KProcess::quote( *it ).local8Bit(),
+ 0, true );
+
+ if ( exitStatus != 0 ) {
+ status = ERROR;
+ return KeyList();
+ }
+
+ // now we need to parse the output for public keys
+ publicKeys = parseKeyList( output, false );
+
+ // put all new keys into a map, remove duplicates
+ while ( !publicKeys.isEmpty() ) {
+ Key * key = publicKeys.take( 0 );
+ if ( !map.contains( key->primaryFingerprint() ) )
+ map.insert( key->primaryFingerprint(), key );
+ else
+ delete key;
+ }
+ }
+ // build list from the map
+ for ( KeyMap::ConstIterator it = map.begin(); it != map.end(); ++it ) {
+ publicKeys.append( it.data() );
+ }
+ }
+
+ // sort the list of public keys
+ publicKeys.sort();
+
+ return publicKeys;
+}
+
+KeyList
+Base2::secretKeys( const QStringList & patterns )
+{
+ return publicKeys( patterns );
+}
+
+
+int
+Base2::signKey(const KeyID& keyID, const char *passphrase)
+{
+ QCString cmd;
+ int exitStatus = 0;
+
+ cmd = PGP2 " +batchmode +language=en -ks -f ";
+ cmd += addUserId();
+ cmd += " 0x" + keyID;
+
+ status = 0;
+ exitStatus = run(cmd.data(),passphrase);
+
+ if (exitStatus != 0)
+ status = ERROR;
+
+ return status;
+}
+
+
+QCString Base2::getAsciiPublicKey(const KeyID& keyID)
+{
+ int exitStatus = 0;
+
+ if (keyID.isEmpty())
+ return QCString();
+
+ status = 0;
+ exitStatus = run( PGP2 " +batchmode +force +language=en -kxaf 0x" + keyID,
+ 0, true );
+
+ if(exitStatus != 0) {
+ status = ERROR;
+ return QCString();
+ }
+
+ return output;
+}
+
+
+Key*
+Base2::parsePublicKeyData( const QCString& output, Key* key /* = 0 */ )
+{
+ Subkey *subkey = 0;
+ int index;
+
+ // search start of key data
+ if( !strncmp( output.data(), "pub", 3 ) ||
+ !strncmp( output.data(), "sec", 3 ) )
+ index = 0;
+ else
+ {
+ /*
+ if( secretKeys )
+ index = output.find( "\nsec" );
+ else
+ */
+ index = output.find( "\npub" );
+ if( index == -1 )
+ return 0;
+ else
+ index++;
+ }
+
+ while( true )
+ {
+ int index2;
+
+ // search the end of the current line
+ if( ( index2 = output.find( '\n', index ) ) == -1 )
+ break;
+
+ if( !strncmp( output.data() + index, "pub", 3 ) ||
+ !strncmp( output.data() + index, "sec", 3 ) )
+ { // line contains primary key data
+ // Example 1 (nothing special):
+ // pub 1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
+ // Example 2 (disabled key):
+ // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
+ // Example 3 (expired key):
+ // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
+ // Example 4 (revoked key):
+ // pub 1024/956721F9 2001/09/09 *** KEY REVOKED ***
+
+ int pos, pos2;
+
+ if( key == 0 )
+ key = new Key();
+ else
+ key->clear();
+ /*key->setSecret( secretKeys );*/
+ // set default key capabilities
+ key->setCanEncrypt( true );
+ key->setCanSign( true );
+ key->setCanCertify( true );
+
+ /*subkey = new Subkey( "", secretKeys );*/
+ subkey = new Subkey( "", false );
+ key->addSubkey( subkey );
+ // set default key capabilities
+ subkey->setCanEncrypt( true );
+ subkey->setCanSign( true );
+ subkey->setCanCertify( true );
+ // expiration date defaults to never
+ subkey->setExpirationDate( -1 );
+
+ // Key Flags
+ switch( output[index+3] )
+ {
+ case ' ': // nothing special
+ break;
+ case '-': // disabled key
+ subkey->setDisabled( true );
+ key->setDisabled( true );
+ break;
+ case '>': // expired key
+ subkey->setExpired( true );
+ key->setExpired( true );
+ break;
+ default:
+ kdDebug(5100) << "Unknown key flag.\n";
+ }
+
+ // Key Length
+ pos = index + 4;
+ while( output[pos] == ' ' )
+ pos++;
+ pos2 = output.find( '/', pos );
+ subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
+
+ // Key ID
+ pos = pos2 + 1;
+ pos2 = output.find( ' ', pos );
+ subkey->setKeyID( output.mid( pos, pos2-pos ) );
+
+ // Creation Date
+ pos = pos2 + 1;
+ while( output[pos] == ' ' )
+ pos++;
+ pos2 = output.find( ' ', pos );
+ int year = output.mid( pos, 4 ).toInt();
+ int month = output.mid( pos+5, 2 ).toInt();
+ int day = output.mid( pos+8, 2 ).toInt();
+ QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
+ QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
+ // The calculated creation date isn't exactly correct because QDateTime
+ // doesn't know anything about timezones and always assumes local time
+ // although epoch is of course UTC. But as PGP 2 anyway doesn't print
+ // the time this doesn't matter too much.
+ subkey->setCreationDate( epoch.secsTo( dt ) );
+
+ // User ID
+ pos = pos2 + 1;
+ while( output[pos] == ' ' )
+ pos++;
+ QCString uid = output.mid( pos, index2-pos );
+ if( uid != "*** KEY REVOKED ***" )
+ key->addUserID( uid );
+ else
+ {
+ subkey->setRevoked( true );
+ key->setRevoked( true );
+ }
+ }
+ else if( output[index] == ' ' )
+ { // line contains additional key data
+
+ if( key == 0 )
+ break;
+ assert( subkey != 0 );
+
+ int pos = index + 1;
+ while( output[pos] == ' ' )
+ pos++;
+
+ if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
+ { // line contains a fingerprint
+ // Example:
+ // Key fingerprint = 47 30 7C 76 05 BF 5E FB 72 41 00 F2 7D 0B D0 49
+
+ QCString fingerprint = output.mid( pos, index2-pos );
+ // remove white space from the fingerprint
+ for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; )
+ fingerprint.replace( idx, 1, "" );
+
+ subkey->setFingerprint( fingerprint );
+ }
+ else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
+ !strncmp( output.data() + pos, "no expire ", 10 ) )
+ { // line contains additional key properties
+ // Examples:
+ // Expire: 2001/09/10
+ // no expire ENCRyption only
+ // no expire SIGNature only
+
+ if( output[pos] == 'E' )
+ {
+ // Expiration Date
+ pos += 8;
+ int year = output.mid( pos, 4 ).toInt();
+ int month = output.mid( pos+5, 2 ).toInt();
+ int day = output.mid( pos+8, 2 ).toInt();
+ QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
+ QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
+ // Here the same comments as for the creation date are valid.
+ subkey->setExpirationDate( epoch.secsTo( dt ) );
+ pos += 11; // note that there is always a blank after the expire date
+ }
+ else
+ pos += 10;
+
+ // optional key capabilities (sign/encrypt only)
+ if( pos != index2 )
+ {
+ if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
+ {
+ subkey->setCanEncrypt( false );
+ key->setCanEncrypt( false );
+ }
+ else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
+ {
+ subkey->setCanSign( false );
+ key->setCanSign( false );
+ subkey->setCanCertify( false );
+ key->setCanCertify( false );
+ }
+ }
+ }
+ else
+ { // line contains an additional user id
+ // Example:
+ // Test key (2nd user ID) <abc@xyz>
+
+ key->addUserID( output.mid( pos, index2-pos ) );
+ }
+ }
+ index = index2 + 1;
+ }
+
+ //kdDebug(5100) << "finished parsing key data\n";
+
+ return key;
+}
+
+
+void
+Base2::parseTrustDataForKey( Key* key, const QCString& str )
+{
+ if( ( key == 0 ) || str.isEmpty() )
+ return;
+
+ QCString keyID = key->primaryKeyID();
+ UserIDList userIDs = key->userIDs();
+
+ // search the trust data belonging to this key
+ int index = str.find( '\n' ) + 1;
+ while( ( index > 0 ) &&
+ ( strncmp( str.data() + index+2, keyID.data(), 8 ) != 0 ) )
+ index = str.find( '\n', index ) + 1;
+
+ if( index == 0 )
+ return;
+
+ bool ultimateTrust = false;
+ if( !strncmp( str.data() + index+11, "ultimate", 8 ) )
+ ultimateTrust = true;
+
+ bool firstLine = true;
+
+ while( true )
+ { // loop over all trust information about this key
+ int index2;
+
+ // search the end of the current line
+ if( ( index2 = str.find( '\n', index ) ) == -1 )
+ break;
+
+ // check if trust info for the next key starts
+ if( !firstLine && ( str[index+2] != ' ' ) )
+ break;
+
+ if( str[index+21] != ' ' )
+ { // line contains a validity value for a user ID
+
+ // determine the validity
+ Validity validity = KPGP_VALIDITY_UNKNOWN;
+ if( !strncmp( str.data() + index+21, "complete", 8 ) )
+ if( ultimateTrust )
+ validity = KPGP_VALIDITY_ULTIMATE;
+ else
+ validity = KPGP_VALIDITY_FULL;
+ else if( !strncmp( str.data() + index+21, "marginal", 8 ) )
+ validity = KPGP_VALIDITY_MARGINAL;
+ else if( !strncmp( str.data() + index+21, "never", 5 ) )
+ validity = KPGP_VALIDITY_NEVER;
+ else if( !strncmp( str.data() + index+21, "undefined", 9 ) )
+ validity = KPGP_VALIDITY_UNDEFINED;
+
+ // determine the user ID
+ int pos = index + 31;
+ if( str[index+2] == ' ' )
+ pos++; // additional user IDs start one column later
+ QString uid = str.mid( pos, index2-pos );
+
+ // set the validity of the corresponding user ID
+ for( UserIDListIterator it( userIDs ); it.current(); ++it )
+ if( (*it)->text() == uid )
+ {
+ kdDebug(5100)<<"Setting the validity of "<<uid<<" to "<<validity<<endl;
+ (*it)->setValidity( validity );
+ break;
+ }
+ }
+
+ firstLine = false;
+ index = index2 + 1;
+ }
+}
+
+
+KeyList
+Base2::parseKeyList( const QCString& output, bool secretKeys )
+{
+ kdDebug(5100) << "Kpgp::Base2::parseKeyList()" << endl;
+ KeyList keys;
+ Key *key = 0;
+ Subkey *subkey = 0;
+ int index;
+
+ // search start of key data
+ if( !strncmp( output.data(), "pub", 3 ) ||
+ !strncmp( output.data(), "sec", 3 ) )
+ index = 0;
+ else
+ {
+ if( secretKeys )
+ index = output.find( "\nsec" );
+ else
+ index = output.find( "\npub" );
+ if( index == -1 )
+ return keys;
+ else
+ index++;
+ }
+
+ while( true )
+ {
+ int index2;
+
+ // search the end of the current line
+ if( ( index2 = output.find( '\n', index ) ) == -1 )
+ break;
+
+ if( !strncmp( output.data() + index, "pub", 3 ) ||
+ !strncmp( output.data() + index, "sec", 3 ) )
+ { // line contains primary key data
+ // Example 1:
+ // pub 1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
+ // Example 2 (disabled key):
+ // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
+ // Example 3 (expired key):
+ // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
+ // Example 4 (revoked key):
+ // pub 1024/956721F9 2001/09/09 *** KEY REVOKED ***
+
+ int pos, pos2;
+
+ if( key != 0 ) // store the previous key in the key list
+ keys.append( key );
+
+ key = new Key();
+ key->setSecret( secretKeys );
+ // set default key capabilities
+ key->setCanEncrypt( true );
+ key->setCanSign( true );
+ key->setCanCertify( true );
+
+ subkey = new Subkey( "", secretKeys );
+ key->addSubkey( subkey );
+ // set default key capabilities
+ subkey->setCanEncrypt( true );
+ subkey->setCanSign( true );
+ subkey->setCanCertify( true );
+ // expiration date defaults to never
+ subkey->setExpirationDate( -1 );
+
+ // Key Flags
+ switch( output[index+3] )
+ {
+ case ' ': // nothing special
+ break;
+ case '-': // disabled key
+ subkey->setDisabled( true );
+ key->setDisabled( true );
+ break;
+ case '>': // expired key
+ subkey->setExpired( true );
+ key->setExpired( true );
+ break;
+ default:
+ kdDebug(5100) << "Unknown key flag.\n";
+ }
+
+ // Key Length
+ pos = index + 4;
+ while( output[pos] == ' ' )
+ pos++;
+ pos2 = output.find( '/', pos );
+ subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
+
+ // Key ID
+ pos = pos2 + 1;
+ pos2 = output.find( ' ', pos );
+ subkey->setKeyID( output.mid( pos, pos2-pos ) );
+
+ // Creation Date
+ pos = pos2 + 1;
+ while( output[pos] == ' ' )
+ pos++;
+ pos2 = output.find( ' ', pos );
+ int year = output.mid( pos, 4 ).toInt();
+ int month = output.mid( pos+5, 2 ).toInt();
+ int day = output.mid( pos+8, 2 ).toInt();
+ QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
+ QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
+ // The calculated creation date isn't exactly correct because QDateTime
+ // doesn't know anything about timezones and always assumes local time
+ // although epoch is of course UTC. But as PGP 2 anyway doesn't print
+ // the time this doesn't matter too much.
+ subkey->setCreationDate( epoch.secsTo( dt ) );
+
+ // User ID
+ pos = pos2 + 1;
+ while( output[pos] == ' ' )
+ pos++;
+ QCString uid = output.mid( pos, index2-pos );
+ if( uid != "*** KEY REVOKED ***" )
+ key->addUserID( uid );
+ else
+ {
+ subkey->setRevoked( true );
+ key->setRevoked( true );
+ }
+ }
+ else if( output[index] == ' ' )
+ { // line contains additional key data
+
+ if( key == 0 )
+ break;
+
+ int pos = index + 1;
+ while( output[pos] == ' ' )
+ pos++;
+
+ if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
+ { // line contains a fingerprint
+ // Example:
+ // Key fingerprint = 47 30 7C 76 05 BF 5E FB 72 41 00 F2 7D 0B D0 49
+
+ int pos2;
+ pos2 = pos + 18;
+ QCString fingerprint = output.mid( pos, index2-pos );
+ // remove white space from the fingerprint
+ for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; )
+ fingerprint.replace( idx, 1, "" );
+
+ subkey->setFingerprint( fingerprint );
+ }
+ else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
+ !strncmp( output.data() + pos, "no expire ", 10 ) )
+ { // line contains additional key properties
+ // Examples:
+ // Expire: 2001/09/10
+ // no expire ENCRyption only
+ // no expire SIGNature only
+
+ if( output[pos] == 'E' )
+ {
+ // Expiration Date
+ pos += 8;
+ int year = output.mid( pos, 4 ).toInt();
+ int month = output.mid( pos+5, 2 ).toInt();
+ int day = output.mid( pos+8, 2 ).toInt();
+ QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
+ QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
+ // Here the same comments as for the creation date are valid.
+ subkey->setExpirationDate( epoch.secsTo( dt ) );
+ pos += 11; // note that there is always a blank after the expire date
+ }
+ else
+ pos += 10;
+
+ // optional key capabilities (sign/encrypt only)
+ if( pos != index2 )
+ {
+ if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
+ {
+ subkey->setCanEncrypt( false );
+ key->setCanEncrypt( false );
+ }
+ else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
+ {
+ subkey->setCanSign( false );
+ key->setCanSign( false );
+ subkey->setCanCertify( false );
+ key->setCanCertify( false );
+ }
+ }
+ }
+ else
+ { // line contains an additional user id
+ // Example:
+ // Test key (2nd user ID) <abc@xyz>
+
+ key->addUserID( output.mid( pos, index2-pos ) );
+ }
+ }
+
+ index = index2 + 1;
+ }
+
+ if (key != 0) // store the last key in the key list
+ keys.append( key );
+
+ //kdDebug(5100) << "finished parsing keys" << endl;
+
+ return keys;
+}
+
+
+} // namespace Kpgp