libkpgp

kpgpbase6.cpp
1 /*
2  kpgpbase6.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 
25 #include <string.h> /* strncmp */
26 #include <assert.h>
27 
28 #include <tqdatetime.h>
29 
30 #include <tdelocale.h>
31 #include <kdebug.h>
32 
33 #define PGP6 "pgp"
34 
35 namespace Kpgp {
36 
37 Base6::Base6()
38  : Base2()
39 {
40 }
41 
42 
43 Base6::~Base6()
44 {
45 }
46 
47 
48 int
49 Base6::decrypt( Block& block, const TQString &passphrase )
50 {
51  int index, index2;
52  int exitStatus = 0;
53 
54  clear();
55  input = block.text();
56  exitStatus = run( PGP6 " +batchmode +language=C -f", passphrase);
57  if( !output.isEmpty() )
58  block.setProcessedText( output );
59  block.setError( error );
60 
61  if(exitStatus == -1) {
62  errMsg = i18n("error running PGP");
63  status = RUN_ERR;
64  block.setStatus( status );
65  return status;
66  }
67 
68  // encrypted message
69  if( error.find("File is encrypted.") != -1)
70  {
71  //kdDebug(5100) << "kpgpbase: message is encrypted" << endl;
72  status |= ENCRYPTED;
73  if((index = error.find("Key for user ID")) != -1)
74  {
75  // Find out the key for which the phrase is needed
76  index = error.find(':', index) + 2;
77  index2 = error.find('\n', index);
78  block.setRequiredUserId( error.mid(index, index2 - index) );
79  //kdDebug(5100) << "Base: key needed is \"" << block.requiredUserId() << "\"!\n";
80 
81  // Test output length to find out, if the passphrase is
82  // bad. If someone knows a better way, please fix this.
85  if (!passphrase || !output.length())
86  {
87  errMsg = i18n("Bad passphrase; could not decrypt.");
88  //kdDebug(5100) << "Base: passphrase is bad" << endl;
89  status |= BADPHRASE;
90  status |= ERROR;
91  }
92  }
93  else if( error.find("You do not have the secret key needed to decrypt this file.") != -1)
94  {
95  errMsg = i18n("You do not have the secret key for this message.");
96  //kdDebug(5100) << "Base: no secret key for this message" << endl;
97  status |= NO_SEC_KEY;
98  status |= ERROR;
99  }
100  }
101 
102  // signed message
103 
104  // Examples (made with PGP 6.5.8)
105  /* Example no. 1 (signed with unknown key):
106  * File is signed. signature not checked.
107  * Signature made 2001/11/25 11:55 GMT
108  * key does not meet validity threshold.
109  *
110  * WARNING: Because this public key is not certified with a trusted
111  * signature, it is not known with high confidence that this public key
112  * actually belongs to: "(KeyID: 0x475027BD)".
113  */
114  /* Example no. 2 (signed with untrusted key):
115  * File is signed. Good signature from user "Joe User <joe@foo.bar>".
116  * Signature made 2001/12/05 13:09 GMT
117  *
118  * WARNING: Because this public key is not certified with a trusted
119  * signature, it is not known with high confidence that this public key
120  * actually belongs to: "Joe User <joe@foo.bar>".
121  */
122  /* Example no. 3 (signed with trusted key):
123  * File is signed. Good signature from user "Joe User <joe@foo.bar>".
124  * Signature made 2001/12/05 13:09 GMT
125  */
126  if(((index = error.find("File is signed.")) != -1)
127  || (error.find("Good signature") != -1 ))
128  {
129  //kdDebug(5100) << "Base: message is signed" << endl;
130  status |= SIGNED;
131  // determine the signature date
132  if( ( index2 = error.find( "Signature made", index ) ) != -1 )
133  {
134  index2 += 15;
135  int eol = error.find( '\n', index2 );
136  block.setSignatureDate( error.mid( index2, eol-index2 ) );
137  kdDebug(5100) << "Message was signed on '" << block.signatureDate() << "'\n";
138  }
139  else
140  block.setSignatureDate( TQCString() );
141  // determine signature status and signature key
142  if( error.find("signature not checked") != -1)
143  {
144  index = error.find("KeyID:",index);
145  block.setSignatureKeyId( error.mid(index+9,8) );
146  block.setSignatureUserId( TQString() );
147  status |= UNKNOWN_SIG;
148  status |= GOODSIG;
149  }
150  else if((index = error.find("Good signature")) != -1 )
151  {
152  status |= GOODSIG;
153  // get signer
154  index = error.find('"',index)+1;
155  index2 = error.find('"', index);
156  block.setSignatureUserId( error.mid(index, index2-index) );
157 
158  // get key ID of signer
159  index = error.find("KeyID:",index2);
160  if (index == -1)
161  block.setSignatureKeyId( TQCString() );
162  else
163  block.setSignatureKeyId( error.mid(index+9,8) );
164  }
165  else if( error.find("Can't find the right public key") != -1 )
166  {
167  // #### fix this hack
168  // #### This doesn't happen with PGP 6.5.8 because it seems to
169  // #### automatically create an empty pubring if it doesn't exist.
170  status |= UNKNOWN_SIG;
171  status |= GOODSIG; // this is a hack...
172  block.setSignatureUserId( i18n("??? (file ~/.pgp/pubring.pkr not found)") );
173  block.setSignatureKeyId( "???" );
174  }
175  else
176  {
177  status |= ERROR;
178  block.setSignatureUserId( TQString() );
179  block.setSignatureKeyId( TQCString() );
180  }
181  }
182  //kdDebug(5100) << "status = " << status << endl;
183  block.setStatus( status );
184  return status;
185 }
186 
187 
188 Key*
189 Base6::readPublicKey( const KeyID& keyID,
190  const bool readTrust /* = false */,
191  Key* key /* = 0 */ )
192 {
193  int exitStatus = 0;
194 
195  status = 0;
196  exitStatus = run( PGP6 " +batchmode -compatible +verbose=0 +language=C -kvvc "
197  "0x" + keyID, 0, true );
198 
199  if(exitStatus != 0) {
200  status = ERROR;
201  return 0;
202  }
203 
204  key = parseSingleKey( output, key );
205 
206  if( key == 0 )
207  {
208  return 0;
209  }
210 
211  if( readTrust )
212  {
213  exitStatus = run( PGP6 " +batchmode -compatible +verbose=0 +language=C -kc "
214  "0x" + keyID, 0, true );
215 
216  if(exitStatus != 0) {
217  status = ERROR;
218  return 0;
219  }
220 
221  parseTrustDataForKey( key, output );
222  }
223 
224  return key;
225 }
226 
227 
228 KeyList
229 Base6::publicKeys( const TQStringList & patterns )
230 {
231  return doGetPublicKeys( PGP6 " +batchmode -compatible +verbose=0 "
232  "+language=C -kvvc", patterns );
233 }
234 
235 
236 /*
237 TQStrList
238 Base6::pubKeys()
239 {
240  int index, index2;
241  int exitStatus = 0;
242  int compatibleMode = 1;
243 
244  status = 0;
245  exitStatus = run("pgp +batchmode +language=C -kv -f");
246 
247  if(exitStatus != 0) {
248  status = ERROR;
249  return 0;
250  }
251 
252  //truncate trailing "\n"
253  if (error.length() > 1) error.truncate(error.length()-1);
254 
255  TQStrList publicKeys;
256  index = error.find("bits/keyID",1); // skip first to "\n"
257  if (index ==-1)
258  {
259  index = error.find("Type bits",1); // skip first to "\n"
260  if (index == -1)
261  return 0;
262  else
263  compatibleMode = 0;
264  }
265 
266  while( (index = error.find("\n",index)) != -1)
267  {
268  //parse line
269  TQCString line;
270  if( (index2 = error.find("\n",index+1)) != -1)
271  // skip last line
272  {
273  int index3;
274  if (compatibleMode)
275  {
276  int index_pub = error.find("pub ",index);
277  int index_sec = error.find("sec ",index);
278  if (index_pub < 0)
279  index3 = index_sec;
280  else if (index_sec < 0)
281  index3 = index_pub;
282  else
283  index3 = (index_pub < index_sec ? index_pub : index_sec);
284  }
285  else
286  {
287  int index_rsa = error.find("RSA ",index);
288  int index_dss = error.find("DSS ",index);
289  if (index_rsa < 0)
290  index3 = index_dss;
291  else if (index_dss < 0)
292  index3 = index_rsa;
293  else
294  index3 = (index_rsa < index_dss ? index_rsa : index_dss);
295  }
296 
297  if( (index3 >index2) || (index3 == -1) )
298  {
299  // second address for the same key
300  line = error.mid(index+1,index2-index-1);
301  line = line.stripWhiteSpace();
302  } else {
303  // line with new key
304  int index4 = error.find(TQRegExp("/\\d{2}/\\d{2} "), index);
305  line = error.mid(index4+7,index2-index4-7);
306  }
307  //kdDebug(5100) << "Base: found key for " << (const char *)line << endl;
308 
309  // don't add PGP's comments to the key list
310  if (strncmp(line.data(),"*** KEY EXPIRED ***",19) &&
311  line.find(TQRegExp("^expires \\d{4}/\\d{2}/\\d{2}")) < 0 &&
312  strncmp(line.data(),"*** DEFAULT SIGNING KEY ***",27)) {
313  publicKeys.append(line);
314  }
315  }
316  else
317  break;
318  index = index2;
319  }
320 
321  // Also look for pgp key groups
322  exitStatus = run("pgp +batchmode +language=C -gv -f");
323 
324  if(exitStatus != 0) {
325  status = ERROR;
326  return 0;
327  }
328 
329  index = 0;
330  while ( (index = error.find("\n >", index)) != -1 ) {
331  TQCString line;
332  index += 4;
333  index2 = error.find(" \"", index);
334  line = error.mid(index, index2-index+1).stripWhiteSpace();
335 
336  //kdDebug(5100) << "Base6: found key group for " << line << endl;
337  publicKeys.append(line);
338  }
339 
340  return publicKeys;
341 }
342 */
343 
344 
345 KeyList
346 Base6::secretKeys( const TQStringList & patterns )
347 {
348  return publicKeys( patterns );
349 }
350 
351 
352 int
353 Base6::isVersion6()
354 {
355  int exitStatus = 0;
356 
357  exitStatus = run( PGP6, 0, true );
358 
359  if(exitStatus == -1) {
360  errMsg = i18n("error running PGP");
361  status = RUN_ERR;
362  return 0;
363  }
364 
365  if( error.find("Version 6") != -1)
366  {
367  //kdDebug(5100) << "kpgpbase: pgp version 6.x detected" << endl;
368  return 1;
369  }
370 
371  //kdDebug(5100) << "kpgpbase: not pgp version 6.x" << endl;
372  return 0;
373 }
374 
375 
376 Key*
377 Base6::parseKeyData( const TQCString& output, int& offset, Key* key /* = 0 */ )
378 // This function parses the data for a single key which is output by PGP 6
379 // with the following command line arguments:
380 // +batchmode -compatible +verbose=0 +language=C -kvvc
381 // It expects the key data to start at offset and returns the start of
382 // the next key's data in offset.
383 {
384  if( ( strncmp( output.data() + offset, "DSS", 3 ) != 0 ) &&
385  ( strncmp( output.data() + offset, "RSA", 3 ) != 0 ) )
386  {
387  kdDebug(5100) << "Unknown key type or corrupt key data.\n";
388  return 0;
389  }
390 
391  Subkey *subkey = 0;
392  bool firstLine = true;
393  bool canSign = false;
394  bool canEncr = false;
395  bool fpr = false;
396 
397  while( true )
398  {
399  int eol;
400 
401  // search the end of the current line
402  if( ( eol = output.find( '\n', offset ) ) == -1 )
403  break;
404 
405  //kdDebug(5100) << "Parsing: " << output.mid(offset, eol-offset) << endl;
406 
407  if( firstLine && ( !strncmp( output.data() + offset, "DSS", 3 ) ||
408  !strncmp( output.data() + offset, "RSA", 3 ) ) )
409  { // line contains primary key data
410  // Example 1:
411  // RSA 1024 0xE2D074D3 2001/09/09 Test Key <testkey@xyz>
412  // Example 2 (disabled key):
413  // RSA@ 1024 0x8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
414  // Example 3 (expired key):
415  // RSA 1024 0x7B94827D 2001/09/09 *** KEY EXPIRED ***
416  // Example 4 (revoked key):
417  // RSA 1024 0x956721F9 2001/09/09 *** KEY REVOKED ***
418  // Example 5 (default signing key):
419  // RSA 1024 0x12345678 2001/09/09 *** DEFAULT SIGNING KEY ***
420  // Example 6 (expiring key):
421  // RSA 2048 0xC11DB2E5 2000/02/24 expires 2001/12/31
422  // Example 7 (complex example):
423  // DSS 1024 0x80E104A7 2000/06/05 expires 2002/05/31
424  // DSS 1024 0x80E104A7 2001/06/27 *** KEY REVOKED ***expires 2002/06/27
425  // DH 1024 0x80E104A7 2000/06/05 *** KEY REVOKED ****** KEY EXPIRED ***
426  //kdDebug(5100)<<"Primary key data:\n";
427  bool sign = false;
428  bool encr = false;
429 
430  // set default key capabilities
431  if( !strncmp( output.data() + offset, "DSS", 3 ) )
432  sign = true;
433  if( !strncmp( output.data() + offset, "RSA", 3 ) )
434  {
435  sign = true;
436  encr = true;
437  }
438 
439  int pos, pos2;
440 
441  if( key == 0 )
442  key = new Key();
443  else
444  key->clear();
445 
446  subkey = new Subkey( "", false );
447  key->addSubkey( subkey );
448  // expiration date defaults to never
449  subkey->setExpirationDate( -1 );
450 
451  // Key Flags
452  switch( output[offset+3] )
453  {
454  case ' ': // nothing special
455  break;
456  case '@': // disabled key
457  subkey->setDisabled( true );
458  key->setDisabled( true );
459  break;
460  default:
461  kdDebug(5100) << "Unknown key flag.\n";
462  }
463 
464  // Key Length
465  pos = offset + 4;
466  while( output[pos] == ' ' )
467  pos++;
468  pos2 = output.find( ' ', pos );
469  subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
470  //kdDebug(5100) << "Key Length: "<<subkey->keyLength()<<endl;
471 
472  // Key ID
473  pos = pos2 + 1;
474  while( output[pos] == ' ' )
475  pos++;
476  pos += 2; // skip the '0x'
477  pos2 = output.find( ' ', pos );
478  subkey->setKeyID( output.mid( pos, pos2-pos ) );
479  //kdDebug(5100) << "Key ID: "<<subkey->keyID()<<endl;
480 
481  // Creation Date
482  pos = pos2 + 1;
483  while( output[pos] == ' ' )
484  pos++;
485  pos2 = output.find( ' ', pos );
486  int year = output.mid( pos, 4 ).toInt();
487  int month = output.mid( pos+5, 2 ).toInt();
488  int day = output.mid( pos+8, 2 ).toInt();
489  TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) );
490  TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) );
491  // The calculated creation date isn't exactly correct because TQDateTime
492  // doesn't know anything about timezones and always assumes local time
493  // although epoch is of course UTC. But as PGP 6 anyway doesn't print
494  // the time this doesn't matter too much.
495  subkey->setCreationDate( epoch.secsTo( dt ) );
496 
497  // User ID or key properties
498  pos = pos2 + 1;
499  while( output[pos] == ' ' )
500  pos++;
501  while( pos < eol )
502  { // loop over User ID resp. key properties
503  if( !strncmp( output.data() + pos, "*** KEY REVOKED ***", 19 ) )
504  {
505  sign = false;
506  encr = false;
507  subkey->setRevoked( true );
508  key->setRevoked( true );
509  pos += 19;
510  //kdDebug(5100) << "Key was revoked.\n";
511  }
512  else if( !strncmp( output.data() + pos, "*** KEY EXPIRED ***", 19 ) )
513  {
514  sign = false;
515  encr = false;
516  subkey->setExpired( true );
517  key->setExpired( true );
518  pos += 19;
519  //kdDebug(5100) << "Key has expired.\n";
520  }
521  else if( !strncmp( output.data() + pos, "expires ", 8 ) )
522  {
523  pos += 8;
524  int year = output.mid( pos, 4 ).toInt();
525  int month = output.mid( pos+5, 2 ).toInt();
526  int day = output.mid( pos+8, 2 ).toInt();
527  TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) );
528  // Here the same comments as for the creation date are valid.
529  subkey->setExpirationDate( epoch.secsTo( dt ) );
530  pos += 10;
531  //kdDebug(5100) << "Key expires...\n";
532  }
533  else if( !strncmp( output.data() + pos, "*** DEFAULT SIGNING KEY ***", 27 ) )
534  {
535  pos += 27;
536  //kdDebug(5100) << "Key is default signing key.\n";
537  }
538  else
539  {
540  TQCString uid = output.mid( pos, eol-pos );
541  key->addUserID( uid );
542  pos = eol;
543  //kdDebug(5100) << "User ID:"<<uid<<endl;
544  }
545  }
546  // set key capabilities of the primary subkey
547  subkey->setCanEncrypt( encr );
548  subkey->setCanSign( sign );
549  subkey->setCanCertify( sign );
550  // remember the global key capabilities
551  canSign = sign;
552  canEncr = encr;
553  }
554  else if( !strncmp( output.data() + offset, "DSS", 3 ) ||
555  !strncmp( output.data() + offset, " DH", 3 ) ||
556  !strncmp( output.data() + offset, "RSA", 3 ) )
557  { // line contains secondary key data (or data for the next key)
558  if( fpr )
559  break; // here begins the next key's data
560  //kdDebug(5100)<<"Secondary key data:\n";
561 
562  if( key == 0 )
563  break;
564 
565  bool sign = false;
566  bool encr = false;
567 
568  // set default key capabilities
569  if( !strncmp( output.data() + offset, "DSS", 3 ) )
570  sign = true;
571  if( !strncmp( output.data() + offset, " DH", 3 ) )
572  encr = true;
573  if( !strncmp( output.data() + offset, "RSA", 3 ) )
574  {
575  sign = true;
576  encr = true;
577  }
578 
579  int pos, pos2;
580 
581  // Key Length of secondary key (ignored)
582  pos = offset + 4;
583  while( output[pos] == ' ' )
584  pos++;
585  pos2 = output.find( ' ', pos );
586 
587  // Key ID (ignored as it is anyway equal to the primary key id)
588  pos = pos2 + 1;
589  while( output[pos] == ' ' )
590  pos++;
591  pos2 = output.find( ' ', pos );
592 
593  // Creation Date of secondary key (ignored)
594  pos = pos2 + 1;
595  while( output[pos] == ' ' )
596  pos++;
597  pos2 = output.find( ' ', pos );
598 
599  // User ID or key properties
600  pos = pos2 + 1;
601  while( output[pos] == ' ' )
602  pos++;
603  while( pos < eol )
604  { // loop over User ID resp. key properties
605  if( !strncmp( output.data() + pos, "*** KEY REVOKED ***", 19 ) )
606  {
607  sign = false;
608  encr = false;
609  pos += 19;
610  //kdDebug(5100) << "Key was revoked.\n";
611  }
612  else if( !strncmp( output.data() + pos, "*** KEY EXPIRED ***", 19 ) )
613  {
614  sign = false;
615  encr = false;
616  pos += 19;
617  //kdDebug(5100) << "Key has expired.\n";
618  }
619  else if( !strncmp( output.data() + pos, "expires ", 8 ) )
620  {
621  pos += 18; // skip the expiration date
622  //kdDebug(5100) << "Key expires...\n";
623  }
624  else if( !strncmp( output.data() + pos, "*** DEFAULT SIGNING KEY ***", 27 ) )
625  {
626  pos += 27;
627  //kdDebug(5100) << "Key is default signing key.\n";
628  }
629  else
630  {
631  TQCString uid = output.mid( pos, eol-pos );
632  key->addUserID( uid );
633  pos = eol;
634  //kdDebug(5100) << "User ID:"<<uid<<endl;
635  }
636  }
637  // store the global key capabilities
638  canSign = canSign || sign;
639  canEncr = canEncr || encr;
640  }
641  else if( !strncmp( output.data() + offset, "Unknown type", 12 ) )
642  { // line contains key data of unknown type (ignored)
643  kdDebug(5100)<<"Unknown key type.\n";
644  }
645  else if( output[offset] == ' ' )
646  { // line contains additional key data
647  if( key == 0 )
648  break;
649  //kdDebug(5100)<<"Additional key data:\n";
650 
651  int pos = offset + 1;
652  while( output[pos] == ' ' )
653  pos++;
654 
655  if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
656  { // line contains a fingerprint
657  // Example:
658  // Key fingerprint = D0 6C BB 3A F5 16 82 C4 F3 A0 8A B3 7B 16 99 70
659 
660  fpr = true; // we found a fingerprint
661 
662  pos += 18;
663  TQCString fingerprint = output.mid( pos, eol-pos );
664  // remove white space from the fingerprint
665  for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; )
666  fingerprint.replace( idx, 1, "" );
667 
668  //kdDebug(5100)<<"Fingerprint: "<<fingerprint<<endl;
669  assert( subkey != 0 );
670  subkey->setFingerprint( fingerprint );
671  }
672  else
673  { // line contains an additional user id
674  // Example:
675  // Test key (2nd user ID) <abc@xyz>
676 
677  //kdDebug(5100)<<"User ID: "<<output.mid( pos, eol-pos )<<endl;
678  key->addUserID( output.mid( pos, eol-pos ) );
679  }
680  }
681  else if( !strncmp( output.data() + offset, "sig", 3 ) )
682  { // line contains signature data (ignored)
683  //kdDebug(5100)<<"Signature.\n";
684  }
685  else // end of key data
686  break;
687 
688  firstLine = false;
689  offset = eol + 1;
690  }
691 
692  if( key != 0 )
693  {
694  // set the global key capabilities
695  key->setCanEncrypt( canEncr );
696  key->setCanSign( canSign );
697  key->setCanCertify( canSign );
698  //kdDebug(5100)<<"Key capabilities: "<<(canEncr?"E":"")<<(canSign?"SC":"")<<endl;
699  }
700 
701  return key;
702 }
703 
704 
705 Key*
706 Base6::parseSingleKey( const TQCString& output, Key* key /* = 0 */ )
707 {
708  int offset;
709 
710  // search start of header line
711  if( !strncmp( output.data(), "Type bits", 9 ) )
712  offset = 9;
713  else
714  {
715  offset = output.find( "\nType bits" );
716  if( offset == -1 )
717  return 0;
718  else
719  offset += 10;
720  }
721 
722  // key data begins in the next line
723  offset = output.find( '\n', offset ) + 1;
724  if( offset == 0 )
725  return 0;
726 
727  key = parseKeyData( output, offset, key );
728 
729  //kdDebug(5100) << "finished parsing keys" << endl;
730 
731  return key;
732 }
733 
734 
735 KeyList
736 Base6::parseKeyList( const TQCString& output, bool secretKeys )
737 {
738  kdDebug(5100) << "Kpgp::Base6::parseKeyList()" << endl;
739  KeyList keys;
740  Key *key = 0;
741  int offset;
742 
743  // search start of header line
744  if( !strncmp( output.data(), "Type bits", 9 ) )
745  offset = 0;
746  else
747  {
748  offset = output.find( "\nType bits" ) + 1;
749  if( offset == 0 )
750  return keys;
751  }
752 
753  // key data begins in the next line
754  offset = output.find( '\n', offset ) + 1;
755  if( offset == -1 )
756  return keys;
757 
758  do
759  {
760  key = parseKeyData( output, offset );
761  if( key != 0 )
762  {
763  key->setSecret( secretKeys );
764  keys.append( key );
765  }
766  }
767  while( key != 0 );
768 
769  //kdDebug(5100) << "finished parsing keys" << endl;
770 
771  return keys;
772 }
773 
774 
775 void
776 Base6::parseTrustDataForKey( Key* key, const TQCString& str )
777 {
778  if( ( key == 0 ) || str.isEmpty() )
779  return;
780 
781  TQCString keyID = "0x" + key->primaryKeyID();
782  UserIDList userIDs = key->userIDs();
783 
784  // search the start of the trust data
785  int offset = str.find( "\n\n KeyID" );
786  if( offset == -1 )
787  return;
788 
789  offset = str.find( '\n', offset ) + 1;
790  if( offset == 0 )
791  return;
792 
793  bool ultimateTrust = false;
794  if( !strncmp( str.data() + offset+13, "ultimate", 8 ) )
795  ultimateTrust = true;
796 
797  while( true )
798  { // loop over all trust information about this key
799 
800  int eol;
801 
802  // search the end of the current line
803  if( ( eol = str.find( '\n', offset ) ) == -1 )
804  break;
805 
806  if( str[offset+23] != ' ' )
807  { // line contains a validity value for a user ID
808 
809  // determine the validity
810  Validity validity = KPGP_VALIDITY_UNKNOWN;
811  if( !strncmp( str.data() + offset+23, "complete", 8 ) )
812  if( ultimateTrust )
813  validity = KPGP_VALIDITY_ULTIMATE;
814  else
815  validity = KPGP_VALIDITY_FULL;
816  else if( !strncmp( str.data() + offset+23, "marginal", 8 ) )
817  validity = KPGP_VALIDITY_MARGINAL;
818  else if( !strncmp( str.data() + offset+23, "invalid", 7 ) )
819  validity = KPGP_VALIDITY_UNDEFINED;
820 
821  // determine the user ID
822  int pos = offset + 33;
823  TQString uid = str.mid( pos, eol-pos );
824 
825  // set the validity of the corresponding user ID
826  for( UserIDListIterator it( userIDs ); it.current(); ++it )
827  if( (*it)->text() == uid )
828  {
829  kdDebug(5100)<<"Setting the validity of "<<uid<<" to "<<validity<<endl;
830  (*it)->setValidity( validity );
831  break;
832  }
833  }
834 
835  offset = eol + 1;
836  }
837 }
838 
839 
840 } // namespace Kpgp