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

libkpgp

  • sources
  • kde-4.14
  • kdepim
  • libkpgp
kpgpbase2.cpp
Go to the documentation of this file.
1 /*
2  kpgpbase2.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 #include "kpgpbase.h"
20 #include "kpgp.h"
21 
22 #include <string.h> /* strncmp */
23 #include <assert.h>
24 
25 #include <QDateTime>
26 
27 #include <klocale.h>
28 #include <kshell.h>
29 #include <kdebug.h>
30 
31 #include <algorithm>
32 
33 #define PGP2 "pgp"
34 
35 namespace Kpgp {
36 
37 Base2::Base2()
38  : Base()
39 {
40 }
41 
42 
43 Base2::~Base2()
44 {
45 }
46 
47 
48 int
49 Base2::encrypt( Block& block, const KeyIDList& recipients )
50 {
51  return encsign( block, recipients, 0 );
52 }
53 
54 
55 int
56 Base2::clearsign( Block& block, const char *passphrase )
57 {
58  return encsign( block, KeyIDList(), passphrase );
59 }
60 
61 
62 int
63 Base2::encsign( Block& block, const KeyIDList& recipients,
64  const char *passphrase )
65 {
66  QByteArray cmd;
67  int exitStatus = 0;
68 
69  if(!recipients.isEmpty() && passphrase != 0)
70  cmd = PGP2 " +batchmode +language=en +verbose=1 -seat";
71  else if(!recipients.isEmpty())
72  cmd = PGP2 " +batchmode +language=en +verbose=1 -eat";
73  else if(passphrase != 0)
74  cmd = PGP2 " +batchmode +language=en +verbose=1 -sat";
75  else
76  {
77  kDebug( 5326 ) <<"kpgpbase: Neither recipients nor passphrase specified.";
78  return OK;
79  }
80 
81  if(passphrase != 0)
82  cmd += addUserId();
83 
84  if(!recipients.isEmpty()) {
85  if(Module::getKpgp()->encryptToSelf())
86  {
87  cmd += " 0x";
88  cmd += Module::getKpgp()->user();
89  }
90  KeyIDList::ConstIterator end( recipients.end() );
91  for( KeyIDList::ConstIterator it = recipients.constBegin();
92  it != end; ++it ) {
93  cmd += " 0x";
94  cmd += (*it);
95  }
96  }
97  cmd += " -f";
98 
99  clear();
100  input = block.text();
101  exitStatus = run(cmd.data(), passphrase);
102  if( !output.isEmpty() )
103  block.setProcessedText( output );
104  block.setError( error );
105 
106  if(exitStatus != 0)
107  status = ERROR;
108 
109 #if 0
110  // #### FIXME: As we check the keys ourselves the following problems
111  // shouldn't occur. Therefore I don't handle them for now.
112  // IK 01/2002
113  if(!recipients.isEmpty())
114  {
115  int index = 0;
116  bool bad = false;
117  unsigned int num = 0;
118  QByteArray badkeys = "";
119  if (error.contains("Cannot find the public key") )
120  {
121  index = 0;
122  num = 0;
123  while((index = error.indexOf("Cannot find the public key",index))
124  != -1)
125  {
126  bad = true;
127  index = error.indexOf('\'',index);
128  int index2 = error.indexOf('\'',index+1);
129  if (num++)
130  badkeys += ", ";
131  badkeys += error.mid(index, index2-index+1);
132  }
133  if(bad)
134  {
135  badkeys.trimmed();
136  if(num == recipients.count())
137  errMsg = i18n("Could not find public keys matching the userid(s)\n"
138  "%1;\n"
139  "the message is not encrypted.",
140  badkeys.data() );
141  else
142  errMsg = i18n("Could not find public keys matching the userid(s)\n"
143  "%1;\n"
144  "these persons will not be able to read the message.",
145  badkeys.data() );
146  status |= MISSINGKEY;
147  status |= ERROR;
148  }
149  }
150  if (error.contains("skipping userid") )
151  {
152  index = 0;
153  num = 0;
154  while((index = error.indexOf("skipping userid",index))
155  != -1)
156  {
157  bad = true;
158  int index2 = error.indexOf('\n',index+16);
159  if (num++)
160  badkeys += ", ";
161  badkeys += error.mid(index+16, index2-index-16);
162  index = index2;
163  }
164  if(bad)
165  {
166  badkeys.trimmed();
167  if(num == recipients.count())
168  errMsg = i18n("Public keys not certified with trusted signature "
169  "for userid(s)\n"
170  "%1.\n"
171  "The message is not encrypted.",
172  badkeys.data() );
173  else
174  errMsg = i18n("Public keys not certified with trusted signature "
175  "for userid(s)\n"
176  "%1;\n"
177  "these persons will not be able to read the message.",
178  badkeys.data() );
179  status |= BADKEYS;
180  status |= ERROR;
181  return status;
182  }
183  }
184  }
185 #endif
186  if(passphrase != 0)
187  {
188  if(error.contains("Pass phrase is good") )
189  {
190  //kDebug( 5326 ) <<"Base: Good Passphrase!";
191  status |= SIGNED;
192  }
193  if( error.contains("Bad pass phrase") )
194  {
195  errMsg = i18n("Bad passphrase; could not sign.");
196  status |= BADPHRASE;
197  status |= ERR_SIGNING;
198  status |= ERROR;
199  }
200  }
201  if (error.contains("Signature error") )
202  {
203  errMsg = i18n("Signing failed: please check your PGP User Identity, "
204  "the PGP setup, and the key rings.");
205  status |= NO_SEC_KEY;
206  status |= ERR_SIGNING;
207  status |= ERROR;
208  }
209  if (error.contains("Encryption error") )
210  {
211  errMsg = i18n("Encryption failed: please check your PGP setup "
212  "and the key rings.");
213  status |= NO_SEC_KEY;
214  status |= BADKEYS;
215  status |= ERROR;
216  }
217 
218  //kDebug( 5326 ) <<"status =" << status;
219  block.setStatus( status );
220  return status;
221 }
222 
223 
224 int
225 Base2::decrypt( Block& block, const char *passphrase )
226 {
227  int index, index2;
228  int exitStatus = 0;
229 
230  clear();
231  input = block.text();
232  exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
233  if( !output.isEmpty() )
234  block.setProcessedText( output );
235  block.setError( error );
236 
237  // pgp2.6 has sometimes problems with the ascii armor pgp5.0 produces
238  // this hack can solve parts of the problem
239  if(error.contains("ASCII armor corrupted.") )
240  {
241  kDebug( 5326 ) <<"removing ASCII armor header";
242  int index1 = input.indexOf("-----BEGIN PGP SIGNED MESSAGE-----");
243  if(index1 != -1)
244  index1 = input.indexOf("-----BEGIN PGP SIGNATURE-----", index1);
245  else
246  index1 = input.indexOf("-----BEGIN PGP MESSAGE-----");
247  index1 = input.indexOf('\n', index1);
248  index2 = input.indexOf("\n\n", index1);
249  input.remove(index1, index2 - index1);
250  exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
251  if( !output.isEmpty() )
252  block.setProcessedText( output );
253  block.setError( error );
254  }
255 
256  if(exitStatus == -1) {
257  errMsg = i18n("error running PGP");
258  status = ERROR;
259  block.setStatus( status );
260  return status;
261  }
262 
263  /* Example No.1 (PGP 2.6.3in):
264  * File is encrypted. Secret key is required to read it.
265  * Key for user ID: Test Key (only for testing) <testkey@ingo-kloecker.de>
266  * 1024-bit key, key ID E2D074D3, created 2001/09/09
267  *
268  * Error: Bad pass phrase.
269  *
270  * This message can only be read by:
271  * Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
272  * Test Key (only for testing) <testkey@ingo-kloecker.de>
273  *
274  * You do not have the secret key needed to decrypt this file.
275  */
276  /* Example No.2 (PGP 2.6.3in):
277  * File is encrypted. Secret key is required to read it.
278  * This message can only be read by:
279  * Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
280  *
281  * You do not have the secret key needed to decrypt this file.
282  */
283  if(error.contains("File is encrypted.") )
284  {
285  //kDebug( 5326 ) <<"kpgpbase: message is encrypted";
286  status |= ENCRYPTED;
287  if((index = error.indexOf("Key for user ID:")) != -1 )
288  {
289  // Find out the key for which the phrase is needed
290  index += 17;
291  index2 = error.indexOf('\n', index);
292  block.setRequiredUserId( QLatin1String(error.mid(index, index2 - index)) );
293  //kDebug( 5326 ) <<"Base: key needed is \"" << block.requiredUserId() <<"\"!";
294 
295  if((passphrase != 0) && (error.contains("Bad pass phrase") ))
296  {
297  errMsg = i18n("Bad passphrase; could not decrypt.");
298  kDebug( 5326 ) <<"Base: passphrase is bad";
299  status |= BADPHRASE;
300  status |= ERROR;
301  }
302  }
303  else
304  {
305  // no secret key fitting this message
306  status |= NO_SEC_KEY;
307  status |= ERROR;
308  errMsg = i18n("You do not have the secret key needed to decrypt this message.");
309  kDebug( 5326 ) <<"Base: no secret key for this message";
310  }
311  // check for persons
312 #if 0
313  // ##### FIXME: This information is anyway currently not used
314  // I'll change it to always determine the recipients.
315  index = error.indexOf("can only be read by:");
316  if(index != -1)
317  {
318  index = error.indexOf('\n',index);
319  int end = error.indexOf("\n\n",index);
320 
321  mRecipients.clear();
322  while( (index2 = error.indexOf('\n',index+1)) <= end )
323  {
324  QByteArray item = error.mid(index+1,index2-index-1);
325  item.trimmed();
326  mRecipients.append(item);
327  index = index2;
328  }
329  }
330 #endif
331  }
332 
333  // handle signed message
334 
335  // Examples (made with PGP 2.6.3in)
336  /* Example No. 1 (signed with unknown key):
337  * File has signature. Public key is required to check signature.
338  *
339  * Key matching expected Key ID 12345678 not found in file '/home/user/.pgp/pubring.pgp'.
340  *
341  * WARNING: Can't find the right public key-- can't check signature integrity.
342  */
343  /* Example No. 2 (bad signature):
344  * File has signature. Public key is required to check signature.
345  * ..
346  * WARNING: Bad signature, doesn't match file contents!
347  *
348  * Bad signature from user "Joe User <joe@foo.bar>".
349  * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
350  */
351  /* Example No. 3.1 (good signature with untrusted key):
352  * File has signature. Public key is required to check signature.
353  * .
354  * Good signature from user "Joe User <joe@foo.bar>".
355  * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
356  *
357  * WARNING: Because this public key is not certified with a trusted
358  * signature, it is not known with high confidence that this public key
359  * actually belongs to: "Joe User <joe@foo.bar>".
360  */
361  /* Example No. 3.2 (good signature with untrusted key):
362  * File has signature. Public key is required to check signature.
363  * .
364  * Good signature from user "Joe User <joe@foo.bar>".
365  * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
366  *
367  * WARNING: Because this public key is not certified with enough trusted
368  * signatures, it is not known with high confidence that this public key
369  * actually belongs to: "Joe User <joe@foo.bar>".
370  */
371  /* Example No. 4 (good signature with revoked key):
372  * File has signature. Public key is required to check signature.
373  * .
374  * Good signature from user "Joe User <joe@foo.bar>".
375  * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
376  *
377  *
378  * Key for user ID: Joe User <joe@foo.bar>
379  * 1024-bit key, key ID 12345678, created 2001/09/09
380  * Key has been revoked.
381  *
382  * WARNING: This key has been revoked by its owner,
383  * possibly because the secret key was compromised.
384  * This could mean that this signature is a forgery.
385  */
386  /* Example No. 5 (good signature with trusted key):
387  * File has signature. Public key is required to check signature.
388  * .
389  * Good signature from user "Joe User <joe@foo.bar>".
390  * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
391  */
392 
393  if((index = error.indexOf("File has signature")) != -1 )
394  {
395  // move index to start of next line
396  index = error.indexOf('\n', index+18) + 1;
397  //kDebug( 5326 ) <<"Base: message is signed";
398  status |= SIGNED;
399  // get signature date and signature key ID
400  if ((index2 = error.indexOf("Signature made", index)) != -1 ) {
401  index2 += 15;
402  int index3 = error.indexOf("using", index2);
403  block.setSignatureDate( error.mid(index2, index3-index2-1) );
404  kDebug( 5326 ) <<"Message was signed on '" << block.signatureDate() <<"'";
405  index3 = error.indexOf("key ID ", index3) + 7;
406  block.setSignatureKeyId( error.mid(index3,8) );
407  kDebug( 5326 ) <<"Message was signed with key '" << block.signatureKeyId() <<"'";
408  }
409  else {
410  // if pgp can't find the keyring it unfortunately doesn't print
411  // the signature date and key ID
412  block.setSignatureDate( "" );
413  block.setSignatureKeyId( "" );
414  }
415 
416  if( ( index2 = error.indexOf("Key matching expected", index) ) != -1 )
417  {
418  status |= UNKNOWN_SIG;
419  status |= GOODSIG;
420  int index3 = error.indexOf("Key ID ", index2) + 7;
421  block.setSignatureKeyId( error.mid(index3,8) );
422  block.setSignatureUserId( QString() );
423  }
424  else if( (index2 = error.indexOf("Good signature from", index)) != -1 )
425  {
426  status |= GOODSIG;
427  // get signer
428  index = error.indexOf('"',index2+19);
429  index2 = error.indexOf('"', index+1);
430  block.setSignatureUserId( QLatin1String(error.mid(index+1, index2-index-1)) );
431  }
432  else if( (index2 = error.indexOf("Bad signature from", index)) != -1 )
433  {
434  status |= ERROR;
435  // get signer
436  index = error.indexOf('"',index2+19);
437  index2 = error.indexOf('"', index+1);
438  block.setSignatureUserId( QLatin1String(error.mid(index+1, index2-index-1)) );
439  }
440  else if( error.indexOf("Keyring file", index) != -1 )
441  {
442  // #### fix this hack
443  status |= UNKNOWN_SIG;
444  status |= GOODSIG; // this is a hack...
445  // determine file name of missing keyring file
446  index = error.indexOf('\'', index) + 1;
447  index2 = error.indexOf('\'', index);
448  block.setSignatureUserId( i18n("The keyring file %1 does not exist.\n"
449  "Please check your PGP setup.", QString::fromLatin1( error.mid(index, index2-index)) ) );
450  }
451  else
452  {
453  status |= ERROR;
454  block.setSignatureUserId( i18n("Unknown error") );
455  }
456  }
457  //kDebug( 5326 ) <<"status =" << status;
458  block.setStatus( status );
459  return status;
460 }
461 
462 
463 Key*
464 Base2::readPublicKey( const KeyID& keyID,
465  const bool readTrust /* = false */,
466  Key* key /* = 0 */ )
467 {
468  int exitStatus = 0;
469 
470  status = 0;
471  exitStatus = run( QByteArray(QByteArray(PGP2 " +batchmode +language=en +verbose=0 -kvc -f 0x") +
472  keyID), 0, true );
473 
474  if(exitStatus != 0) {
475  status = ERROR;
476  return 0;
477  }
478 
479  key = parsePublicKeyData( output, key );
480 
481  if( key == 0 )
482  {
483  return 0;
484  }
485 
486  if( readTrust )
487  {
488  exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kc -f",
489  0, true );
490 
491  if(exitStatus != 0) {
492  status = ERROR;
493  return 0;
494  }
495 
496  parseTrustDataForKey( key, error );
497  }
498 
499  return key;
500 }
501 
502 
503 KeyList
504 Base2::publicKeys( const QStringList & patterns )
505 {
506  return doGetPublicKeys( PGP2 " +batchmode +language=en +verbose=0 -kvc -f",
507  patterns );
508 }
509 
510 KeyList
511 Base2::doGetPublicKeys( const QByteArray & cmd, const QStringList & patterns )
512 {
513  int exitStatus = 0;
514  KeyList publicKeys;
515 
516  status = 0;
517  if ( patterns.isEmpty() ) {
518  exitStatus = run( cmd, 0, true );
519 
520  if ( exitStatus != 0 ) {
521  status = ERROR;
522  return KeyList();
523  }
524 
525  // now we need to parse the output for public keys
526  publicKeys = parseKeyList( output, false );
527  }
528  else {
529  typedef QMap<QByteArray, Key*> KeyMap;
530  KeyMap map;
531  QStringList::ConstIterator end( patterns.constEnd() );
532  for ( QStringList::ConstIterator it = patterns.constBegin();
533  it != end; ++it ) {
534  exitStatus = run( QByteArray(cmd + QByteArray(" ") + KShell::quoteArg( *it ).toLocal8Bit()),
535  0, true );
536 
537  if ( exitStatus != 0 ) {
538  status = ERROR;
539  return KeyList();
540  }
541 
542  // now we need to parse the output for public keys
543  publicKeys = parseKeyList( output, false );
544 
545  // put all new keys into a map, remove duplicates
546  while ( !publicKeys.isEmpty() ) {
547  Key * key = publicKeys.takeFirst();
548  if ( !map.contains( key->primaryFingerprint() ) )
549  map.insert( key->primaryFingerprint(), key );
550  else
551  delete key;
552  }
553  }
554  // build list from the map
555  KeyMap::ConstIterator endKeyMap( map.constEnd() );
556  for ( KeyMap::ConstIterator it = map.constBegin(); it != endKeyMap; ++it ) {
557  publicKeys.append( it.value() );
558  }
559  }
560 
561  // sort the list of public keys
562  std::sort( publicKeys.begin(), publicKeys.end(), KeyCompare );
563 
564  return publicKeys;
565 }
566 
567 KeyList
568 Base2::secretKeys( const QStringList & patterns )
569 {
570  return publicKeys( patterns );
571 }
572 
573 
574 int
575 Base2::signKey(const KeyID& keyID, const char *passphrase)
576 {
577  QByteArray cmd;
578  int exitStatus = 0;
579 
580  cmd = PGP2 " +batchmode +language=en -ks -f ";
581  cmd += addUserId();
582  cmd += " 0x" + keyID;
583 
584  status = 0;
585  exitStatus = run(cmd.data(),passphrase);
586 
587  if (exitStatus != 0)
588  status = ERROR;
589 
590  return status;
591 }
592 
593 
594 QByteArray Base2::getAsciiPublicKey(const KeyID& keyID)
595 {
596  if (keyID.isEmpty())
597  return QByteArray();
598 
599  status = 0;
600  int exitStatus = run( QByteArray(QByteArray(PGP2 " +batchmode +force +language=en -kxaf 0x") + keyID),
601  0, true );
602 
603  if(exitStatus != 0) {
604  status = ERROR;
605  return QByteArray();
606  }
607 
608  return output;
609 }
610 
611 
612 Key*
613 Base2::parsePublicKeyData( const QByteArray& output, Key* key /* = 0 */ )
614 {
615  Subkey *subkey = 0;
616  int index;
617 
618  // search start of key data
619  if( !strncmp( output.data(), "pub", 3 ) ||
620  !strncmp( output.data(), "sec", 3 ) )
621  index = 0;
622  else
623  {
624  /*
625  if( secretKeys )
626  index = output.indexOf( "\nsec" );
627  else
628  */
629  index = output.indexOf( "\npub" );
630  if( index == -1 )
631  return 0;
632  else
633  index++;
634  }
635 
636  while( true )
637  {
638  int index2;
639 
640  // search the end of the current line
641  if( ( index2 = output.indexOf( '\n', index ) ) == -1 )
642  break;
643 
644  if( !strncmp( output.data() + index, "pub", 3 ) ||
645  !strncmp( output.data() + index, "sec", 3 ) )
646  { // line contains primary key data
647  // Example 1 (nothing special):
648  // pub 1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
649  // Example 2 (disabled key):
650  // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
651  // Example 3 (expired key):
652  // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
653  // Example 4 (revoked key):
654  // pub 1024/956721F9 2001/09/09 *** KEY REVOKED ***
655 
656  int pos, pos2;
657 
658  if( key == 0 )
659  key = new Key();
660  else
661  key->clear();
662  /*key->setSecret( secretKeys );*/
663  // set default key capabilities
664  key->setCanEncrypt( true );
665  key->setCanSign( true );
666  key->setCanCertify( true );
667 
668  /*subkey = new Subkey( "", secretKeys );*/
669  subkey = new Subkey( "", false );
670  key->addSubkey( subkey );
671  // set default key capabilities
672  subkey->setCanEncrypt( true );
673  subkey->setCanSign( true );
674  subkey->setCanCertify( true );
675  // expiration date defaults to never
676  subkey->setExpirationDate( -1 );
677 
678  // Key Flags
679  switch( output[index+3] )
680  {
681  case ' ': // nothing special
682  break;
683  case '-': // disabled key
684  subkey->setDisabled( true );
685  key->setDisabled( true );
686  break;
687  case '>': // expired key
688  subkey->setExpired( true );
689  key->setExpired( true );
690  break;
691  default:
692  kDebug( 5326 ) <<"Unknown key flag.";
693  }
694 
695  // Key Length
696  pos = index + 4;
697  while( output[pos] == ' ' )
698  pos++;
699  pos2 = output.indexOf( '/', pos );
700  subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
701 
702  // Key ID
703  pos = pos2 + 1;
704  pos2 = output.indexOf( ' ', pos );
705  subkey->setKeyID( output.mid( pos, pos2-pos ) );
706 
707  // Creation Date
708  pos = pos2 + 1;
709  while( output[pos] == ' ' )
710  pos++;
711  pos2 = output.indexOf( ' ', pos );
712  int year = output.mid( pos, 4 ).toInt();
713  int month = output.mid( pos+5, 2 ).toInt();
714  int day = output.mid( pos+8, 2 ).toInt();
715  QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
716  QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
717  // The calculated creation date isn't exactly correct because QDateTime
718  // doesn't know anything about timezones and always assumes local time
719  // although epoch is of course UTC. But as PGP 2 anyway doesn't print
720  // the time this doesn't matter too much.
721  subkey->setCreationDate( epoch.secsTo( dt ) );
722 
723  // User ID
724  pos = pos2 + 1;
725  while( output[pos] == ' ' )
726  pos++;
727  QByteArray uid = output.mid( pos, index2-pos );
728  if( uid != "*** KEY REVOKED ***" )
729  key->addUserID( QLatin1String(uid) );
730  else
731  {
732  subkey->setRevoked( true );
733  key->setRevoked( true );
734  }
735  }
736  else if( output[index] == ' ' )
737  { // line contains additional key data
738 
739  if( key == 0 )
740  break;
741  assert( subkey != 0 );
742 
743  int pos = index + 1;
744  while( output[pos] == ' ' )
745  pos++;
746 
747  if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
748  { // line contains a fingerprint
749  // Example:
750  // Key fingerprint = 47 30 7C 76 05 BF 5E FB 72 41 00 F2 7D 0B D0 49
751 
752  QByteArray fingerprint = output.mid( pos, index2-pos );
753  // remove white space from the fingerprint
754  for ( int idx = 0 ; (idx = fingerprint.indexOf(' ', idx)) != -1 ; )
755  fingerprint.replace( idx, 1, "" );
756 
757  subkey->setFingerprint( fingerprint );
758  }
759  else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
760  !strncmp( output.data() + pos, "no expire ", 10 ) )
761  { // line contains additional key properties
762  // Examples:
763  // Expire: 2001/09/10
764  // no expire ENCRyption only
765  // no expire SIGNature only
766 
767  if( output[pos] == 'E' )
768  {
769  // Expiration Date
770  pos += 8;
771  int year = output.mid( pos, 4 ).toInt();
772  int month = output.mid( pos+5, 2 ).toInt();
773  int day = output.mid( pos+8, 2 ).toInt();
774  QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
775  QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
776  // Here the same comments as for the creation date are valid.
777  subkey->setExpirationDate( epoch.secsTo( dt ) );
778  pos += 11; // note that there is always a blank after the expire date
779  }
780  else
781  pos += 10;
782 
783  // optional key capabilities (sign/encrypt only)
784  if( pos != index2 )
785  {
786  if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
787  {
788  subkey->setCanEncrypt( false );
789  key->setCanEncrypt( false );
790  }
791  else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
792  {
793  subkey->setCanSign( false );
794  key->setCanSign( false );
795  subkey->setCanCertify( false );
796  key->setCanCertify( false );
797  }
798  }
799  }
800  else
801  { // line contains an additional user id
802  // Example:
803  // Test key (2nd user ID) <abc@xyz>
804 
805  key->addUserID( QLatin1String(output.mid( pos, index2-pos )) );
806  }
807  }
808  index = index2 + 1;
809  }
810 
811  //kDebug( 5326 ) <<"finished parsing key data";
812 
813  return key;
814 }
815 
816 
817 void
818 Base2::parseTrustDataForKey( Key* key, const QByteArray& str )
819 {
820  if( ( key == 0 ) || str.isEmpty() )
821  return;
822 
823  QByteArray keyID = key->primaryKeyID();
824  UserIDList userIDs = key->userIDs();
825 
826  // search the trust data belonging to this key
827  int index = str.indexOf( '\n' ) + 1;
828  while( ( index > 0 ) &&
829  ( strncmp( str.data() + index+2, keyID.data(), 8 ) != 0 ) )
830  index = str.indexOf( '\n', index ) + 1;
831 
832  if( index == 0 )
833  return;
834 
835  bool ultimateTrust = false;
836  if( !strncmp( str.data() + index+11, "ultimate", 8 ) )
837  ultimateTrust = true;
838 
839  bool firstLine = true;
840 
841  while( true )
842  { // loop over all trust information about this key
843  int index2;
844 
845  // search the end of the current line
846  if( ( index2 = str.indexOf( '\n', index ) ) == -1 )
847  break;
848 
849  // check if trust info for the next key starts
850  if( !firstLine && ( str[index+2] != ' ' ) )
851  break;
852 
853  if( str[index+21] != ' ' )
854  { // line contains a validity value for a user ID
855 
856  // determine the validity
857  Validity validity = KPGP_VALIDITY_UNKNOWN;
858  if( !strncmp( str.data() + index+21, "complete", 8 ) )
859  if( ultimateTrust )
860  validity = KPGP_VALIDITY_ULTIMATE;
861  else
862  validity = KPGP_VALIDITY_FULL;
863  else if( !strncmp( str.data() + index+21, "marginal", 8 ) )
864  validity = KPGP_VALIDITY_MARGINAL;
865  else if( !strncmp( str.data() + index+21, "never", 5 ) )
866  validity = KPGP_VALIDITY_NEVER;
867  else if( !strncmp( str.data() + index+21, "undefined", 9 ) )
868  validity = KPGP_VALIDITY_UNDEFINED;
869 
870  // determine the user ID
871  int pos = index + 31;
872  if( str[index+2] == ' ' )
873  pos++; // additional user IDs start one column later
874  QString uid = QLatin1String(str.mid( pos, index2-pos ));
875 
876  // set the validity of the corresponding user ID
877  for( UserIDList::Iterator it = userIDs.begin(); it != userIDs.end(); ++it )
878  if( (*it)->text() == uid )
879  {
880  kDebug( 5326 )<<"Setting the validity of"<<uid<<" to"<<validity;
881  (*it)->setValidity( validity );
882  break;
883  }
884  }
885 
886  firstLine = false;
887  index = index2 + 1;
888  }
889 }
890 
891 
892 KeyList
893 Base2::parseKeyList( const QByteArray& output, bool secretKeys )
894 {
895  kDebug( 5326 ) <<"Kpgp::Base2::parseKeyList()";
896  KeyList keys;
897  Key *key = 0;
898  Subkey *subkey = 0;
899  int index;
900 
901  // search start of key data
902  if( !strncmp( output.data(), "pub", 3 ) ||
903  !strncmp( output.data(), "sec", 3 ) )
904  index = 0;
905  else
906  {
907  if( secretKeys )
908  index = output.indexOf( "\nsec" );
909  else
910  index = output.indexOf( "\npub" );
911  if( index == -1 )
912  return keys;
913  else
914  index++;
915  }
916 
917  while( true )
918  {
919  int index2;
920 
921  // search the end of the current line
922  if( ( index2 = output.indexOf( '\n', index ) ) == -1 )
923  break;
924 
925  if( !strncmp( output.data() + index, "pub", 3 ) ||
926  !strncmp( output.data() + index, "sec", 3 ) )
927  { // line contains primary key data
928  // Example 1:
929  // pub 1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
930  // Example 2 (disabled key):
931  // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
932  // Example 3 (expired key):
933  // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
934  // Example 4 (revoked key):
935  // pub 1024/956721F9 2001/09/09 *** KEY REVOKED ***
936 
937  int pos, pos2;
938 
939  if( key != 0 ) // store the previous key in the key list
940  keys.append( key );
941 
942  key = new Key();
943  key->setSecret( secretKeys );
944  // set default key capabilities
945  key->setCanEncrypt( true );
946  key->setCanSign( true );
947  key->setCanCertify( true );
948 
949  subkey = new Subkey( "", secretKeys );
950  key->addSubkey( subkey );
951  // set default key capabilities
952  subkey->setCanEncrypt( true );
953  subkey->setCanSign( true );
954  subkey->setCanCertify( true );
955  // expiration date defaults to never
956  subkey->setExpirationDate( -1 );
957 
958  // Key Flags
959  switch( output[index+3] )
960  {
961  case ' ': // nothing special
962  break;
963  case '-': // disabled key
964  subkey->setDisabled( true );
965  key->setDisabled( true );
966  break;
967  case '>': // expired key
968  subkey->setExpired( true );
969  key->setExpired( true );
970  break;
971  default:
972  kDebug( 5326 ) <<"Unknown key flag.";
973  }
974 
975  // Key Length
976  pos = index + 4;
977  while( output[pos] == ' ' )
978  pos++;
979  pos2 = output.indexOf( '/', pos );
980  subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
981 
982  // Key ID
983  pos = pos2 + 1;
984  pos2 = output.indexOf( ' ', pos );
985  subkey->setKeyID( output.mid( pos, pos2-pos ) );
986 
987  // Creation Date
988  pos = pos2 + 1;
989  while( output[pos] == ' ' )
990  pos++;
991  pos2 = output.indexOf( ' ', pos );
992  int year = output.mid( pos, 4 ).toInt();
993  int month = output.mid( pos+5, 2 ).toInt();
994  int day = output.mid( pos+8, 2 ).toInt();
995  QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
996  QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
997  // The calculated creation date isn't exactly correct because QDateTime
998  // doesn't know anything about timezones and always assumes local time
999  // although epoch is of course UTC. But as PGP 2 anyway doesn't print
1000  // the time this doesn't matter too much.
1001  subkey->setCreationDate( epoch.secsTo( dt ) );
1002 
1003  // User ID
1004  pos = pos2 + 1;
1005  while( output[pos] == ' ' )
1006  pos++;
1007  QByteArray uid = output.mid( pos, index2-pos );
1008  if( uid != "*** KEY REVOKED ***" )
1009  key->addUserID( QLatin1String(uid) );
1010  else
1011  {
1012  subkey->setRevoked( true );
1013  key->setRevoked( true );
1014  }
1015  }
1016  else if( output[index] == ' ' )
1017  { // line contains additional key data
1018 
1019  if( key == 0 )
1020  break;
1021 
1022  int pos = index + 1;
1023  while( output[pos] == ' ' )
1024  pos++;
1025 
1026  if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
1027  { // line contains a fingerprint
1028  // Example:
1029  // Key fingerprint = 47 30 7C 76 05 BF 5E FB 72 41 00 F2 7D 0B D0 49
1030 
1031  QByteArray fingerprint = output.mid( pos, index2-pos );
1032  // remove white space from the fingerprint
1033  for ( int idx = 0 ; (idx = fingerprint.indexOf(' ', idx)) != -1 ; )
1034  fingerprint.replace( idx, 1, "" );
1035 
1036  subkey->setFingerprint( fingerprint );
1037  }
1038  else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
1039  !strncmp( output.data() + pos, "no expire ", 10 ) )
1040  { // line contains additional key properties
1041  // Examples:
1042  // Expire: 2001/09/10
1043  // no expire ENCRyption only
1044  // no expire SIGNature only
1045 
1046  if( output[pos] == 'E' )
1047  {
1048  // Expiration Date
1049  pos += 8;
1050  int year = output.mid( pos, 4 ).toInt();
1051  int month = output.mid( pos+5, 2 ).toInt();
1052  int day = output.mid( pos+8, 2 ).toInt();
1053  QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
1054  QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
1055  // Here the same comments as for the creation date are valid.
1056  subkey->setExpirationDate( epoch.secsTo( dt ) );
1057  pos += 11; // note that there is always a blank after the expire date
1058  }
1059  else
1060  pos += 10;
1061 
1062  // optional key capabilities (sign/encrypt only)
1063  if( pos != index2 )
1064  {
1065  if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
1066  {
1067  subkey->setCanEncrypt( false );
1068  key->setCanEncrypt( false );
1069  }
1070  else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
1071  {
1072  subkey->setCanSign( false );
1073  key->setCanSign( false );
1074  subkey->setCanCertify( false );
1075  key->setCanCertify( false );
1076  }
1077  }
1078  }
1079  else
1080  { // line contains an additional user id
1081  // Example:
1082  // Test key (2nd user ID) <abc@xyz>
1083 
1084  key->addUserID( QLatin1String(output.mid( pos, index2-pos )) );
1085  }
1086  }
1087 
1088  index = index2 + 1;
1089  }
1090 
1091  if (key != 0) // store the last key in the key list
1092  keys.append( key );
1093 
1094  //kDebug( 5326 ) <<"finished parsing keys";
1095 
1096  return keys;
1097 }
1098 
1099 
1100 } // namespace Kpgp
Kpgp::Subkey::setRevoked
void setRevoked(const bool revoked)
Sets the flag if the subkey has been revoked to revoked .
Definition: kpgpkey.h:436
Kpgp::Validity
Validity
These are the possible validity values for a PGP user id and for the owner trust. ...
Definition: kpgpkey.h:32
Kpgp::KeyList
QList< Key * > KeyList
Definition: kpgpkey.h:843
Kpgp::Base2::~Base2
virtual ~Base2()
Definition: kpgpbase2.cpp:43
QByteArray::toUInt
uint toUInt(bool *ok, int base) const
Kpgp::Key::setCanCertify
void setCanCertify(const bool canCertify)
Sets the flag if the key can be used to certify keys to canCertify .
Definition: kpgpkey.h:762
Kpgp::Block::setError
void setError(const QByteArray &str)
Definition: kpgpblock.h:222
Kpgp::Subkey::setDisabled
void setDisabled(const bool disabled)
Sets the flag if the subkey has been disabled to disabled .
Definition: kpgpkey.h:446
QByteArray::toInt
int toInt(bool *ok, int base) const
Kpgp::Block::setSignatureDate
void setSignatureDate(const QByteArray &date)
Definition: kpgpblock.h:278
QByteArray::trimmed
QByteArray trimmed() const
Kpgp::Subkey::setExpired
void setExpired(const bool expired)
Sets the flag if the subkey has expired to expired .
Definition: kpgpkey.h:441
Kpgp::Module::encryptToSelf
bool encryptToSelf(void) const
Definition: kpgp.cpp:173
QByteArray
Kpgp::Base::output
QByteArray output
Definition: kpgpbase.h:97
Kpgp::NO_SEC_KEY
Definition: kpgpblock.h:56
Kpgp::Module::user
const KeyID user() const
Returns the actual key ID of the currently set key.
Definition: kpgp.cpp:160
Kpgp::KPGP_VALIDITY_ULTIMATE
Definition: kpgpkey.h:39
QMap
Kpgp::Key::setCanEncrypt
void setCanEncrypt(const bool canEncrypt)
Sets the flag if the key can be used to encrypt data to canEncrypt .
Definition: kpgpkey.h:752
QByteArray::isEmpty
bool isEmpty() const
Kpgp::KPGP_VALIDITY_FULL
Definition: kpgpkey.h:38
Kpgp::Subkey::setKeyLength
void setKeyLength(const unsigned int keyLen)
Sets the key length of the subkey to keyLen bits.
Definition: kpgpkey.h:476
Kpgp::Base2::secretKeys
virtual KeyList secretKeys(const QStringList &patterns=QStringList())
Returns the list of secret keys in the users secret keyring.
Definition: kpgpbase2.cpp:568
Kpgp::Block
Definition: kpgpblock.h:89
Kpgp::Base::addUserId
QByteArray addUserId()
Definition: kpgpbase.cpp:688
Kpgp::Base2::Base2
Base2()
Definition: kpgpbase2.cpp:37
Kpgp::Base::errMsg
QString errMsg
Definition: kpgpbase.h:99
QTime
Kpgp::BADPHRASE
Definition: kpgpblock.h:54
Kpgp::Block::setRequiredUserId
void setRequiredUserId(const QString &userId)
Definition: kpgpblock.h:302
Kpgp::Module::getKpgp
static Kpgp::Module * getKpgp()
return the actual pgp object
Definition: kpgp.cpp:1067
Kpgp::Subkey::setCanSign
void setCanSign(const bool canSign)
Sets the flag if the subkey can be used to sign data to canSign .
Definition: kpgpkey.h:461
Kpgp::Base2::clearsign
virtual int clearsign(Block &block, const char *passphrase)
Clearsigns the message with the currently set key.
Definition: kpgpbase2.cpp:56
Kpgp::Subkey::setKeyID
void setKeyID(const KeyID &keyID)
Sets the key ID of the subkey to keyID .
Definition: kpgpkey.h:481
Kpgp::Base2::signKey
virtual int signKey(const KeyID &keyID, const char *passphrase)
Signs the given key with the currently set user key.
Definition: kpgpbase2.cpp:575
Kpgp::Key::setSecret
void setSecret(const bool secret)
Sets the flag if the key is a secret key to secret .
Definition: kpgpkey.h:727
Kpgp::Key::setDisabled
void setDisabled(const bool disabled)
Sets the flag if the key has been disabled to disabled .
Definition: kpgpkey.h:742
QByteArray::indexOf
int indexOf(char ch, int from) const
QList::count
int count(const T &value) const
Kpgp::KeyCompare
bool KeyCompare(Key *left, Key *right)
Definition: kpgpkey.h:845
QList::append
void append(const T &value)
Kpgp::Base::run
virtual int run(const char *cmd, const char *passphrase=0, bool onlyReadFromPGP=false)
Definition: kpgpbase.cpp:67
Kpgp::Block::setSignatureUserId
void setSignatureUserId(const QString &userId)
Definition: kpgpblock.h:254
kpgpbase.h
QList::isEmpty
bool isEmpty() const
Kpgp::Subkey
This class is used to store information about a subkey of a PGP key.
Definition: kpgpkey.h:183
Kpgp::GOODSIG
Definition: kpgpblock.h:51
Kpgp::Base2::encrypt
virtual int encrypt(Block &block, const KeyIDList &recipients)
Encrypts the message with the given keys.
Definition: kpgpbase2.cpp:49
Kpgp::Key::addUserID
void addUserID(const QString &uid, const Validity validity=KPGP_VALIDITY_UNKNOWN, const bool revoked=false, const bool invalid=false)
Adds a user ID with the given values to the key if uid isn't an empty string.
Definition: kpgpkey.cpp:200
QByteArray::replace
QByteArray & replace(int pos, int len, const char *after)
PGP2
#define PGP2
Definition: kpgpbase2.cpp:33
QList< UserID * >::Iterator
typedef Iterator
Kpgp::BADKEYS
Definition: kpgpblock.h:55
QDate
Kpgp::KPGP_VALIDITY_UNDEFINED
Definition: kpgpkey.h:35
Kpgp::Base2::doGetPublicKeys
KeyList doGetPublicKeys(const QByteArray &cmd, const QStringList &patterns)
Definition: kpgpbase2.cpp:511
QString
Kpgp::Base2::decrypt
virtual int decrypt(Block &block, const char *passphrase=0)
Decrypts the message.
Definition: kpgpbase2.cpp:225
QList
Kpgp::KeyIDList
Definition: kpgpkey.h:57
Kpgp::ENCRYPTED
Definition: kpgpblock.h:49
Kpgp::OK
Definition: kpgpblock.h:46
QByteArray::mid
QByteArray mid(int pos, int len) const
Kpgp::UserIDList
QList< UserID * > UserIDList
Definition: kpgpkey.h:138
Kpgp::Subkey::setExpirationDate
void setExpirationDate(const time_t expirationDate)
Sets the expiration date of the subkey to expirationDate seconds since Epoch.
Definition: kpgpkey.h:496
Kpgp::Block::signatureDate
QByteArray signatureDate() const
date of the signature WARNING: Will most likely be changed to QDateTime
Definition: kpgpblock.h:272
QStringList
Kpgp::Block::signatureKeyId
QByteArray signatureKeyId() const
keyID of signer
Definition: kpgpblock.h:260
QByteArray::append
QByteArray & append(char ch)
QList::end
iterator end()
Kpgp::KPGP_VALIDITY_MARGINAL
Definition: kpgpkey.h:37
Kpgp::Base2::encsign
virtual int encsign(Block &block, const KeyIDList &recipients, const char *passphrase=0)
Encrypts and signs the message with the given keys.
Definition: kpgpbase2.cpp:63
Kpgp::Base2::parseKeyList
virtual KeyList parseKeyList(const QByteArray &, bool)
Definition: kpgpbase2.cpp:893
Kpgp::Block::setSignatureKeyId
void setSignatureKeyId(const QByteArray &keyId)
Definition: kpgpblock.h:266
Kpgp::MISSINGKEY
Definition: kpgpblock.h:57
Kpgp::Subkey::setCanCertify
void setCanCertify(const bool canCertify)
Sets the flag if the subkey can be used to certify keys to canCertify .
Definition: kpgpkey.h:466
Kpgp::Block::text
QByteArray text() const
Definition: kpgpblock.h:193
Kpgp::Key::primaryFingerprint
QByteArray primaryFingerprint() const
Returns the fingerprint of the primary key or a null string if there are no subkeys.
Definition: kpgpkey.h:797
QList::takeFirst
T takeFirst()
QLatin1String
Kpgp::Subkey::setFingerprint
void setFingerprint(const QByteArray &fingerprint)
Sets the fingerprint of the subkey to fingerprint .
Definition: kpgpkey.h:486
QDateTime::secsTo
int secsTo(const QDateTime &other) const
Kpgp::Key::addSubkey
void addSubkey(const KeyID &keyID, const bool secret=false)
Adds a subkey with the given values to the key if keyID isn't an empty string.
Definition: kpgpkey.cpp:222
Kpgp::Base
Definition: kpgpbase.h:30
Kpgp::Base::input
QByteArray input
Definition: kpgpbase.h:96
Kpgp::Key::setExpired
void setExpired(const bool expired)
Sets the flag if the key has expired to expired .
Definition: kpgpkey.h:737
Kpgp::Block::setProcessedText
void setProcessedText(const QByteArray &str)
Definition: kpgpblock.h:209
QList< KeyID >::ConstIterator
typedef ConstIterator
QByteArray::contains
bool contains(char ch) const
Kpgp::Key::setRevoked
void setRevoked(const bool revoked)
Sets the flag if the key has been revoked to revoked .
Definition: kpgpkey.h:732
Kpgp::KPGP_VALIDITY_NEVER
Definition: kpgpkey.h:36
QByteArray::data
char * data()
Kpgp::Key
This class is used to store information about a PGP key.
Definition: kpgpkey.h:506
Kpgp::ERROR
Definition: kpgpblock.h:48
Kpgp::KPGP_VALIDITY_UNKNOWN
Definition: kpgpkey.h:34
QString::fromLatin1
QString fromLatin1(const char *str, int size)
Kpgp::UNKNOWN_SIG
Definition: kpgpblock.h:53
Kpgp::Base2::publicKeys
virtual KeyList publicKeys(const QStringList &patterns=QStringList())
Returns the list of public keys in the users public keyring.
Definition: kpgpbase2.cpp:504
Kpgp::Base::clear
virtual void clear()
Definition: kpgpbase.cpp:56
Kpgp::Base::error
QByteArray error
Definition: kpgpbase.h:98
Kpgp::SIGNED
Definition: kpgpblock.h:50
kpgp.h
QList::constEnd
const_iterator constEnd() const
QList::constBegin
const_iterator constBegin() const
Kpgp::Base::status
int status
Definition: kpgpbase.h:103
Kpgp::Base2::readPublicKey
virtual Key * readPublicKey(const KeyID &keyID, const bool readTrust=false, Key *key=0)
Reads the key data for the given key and returns it.
Definition: kpgpbase2.cpp:464
QByteArray::remove
QByteArray & remove(int pos, int len)
Kpgp::Subkey::setCanEncrypt
void setCanEncrypt(const bool canEncrypt)
Sets the flag if the subkey can be used to encrypt data to canEncrypt .
Definition: kpgpkey.h:456
Kpgp::Key::setCanSign
void setCanSign(const bool canSign)
Sets the flag if the key can be used to sign data to canSign .
Definition: kpgpkey.h:757
Kpgp::ERR_SIGNING
Definition: kpgpblock.h:52
QList::begin
iterator begin()
Kpgp::Base2::getAsciiPublicKey
virtual QByteArray getAsciiPublicKey(const KeyID &keyID)
Returns the ascii armored data of the public key with the given key id.
Definition: kpgpbase2.cpp:594
Kpgp::Subkey::setCreationDate
void setCreationDate(const time_t creationDate)
Sets the creation date of the subkey to creationDate seconds since Epoch.
Definition: kpgpkey.h:491
Kpgp::Key::clear
void clear()
Clears/resets all key data.
Definition: kpgpkey.cpp:117
QDateTime
Kpgp::Block::setStatus
void setStatus(const int status)
Definition: kpgpblock.h:234
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:32:22 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

libkpgp

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

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal