• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

libkpgp

kpgpbase2.cpp

Go to the documentation of this file.
00001 /*
00002     kpgpbase2.cpp
00003 
00004     Copyright (C) 2001,2002 the KPGP authors
00005     See file AUTHORS.kpgp for details
00006 
00007     This file is part of KPGP, the KDE PGP/GnuPG support library.
00008 
00009     KPGP is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software Foundation,
00016     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "kpgpbase.h"
00020 #include "kpgp.h"
00021 
00022 #include <string.h> /* strncmp */
00023 #include <assert.h>
00024 
00025 #include <QDateTime>
00026 //Added by qt3to4:
00027 #include <QByteArray>
00028 
00029 #include <klocale.h>
00030 #include <kshell.h>
00031 #include <kdebug.h>
00032 
00033 #define PGP2 "pgp"
00034 
00035 namespace Kpgp {
00036 
00037 Base2::Base2()
00038   : Base()
00039 {
00040 }
00041 
00042 
00043 Base2::~Base2()
00044 {
00045 }
00046 
00047 
00048 int
00049 Base2::encrypt( Block& block, const KeyIDList& recipients )
00050 {
00051   return encsign( block, recipients, 0 );
00052 }
00053 
00054 
00055 int
00056 Base2::clearsign( Block& block, const char *passphrase )
00057 {
00058   return encsign( block, KeyIDList(), passphrase );
00059 }
00060 
00061 
00062 int
00063 Base2::encsign( Block& block, const KeyIDList& recipients,
00064                 const char *passphrase )
00065 {
00066   QByteArray cmd;
00067   int exitStatus = 0;
00068 
00069   if(!recipients.isEmpty() && passphrase != 0)
00070     cmd = PGP2 " +batchmode +language=en +verbose=1 -seat";
00071   else if(!recipients.isEmpty())
00072     cmd = PGP2 " +batchmode +language=en +verbose=1 -eat";
00073   else if(passphrase != 0)
00074     cmd = PGP2 " +batchmode +language=en +verbose=1 -sat";
00075   else
00076   {
00077     kDebug( 5326 ) <<"kpgpbase: Neither recipients nor passphrase specified.";
00078     return OK;
00079   }
00080 
00081   if(passphrase != 0)
00082     cmd += addUserId();
00083 
00084   if(!recipients.isEmpty()) {
00085     if(Module::getKpgp()->encryptToSelf())
00086     {
00087       cmd += " 0x";
00088       cmd += Module::getKpgp()->user();
00089     }
00090 
00091     for( KeyIDList::ConstIterator it = recipients.begin();
00092          it != recipients.end(); ++it ) {
00093       cmd += " 0x";
00094       cmd += (*it);
00095     }
00096   }
00097   cmd += " -f";
00098 
00099   clear();
00100   input = block.text();
00101   exitStatus = run(cmd.data(), passphrase);
00102   if( !output.isEmpty() )
00103     block.setProcessedText( output );
00104   block.setError( error );
00105 
00106   if(exitStatus != 0)
00107     status = ERROR;
00108 
00109 #if 0
00110   // #### FIXME: As we check the keys ourselves the following problems
00111   //             shouldn't occur. Therefore I don't handle them for now.
00112   //             IK 01/2002
00113   if(!recipients.isEmpty())
00114   {
00115     int index = 0;
00116     bool bad = false;
00117     unsigned int num = 0;
00118     QByteArray badkeys = "";
00119     if (error.contains("Cannot find the public key") )
00120     {
00121       index = 0;
00122       num = 0;
00123       while((index = error.indexOf("Cannot find the public key",index))
00124         != -1)
00125       {
00126         bad = true;
00127         index = error.indexOf('\'',index);
00128         int index2 = error.indexOf('\'',index+1);
00129         if (num++)
00130           badkeys += ", ";
00131         badkeys += error.mid(index, index2-index+1);
00132       }
00133       if(bad)
00134       {
00135         badkeys.trimmed();
00136         if(num == recipients.count())
00137       errMsg = i18n("Could not find public keys matching the userid(s)\n"
00138                         "%1;\n"
00139                         "the message is not encrypted.",
00140                          badkeys.data() );
00141         else
00142           errMsg = i18n("Could not find public keys matching the userid(s)\n"
00143                         "%1;\n"
00144                         "these persons will not be able to read the message.",
00145                          badkeys.data() );
00146         status |= MISSINGKEY;
00147         status |= ERROR;
00148       }
00149     }
00150     if (error.contains("skipping userid") )
00151     {
00152       index = 0;
00153       num = 0;
00154       while((index = error.indexOf("skipping userid",index))
00155         != -1)
00156       {
00157         bad = true;
00158         int index2 = error.indexOf('\n',index+16);
00159         if (num++)
00160           badkeys += ", ";
00161         badkeys += error.mid(index+16, index2-index-16);
00162         index = index2;
00163       }
00164       if(bad)
00165       {
00166         badkeys.trimmed();
00167         if(num == recipients.count())
00168       errMsg = i18n("Public keys not certified with trusted signature "
00169                         "for userid(s)\n"
00170                         "%1.\n"
00171                         "The message is not encrypted.",
00172                          badkeys.data() );
00173         else
00174       errMsg = i18n("Public keys not certified with trusted signature "
00175                         "for userid(s)\n"
00176                         "%1;\n"
00177                         "these persons will not be able to read the message.",
00178                          badkeys.data() );
00179         status |= BADKEYS;
00180         status |= ERROR;
00181         return status;
00182       }
00183     }
00184   }
00185 #endif
00186   if(passphrase != 0)
00187   {
00188     if(error.contains("Pass phrase is good") )
00189     {
00190       //kDebug( 5326 ) <<"Base: Good Passphrase!";
00191       status |= SIGNED;
00192     }
00193     if( error.contains("Bad pass phrase") )
00194     {
00195       errMsg = i18n("Bad passphrase; could not sign.");
00196       status |= BADPHRASE;
00197       status |= ERR_SIGNING;
00198       status |= ERROR;
00199     }
00200   }
00201   if (error.contains("Signature error") )
00202   {
00203     errMsg = i18n("Signing failed: please check your PGP User Identity, "
00204                   "the PGP setup, and the key rings.");
00205     status |= NO_SEC_KEY;
00206     status |= ERR_SIGNING;
00207     status |= ERROR;
00208   }
00209   if (error.contains("Encryption error") )
00210   {
00211     errMsg = i18n("Encryption failed: please check your PGP setup "
00212                   "and the key rings.");
00213     status |= NO_SEC_KEY;
00214     status |= BADKEYS;
00215     status |= ERROR;
00216   }
00217 
00218   //kDebug( 5326 ) <<"status =" << status;
00219   block.setStatus( status );
00220   return status;
00221 }
00222 
00223 
00224 int
00225 Base2::decrypt( Block& block, const char *passphrase )
00226 {
00227   int index, index2;
00228   int exitStatus = 0;
00229 
00230   clear();
00231   input = block.text();
00232   exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
00233   if( !output.isEmpty() )
00234     block.setProcessedText( output );
00235   block.setError( error );
00236 
00237   // pgp2.6 has sometimes problems with the ascii armor pgp5.0 produces
00238   // this hack can solve parts of the problem
00239   if(error.contains("ASCII armor corrupted.") )
00240   {
00241     kDebug( 5326 ) <<"removing ASCII armor header";
00242     int index1 = input.indexOf("-----BEGIN PGP SIGNED MESSAGE-----");
00243     if(index1 != -1)
00244       index1 = input.indexOf("-----BEGIN PGP SIGNATURE-----", index1);
00245     else
00246       index1 = input.indexOf("-----BEGIN PGP MESSAGE-----");
00247     index1 = input.indexOf('\n', index1);
00248     index2 = input.indexOf("\n\n", index1);
00249     input.remove(index1, index2 - index1);
00250     exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
00251     if( !output.isEmpty() )
00252       block.setProcessedText( output );
00253     block.setError( error );
00254   }
00255 
00256   if(exitStatus == -1) {
00257     errMsg = i18n("error running PGP");
00258     status = ERROR;
00259     block.setStatus( status );
00260     return status;
00261   }
00262 
00263   /* Example No.1 (PGP 2.6.3in):
00264    * File is encrypted.  Secret key is required to read it.
00265    * Key for user ID: Test Key (only for testing) <testkey@ingo-kloecker.de>
00266    * 1024-bit key, key ID E2D074D3, created 2001/09/09
00267    *
00268    * Error:  Bad pass phrase.
00269    *
00270    * This message can only be read by:
00271    *   Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
00272    *   Test Key (only for testing) <testkey@ingo-kloecker.de>
00273    *
00274    * You do not have the secret key needed to decrypt this file.
00275    */
00276   /* Example No.2 (PGP 2.6.3in):
00277    * File is encrypted.  Secret key is required to read it.
00278    * This message can only be read by:
00279    *   Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
00280    *
00281    * You do not have the secret key needed to decrypt this file.
00282    */
00283   if(error.contains("File is encrypted.") )
00284   {
00285     //kDebug( 5326 ) <<"kpgpbase: message is encrypted";
00286     status |= ENCRYPTED;
00287     if((index = error.indexOf("Key for user ID:")) != -1 )
00288     {
00289       // Find out the key for which the phrase is needed
00290       index  += 17;
00291       index2 = error.indexOf('\n', index);
00292       block.setRequiredUserId( error.mid(index, index2 - index) );
00293       //kDebug( 5326 ) <<"Base: key needed is \"" << block.requiredUserId() <<"\"!";
00294 
00295       if((passphrase != 0) && (error.contains("Bad pass phrase") ))
00296       {
00297         errMsg = i18n("Bad passphrase; could not decrypt.");
00298         kDebug( 5326 ) <<"Base: passphrase is bad";
00299         status |= BADPHRASE;
00300         status |= ERROR;
00301       }
00302     }
00303     else
00304     {
00305       // no secret key fitting this message
00306       status |= NO_SEC_KEY;
00307       status |= ERROR;
00308       errMsg = i18n("You do not have the secret key needed to decrypt this message.");
00309       kDebug( 5326 ) <<"Base: no secret key for this message";
00310     }
00311     // check for persons
00312 #if 0
00313     // ##### FIXME: This information is anyway currently not used
00314     //       I'll change it to always determine the recipients.
00315     index = error.indexOf("can only be read by:");
00316     if(index != -1)
00317     {
00318       index = error.indexOf('\n',index);
00319       int end = error.indexOf("\n\n",index);
00320 
00321       mRecipients.clear();
00322       while( (index2 = error.indexOf('\n',index+1)) <= end )
00323       {
00324     QByteArray item = error.mid(index+1,index2-index-1);
00325     item.trimmed();
00326     mRecipients.append(item);
00327     index = index2;
00328       }
00329     }
00330 #endif
00331   }
00332 
00333   // handle signed message
00334 
00335   // Examples (made with PGP 2.6.3in)
00336   /* Example No. 1 (signed with unknown key):
00337    * File has signature.  Public key is required to check signature.
00338    *
00339    * Key matching expected Key ID 12345678 not found in file '/home/user/.pgp/pubring.pgp'.
00340    *
00341    * WARNING: Can't find the right public key-- can't check signature integrity.
00342    */
00343   /* Example No. 2 (bad signature):
00344    * File has signature.  Public key is required to check signature.
00345    * ..
00346    * WARNING: Bad signature, doesn't match file contents!
00347    *
00348    * Bad signature from user "Joe User <joe@foo.bar>".
00349    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00350    */
00351   /* Example No. 3.1 (good signature with untrusted key):
00352    * File has signature.  Public key is required to check signature.
00353    * .
00354    * Good signature from user "Joe User <joe@foo.bar>".
00355    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00356    *
00357    * WARNING:  Because this public key is not certified with a trusted
00358    * signature, it is not known with high confidence that this public key
00359    * actually belongs to: "Joe User <joe@foo.bar>".
00360    */
00361   /* Example No. 3.2 (good signature with untrusted key):
00362    * File has signature.  Public key is required to check signature.
00363    * .
00364    * Good signature from user "Joe User <joe@foo.bar>".
00365    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00366    *
00367    * WARNING:  Because this public key is not certified with enough trusted
00368    * signatures, it is not known with high confidence that this public key
00369    * actually belongs to: "Joe User <joe@foo.bar>".
00370    */
00371   /* Example No. 4 (good signature with revoked key):
00372    * File has signature.  Public key is required to check signature.
00373    * .
00374    * Good signature from user "Joe User <joe@foo.bar>".
00375    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00376    *
00377    *
00378    * Key for user ID: Joe User <joe@foo.bar>
00379    * 1024-bit key, key ID 12345678, created 2001/09/09
00380    * Key has been revoked.
00381    *
00382    * WARNING:  This key has been revoked by its owner,
00383    * possibly because the secret key was compromised.
00384    * This could mean that this signature is a forgery.
00385    */
00386   /* Example No. 5 (good signature with trusted key):
00387    * File has signature.  Public key is required to check signature.
00388    * .
00389    * Good signature from user "Joe User <joe@foo.bar>".
00390    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00391    */
00392 
00393   if((index = error.indexOf("File has signature")) != -1 )
00394   {
00395     // move index to start of next line
00396     index = error.indexOf('\n', index+18) + 1;
00397     //kDebug( 5326 ) <<"Base: message is signed";
00398     status |= SIGNED;
00399     // get signature date and signature key ID
00400     if ((index2 = error.indexOf("Signature made", index)) != -1 ) {
00401       index2 += 15;
00402       int index3 = error.indexOf("using", index2);
00403       block.setSignatureDate( error.mid(index2, index3-index2-1) );
00404       kDebug( 5326 ) <<"Message was signed on '" << block.signatureDate() <<"'";
00405       index3 = error.indexOf("key ID ", index3) + 7;
00406       block.setSignatureKeyId( error.mid(index3,8) );
00407       kDebug( 5326 ) <<"Message was signed with key '" << block.signatureKeyId() <<"'";
00408     }
00409     else {
00410       // if pgp can't find the keyring it unfortunately doesn't print
00411       // the signature date and key ID
00412       block.setSignatureDate( "" );
00413       block.setSignatureKeyId( "" );
00414     }
00415 
00416     if( ( index2 = error.indexOf("Key matching expected", index) ) != -1 )
00417     {
00418       status |= UNKNOWN_SIG;
00419       status |= GOODSIG;
00420       int index3 = error.indexOf("Key ID ", index2) + 7;
00421       block.setSignatureKeyId( error.mid(index3,8) );
00422       block.setSignatureUserId( QString() );
00423     }
00424     else if( (index2 = error.indexOf("Good signature from", index)) != -1 )
00425     {
00426       status |= GOODSIG;
00427       // get signer
00428       index = error.indexOf('"',index2+19);
00429       index2 = error.indexOf('"', index+1);
00430       block.setSignatureUserId( error.mid(index+1, index2-index-1) );
00431     }
00432     else if( (index2 = error.indexOf("Bad signature from", index)) != -1 )
00433     {
00434       status |= ERROR;
00435       // get signer
00436       index = error.indexOf('"',index2+19);
00437       index2 = error.indexOf('"', index+1);
00438       block.setSignatureUserId( error.mid(index+1, index2-index-1) );
00439     }
00440     else if( error.indexOf("Keyring file", index) != -1 )
00441     {
00442       // #### fix this hack
00443       status |= UNKNOWN_SIG;
00444       status |= GOODSIG; // this is a hack...
00445       // determine file name of missing keyring file
00446       index = error.indexOf('\'', index) + 1;
00447       index2 = error.indexOf('\'', index);
00448       block.setSignatureUserId( i18n("The keyring file %1 does not exist.\n"
00449       "Please check your PGP setup.", QString::fromLatin1( error.mid(index, index2-index)) ) );
00450     }
00451     else
00452     {
00453       status |= ERROR;
00454       block.setSignatureUserId( i18n("Unknown error") );
00455     }
00456   }
00457   //kDebug( 5326 ) <<"status =" << status;
00458   block.setStatus( status );
00459   return status;
00460 }
00461 
00462 
00463 Key*
00464 Base2::readPublicKey( const KeyID& keyID,
00465                       const bool readTrust /* = false */,
00466                       Key* key /* = 0 */ )
00467 {
00468   int exitStatus = 0;
00469 
00470   status = 0;
00471   exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kvc -f 0x" +
00472                     keyID, 0, true );
00473 
00474   if(exitStatus != 0) {
00475     status = ERROR;
00476     return 0;
00477   }
00478 
00479   key = parsePublicKeyData( output, key );
00480 
00481   if( key == 0 )
00482   {
00483     return 0;
00484   }
00485 
00486   if( readTrust )
00487   {
00488     exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kc -f",
00489                       0, true );
00490 
00491     if(exitStatus != 0) {
00492       status = ERROR;
00493       return 0;
00494     }
00495 
00496     parseTrustDataForKey( key, error );
00497   }
00498 
00499   return key;
00500 }
00501 
00502 
00503 KeyList
00504 Base2::publicKeys( const QStringList & patterns )
00505 {
00506   return doGetPublicKeys( PGP2 " +batchmode +language=en +verbose=0 -kvc -f",
00507                           patterns );
00508 }
00509 
00510 KeyList
00511 Base2::doGetPublicKeys( const QByteArray & cmd, const QStringList & patterns )
00512 {
00513   int exitStatus = 0;
00514   KeyList publicKeys;
00515 
00516   status = 0;
00517   if ( patterns.isEmpty() ) {
00518     exitStatus = run( cmd, 0, true );
00519 
00520     if ( exitStatus != 0 ) {
00521       status = ERROR;
00522       return KeyList();
00523     }
00524 
00525     // now we need to parse the output for public keys
00526     publicKeys = parseKeyList( output, false );
00527   }
00528   else {
00529     typedef QMap<QByteArray, Key*> KeyMap;
00530     KeyMap map;
00531 
00532     for ( QStringList::ConstIterator it = patterns.begin();
00533           it != patterns.end(); ++it ) {
00534       exitStatus = run( cmd + ' ' + KShell::quoteArg( *it ).toLocal8Bit(),
00535                         0, true );
00536 
00537       if ( exitStatus != 0 ) {
00538         status = ERROR;
00539         return KeyList();
00540       }
00541 
00542       // now we need to parse the output for public keys
00543       publicKeys = parseKeyList( output, false );
00544 
00545       // put all new keys into a map, remove duplicates
00546       while ( !publicKeys.isEmpty() ) {
00547         Key * key = publicKeys.take( 0 );
00548         if ( !map.contains( key->primaryFingerprint() ) )
00549           map.insert( key->primaryFingerprint(), key );
00550         else
00551           delete key;
00552       }
00553     }
00554     // build list from the map
00555     for ( KeyMap::ConstIterator it = map.begin(); it != map.end(); ++it ) {
00556       publicKeys.append( it.value() );
00557     }
00558   }
00559 
00560   // sort the list of public keys
00561   publicKeys.sort();
00562 
00563   return publicKeys;
00564 }
00565 
00566 KeyList
00567 Base2::secretKeys( const QStringList & patterns )
00568 {
00569   return publicKeys( patterns );
00570 }
00571 
00572 
00573 int
00574 Base2::signKey(const KeyID& keyID, const char *passphrase)
00575 {
00576   QByteArray cmd;
00577   int exitStatus = 0;
00578 
00579   cmd = PGP2 " +batchmode +language=en -ks -f ";
00580   cmd += addUserId();
00581   cmd += " 0x" + keyID;
00582 
00583   status = 0;
00584   exitStatus = run(cmd.data(),passphrase);
00585 
00586   if (exitStatus != 0)
00587     status = ERROR;
00588 
00589   return status;
00590 }
00591 
00592 
00593 QByteArray Base2::getAsciiPublicKey(const KeyID& keyID)
00594 {
00595   int exitStatus = 0;
00596 
00597   if (keyID.isEmpty())
00598     return QByteArray();
00599 
00600   status = 0;
00601   exitStatus = run( PGP2 " +batchmode +force +language=en -kxaf 0x" + keyID,
00602                     0, true );
00603 
00604   if(exitStatus != 0) {
00605     status = ERROR;
00606     return QByteArray();
00607   }
00608 
00609   return output;
00610 }
00611 
00612 
00613 Key*
00614 Base2::parsePublicKeyData( const QByteArray& output, Key* key /* = 0 */ )
00615 {
00616   Subkey *subkey = 0;
00617   int index;
00618 
00619   // search start of key data
00620   if( !strncmp( output.data(), "pub", 3 ) ||
00621       !strncmp( output.data(), "sec", 3 ) )
00622     index = 0;
00623   else
00624   {
00625     /*
00626     if( secretKeys )
00627       index = output.indexOf( "\nsec" );
00628     else
00629     */
00630       index = output.indexOf( "\npub" );
00631     if( index == -1 )
00632       return 0;
00633     else
00634       index++;
00635   }
00636 
00637   while( true )
00638   {
00639     int index2;
00640 
00641     // search the end of the current line
00642     if( ( index2 = output.indexOf( '\n', index ) ) == -1 )
00643       break;
00644 
00645     if( !strncmp( output.data() + index, "pub", 3 ) ||
00646         !strncmp( output.data() + index, "sec", 3 ) )
00647     { // line contains primary key data
00648       // Example 1 (nothing special):
00649       // pub  1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
00650       // Example 2 (disabled key):
00651       // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
00652       // Example 3 (expired key):
00653       // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
00654       // Example 4 (revoked key):
00655       // pub  1024/956721F9 2001/09/09 *** KEY REVOKED ***
00656 
00657       int pos, pos2;
00658 
00659       if( key == 0 )
00660         key = new Key();
00661       else
00662         key->clear();
00663       /*key->setSecret( secretKeys );*/
00664       // set default key capabilities
00665       key->setCanEncrypt( true );
00666       key->setCanSign( true );
00667       key->setCanCertify( true );
00668 
00669       /*subkey = new Subkey( "", secretKeys );*/
00670       subkey = new Subkey( "", false );
00671       key->addSubkey( subkey );
00672       // set default key capabilities
00673       subkey->setCanEncrypt( true );
00674       subkey->setCanSign( true );
00675       subkey->setCanCertify( true );
00676       // expiration date defaults to never
00677       subkey->setExpirationDate( -1 );
00678 
00679       // Key Flags
00680       switch( output[index+3] )
00681       {
00682       case ' ': // nothing special
00683         break;
00684       case '-': // disabled key
00685         subkey->setDisabled( true );
00686         key->setDisabled( true );
00687         break;
00688       case '>': // expired key
00689         subkey->setExpired( true );
00690         key->setExpired( true );
00691         break;
00692       default:
00693         kDebug( 5326 ) <<"Unknown key flag.";
00694       }
00695 
00696       // Key Length
00697       pos = index + 4;
00698       while( output[pos] == ' ' )
00699         pos++;
00700       pos2 = output.indexOf( '/', pos );
00701       subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
00702 
00703       // Key ID
00704       pos = pos2 + 1;
00705       pos2 = output.indexOf( ' ', pos );
00706       subkey->setKeyID( output.mid( pos, pos2-pos ) );
00707 
00708       // Creation Date
00709       pos = pos2 + 1;
00710       while( output[pos] == ' ' )
00711         pos++;
00712       pos2 = output.indexOf( ' ', pos );
00713       int year = output.mid( pos, 4 ).toInt();
00714       int month = output.mid( pos+5, 2 ).toInt();
00715       int day = output.mid( pos+8, 2 ).toInt();
00716       QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00717       QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
00718       // The calculated creation date isn't exactly correct because QDateTime
00719       // doesn't know anything about timezones and always assumes local time
00720       // although epoch is of course UTC. But as PGP 2 anyway doesn't print
00721       // the time this doesn't matter too much.
00722       subkey->setCreationDate( epoch.secsTo( dt ) );
00723 
00724       // User ID
00725       pos = pos2 + 1;
00726       while( output[pos] == ' ' )
00727         pos++;
00728       QByteArray uid = output.mid( pos, index2-pos );
00729       if( uid != "*** KEY REVOKED ***" )
00730         key->addUserID( uid );
00731       else
00732       {
00733         subkey->setRevoked( true );
00734         key->setRevoked( true );
00735       }
00736     }
00737     else if( output[index] == ' ' )
00738     { // line contains additional key data
00739 
00740       if( key == 0 )
00741         break;
00742       assert( subkey != 0 );
00743 
00744       int pos = index + 1;
00745       while( output[pos] == ' ' )
00746         pos++;
00747 
00748       if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
00749       { // line contains a fingerprint
00750         // Example:
00751         //             Key fingerprint = 47 30 7C 76 05 BF 5E FB  72 41 00 F2 7D 0B D0 49
00752 
00753         QByteArray fingerprint = output.mid( pos, index2-pos );
00754         // remove white space from the fingerprint
00755     for ( int idx = 0 ; (idx = fingerprint.indexOf(' ', idx)) != -1 ; )
00756       fingerprint.replace( idx, 1, "" );
00757 
00758         subkey->setFingerprint( fingerprint );
00759       }
00760       else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
00761                !strncmp( output.data() + pos, "no expire ", 10 ) )
00762       { // line contains additional key properties
00763         // Examples:
00764         //            Expire: 2001/09/10
00765         //                     no expire ENCRyption only
00766         //                     no expire SIGNature only
00767 
00768         if( output[pos] == 'E' )
00769         {
00770           // Expiration Date
00771           pos += 8;
00772           int year = output.mid( pos, 4 ).toInt();
00773           int month = output.mid( pos+5, 2 ).toInt();
00774           int day = output.mid( pos+8, 2 ).toInt();
00775           QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00776           QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
00777           // Here the same comments as for the creation date are valid.
00778           subkey->setExpirationDate( epoch.secsTo( dt ) );
00779           pos += 11; // note that there is always a blank after the expire date
00780         }
00781         else
00782           pos += 10;
00783 
00784         // optional key capabilities (sign/encrypt only)
00785         if( pos != index2 )
00786         {
00787           if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
00788           {
00789             subkey->setCanEncrypt( false );
00790             key->setCanEncrypt( false );
00791           }
00792           else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
00793           {
00794             subkey->setCanSign( false );
00795             key->setCanSign( false );
00796             subkey->setCanCertify( false );
00797             key->setCanCertify( false );
00798           }
00799         }
00800       }
00801       else
00802       { // line contains an additional user id
00803         // Example:
00804         //                               Test key (2nd user ID) <abc@xyz>
00805 
00806         key->addUserID( output.mid( pos, index2-pos ) );
00807       }
00808     }
00809     index = index2 + 1;
00810   }
00811 
00812   //kDebug( 5326 ) <<"finished parsing key data";
00813 
00814   return key;
00815 }
00816 
00817 
00818 void
00819 Base2::parseTrustDataForKey( Key* key, const QByteArray& str )
00820 {
00821   if( ( key == 0 ) || str.isEmpty() )
00822     return;
00823 
00824   QByteArray keyID = key->primaryKeyID();
00825   UserIDList userIDs = key->userIDs();
00826 
00827   // search the trust data belonging to this key
00828   int index = str.indexOf( '\n' ) + 1;
00829   while( ( index > 0 ) &&
00830          ( strncmp( str.data() + index+2, keyID.data(), 8 ) != 0 ) )
00831     index = str.indexOf( '\n', index ) + 1;
00832 
00833   if( index == 0 )
00834     return;
00835 
00836   bool ultimateTrust = false;
00837   if( !strncmp( str.data() + index+11, "ultimate", 8 ) )
00838     ultimateTrust = true;
00839 
00840   bool firstLine = true;
00841 
00842   while( true )
00843   { // loop over all trust information about this key
00844     int index2;
00845 
00846     // search the end of the current line
00847     if( ( index2 = str.indexOf( '\n', index ) ) == -1 )
00848       break;
00849 
00850     // check if trust info for the next key starts
00851     if( !firstLine && ( str[index+2] != ' ' ) )
00852       break;
00853 
00854     if( str[index+21] != ' ' )
00855     { // line contains a validity value for a user ID
00856 
00857       // determine the validity
00858       Validity validity = KPGP_VALIDITY_UNKNOWN;
00859       if( !strncmp( str.data() + index+21, "complete", 8 ) )
00860         if( ultimateTrust )
00861           validity = KPGP_VALIDITY_ULTIMATE;
00862         else
00863           validity = KPGP_VALIDITY_FULL;
00864       else if( !strncmp( str.data() + index+21, "marginal", 8 ) )
00865         validity = KPGP_VALIDITY_MARGINAL;
00866       else if( !strncmp( str.data() + index+21, "never", 5 ) )
00867         validity = KPGP_VALIDITY_NEVER;
00868       else if( !strncmp( str.data() + index+21, "undefined", 9 ) )
00869         validity = KPGP_VALIDITY_UNDEFINED;
00870 
00871       // determine the user ID
00872       int pos = index + 31;
00873       if( str[index+2] == ' ' )
00874         pos++; // additional user IDs start one column later
00875       QString uid = str.mid( pos, index2-pos );
00876 
00877       // set the validity of the corresponding user ID
00878       for( UserIDListIterator it( userIDs ); it.current(); ++it )
00879         if( (*it)->text() == uid )
00880         {
00881           kDebug( 5326 )<<"Setting the validity of"<<uid<<" to"<<validity;
00882           (*it)->setValidity( validity );
00883           break;
00884         }
00885     }
00886 
00887     firstLine = false;
00888     index = index2 + 1;
00889   }
00890 }
00891 
00892 
00893 KeyList
00894 Base2::parseKeyList( const QByteArray& output, bool secretKeys )
00895 {
00896   kDebug( 5326 ) <<"Kpgp::Base2::parseKeyList()";
00897   KeyList keys;
00898   Key *key = 0;
00899   Subkey *subkey = 0;
00900   int index;
00901 
00902   // search start of key data
00903   if( !strncmp( output.data(), "pub", 3 ) ||
00904       !strncmp( output.data(), "sec", 3 ) )
00905     index = 0;
00906   else
00907   {
00908     if( secretKeys )
00909       index = output.indexOf( "\nsec" );
00910     else
00911       index = output.indexOf( "\npub" );
00912     if( index == -1 )
00913       return keys;
00914     else
00915       index++;
00916   }
00917 
00918   while( true )
00919   {
00920     int index2;
00921 
00922     // search the end of the current line
00923     if( ( index2 = output.indexOf( '\n', index ) ) == -1 )
00924       break;
00925 
00926     if( !strncmp( output.data() + index, "pub", 3 ) ||
00927         !strncmp( output.data() + index, "sec", 3 ) )
00928     { // line contains primary key data
00929       // Example 1:
00930       // pub  1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
00931       // Example 2 (disabled key):
00932       // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
00933       // Example 3 (expired key):
00934       // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
00935       // Example 4 (revoked key):
00936       // pub  1024/956721F9 2001/09/09 *** KEY REVOKED ***
00937 
00938       int pos, pos2;
00939 
00940       if( key != 0 ) // store the previous key in the key list
00941     keys.append( key );
00942 
00943       key = new Key();
00944       key->setSecret( secretKeys );
00945       // set default key capabilities
00946       key->setCanEncrypt( true );
00947       key->setCanSign( true );
00948       key->setCanCertify( true );
00949 
00950       subkey = new Subkey( "", secretKeys );
00951       key->addSubkey( subkey );
00952       // set default key capabilities
00953       subkey->setCanEncrypt( true );
00954       subkey->setCanSign( true );
00955       subkey->setCanCertify( true );
00956       // expiration date defaults to never
00957       subkey->setExpirationDate( -1 );
00958 
00959       // Key Flags
00960       switch( output[index+3] )
00961       {
00962       case ' ': // nothing special
00963         break;
00964       case '-': // disabled key
00965         subkey->setDisabled( true );
00966         key->