diff options
Diffstat (limited to 'libkpgp/kpgp.cpp')
-rw-r--r-- | libkpgp/kpgp.cpp | 1811 |
1 files changed, 1811 insertions, 0 deletions
diff --git a/libkpgp/kpgp.cpp b/libkpgp/kpgp.cpp new file mode 100644 index 000000000..d478d1999 --- /dev/null +++ b/libkpgp/kpgp.cpp @@ -0,0 +1,1811 @@ +/* -*- mode: C++; c-file-style: "gnu" -*- + kpgp.cpp + + Copyright (C) 2001,2002 the KPGP authors + See file AUTHORS.kpgp for details + + This file is part of KPGP, the KDE PGP/GnuPG support library. + + KPGP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <time.h> +#include <stdlib.h> +#include <assert.h> +#include <stdarg.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <signal.h> + +#include <qlabel.h> +#include <qcursor.h> +#include <qapplication.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kconfigbase.h> +#include <kconfig.h> +#include <kstaticdeleter.h> + +#include "kpgpbase.h" +#include "kpgpui.h" +#include "kpgp.h" + +namespace Kpgp { + +Module *Module::kpgpObject = 0L; +static KStaticDeleter<Module> kpgpod; + +Module::Module() + : mPublicKeys(), + mPublicKeysCached(false), + mSecretKeys(), + mSecretKeysCached(false), + passphrase(0), passphrase_buffer_len(0), havePassPhrase(false) +{ + if (!kpgpObject) { + kdDebug(5100) << "creating new pgp object" << endl; + } + kpgpObject=kpgpod.setObject(Module::kpgpObject, this); + pgp = 0; + + config = new KConfig("kpgprc"); + + init(); +} + +Module::~Module() +{ + writeAddressData(); + + if (kpgpObject == this) kpgpObject = kpgpod.setObject( Module::kpgpObject, 0, false ); + clear(TRUE); + delete config; + delete pgp; +} + +// ----------------- public methods ------------------------- + +void +Module::init() +{ + wipePassPhrase(); + + // read kpgp config file entries + readConfig(); + + // read the email address -> { encryption keys, encryption preference } + // associations + readAddressData(); + + // do we have a pgp executable + checkForPGP(); + + // create the Base object later when it is + // needed to avoid the costly check done for + // the autodetection of PGP 2/6 + //assignPGPBase(); + delete pgp; + pgp=0; +} + + +void +Module::readConfig() +{ + storePass = config->readBoolEntry("storePass", false); + showEncryptionResult = config->readBoolEntry("showEncryptionResult", true); + mShowKeyApprovalDlg = config->readBoolEntry( "showKeysForApproval", true ); + // We have no config GUI for this key anymore, and the KPGP backend isn't ported, + // so let's just use Auto all the time. See #92619. + ///pgpType = (Module::PGPType) config->readNumEntry("pgpType", tAuto); + pgpType = tAuto; + flagEncryptToSelf = config->readBoolEntry("encryptToSelf", true); +} + +void +Module::writeConfig(bool sync) +{ + config->writeEntry("storePass", storePass); + config->writeEntry("showEncryptionResult", showEncryptionResult); + config->writeEntry( "showKeysForApproval", mShowKeyApprovalDlg ); + //config->writeEntry("pgpType", (int) pgpType); + config->writeEntry("encryptToSelf", flagEncryptToSelf); + + if(sync) + config->sync(); + + /// ### Why is the pgp object deleted? This is only necessary if the + /// PGP type was changed in the config dialog. + delete pgp; + pgp = 0; +} + + +void +Module::setUser(const KeyID& keyID) +{ + if (pgpUser != keyID) { + pgpUser = keyID; + wipePassPhrase(); + } +} + +const KeyID +Module::user(void) const +{ + return pgpUser; +} + + +void +Module::setEncryptToSelf(bool flag) +{ + flagEncryptToSelf = flag; +} + +bool +Module::encryptToSelf(void) const +{ + return flagEncryptToSelf; +} + + +void +Module::setStorePassPhrase(bool flag) +{ + storePass = flag; +} + +bool +Module::storePassPhrase(void) const +{ + return storePass; +} + +int +Module::prepare( bool needPassPhrase, Block* block ) +{ + if (0 == pgp) assignPGPBase(); + + if(!havePgp) + { + errMsg = i18n("Could not find PGP executable.\n" + "Please check your PATH is set correctly."); + return 0; + } + + if( block && ( block->status() & NO_SEC_KEY ) ) + return 0; + + if(needPassPhrase && !havePassPhrase) { + if( ( tGPG == pgpType ) && ( 0 != getenv("GPG_AGENT_INFO") ) ) { + // the user uses gpg-agent which asks itself for the passphrase + kdDebug(5100) << "user uses gpg-agent -> don't ask for passphrase\n"; + // set dummy passphrase (because else signing doesn't work -> FIXME) + setPassPhrase( "dummy" ); + } + else { + QString ID; + if( block ) + ID = block->requiredUserId(); + PassphraseDialog passdlg(0, i18n("OpenPGP Security Check"), true, ID); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int passdlgResult = passdlg.exec(); + QApplication::restoreOverrideCursor(); + if (passdlgResult == QDialog::Accepted) { + if (!setPassPhrase(passdlg.passphrase())) { + if (strlen(passdlg.passphrase()) >= 1024) + errMsg = i18n("Passphrase is too long, it must contain fewer than 1024 characters."); + else + errMsg = i18n("Out of memory."); + return 0; + } + } else { + wipePassPhrase(); + return -1; + } + } + } + return 1; +} + +void +Module::wipePassPhrase(bool freeMem) +{ + if ( passphrase ) { + if ( passphrase_buffer_len ) + memset( passphrase, 0x00, passphrase_buffer_len ); + else { + kdDebug(5100) << "wipePassPhrase: passphrase && !passphrase_buffer_len ???" << endl; + passphrase = 0; + } + } + if ( freeMem && passphrase ) { + free( passphrase ); + passphrase = 0; + passphrase_buffer_len = 0; + } + havePassPhrase = false; +} + +bool +Module::verify( Block& block ) +{ + int retval; + + if (0 == pgp) assignPGPBase(); + + // everything ready + if( !prepare( false, &block ) ) + return false; + // ok now try to verify the message. + retval = pgp->verify( block ); + + if(retval & ERROR) + { + errMsg = pgp->lastErrorMessage(); + return false; + } + return true; +} + +bool +Module::decrypt( Block& block ) +{ + int retval; + + if (0 == pgp) assignPGPBase(); + + do { + // loop as long as the user enters a wrong passphrase and doesn't abort + // everything ready + if( prepare( true, &block ) != 1 ) + return FALSE; + // ok now try to decrypt the message. + retval = pgp->decrypt( block, passphrase ); + // loop on bad passphrase + if( retval & BADPHRASE ) { + wipePassPhrase(); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int ret = KMessageBox::warningContinueCancel(0, + i18n("You just entered an invalid passphrase.\n" + "Do you want to try again, or " + "cancel and view the message undecrypted?"), + i18n("PGP Warning"), i18n("&Retry")); + QApplication::restoreOverrideCursor(); + if ( ret == KMessageBox::Cancel ) break; + } else + break; + } while ( true ); + + // erase the passphrase if we do not want to keep it + cleanupPass(); + + if(retval & ERROR) + { + errMsg = pgp->lastErrorMessage(); + return false; + } + return true; +} + +Kpgp::Result +Module::clearsign( Block& block, + const KeyID& keyId, const QCString& charset ) +{ + return encrypt( block, QStringList(), keyId, true, charset ); +} + +Kpgp::Result +Module::encrypt( Block& block, + const QStringList& receivers, const KeyID& keyId, + bool sign, const QCString& charset ) +{ + KeyIDList encryptionKeyIds; // list of keys which are used for encryption + int status = 0; + errMsg = ""; + + if( 0 == pgp ) assignPGPBase(); + + setUser( keyId ); + + if( !receivers.empty() ) { + Kpgp::Result result = getEncryptionKeys( encryptionKeyIds, receivers, + keyId ); + if( Kpgp::Ok != result ) { + return result; + } + } + + status = doEncSign( block, encryptionKeyIds, sign ); + + if( status & CANCEL ) + return Kpgp::Canceled; + + // check for bad passphrase + while( status & BADPHRASE ) { + wipePassPhrase(); + QString str = i18n("You entered an invalid passphrase.\n" + "Do you want to try again, continue and leave the " + "message unsigned, or cancel sending the message?"); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int ret = KMessageBox::warningYesNoCancel( 0, str, + i18n("PGP Warning"), + i18n("&Retry"), + i18n("Send &Unsigned") ); + QApplication::restoreOverrideCursor(); + if( ret == KMessageBox::Cancel ) { + return Kpgp::Canceled; + } + if( ret == KMessageBox::No ) { + // the user selected "Send unsigned" + if( encryptionKeyIds.isEmpty() ) { + block.reset(); + return Kpgp::Ok; + } + else { + sign = false; + } + } + // ok let's try once again... + status = doEncSign( block, encryptionKeyIds, sign ); + } + + // did signing fail? + if( status & ERR_SIGNING ) { + QString str = i18n("%1 = 'signing failed' error message", + "%1\nDo you want to send the message unsigned, " + "or cancel sending the message?") + .arg( pgp->lastErrorMessage() ); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int ret = KMessageBox::warningContinueCancel( 0, str, + i18n("PGP Warning"), + i18n("Send &Unsigned") ); + QApplication::restoreOverrideCursor(); + if( ret == KMessageBox::Cancel ) { + return Kpgp::Canceled; + } + sign = false; + status = doEncSign( block, encryptionKeyIds, sign ); + } + + // check for bad keys + if( status & BADKEYS ) { + QString str = i18n("%1 = 'bad keys' error message", + "%1\nDo you want to encrypt anyway, leave the " + "message as-is, or cancel sending the message?") + .arg( pgp->lastErrorMessage() ); + + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int ret = KMessageBox::warningYesNoCancel( 0, str, + i18n("PGP Warning"), + i18n("Send &Encrypted"), + i18n("Send &Unencrypted") ); + QApplication::restoreOverrideCursor(); + if( ret == KMessageBox::Cancel ) { + return Kpgp::Canceled; + } + if( ret == KMessageBox::No ) { + // the user selected "Send unencrypted" + if( sign ) { + doEncSign( block, KeyIDList(), sign ); + } + else { + block.reset(); + } + return Kpgp::Ok; + } + } + + if( status & MISSINGKEY ) { + QString str = i18n("%1 = 'missing keys' error message", + "%1\nDo you want to leave the message as-is, " + "or cancel sending the message?") + .arg( pgp->lastErrorMessage() ); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int ret = KMessageBox::warningContinueCancel( 0, str, + i18n("PGP Warning"), + i18n("&Send As-Is") ); + QApplication::restoreOverrideCursor(); + if( ret == KMessageBox::Cancel ) { + return Kpgp::Canceled; + } + block.reset(); + return Kpgp::Ok; + } + + if( status & ERROR ) { + // show error dialog + errMsg = i18n( "The following error occurred:\n%1" ) + .arg( pgp->lastErrorMessage() ); + QString details = i18n( "This is the error message of %1:\n%2" ) + .arg( ( pgpType == tGPG ) ? "GnuPG" : "PGP" ) + .arg( block.error().data() ); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + KMessageBox::detailedSorry( 0, errMsg, details ); + QApplication::restoreOverrideCursor(); + return Kpgp::Failure; + } + + if( showCipherText() ) { + // show cipher text dialog + CipherTextDialog *cipherTextDlg = new CipherTextDialog( block.text(), charset ); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + bool result = ( cipherTextDlg->exec() == QDialog::Accepted ); + QApplication::restoreOverrideCursor(); + delete cipherTextDlg; + return result == QDialog::Accepted ? Kpgp::Ok : Kpgp::Canceled; + } + return Kpgp::Ok; +} + +int +Module::doEncSign( Block& block, + const KeyIDList& recipientKeyIds, bool sign ) +{ + int retval = 0; + + if( 0 == pgp ) assignPGPBase(); + + // to avoid error messages in case pgp is not installed + if( !havePgp ) return OK; + + if( sign ) { + int result = prepare( true, &block ); + switch( result ) { + case -1: + return CANCEL; + case 0: + return ERROR; + } + retval = pgp->encsign( block, recipientKeyIds, passphrase ); + } + else { + if( !prepare( false, &block ) ) return ERROR; + retval = pgp->encrypt( block, recipientKeyIds ); + } + // erase the passphrase if we do not want to keep it + cleanupPass(); + + return retval; +} + +Kpgp::Result +Module::getEncryptionKeys( KeyIDList& encryptionKeyIds, + const QStringList& recipients, + const KeyID& keyId ) +{ + if( recipients.empty() ) { + encryptionKeyIds.clear(); + return Kpgp::Ok; + } + + // list of lists of encryption keys (one list per recipient + one list + // for the sender) + QValueVector<KeyIDList> recipientKeyIds( recipients.count() + 1 ); + // add the sender's encryption key(s) to the list of recipient key IDs + if( encryptToSelf() ) { + recipientKeyIds[0] = KeyIDList( keyId ); + } + else { + recipientKeyIds[0] = KeyIDList(); + } + bool showKeysForApproval = false; + int i = 1; + for( QStringList::ConstIterator it = recipients.begin(); + it != recipients.end(); ++it, ++i ) { + EncryptPref encrPref = encryptionPreference( *it ); + if( ( encrPref == UnknownEncryptPref ) || ( encrPref == NeverEncrypt ) ) + showKeysForApproval = true; + + KeyIDList keyIds = getEncryptionKeys( *it ); + if( keyIds.isEmpty() ) { + showKeysForApproval = true; + } + recipientKeyIds[i] = keyIds; + } + + kdDebug(5100) << "recipientKeyIds = (\n"; + QValueVector<KeyIDList>::const_iterator kit; + for( kit = recipientKeyIds.begin(); kit != recipientKeyIds.end(); ++kit ) { + kdDebug(5100) << "( 0x" << (*kit).toStringList().join( ", 0x" ) + << " ),\n"; + } + kdDebug(5100) << ")\n"; + + if( showKeysForApproval || mShowKeyApprovalDlg ) { + // #### FIXME: Until we support encryption with untrusted keys only + // #### trusted keys are allowed + unsigned int allowedKeys = PublicKeys | EncryptionKeys | ValidKeys | TrustedKeys; +#if 0 + // ### reenable this code when we support encryption with untrusted keys + if( pgpType != tGPG ) { + // usage of untrusted keys is only possible with GnuPG + allowedKeys |= TrustedKeys; + } +#endif + // show the recipients <-> key relation + KeyApprovalDialog dlg( recipients, recipientKeyIds, allowedKeys ); + + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int ret = dlg.exec(); + + if( ret == QDialog::Rejected ) { + QApplication::restoreOverrideCursor(); + return Kpgp::Canceled; + } + + recipientKeyIds = dlg.keys(); + QApplication::restoreOverrideCursor(); + } + + // flatten the list of lists of key IDs and count empty key ID lists + unsigned int emptyListCount = 0; + for( QValueVector<KeyIDList>::const_iterator it = recipientKeyIds.begin(); + it != recipientKeyIds.end(); ++it ) { + if( (*it).isEmpty() ) { + // only count empty key ID lists for the recipients + if( it != recipientKeyIds.begin() ) { + emptyListCount++; + } + } + else { + for( KeyIDList::ConstIterator kit = (*it).begin(); + kit != (*it).end(); kit++ ) { + encryptionKeyIds.append( *kit ); + } + } + } + + // FIXME-AFTER-KDE-3.1: Show warning if message won't be encrypted to self + + // show a warning if the user didn't select an encryption key for + // some of the recipients + if( recipientKeyIds.size() == emptyListCount + 1 ) { // (+1 because of the sender's key) + QString str = ( recipients.count() == 1 ) + ? i18n("You did not select an encryption key for the " + "recipient of this message; therefore, the message " + "will not be encrypted.") + : i18n("You did not select an encryption key for any of the " + "recipients of this message; therefore, the message " + "will not be encrypted."); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int ret = KMessageBox::warningContinueCancel( 0, str, + i18n("PGP Warning"), + i18n("Send &Unencrypted") ); + QApplication::restoreOverrideCursor(); + if( ret == KMessageBox::Cancel ) { + return Kpgp::Canceled; + } + else + encryptionKeyIds.clear(); + } + else if( emptyListCount > 0 ) { + QString str = ( emptyListCount == 1 ) + ? i18n("You did not select an encryption key for one of " + "the recipients; this person will not be able to " + "decrypt the message if you encrypt it.") + : i18n("You did not select encryption keys for some of " + "the recipients; these persons will not be able to " + "decrypt the message if you encrypt it." ); + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + int ret = KMessageBox::warningYesNoCancel( 0, str, + i18n("PGP Warning"), + i18n("Send &Encrypted"), + i18n("Send &Unencrypted") ); + QApplication::restoreOverrideCursor(); + if( ret == KMessageBox::Cancel ) { + return Kpgp::Canceled; + } + else if( ret == KMessageBox::No ) { + // the user selected "Send unencrypted" + encryptionKeyIds.clear(); + } + } + + return Kpgp::Ok; +} + +int +Module::encryptionPossible( const QStringList& recipients ) +{ + if( 0 == pgp ) assignPGPBase(); + + if( !usePGP() ) + return 0; + + if( recipients.empty() ) + return 0; + + int noKey = 0, never = 0, unknown = 0, always = 0, aip = 0, ask = 0, + askwp = 0; + for( QStringList::ConstIterator it = recipients.begin(); + it != recipients.end(); ++it) { + if( haveTrustedEncryptionKey( *it ) ) { + EncryptPref encrPref = encryptionPreference( *it ); + switch( encrPref ) { + case NeverEncrypt: + never++; + break; + case UnknownEncryptPref: + unknown++; + break; + case AlwaysEncrypt: + always++; + break; + case AlwaysEncryptIfPossible: + aip++; + break; + case AlwaysAskForEncryption: + ask++; + break; + case AskWheneverPossible: + askwp++; + break; + } + } + else { + noKey++; + } + } + + if( ( always+aip > 0 ) && ( never+unknown+ask+askwp+noKey == 0 ) ) { + return 1; // encryption possible and desired + } + + if( ( unknown+ask+askwp > 0 ) && ( never+noKey == 0 ) ) { + return 2; // encryption possible, but user has to be asked + } + + if( ( never+noKey > 0 ) && ( always+ask == 0 ) ) { + return 0; // encryption isn't possible or desired + } + + return -1; // we can't decide it automatically +} + +bool +Module::signKey(const KeyID& keyId) +{ + if (0 == pgp) assignPGPBase(); + + if( prepare( true ) != 1 ) + return FALSE; + if(pgp->signKey(keyId, passphrase) & ERROR) + { + errMsg = pgp->lastErrorMessage(); + return false; + } + return true; +} + + +const KeyList +Module::publicKeys() +{ + if (0 == pgp) assignPGPBase(); + + if (!prepare()) return KeyList(); + + if( !mPublicKeysCached ) { + readPublicKeys(); + } + + return mPublicKeys; +} + + +const KeyList +Module::secretKeys() +{ + if (0 == pgp) assignPGPBase(); + + if (!prepare()) return KeyList(); + + if( !mSecretKeysCached ) { + readSecretKeys(); + } + + return mSecretKeys; +} + + +Key* +Module::publicKey(const KeyID& keyID) +{ + readPublicKeys(); + + for( KeyListIterator it( mPublicKeys ); (*it); ++it ) + if( keyID == (*it)->primaryKeyID() || + keyID == (*it)->primaryFingerprint() ) + return (*it); + + return 0; +} + +Key* +Module::publicKey( const QString& userID ) +{ + readPublicKeys(); + + for( KeyListIterator it( mPublicKeys ); (*it); ++it ) + if( (*it)->matchesUserID( userID ) ) + return (*it); + + return 0; +} + +Key* +Module::secretKey(const KeyID& keyID) +{ + readSecretKeys(); + + for( KeyListIterator it( mSecretKeys ); (*it); ++it ) + if( keyID == (*it)->primaryKeyID() || + keyID == (*it)->primaryFingerprint() ) + return (*it); + + return 0; +} + +Validity +Module::keyTrust( const KeyID& keyID ) +{ + Key *key = publicKey( keyID ); + + if( ( 0 == key ) || ( key->keyTrust() == KPGP_VALIDITY_UNKNOWN ) ) + { // (re)check the key if it's unknown or if its trust is unknown + key = rereadKey( keyID, true ); + if( key == 0 ) + return KPGP_VALIDITY_UNKNOWN; + } + + return key->keyTrust(); +} + +Validity +Module::keyTrust( const QString& userID ) +{ + Key *key = publicKey( userID ); + + if( key == 0 ) + return KPGP_VALIDITY_UNKNOWN; + + if( key->keyTrust() == KPGP_VALIDITY_UNKNOWN ) + { + key = rereadKey( key->primaryKeyID(), true ); + if( key == 0 ) + return KPGP_VALIDITY_UNKNOWN; + } + + return key->keyTrust(); +} + +bool +Module::isTrusted( const KeyID& keyID ) +{ + return ( keyTrust( keyID ) >= KPGP_VALIDITY_MARGINAL ); +} + +Key* +Module::rereadKey( const KeyID& keyID, const bool readTrust /* = true */ ) +{ + if( 0 == pgp ) assignPGPBase(); + + // search the old key data in the key list + Key* oldKey = publicKey( keyID ); + + Key* newKey = pgp->readPublicKey( keyID, readTrust, oldKey ); + + if( ( 0 == oldKey ) && ( 0 != newKey ) ) + { + mPublicKeys.inSort( newKey ); + kdDebug(5100) << "New public key 0x" << newKey->primaryKeyID() << " (" + << newKey->primaryUserID() << ").\n"; + } + else if( ( 0 != oldKey ) && ( 0 == newKey ) ) + { // the key has been deleted in the meantime + kdDebug(5100) << "Public key 0x" << oldKey->primaryKeyID() << " (" + << oldKey->primaryUserID() << ") will be removed.\n"; + mPublicKeys.removeRef( oldKey ); + } + + return newKey; +} + +QCString +Module::getAsciiPublicKey(const KeyID& keyID) +{ + if (0 == pgp) assignPGPBase(); + + return pgp->getAsciiPublicKey(keyID); +} + + +bool Module::setPassPhrase(const char * aPass) +{ + // null out old buffer before we touch the new string. So in case + // aPass isn't properly null-terminated, we don't leak secret data. + wipePassPhrase(); + + if (aPass) + { + size_t newlen = strlen( aPass ); + if ( newlen >= 1024 ) { + // rediculously long passphrase. + // Maybe someone wants to trick us in malloc()'ing + // huge buffers... + return false; + } + if ( passphrase_buffer_len < newlen + 1 ) { + // too little space in current buffer: + // allocate a larger one. + if ( passphrase ) + free( passphrase ); + passphrase_buffer_len = (newlen + 1 + 15) & ~0xF; // make it a multiple of 16. + passphrase = (char*)malloc( passphrase_buffer_len ); + if (!passphrase) { + passphrase_buffer_len = 0; + return false; + } + } + memcpy( passphrase, aPass, newlen + 1 ); + havePassPhrase = true; + } + return true; +} + +bool +Module::changePassPhrase() +{ + //FIXME... + KMessageBox::information(0,i18n("This feature is\nstill missing")); + return FALSE; +} + +void +Module::clear(const bool erasePassPhrase) +{ + if(erasePassPhrase) + wipePassPhrase(true); +} + +const QString +Module::lastErrorMsg(void) const +{ + return errMsg; +} + +bool +Module::havePGP(void) const +{ + return havePgp; +} + +void +Module::setShowCipherText(const bool flag) +{ + showEncryptionResult = flag; +} + +bool +Module::showCipherText(void) const +{ + return showEncryptionResult; +} + +KeyID +Module::selectSecretKey( const QString& title, + const QString& text, + const KeyID& keyId ) +{ + if( 0 == pgp ) { + assignPGPBase(); + } + + if( usePGP() ) { + return selectKey( secretKeys(), title, text, keyId, SecretKeys ); + } + else { + KMessageBox::sorry( 0, i18n("You either do not have GnuPG/PGP installed " + "or you chose not to use GnuPG/PGP.") ); + return KeyID(); + } +} + +KeyID +Module::selectPublicKey( const QString& title, + const QString& text /* = QString::null */, + const KeyID& oldKeyId /* = KeyID() */, + const QString& address /* = QString::null */, + const unsigned int allowedKeys /* = AllKeys */ ) +{ + if( 0 == pgp ) { + assignPGPBase(); + } + + if( usePGP() ) { + KeyID keyId; + + if( address.isEmpty() ) { + keyId = selectKey( publicKeys(), title, text, oldKeyId, allowedKeys ); + } + else { + bool rememberChoice; + keyId = selectKey( rememberChoice, publicKeys(), title, text, oldKeyId, + allowedKeys ); + if( !keyId.isEmpty() && rememberChoice ) { + setKeysForAddress( address, KeyIDList( keyId ) ); + } + } + + return keyId; + } + else { + KMessageBox::sorry( 0, i18n("You either do not have GnuPG/PGP installed " + "or you chose not to use GnuPG/PGP.") ); + return KeyID(); + } +} + + +KeyIDList +Module::selectPublicKeys( const QString& title, + const QString& text /* = QString::null */, + const KeyIDList& oldKeyIds /* = KeyIDList() */, + const QString& address /* = QString::null */, + const unsigned int allowedKeys /* = AllKeys */ ) +{ + if( 0 == pgp ) { + assignPGPBase(); + } + + if( usePGP() ) { + KeyIDList keyIds; + + if( address.isEmpty() ) { + keyIds = selectKeys( publicKeys(), title, text, oldKeyIds, allowedKeys ); + } + else { + bool rememberChoice; + keyIds = selectKeys( rememberChoice, publicKeys(), title, text, + oldKeyIds, allowedKeys ); + if( !keyIds.isEmpty() && rememberChoice ) { + setKeysForAddress( address, keyIds ); + } + } + + return keyIds; + } + else { + KMessageBox::sorry( 0, i18n("You either do not have GnuPG/PGP installed " + "or you chose not to use GnuPG/PGP.") ); + return KeyIDList(); + } +} + + +// -- static member functions ---------------------------------------------- + +Module * +Module::getKpgp() +{ + if (!kpgpObject) + { + kdError(5100) << "there is no instance of kpgp available" << endl; + } + return kpgpObject; +} + + +KConfig * +Module::getConfig() +{ + return getKpgp()->config; +} + + +bool +Module::prepareMessageForDecryption( const QCString& msg, + QPtrList<Block>& pgpBlocks, + QStrList& nonPgpBlocks ) +{ + BlockType pgpBlock = NoPgpBlock; + int start = -1; // start of the current PGP block + int lastEnd = -1; // end of the last PGP block + + pgpBlocks.setAutoDelete( true ); + pgpBlocks.clear(); + nonPgpBlocks.setAutoDelete( true ); + nonPgpBlocks.clear(); + + if( msg.isEmpty() ) + { + nonPgpBlocks.append( "" ); + return false; + } + + if( !strncmp( msg.data(), "-----BEGIN PGP ", 15 ) ) + start = 0; + else + { + start = msg.find( "\n-----BEGIN PGP" ) + 1; + if( start == 0 ) + { + nonPgpBlocks.append( msg ); + return false; // message doesn't contain an OpenPGP block + } + } + + while( start != -1 ) + { + int nextEnd, nextStart; + + // is the PGP block a clearsigned block? + if( !strncmp( msg.data() + start + 15, "SIGNED", 6 ) ) + pgpBlock = ClearsignedBlock; + else + pgpBlock = UnknownBlock; + + nextEnd = msg.find( "\n-----END PGP", start + 15 ); + if( nextEnd == -1 ) + { + nonPgpBlocks.append( msg.mid( lastEnd+1 ) ); + break; + } + nextStart = msg.find( "\n-----BEGIN PGP", start + 15 ); + + if( ( nextStart == -1 ) || ( nextEnd < nextStart ) || + ( pgpBlock == ClearsignedBlock ) ) + { // most likely we found a PGP block (but we don't check if it's valid) + // store the preceding non-PGP block + nonPgpBlocks.append( msg.mid( lastEnd+1, start-lastEnd-1 ) ); + lastEnd = msg.find( "\n", nextEnd + 14 ); + if( lastEnd == -1 ) + { + pgpBlocks.append( new Block( msg.mid( start ) ) ); + nonPgpBlocks.append( "" ); + break; + } + else + { + pgpBlocks.append( new Block( msg.mid( start, lastEnd+1-start ) ) ); + if( ( nextStart != -1 ) && ( nextEnd > nextStart ) ) + nextStart = msg.find( "\n-----BEGIN PGP", lastEnd+1 ); + } + } + + start = nextStart; + if( start == -1 ) + nonPgpBlocks.append( msg.mid( lastEnd+1 ) ); + else + start++; // move start behind the '\n' + } + + return ( !pgpBlocks.isEmpty() ); +} + + +// --------------------- private functions ------------------- + +bool +Module::haveTrustedEncryptionKey( const QString& person ) +{ + if( 0 == pgp ) assignPGPBase(); + + if( !usePGP() ) return false; + + readPublicKeys(); + + QString address = canonicalAddress( person ).lower(); + + // First look for this person's address in the address data dictionary + KeyIDList keyIds = keysForAddress( address ); + if( !keyIds.isEmpty() ) { + // Check if at least one of the keys is a trusted and valid encryption key + for( KeyIDList::ConstIterator it = keyIds.begin(); + it != keyIds.end(); ++it ) { + keyTrust( *it ); // this is called to make sure that the trust info + // for this key is read + Key *key = publicKey( *it ); + if( key && ( key->isValidEncryptionKey() ) && + ( key->keyTrust() >= KPGP_VALIDITY_MARGINAL ) ) + return true; + } + } + + // Now search the public keys for matching keys + KeyListIterator it( mPublicKeys ); + + // search a key which matches the complete address + for( it.toFirst(); (*it); ++it ) { + // search case insensitively in the list of userIDs of this key + if( (*it)->matchesUserID( person, false ) ) { + keyTrust( (*it)->primaryKeyID() ); // this is called to make sure that + // the trust info for this key is read + if( ( (*it)->isValidEncryptionKey() ) && + ( (*it)->keyTrust() >= KPGP_VALIDITY_MARGINAL ) ) { + return true; + } + } + } + + // if no key matches the complete address look for a key which matches + // the canonical mail address + for( it.toFirst(); (*it); ++it ) { + // search case insensitively in the list of userIDs of this key + if( (*it)->matchesUserID( address, false ) ) { + keyTrust( (*it)->primaryKeyID() ); // this is called to make sure that + // the trust info for this key is read + if( ( (*it)->isValidEncryptionKey() ) && + ( (*it)->keyTrust() >= KPGP_VALIDITY_MARGINAL ) ) { + return true; + } + } + } + + // no trusted encryption key was found for the given person + return false; +} + +KeyIDList +Module::getEncryptionKeys( const QString& person ) +{ + if( 0 == pgp ) assignPGPBase(); + + if( !usePGP() ) return KeyIDList(); + + readPublicKeys(); + + QString address = canonicalAddress( person ).lower(); + + // #### FIXME: Until we support encryption with untrusted keys only + // #### trusted keys are allowed + unsigned int allowedKeys = PublicKeys | EncryptionKeys | ValidKeys | TrustedKeys; +#if 0 + // ### reenable this code when we support encryption with untrusted keys + if( pgpType != tGPG ) { + // usage of untrusted keys is only possible with GnuPG + allowedKeys |= TrustedKeys; + } +#endif + + // First look for this person's address in the address->key dictionary + KeyIDList keyIds = keysForAddress( address ); + if( !keyIds.isEmpty() ) { + kdDebug(5100) << "Using encryption keys 0x" + << keyIds.toStringList().join( ", 0x" ) + << " for " << person << endl; + // Check if all of the keys are a trusted and valid encryption keys + bool keysOk = true; + for( KeyIDList::ConstIterator it = keyIds.begin(); + it != keyIds.end(); ++it ) { + keyTrust( *it ); // this is called to make sure that the trust info + // for this key is read + Key *key = publicKey( *it ); + if( !( key && ( key->isValidEncryptionKey() ) && + ( key->keyTrust() >= KPGP_VALIDITY_MARGINAL ) ) ) + keysOk = false; + } + if( keysOk ) { + return keyIds; + } + else { + bool rememberChoice; + keyIds = selectKeys( rememberChoice, mPublicKeys, + i18n("Encryption Key Selection"), + i18n("if in your language something like " + "'key(s)' isn't possible please " + "use the plural in the translation", + "There is a problem with the " + "encryption key(s) for \"%1\".\n\n" + "Please re-select the key(s) which should " + "be used for this recipient." + ).arg(person), + keyIds, + allowedKeys ); + if( !keyIds.isEmpty() ) { + if( rememberChoice ) { + setKeysForAddress( person, keyIds ); + } + return keyIds; + } + } + } + + // Now search all public keys for matching keys + KeyListIterator it( mPublicKeys ); + KeyList matchingKeys; + + // search all keys which match the complete address + kdDebug(5100) << "Looking for keys matching " << person << " ...\n"; + for( it.toFirst(); (*it); ++it ) { + // search case insensitively in the list of userIDs of this key + if( (*it)->matchesUserID( person, false ) ) { + keyTrust( (*it)->primaryKeyID() ); // this is called to make sure that + // the trust info for this key is read + if( ( (*it)->isValidEncryptionKey() ) && + ( (*it)->keyTrust() >= KPGP_VALIDITY_MARGINAL ) ) { + kdDebug(5100) << "Matching trusted key found: " + << (*it)->primaryKeyID() << endl; + matchingKeys.append( *it ); + } + } + } + + // if no keys match the complete address look for keys which match + // the canonical mail address + kdDebug(5100) << "Looking for keys matching " << address << " ...\n"; + if( matchingKeys.isEmpty() ) { + for ( it.toFirst(); (*it); ++it ) { + // search case insensitively in the list of userIDs of this key + if( (*it)->matchesUserID( address, false ) ) { + keyTrust( (*it)->primaryKeyID() ); // this is called to make sure that + // the trust info for this key is read + if( ( (*it)->isValidEncryptionKey() ) && + ( (*it)->keyTrust() >= KPGP_VALIDITY_MARGINAL ) ) { + kdDebug(5100) << "Matching trusted key found: " + << (*it)->primaryKeyID() << endl; + matchingKeys.append( *it ); + } + } + } + } + + // no match until now, let the user choose the key + if( matchingKeys.isEmpty() ) { + // FIXME: let user get the key from keyserver + bool rememberChoice; + KeyIDList keyIds = selectKeys( rememberChoice, mPublicKeys, + i18n("Encryption Key Selection"), + i18n("if in your language something like " + "'key(s)' isn't possible please " + "use the plural in the translation", + "No valid and trusted OpenPGP key was " + "found for \"%1\".\n\n" + "Select the key(s) which should " + "be used for this recipient." + ).arg(person), + KeyIDList(), + allowedKeys ); + if( !keyIds.isEmpty() ) { + if( rememberChoice ) { + setKeysForAddress( person, keyIds ); + } + return keyIds; + } + } + // only one key matches + else if( matchingKeys.count() == 1 ) { + return KeyIDList( matchingKeys.getFirst()->primaryKeyID() ); + } + // more than one key matches; let the user choose the key(s) + else { + bool rememberChoice; + KeyIDList keyIds = selectKeys( rememberChoice, matchingKeys, + i18n("Encryption Key Selection"), + i18n("if in your language something like " + "'key(s)' isn't possible please " + "use the plural in the translation", + "More than one key matches \"%1\".\n\n" + "Select the key(s) which should " + "be used for this recipient." + ).arg(person), + KeyIDList(), + allowedKeys ); + if( !keyIds.isEmpty() ) { + if( rememberChoice ) { + setKeysForAddress( person, keyIds ); + } + return keyIds; + } + } + + return KeyIDList(); +} + +// check if pgp 2.6.x or 5.0 is installed +// kpgp will prefer to user pgp 5.0 +bool +Module::checkForPGP(void) +{ + // get path + QCString path; + QStrList pSearchPaths; + int index = 0; + int lastindex = -1; + + havePgp=FALSE; + + path = getenv("PATH"); + while((index = path.find(":",lastindex+1)) != -1) + { + pSearchPaths.append(path.mid(lastindex+1,index-lastindex-1)); + lastindex = index; + } + if(lastindex != (int)path.length() - 1) + pSearchPaths.append( path.mid(lastindex+1,path.length()-lastindex) ); + + QStrListIterator it(pSearchPaths); + + haveGpg=FALSE; + // lets try gpg + + for ( it.toFirst() ; it.current() ; ++it ) + { + path = (*it); + path += "/gpg"; + if ( !access( path, X_OK ) ) + { + kdDebug(5100) << "Kpgp: gpg found" << endl; + havePgp=TRUE; + haveGpg=TRUE; + break; + } + } + + // search for pgp5.0 + havePGP5=FALSE; + for ( it.toFirst() ; it.current() ; ++it ) + { + path = (*it); + path += "/pgpe"; + if ( !access( path, X_OK ) ) + { + kdDebug(5100) << "Kpgp: pgp 5 found" << endl; + havePgp=TRUE; + havePGP5=TRUE; + break; + } + } + + // lets try pgp2.6.x + if (!havePgp) { + for ( it.toFirst() ; it.current() ; ++it ) + { + path = it.current(); + path += "/pgp"; + if ( !access( path, X_OK ) ) + { + kdDebug(5100) << "Kpgp: pgp 2 or 6 found" << endl; + havePgp=TRUE; + break; + } + } + } + + if (!havePgp) + { + kdDebug(5100) << "Kpgp: no pgp found" << endl; + } + + return havePgp; +} + +void +Module::assignPGPBase(void) +{ + if (pgp) + delete pgp; + + if(havePgp) + { + switch (pgpType) + { + case tGPG: + kdDebug(5100) << "Kpgp: assign pgp - gpg" << endl; + pgp = new BaseG(); + break; + + case tPGP2: + kdDebug(5100) << "Kpgp: assign pgp - pgp 2" << endl; + pgp = new Base2(); + break; + + case tPGP5: + kdDebug(5100) << "Kpgp: assign pgp - pgp 5" << endl; + pgp = new Base5(); + break; + + case tPGP6: + kdDebug(5100) << "Kpgp: assign pgp - pgp 6" << endl; + pgp = new Base6(); + break; + + case tOff: + // dummy handler + kdDebug(5100) << "Kpgp: pgpBase is dummy " << endl; + pgp = new Base(); + break; + + case tAuto: + kdDebug(5100) << "Kpgp: assign pgp - auto" << endl; + // fall through + default: + kdDebug(5100) << "Kpgp: assign pgp - default" << endl; + if (haveGpg) + { + kdDebug(5100) << "Kpgp: pgpBase is gpg " << endl; + pgp = new BaseG(); + pgpType = tGPG; + } + else if(havePGP5) + { + kdDebug(5100) << "Kpgp: pgpBase is pgp 5" << endl; + pgp = new Base5(); + pgpType = tPGP5; + } + else + { + Base6 *pgp_v6 = new Base6(); + if (!pgp_v6->isVersion6()) + { + kdDebug(5100) << "Kpgp: pgpBase is pgp 2 " << endl; + delete pgp_v6; + pgp = new Base2(); + pgpType = tPGP2; + } + else + { + kdDebug(5100) << "Kpgp: pgpBase is pgp 6 " << endl; + pgp = pgp_v6; + pgpType = tPGP6; + } + } + } // switch + } + else + { + // dummy handler + kdDebug(5100) << "Kpgp: pgpBase is dummy " << endl; + pgp = new Base(); + pgpType = tOff; + } +} + +QString +Module::canonicalAddress( const QString& _adress ) +{ + int index,index2; + + QString address = _adress.simplifyWhiteSpace(); + address = address.stripWhiteSpace(); + + // just leave pure e-mail address. + if((index = address.find("<")) != -1) + if((index2 = address.find("@",index+1)) != -1) + if((index2 = address.find(">",index2+1)) != -1) + return address.mid(index,index2-index+1); + + if((index = address.find("@")) == -1) + { + // local address + //char hostname[1024]; + //gethostname(hostname,1024); + //return "<" + address + "@" + hostname + ">"; + return "<" + address + "@localdomain>"; + } + else + { + int index1 = address.findRev(" ",index); + int index2 = address.find(" ",index); + if(index2 == -1) index2 = address.length(); + return "<" + address.mid(index1+1 ,index2-index1-1) + ">"; + } +} + +void +Module::readPublicKeys( bool reread ) +{ + if( 0 == pgp ) assignPGPBase(); + + if( !usePGP() ) + { + mPublicKeys.clear(); + mPublicKeysCached = false; + return; + } + + if( !mPublicKeysCached || reread ) + { + if( mPublicKeys.isEmpty() ) + { + mPublicKeys = pgp->publicKeys(); + } + else + { + KeyList newPublicKeyList = pgp->publicKeys(); + + // merge the trust info from the old key list into the new key list + // FIXME: This is currently O(K^2) where K = #keys. As the key lists + // are sorted this can be done in O(K). + KeyListIterator it( newPublicKeyList ); + for( it.toFirst(); (*it); ++it ) + { + Key* oldKey = publicKey( (*it)->primaryKeyID() ); + if( oldKey ) + { + (*it)->cloneKeyTrust( oldKey ); + } + } + + mPublicKeys = newPublicKeyList; + } + + mPublicKeysCached = true; + mPublicKeys.setAutoDelete( true ); + } +} + +void +Module::readSecretKeys( bool reread ) +{ + if( 0 == pgp ) assignPGPBase(); + + if( !usePGP() ) + { + mSecretKeys.clear(); + mSecretKeysCached = false; + return; + } + + if( mSecretKeys.isEmpty() || reread ) + { + if( mSecretKeys.isEmpty() ) + { + mSecretKeys = pgp->secretKeys(); + } + else + { + KeyList newSecretKeyList = pgp->secretKeys(); + + // merge the trust info from the old key list into the new key list + // FIXME: This is currently O(K^2) where K = #keys. As the key lists + // are sorted this can be done in O(K). + KeyListIterator it( newSecretKeyList ); + for( it.toFirst(); (*it); ++it ) + { + Key* oldKey = secretKey( (*it)->primaryKeyID() ); + if( oldKey ) + { + (*it)->cloneKeyTrust( oldKey ); + } + } + + mSecretKeys = newSecretKeyList; + } + + mSecretKeysCached = true; + mSecretKeys.setAutoDelete( true ); + } +} + +KeyID +Module::selectKey( const KeyList& keys, + const QString& title, + const QString& text /* = QString::null */ , + const KeyID& keyId /* = KeyID() */ , + const unsigned int allowedKeys /* = AllKeys */ ) +{ + KeyID retval = KeyID(); + + KeySelectionDialog dlg( keys, title, text, KeyIDList( keyId ), false, + allowedKeys, false ); + + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + bool rej = ( dlg.exec() == QDialog::Rejected ); + QApplication::restoreOverrideCursor(); + + if( !rej ) { + retval = dlg.key(); + } + + return retval; +} + +KeyIDList +Module::selectKeys( const KeyList& keys, + const QString& title, + const QString& text /* = QString::null */ , + const KeyIDList& keyIds /* = KeyIDList() */ , + const unsigned int allowedKeys /* = AllKeys */ ) +{ + KeyIDList retval = KeyIDList(); + + KeySelectionDialog dlg( keys, title, text, keyIds, false, allowedKeys, + true ); + + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + bool rej = ( dlg.exec() == QDialog::Rejected ); + QApplication::restoreOverrideCursor(); + + if( !rej ) { + retval = dlg.keys(); + } + + return retval; +} + + +KeyID +Module::selectKey( bool& rememberChoice, + const KeyList& keys, + const QString& title, + const QString& text /* = QString::null */ , + const KeyID& keyId /* = KeyID() */ , + const unsigned int allowedKeys /* = AllKeys */ ) +{ + KeyID retval = KeyID(); + + KeySelectionDialog dlg( keys, title, text, KeyIDList( keyId ), false, + allowedKeys, false ); + + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + bool rej = ( dlg.exec() == QDialog::Rejected ); + QApplication::restoreOverrideCursor(); + + if( !rej ) { + retval = dlg.key(); + rememberChoice = dlg.rememberSelection(); + } + else { + rememberChoice = false; + } + + return retval; +} + +KeyIDList +Module::selectKeys( bool& rememberChoice, + const KeyList& keys, + const QString& title, + const QString& text /* = QString::null */ , + const KeyIDList& keyIds /* = KeyIDList() */ , + const unsigned int allowedKeys /* = AllKeys */ ) +{ + KeyIDList retval = KeyIDList(); + + KeySelectionDialog dlg( keys, title, text, keyIds, true, allowedKeys, + true ); + + QApplication::setOverrideCursor( QCursor(QCursor::ArrowCursor) ); + bool rej = ( dlg.exec() == QDialog::Rejected ); + QApplication::restoreOverrideCursor(); + + if( !rej ) { + retval = dlg.keys(); + rememberChoice = dlg.rememberSelection(); + } + else { + rememberChoice = false; + } + + return retval; +} + +KeyIDList +Module::keysForAddress( const QString& address ) +{ + if( address.isEmpty() ) { + return KeyIDList(); + } + QString addr = canonicalAddress( address ).lower(); + if( addressDataDict.contains( addr ) ) { + return addressDataDict[addr].keyIds; + } + else { + return KeyIDList(); + } +} + +void +Module::setKeysForAddress( const QString& address, const KeyIDList& keyIds ) +{ + if( address.isEmpty() ) { + return; + } + QString addr = canonicalAddress( address ).lower(); + if( addressDataDict.contains( addr ) ) { + addressDataDict[addr].keyIds = keyIds; + } + else { + AddressData data; + data.encrPref = UnknownEncryptPref; + data.keyIds = keyIds; + addressDataDict.insert( addr, data ); + } + + //writeAddressData(); +} + +void +Module::readAddressData() +{ + QString address; + AddressData data; + + KConfigGroup general( config, "General" ); + int num = general.readNumEntry( "addressEntries", 0 ); + + addressDataDict.clear(); + for( int i=1; i<=num; i++ ) { + KConfigGroup addrGroup( config, QString("Address #%1").arg(i).local8Bit() ); + address = addrGroup.readEntry( "Address" ); + data.keyIds = KeyIDList::fromStringList( addrGroup.readListEntry( "Key IDs" ) ); + data.encrPref = (EncryptPref) addrGroup.readNumEntry( "EncryptionPreference", + UnknownEncryptPref ); +// kdDebug(5100) << "Read address " << i << ": " << address +// << "\nKey IDs: 0x" << data.keyIds.toStringList().join(", 0x") +// << "\nEncryption preference: " << data.encrPref << endl; + if ( !address.isEmpty() ) { + addressDataDict.insert( address, data ); + } + } +} + +void +Module::writeAddressData() +{ + KConfigGroup general( config, "General" ); + general.writeEntry( "addressEntries", addressDataDict.count() ); + + int i; + AddressDataDict::Iterator it; + for ( i=1, it = addressDataDict.begin(); + it != addressDataDict.end(); + ++it, i++ ) { + KConfigGroup addrGroup( config, QString("Address #%1").arg(i).local8Bit() ); + addrGroup.writeEntry( "Address", it.key() ); + addrGroup.writeEntry( "Key IDs", it.data().keyIds.toStringList() ); + addrGroup.writeEntry( "EncryptionPreference", it.data().encrPref ); + } + + config->sync(); +} + +EncryptPref +Module::encryptionPreference( const QString& address ) +{ + QString addr = canonicalAddress( address ).lower(); + if( addressDataDict.contains( addr ) ) { + return addressDataDict[addr].encrPref; + } + else { + return UnknownEncryptPref; + } +} + +void +Module::setEncryptionPreference( const QString& address, + const EncryptPref pref ) +{ + if( address.isEmpty() ) { + return; + } + QString addr = canonicalAddress( address ).lower(); + if( addressDataDict.contains( addr ) ) { + addressDataDict[addr].encrPref = pref; + } + else { + AddressData data; + data.encrPref = pref; + addressDataDict.insert( addr, data ); + } +} + +} // namespace Kpgp |