1 // -*- indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*-
3 This file is part of the KDE libraries
5 Copyright (c) 2002-2004 George Staikos <staikos@kde.org>
6 Copyright (c) 2008 Michael Leupold <lemma@confuego.org>
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
27 #include "kbetterthankdialog.h"
28 #include "kwalletwizard.h"
30 #include <kuniqueapplication.h>
31 #include <ktoolinvocation.h>
33 #include <kconfiggroup.h>
35 #include <kdirwatch.h>
38 #include <kmessagebox.h>
39 #include <kpassworddialog.h>
40 #include <knewpassworddialog.h>
41 #include <kstandarddirs.h>
42 #include <kwalletentry.h>
43 #include <kwindowsystem.h>
44 #include <kpluginfactory.h>
45 #include <kpluginloader.h>
47 #include <QtCore/QDir>
48 #include <QtGui/QTextDocument> // Qt::escape
49 #include <QtCore/QRegExp>
50 #include <QtCore/QTimer>
51 #include <QtCore/QEventLoop>
55 #include "kwalletadaptor.h"
56 #include "kwalletopenloop.h"
58 class KWalletTransaction
{
62 : tType(Unknown
), cancelled(false), tId(nextTransactionId
)
65 // make sure the id is never < 0 as that's used for the
67 if (nextTransactionId
< 0) {
68 nextTransactionId
= 0;
72 ~KWalletTransaction() {
87 bool cancelled
; // set true if the client dies before open
90 int tId
; // transaction id
93 static int nextTransactionId
;
96 int KWalletTransaction::nextTransactionId
= 0;
99 : QObject(0), _failed(0), _syncTime(5000), _curtrans(0) {
102 _showingFailureNotify
= false;
105 connect(&_closeTimers
, SIGNAL(timedOut(int)), this, SLOT(timedOutClose(int)));
106 connect(&_syncTimers
, SIGNAL(timedOut(int)), this, SLOT(timedOutSync(int)));
108 (void)new KWalletAdaptor(this);
110 QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.kwalletd"));
111 QDBusConnection::sessionBus().registerObject(QLatin1String("/modules/kwalletd"), this);
114 screensaver
= new QDBusInterface("org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver");
118 KGlobal::dirs()->addResourceType("kwallet", 0, "share/apps/kwallet");
119 connect(QDBusConnection::sessionBus().interface(),
120 SIGNAL(serviceOwnerChanged(QString
,QString
,QString
)),
121 SLOT(slotServiceOwnerChanged(QString
,QString
,QString
)));
122 _dw
= new KDirWatch(this );
123 _dw
->setObjectName( "KWallet Directory Watcher" );
124 _dw
->addDir(KGlobal::dirs()->saveLocation("kwallet"));
125 _dw
->startScan(true);
126 connect(_dw
, SIGNAL(dirty(const QString
&)), this, SLOT(emitWalletListDirty()));
130 KWalletD::~KWalletD() {
136 qDeleteAll(_transactions
);
140 int KWalletD::generateHandle() {
143 // ASSUMPTION: RAND_MAX is fairly large.
146 } while (_wallets
.contains(rc
) || rc
== 0);
151 QPair
<int, KWallet::Backend
*> KWalletD::findWallet(const QString
& walletName
) const
153 Wallets::const_iterator it
= _wallets
.constBegin();
154 const Wallets::const_iterator end
= _wallets
.constEnd();
155 for (; it
!= end
; ++it
) {
156 if (it
.value()->walletName() == walletName
) {
157 return qMakePair(it
.key(), it
.value());
160 return qMakePair(-1, static_cast<KWallet::Backend
*>(0));
163 void KWalletD::processTransactions() {
164 static bool processing
= false;
172 // Process remaining transactions
173 while (!_transactions
.isEmpty()) {
174 _curtrans
= _transactions
.takeFirst();
177 assert(_curtrans
->tType
!= KWalletTransaction::Unknown
);
179 switch (_curtrans
->tType
) {
180 case KWalletTransaction::Open
:
181 res
= doTransactionOpen(_curtrans
->appid
, _curtrans
->wallet
, _curtrans
->isPath
,
182 _curtrans
->wId
, _curtrans
->modal
, _curtrans
->service
);
184 // multiple requests from the same client
185 // should not produce multiple password
186 // dialogs on a failure
188 QList
<KWalletTransaction
*>::iterator it
;
189 for (it
= _transactions
.begin(); it
!= _transactions
.end(); ++it
) {
190 KWalletTransaction
*x
= *it
;
191 if (_curtrans
->appid
== x
->appid
&& x
->tType
== KWalletTransaction::Open
192 && x
->wallet
== _curtrans
->wallet
&& x
->wId
== _curtrans
->wId
) {
193 x
->tType
= KWalletTransaction::OpenFail
;
196 } else if (_curtrans
->cancelled
) {
197 // the wallet opened successfully but the application
198 // opening exited/crashed while the dialog was still shown.
199 KWalletTransaction
*_xact
= new KWalletTransaction();
200 _xact
->tType
= KWalletTransaction::CloseCancelled
;
201 _xact
->appid
= _curtrans
->appid
;
202 _xact
->wallet
= _curtrans
->wallet
;
203 _xact
->service
= _curtrans
->service
;
204 _transactions
.append(_xact
);
207 // emit the AsyncOpened signal as a reply
208 emit
walletAsyncOpened(_curtrans
->tId
, res
);
211 case KWalletTransaction::OpenFail
:
212 // emit the AsyncOpened signal with an invalid handle
213 emit
walletAsyncOpened(_curtrans
->tId
, -1);
216 case KWalletTransaction::ChangePassword
:
217 doTransactionChangePassword(_curtrans
->appid
, _curtrans
->wallet
, _curtrans
->wId
);
220 case KWalletTransaction::CloseCancelled
:
221 doTransactionOpenCancelled(_curtrans
->appid
, _curtrans
->wallet
,
225 case KWalletTransaction::Unknown
:
240 int KWalletD::openPath(const QString
& path
, qlonglong wId
, const QString
& appid
) {
241 int tId
= openPathAsync(path
, wId
, appid
, false);
246 // wait for the open-transaction to be processed
247 KWalletOpenLoop
loop(this);
248 return loop
.waitForAsyncOpen(tId
);
251 int KWalletD::open(const QString
& wallet
, qlonglong wId
, const QString
& appid
) {
252 int tId
= openAsync(wallet
, wId
, appid
, false);
257 // wait for the open-transaction to be processed
258 KWalletOpenLoop
loop(this);
259 return loop
.waitForAsyncOpen(tId
);
262 int KWalletD::openAsync(const QString
& wallet
, qlonglong wId
, const QString
& appid
,
263 bool handleSession
) {
264 if (!_enabled
) { // guard
268 if (!QRegExp("^[\\w\\^\\&\\'\\@\\{\\}\\[\\]\\,\\$\\=\\!\\-\\#\\(\\)\\%\\.\\+\\_]+$").exactMatch(wallet
)) {
272 KWalletTransaction
*xact
= new KWalletTransaction
;
273 _transactions
.append(xact
);
276 xact
->wallet
= wallet
;
278 xact
->modal
= true; // mark dialogs as modal, the app has blocking wait
279 xact
->tType
= KWalletTransaction::Open
;
280 xact
->isPath
= false;
282 xact
->service
= message().service();
284 QTimer::singleShot(0, this, SLOT(processTransactions()));
286 // opening is in progress. return the transaction number
290 int KWalletD::openPathAsync(const QString
& path
, qlonglong wId
, const QString
& appid
,
291 bool handleSession
) {
292 if (!_enabled
) { // gaurd
296 KWalletTransaction
*xact
= new KWalletTransaction
;
297 _transactions
.append(xact
);
303 xact
->tType
= KWalletTransaction::Open
;
306 xact
->service
= message().service();
308 QTimer::singleShot(0, this, SLOT(processTransactions()));
310 // opening is in progress. return the transaction number
314 // Sets up a dialog that will be shown by kwallet.
315 void KWalletD::setupDialog( QWidget
* dialog
, WId wId
, const QString
& appid
, bool modal
) {
317 KWindowSystem::setMainWindow( dialog
, wId
); // correct, set dialog parent
320 kWarning() << "Using kwallet without parent window!";
322 kWarning() << "Application '" << appid
<< "' using kwallet without parent window!";
323 // allow dialog activation even if it interrupts, better than trying hacks
324 // with keeping the dialog on top or on all desktops
325 kapp
->updateUserTimestamp();
329 KWindowSystem::setState( dialog
->winId(), NET::Modal
);
331 KWindowSystem::clearState( dialog
->winId(), NET::Modal
);
333 activeDialog
= dialog
;
336 // If there's a dialog already open and another application tries some operation that'd lead to
337 // opening a dialog, that application will be blocked by this dialog. A proper solution would
338 // be to set the second application's window also as a parent for the active dialog, so that
339 // KWin properly handles focus changes and so on, but there's currently no support for multiple
340 // dialog parents. Hopefully to be done in KDE4, for now just use all kinds of bad hacks to make
341 // sure the user doesn't overlook the active dialog.
342 void KWalletD::checkActiveDialog() {
343 if( !activeDialog
|| activeDialog
->isHidden())
345 kapp
->updateUserTimestamp();
347 KWindowSystem::setState( activeDialog
->winId(), NET::KeepAbove
);
348 KWindowSystem::setOnAllDesktops( activeDialog
->winId(), true );
349 KWindowSystem::forceActiveWindow( activeDialog
->winId());
354 int KWalletD::doTransactionOpen(const QString
& appid
, const QString
& wallet
, bool isPath
,
355 qlonglong wId
, bool modal
, const QString
& service
) {
356 if (_firstUse
&& !wallets().contains(KWallet::Wallet::LocalWallet()) && !isPath
) {
358 KWalletWizard
*wiz
= new KWalletWizard(0);
359 wiz
->setWindowTitle(i18n("KDE Wallet Service"));
360 setupDialog( wiz
, (WId
)wId
, appid
, modal
);
361 int rc
= wiz
->exec();
362 if (rc
== QDialog::Accepted
) {
363 bool useWallet
= wiz
->field("useWallet").toBool();
364 KConfig
kwalletrc("kwalletrc");
365 KConfigGroup
cfg(&kwalletrc
, "Wallet");
366 cfg
.writeEntry("First Use", false);
367 cfg
.writeEntry("Enabled", useWallet
);
368 cfg
.writeEntry("Close When Idle", wiz
->field("closeWhenIdle").toBool());
369 cfg
.writeEntry("Use One Wallet", !wiz
->field("networkWallet").toBool());
379 KWallet::Backend
*b
= new KWallet::Backend(KWallet::Wallet::LocalWallet());
380 QString pass
= wiz
->field("pass1").toString();
381 QByteArray
p(pass
.toUtf8(), pass
.length());
384 b
->createFolder(KWallet::Wallet::PasswordFolder());
385 b
->createFolder(KWallet::Wallet::FormDataFolder());
393 } else if (_firstUse
&& !isPath
) {
394 KConfig
kwalletrc("kwalletrc");
395 KConfigGroup
cfg(&kwalletrc
, "Wallet");
397 cfg
.writeEntry("First Use", false);
400 int rc
= internalOpen(appid
, wallet
, isPath
, WId(wId
), modal
, service
);
405 int KWalletD::internalOpen(const QString
& appid
, const QString
& wallet
, bool isPath
, WId w
,
406 bool modal
, const QString
& service
) {
407 bool brandNew
= false;
410 if (appid
.isEmpty()) {
411 thisApp
= "KDE System";
416 if (implicitDeny(wallet
, thisApp
)) {
420 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
421 int rc
= walletInfo
.first
;
423 if (_wallets
.count() > 20) {
424 kDebug() << "Too many wallets open.";
428 KWallet::Backend
*b
= new KWallet::Backend(wallet
, isPath
);
430 bool emptyPass
= false;
431 if ((isPath
&& QFile::exists(wallet
)) || (!isPath
&& KWallet::Backend::exists(wallet
))) {
432 int pwless
= b
->open(QByteArray());
433 if (0 != pwless
|| !b
->isOpen()) {
435 // release, start anew
437 b
= new KWallet::Backend(wallet
, isPath
);
439 KPasswordDialog
*kpd
= new KPasswordDialog();
440 if (appid
.isEmpty()) {
441 kpd
->setPrompt(i18n("<qt>KDE has requested to open the wallet '<b>%1</b>'. Please enter the password for this wallet below.</qt>", Qt::escape(wallet
)));
443 kpd
->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to open the wallet '<b>%2</b>'. Please enter the password for this wallet below.</qt>", Qt::escape(appid
), Qt::escape(wallet
)));
446 // don't use KStdGuiItem::open() here which has trailing ellipsis!
447 kpd
->setButtonGuiItem(KDialog::Ok
,KGuiItem( i18n( "&Open" ), "document-open"));
448 kpd
->setCaption(i18n("KDE Wallet Service"));
449 kpd
->setPixmap(KIcon("kwalletmanager").pixmap(KIconLoader::SizeHuge
));
450 while (!b
->isOpen()) {
451 setupDialog( kpd
, w
, appid
, modal
);
452 if (kpd
->exec() == KDialog::Accepted
) {
453 password
= kpd
->password();
454 int rc
= b
->open(password
.toUtf8());
456 kpd
->setPrompt(i18n("<qt>Error opening the wallet '<b>%1</b>'. Please try again.<br />(Error code %2: %3)</qt>", Qt::escape(wallet
), rc
, KWallet::Backend::openRCToString(rc
)));
467 KNewPasswordDialog
*kpd
= new KNewPasswordDialog();
468 if (wallet
== KWallet::Wallet::LocalWallet() ||
469 wallet
== KWallet::Wallet::NetworkWallet())
471 // Auto create these wallets.
472 if (appid
.isEmpty()) {
473 kpd
->setPrompt(i18n("KDE has requested to open the wallet. This is used to store sensitive data in a secure fashion. Please enter a password to use with this wallet or click cancel to deny the application's request."));
475 kpd
->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to open the KDE wallet. This is used to store sensitive data in a secure fashion. Please enter a password to use with this wallet or click cancel to deny the application's request.</qt>", Qt::escape(appid
)));
478 if (appid
.length() == 0) {
479 kpd
->setPrompt(i18n("<qt>KDE has requested to create a new wallet named '<b>%1</b>'. Please choose a password for this wallet, or cancel to deny the application's request.</qt>", Qt::escape(wallet
)));
481 kpd
->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to create a new wallet named '<b>%2</b>'. Please choose a password for this wallet, or cancel to deny the application's request.</qt>", Qt::escape(appid
), Qt::escape(wallet
)));
485 kpd
->setCaption(i18n("KDE Wallet Service"));
486 kpd
->setButtonGuiItem(KDialog::Ok
,KGuiItem(i18n("C&reate"),"document-new"));
487 kpd
->setPixmap(KIcon("kwalletmanager").pixmap(96, 96));
488 while (!b
->isOpen()) {
489 setupDialog( kpd
, w
, appid
, modal
);
490 if (kpd
->exec() == KDialog::Accepted
) {
491 password
= kpd
->password();
492 int rc
= b
->open(password
.toUtf8());
494 kpd
->setPrompt(i18n("<qt>Error opening the wallet '<b>%1</b>'. Please try again.<br />(Error code %2: %3)</qt>", Qt::escape(wallet
), rc
, KWallet::Backend::openRCToString(rc
)));
505 if (!emptyPass
&& (password
.isNull() || !b
->isOpen())) {
510 if (emptyPass
&& _openPrompt
&& !isAuthorizedApp(appid
, wallet
, w
)) {
515 _wallets
.insert(rc
= generateHandle(), b
);
516 _sessions
.addSession(appid
, service
, rc
);
517 _syncTimers
.addTimer(rc
, _syncTime
);
520 createFolder(rc
, KWallet::Wallet::PasswordFolder(), appid
);
521 createFolder(rc
, KWallet::Wallet::FormDataFolder(), appid
);
526 _closeTimers
.addTimer(rc
, _idleTime
);
529 emit
walletCreated(wallet
);
530 emit
walletOpened(wallet
);
531 if (_wallets
.count() == 1 && _launchManager
) {
532 KToolInvocation::startServiceByDesktopName("kwalletmanager-kwalletd");
535 if (!_sessions
.hasSession(appid
, rc
) && !isAuthorizedApp(appid
, wallet
, w
)) {
538 _sessions
.addSession(appid
, service
, rc
);
539 _wallets
.value(rc
)->ref();
546 bool KWalletD::isAuthorizedApp(const QString
& appid
, const QString
& wallet
, WId w
) {
550 if (appid
.isEmpty()) {
551 thisApp
= "KDE System";
556 if (!implicitAllow(wallet
, thisApp
)) {
557 KConfigGroup cfg
= KSharedConfig::openConfig("kwalletrc")->group("Auto Allow");
558 if (!cfg
.isEntryImmutable(wallet
)) {
559 KBetterThanKDialog
*dialog
= new KBetterThanKDialog
;
560 if (appid
.isEmpty()) {
561 dialog
->setLabel(i18n("<qt>KDE has requested access to the open wallet '<b>%1</b>'.</qt>", Qt::escape(wallet
)));
563 dialog
->setLabel(i18n("<qt>The application '<b>%1</b>' has requested access to the open wallet '<b>%2</b>'.</qt>", Qt::escape(QString(appid
)), Qt::escape(wallet
)));
565 setupDialog( dialog
, w
, appid
, false );
566 response
= dialog
->exec();
571 if (response
== 0 || response
== 1) {
573 KConfigGroup cfg
= KSharedConfig::openConfig("kwalletrc")->group("Auto Allow");
574 QStringList apps
= cfg
.readEntry(wallet
, QStringList());
575 if (!apps
.contains(thisApp
)) {
576 if (cfg
.isEntryImmutable(wallet
)) {
580 _implicitAllowMap
[wallet
] += thisApp
;
581 cfg
.writeEntry(wallet
, apps
);
585 } else if (response
== 3) {
586 KConfigGroup cfg
= KSharedConfig::openConfig("kwalletrc")->group("Auto Deny");
587 QStringList apps
= cfg
.readEntry(wallet
, QStringList());
588 if (!apps
.contains(thisApp
)) {
590 _implicitDenyMap
[wallet
] += thisApp
;
591 cfg
.writeEntry(wallet
, apps
);
602 int KWalletD::deleteWallet(const QString
& wallet
) {
603 QString path
= KGlobal::dirs()->saveLocation("kwallet") + QDir::separator() + wallet
+ ".kwl";
605 if (QFile::exists(path
)) {
606 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
607 internalClose(walletInfo
.second
, walletInfo
.first
, true);
609 emit
walletDeleted(wallet
);
617 void KWalletD::changePassword(const QString
& wallet
, qlonglong wId
, const QString
& appid
) {
618 KWalletTransaction
*xact
= new KWalletTransaction
;
620 //msg.setDelayedReply(true);
622 xact
->wallet
= wallet
;
625 xact
->tType
= KWalletTransaction::ChangePassword
;
627 _transactions
.append(xact
);
629 QTimer::singleShot(0, this, SLOT(processTransactions()));
634 void KWalletD::initiateSync(int handle
) {
635 // add a timer and reset it right away
636 _syncTimers
.addTimer(handle
, _syncTime
);
637 _syncTimers
.resetTimer(handle
, _syncTime
);
640 void KWalletD::doTransactionChangePassword(const QString
& appid
, const QString
& wallet
, qlonglong wId
) {
642 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
643 int handle
= walletInfo
.first
;
644 KWallet::Backend
* w
= walletInfo
.second
;
646 bool reclose
= false;
648 handle
= doTransactionOpen(appid
, wallet
, false, wId
, false, false);
650 KMessageBox::sorryWId((WId
)wId
, i18n("Unable to open wallet. The wallet must be opened in order to change the password."), i18n("KDE Wallet Service"));
654 w
= _wallets
.value(handle
);
660 KNewPasswordDialog
*kpd
= new KNewPasswordDialog();
661 kpd
->setPrompt(i18n("<qt>Please choose a new password for the wallet '<b>%1</b>'.</qt>", Qt::escape(wallet
)));
662 kpd
->setCaption(i18n("KDE Wallet Service"));
663 kpd
->setAllowEmptyPasswords(true);
664 setupDialog( kpd
, (WId
)wId
, appid
, false );
665 if (kpd
->exec() == KDialog::Accepted
) {
666 QString p
= kpd
->password();
668 w
->setPassword(p
.toUtf8());
669 int rc
= w
->close(true);
671 KMessageBox::sorryWId((WId
)wId
, i18n("Error re-encrypting the wallet. Password was not changed."), i18n("KDE Wallet Service"));
674 rc
= w
->open(p
.toUtf8());
676 KMessageBox::sorryWId((WId
)wId
, i18n("Error reopening the wallet. Data may be lost."), i18n("KDE Wallet Service"));
686 internalClose(w
, handle
, true);
691 int KWalletD::close(const QString
& wallet
, bool force
) {
692 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
693 int handle
= walletInfo
.first
;
694 KWallet::Backend
* w
= walletInfo
.second
;
696 return internalClose(w
, handle
, force
);
700 int KWalletD::internalClose(KWallet::Backend
*w
, int handle
, bool force
) {
702 const QString
& wallet
= w
->walletName();
703 if ((w
->refCount() == 0 && !_leaveOpen
) || force
) {
704 // this is only a safety measure. sessions should be gone already.
705 _sessions
.removeAllSessions(handle
);
707 _closeTimers
.removeTimer(handle
);
709 _syncTimers
.removeTimer(handle
);
710 _wallets
.remove(handle
);
712 doCloseSignals(handle
, wallet
);
723 int KWalletD::close(int handle
, bool force
, const QString
& appid
) {
724 KWallet::Backend
*w
= _wallets
.value(handle
);
727 if (_sessions
.hasSession(appid
, handle
)) {
728 // remove one handle for the application
729 bool removed
= _sessions
.removeSession(appid
, message().service(), handle
);
730 // alternatively try sessionless
731 if (removed
|| _sessions
.removeSession(appid
, "", handle
)) {
734 return internalClose(w
, handle
, force
);
736 return 1; // not closed, handle unknown
738 return -1; // not open to begin with, or other error
742 bool KWalletD::isOpen(const QString
& wallet
) {
743 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
744 return walletInfo
.second
!= 0;
748 bool KWalletD::isOpen(int handle
) {
753 KWallet::Backend
*rc
= _wallets
.value(handle
);
755 if (rc
== 0 && ++_failed
> 5) {
757 QTimer::singleShot(0, this, SLOT(notifyFailures()));
758 } else if (rc
!= 0) {
766 QStringList
KWalletD::wallets() const {
767 QString path
= KGlobal::dirs()->saveLocation("kwallet");
768 QDir
dir(path
, "*.kwl");
771 dir
.setFilter(QDir::Files
| QDir::Hidden
);
773 foreach (const QFileInfo
&fi
, dir
.entryInfoList()) {
774 QString fn
= fi
.fileName();
775 if (fn
.endsWith(".kwl")) {
776 fn
.truncate(fn
.length()-4);
784 void KWalletD::sync(int handle
, const QString
& appid
) {
787 // get the wallet and check if we have a password for it (safety measure)
788 if ((b
= getWallet(appid
, handle
))) {
789 QString wallet
= b
->walletName();
794 void KWalletD::timedOutSync(int handle
) {
795 _syncTimers
.removeTimer(handle
);
796 if (_wallets
.contains(handle
) && _wallets
[handle
]) {
797 _wallets
[handle
]->sync();
801 void KWalletD::doTransactionOpenCancelled(const QString
& appid
, const QString
& wallet
,
802 const QString
& service
) {
804 // there will only be one session left to remove - all others
805 // have already been removed in slotServiceOwnerChanged and all
806 // transactions for opening new sessions have been deleted.
807 if (!_sessions
.hasSession(appid
)) {
811 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
812 int handle
= walletInfo
.first
;
813 KWallet::Backend
*b
= walletInfo
.second
;
814 if (handle
!= -1 && b
) {
816 internalClose(b
, handle
, false);
819 // close the session in case the wallet hasn't been closed yet
820 _sessions
.removeSession(appid
, service
, handle
);
823 QStringList
KWalletD::folderList(int handle
, const QString
& appid
) {
826 if ((b
= getWallet(appid
, handle
))) {
827 return b
->folderList();
830 return QStringList();
834 bool KWalletD::hasFolder(int handle
, const QString
& f
, const QString
& appid
) {
837 if ((b
= getWallet(appid
, handle
))) {
838 return b
->hasFolder(f
);
845 bool KWalletD::removeFolder(int handle
, const QString
& f
, const QString
& appid
) {
848 if ((b
= getWallet(appid
, handle
))) {
849 bool rc
= b
->removeFolder(f
);
850 initiateSync(handle
);
851 emit
folderListUpdated(b
->walletName());
859 bool KWalletD::createFolder(int handle
, const QString
& f
, const QString
& appid
) {
862 if ((b
= getWallet(appid
, handle
))) {
863 bool rc
= b
->createFolder(f
);
864 initiateSync(handle
);
865 emit
folderListUpdated(b
->walletName());
873 QByteArray
KWalletD::readMap(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
876 if ((b
= getWallet(appid
, handle
))) {
877 b
->setFolder(folder
);
878 KWallet::Entry
*e
= b
->readEntry(key
);
879 if (e
&& e
->type() == KWallet::Wallet::Map
) {
888 QVariantMap
KWalletD::readMapList(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
891 if ((b
= getWallet(appid
, handle
))) {
892 b
->setFolder(folder
);
894 foreach (KWallet::Entry
*entry
, b
->readEntryList(key
)) {
895 if (entry
->type() == KWallet::Wallet::Map
) {
896 rc
.insert(entry
->key(), entry
->map());
902 return QVariantMap();
906 QByteArray
KWalletD::readEntry(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
909 if ((b
= getWallet(appid
, handle
))) {
910 b
->setFolder(folder
);
911 KWallet::Entry
*e
= b
->readEntry(key
);
921 QVariantMap
KWalletD::readEntryList(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
924 if ((b
= getWallet(appid
, handle
))) {
925 b
->setFolder(folder
);
927 foreach (KWallet::Entry
*entry
, b
->readEntryList(key
)) {
928 rc
.insert(entry
->key(), entry
->value());
933 return QVariantMap();
937 QStringList
KWalletD::entryList(int handle
, const QString
& folder
, const QString
& appid
) {
940 if ((b
= getWallet(appid
, handle
))) {
941 b
->setFolder(folder
);
942 return b
->entryList();
945 return QStringList();
949 QString
KWalletD::readPassword(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
952 if ((b
= getWallet(appid
, handle
))) {
953 b
->setFolder(folder
);
954 KWallet::Entry
*e
= b
->readEntry(key
);
955 if (e
&& e
->type() == KWallet::Wallet::Password
) {
956 return e
->password();
964 QVariantMap
KWalletD::readPasswordList(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
967 if ((b
= getWallet(appid
, handle
))) {
968 b
->setFolder(folder
);
970 foreach (KWallet::Entry
*entry
, b
->readEntryList(key
)) {
971 if (entry
->type() == KWallet::Wallet::Password
) {
972 rc
.insert(entry
->key(), entry
->password());
978 return QVariantMap();
982 int KWalletD::writeMap(int handle
, const QString
& folder
, const QString
& key
, const QByteArray
& value
, const QString
& appid
) {
985 if ((b
= getWallet(appid
, handle
))) {
986 b
->setFolder(folder
);
990 e
.setType(KWallet::Wallet::Map
);
992 initiateSync(handle
);
993 emitFolderUpdated(b
->walletName(), folder
);
1001 int KWalletD::writeEntry(int handle
, const QString
& folder
, const QString
& key
, const QByteArray
& value
, int entryType
, const QString
& appid
) {
1002 KWallet::Backend
*b
;
1004 if ((b
= getWallet(appid
, handle
))) {
1005 b
->setFolder(folder
);
1009 e
.setType(KWallet::Wallet::EntryType(entryType
));
1011 initiateSync(handle
);
1012 emitFolderUpdated(b
->walletName(), folder
);
1020 int KWalletD::writeEntry(int handle
, const QString
& folder
, const QString
& key
, const QByteArray
& value
, const QString
& appid
) {
1021 KWallet::Backend
*b
;
1023 if ((b
= getWallet(appid
, handle
))) {
1024 b
->setFolder(folder
);
1028 e
.setType(KWallet::Wallet::Stream
);
1030 initiateSync(handle
);
1031 emitFolderUpdated(b
->walletName(), folder
);
1039 int KWalletD::writePassword(int handle
, const QString
& folder
, const QString
& key
, const QString
& value
, const QString
& appid
) {
1040 KWallet::Backend
*b
;
1042 if ((b
= getWallet(appid
, handle
))) {
1043 b
->setFolder(folder
);
1047 e
.setType(KWallet::Wallet::Password
);
1049 initiateSync(handle
);
1050 emitFolderUpdated(b
->walletName(), folder
);
1058 int KWalletD::entryType(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
1059 KWallet::Backend
*b
;
1061 if ((b
= getWallet(appid
, handle
))) {
1062 if (!b
->hasFolder(folder
)) {
1063 return KWallet::Wallet::Unknown
;
1065 b
->setFolder(folder
);
1066 if (b
->hasEntry(key
)) {
1067 return b
->readEntry(key
)->type();
1071 return KWallet::Wallet::Unknown
;
1075 bool KWalletD::hasEntry(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
1076 KWallet::Backend
*b
;
1078 if ((b
= getWallet(appid
, handle
))) {
1079 if (!b
->hasFolder(folder
)) {
1082 b
->setFolder(folder
);
1083 return b
->hasEntry(key
);
1090 int KWalletD::removeEntry(int handle
, const QString
& folder
, const QString
& key
, const QString
& appid
) {
1091 KWallet::Backend
*b
;
1093 if ((b
= getWallet(appid
, handle
))) {
1094 if (!b
->hasFolder(folder
)) {
1097 b
->setFolder(folder
);
1098 bool rc
= b
->removeEntry(key
);
1099 initiateSync(handle
);
1100 emitFolderUpdated(b
->walletName(), folder
);
1108 void KWalletD::slotServiceOwnerChanged(const QString
& name
, const QString
&oldOwner
,
1109 const QString
& newOwner
)
1113 if (!newOwner
.isEmpty()) {
1114 return; // no application exit, don't care.
1117 // as we don't have the application id we have to cycle
1118 // all sessions. As an application can basically open wallets
1119 // with several appids, we can't stop if we found one.
1120 QString
service(oldOwner
);
1121 QList
<KWalletAppHandlePair
> sessremove(_sessions
.findSessions(service
));
1122 KWallet::Backend
*b
= 0;
1124 // check all sessions for wallets to close
1125 Q_FOREACH(const KWalletAppHandlePair
&s
, sessremove
) {
1126 b
= getWallet(s
.first
, s
.second
);
1129 internalClose(b
, s
.second
, false);
1133 // remove all the sessions in case they aren't gone yet
1134 Q_FOREACH(const KWalletAppHandlePair
&s
, sessremove
) {
1135 _sessions
.removeSession(s
.first
, service
, s
.second
);
1138 // cancel all open-transactions still running for the service
1139 QList
<KWalletTransaction
*>::iterator tit
;
1140 for (tit
= _transactions
.begin(); tit
!= _transactions
.end(); ++tit
) {
1141 if ((*tit
)->tType
== KWalletTransaction::Open
&& (*tit
)->service
== oldOwner
) {
1146 _transactions
.removeAll(0);
1148 // if there's currently an open-transaction being handled,
1149 // mark it as cancelled.
1150 if (_curtrans
&& _curtrans
->tType
== KWalletTransaction::Open
&&
1151 _curtrans
->service
== oldOwner
) {
1152 _curtrans
->cancelled
= true;
1156 KWallet::Backend
*KWalletD::getWallet(const QString
& appid
, int handle
) {
1161 KWallet::Backend
*w
= _wallets
.value(handle
);
1163 if (w
) { // the handle is valid
1164 if (_sessions
.hasSession(appid
, handle
)) {
1165 // the app owns this handle
1168 _closeTimers
.resetTimer(handle
, _idleTime
);
1174 if (++_failed
> 5) {
1176 QTimer::singleShot(0, this, SLOT(notifyFailures()));
1183 void KWalletD::notifyFailures() {
1184 if (!_showingFailureNotify
) {
1185 _showingFailureNotify
= true;
1186 KMessageBox::information(0, i18n("There have been repeated failed attempts to gain access to a wallet. An application may be misbehaving."), i18n("KDE Wallet Service"));
1187 _showingFailureNotify
= false;
1192 void KWalletD::doCloseSignals(int handle
, const QString
& wallet
) {
1193 emit
walletClosed(handle
);
1194 emit
walletClosed(wallet
);
1195 if (_wallets
.isEmpty()) {
1196 emit
allWalletsClosed();
1201 int KWalletD::renameEntry(int handle
, const QString
& folder
, const QString
& oldName
, const QString
& newName
, const QString
& appid
) {
1202 KWallet::Backend
*b
;
1204 if ((b
= getWallet(appid
, handle
))) {
1205 b
->setFolder(folder
);
1206 int rc
= b
->renameEntry(oldName
, newName
);
1207 initiateSync(handle
);
1208 emitFolderUpdated(b
->walletName(), folder
);
1216 QStringList
KWalletD::users(const QString
& wallet
) const {
1217 const QPair
<int,KWallet::Backend
*> walletInfo
= findWallet(wallet
);
1218 return _sessions
.getApplications(walletInfo
.first
);
1222 bool KWalletD::disconnectApplication(const QString
& wallet
, const QString
& application
) {
1223 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
1224 int handle
= walletInfo
.first
;
1225 KWallet::Backend
* backend
= walletInfo
.second
;
1227 if (handle
!= -1 && _sessions
.hasSession(application
, handle
)) {
1228 int removed
= _sessions
.removeAllSessions(application
, handle
);
1230 for (int i
= 0; i
< removed
; ++i
) {
1233 internalClose(backend
, handle
, false);
1235 emit
applicationDisconnected(wallet
, application
);
1243 void KWalletD::emitFolderUpdated(const QString
& wallet
, const QString
& folder
) {
1244 emit
folderUpdated(wallet
, folder
);
1248 void KWalletD::emitWalletListDirty() {
1249 emit
walletListDirty();
1253 void KWalletD::reconfigure() {
1254 KConfig
cfg("kwalletrc");
1255 KConfigGroup
walletGroup(&cfg
, "Wallet");
1256 _firstUse
= walletGroup
.readEntry("First Use", true);
1257 _enabled
= walletGroup
.readEntry("Enabled", true);
1258 _launchManager
= walletGroup
.readEntry("Launch Manager", true);
1259 _leaveOpen
= walletGroup
.readEntry("Leave Open", false);
1260 bool idleSave
= _closeIdle
;
1261 _closeIdle
= walletGroup
.readEntry("Close When Idle", false);
1262 _openPrompt
= walletGroup
.readEntry("Prompt on Open", true);
1263 int timeSave
= _idleTime
;
1265 _idleTime
= walletGroup
.readEntry("Idle Timeout", 10) * 60 * 1000;
1267 if ( screensaver
->isValid() ) {
1268 if (walletGroup
.readEntry("Close on Screensaver", false)) {
1269 connect(screensaver
, SIGNAL(ActiveChanged(bool)), SLOT(screenSaverChanged(bool)));
1271 screensaver
->disconnect(SIGNAL(ActiveChanged(bool)), this, SLOT(screenSaverChanged(bool)));
1275 // Handle idle changes
1277 if (_idleTime
!= timeSave
) { // Timer length changed
1278 Wallets::const_iterator it
= _wallets
.constBegin();
1279 const Wallets::const_iterator end
= _wallets
.constEnd();
1280 for (; it
!= end
; ++it
) {
1281 _closeTimers
.resetTimer(it
.key(), _idleTime
);
1285 if (!idleSave
) { // add timers for all the wallets
1286 Wallets::const_iterator it
= _wallets
.constBegin();
1287 const Wallets::const_iterator end
= _wallets
.constEnd();
1288 for (; it
!= end
; ++it
) {
1289 _closeTimers
.addTimer(it
.key(), _idleTime
);
1293 _closeTimers
.clear();
1296 // Update the implicit allow stuff
1297 _implicitAllowMap
.clear();
1298 const KConfigGroup
autoAllowGroup(&cfg
, "Auto Allow");
1299 QStringList entries
= autoAllowGroup
.entryMap().keys();
1300 for (QStringList::const_iterator i
= entries
.constBegin(); i
!= entries
.constEnd(); ++i
) {
1301 _implicitAllowMap
[*i
] = autoAllowGroup
.readEntry(*i
, QStringList());
1304 // Update the implicit allow stuff
1305 _implicitDenyMap
.clear();
1306 const KConfigGroup
autoDenyGroup(&cfg
, "Auto Deny");
1307 entries
= autoDenyGroup
.entryMap().keys();
1308 for (QStringList::const_iterator i
= entries
.constBegin(); i
!= entries
.constEnd(); ++i
) {
1309 _implicitDenyMap
[*i
] = autoDenyGroup
.readEntry(*i
, QStringList());
1312 // Update if wallet was enabled/disabled
1313 if (!_enabled
) { // close all wallets
1314 while (!_wallets
.isEmpty()) {
1315 Wallets::const_iterator it
= _wallets
.constBegin();
1316 internalClose(it
.value(), it
.key(), true);
1318 KUniqueApplication::exit(0);
1323 bool KWalletD::isEnabled() const {
1328 bool KWalletD::folderDoesNotExist(const QString
& wallet
, const QString
& folder
) {
1329 if (!wallets().contains(wallet
)) {
1333 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
1334 if (walletInfo
.second
) {
1335 return walletInfo
.second
->folderDoesNotExist(folder
);
1338 KWallet::Backend
*b
= new KWallet::Backend(wallet
);
1339 b
->open(QByteArray());
1340 bool rc
= b
->folderDoesNotExist(folder
);
1346 bool KWalletD::keyDoesNotExist(const QString
& wallet
, const QString
& folder
, const QString
& key
) {
1347 if (!wallets().contains(wallet
)) {
1351 const QPair
<int, KWallet::Backend
*> walletInfo
= findWallet(wallet
);
1352 if (walletInfo
.second
) {
1353 return walletInfo
.second
->entryDoesNotExist(folder
, key
);
1356 KWallet::Backend
*b
= new KWallet::Backend(wallet
);
1357 b
->open(QByteArray());
1358 bool rc
= b
->entryDoesNotExist(folder
, key
);
1364 bool KWalletD::implicitAllow(const QString
& wallet
, const QString
& app
) {
1365 return _implicitAllowMap
[wallet
].contains(app
);
1369 bool KWalletD::implicitDeny(const QString
& wallet
, const QString
& app
) {
1370 return _implicitDenyMap
[wallet
].contains(app
);
1374 void KWalletD::timedOutClose(int id
) {
1375 KWallet::Backend
*w
= _wallets
.value(id
);
1377 internalClose(w
, id
, true);
1382 void KWalletD::closeAllWallets() {
1383 Wallets walletsCopy
= _wallets
;
1385 Wallets::const_iterator it
= walletsCopy
.constBegin();
1386 const Wallets::const_iterator end
= walletsCopy
.constEnd();
1387 for (; it
!= end
; ++it
) {
1388 internalClose(it
.value(), it
.key(), true);
1391 walletsCopy
.clear();
1393 // All of this should be basically noop. Let's just be safe.
1398 QString
KWalletD::networkWallet() {
1399 return KWallet::Wallet::NetworkWallet();
1403 QString
KWalletD::localWallet() {
1404 return KWallet::Wallet::LocalWallet();
1407 void KWalletD::screenSaverChanged(bool s
)
1413 #include "kwalletd.moc"