libkpgp

kpgpbaseG.cpp
1 /*
2  kpgpbaseG.cpp
3 
4  Copyright (C) 2001,2002 the KPGP authors
5  See file AUTHORS.kpgp for details
6 
7  This file is part of KPGP, the KDE PGP/GnuPG support library.
8 
9  KPGP is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software Foundation,
16  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 
23 #include "kpgpbase.h"
24 #include "kpgp.h"
25 
26 #include <tdelocale.h>
27 #include <kprocess.h>
28 #include <kdebug.h>
29 
30 #include <tqtextcodec.h>
31 
32 #include <string.h> /* strncmp */
33 
34 namespace Kpgp {
35 
36 BaseG::BaseG()
37  : Base()
38 {
39  // determine the version of gpg (the method is equivalent to gpgme's method)
40  runGpg( "--version", 0 );
41  int eol = output.find( '\n' );
42  if( eol > 0 ) {
43  int pos = output.findRev( ' ', eol - 1 );
44  if( pos != -1 ) {
45  mVersion = output.mid( pos + 1, eol - pos - 1 );
46  kdDebug(5100) << "found GnuPG " << mVersion << endl;
47  }
48  }
49 }
50 
51 
52 BaseG::~BaseG()
53 {
54 }
55 
56 
57 int
58 BaseG::encrypt( Block& block, const KeyIDList& recipients )
59 {
60  return encsign( block, recipients, 0 );
61 }
62 
63 
64 int
65 BaseG::clearsign( Block& block, const char *passphrase )
66 {
67  return encsign( block, KeyIDList(), passphrase );
68 }
69 
70 
71 int
72 BaseG::encsign( Block& block, const KeyIDList& recipients,
73  const char *passphrase )
74 {
75  TQCString cmd;
76  int exitStatus = 0;
77 
78  if(!recipients.isEmpty() && passphrase != 0)
79  cmd = "--batch --armor --sign --encrypt --textmode";
80  else if(!recipients.isEmpty())
81  cmd = "--batch --armor --encrypt --textmode";
82  else if(passphrase != 0)
83  cmd = "--batch --escape-from --clearsign";
84  else
85  {
86  kdDebug(5100) << "kpgpbase: Neither recipients nor passphrase specified." << endl;
87  return OK;
88  }
89 
90  if(passphrase != 0)
91  cmd += addUserId();
92 
93  if(!recipients.isEmpty())
94  {
95  cmd += " --set-filename stdin";
96 
97  TQCString pgpUser = Module::getKpgp()->user();
98  if(Module::getKpgp()->encryptToSelf() && !pgpUser.isEmpty()) {
99  cmd += " -r 0x";
100  cmd += pgpUser;
101  }
102 
103  for( KeyIDList::ConstIterator it = recipients.begin();
104  it != recipients.end(); ++it ) {
105  cmd += " -r 0x";
106  cmd += (*it);
107  }
108  }
109 
110  clear();
111  input = block.text();
112  exitStatus = runGpg(cmd.data(), passphrase);
113  if( !output.isEmpty() )
114  block.setProcessedText( output );
115  block.setError( error );
116 
117  if( exitStatus != 0 )
118  {
119  // this error message is later hopefully overwritten
120  errMsg = i18n( "Unknown error." );
121  status = ERROR;
122  }
123 
124 #if 0
125  // #### FIXME: As we check the keys ourselves the following problems
126  // shouldn't occur. Therefore I don't handle them for now.
127  // IK 01/2002
128  if(!recipients.isEmpty())
129  {
130  int index = 0;
131  bool bad = FALSE;
132  unsigned int num = 0;
133  TQCString badkeys = "";
134  // Examples:
135  // gpg: 0x12345678: skipped: public key not found
136  // gpg: 0x12345678: skipped: public key is disabled
137  // gpg: 0x12345678: skipped: unusable public key
138  // (expired or revoked key)
139  // gpg: 23456789: no info to calculate a trust probability
140  // (untrusted key, 23456789 is the key Id of the encryption sub key)
141  while((index = error.find("skipped: ",index)) != -1)
142  {
143  bad = TRUE;
144  index = error.find('\'',index);
145  int index2 = error.find('\'',index+1);
146  badkeys += error.mid(index, index2-index+1) + ", ";
147  num++;
148  }
149  if(bad)
150  {
151  badkeys.stripWhiteSpace();
152  if(num == recipients.count())
153  errMsg = i18n("Could not find public keys matching the userid(s)\n"
154  "%1;\n"
155  "the message is not encrypted.")
156  .arg( badkeys.data() );
157  else
158  errMsg = i18n("Could not find public keys matching the userid(s)\n"
159  "%1;\n"
160  "these persons will not be able to read the message.")
161  .arg( badkeys.data() );
162  status |= MISSINGKEY;
163  status |= ERROR;
164  }
165  }
166 #endif
167  if( passphrase != 0 )
168  {
169  // Example 1 (bad passphrase, clearsign only):
170  // gpg: skipped `0x12345678': bad passphrase
171  // gpg: [stdin]: clearsign failed: bad passphrase
172  // Example 2 (bad passphrase, sign & encrypt):
173  // gpg: skipped `0x12345678': bad passphrase
174  // gpg: [stdin]: sign+encrypt failed: bad passphrase
175  // Example 3 (unusable secret key, clearsign only):
176  // gpg: skipped `0x12345678': unusable secret key
177  // gpg: [stdin]: clearsign failed: unusable secret key
178  // Example 4 (unusable secret key, sign & encrypt):
179  // gpg: skipped `0xAC0EB35D': unusable secret key
180  // gpg: [stdin]: sign+encrypt failed: unusable secret key
181  if( error.find("bad passphrase") != -1 )
182  {
183  errMsg = i18n("Signing failed because the passphrase is wrong.");
184  status |= BADPHRASE;
185  status |= ERR_SIGNING;
186  status |= ERROR;
187  }
188  else if( error.find("unusable secret key") != -1 )
189  {
190  errMsg = i18n("Signing failed because your secret key is unusable.");
191  status |= ERR_SIGNING;
192  status |= ERROR;
193  }
194  else if( !( status & ERROR ) )
195  {
196  //kdDebug(5100) << "Base: Good Passphrase!" << endl;
197  status |= SIGNED;
198  }
199  }
200 
201  //kdDebug(5100) << "status = " << status << endl;
202  block.setStatus( status );
203  return status;
204 }
205 
206 
207 int
208 BaseG::decrypt( Block& block, const char *passphrase )
209 {
210  int index, index2;
211  int exitStatus = 0;
212 
213  clear();
214  input = block.text();
215  exitStatus = runGpg("--batch --decrypt", passphrase);
216  if( !output.isEmpty() && ( error.find( "gpg: quoted printable" ) == -1 ) )
217  block.setProcessedText( output );
218  block.setError( error );
219 
220  if(exitStatus == -1) {
221  errMsg = i18n("Error running gpg");
222  status = RUN_ERR;
223  block.setStatus( status );
224  return status;
225  }
226 
227  // Example 1 (good passphrase, decryption successful):
228  // gpg: encrypted with 2048-bit ELG-E key, ID 12345678, created 2000-11-11
229  // "Foo Bar <foo@bar.xyz>"
230  //
231  // Example 2 (bad passphrase):
232  // gpg: encrypted with 1024-bit RSA key, ID 12345678, created 1991-01-01
233  // "Foo Bar <foo@bar.xyz>"
234  // gpg: public key decryption failed: bad passphrase
235  // gpg: decryption failed: secret key not available
236  //
237  // Example 3 (no secret key available):
238  // gpg: encrypted with RSA key, ID 12345678
239  // gpg: decryption failed: secret key not available
240  //
241  // Example 4 (good passphrase for second key, decryption successful):
242  // gpg: encrypted with 2048-bit ELG-E key, ID 12345678, created 2000-01-01
243  // "Foo Bar (work) <foo@bar.xyz>"
244  // gpg: public key decryption failed: bad passphrase
245  // gpg: encrypted with 2048-bit ELG-E key, ID 23456789, created 2000-02-02
246  // "Foo Bar (home) <foo@bar.xyz>"
247  if( error.find( "gpg: encrypted with" ) != -1 )
248  {
249  //kdDebug(5100) << "kpgpbase: message is encrypted" << endl;
250  status |= ENCRYPTED;
251  if( error.find( "\ngpg: decryption failed" ) != -1 )
252  {
253  if( ( index = error.find( "bad passphrase" ) ) != -1 )
254  {
255  if( passphrase != 0 )
256  {
257  errMsg = i18n( "Bad passphrase; could not decrypt." );
258  kdDebug(5100) << "Base: passphrase is bad" << endl;
259  status |= BADPHRASE;
260  status |= ERROR;
261  }
262  else
263  {
264  // Search backwards the user ID of the needed key
265  index2 = error.findRev('"', index) - 1;
266  index = error.findRev(" \"", index2) + 7;
267  // The conversion from UTF8 is necessary because gpg stores and
268  // prints user IDs in UTF8
269  block.setRequiredUserId( TQString::fromUtf8( error.mid( index, index2 - index + 1 ) ) );
270  kdDebug(5100) << "Base: key needed is \"" << block.requiredUserId() << "\"!" << endl;
271  }
272  }
273  else if( error.find( "secret key not available" ) != -1 )
274  {
275  // no secret key fitting this message
276  status |= NO_SEC_KEY;
277  status |= ERROR;
278  errMsg = i18n("You do not have the secret key needed to decrypt this message.");
279  kdDebug(5100) << "Base: no secret key for this message" << endl;
280  }
281  }
282  // check for persons
283 #if 0
284  // ##### FIXME: This information is anyway currently not used
285  // I'll change it to always determine the recipients.
286  index = error.find("can only be read by:");
287  if(index != -1)
288  {
289  index = error.find('\n',index);
290  int end = error.find("\n\n",index);
291 
292  mRecipients.clear();
293  while( (index2 = error.find('\n',index+1)) <= end )
294  {
295  TQCString item = error.mid(index+1,index2-index-1);
296  item.stripWhiteSpace();
297  mRecipients.append(item);
298  index = index2;
299  }
300  }
301 #endif
302  }
303 
304  // Example 1 (unknown signature key):
305  // gpg: Signature made Wed 02 Jan 2002 11:26:33 AM CET using DSA key ID 2E250C64
306  // gpg: Can't check signature: public key not found
307  if((index = error.find("Signature made")) != -1)
308  {
309  //kdDebug(5100) << "Base: message is signed" << endl;
310  status |= SIGNED;
311  // get signature date and signature key ID
312  // Example: Signature made Sun 06 May 2001 03:49:27 PM CEST using DSA key ID 12345678
313  index2 = error.find("using", index+15);
314  block.setSignatureDate( error.mid(index+15, index2-(index+15)-1) );
315  kdDebug(5100) << "Message was signed on '" << block.signatureDate() << "'\n";
316  index2 = error.find("key ID ", index2) + 7;
317  block.setSignatureKeyId( error.mid(index2,8) );
318  kdDebug(5100) << "Message was signed with key '" << block.signatureKeyId() << "'\n";
319  // move index to start of next line
320  index = error.find('\n', index2)+1;
321 
322  if ((error.find("Key matching expected", index) != -1)
323  || (error.find("Can't check signature", index) != -1))
324  {
325  status |= UNKNOWN_SIG;
326  status |= GOODSIG;
327  block.setSignatureUserId( TQString() );
328  }
329  else if( error.find("Good signature", index) != -1 )
330  {
331  status |= GOODSIG;
332  // get the primary user ID of the signer
333  index = error.find('"',index);
334  index2 = error.find('\n',index+1);
335  index2 = error.findRev('"', index2-1);
336  block.setSignatureUserId( error.mid( index+1, index2-index-1 ) );
337  }
338  else if( error.find("BAD signature", index) != -1 )
339  {
340  //kdDebug(5100) << "BAD signature" << endl;
341  status |= ERROR;
342  // get the primary user ID of the signer
343  index = error.find('"',index);
344  index2 = error.find('\n',index+1);
345  index2 = error.findRev('"', index2-1);
346  block.setSignatureUserId( error.mid( index+1, index2-index-1 ) );
347  }
348  else if( error.find("Can't find the right public key", index) != -1 )
349  {
350  // #### fix this hack
351  // I think this can't happen anymore because if the pubring is missing
352  // the current GnuPG creates a new empty one.
353  status |= UNKNOWN_SIG;
354  status |= GOODSIG; // this is a hack...
355  block.setSignatureUserId( i18n("??? (file ~/.gnupg/pubring.gpg not found)") );
356  }
357  else
358  {
359  status |= ERROR;
360  block.setSignatureUserId( TQString() );
361  }
362  }
363  //kdDebug(5100) << "status = " << status << endl;
364  block.setStatus( status );
365  return status;
366 }
367 
368 
369 Key*
370 BaseG::readPublicKey( const KeyID& keyID,
371  const bool readTrust /* = false */,
372  Key* key /* = 0 */ )
373 {
374  int exitStatus = 0;
375 
376  status = 0;
377  if( readTrust )
378  exitStatus = runGpg( "--batch --list-public-keys --with-fingerprint --with-colons --fixed-list-mode 0x" + keyID, 0, true );
379  else
380  exitStatus = runGpg( "--batch --list-public-keys --with-fingerprint --with-colons --fixed-list-mode --no-expensive-trust-checks 0x" + keyID, 0, true );
381 
382  if(exitStatus != 0) {
383  status = ERROR;
384  return 0;
385  }
386 
387  int offset;
388  // search start of key data
389  if( !strncmp( output.data(), "pub:", 4 ) )
390  offset = 0;
391  else {
392  offset = output.find( "\npub:" );
393  if( offset == -1 )
394  return 0;
395  else
396  offset++;
397  }
398 
399  key = parseKeyData( output, offset, key );
400 
401  return key;
402 }
403 
404 
405 KeyList
406 BaseG::publicKeys( const TQStringList & patterns )
407 {
408  int exitStatus = 0;
409 
410  // the option --with-colons should be used for interprocess communication
411  // with gpg (according to Werner Koch)
412  TQCString cmd = "--batch --list-public-keys --with-fingerprint --with-colons "
413  "--fixed-list-mode --no-expensive-trust-checks";
414  for ( TQStringList::ConstIterator it = patterns.begin();
415  it != patterns.end(); ++it ) {
416  cmd += " ";
417  cmd += TDEProcess::quote( *it ).local8Bit();
418  }
419  status = 0;
420  exitStatus = runGpg( cmd, 0, true );
421 
422  if(exitStatus != 0) {
423  status = ERROR;
424  return KeyList();
425  }
426 
427  // now we need to parse the output for public keys
428  KeyList publicKeys = parseKeyList(output, false);
429 
430  // sort the list of public keys
431  publicKeys.sort();
432 
433  return publicKeys;
434 }
435 
436 
437 KeyList
438 BaseG::secretKeys( const TQStringList & patterns )
439 {
440  int exitStatus = 0;
441 
442  // the option --with-colons should be used for interprocess communication
443  // with gpg (according to Werner Koch)
444  TQCString cmd = "--batch --list-secret-keys --with-fingerprint --with-colons "
445  "--fixed-list-mode";
446  for ( TQStringList::ConstIterator it = patterns.begin();
447  it != patterns.end(); ++it ) {
448  cmd += " ";
449  cmd += TDEProcess::quote( *it ).local8Bit();
450  }
451  status = 0;
452  exitStatus = runGpg( cmd, 0, true );
453 
454  if(exitStatus != 0) {
455  status = ERROR;
456  return KeyList();
457  }
458 
459  // now we need to parse the output for secret keys
460  KeyList secretKeys = parseKeyList(output, true);
461 
462  // sort the list of secret keys
463  secretKeys.sort();
464 
465  return secretKeys;
466 }
467 
468 
469 int
470 BaseG::signKey(const KeyID& keyID, const char *passphrase)
471 {
472  TQCString cmd;
473  int exitStatus = 0;
474 
475  cmd = "--batch";
476  cmd += addUserId();
477  cmd += " --sign-key 0x";
478  cmd += keyID;
479 
480  status = 0;
481  exitStatus = runGpg(cmd.data(), passphrase);
482 
483  if (exitStatus != 0)
484  status = ERROR;
485 
486  return status;
487 }
488 
489 
490 TQCString
491 BaseG::getAsciiPublicKey(const KeyID& keyID)
492 {
493  int exitStatus = 0;
494 
495  if (keyID.isEmpty())
496  return TQCString();
497 
498  status = 0;
499  exitStatus = runGpg("--batch --armor --export 0x" + keyID, 0, true);
500 
501  if(exitStatus != 0) {
502  status = ERROR;
503  return TQCString();
504  }
505 
506  return output;
507 }
508 
509 
510 Key*
511 BaseG::parseKeyData( const TQCString& output, int& offset, Key* key /* = 0 */ )
512 // This function parses the data for a single key which is output by GnuPG
513 // with the following command line arguments:
514 // --batch --list-public-keys --with-fingerprint --with-colons
515 // --fixed-list-mode [--no-expensive-trust-checks]
516 // It expects the key data to start at offset and returns the start of
517 // the next key's data in offset.
518 // Subkeys are currently ignored.
519 {
520  int index = offset;
521 
522  if( ( strncmp( output.data() + offset, "pub:", 4 ) != 0 )
523  && ( strncmp( output.data() + offset, "sec:", 4 ) != 0 ) ) {
524  return 0;
525  }
526 
527  if( key == 0 )
528  key = new Key();
529  else
530  key->clear();
531 
532  TQCString keyID;
533  bool firstKey = true;
534 
535  while( true )
536  {
537  int eol;
538  // search the end of the current line
539  if( ( eol = output.find( '\n', index ) ) == -1 )
540  break;
541 
542  bool bIsPublicKey = false;
543  if( ( bIsPublicKey = !strncmp( output.data() + index, "pub:", 4 ) )
544  || !strncmp( output.data() + index, "sec:", 4 ) )
545  { // line contains primary key data
546  // Example: pub:f:1024:17:63CB691DFAEBD5FC:860451781::379:-:::scESC:
547 
548  // abort parsing if we found the start of the next key
549  if( !firstKey )
550  break;
551  firstKey = false;
552 
553  key->setSecret( !bIsPublicKey );
554 
555  Subkey *subkey = new Subkey( TQCString(), !bIsPublicKey );
556 
557  int pos = index + 4; // begin of 2nd field
558  int pos2 = output.find( ':', pos );
559  for( int field = 2; field <= 12; field++ )
560  {
561  switch( field )
562  {
563  case 2: // the calculated trust
564  if( pos2 > pos )
565  {
566  switch( output[pos] )
567  {
568  case 'o': // unknown (this key is new to the system)
569  break;
570  case 'i': // the key is invalid, e.g. missing self-signature
571  subkey->setInvalid( true );
572  key->setInvalid( true );
573  break;
574  case 'd': // the key has been disabled
575  subkey->setDisabled( true );
576  key->setDisabled( true );
577  break;
578  case 'r': // the key has been revoked
579  subkey->setRevoked( true );
580  key->setRevoked( true );
581  break;
582  case 'e': // the key has expired
583  subkey->setExpired( true );
584  key->setExpired( true );
585  break;
586  case '-': // undefined (no path leads to the key)
587  case 'q': // undefined (no trusted path leads to the key)
588  case 'n': // don't trust this key at all
589  case 'm': // the key is marginally trusted
590  case 'f': // the key is fully trusted
591  case 'u': // the key is ultimately trusted (secret key available)
592  // These values are ignored since we determine the key trust
593  // from the trust values of the user ids.
594  break;
595  default:
596  kdDebug(5100) << "Unknown trust value\n";
597  }
598  }
599  break;
600  case 3: // length of key in bits
601  if( pos2 > pos )
602  subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
603  break;
604  case 4: // the key algorithm
605  if( pos2 > pos )
606  subkey->setKeyAlgorithm( output.mid( pos, pos2-pos ).toUInt() );
607  break;
608  case 5: // the long key id
609  keyID = output.mid( pos, pos2-pos );
610  subkey->setKeyID( keyID );
611  break;
612  case 6: // the creation date (in seconds since 1970-01-01 00:00:00)
613  if( pos2 > pos )
614  subkey->setCreationDate( output.mid( pos, pos2-pos ).toLong() );
615  break;
616  case 7: // the expiration date (in seconds since 1970-01-01 00:00:00)
617  if( pos2 > pos )
618  subkey->setExpirationDate( output.mid( pos, pos2-pos ).toLong() );
619  else
620  subkey->setExpirationDate( -1 ); // key expires never
621  break;
622  case 8: // local ID (ignored)
623  case 9: // Ownertrust (ignored for now)
624  case 10: // User-ID (always empty in --fixed-list-mode)
625  case 11: // signature class (always empty except for key signatures)
626  break;
627  case 12: // key capabilities
628  for( int i=pos; i<pos2; i++ )
629  switch( output[i] )
630  {
631  case 'e':
632  subkey->setCanEncrypt( true );
633  break;
634  case 's':
635  subkey->setCanSign( true );
636  break;
637  case 'c':
638  subkey->setCanCertify( true );
639  break;
640  case 'E':
641  key->setCanEncrypt( true );
642  break;
643  case 'S':
644  key->setCanSign( true );
645  break;
646  case 'C':
647  key->setCanCertify( true );
648  break;
649  default:
650  kdDebug(5100) << "Unknown key capability\n";
651  }
652  break;
653  }
654  pos = pos2 + 1;
655  pos2 = output.find( ':', pos );
656  }
657  key->addSubkey( subkey );
658  }
659  else if( !strncmp( output.data() + index, "uid:", 4 ) )
660  { // line contains a user id
661  // Example: uid:f::::::::Philip R. Zimmermann <prz@pgp.com>:
662 
663  UserID *userID = new UserID( "" );
664 
665  int pos = index + 4; // begin of 2nd field
666  int pos2 = output.find( ':', pos );
667  for( int field=2; field <= 10; field++ )
668  {
669  switch( field )
670  {
671  case 2: // the calculated trust
672  if( pos2 > pos )
673  {
674  switch( output[pos] )
675  {
676  case 'i': // the user id is invalid, e.g. missing self-signature
677  userID->setInvalid( true );
678  break;
679  case 'r': // the user id has been revoked
680  userID->setRevoked( true );
681  break;
682  case '-': // undefined (no path leads to the key)
683  case 'q': // undefined (no trusted path leads to the key)
684  userID->setValidity( KPGP_VALIDITY_UNDEFINED );
685  break;
686  case 'n': // don't trust this key at all
687  userID->setValidity( KPGP_VALIDITY_NEVER );
688  break;
689  case 'm': // the key is marginally trusted
690  userID->setValidity( KPGP_VALIDITY_MARGINAL );
691  break;
692  case 'f': // the key is fully trusted
693  userID->setValidity( KPGP_VALIDITY_FULL );
694  break;
695  case 'u': // the key is ultimately trusted (secret key available)
696  userID->setValidity( KPGP_VALIDITY_ULTIMATE );
697  break;
698  default:
699  kdDebug(5100) << "Unknown trust value\n";
700  }
701  }
702  break;
703  case 3: // these fields are empty
704  case 4:
705  case 5:
706  case 6:
707  case 7:
708  case 8:
709  case 9:
710  break;
711  case 10: // User-ID
712  TQCString uid = output.mid( pos, pos2-pos );
713  // replace "\xXX" with the corresponding character;
714  // other escaped characters, i.e. \n, \r etc., are ignored
715  // because they shouldn't appear in user IDs
716  for ( int idx = 0 ; (idx = uid.find( "\\x", idx )) >= 0 ; ++idx ) {
717  char str[2] = "x";
718  str[0] = (char) TQString( uid.mid( idx + 2, 2 ) ).toShort( 0, 16 );
719  uid.replace( idx, 4, str );
720  }
721  TQString uidString = TQString::fromUtf8( uid.data() );
722  // check whether uid was utf-8 encoded
723  bool isUtf8 = true;
724  for ( unsigned int i = 0; i + 1 < uidString.length(); ++i ) {
725  if ( uidString[i].unicode() == 0xdbff &&
726  uidString[i+1].row() == 0xde ) {
727  // we found a non-Unicode character (see TQString::fromUtf8())
728  isUtf8 = false;
729  break;
730  }
731  }
732  if( !isUtf8 ) {
733  // The user id isn't utf-8 encoded. It was most likely
734  // created with PGP which either used latin1 or koi8-r.
735  kdDebug(5100) << "User Id '" << uid
736  << "' doesn't seem to be utf-8 encoded." << endl;
737 
738  // We determine the ratio between non-ASCII and ASCII chars.
739  // A koi8-r user id should have lots of non-ASCII chars.
740  int nonAsciiCount = 0, asciiCount = 0;
741 
742  // We only look at the first part of the user id (i. e. everything
743  // before the email address resp. before a comment)
744  for( signed char* ch = (signed char*)uid.data();
745  *ch && ( *ch != '(' ) && ( *ch != '<' );
746  ++ch ) {
747  if( ( ( *ch >= 'A' ) && ( *ch <= 'Z' ) )
748  || ( ( *ch >= 'a' ) && ( *ch <= 'z' ) ) )
749  ++asciiCount;
750  else if( *ch < 0 )
751  ++nonAsciiCount;
752  }
753  kdDebug(5100) << "ascii-nonAscii ratio : " << asciiCount
754  << ":" << nonAsciiCount << endl;
755  if( nonAsciiCount > asciiCount ) {
756  // assume koi8-r encoding
757  kdDebug(5100) << "Assume koi8-r encoding." << endl;
758  TQTextCodec *codec = TQTextCodec::codecForName("KOI8-R");
759  uidString = codec->toUnicode( uid.data() );
760  // check the case of the first two characters to find out
761  // whether the user id is probably CP1251 encoded (for some
762  // reason in CP1251 the lower case characters have smaller
763  // codes than the upper case characters, so if the first char
764  // of the koi8-r decoded user id is lower case and the second
765  // char is upper case then it's likely that the user id is
766  // CP1251 encoded)
767  if( ( uidString.length() >= 2 )
768  && ( uidString[0].lower() == uidString[0] )
769  && ( uidString[1].upper() == uidString[1] ) ) {
770  // koi8-r decoded user id has inverted case, so assume
771  // CP1251 encoding
772  kdDebug(5100) << "No, it doesn't seem to be koi8-r. "
773  "Use CP 1251 instead." << endl;
774  TQTextCodec *codec = TQTextCodec::codecForName("CP1251");
775  uidString = codec->toUnicode( uid.data() );
776  }
777  }
778  else {
779  // assume latin1 encoding
780  kdDebug(5100) << "Assume latin1 encoding." << endl;
781  uidString = TQString::fromLatin1( uid.data() );
782  }
783  }
784  userID->setText( uidString );
785  break;
786  }
787  pos = pos2 + 1;
788  pos2 = output.find( ':', pos );
789  }
790 
791  // user IDs are printed in UTF-8 by gpg (if one uses --with-colons)
792  key->addUserID( userID );
793  }
794  else if( !strncmp( output.data() + index, "fpr:", 4 ) )
795  { // line contains a fingerprint
796  // Example: fpr:::::::::17AFBAAF21064E513F037E6E63CB691DFAEBD5FC:
797 
798  if (key == 0) // invalid key data
799  break;
800 
801  // search the fingerprint (it's in the 10th field)
802  int pos = index + 4;
803  for( int i = 0; i < 8; i++ )
804  pos = output.find( ':', pos ) + 1;
805  int pos2 = output.find( ':', pos );
806 
807  key->setFingerprint( keyID, output.mid( pos, pos2-pos ) );
808  }
809  index = eol + 1;
810  }
811 
812  //kdDebug(5100) << "finished parsing key data\n";
813 
814  offset = index;
815 
816  return key;
817 }
818 
819 
820 KeyList
821 BaseG::parseKeyList( const TQCString& output, bool secretKeys )
822 {
823  KeyList keys;
824  Key *key = 0;
825  int offset;
826 
827  // search start of key data
828  if( !strncmp( output.data(), "pub:", 4 )
829  || !strncmp( output.data(), "sec:", 4 ) )
830  offset = 0;
831  else {
832  if( secretKeys )
833  offset = output.find( "\nsec:" );
834  else
835  offset = output.find( "\npub:" );
836  if( offset == -1 )
837  return keys;
838  else
839  offset++;
840  }
841 
842  do {
843  key = parseKeyData( output, offset );
844  if( key != 0 )
845  keys.append( key );
846  }
847  while( key != 0 );
848 
849  //kdDebug(5100) << "finished parsing keys" << endl;
850 
851  return keys;
852 }
853 
854 
855 } // namespace Kpgp
Definition: kpgp.cpp:48