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

libkpgp

kpgpbaseG.cpp

Go to the documentation of this file.
00001 /*
00002     kpgpbaseG.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 <klocale.h>
00023 #include <kshell.h>
00024 #include <kdebug.h>
00025 
00026 #include <QTextCodec>
00027 #include <QByteArray>
00028 
00029 #include <string.h> /* strncmp */
00030 
00031 namespace Kpgp {
00032 
00033 BaseG::BaseG()
00034   : Base()
00035 {
00036   // determine the version of gpg (the method is equivalent to gpgme's method)
00037   runGpg( "--version", 0 );
00038   int eol = output.indexOf( '\n' );
00039   if( eol > 0 ) {
00040     int pos = output.lastIndexOf( ' ', eol - 1 );
00041     if( pos != -1 ) {
00042       mVersion = output.mid( pos + 1, eol - pos - 1 );
00043       kDebug( 5326 ) <<"found GnuPG" << mVersion;
00044     }
00045   }
00046 }
00047 
00048 
00049 BaseG::~BaseG()
00050 {
00051 }
00052 
00053 
00054 int
00055 BaseG::encrypt( Block& block, const KeyIDList& recipients )
00056 {
00057   return encsign( block, recipients, 0 );
00058 }
00059 
00060 
00061 int
00062 BaseG::clearsign( Block& block, const char *passphrase )
00063 {
00064   return encsign( block, KeyIDList(), passphrase );
00065 }
00066 
00067 
00068 int
00069 BaseG::encsign( Block& block, const KeyIDList& recipients,
00070                 const char *passphrase )
00071 {
00072   QByteArray cmd;
00073   int exitStatus = 0;
00074 
00075   if(!recipients.isEmpty() && passphrase != 0)
00076     cmd = "--batch --armor --sign --encrypt --textmode";
00077   else if(!recipients.isEmpty())
00078     cmd = "--batch --armor --encrypt --textmode";
00079   else if(passphrase != 0)
00080     cmd = "--batch --escape-from --clearsign";
00081   else
00082   {
00083     kDebug( 5326 ) <<"kpgpbase: Neither recipients nor passphrase specified.";
00084     return OK;
00085   }
00086 
00087   if(passphrase != 0)
00088     cmd += addUserId();
00089 
00090   if(!recipients.isEmpty())
00091   {
00092     cmd += " --set-filename stdin";
00093 
00094     QByteArray pgpUser = Module::getKpgp()->user();
00095     if(Module::getKpgp()->encryptToSelf() && !pgpUser.isEmpty()) {
00096       cmd += " -r 0x";
00097       cmd += pgpUser;
00098     }
00099 
00100     for( KeyIDList::ConstIterator it = recipients.begin();
00101          it != recipients.end(); ++it ) {
00102       cmd += " -r 0x";
00103       cmd += (*it);
00104     }
00105   }
00106 
00107   clear();
00108   input = block.text();
00109   exitStatus = runGpg(cmd.data(), passphrase);
00110   if( !output.isEmpty() )
00111     block.setProcessedText( output );
00112   block.setError( error );
00113 
00114   if( exitStatus != 0 )
00115   {
00116     // this error message is later hopefully overwritten
00117     errMsg = i18n( "Unknown error." );
00118     status = ERROR;
00119   }
00120 
00121 #if 0
00122   // #### FIXME: As we check the keys ourselves the following problems
00123   //             shouldn't occur. Therefore I don't handle them for now.
00124   //             IK 01/2002
00125   if(!recipients.isEmpty())
00126   {
00127     int index = 0;
00128     bool bad = false;
00129     unsigned int num = 0;
00130     QByteArray badkeys = "";
00131     // Examples:
00132     // gpg: 0x12345678: skipped: public key not found
00133     // gpg: 0x12345678: skipped: public key is disabled
00134     // gpg: 0x12345678: skipped: unusable public key
00135     // (expired or revoked key)
00136     // gpg: 23456789: no info to calculate a trust probability
00137     // (untrusted key, 23456789 is the key Id of the encryption sub key)
00138     while((index = error.indexOf("skipped: ",index) ) != -1 )
00139     {
00140       bad = true;
00141       index = error.indexOf('\'',index);
00142       int index2 = error.indexOf('\'',index+1);
00143       badkeys += error.mid(index, index2-index+1) + ", ";
00144       num++;
00145     }
00146     if(bad)
00147     {
00148       badkeys.trimmed();
00149       if(num == recipients.count())
00150         errMsg = i18n("Could not find public keys matching the userid(s)\n"
00151                       "%1;\n"
00152                       "the message is not encrypted.",
00153                        badkeys.data() );
00154       else
00155         errMsg = i18n("Could not find public keys matching the userid(s)\n"
00156                       "%1;\n"
00157                       "these persons will not be able to read the message.",
00158                        badkeys.data() );
00159       status |= MISSINGKEY;
00160       status |= ERROR;
00161     }
00162   }
00163 #endif
00164   if( passphrase != 0 )
00165   {
00166     // Example 1 (bad passphrase, clearsign only):
00167     // gpg: skipped `0x12345678': bad passphrase
00168     // gpg: [stdin]: clearsign failed: bad passphrase
00169     // Example 2 (bad passphrase, sign & encrypt):
00170     // gpg: skipped `0x12345678': bad passphrase
00171     // gpg: [stdin]: sign+encrypt failed: bad passphrase
00172     // Example 3 (unusable secret key, clearsign only):
00173     // gpg: skipped `0x12345678': unusable secret key
00174     // gpg: [stdin]: clearsign failed: unusable secret key
00175     // Example 4 (unusable secret key, sign & encrypt):
00176     // gpg: skipped `0xAC0EB35D': unusable secret key
00177     // gpg: [stdin]: sign+encrypt failed: unusable secret key
00178     if( error.contains("bad passphrase") )
00179     {
00180       errMsg = i18n("Signing failed because the passphrase is wrong.");
00181       status |= BADPHRASE;
00182       status |= ERR_SIGNING;
00183       status |= ERROR;
00184     }
00185     else if( error.contains("unusable secret key") )
00186     {
00187       errMsg = i18n("Signing failed because your secret key is unusable.");
00188       status |= ERR_SIGNING;
00189       status |= ERROR;
00190     }
00191     else if( !( status & ERROR ) )
00192     {
00193       //kDebug( 5326 ) <<"Base: Good Passphrase!";
00194       status |= SIGNED;
00195     }
00196   }
00197 
00198   //kDebug( 5326 ) <<"status =" << status;
00199   block.setStatus( status );
00200   return status;
00201 }
00202 
00203 
00204 int
00205 BaseG::decrypt( Block& block, const char *passphrase )
00206 {
00207   int index, index2;
00208   int exitStatus = 0;
00209 
00210   clear();
00211   input = block.text();
00212   exitStatus = runGpg("--batch --decrypt", passphrase);
00213   if( !output.isEmpty() && ( !error.contains( "gpg: quoted printable" ) ) )
00214     block.setProcessedText( output );
00215   block.setError( error );
00216 
00217   if(exitStatus == -1) {
00218     errMsg = i18n("Error running gpg");
00219     status = ERROR;
00220     block.setStatus( status );
00221     return status;
00222   }
00223 
00224   // Example 1 (good passphrase, decryption successful):
00225   // gpg: encrypted with 2048-bit ELG-E key, ID 12345678, created 2000-11-11
00226   //       "Foo Bar <foo@bar.xyz>"
00227   //
00228   // Example 2 (bad passphrase):
00229   // gpg: encrypted with 1024-bit RSA key, ID 12345678, created 1991-01-01
00230   //       "Foo Bar <foo@bar.xyz>"
00231   // gpg: public key decryption failed: bad passphrase
00232   // gpg: decryption failed: secret key not available
00233   //
00234   // Example 3 (no secret key available):
00235   // gpg: encrypted with RSA key, ID 12345678
00236   // gpg: decryption failed: secret key not available
00237   //
00238   // Example 4 (good passphrase for second key, decryption successful):
00239   // gpg: encrypted with 2048-bit ELG-E key, ID 12345678, created 2000-01-01
00240   //       "Foo Bar (work) <foo@bar.xyz>"
00241   // gpg: public key decryption failed: bad passphrase
00242   // gpg: encrypted with 2048-bit ELG-E key, ID 23456789, created 2000-02-02
00243   //       "Foo Bar (home) <foo@bar.xyz>"
00244   if( error.contains( "gpg: encrypted with" ) )
00245   {
00246     //kDebug( 5326 ) <<"kpgpbase: message is encrypted";
00247     status |= ENCRYPTED;
00248     if( error.contains( "\ngpg: decryption failed" ) )
00249     {
00250       if( ( index = error.indexOf( "bad passphrase" ) ) != -1 )
00251       {
00252         if( passphrase != 0 )
00253         {
00254           errMsg = i18n( "Bad passphrase; could not decrypt." );
00255           kDebug( 5326 ) <<"Base: passphrase is bad";
00256           status |= BADPHRASE;
00257           status |= ERROR;
00258         }
00259         else
00260         {
00261           // Search backwards the user ID of the needed key
00262           index2 = error.lastIndexOf('"', index) - 1;
00263           index = error.lastIndexOf("      \"", index2) + 7;
00264           // The conversion from UTF8 is necessary because gpg stores and
00265           // prints user IDs in UTF8
00266           block.setRequiredUserId( QString::fromUtf8( error.mid( index, index2 - index + 1 ) ) );
00267           kDebug( 5326 ) <<"Base: key needed is \"" << block.requiredUserId() <<"\"!";
00268         }
00269       }
00270       else if( error.contains( "secret key not available" ) )
00271       {
00272         // no secret key fitting this message
00273         status |= NO_SEC_KEY;
00274         status |= ERROR;
00275         errMsg = i18n("You do not have the secret key needed to decrypt this message.");
00276         kDebug( 5326 ) <<"Base: no secret key for this message";
00277       }
00278     }
00279     // check for persons
00280 #if 0
00281     // ##### FIXME: This information is anyway currently not used
00282     //       I'll change it to always determine the recipients.
00283     index = error.indexOf("can only be read by:");
00284     if(index != -1)
00285     {
00286       index = error.indexOf('\n',index);
00287       int end = error.indexOf("\n\n",index);
00288 
00289       mRecipients.clear();
00290       while( (index2 = error.indexOf('\n',index+1)) <= end )
00291       {
00292     QByteArray item = error.mid(index+1,index2-index-1);
00293     item.trimmed();
00294     mRecipients.append(item);
00295     index = index2;
00296       }
00297     }
00298 #endif
00299   }
00300 
00301   // Example 1 (unknown signature key):
00302   // gpg: Signature made Wed 02 Jan 2002 11:26:33 AM CET using DSA key ID 2E250C64
00303   // gpg: Can't check signature: public key not found
00304   if( ( index = error.indexOf("Signature made") ) != -1 )
00305   {
00306     //kDebug( 5326 ) <<"Base: message is signed";
00307     status |= SIGNED;
00308     // get signature date and signature key ID
00309     // Example: Signature made Sun 06 May 2001 03:49:27 PM CEST using DSA key ID 12345678
00310     index2 = error.indexOf("using", index+15);
00311     block.setSignatureDate( error.mid(index+15, index2-(index+15)-1) );
00312     kDebug( 5326 ) <<"Message was signed on '" << block.signatureDate() <<"'";
00313     index2 = error.indexOf("key ID ", index2) + 7;
00314     block.setSignatureKeyId( error.mid(index2,8) );
00315     kDebug( 5326 ) <<"Message was signed with key '" << block.signatureKeyId() <<"'";
00316     // move index to start of next line
00317     index = error.indexOf('\n', index2)+1;
00318 
00319     if ((error.indexOf("Key matching expected", index) != -1 )
00320         || (error.indexOf("Can't check signature", index) != -1 ))
00321     {
00322       status |= UNKNOWN_SIG;
00323       status |= GOODSIG;
00324       block.setSignatureUserId( QString() );
00325     }
00326     else if( error.indexOf("Good signature", index) != -1 )
00327     {
00328       status |= GOODSIG;
00329       // get the primary user ID of the signer
00330       index = error.indexOf('"',index);
00331       index2 = error.indexOf('\n',index+1);
00332       index2 = error.lastIndexOf('"', index2-1);
00333       block.setSignatureUserId( error.mid( index+1, index2-index-1 ) );
00334     }
00335     else if( error.indexOf("BAD signature", index) != -1 )
00336     {
00337       //kDebug( 5326 ) <<"BAD signature";
00338       status |= ERROR;
00339       // get the primary user ID of the signer
00340       index = error.indexOf('"',index);
00341       index2 = error.indexOf('\n',index+1);
00342       index2 = error.lastIndexOf('"', index2-1);
00343       block.setSignatureUserId( error.mid( index+1, index2-index-1 ) );
00344     }
00345     else if( error.indexOf("Can't find the right public key", index) != -1 )
00346     {
00347       // #### fix this hack
00348       // I think this can't happen anymore because if the pubring is missing
00349       // the current GnuPG creates a new empty one.
00350       status |= UNKNOWN_SIG;
00351       status |= GOODSIG; // this is a hack...
00352       block.setSignatureUserId( i18n("??? (file ~/.gnupg/pubring.gpg not found)") );
00353     }
00354     else
00355     {
00356       status |= ERROR;
00357       block.setSignatureUserId( QString() );
00358     }
00359   }
00360   //kDebug( 5326 ) <<"status =" << status;
00361   block.setStatus( status );
00362   return status;
00363 }
00364 
00365 
00366 Key*
00367 BaseG::readPublicKey( const KeyID& keyID,
00368                       const bool readTrust /* = false */,
00369                       Key* key /* = 0 */ )
00370 {
00371   int exitStatus = 0;
00372 
00373   status = 0;
00374   if( readTrust )
00375     exitStatus = runGpg( "--batch --list-public-keys --with-fingerprint --with-colons --fixed-list-mode 0x" + keyID, 0, true );
00376   else
00377     exitStatus = runGpg( "--batch --list-public-keys --with-fingerprint --with-colons --fixed-list-mode --no-expensive-trust-checks 0x" + keyID, 0, true );
00378 
00379   if(exitStatus != 0) {
00380     status = ERROR;
00381     return 0;
00382   }
00383 
00384   int offset;
00385   // search start of key data
00386   if( !strncmp( output.data(), "pub:", 4 ) )
00387     offset = 0;
00388   else {
00389     offset = output.indexOf( "\npub:" );
00390     if( offset == -1 )
00391       return 0;
00392     else
00393       offset++;
00394   }
00395 
00396   key = parseKeyData( output, offset, key );
00397 
00398   return key;
00399 }
00400 
00401 
00402 KeyList
00403 BaseG::publicKeys( const QStringList & patterns )
00404 {
00405   int exitStatus = 0;
00406 
00407   // the option --with-colons should be used for interprocess communication
00408   // with gpg (according to Werner Koch)
00409   QByteArray cmd = "--batch --list-public-keys --with-fingerprint --with-colons "
00410                  "--fixed-list-mode --no-expensive-trust-checks";
00411   for ( QStringList::ConstIterator it = patterns.begin();
00412         it != patterns.end(); ++it ) {
00413     cmd += ' ';
00414     cmd += KShell::quoteArg( *it ).toLocal8Bit();
00415   }
00416   status = 0;
00417   exitStatus = runGpg( cmd, 0, true );
00418 
00419   if(exitStatus != 0) {
00420     status = ERROR;
00421     return KeyList();
00422   }
00423 
00424   // now we need to parse the output for public keys
00425   KeyList publicKeys = parseKeyList(output, false);
00426 
00427   // sort the list of public keys
00428   publicKeys.sort();
00429 
00430   return publicKeys;
00431 }
00432 
00433 
00434 KeyList
00435 BaseG::secretKeys( const QStringList & patterns )
00436 {
00437   int exitStatus = 0;
00438 
00439   // the option --with-colons should be used for interprocess communication
00440   // with gpg (according to Werner Koch)
00441   QByteArray cmd = "--batch --list-secret-keys --with-fingerprint --with-colons "
00442                  "--fixed-list-mode";
00443   for ( QStringList::ConstIterator it = patterns.begin();
00444         it != patterns.end(); ++it ) {
00445     cmd += ' ';
00446     cmd += KShell::quoteArg( *it ).toLocal8Bit();
00447   }
00448   status = 0;
00449   exitStatus = runGpg( cmd, 0, true );
00450 
00451   if(exitStatus != 0) {
00452     status = ERROR;
00453     return KeyList();
00454   }
00455 
00456   // now we need to parse the output for secret keys
00457   KeyList secretKeys = parseKeyList(output, true);
00458 
00459   // sort the list of secret keys
00460   secretKeys.sort();
00461 
00462   return secretKeys;
00463 }
00464 
00465 
00466 int
00467 BaseG::signKey(const KeyID& keyID, const char *passphrase)
00468 {
00469   QByteArray cmd;
00470   int exitStatus = 0;
00471 
00472   cmd = "--batch";
00473   cmd += addUserId();
00474   cmd += " --sign-key 0x";
00475   cmd += keyID;
00476 
00477   status = 0;
00478   exitStatus = runGpg(cmd.data(), passphrase);
00479 
00480   if (exitStatus != 0)
00481     status = ERROR;
00482 
00483   return status;
00484 }
00485 
00486 
00487 QByteArray
00488 BaseG::getAsciiPublicKey(const KeyID& keyID)
00489 {
00490   int exitStatus = 0;
00491 
00492   if (keyID.isEmpty())
00493     return QByteArray();
00494 
00495   status = 0;
00496   exitStatus = runGpg("--batch --armor --export 0x" + keyID, 0, true);
00497 
00498   if(exitStatus != 0) {
00499     status = ERROR;
00500     return QByteArray();
00501   }
00502 
00503   return output;
00504 }
00505 
00506 
00507 Key*
00508 BaseG::parseKeyData( const QByteArray& output, int& offset, Key* key /* = 0 */ )
00509 // This function parses the data for a single key which is output by GnuPG
00510 // with the following command line arguments:
00511 //   --batch --list-public-keys --with-fingerprint --with-colons
00512 //   --fixed-list-mode [--no-expensive-trust-checks]
00513 // It expects the key data to start at offset and returns the start of
00514 // the next key's data in offset.
00515 // Subkeys are currently ignored.
00516 {
00517   int index = offset;
00518 
00519   if(    ( strncmp( output.data() + offset, "pub:", 4 ) != 0 )
00520       && ( strncmp( output.data() + offset, "sec:", 4 ) != 0 ) ) {
00521     return 0;
00522   }
00523 
00524   if( key == 0 )
00525     key = new Key();
00526   else
00527     key->clear();
00528 
00529   QByteArray keyID;
00530   bool firstKey = true;
00531 
00532   while( true )
00533   {
00534     int eol;
00535     // search the end of the current line
00536     if( ( eol = output.indexOf( '\n', index ) ) == -1 )
00537       break;
00538 
00539     bool bIsPublicKey = false;
00540     if( ( bIsPublicKey = !strncmp( output.data() + index, "pub:", 4 ) )
00541         || !strncmp( output.data() + index, "sec:", 4 ) )
00542     { // line contains primary key data
00543       // Example: pub:f:1024:17:63CB691DFAEBD5FC:860451781::379:-:::scESC:
00544 
00545       // abort parsing if we found the start of the next key
00546       if( !firstKey )
00547         break;
00548       firstKey = false;
00549 
00550       key->setSecret( !bIsPublicKey );
00551 
00552       Subkey *subkey = new Subkey( QByteArray(), !bIsPublicKey );
00553 
00554       int pos = index + 4; // begin of 2nd field
00555       int pos2 = output.indexOf( ':', pos );
00556       for( int field = 2; field <= 12; field++ )
00557       {
00558         switch( field )
00559         {
00560         case 2: // the calculated trust
00561           if( pos2 > pos )
00562           {
00563             switch( output[pos] )
00564             {
00565             case 'o': // unknown (this key is new to the system)
00566               break;
00567             case 'i': // the key is invalid, e.g. missing self-signature
00568               subkey->setInvalid( true );
00569               key->setInvalid( true );
00570               break;
00571             case 'd': // the key has been disabled
00572               subkey->setDisabled( true );
00573               key->setDisabled( true );
00574               break;
00575             case 'r': // the key has been revoked
00576               subkey->setRevoked( true );
00577               key->setRevoked( true );
00578               break;
00579             case 'e': // the key has expired
00580               subkey->setExpired( true );
00581               key->setExpired( true );
00582               break;
00583             case '-': // undefined (no path leads to the key)
00584             case 'q': // undefined (no trusted path leads to the key)
00585             case 'n': // don't trust this key at all
00586             case 'm': // the key is marginally trusted
00587             case 'f': // the key is fully trusted
00588             case 'u': // the key is ultimately trusted (secret key available)
00589               // These values are ignored since we determine the key trust
00590               // from the trust values of the user ids.
00591               break;
00592             default:
00593               kDebug( 5326 ) <<"Unknown trust value";
00594             }
00595           }
00596           break;
00597         case 3: // length of key in bits
00598           if( pos2 > pos )
00599             subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
00600           break;
00601         case 4: //  the key algorithm
00602           if( pos2 > pos )
00603             subkey->setKeyAlgorithm( output.mid( pos, pos2-pos ).toUInt() );
00604           break;
00605         case 5: // the long key id
00606           keyID = output.mid( pos, pos2-pos );
00607           subkey->setKeyID( keyID );
00608           break;
00609         case 6: // the creation date (in seconds since 1970-01-01 00:00:00)
00610           if( pos2 > pos )
00611             subkey->setCreationDate( QString(output.mid( pos, pos2-pos )).toLong() );
00612           break;
00613         case 7: // the expiration date (in seconds since 1970-01-01 00:00:00)
00614           if( pos2 > pos )
00615             subkey->setExpirationDate( QString(output.mid( pos, pos2-pos )).toLong() );
00616           else
00617             subkey->setExpirationDate( -1 ); // key expires never
00618           break;
00619         case 8: // local ID (ignored)
00620         case 9: // Ownertrust (ignored for now)
00621         case 10: // User-ID (always empty in --fixed-list-mode)
00622         case 11: // signature class (always empty except for key signatures)
00623           break;
00624         case 12: // key capabilities
00625           for( int i=pos; i<pos2; i++ )
00626             switch( output[i] )
00627             {
00628             case 'e':
00629               subkey->setCanEncrypt( true );
00630               break;
00631             case 's':
00632               subkey->setCanSign( true );
00633               break;
00634             case 'c':
00635               subkey->setCanCertify( true );
00636               break;
00637             case 'E':
00638               key->setCanEncrypt( true );
00639               break;
00640             case 'S':
00641               key->setCanSign( true );
00642               break;
00643             case 'C':
00644               key->setCanCertify( true );
00645               break;
00646             default:
00647               kDebug( 5326 ) <<"Unknown key capability";
00648             }
00649           break;
00650         }
00651         pos = pos2 + 1;
00652         pos2 = output.indexOf( ':', pos );
00653       }
00654       key->addSubkey( subkey );
00655     }
00656     else if( !strncmp( output.data() + index, "uid:", 4 ) )
00657     { // line contains a user id
00658       // Example: uid:f::::::::Philip R. Zimmermann <prz@pgp.com>:
00659 
00660       UserID *userID = new UserID( "" );
00661 
00662       int pos = index + 4; // begin of 2nd field
00663       int pos2 = output.indexOf( ':', pos );
00664       for( int field=2; field <= 10; field++ )
00665       {
00666         switch( field )
00667         {
00668         case 2: // the calculated trust
00669           if( pos2 > pos )
00670           {
00671             switch( output[pos] )
00672             {
00673             case 'i': // the user id is invalid, e.g. missing self-signature
00674               userID->setInvalid( true );
00675               break;
00676             case 'r': // the user id has been revoked
00677               userID->setRevoked( true );
00678               break;
00679             case '-': // undefined (no path leads to the key)
00680             case 'q': // undefined (no trusted path leads to the key)
00681               userID->setValidity( KPGP_VALIDITY_UNDEFINED );
00682               break;
00683             case 'n': // don't trust this key at all
00684               userID->setValidity( KPGP_VALIDITY_NEVER );
00685               break;
00686             case 'm': // the key is marginally trusted
00687               userID->setValidity( KPGP_VALIDITY_MARGINAL );
00688               break;
00689             case 'f': // the key is fully trusted
00690               userID->setValidity( KPGP_VALIDITY_FULL );
00691               break;
00692             case 'u': // the key is ultimately trusted (secret key available)
00693               userID->setValidity( KPGP_VALIDITY_ULTIMATE );
00694               break;
00695             default:
00696               kDebug( 5326 ) <<"Unknown trust value";
00697             }
00698           }
00699           break;
00700         case 3: // these fields are empty
00701         case 4:
00702         case 5:
00703         case 6:
00704         case 7:
00705         case 8:
00706         case 9:
00707           break;
00708         case 10: // User-ID
00709           QByteArray uid = output.mid( pos, pos2-pos );
00710           // replace "\xXX" with the corresponding character;
00711           // other escaped characters, i.e. \n, \r etc., are ignored
00712           // because they shouldn't appear in user IDs
00713           for ( int idx = 0 ; (idx = uid.indexOf( "\\x", idx ) != -1) ; ++idx ) {
00714             char str[2] = "x";
00715             str[0] = (char) QString( uid.mid( idx + 2, 2 ) ).toShort( 0, 16 );
00716             uid.replace( idx, 4, str );
00717           }
00718           QString uidString = QString::fromUtf8( uid.data() );
00719           // check whether uid was utf-8 encoded
00720           bool isUtf8 = true;
00721           for ( int i = 0; i + 1 < uidString.length(); ++i ) {
00722             if ( uidString[i].unicode() == 0xdbff &&
00723                  uidString[i+1].row() == 0xde ) {
00724               // we found a non-Unicode character (see QString::fromUtf8())
00725               isUtf8 = false;
00726               break;
00727             }
00728           }
00729           if( !isUtf8 ) {
00730             // The user id isn't utf-8 encoded. It was most likely
00731             // created with PGP which either used latin1 or koi8-r.
00732             kDebug( 5326 ) <<"User Id '" << uid
00733                           << "' doesn't seem to be utf-8 encoded.";
00734 
00735             // We determine the ratio between non-ASCII and ASCII chars.
00736             // A koi8-r user id should have lots of non-ASCII chars.
00737             int nonAsciiCount = 0, asciiCount = 0;
00738 
00739             // We only look at the first part of the user id (i. e. everything
00740             // before the email address resp. before a comment)
00741             for( signed char* ch = (signed char*)uid.data();
00742                  *ch && ( *ch != '(' ) && ( *ch != '<' );
00743                  ++ch ) {
00744               if( ( ( *ch >= 'A' ) && ( *ch <= 'Z' ) )
00745                   || ( ( *ch >= 'a' ) && ( *ch <= 'z' ) ) )
00746                 ++asciiCount;
00747               else if( *ch < 0 )
00748                 ++nonAsciiCount;
00749             }
00750             kDebug( 5326 ) <<"ascii-nonAscii ratio :" << asciiCount
00751                           << ":" << nonAsciiCount;
00752             if( nonAsciiCount > asciiCount ) {
00753               // assume koi8-r encoding
00754               kDebug( 5326 ) <<"Assume koi8-r encoding.";
00755               QTextCodec *codec = QTextCodec::codecForName("KOI8-R");
00756               uidString = codec->toUnicode( uid.data() );
00757               // check the case of the first two characters to find out
00758               // whether the user id is probably CP1251 encoded (for some
00759               // reason in CP1251 the lower case characters have smaller
00760               // codes than the upper case characters, so if the first char
00761               // of the koi8-r decoded user id is lower case and the second
00762               // char is upper case then it's likely that the user id is
00763               // CP1251 encoded)
00764               if( ( uidString.length() >= 2 )
00765                   && ( uidString[0].toLower() == uidString[0] )
00766                   && ( uidString[1].toUpper() == uidString[1] ) ) {
00767                 // koi8-r decoded user id has inverted case, so assume
00768                 // CP1251 encoding
00769                 kDebug( 5326 ) <<"No, it doesn't seem to be koi8-r."
00770                                  "Use CP 1251 instead.";
00771                 QTextCodec *codec = QTextCodec::codecForName("CP1251");
00772                 uidString = codec->toUnicode( uid.data() );
00773               }
00774             }
00775             else {
00776               // assume latin1 encoding
00777               kDebug( 5326 ) <<"Assume latin1 encoding.";
00778               uidString = QString::fromLatin1( uid.data() );
00779             }
00780           }
00781           userID->setText( uidString );
00782           break;
00783         }
00784         pos = pos2 + 1;
00785         pos2 = output.indexOf( ':', pos );
00786       }
00787 
00788       // user IDs are printed in UTF-8 by gpg (if one uses --with-colons)
00789       key->addUserID( userID );
00790     }
00791     else if( !strncmp( output.data() + index, "fpr:", 4 ) )
00792     { // line contains a fingerprint
00793       // Example: fpr:::::::::17AFBAAF21064E513F037E6E63CB691DFAEBD5FC:
00794 
00795       if (key == 0) // invalid key data
00796     break;
00797 
00798       // search the fingerprint (it's in the 10th field)
00799       int pos = index + 4;
00800       for( int i = 0; i < 8; i++ )
00801         pos = output.indexOf( ':', pos ) + 1;
00802       int pos2 = output.indexOf( ':', pos );
00803 
00804       key->setFingerprint( keyID, output.mid( pos, pos2-pos ) );
00805     }
00806     index = eol + 1;
00807   }
00808 
00809   //kDebug( 5326 ) <<"finished parsing key data";
00810 
00811   offset = index;
00812 
00813   return key;
00814 }
00815 
00816 
00817 KeyList
00818 BaseG::parseKeyList( const QByteArray& output, bool secretKeys )
00819 {
00820   KeyList keys;
00821   Key *key = 0;
00822   int offset;
00823 
00824   // search start of key data
00825   if(    !strncmp( output.data(), "pub:", 4 )
00826       || !strncmp( output.data(), "sec:", 4 ) )
00827     offset = 0;
00828   else {
00829     if( secretKeys )
00830       offset = output.indexOf( "\nsec:" );
00831     else
00832       offset = output.indexOf( "\npub:" );
00833     if( offset == -1 )
00834       return keys;
00835     else
00836       offset++;
00837   }
00838 
00839   do {
00840     key = parseKeyData( output, offset );
00841     if( key != 0 )
00842       keys.append( key );
00843   }
00844   while( key != 0 );
00845 
00846   //kDebug( 5326 ) <<"finished parsing keys";
00847 
00848   return keys;
00849 }
00850 
00851 
00852 } // namespace Kpgp

libkpgp

Skip menu "libkpgp"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  •   doc
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal