From 24c803ef0493a8d8dffef6b727b2e2996da948d9 Mon Sep 17 00:00:00 2001 From: Don Sanders Date: Thu, 27 Jan 2000 09:33:47 +0000 Subject: [PATCH] PGP 6.x support and a few other PGP related things from Andreas Gungl svn path=/trunk/kdenetwork/kmail/; revision=39335 --- kpgp.cpp | 104 +++++++++++++++++++++++++-- kpgp.h | 34 +++++++++ kpgpbase.cpp | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++ kpgpbase.h | 20 ++++++ 4 files changed, 353 insertions(+), 4 deletions(-) diff --git a/kpgp.cpp b/kpgp.cpp index 7abdf9005..723e59fce 100644 --- a/kpgp.cpp +++ b/kpgp.cpp @@ -66,8 +66,15 @@ Kpgp::init() else if (haveGpg) pgp = new KpgpBaseG(); else - pgp = new KpgpBase2(); - + { + KpgpBase6 *pgp_v6 = new KpgpBase6(); + if (!pgp_v6->isVersion6()) + { + delete pgp_v6; + pgp = new KpgpBase2(); + } + else pgp = pgp_v6; + } } else { @@ -470,7 +477,7 @@ Kpgp::getPublicKey(QString _person) } // do the search case insensitive, but return the correct key. - QString adress,str; + QString adress,str,disp_str; adress = _person.lower(); // first try the canonical mail adress. @@ -478,12 +485,21 @@ Kpgp::getPublicKey(QString _person) for(str=publicKeys.first(); str!=0; str=publicKeys.next()) if(str.contains(adress)) return str; - // now try the pure input + // now check if the key contains the address adress = _person.lower(); for(str=publicKeys.first(); str!=0; str=publicKeys.next()) if(str.contains(adress)) return str; // FIXME: let user set the key/ get from keyserver + // now check if the address contains the key + adress = _person.lower(); + for(str=publicKeys.first(); str!=0; str=publicKeys.next()) + if(adress.contains(str)) return str; + + // no match until now, let the user choose the key: + adress = canonicalAdress(adress); + str= SelectPublicKey(publicKeys, adress); + if (!str.isEmpty()) return str; return QString::null; } @@ -729,6 +745,21 @@ Kpgp::canonicalAdress(QString _adress) } } +QString +Kpgp::SelectPublicKey(QStrList pbkeys, const char *caption) +{ + KpgpSelDlg dlg(pbkeys,caption); + QString txt =""; + + if (dlg.exec()==QDialog::Rejected) return 0; + txt = dlg.key(); + if (!txt.isEmpty()) + { + return txt; + } + return 0; +} + //---------------------------------------------------------------------- // widgets needed by kpgp @@ -932,3 +963,68 @@ KpgpConfig::applySettings() } +//----------------------------------------------------------------------------- +#define KpgpDlgInherited QDialog +KpgpSelDlg::KpgpSelDlg(QStrList aKeyList, const char *aCap): + KpgpDlgInherited(NULL, aCap, TRUE), mGrid(this, 2, 2), + mListBox(this), + mBtnOk(i18n("OK"),this), + mBtnCancel(i18n("Cancel"),this) +{ + const char* key; + QString caption; + + caption=i18n("Select public key for recipient \""); + caption += aCap; + caption += i18n("\""); + + initMetaObject(); + + setCaption(aCap ? /*(const char *)*/caption : i18n("PGP Key Selection")); + + /*assert(aKeyList != NULL);*/ + mKeyList = aKeyList; + mkey = ""; + + mBtnOk.adjustSize(); + mBtnOk.setMinimumSize(mBtnOk.size()); + mBtnCancel.adjustSize(); + mBtnCancel.setMinimumSize(mBtnCancel.size()); + + mGrid.addMultiCellWidget(&mListBox, 0, 0, 0, 1); + mGrid.addWidget(&mBtnOk, 1, 0); + mGrid.addWidget(&mBtnCancel, 1, 1); + + mGrid.setRowStretch(0,10); + mGrid.setRowStretch(1,0); + mGrid.setColStretch(0,10); + mGrid.setColStretch(1,10); + mGrid.activate(); + + connect(&mBtnOk, SIGNAL(clicked()), SLOT(slotOk())); + connect(&mListBox, SIGNAL(selected(int)), SLOT(slotOk())); + connect(&mBtnCancel, SIGNAL(clicked()), SLOT(slotCancel())); + + for (key=mKeyList.first(); key; key=mKeyList.next()) + { + //insert only real keys: + // if (!(QString)key.contains("matching key")) + mListBox.insertItem(key); + } +} + +void KpgpSelDlg::slotOk() +{ + int idx = mListBox.currentItem(); + + if (idx>=0) mkey = mListBox.text(idx); + else mkey = ""; + + accept(); +} + +void KpgpSelDlg::slotCancel() +{ + mkey = ""; + reject(); +} diff --git a/kpgp.h b/kpgp.h index 934cf0b33..a6deb898b 100644 --- a/kpgp.h +++ b/kpgp.h @@ -2,6 +2,12 @@ * This code is under GPL V2.0 * * @author Lars Knoll + * + * GNUPG support + * @author "J. Nick Koston" + * + * PGP6 and other enhancements + * @author Andreas Gungl */ #ifndef KPGP_H #define KPGP_H @@ -12,6 +18,9 @@ #include #include #include +#include +#include +#include class QLineEdit; class QCursor; @@ -153,6 +162,9 @@ private: // transform an adress into canonical form QString canonicalAdress(QString _person); + //Select public key from a list of all public keys + QString SelectPublicKey(QStrList pbkeys, const char *caption); + bool checkForPGP(void); static Kpgp *kpgpObject; @@ -234,5 +246,27 @@ protected: }; +// ------------------------------------------------------------------------- +class KpgpSelDlg: public QDialog +{ + Q_OBJECT +public: + KpgpSelDlg(QStrList aKeyList, const char *caption=NULL); + virtual ~KpgpSelDlg() {}; + + virtual const QString key(void) const {return mkey;}; + +protected slots: + void slotOk(); + void slotCancel(); + +protected: + QGridLayout mGrid; + QListBox mListBox; + QPushButton mBtnOk, mBtnCancel; + QString mkey; + QStrList mKeyList; +}; + #endif diff --git a/kpgpbase.cpp b/kpgpbase.cpp index ec8694960..da2b7acd4 100644 --- a/kpgpbase.cpp +++ b/kpgpbase.cpp @@ -893,6 +893,9 @@ KpgpBase2::pubKeys() status = run(cmd); if(status == RUN_ERR) return 0; + //truncate trailing "\n" + if (output.length() > 1) output.truncate(output.length()-1); + QStrList publicKeys; index = output.find("\n",1)+1; // skip first to "\n" while( (index = output.find("\n",index)) != -1) @@ -1265,3 +1268,199 @@ KpgpBase5::signKey(const char *key, const char *passphrase) return status; } +// ------------------------------------------------------------------------- + +KpgpBase6::KpgpBase6() + : KpgpBase2() +{ +} + +KpgpBase6::~KpgpBase6() +{ +} + +int +KpgpBase6::decrypt(const char *passphrase) +{ + QString cmd; + int index, index2; + output = ""; + + cmd = "pgp +batchmode -f"; + + status = run(cmd, passphrase); + + if(status != OK) + { + errMsg = i18n("error running pgp"); + return status; + } + + // encrypted message + if( info.find("File is encrypted.") != -1) + { + //debug("kpgpbase: message is encrypted"); + status |= ENCRYPTED; + if( info.find("Key for user ID") != -1) + { + // Test output length to find out, if the passphrase is + // bad. If someone knows a better way, please fix this. + if (!passphrase || !output.length()) + { + errMsg = i18n("Bad pass Phrase; couldn't decrypt"); + //debug("KpgpBase: passphrase is bad"); + status |= BADPHRASE; + status |= ERROR; + } + } + else if( info.find("Secret key is required to read it.") != -1) + { + errMsg = i18n("Do not have the secret key for this message"); + //debug("KpgpBase: no secret key for this message"); + status |= NO_SEC_KEY; + status |= ERROR; + } + } + + // signed message + if(((index = info.find("File is signed.")) != -1) + || (info.find("Good signature") != -1 )) + { + //debug("KpgpBase: message is signed"); + status |= SIGNED; + if( info.find("signature not checked") != -1) + { + index = info.find("KeyID:",index); + signatureID = info.mid(index+7,8); + signature = i18n("unknown key ID "); + signature += " " +signatureID; + status |= UNKNOWN_SIG; + status |= GOODSIG; + } + else if((index = info.find("Good signature")) != -1 ) + { + status |= GOODSIG; + // get signer + index = info.find("\"",index); + index2 = info.find("\"", index+1); + signature = info.mid(index+1, index2-index-1); + + // get key ID of signer + index = info.find("KeyID:",index2); + if (index == -1) + signatureID = "???"; + else + signatureID = info.mid(index+7,8); + } + else if( info.find("Can't find the right public key") != -1 ) + { + status |= UNKNOWN_SIG; + status |= GOODSIG; // this is a hack... + signature = i18n("??? (file ~/.pgp/pubring.pkr not found)"); + signatureID = "???"; + } + else + { + status |= ERROR; + signature = ""; + signatureID = ""; + } + } + //debug("status = %d",status); + return status; +} + +QStrList +KpgpBase6::pubKeys() +{ + QString cmd; + int index, index2; + int compatibleMode = 1; + + cmd = "pgp +batchmode -kv -f \"\" ~/.pgp/pubring.pkr"; + status = run(cmd); + if(status != OK) return 0; + + //truncate trailing "\n" + if (info.length() > 1) info.truncate(info.length()-1); + + QStrList publicKeys; + index = info.find("bits/keyID",1); // skip first to "\n" + if (index ==-1) + { + index = info.find("Type bits",1); // skip first to "\n" + if (index == -1) + return 0; + else + compatibleMode = 0; + } + + while( (index = info.find("\n",index)) != -1) + { + //parse line + QString line; + if( (index2 = info.find("\n",index+1)) != -1) + // skip last line + { + int index3; + if (compatibleMode) + index3 = info.find("pub ",index); + else + { + int index_rsa = info.find("RSA ",index); + int index_dss = info.find("DSS ",index); + if (index_rsa < 0) + index3 = index_dss; + else if (index_dss < 0) + index3 = index_rsa; + else + index3 = (index_rsa < index_dss ? index_rsa : index_dss); + } + + if( (index3 >index2) || (index3 == -1) ) + { + // second adress for the same key + line = info.mid(index+1,index2-index-1); + line = line.stripWhiteSpace(); + line = line.lower(); + } else { + // line with new key + int index4 = info.find( + QRegExp("/[0-9][0-9]/[0-9][0-9] "), + index); + line = info.mid(index4+7,index2-index4-7); + line = line.lower(); + } + //debug("KpgpBase: found key for %s",(const char *)line); + publicKeys.append(line); + } + index = index2; + } + return publicKeys; +} + +int +KpgpBase6::isVersion6() +{ + QString cmd; + QString empty; + + cmd = "pgp"; + + status = run(cmd, empty); + + if(status != OK) + { + errMsg = i18n("error running pgp"); + return 0; + } + + if( info.find("Version 6") != -1) + { + //debug("kpgpbase: pgp version 6.x detected"); + return 1; + } + + //debug("kpgpbase: not pgp version 6.x"); + return 0; +} diff --git a/kpgpbase.h b/kpgpbase.h index 5aa17dea6..432409d1a 100644 --- a/kpgpbase.h +++ b/kpgpbase.h @@ -2,6 +2,12 @@ * This code is under GPL V2.0 * * @author Lars Knoll + * + * GNUPG support + * @author "J. Nick Koston" + * + * PGP6 and other enhancements + * @author Andreas Gungl */ #ifndef KPGPBASE_H #define KPGPBASE_H @@ -148,6 +154,20 @@ public: virtual int signKey(const char *key, const char *passphrase); }; + +class KpgpBase6 : public KpgpBase2 +{ + +public: + KpgpBase6(); + virtual ~KpgpBase6(); + + virtual int decrypt(const char *passphrase = 0); + virtual QStrList pubKeys(); + + virtual int isVersion6(); +}; + // --------------------------------------------------------------------------- // inlined functions