1 /* -*- mode: C++; c-file-style: "gnu" -*-
4 Copyright (C) 2001,2002 the KPGP authors
5 See file AUTHORS.kpgp for details
7 This file is part of KPGP, the KDE PGP/GnuPG support library.
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.
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
25 #include <kmessagebox.h>
26 #include <kconfigbase.h>
27 #include <kconfiggroup.h>
33 #include <QApplication>
48 #include <sys/socket.h>
49 #include <sys/types.h>
60 ModuleStatic() : kpgpObject( 0 ) {}
61 ~ModuleStatic() { delete kpgpObject
; }
65 K_GLOBAL_STATIC( ModuleStatic
, s_module
)
69 mPublicKeysCached(false),
71 mSecretKeysCached(false),
72 passphrase(0), passphrase_buffer_len(0), havePassPhrase(false)
76 config
= new KConfig("kpgprc");
85 if (!s_module
.isDestroyed() && s_module
->kpgpObject
== this)
86 s_module
->kpgpObject
= 0;
92 // ----------------- public methods -------------------------
99 // read kpgp config file entries
102 // read the email address -> { encryption keys, encryption preference }
106 // do we have a pgp executable
109 // create the Base object later when it is
110 // needed to avoid the costly check done for
111 // the autodetection of PGP 2/6
120 KConfigGroup
grp(config
, QString());
121 storePass
= grp
.readEntry("storePass", false);
122 showEncryptionResult
= grp
.readEntry("showEncryptionResult", true);
123 mShowKeyApprovalDlg
= grp
.readEntry( "showKeysForApproval", true );
124 // We have no config GUI for this key anymore, and the KPGP backend isn't ported,
125 // so let's just use Auto all the time. See #92619.
126 ///pgpType = (Module::PGPType) config->readEntry("pgpType", tAuto);
128 flagEncryptToSelf
= grp
.readEntry("encryptToSelf", true);
132 Module::writeConfig(bool sync
)
134 KConfigGroup
grp(config
, QString());
135 grp
.writeEntry("storePass", storePass
);
136 grp
.writeEntry("showEncryptionResult", showEncryptionResult
);
137 grp
.writeEntry( "showKeysForApproval", mShowKeyApprovalDlg
);
138 //config->writeEntry("pgpType", (int) pgpType);
139 grp
.writeEntry("encryptToSelf", flagEncryptToSelf
);
144 /// ### Why is the pgp object deleted? This is only necessary if the
145 /// PGP type was changed in the config dialog.
151 Module::setUser(const KeyID
& keyID
)
153 if (pgpUser
!= keyID
) {
160 Module::user(void) const
167 Module::setEncryptToSelf(bool flag
)
169 flagEncryptToSelf
= flag
;
173 Module::encryptToSelf(void) const
175 return flagEncryptToSelf
;
180 Module::setStorePassPhrase(bool flag
)
186 Module::storePassPhrase(void) const
192 Module::prepare( bool needPassPhrase
, Block
* block
)
194 if (0 == pgp
) assignPGPBase();
198 errMsg
= i18n("Could not find PGP executable.\n"
199 "Please check your PATH is set correctly.");
203 if( block
&& ( block
->status() & NO_SEC_KEY
) )
206 if(needPassPhrase
&& !havePassPhrase
) {
207 if( ( tGPG
== pgpType
) && ( 0 != getenv("GPG_AGENT_INFO") ) ) {
208 // the user uses gpg-agent which asks itself for the passphrase
209 kDebug( 5326 ) <<"user uses gpg-agent -> don't ask for passphrase";
210 // set dummy passphrase (because else signing doesn't work -> FIXME)
211 setPassPhrase( "dummy" );
216 ID
= block
->requiredUserId();
217 PassphraseDialog
passdlg(0, i18n("OpenPGP Security Check"), ID
);
219 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
221 int passdlgResult
= passdlg
.exec();
223 QApplication::restoreOverrideCursor();
225 if (passdlgResult
== QDialog::Accepted
) {
226 if (!setPassPhrase(passdlg
.passphrase())) {
227 if ( passdlg
.passphrase().length() >= 1024)
228 errMsg
= i18n("Passphrase is too long, it must contain fewer than 1024 characters.");
230 errMsg
= i18n("Out of memory.");
243 Module::wipePassPhrase(bool freeMem
)
246 if ( passphrase_buffer_len
)
247 memset( passphrase
, 0x00, passphrase_buffer_len
);
249 kDebug( 5326 ) <<"wipePassPhrase: passphrase && !passphrase_buffer_len ???";
253 if ( freeMem
&& passphrase
) {
256 passphrase_buffer_len
= 0;
258 havePassPhrase
= false;
262 Module::verify( Block
& block
)
266 if (0 == pgp
) assignPGPBase();
269 if( !prepare( false, &block
) )
271 // ok now try to verify the message.
272 retval
= pgp
->verify( block
);
274 if(retval
& Kpgp::ERROR
)
276 errMsg
= pgp
->lastErrorMessage();
283 Module::decrypt( Block
& block
)
287 if (0 == pgp
) assignPGPBase();
290 // loop as long as the user enters a wrong passphrase and doesn't abort
292 if( prepare( true, &block
) != 1 )
294 // ok now try to decrypt the message.
295 retval
= pgp
->decrypt( block
, passphrase
);
296 // loop on bad passphrase
297 if( retval
& BADPHRASE
) {
300 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
302 int ret
= KMessageBox::warningContinueCancel(0,
303 i18n("You just entered an invalid passphrase.\n"
304 "Do you want to try again, or "
305 "cancel and view the message undecrypted?"),
306 i18n("PGP Warning"), KGuiItem(i18n("&Retry")));
308 QApplication::restoreOverrideCursor();
310 if ( ret
== KMessageBox::Cancel
) break;
315 // erase the passphrase if we do not want to keep it
318 if(retval
& Kpgp::ERROR
)
320 errMsg
= pgp
->lastErrorMessage();
327 Module::clearsign( Block
& block
,
328 const KeyID
& keyId
, const QByteArray
& charset
)
330 return encrypt( block
, QStringList(), keyId
, true, charset
);
334 Module::encrypt( Block
& block
,
335 const QStringList
& receivers
, const KeyID
& keyId
,
336 bool sign
, const QByteArray
& charset
)
338 KeyIDList encryptionKeyIds
; // list of keys which are used for encryption
342 if( 0 == pgp
) assignPGPBase();
346 if( !receivers
.empty() ) {
347 Kpgp::Result result
= getEncryptionKeys( encryptionKeyIds
, receivers
,
349 if( Kpgp::Ok
!= result
) {
354 status
= doEncSign( block
, encryptionKeyIds
, sign
);
356 if( status
& CANCEL
)
357 return Kpgp::Canceled
;
359 // check for bad passphrase
360 while( status
& BADPHRASE
) {
362 QString str
= i18n("You entered an invalid passphrase.\n"
363 "Do you want to try again, continue and leave the "
364 "message unsigned, or cancel sending the message?");
366 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
368 int ret
= KMessageBox::warningYesNoCancel( 0, str
,
370 KGuiItem(i18n("&Retry")),
371 KGuiItem(i18n("Send &Unsigned")) );
373 QApplication::restoreOverrideCursor();
375 if( ret
== KMessageBox::Cancel
) {
376 return Kpgp::Canceled
;
378 if( ret
== KMessageBox::No
) {
379 // the user selected "Send unsigned"
380 if( encryptionKeyIds
.isEmpty() ) {
388 // ok let's try once again...
389 status
= doEncSign( block
, encryptionKeyIds
, sign
);
393 if( status
& ERR_SIGNING
) {
394 QString str
= i18nc("%1 = 'signing failed' error message",
395 "%1\nDo you want to send the message unsigned, "
396 "or cancel sending the message?",
397 pgp
->lastErrorMessage() );
399 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
401 int ret
= KMessageBox::warningContinueCancel( 0, str
,
403 KGuiItem(i18n("Send &Unsigned")) );
405 QApplication::restoreOverrideCursor();
407 if( ret
== KMessageBox::Cancel
) {
408 return Kpgp::Canceled
;
411 status
= doEncSign( block
, encryptionKeyIds
, sign
);
414 // check for bad keys
415 if( status
& BADKEYS
) {
416 QString str
= i18nc("%1 = 'bad keys' error message",
417 "%1\nDo you want to encrypt anyway, leave the "
418 "message as-is, or cancel sending the message?",
419 pgp
->lastErrorMessage() );
422 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
424 int ret
= KMessageBox::warningYesNoCancel( 0, str
,
426 KGuiItem(i18n("Send &Encrypted")),
427 KGuiItem(i18n("Send &Unencrypted")) );
429 QApplication::restoreOverrideCursor();
431 if( ret
== KMessageBox::Cancel
) {
432 return Kpgp::Canceled
;
434 if( ret
== KMessageBox::No
) {
435 // the user selected "Send unencrypted"
437 doEncSign( block
, KeyIDList(), sign
);
446 if( status
& MISSINGKEY
) {
447 QString str
= i18nc("%1 = 'missing keys' error message",
448 "%1\nDo you want to leave the message as-is, "
449 "or cancel sending the message?",
450 pgp
->lastErrorMessage() );
452 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
454 int ret
= KMessageBox::warningContinueCancel( 0, str
,
456 KGuiItem(i18n("&Send As-Is")) );
458 QApplication::restoreOverrideCursor();
460 if( ret
== KMessageBox::Cancel
) {
461 return Kpgp::Canceled
;
467 if( status
& Kpgp::ERROR
) {
469 errMsg
= i18n( "The following error occurred:\n%1" ,
470 pgp
->lastErrorMessage() );
471 QString details
= i18n( "This is the error message of %1:\n%2" ,
472 ( pgpType
== tGPG
) ? "GnuPG" : "PGP" ,
473 block
.error().data() );
475 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
477 KMessageBox::detailedSorry( 0, errMsg
, details
);
479 QApplication::restoreOverrideCursor();
481 return Kpgp::Failure
;
484 if( showCipherText() ) {
485 // show cipher text dialog
486 CipherTextDialog
*cipherTextDlg
= new CipherTextDialog( block
.text(), charset
);
488 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
490 bool result
= ( cipherTextDlg
->exec() == QDialog::Accepted
);
492 QApplication::restoreOverrideCursor();
494 delete cipherTextDlg
;
495 return result
== QDialog::Accepted
? Kpgp::Ok
: Kpgp::Canceled
;
501 Module::doEncSign( Block
& block
,
502 const KeyIDList
& recipientKeyIds
, bool sign
)
506 if( 0 == pgp
) assignPGPBase();
508 // to avoid error messages in case pgp is not installed
509 if( !havePgp
) return OK
;
512 int result
= prepare( true, &block
);
519 retval
= pgp
->encsign( block
, recipientKeyIds
, passphrase
);
522 if( !prepare( false, &block
) ) return Kpgp::ERROR
;
523 retval
= pgp
->encrypt( block
, recipientKeyIds
);
525 // erase the passphrase if we do not want to keep it
532 Module::getEncryptionKeys( KeyIDList
& encryptionKeyIds
,
533 const QStringList
& recipients
,
536 if( recipients
.empty() ) {
537 encryptionKeyIds
.clear();
541 // list of lists of encryption keys (one list per recipient + one list
543 QVector
<KeyIDList
> recipientKeyIds( recipients
.count() + 1 );
544 // add the sender's encryption key(s) to the list of recipient key IDs
545 if( encryptToSelf() ) {
546 recipientKeyIds
[0] = KeyIDList( keyId
);
549 recipientKeyIds
[0] = KeyIDList();
551 bool showKeysForApproval
= false;
553 for( QStringList::ConstIterator it
= recipients
.constBegin();
554 it
!= recipients
.constEnd(); ++it
, ++i
) {
555 EncryptPref encrPref
= encryptionPreference( *it
);
556 if( ( encrPref
== UnknownEncryptPref
) || ( encrPref
== NeverEncrypt
) )
557 showKeysForApproval
= true;
559 KeyIDList keyIds
= getEncryptionKeys( *it
);
560 if( keyIds
.isEmpty() ) {
561 showKeysForApproval
= true;
563 recipientKeyIds
[i
] = keyIds
;
566 kDebug( 5326 ) <<"recipientKeyIds = (";
567 QVector
<KeyIDList
>::const_iterator kit
;
568 for( kit
= recipientKeyIds
.constBegin(); kit
!= recipientKeyIds
.constEnd(); ++kit
) {
569 kDebug( 5326 ) <<"( 0x" << (*kit
).toStringList().join(", 0x" )
572 kDebug( 5326 ) <<")";
574 if( showKeysForApproval
|| mShowKeyApprovalDlg
) {
575 // #### FIXME: Until we support encryption with untrusted keys only
576 // #### trusted keys are allowed
577 unsigned int allowedKeys
= PublicKeys
| EncryptionKeys
| ValidKeys
| TrustedKeys
;
579 // ### reenable this code when we support encryption with untrusted keys
580 if( pgpType
!= tGPG
) {
581 // usage of untrusted keys is only possible with GnuPG
582 allowedKeys
|= TrustedKeys
;
585 // show the recipients <-> key relation
586 KeyApprovalDialog
dlg( recipients
, recipientKeyIds
, allowedKeys
);
589 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
591 int ret
= dlg
.exec();
593 if( ret
== QDialog::Rejected
) {
595 QApplication::restoreOverrideCursor();
597 return Kpgp::Canceled
;
600 recipientKeyIds
= dlg
.keys();
602 QApplication::restoreOverrideCursor();
606 // flatten the list of lists of key IDs and count empty key ID lists
607 int emptyListCount
= 0;
608 for( QVector
<KeyIDList
>::const_iterator it
= recipientKeyIds
.constBegin();
609 it
!= recipientKeyIds
.constEnd(); ++it
) {
610 if( (*it
).isEmpty() ) {
611 // only count empty key ID lists for the recipients
612 if( it
!= recipientKeyIds
.constBegin() ) {
617 for( KeyIDList::ConstIterator kit
= (*it
).constBegin();
618 kit
!= (*it
).constEnd(); kit
++ ) {
619 encryptionKeyIds
.append( *kit
);
624 // FIXME-AFTER-KDE-3.1: Show warning if message won't be encrypted to self
626 // show a warning if the user didn't select an encryption key for
627 // some of the recipients
628 if( recipientKeyIds
.size() == emptyListCount
+ 1 ) { // (+1 because of the sender's key)
629 QString str
= ( recipients
.count() == 1 )
630 ? i18n("You did not select an encryption key for the "
631 "recipient of this message; therefore, the message "
632 "will not be encrypted.")
633 : i18n("You did not select an encryption key for any of the "
634 "recipients of this message; therefore, the message "
635 "will not be encrypted.");
637 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
639 int ret
= KMessageBox::warningContinueCancel( 0, str
,
641 KGuiItem(i18n("Send &Unencrypted")) );
643 QApplication::restoreOverrideCursor();
645 if( ret
== KMessageBox::Cancel
) {
646 return Kpgp::Canceled
;
649 encryptionKeyIds
.clear();
651 else if( emptyListCount
> 0 ) {
652 QString str
= ( emptyListCount
== 1 )
653 ? i18n("You did not select an encryption key for one of "
654 "the recipients; this person will not be able to "
655 "decrypt the message if you encrypt it.")
656 : i18n("You did not select encryption keys for some of "
657 "the recipients; these persons will not be able to "
658 "decrypt the message if you encrypt it." );
660 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
662 int ret
= KMessageBox::warningYesNoCancel( 0, str
,
664 KGuiItem(i18n("Send &Encrypted")),
665 KGuiItem(i18n("Send &Unencrypted")) );
667 QApplication::restoreOverrideCursor();
669 if( ret
== KMessageBox::Cancel
) {
670 return Kpgp::Canceled
;
672 else if( ret
== KMessageBox::No
) {
673 // the user selected "Send unencrypted"
674 encryptionKeyIds
.clear();
682 Module::encryptionPossible( const QStringList
& recipients
)
684 if( 0 == pgp
) assignPGPBase();
689 if( recipients
.empty() )
692 int noKey
= 0, never
= 0, unknown
= 0, always
= 0, aip
= 0, ask
= 0,
694 for( QStringList::ConstIterator it
= recipients
.constBegin();
695 it
!= recipients
.constEnd(); ++it
) {
696 if( haveTrustedEncryptionKey( *it
) ) {
697 EncryptPref encrPref
= encryptionPreference( *it
);
702 case UnknownEncryptPref
:
708 case AlwaysEncryptIfPossible
:
711 case AlwaysAskForEncryption
:
714 case AskWheneverPossible
:
724 if( ( always
+aip
> 0 ) && ( never
+unknown
+ask
+askwp
+noKey
== 0 ) ) {
725 return 1; // encryption possible and desired
728 if( ( unknown
+ask
+askwp
> 0 ) && ( never
+noKey
== 0 ) ) {
729 return 2; // encryption possible, but user has to be asked
732 if( ( never
+noKey
> 0 ) && ( always
+ask
== 0 ) ) {
733 return 0; // encryption isn't possible or desired
736 return -1; // we can't decide it automatically
740 Module::signKey(const KeyID
& keyId
)
742 if (0 == pgp
) assignPGPBase();
744 if( prepare( true ) != 1 )
746 if(pgp
->signKey(keyId
, passphrase
) & Kpgp::ERROR
)
748 errMsg
= pgp
->lastErrorMessage();
758 if (0 == pgp
) assignPGPBase();
760 if (!prepare()) return KeyList();
762 if( !mPublicKeysCached
) {
773 if (0 == pgp
) assignPGPBase();
775 if (!prepare()) return KeyList();
777 if( !mSecretKeysCached
) {
786 Module::publicKey(const KeyID
& keyID
)
790 foreach ( Key
* key
, mPublicKeys
) {
791 if( keyID
== key
->primaryKeyID() ||
792 keyID
== key
->primaryFingerprint() )
800 Module::publicKey( const QString
& userID
)
804 foreach ( Key
* key
, mPublicKeys
) {
805 if( key
->matchesUserID( userID
) )
813 Module::secretKey(const KeyID
& keyID
)
817 foreach ( Key
* key
, mSecretKeys
) {
818 if( keyID
== key
->primaryKeyID() ||
819 keyID
== key
->primaryFingerprint() )
827 Module::keyTrust( const KeyID
& keyID
)
829 Key
*key
= publicKey( keyID
);
831 if( ( 0 == key
) || ( key
->keyTrust() == KPGP_VALIDITY_UNKNOWN
) )
832 { // (re)check the key if it's unknown or if its trust is unknown
833 key
= rereadKey( keyID
, true );
835 return KPGP_VALIDITY_UNKNOWN
;
838 return key
->keyTrust();
842 Module::keyTrust( const QString
& userID
)
844 Key
*key
= publicKey( userID
);
847 return KPGP_VALIDITY_UNKNOWN
;
849 if( key
->keyTrust() == KPGP_VALIDITY_UNKNOWN
)
851 key
= rereadKey( key
->primaryKeyID(), true );
853 return KPGP_VALIDITY_UNKNOWN
;
856 return key
->keyTrust();
860 Module::isTrusted( const KeyID
& keyID
)
862 return ( keyTrust( keyID
) >= KPGP_VALIDITY_MARGINAL
);
866 Module::rereadKey( const KeyID
& keyID
, const bool readTrust
/* = true */ )
868 if( 0 == pgp
) assignPGPBase();
870 // search the old key data in the key list
871 Key
* oldKey
= publicKey( keyID
);
873 Key
* newKey
= pgp
->readPublicKey( keyID
, readTrust
, oldKey
);
875 if( ( 0 == oldKey
) && ( 0 != newKey
) )
877 KeyList::Iterator it
= std::lower_bound( mPublicKeys
.begin(), mPublicKeys
.end(), newKey
, KeyCompare
);
878 mPublicKeys
.insert( it
, newKey
);
879 kDebug( 5326 ) <<"New public key 0x" << newKey
->primaryKeyID() <<" ("
880 << newKey
->primaryUserID() << ").\n";
882 else if( ( 0 != oldKey
) && ( 0 == newKey
) )
883 { // the key has been deleted in the meantime
884 kDebug( 5326 ) <<"Public key 0x" << oldKey
->primaryKeyID() <<" ("
885 << oldKey
->primaryUserID() << ") will be removed.\n";
886 mPublicKeys
.removeAll( oldKey
);
893 Module::getAsciiPublicKey(const KeyID
& keyID
)
895 if (0 == pgp
) assignPGPBase();
897 return pgp
->getAsciiPublicKey(keyID
);
901 bool Module::setPassPhrase(const QString
& aPass
)
903 // null out old buffer before we touch the new string. So in case
904 // aPass isn't properly null-terminated, we don't leak secret data.
909 size_t newlen
= aPass
.length();
910 if ( newlen
>= 1024 ) {
911 // rediculously long passphrase.
912 // Maybe someone wants to trick us in malloc()'ing
916 if ( passphrase_buffer_len
< newlen
+ 1 ) {
917 // too little space in current buffer:
918 // allocate a larger one.
921 passphrase_buffer_len
= (newlen
+ 1 + 15) & ~0xF; // make it a multiple of 16.
922 passphrase
= (char*)malloc( passphrase_buffer_len
);
924 passphrase_buffer_len
= 0;
928 memcpy( passphrase
, aPass
.toLocal8Bit().data(), newlen
+ 1 );
929 havePassPhrase
= true;
935 Module::changePassPhrase()
938 KMessageBox::information(0,i18n("This feature is\nstill missing"));
943 Module::clear(const bool erasePassPhrase
)
946 wipePassPhrase(true);
950 Module::lastErrorMsg(void) const
956 Module::havePGP(void) const
962 Module::setShowCipherText(const bool flag
)
964 showEncryptionResult
= flag
;
968 Module::showCipherText(void) const
970 return showEncryptionResult
;
974 Module::selectSecretKey( const QString
& title
,
983 return selectKey( secretKeys(), title
, text
, keyId
, SecretKeys
);
986 KMessageBox::sorry( 0, i18n("You either do not have GnuPG/PGP installed "
987 "or you chose not to use GnuPG/PGP.") );
993 Module::selectPublicKey( const QString
& title
,
994 const QString
& text
/*QString() */,
995 const KeyID
& oldKeyId
/* = KeyID() */,
996 const QString
& address
/*QString() */,
997 const unsigned int allowedKeys
/* = AllKeys */ )
1006 if( address
.isEmpty() ) {
1007 keyId
= selectKey( publicKeys(), title
, text
, oldKeyId
, allowedKeys
);
1010 bool rememberChoice
;
1011 keyId
= selectKey( rememberChoice
, publicKeys(), title
, text
, oldKeyId
,
1013 if( !keyId
.isEmpty() && rememberChoice
) {
1014 setKeysForAddress( address
, KeyIDList( keyId
) );
1021 KMessageBox::sorry( 0, i18n("You either do not have GnuPG/PGP installed "
1022 "or you chose not to use GnuPG/PGP.") );
1029 Module::selectPublicKeys( const QString
& title
,
1030 const QString
& text
/* = QString() */,
1031 const KeyIDList
& oldKeyIds
/* = KeyIDList() */,
1032 const QString
& address
/*= QString() */,
1033 const unsigned int allowedKeys
/* = AllKeys */ )
1042 if( address
.isEmpty() ) {
1043 keyIds
= selectKeys( publicKeys(), title
, text
, oldKeyIds
, allowedKeys
);
1046 bool rememberChoice
;
1047 keyIds
= selectKeys( rememberChoice
, publicKeys(), title
, text
,
1048 oldKeyIds
, allowedKeys
);
1049 if( !keyIds
.isEmpty() && rememberChoice
) {
1050 setKeysForAddress( address
, keyIds
);
1057 KMessageBox::sorry( 0, i18n("You either do not have GnuPG/PGP installed "
1058 "or you chose not to use GnuPG/PGP.") );
1064 // -- static member functions ----------------------------------------------
1069 if (!s_module
->kpgpObject
)
1071 s_module
->kpgpObject
= new Module();
1073 return s_module
->kpgpObject
;
1080 return getKpgp()->config
;
1085 Module::prepareMessageForDecryption( const QByteArray
& msg
,
1086 QList
<Block
>& pgpBlocks
,
1087 QList
<QByteArray
>& nonPgpBlocks
)
1089 BlockType pgpBlock
= NoPgpBlock
;
1090 int start
= -1; // start of the current PGP block
1091 int lastEnd
= -1; // end of the last PGP block
1094 nonPgpBlocks
.clear();
1098 nonPgpBlocks
.append( "" );
1102 if( !strncmp( msg
.data(), "-----BEGIN PGP ", 15 ) )
1106 start
= msg
.indexOf( "\n-----BEGIN PGP" ) + 1;
1109 nonPgpBlocks
.append( msg
);
1110 return false; // message doesn't contain an OpenPGP block
1114 while( start
!= -1 )
1116 int nextEnd
, nextStart
;
1118 // is the PGP block a clearsigned block?
1119 if( !strncmp( msg
.data() + start
+ 15, "SIGNED", 6 ) )
1120 pgpBlock
= ClearsignedBlock
;
1122 pgpBlock
= UnknownBlock
;
1124 nextEnd
= msg
.indexOf( "\n-----END PGP", start
+ 15 );
1127 nonPgpBlocks
.append( msg
.mid( lastEnd
+1 ) );
1130 nextStart
= msg
.indexOf( "\n-----BEGIN PGP", start
+ 15 );
1132 if( ( nextStart
== -1 ) || ( nextEnd
< nextStart
) ||
1133 ( pgpBlock
== ClearsignedBlock
) )
1134 { // most likely we found a PGP block (but we don't check if it's valid)
1135 // store the preceding non-PGP block
1136 nonPgpBlocks
.append( msg
.mid( lastEnd
+1, start
-lastEnd
-1 ) );
1137 lastEnd
= msg
.indexOf( "\n", nextEnd
+ 14 );
1140 pgpBlocks
.append( Block( msg
.mid( start
) ) );
1141 nonPgpBlocks
.append( "" );
1146 pgpBlocks
.append( Block( msg
.mid( start
, lastEnd
+1-start
) ) );
1147 if( ( nextStart
!= -1 ) && ( nextEnd
> nextStart
) )
1148 nextStart
= msg
.indexOf( "\n-----BEGIN PGP", lastEnd
+1 );
1154 nonPgpBlocks
.append( msg
.mid( lastEnd
+1 ) );
1156 start
++; // move start behind the '\n'
1159 return ( !pgpBlocks
.isEmpty() );
1163 // --------------------- private functions -------------------
1166 Module::haveTrustedEncryptionKey( const QString
& person
)
1168 if( 0 == pgp
) assignPGPBase();
1170 if( !usePGP() ) return false;
1174 QString address
= canonicalAddress( person
).toLower();
1176 // First look for this person's address in the address data dictionary
1177 KeyIDList keyIds
= keysForAddress( address
);
1178 if( !keyIds
.isEmpty() ) {
1179 // Check if at least one of the keys is a trusted and valid encryption key
1180 for( KeyIDList::ConstIterator it
= keyIds
.constBegin();
1181 it
!= keyIds
.constEnd(); ++it
) {
1182 keyTrust( *it
); // this is called to make sure that the trust info
1183 // for this key is read
1184 Key
*key
= publicKey( *it
);
1185 if( key
&& ( key
->isValidEncryptionKey() ) &&
1186 ( key
->keyTrust() >= KPGP_VALIDITY_MARGINAL
) )
1191 // Now search the public keys for matching keys
1192 KeyList::Iterator it
= mPublicKeys
.begin();
1194 // search a key which matches the complete address
1195 for(; it
!= mPublicKeys
.end(); ++it
) {
1196 // search case insensitively in the list of userIDs of this key
1197 if( (*it
)->matchesUserID( person
, false ) ) {
1198 keyTrust( (*it
)->primaryKeyID() ); // this is called to make sure that
1199 // the trust info for this key is read
1200 if( ( (*it
)->isValidEncryptionKey() ) &&
1201 ( (*it
)->keyTrust() >= KPGP_VALIDITY_MARGINAL
) ) {
1207 // if no key matches the complete address look for a key which matches
1208 // the canonical mail address
1209 for( it
= mPublicKeys
.begin(); it
!= mPublicKeys
.end(); ++it
) {
1210 // search case insensitively in the list of userIDs of this key
1211 if( (*it
)->matchesUserID( address
, false ) ) {
1212 keyTrust( (*it
)->primaryKeyID() ); // this is called to make sure that
1213 // the trust info for this key is read
1214 if( ( (*it
)->isValidEncryptionKey() ) &&
1215 ( (*it
)->keyTrust() >= KPGP_VALIDITY_MARGINAL
) ) {
1221 // no trusted encryption key was found for the given person
1226 Module::getEncryptionKeys( const QString
& person
)
1228 if( 0 == pgp
) assignPGPBase();
1230 if( !usePGP() ) return KeyIDList();
1234 QString address
= canonicalAddress( person
).toLower();
1236 // #### FIXME: Until we support encryption with untrusted keys only
1237 // #### trusted keys are allowed
1238 unsigned int allowedKeys
= PublicKeys
| EncryptionKeys
| ValidKeys
| TrustedKeys
;
1240 // ### reenable this code when we support encryption with untrusted keys
1241 if( pgpType
!= tGPG
) {
1242 // usage of untrusted keys is only possible with GnuPG
1243 allowedKeys
|= TrustedKeys
;
1247 // First look for this person's address in the address->key dictionary
1248 KeyIDList keyIds
= keysForAddress( address
);
1249 if( !keyIds
.isEmpty() ) {
1250 kDebug( 5326 ) <<"Using encryption keys 0x"
1251 << keyIds
.toStringList().join( ", 0x" )
1253 // Check if all of the keys are a trusted and valid encryption keys
1255 for( KeyIDList::ConstIterator it
= keyIds
.constBegin();
1256 it
!= keyIds
.constEnd(); ++it
) {
1257 keyTrust( *it
); // this is called to make sure that the trust info
1258 // for this key is read
1259 Key
*key
= publicKey( *it
);
1260 if( !( key
&& ( key
->isValidEncryptionKey() ) &&
1261 ( key
->keyTrust() >= KPGP_VALIDITY_MARGINAL
) ) )
1268 bool rememberChoice
;
1269 keyIds
= selectKeys( rememberChoice
, mPublicKeys
,
1270 i18n("Encryption Key Selection"),
1271 i18nc("if in your language something like "
1272 "'key(s)' isn't possible please "
1273 "use the plural in the translation",
1274 "There is a problem with the "
1275 "encryption key(s) for \"%1\".\n\n"
1276 "Please re-select the key(s) which should "
1277 "be used for this recipient."
1281 if( !keyIds
.isEmpty() ) {
1282 if( rememberChoice
) {
1283 setKeysForAddress( person
, keyIds
);
1290 // Now search all public keys for matching keys
1291 KeyList::Iterator it
= mPublicKeys
.begin();
1292 KeyList matchingKeys
;
1294 // search all keys which match the complete address
1295 kDebug( 5326 ) <<"Looking for keys matching" << person
<<" ...";
1296 for( ; it
!= mPublicKeys
.end(); ++it
) {
1297 // search case insensitively in the list of userIDs of this key
1298 if( (*it
)->matchesUserID( person
, false ) ) {
1299 keyTrust( (*it
)->primaryKeyID() ); // this is called to make sure that
1300 // the trust info for this key is read
1301 if( ( (*it
)->isValidEncryptionKey() ) &&
1302 ( (*it
)->keyTrust() >= KPGP_VALIDITY_MARGINAL
) ) {
1303 kDebug( 5326 ) <<"Matching trusted key found:"
1304 << (*it
)->primaryKeyID();
1305 matchingKeys
.append( *it
);
1310 // if no keys match the complete address look for keys which match
1311 // the canonical mail address
1312 kDebug( 5326 ) <<"Looking for keys matching" << address
<<" ...";
1313 if( matchingKeys
.isEmpty() ) {
1314 for ( it
= mPublicKeys
.begin(); it
!= mPublicKeys
.end(); ++it
) {
1315 // search case insensitively in the list of userIDs of this key
1316 if( (*it
)->matchesUserID( address
, false ) ) {
1317 keyTrust( (*it
)->primaryKeyID() ); // this is called to make sure that
1318 // the trust info for this key is read
1319 if( ( (*it
)->isValidEncryptionKey() ) &&
1320 ( (*it
)->keyTrust() >= KPGP_VALIDITY_MARGINAL
) ) {
1321 kDebug( 5326 ) <<"Matching trusted key found:"
1322 << (*it
)->primaryKeyID();
1323 matchingKeys
.append( *it
);
1329 // no match until now, let the user choose the key
1330 if( matchingKeys
.isEmpty() ) {
1331 // FIXME: let user get the key from keyserver
1332 bool rememberChoice
;
1333 KeyIDList keyIds
= selectKeys( rememberChoice
, mPublicKeys
,
1334 i18n("Encryption Key Selection"),
1335 i18nc("if in your language something like "
1336 "'key(s)' isn't possible please "
1337 "use the plural in the translation",
1338 "No valid and trusted OpenPGP key was "
1339 "found for \"%1\".\n\n"
1340 "Select the key(s) which should "
1341 "be used for this recipient."
1345 if( !keyIds
.isEmpty() ) {
1346 if( rememberChoice
) {
1347 setKeysForAddress( person
, keyIds
);
1352 // only one key matches
1353 else if( matchingKeys
.count() == 1 ) {
1354 return KeyIDList( matchingKeys
.first()->primaryKeyID() );
1356 // more than one key matches; let the user choose the key(s)
1358 bool rememberChoice
;
1359 KeyIDList keyIds
= selectKeys( rememberChoice
, matchingKeys
,
1360 i18n("Encryption Key Selection"),
1361 i18nc("if in your language something like "
1362 "'key(s)' isn't possible please "
1363 "use the plural in the translation",
1364 "More than one key matches \"%1\".\n\n"
1365 "Select the key(s) which should "
1366 "be used for this recipient."
1370 if( !keyIds
.isEmpty() ) {
1371 if( rememberChoice
) {
1372 setKeysForAddress( person
, keyIds
);
1381 // check if pgp 2.6.x or 5.0 is installed
1382 // kpgp will prefer to user pgp 5.0
1384 Module::checkForPGP(void)
1388 QStringList pSearchPaths
;
1392 path
= QString::fromLocal8Bit( getenv("PATH") );
1393 pSearchPaths
= path
.split( KPATH_SEPARATOR
, QString::SkipEmptyParts
);
1398 foreach( const QString
& curPath
, pSearchPaths
)
1402 if ( QFileInfo(path
).isExecutable() )
1404 kDebug( 5326 ) <<"Kpgp: gpg found";
1411 // search for pgp5.0
1413 foreach( const QString
& curPath
, pSearchPaths
)
1417 if ( QFileInfo(path
).isExecutable() )
1419 kDebug( 5326 ) <<"Kpgp: pgp 5 found";
1426 // lets try pgp2.6.x
1428 foreach( const QString
& curPath
, pSearchPaths
)
1432 if ( QFileInfo(path
).isExecutable() )
1434 kDebug( 5326 ) <<"Kpgp: pgp 2 or 6 found";
1443 kDebug( 5326 ) <<"Kpgp: no pgp found";
1450 Module::assignPGPBase(void)
1460 kDebug( 5326 ) <<"Kpgp: assign pgp - gpg";
1465 kDebug( 5326 ) <<"Kpgp: assign pgp - pgp 2";
1470 kDebug( 5326 ) <<"Kpgp: assign pgp - pgp 5";
1475 kDebug( 5326 ) <<"Kpgp: assign pgp - pgp 6";
1481 kDebug( 5326 ) <<"Kpgp: pgpBase is dummy";
1486 kDebug( 5326 ) <<"Kpgp: assign pgp - auto";
1489 kDebug( 5326 ) <<"Kpgp: assign pgp - default";
1492 kDebug( 5326 ) <<"Kpgp: pgpBase is gpg";
1498 kDebug( 5326 ) <<"Kpgp: pgpBase is pgp 5";
1504 Base6
*pgp_v6
= new Base6();
1505 if (!pgp_v6
->isVersion6())
1507 kDebug( 5326 ) <<"Kpgp: pgpBase is pgp 2";
1514 kDebug( 5326 ) <<"Kpgp: pgpBase is pgp 6";
1524 kDebug( 5326 ) <<"Kpgp: pgpBase is dummy";
1531 Module::canonicalAddress( const QString
& _adress
)
1535 QString address
= _adress
.simplified();
1536 address
= address
.trimmed();
1538 // just leave pure e-mail address.
1539 if((index
= address
.indexOf("<")) != -1)
1540 if((index2
= address
.indexOf("@",index
+1)) != -1)
1541 if((index2
= address
.indexOf(">",index2
+1)) != -1)
1542 return address
.mid(index
,index2
-index
+1);
1544 if((index
= address
.indexOf("@")) == -1)
1547 //char hostname[1024];
1548 //gethostname(hostname,1024);
1549 //return "<" + address + "@" + hostname + ">";
1550 return '<' + address
+ "@localdomain>";
1554 int index1
= address
.lastIndexOf(" ",index
);
1555 int index2
= address
.indexOf(" ",index
);
1556 if(index2
== -1) index2
= address
.length();
1557 return '<' + address
.mid(index1
+1 ,index2
-index1
-1) + '>';
1562 Module::readPublicKeys( bool reread
)
1564 if( 0 == pgp
) assignPGPBase();
1568 qDeleteAll( mPublicKeys
);
1569 mPublicKeys
.clear();
1570 mPublicKeysCached
= false;
1574 if( !mPublicKeysCached
|| reread
)
1576 if( mPublicKeys
.isEmpty() )
1578 mPublicKeys
= pgp
->publicKeys();
1582 KeyList newPublicKeyList
= pgp
->publicKeys();
1584 // merge the trust info from the old key list into the new key list
1585 // FIXME: This is currently O(K^2) where K = #keys. As the key lists
1586 // are sorted this can be done in O(K).
1587 for( KeyList::Iterator it
= newPublicKeyList
.begin(); it
!= newPublicKeyList
.end(); ++it
)
1589 Key
* oldKey
= publicKey( (*it
)->primaryKeyID() );
1592 (*it
)->cloneKeyTrust( oldKey
);
1596 qDeleteAll( mPublicKeys
);
1597 mPublicKeys
= newPublicKeyList
;
1600 mPublicKeysCached
= true;
1605 Module::readSecretKeys( bool reread
)
1607 if( 0 == pgp
) assignPGPBase();
1611 qDeleteAll( mSecretKeys
);
1612 mSecretKeys
.clear();
1613 mSecretKeysCached
= false;
1617 if( mSecretKeys
.isEmpty() || reread
)
1619 if( mSecretKeys
.isEmpty() )
1621 mSecretKeys
= pgp
->secretKeys();
1625 KeyList newSecretKeyList
= pgp
->secretKeys();
1627 // merge the trust info from the old key list into the new key list
1628 // FIXME: This is currently O(K^2) where K = #keys. As the key lists
1629 // are sorted this can be done in O(K).
1630 for( KeyList::Iterator it
= newSecretKeyList
.begin(); it
!= newSecretKeyList
.end(); ++it
)
1632 Key
* oldKey
= secretKey( (*it
)->primaryKeyID() );
1635 (*it
)->cloneKeyTrust( oldKey
);
1639 qDeleteAll( mSecretKeys
);
1640 mSecretKeys
= newSecretKeyList
;
1643 mSecretKeysCached
= true;
1648 Module::selectKey( const KeyList
& keys
,
1649 const QString
& title
,
1650 const QString
& text
/*=QString() */ ,
1651 const KeyID
& keyId
/* = KeyID() */ ,
1652 const unsigned int allowedKeys
/* = AllKeys */ )
1654 KeyID retval
= KeyID();
1656 #ifndef QT_NO_TREEWIDGET
1657 KeySelectionDialog
dlg( keys
, title
, text
, KeyIDList( keyId
), false,
1658 allowedKeys
, false );
1660 #ifndef QT_NO_CURSOR
1661 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
1663 bool rej
= ( dlg
.exec() == QDialog::Rejected
);
1664 #ifndef QT_NO_CURSOR
1665 QApplication::restoreOverrideCursor();
1677 Module::selectKeys( const KeyList
& keys
,
1678 const QString
& title
,
1679 const QString
& text
/*=QString() */ ,
1680 const KeyIDList
& keyIds
/* = KeyIDList() */ ,
1681 const unsigned int allowedKeys
/* = AllKeys */ )
1683 KeyIDList retval
= KeyIDList();
1685 #ifndef QT_NO_TREEWIDGET
1686 KeySelectionDialog
dlg( keys
, title
, text
, keyIds
, false, allowedKeys
,
1689 #ifndef QT_NO_CURSOR
1690 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
1692 bool rej
= ( dlg
.exec() == QDialog::Rejected
);
1693 #ifndef QT_NO_CURSOR
1694 QApplication::restoreOverrideCursor();
1698 retval
= dlg
.keys();
1707 Module::selectKey( bool& rememberChoice
,
1708 const KeyList
& keys
,
1709 const QString
& title
,
1710 const QString
& text
/*=QString() */ ,
1711 const KeyID
& keyId
/* = KeyID() */ ,
1712 const unsigned int allowedKeys
/* = AllKeys */ )
1714 KeyID retval
= KeyID();
1716 #ifndef QT_NO_TREEWIDGET
1717 KeySelectionDialog
dlg( keys
, title
, text
, KeyIDList( keyId
), false,
1718 allowedKeys
, false );
1720 #ifndef QT_NO_CURSOR
1721 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
1723 bool rej
= ( dlg
.exec() == QDialog::Rejected
);
1724 #ifndef QT_NO_CURSOR
1725 QApplication::restoreOverrideCursor();
1730 rememberChoice
= dlg
.rememberSelection();
1733 rememberChoice
= false;
1741 Module::selectKeys( bool& rememberChoice
,
1742 const KeyList
& keys
,
1743 const QString
& title
,
1744 const QString
& text
/*=QString() */ ,
1745 const KeyIDList
& keyIds
/* = KeyIDList() */ ,
1746 const unsigned int allowedKeys
/* = AllKeys */ )
1748 KeyIDList retval
= KeyIDList();
1750 #ifndef QT_NO_TREEWIDGET
1751 KeySelectionDialog
dlg( keys
, title
, text
, keyIds
, true, allowedKeys
,
1754 #ifndef QT_NO_CURSOR
1755 QApplication::setOverrideCursor( QCursor(Qt::ArrowCursor
) );
1757 bool rej
= ( dlg
.exec() == QDialog::Rejected
);
1758 #ifndef QT_NO_CURSOR
1759 QApplication::restoreOverrideCursor();
1763 retval
= dlg
.keys();
1764 rememberChoice
= dlg
.rememberSelection();
1767 rememberChoice
= false;
1775 Module::keysForAddress( const QString
& address
)
1777 if( address
.isEmpty() ) {
1780 QString addr
= canonicalAddress( address
).toLower();
1781 if( addressDataDict
.contains( addr
) ) {
1782 return addressDataDict
[addr
].keyIds
;
1790 Module::setKeysForAddress( const QString
& address
, const KeyIDList
& keyIds
)
1792 if( address
.isEmpty() ) {
1795 QString addr
= canonicalAddress( address
).toLower();
1796 if( addressDataDict
.contains( addr
) ) {
1797 addressDataDict
[addr
].keyIds
= keyIds
;
1801 data
.encrPref
= UnknownEncryptPref
;
1802 data
.keyIds
= keyIds
;
1803 addressDataDict
.insert( addr
, data
);
1806 //writeAddressData();
1810 Module::readAddressData()
1815 KConfigGroup
general( config
, "General" );
1816 int num
= general
.readEntry( "addressEntries", 0 );
1818 addressDataDict
.clear();
1819 for( int i
=1; i
<=num
; i
++ ) {
1820 KConfigGroup
addrGroup( config
, QString("Address #%1").arg(i
) );
1821 address
= addrGroup
.readEntry( "Address" );
1822 data
.keyIds
= KeyIDList::fromStringList( addrGroup
.readEntry( "Key IDs" , QStringList() ) );
1823 data
.encrPref
= (EncryptPref
) addrGroup
.readEntry( "EncryptionPreference",
1824 int(UnknownEncryptPref
));
1825 // kDebug( 5326 ) <<"Read address" << i <<":" << address
1826 // << "\nKey IDs: 0x" << data.keyIds.toStringList().join(", 0x")
1827 // << "\nEncryption preference:" << data.encrPref;
1828 if ( !address
.isEmpty() ) {
1829 addressDataDict
.insert( address
, data
);
1835 Module::writeAddressData()
1837 KConfigGroup
general( config
, "General" );
1838 general
.writeEntry( "addressEntries", addressDataDict
.count() );
1841 AddressDataDict::Iterator it
;
1842 for ( i
=1, it
= addressDataDict
.begin();
1843 it
!= addressDataDict
.end();
1845 KConfigGroup
addrGroup( config
, QString("Address #%1").arg(i
));
1846 addrGroup
.writeEntry( "Address", it
.key() );
1847 addrGroup
.writeEntry( "Key IDs", it
.value().keyIds
.toStringList() );
1848 addrGroup
.writeEntry( "EncryptionPreference", (int)it
.value().encrPref
);
1855 Module::encryptionPreference( const QString
& address
)
1857 QString addr
= canonicalAddress( address
).toLower();
1858 if( addressDataDict
.contains( addr
) ) {
1859 return addressDataDict
[addr
].encrPref
;
1862 return UnknownEncryptPref
;
1867 Module::setEncryptionPreference( const QString
& address
,
1868 const EncryptPref pref
)
1870 if( address
.isEmpty() ) {
1873 QString addr
= canonicalAddress( address
).toLower();
1874 if( addressDataDict
.contains( addr
) ) {
1875 addressDataDict
[addr
].encrPref
= pref
;
1879 data
.encrPref
= pref
;
1880 addressDataDict
.insert( addr
, data
);