[prev in list] [next in list] [prev in thread] [next in thread]
List: kmail-devel
Subject: [Patch] Wallet support for KMail
From: Volker Krause <volker.krause () rwth-aachen ! de>
Date: 2004-08-26 21:34:24
Message-ID: 200408262334.24760.volker.krause () rwth-aachen ! de
[Download RAW message or body]
Hi,
took a bit longer than I had expected but here it is finally: Wallet support
for mail accounts and SMTP servers.
Mail accounts work as expected (as few as possible wallet password dialogs),
the code is mostly taken from KNode.
SMTP servers are a bit different: First they don't have a unique id which is
needed for the wallet, I added unique id's by coping the corresponding code
from the account manager. Second they are read from the config file on demand
instead of kept in memory. This makes password caching impossible, ie. the
wallet needs to be accessed for every send message (which will result in a
new wallet password dialog if the wallet has been closed in the meantime).
One thing that might be sub-optimal is the location of the static wallet
pointer and the wallet opening method in KAcctMgr, since a) it is not account
specific and also accessed by the KMTransport code and b) I didn't found a
way to access the winID of the toplevel widget from there. I guess you might
know a better place for this code ;)
Beside the issues mentioned above the code works so far, including migration
from the config file to KWallet.
regards
Volker
BTW: Where is the difference between KMTransportInfo::availableTransports()
and TransportManager::transportNames()?
["kmail-wallet.diff" (text/x-diff)]
? .kateconfig
? kmail-wallet.diff
? kmail.kdevelop
? kmail.kdevelop.pcs
? kmail.kdevses
Index: kmacctmgr.cpp
===================================================================
RCS file: /home/kde/kdepim/kmail/kmacctmgr.cpp,v
retrieving revision 1.121
diff -u -p -r1.121 kmacctmgr.cpp
--- kmacctmgr.cpp 26 Aug 2004 03:02:44 -0000 1.121
+++ kmacctmgr.cpp 26 Aug 2004 21:05:57 -0000
@@ -22,6 +22,9 @@ using KMail::NetworkAccount;
#include <kdebug.h>
#include <kconfig.h>
#include <kapplication.h>
+#include <kstaticdeleter.h>
+#include <kwallet.h>
+using KWallet::Wallet;
#include <qregexp.h>
#include <qvaluelist.h>
@@ -458,4 +461,42 @@ QString KMAcctMgr::hostForAccount( const
return net_acct ? net_acct->host() : QString::null;
}
+//-----------------------------------------------------------------------------
+void KMAcctMgr::readPasswords()
+{
+ for (QPtrListIterator<KMAccount> it(mAcctList); it.current(); ++it) {
+ NetworkAccount *acct = dynamic_cast<NetworkAccount*>( it.current() );
+ if( acct )
+ acct->readPassword();
+ }
+}
+
+//-----------------------------------------------------------------------------
+Wallet *KMAcctMgr::mWallet = 0;
+
+Wallet *KMAcctMgr::wallet() {
+ if ( mWallet && mWallet->isOpen() )
+ return mWallet;
+
+ if ( !Wallet::isEnabled() )
+ return 0;
+
+ delete mWallet;
+ static KStaticDeleter<Wallet> sd;
+ // FIXME: we should pass topLevelWidget()->winId() to openWallet()
+ // but where do I get a widget from?
+ sd.setObject( mWallet, Wallet::openWallet(Wallet::NetworkWallet()) );
+
+ if ( !mWallet ) {
+ KMessageBox::error(0, i18n("The wallet could not be opened. "
+ "This error is most probably caused by providing a wrong password."));
+ return 0;
+ }
+
+ if (!mWallet->hasFolder("kmail"))
+ mWallet->createFolder("kmail");
+ mWallet->setFolder("kmail");
+ return mWallet;
+}
+
#include "kmacctmgr.moc"
Index: kmacctmgr.h
===================================================================
RCS file: /home/kde/kdepim/kmail/kmacctmgr.h,v
retrieving revision 1.48
diff -u -p -r1.48 kmacctmgr.h
--- kmacctmgr.h 26 Aug 2004 03:02:44 -0000 1.48
+++ kmacctmgr.h 26 Aug 2004 21:05:57 -0000
@@ -11,6 +11,9 @@
class QString;
class QStringList;
+namespace KWallet {
+ class Wallet;
+}
class KMAcctMgr: public QObject
@@ -70,6 +73,12 @@ public:
/// Called on exit (KMMainWin::queryExit)
void cancelMailCheck();
+ /** Read passwords of all accounts from the wallet */
+ void readPasswords();
+
+ /** Open KDE wallet and set it to kmail folder */
+ static KWallet::Wallet *wallet();
+
public slots:
virtual void singleCheckMail(KMAccount *, bool _interactive = true);
virtual void singleInvalidateIMAPFolders(KMAccount *);
@@ -113,6 +122,7 @@ private:
// if a summary should be displayed
bool mDisplaySummary;
+ static KWallet::Wallet *mWallet;
};
#endif /*kmacctmgr_h*/
Index: kmsender.cpp
===================================================================
RCS file: /home/kde/kdepim/kmail/kmsender.cpp,v
retrieving revision 1.220
diff -u -p -r1.220 kmsender.cpp
--- kmsender.cpp 28 Jul 2004 09:33:56 -0000 1.220
+++ kmsender.cpp 26 Aug 2004 21:05:57 -0000
@@ -1045,13 +1045,13 @@ bool KMSendSMTP::send(KMMessage *aMsg)
if (ti->auth)
{
- if(ti->user.isEmpty() || ti->pass.isEmpty())
+ if(ti->user.isEmpty() || ti->passwd().isEmpty())
{
bool b = FALSE;
int result;
KCursorSaver idle(KBusyPtr::idle());
- result = KIO::PasswordDialog::getNameAndPassword(ti->user, ti->pass,
+ result = KIO::PasswordDialog::getNameAndPassword(ti->user, ti->passwd(),
&b, i18n("You need to supply a username and a password to use this "
"SMTP server."), FALSE, QString::null, ti->name, QString::null);
@@ -1064,7 +1064,7 @@ bool KMSendSMTP::send(KMMessage *aMsg)
ti->writeConfig(id);
}
destination.setUser(ti->user);
- destination.setPass(ti->pass);
+ destination.setPass(ti->passwd());
}
if (!mSlave || !mInProcess)
Index: kmtransport.cpp
===================================================================
RCS file: /home/kde/kdepim/kmail/kmtransport.cpp,v
retrieving revision 1.39
diff -u -p -r1.39 kmtransport.cpp
--- kmtransport.cpp 13 Jul 2004 22:10:31 -0000 1.39
+++ kmtransport.cpp 26 Aug 2004 21:05:57 -0000
@@ -38,13 +38,18 @@
#include <kmessagebox.h>
#include <kseparator.h>
#include <kdebug.h>
+#include <kwallet.h>
+using KWallet::Wallet;
#include "kmservertest.h"
#include "kmaccount.h"
#include "kmkernel.h"
#include "protocols.h"
+#include "kmacctmgr.h"
+#include "transportmanager.h"
+using namespace KMail;
-KMTransportInfo::KMTransportInfo()
+KMTransportInfo::KMTransportInfo() : mPasswdDirty( false ), mId( 0 )
{
name = i18n("Unnamed");
port = "25";
@@ -63,12 +68,13 @@ void KMTransportInfo::readConfig(int id)
{
KConfig *config = KMKernel::config();
KConfigGroupSaver saver(config, "Transport " + QString::number(id));
+ mId = config->readUnsignedNumEntry( "id", 0 );
type = config->readEntry("type", "smtp");
name = config->readEntry("name", i18n("Unnamed"));
host = config->readEntry("host", "localhost");
port = config->readEntry("port", "25");
user = config->readEntry("user");
- pass = KMAccount::decryptStr(config->readEntry("pass"));
+ mPasswd = KMAccount::decryptStr(config->readEntry("pass"));
precommand = config->readPathEntry("precommand");
encryption = config->readEntry("encryption");
authType = config->readEntry("authtype");
@@ -76,6 +82,19 @@ void KMTransportInfo::readConfig(int id)
storePass = config->readBoolEntry("storepass");
specifyHostname = config->readBoolEntry("specifyHostname", false);
localHostname = config->readEntry("localHostname");
+
+ if (!storePass)
+ return;
+
+ if (!mPasswd.isEmpty()) {
+ // migration to kwallet
+ config->deleteEntry( "pass" );
+ mPasswdDirty = true;
+ } else {
+ // read password if wallet is open, defer otherwise
+ if (Wallet::isOpen(Wallet::NetworkWallet()))
+ readPassword();
+ }
}
@@ -83,13 +102,14 @@ void KMTransportInfo::writeConfig(int id
{
KConfig *config = KMKernel::config();
KConfigGroupSaver saver(config, "Transport " + QString::number(id));
+ if (!mId)
+ mId = TransportManager::createId();
+ config->writeEntry("id", mId);
config->writeEntry("type", type);
config->writeEntry("name", name);
config->writeEntry("host", host);
config->writeEntry("port", port);
config->writeEntry("user", user);
- config->writeEntry("pass", (storePass) ? KMAccount::encryptStr(pass) :
- QString("") );
config->writePathEntry("precommand", precommand);
config->writeEntry("encryption", encryption);
config->writeEntry("authtype", authType);
@@ -97,6 +117,16 @@ void KMTransportInfo::writeConfig(int id
config->writeEntry("storepass", storePass);
config->writeEntry("specifyHostname", specifyHostname);
config->writeEntry("localHostname", localHostname);
+
+ if (storePass && auth && mPasswdDirty) {
+ Wallet *wallet = KMAcctMgr::wallet();
+ if (!wallet || wallet->writePassword("transport-" + QString::number(mId), passwd()) ) {
+ KMessageBox::information(0, i18n("KWallet is not running. It is strongly recommend to use "
+ "KWallet for managing your password"),
+ i18n("KWallet is Not Running."), "KWalletWarning" );
+ config->writeEntry( "pass", KMAccount::encryptStr(passwd()) );
+ }
+ }
}
@@ -129,6 +159,37 @@ QStringList KMTransportInfo::availableTr
}
+QString& KMTransportInfo::passwd()
+{
+ if (auth && storePass && mPasswd.isEmpty())
+ readPassword();
+ return mPasswd;
+}
+
+
+void KMTransportInfo::setPasswd( const QString &passwd )
+{
+ if ( passwd != mPasswd ) {
+ mPasswd = passwd;
+ mPasswdDirty = true;
+ }
+}
+
+
+void KMTransportInfo::readPassword()
+{
+ if (!storePass || !auth)
+ return;
+
+ if ( Wallet::folderDoesNotExist(Wallet::NetworkWallet(), "kmail") ||
+ Wallet::keyDoesNotExist(Wallet::NetworkWallet(), "kmail", "transport-" + QString::number(mId)) )
+ return;
+
+ if ( KMAcctMgr::wallet() )
+ KMAcctMgr::wallet()->readPassword( "transport-" + QString::number(mId), mPasswd );
+}
+
+
KMTransportSelDlg::KMTransportSelDlg( QWidget *parent, const char *name,
bool modal )
: KDialogBase( parent, name, modal, i18n("Add Transport"), Ok|Cancel, Ok )
@@ -429,7 +490,7 @@ void KMTransportDialog::setupSettings()
mSmtp.portEdit->setText(mTransportInfo->port);
mSmtp.authCheck->setChecked(mTransportInfo->auth);
mSmtp.loginEdit->setText(mTransportInfo->user);
- mSmtp.passwordEdit->setText(mTransportInfo->pass);
+ mSmtp.passwordEdit->setText(mTransportInfo->passwd());
mSmtp.storePasswordCheck->setChecked(mTransportInfo->storePass);
mSmtp.precommand->setText(mTransportInfo->precommand);
mSmtp.specifyHostnameCheck->setChecked(mTransportInfo->specifyHostname);
@@ -468,7 +529,7 @@ void KMTransportDialog::saveSettings()
mTransportInfo->port = mSmtp.portEdit->text().stripWhiteSpace();
mTransportInfo->auth = mSmtp.authCheck->isChecked();
mTransportInfo->user = mSmtp.loginEdit->text().stripWhiteSpace();
- mTransportInfo->pass = mSmtp.passwordEdit->text();
+ mTransportInfo->setPasswd( mSmtp.passwordEdit->text() );
mTransportInfo->storePass = mSmtp.storePasswordCheck->isChecked();
mTransportInfo->precommand = mSmtp.precommand->text().stripWhiteSpace();
mTransportInfo->specifyHostname = mSmtp.specifyHostnameCheck->isChecked();
Index: kmtransport.h
===================================================================
RCS file: /home/kde/kdepim/kmail/kmtransport.h,v
retrieving revision 1.10
diff -u -p -r1.10 kmtransport.h
--- kmtransport.h 10 Apr 2004 09:21:44 -0000 1.10
+++ kmtransport.h 26 Aug 2004 21:05:57 -0000
@@ -19,7 +19,7 @@
#ifndef _KMTRANSPORT_H_
#define _KMTRANSPORT_H_
-
+
#include <kdialogbase.h>
class QCheckBox;
@@ -38,22 +38,36 @@ public:
void writeConfig(int id);
static int findTransport(const QString &name);
static QStringList availableTransports();
- QString type, name, host, port, user, pass, precommand, encryption, authType;
+ uint id() const { return mId; }
+
+ /** Get/set password for this account */
+ QString& passwd();
+ void setPasswd( const QString& passwd );
+
+ /** Read password from wallet */
+ void readPassword();
+
+ QString type, name, host, port, user, precommand, encryption, authType;
QString localHostname;
bool auth, storePass, specifyHostname;
+
+ private:
+ QString mPasswd;
+ bool mPasswdDirty;
+ uint mId;
};
class KMTransportSelDlg : public KDialogBase
{
Q_OBJECT
-
+
public:
KMTransportSelDlg( QWidget *parent=0, const char *name=0, bool modal=TRUE );
int selected() const;
-
+
private slots:
void buttonClicked( int id );
-
+
private:
int mSelectedButton;
};
@@ -73,8 +87,8 @@ private slots:
void slotRequiresAuthClicked();
void slotSmtpEncryptionChanged(int);
void slotCheckSmtpCapabilities();
- void slotSmtpCapabilities( const QStringList &, const QStringList &,
- const QString &, const QString &,
+ void slotSmtpCapabilities( const QStringList &, const QStringList &,
+ const QString &, const QString &,
const QString & );
void slotSendmailEditPath(const QString &);
private:
Index: networkaccount.cpp
===================================================================
RCS file: /home/kde/kdepim/kmail/networkaccount.cpp,v
retrieving revision 1.9
diff -u -p -r1.9 networkaccount.cpp
--- networkaccount.cpp 10 Mar 2004 18:41:27 -0000 1.9
+++ networkaccount.cpp 26 Aug 2004 21:05:57 -0000
@@ -28,10 +28,15 @@
#endif
#include "networkaccount.h"
+#include "kmacctmgr.h"
#include <kconfig.h>
#include <kio/global.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kwallet.h>
using KIO::MetaData;
+using KWallet::Wallet;
#include <climits>
@@ -45,7 +50,8 @@ namespace KMail {
mStorePasswd( false ),
mUseSSL( false ),
mUseTLS( false ),
- mAskAgain( false )
+ mAskAgain( false ),
+ mPasswdDirty( false )
{
}
@@ -80,11 +86,16 @@ namespace KMail {
}
QString NetworkAccount::passwd() const {
+ if (storePasswd() && mPasswd.isEmpty())
+ mOwner->readPasswords();
return decryptStr( mPasswd );
}
void NetworkAccount::setPasswd( const QString & passwd, bool storeInConfig ) {
- mPasswd = encryptStr( passwd );
+ if (mPasswd != encryptStr( passwd )) {
+ mPasswd = encryptStr( passwd );
+ mPasswdDirty = true;
+ }
setStorePasswd( storeInConfig );
}
@@ -132,25 +143,39 @@ namespace KMail {
setLogin( config.readEntry( "login" ) );
if ( config.readNumEntry( "store-passwd", false ) ) { // ### s/Num/Bool/
+ setStorePasswd( true );
QString encpasswd = config.readEntry( "pass" );
if ( encpasswd.isEmpty() ) {
- encpasswd = config.readEntry( "passwd" );
- if ( !encpasswd.isEmpty() ) encpasswd = importPassword( encpasswd );
+ encpasswd = config.readEntry( "passwd" );
+ if ( !encpasswd.isEmpty() ) encpasswd = importPassword( encpasswd );
}
- setPasswd( decryptStr( encpasswd ), true );
- } else
+
+ if ( !encpasswd.isEmpty() ) {
+ // migration to KWallet
+ setPasswd( decryptStr( encpasswd ), true );
+ config.deleteEntry( "pass" );
+ config.deleteEntry( "passwd" );
+ mPasswdDirty = true;
+ } else {
+ // read password if wallet is already open, otherwise defer to on-demand loading
+ if (Wallet::isOpen(Wallet::NetworkWallet()))
+ readPassword();
+ }
+
+ } else {
setPasswd( "", false );
-
+ }
+
setHost( config.readEntry( "host" ) );
unsigned int port = config.readUnsignedNumEntry( "port", defaultPort() );
if ( port > USHRT_MAX ) port = defaultPort();
setPort( port );
-
+
setAuth( config.readEntry( "auth", "*" ) );
setUseSSL( config.readBoolEntry( "use-ssl", false ) );
setUseTLS( config.readBoolEntry( "use-tls", false ) );
-
+
mSieveConfig.readConfig( config );
}
@@ -159,7 +184,16 @@ namespace KMail {
config.writeEntry( "login", login() );
config.writeEntry( "store-passwd", storePasswd() );
- if ( storePasswd() ) config.writeEntry( "pass", mPasswd ); // NOT passwd()
+ if ( storePasswd() && mPasswdDirty ) { //config.writeEntry( "pass", mPasswd ); // NOT passwd()
+ Wallet *wallet = KMAcctMgr::wallet();
+ if (!wallet || wallet->writePassword("account-" + QString::number(mId), passwd()) ) {
+ KMessageBox::information(0, i18n("KWallet is not running. It is strongly recommend to use "
+ "KWallet for managing your password"),
+ i18n("KWallet is Not Running."), "KWalletWarning" );
+ config.writeEntry( "pass", encryptStr(passwd()) );
+ }
+ }
+
else config.writeEntry( "passwd", "" ); // ### ???? why two different keys?
config.writeEntry( "host", host() );
@@ -209,6 +243,22 @@ namespace KMail {
setSieveConfig( n->sieveConfig() );
}
+ void NetworkAccount::readPassword() {
+ if (!storePasswd())
+ return;
+
+ if ( Wallet::folderDoesNotExist(Wallet::NetworkWallet(), "kmail") ||
+ Wallet::keyDoesNotExist(Wallet::NetworkWallet(), "kmail", "account-" + QString::number(mId)) )
+ return;
+
+ if ( KMAcctMgr::wallet() ) {
+ QString passwd;
+ KMAcctMgr::wallet()->readPassword( "account-" + QString::number(mId), passwd );
+ setPasswd( passwd, true );
+ mPasswdDirty = false;
+ }
+ }
+
} // namespace KMail
#include "networkaccount.moc"
Index: networkaccount.h
===================================================================
RCS file: /home/kde/kdepim/kmail/networkaccount.h,v
retrieving revision 1.6
diff -u -p -r1.6 networkaccount.h
--- networkaccount.h 10 Mar 2004 18:41:27 -0000 1.6
+++ networkaccount.h 26 Aug 2004 21:05:57 -0000
@@ -110,6 +110,9 @@ namespace KMail {
/** Kill all jobs that are currently in progress */
virtual void killAllJobs( bool disconnectSlave = false ) = 0;
+ /** Read password from wallet, used for on-demand wallet opening */
+ void readPassword();
+
protected:
virtual QString protocol() const = 0;
virtual unsigned short int defaultPort() const = 0;
@@ -123,6 +126,7 @@ namespace KMail {
bool mUseSSL : 1;
bool mUseTLS : 1;
bool mAskAgain : 1;
+ bool mPasswdDirty;
};
Index: transportmanager.cpp
===================================================================
RCS file: /home/kde/kdepim/kmail/transportmanager.cpp,v
retrieving revision 1.12
diff -u -p -r1.12 transportmanager.cpp
--- transportmanager.cpp 11 Jan 2004 21:57:08 -0000 1.12
+++ transportmanager.cpp 26 Aug 2004 21:05:57 -0000
@@ -20,6 +20,7 @@
#include "kmtransport.h"
#include "kmkernel.h"
+#include <kapplication.h>
#include <kconfig.h>
namespace KMail {
@@ -40,4 +41,28 @@ namespace KMail {
return transportNames;
}
+ // more or less copied from KMAcctMgr
+ uint TransportManager::createId()
+ {
+ QValueList<unsigned int> usedIds;
+
+ KConfigGroup general( KMKernel::config(), "General");
+ int numTransports = general.readNumEntry("transports", 0);
+
+ for ( int i = 1 ; i <= numTransports ; i++ ) {
+ KMTransportInfo ti;
+ ti.readConfig(i);
+ usedIds << ti.id();
+ }
+
+ usedIds << 0; // 0 is default for unknown
+ int newId;
+ do
+ {
+ newId = kapp->random();
+ } while ( usedIds.find(newId) != usedIds.end() );
+
+ return newId;
+ }
+
} // namespace KMail
Index: transportmanager.h
===================================================================
RCS file: /home/kde/kdepim/kmail/transportmanager.h,v
retrieving revision 1.3
diff -u -p -r1.3 transportmanager.h
--- transportmanager.h 26 Jul 2003 14:51:50 -0000 1.3
+++ transportmanager.h 26 Aug 2004 21:05:57 -0000
@@ -25,13 +25,16 @@ namespace KMail {
* @author Ingo Kloecker <kloecker@kde.org>
**/
class TransportManager {
-
+
public:
TransportManager() {};
virtual ~TransportManager() {};
-
+
/** Returns the list for transport names */
static QStringList transportNames();
+
+ /** Create a unique id for a transport info item */
+ static unsigned int createId();
};
} // namespace KMail
_______________________________________________
KMail developers mailing list
KMail-devel@kde.org
https://mail.kde.org/mailman/listinfo/kmail-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic