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