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
35namespace Kpgp {
36
37Base6::Base6()
38 : Base2()
39{
40}
41
42
43Base6::~Base6()
44{
45}
46
47
48int
49Base6::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
188Key*
189Base6::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
228KeyList
229Base6::publicKeys( const TQStringList & patterns )
230{
231 return doGetPublicKeys( PGP6 " +batchmode -compatible +verbose=0 "
232 "+language=C -kvvc", patterns );
233}
234
235
236/*
237TQStrList
238Base6::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
345KeyList
346Base6::secretKeys( const TQStringList & patterns )
347{
348 return publicKeys( patterns );
349}
350
351
352int
353Base6::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
376Key*
377Base6::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
705Key*
706Base6::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
735KeyList
736Base6::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
775void
776Base6::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