fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kdeui / util / kwallet.cpp
blobb85e83059b722ee9e391b47c30aed3dcc8d6da39
1 /* This file is part of the KDE project
3 * Copyright (C) 2002-2004 George Staikos <staikos@kde.org>
4 * Copyright (C) 2008 Michael Leupold <lemma@confuego.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include "kwallet.h"
23 #include <ksharedconfig.h>
24 #include <kdebug.h>
25 #include <kdeversion.h>
26 #include <QtGui/QApplication>
27 #include <QtCore/QPointer>
28 #include <QtGui/QWidget>
29 #include <QtDBus/QtDBus>
30 #include <ktoolinvocation.h>
32 #include <assert.h>
33 #include <kglobal.h>
34 #include <kcomponentdata.h>
35 #include <kaboutdata.h>
36 #include <kconfiggroup.h>
38 #include "kwallet_interface.h"
40 using namespace KWallet;
42 typedef QMap<QString, QString> StringStringMap;
43 Q_DECLARE_METATYPE(StringStringMap)
44 typedef QMap<QString, StringStringMap> StringToStringStringMapMap;
45 Q_DECLARE_METATYPE(StringToStringStringMapMap)
46 typedef QMap<QString, QByteArray> StringByteArrayMap;
47 Q_DECLARE_METATYPE(StringByteArrayMap)
49 static QString appid()
51 KComponentData cData = KGlobal::mainComponent();
52 if (cData.isValid()) {
53 const KAboutData* aboutData = cData.aboutData();
54 if (aboutData) {
55 return aboutData->programName();
57 return cData.componentName();
59 return qApp->applicationName();
62 static void registerTypes()
64 static bool registered = false;
65 if (!registered) {
66 qDBusRegisterMetaType<StringStringMap>();
67 qDBusRegisterMetaType<StringToStringStringMapMap>();
68 qDBusRegisterMetaType<StringByteArrayMap>();
69 registered = true;
73 const QString Wallet::LocalWallet() {
74 KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet"));
75 if (!cfg.readEntry("Use One Wallet", true)) {
76 QString tmp = cfg.readEntry("Local Wallet", "localwallet");
77 if (tmp.isEmpty()) {
78 return "localwallet";
80 return tmp;
83 QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
84 if (tmp.isEmpty()) {
85 return "kdewallet";
87 return tmp;
90 const QString Wallet::NetworkWallet() {
91 KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet"));
93 QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
94 if (tmp.isEmpty()) {
95 return "kdewallet";
97 return tmp;
100 const QString Wallet::PasswordFolder() {
101 return "Passwords";
104 const QString Wallet::FormDataFolder() {
105 return "Form Data";
108 class Wallet::WalletPrivate
110 public:
111 WalletPrivate(int h, const QString &n)
112 : name(n), handle(h)
114 QString name;
115 QString folder;
116 int handle;
117 int transactionId;
118 QPointer<QEventLoop> loop;
121 class KWalletDLauncher
123 public:
124 KWalletDLauncher();
125 ~KWalletDLauncher();
126 org::kde::KWallet &getInterface();
127 private:
128 org::kde::KWallet m_wallet;
129 KConfigGroup m_cgroup;
132 K_GLOBAL_STATIC(KWalletDLauncher, walletLauncher)
134 Wallet::Wallet(int handle, const QString& name)
135 : QObject(0L), d(new WalletPrivate(handle, name)) {
137 connect(QDBusConnection::sessionBus().interface(),
138 SIGNAL(serviceOwnerChanged(QString,QString,QString)),
139 this,
140 SLOT(slotServiceOwnerChanged(QString,QString,QString)));
142 connect(&walletLauncher->getInterface(), SIGNAL(walletClosed(int)), SLOT(slotWalletClosed(int)));
143 connect(&walletLauncher->getInterface(), SIGNAL(folderListUpdated(QString)), SLOT(slotFolderListUpdated(QString)));
144 connect(&walletLauncher->getInterface(), SIGNAL(folderUpdated(QString,QString)), SLOT(slotFolderUpdated(QString, QString)));
145 connect(&walletLauncher->getInterface(), SIGNAL(applicationDisconnected(QString, QString)), SLOT(slotApplicationDisconnected(QString, QString)));
147 // Verify that the wallet is still open
148 if (d->handle != -1) {
149 QDBusReply<bool> r = walletLauncher->getInterface().isOpen(d->handle);
150 if (r.isValid() && !r) {
151 d->handle = -1;
152 d->name.clear();
158 Wallet::~Wallet() {
159 if (d->handle != -1) {
160 if (!walletLauncher.isDestroyed()) {
161 walletLauncher->getInterface().close(d->handle, false, appid());
162 } else {
163 kDebug(285) << "Problem with static destruction sequence."
164 "Destroy any static Wallet before the event-loop exits.";
166 d->handle = -1;
167 d->folder.clear();
168 d->name.clear();
170 delete d;
174 QStringList Wallet::walletList() {
175 return walletLauncher->getInterface().wallets();
179 void Wallet::changePassword(const QString& name, WId w) {
180 if( w == 0 )
181 kDebug(285) << "Pass a valid window to KWallet::Wallet::changePassword().";
182 walletLauncher->getInterface().changePassword(name, (qlonglong)w, appid());
186 bool Wallet::isEnabled() {
187 QDBusReply<bool> r = walletLauncher->getInterface().isEnabled();
188 return (r.isValid() && r);
192 bool Wallet::isOpen(const QString& name) {
193 return walletLauncher->getInterface().isOpen(name); // default is false
197 int Wallet::closeWallet(const QString& name, bool force) {
198 QDBusReply<int> r = walletLauncher->getInterface().close(name, force);
199 return r.isValid() ? r : -1;
203 int Wallet::deleteWallet(const QString& name) {
204 QDBusReply<int> r = walletLauncher->getInterface().deleteWallet(name);
205 return r.isValid() ? r : -1;
209 Wallet *Wallet::openWallet(const QString& name, WId w, OpenType ot) {
210 if( w == 0 )
211 kDebug(285) << "Pass a valid window to KWallet::Wallet::openWallet().";
213 Wallet *wallet = new Wallet(-1, name);
215 // connect the daemon's opened signal to the slot filtering the
216 // signals we need
217 connect(&walletLauncher->getInterface(), SIGNAL(walletAsyncOpened(int, int)),
218 wallet, SLOT(walletAsyncOpened(int, int)));
220 // Use an eventloop for synchronous calls
221 QEventLoop loop;
222 if (ot == Synchronous || ot == Path) {
223 connect(wallet, SIGNAL(walletOpened(bool)), &loop, SLOT(quit()));
226 // do the call
227 QDBusReply<int> r;
228 if (ot == Synchronous || ot == Asynchronous) {
229 r = walletLauncher->getInterface().openAsync(name, (qlonglong)w, appid(), true);
230 } else if (ot == Path) {
231 r = walletLauncher->getInterface().openPathAsync(name, (qlonglong)w, appid(), true);
232 } else {
233 delete wallet;
234 return 0;
236 // error communicating with the daemon (maybe not running)
237 if (!r.isValid()) {
238 delete wallet;
239 return 0;
241 wallet->d->transactionId = r.value();
243 if (ot == Synchronous || ot == Path) {
244 // check for an immediate error
245 if (wallet->d->transactionId < 0) {
246 delete wallet;
247 wallet = 0;
248 } else {
249 // wait for the daemon's reply
250 // store a pointer to the event loop so it can be quit in error case
251 wallet->d->loop = &loop;
252 loop.exec();
253 if (wallet->d->handle < 0) {
254 delete wallet;
255 return 0;
258 } else if (ot == Asynchronous) {
259 if (wallet->d->transactionId < 0) {
260 QTimer::singleShot(0, wallet, SLOT(emitWalletAsyncOpenError()));
261 // client code is responsible for deleting the wallet
265 return wallet;
269 bool Wallet::disconnectApplication(const QString& wallet, const QString& app) {
270 return walletLauncher->getInterface().disconnectApplication(wallet, app); // default is false
274 QStringList Wallet::users(const QString& name) {
275 return walletLauncher->getInterface().users(name); // default is QStringList()
279 int Wallet::sync() {
280 if (d->handle == -1) {
281 return -1;
284 walletLauncher->getInterface().sync(d->handle, appid());
285 return 0;
289 int Wallet::lockWallet() {
290 if (d->handle == -1) {
291 return -1;
294 QDBusReply<int> r = walletLauncher->getInterface().close(d->handle, true, appid());
295 d->handle = -1;
296 d->folder.clear();
297 d->name.clear();
298 if (r.isValid()) {
299 return r;
301 return -1;
305 const QString& Wallet::walletName() const {
306 return d->name;
310 bool Wallet::isOpen() const {
311 return d->handle != -1;
315 void Wallet::requestChangePassword(WId w) {
316 if( w == 0 )
317 kDebug(285) << "Pass a valid window to KWallet::Wallet::requestChangePassword().";
318 if (d->handle == -1) {
319 return;
322 walletLauncher->getInterface().changePassword(d->name, (qlonglong)w, appid());
326 void Wallet::slotWalletClosed(int handle) {
327 if (d->handle == handle) {
328 d->handle = -1;
329 d->folder.clear();
330 d->name.clear();
331 emit walletClosed();
336 QStringList Wallet::folderList() {
337 if (d->handle == -1) {
338 return QStringList();
341 QDBusReply<QStringList> r = walletLauncher->getInterface().folderList(d->handle, appid());
342 return r;
346 QStringList Wallet::entryList() {
347 if (d->handle == -1) {
348 return QStringList();
351 QDBusReply<QStringList> r = walletLauncher->getInterface().entryList(d->handle, d->folder, appid());
352 return r;
356 bool Wallet::hasFolder(const QString& f) {
357 if (d->handle == -1) {
358 return false;
361 QDBusReply<bool> r = walletLauncher->getInterface().hasFolder(d->handle, f, appid());
362 return r; // default is false
366 bool Wallet::createFolder(const QString& f) {
367 if (d->handle == -1) {
368 return false;
371 if (!hasFolder(f)) {
372 QDBusReply<bool> r = walletLauncher->getInterface().createFolder(d->handle, f, appid());
373 return r;
376 return true; // folder already exists
380 bool Wallet::setFolder(const QString& f) {
381 bool rc = false;
383 if (d->handle == -1) {
384 return rc;
387 // Don't do this - the folder could have disappeared?
388 #if 0
389 if (f == d->folder) {
390 return true;
392 #endif
394 if (hasFolder(f)) {
395 d->folder = f;
396 rc = true;
399 return rc;
403 bool Wallet::removeFolder(const QString& f) {
404 if (d->handle == -1) {
405 return false;
408 QDBusReply<bool> r = walletLauncher->getInterface().removeFolder(d->handle, f, appid());
409 if (d->folder == f) {
410 setFolder(QString());
413 return r; // default is false
417 const QString& Wallet::currentFolder() const {
418 return d->folder;
422 int Wallet::readEntry(const QString& key, QByteArray& value) {
423 int rc = -1;
425 if (d->handle == -1) {
426 return rc;
429 QDBusReply<QByteArray> r = walletLauncher->getInterface().readEntry(d->handle, d->folder, key, appid());
430 if (r.isValid()) {
431 value = r;
432 rc = 0;
435 return rc;
439 int Wallet::readEntryList(const QString& key, QMap<QString, QByteArray>& value) {
440 registerTypes();
442 int rc = -1;
444 if (d->handle == -1) {
445 return rc;
448 QDBusReply<QVariantMap> r = walletLauncher->getInterface().readEntryList(d->handle, d->folder, key, appid());
449 if (r.isValid()) {
450 rc = 0;
451 // convert <QString, QVariant> to <QString, QByteArray>
452 const QVariantMap val = r.value();
453 for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) {
454 value.insert(it.key(), it.value().toByteArray());
458 return rc;
462 int Wallet::renameEntry(const QString& oldName, const QString& newName) {
463 int rc = -1;
465 if (d->handle == -1) {
466 return rc;
469 QDBusReply<int> r = walletLauncher->getInterface().renameEntry(d->handle, d->folder, oldName, newName, appid());
470 if (r.isValid()) {
471 rc = r;
474 return rc;
478 int Wallet::readMap(const QString& key, QMap<QString,QString>& value) {
479 registerTypes();
481 int rc = -1;
483 if (d->handle == -1) {
484 return rc;
487 QDBusReply<QByteArray> r = walletLauncher->getInterface().readMap(d->handle, d->folder, key, appid());
488 if (r.isValid()) {
489 rc = 0;
490 QByteArray v = r;
491 if (!v.isEmpty()) {
492 QDataStream ds(&v, QIODevice::ReadOnly);
493 ds >> value;
497 return rc;
501 int Wallet::readMapList(const QString& key, QMap<QString, QMap<QString, QString> >& value) {
502 registerTypes();
504 int rc = -1;
506 if (d->handle == -1) {
507 return rc;
510 QDBusReply<QVariantMap> r =
511 walletLauncher->getInterface().readMapList(d->handle, d->folder, key, appid());
512 if (r.isValid()) {
513 rc = 0;
514 const QVariantMap val = r.value();
515 for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) {
516 QByteArray mapData = it.value().toByteArray();
517 if (!mapData.isEmpty()) {
518 QDataStream ds(&mapData, QIODevice::ReadOnly);
519 QMap<QString,QString> v;
520 ds >> v;
521 value.insert(it.key(), v);
526 return rc;
530 int Wallet::readPassword(const QString& key, QString& value) {
531 int rc = -1;
533 if (d->handle == -1) {
534 return rc;
537 QDBusReply<QString> r = walletLauncher->getInterface().readPassword(d->handle, d->folder, key, appid());
538 if (r.isValid()) {
539 value = r;
540 rc = 0;
543 return rc;
547 int Wallet::readPasswordList(const QString& key, QMap<QString, QString>& value) {
548 registerTypes();
550 int rc = -1;
552 if (d->handle == -1) {
553 return rc;
556 QDBusReply<QVariantMap> r = walletLauncher->getInterface().readPasswordList(d->handle, d->folder, key, appid());
557 if (r.isValid()) {
558 rc = 0;
559 const QVariantMap val = r.value();
560 for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) {
561 value.insert(it.key(), it.value().toString());
565 return rc;
569 int Wallet::writeEntry(const QString& key, const QByteArray& value, EntryType entryType) {
570 int rc = -1;
572 if (d->handle == -1) {
573 return rc;
576 QDBusReply<int> r = walletLauncher->getInterface().writeEntry(d->handle, d->folder, key, value, int(entryType), appid());
577 if (r.isValid()) {
578 rc = r;
581 return rc;
585 int Wallet::writeEntry(const QString& key, const QByteArray& value) {
586 int rc = -1;
588 if (d->handle == -1) {
589 return rc;
592 QDBusReply<int> r = walletLauncher->getInterface().writeEntry(d->handle, d->folder, key, value, appid());
593 if (r.isValid()) {
594 rc = r;
597 return rc;
601 int Wallet::writeMap(const QString& key, const QMap<QString,QString>& value) {
602 registerTypes();
604 int rc = -1;
606 if (d->handle == -1) {
607 return rc;
610 QByteArray mapData;
611 QDataStream ds(&mapData, QIODevice::WriteOnly);
612 ds << value;
613 QDBusReply<int> r = walletLauncher->getInterface().writeMap(d->handle, d->folder, key, mapData, appid());
614 if (r.isValid()) {
615 rc = r;
618 return rc;
622 int Wallet::writePassword(const QString& key, const QString& value) {
623 int rc = -1;
625 if (d->handle == -1) {
626 return rc;
629 QDBusReply<int> r = walletLauncher->getInterface().writePassword(d->handle, d->folder, key, value, appid());
630 if (r.isValid()) {
631 rc = r;
634 return rc;
638 bool Wallet::hasEntry(const QString& key) {
639 if (d->handle == -1) {
640 return false;
643 QDBusReply<bool> r = walletLauncher->getInterface().hasEntry(d->handle, d->folder, key, appid());
644 return r; // default is false
648 int Wallet::removeEntry(const QString& key) {
649 int rc = -1;
651 if (d->handle == -1) {
652 return rc;
655 QDBusReply<int> r = walletLauncher->getInterface().removeEntry(d->handle, d->folder, key, appid());
656 if (r.isValid()) {
657 rc = r;
660 return rc;
664 Wallet::EntryType Wallet::entryType(const QString& key) {
665 int rc = 0;
667 if (d->handle == -1) {
668 return Wallet::Unknown;
671 QDBusReply<int> r = walletLauncher->getInterface().entryType(d->handle, d->folder, key, appid());
672 if (r.isValid()) {
673 rc = r;
676 return static_cast<EntryType>(rc);
680 void Wallet::slotServiceOwnerChanged(const QString& name,const QString& oldOwner,const QString& newOwner) {
681 Q_UNUSED(oldOwner);
682 if (newOwner.isEmpty() && name == "org.kde.kwalletd") {
683 // if openWallet() waits for the DBUS reply, prevent it from waiting forever:
684 if ( d->loop )
685 d->loop->quit();
686 if( d->handle >= 0 )
687 slotWalletClosed(d->handle);
692 void Wallet::slotFolderUpdated(const QString& wallet, const QString& folder) {
693 if (d->name == wallet) {
694 emit folderUpdated(folder);
699 void Wallet::slotFolderListUpdated(const QString& wallet) {
700 if (d->name == wallet) {
701 emit folderListUpdated();
706 void Wallet::slotApplicationDisconnected(const QString& wallet, const QString& application) {
707 if (d->handle >= 0
708 && d->name == wallet
709 && application == appid()) {
710 slotWalletClosed(d->handle);
714 void Wallet::walletAsyncOpened(int tId, int handle) {
715 // ignore responses to calls other than ours
716 if (d->transactionId != tId || d->handle != -1) {
717 return;
720 // disconnect the async signal
721 disconnect(this, SLOT(walletAsyncOpened(int, int)));
723 d->handle = handle;
724 emit walletOpened(handle > 0);
727 void Wallet::emitWalletAsyncOpenError() {
728 emit walletOpened(false);
731 bool Wallet::folderDoesNotExist(const QString& wallet, const QString& folder)
733 QDBusReply<bool> r = walletLauncher->getInterface().folderDoesNotExist(wallet, folder);
734 return r;
738 bool Wallet::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key)
740 QDBusReply<bool> r = walletLauncher->getInterface().keyDoesNotExist(wallet, folder, key);
741 return r;
744 void Wallet::virtual_hook(int, void*) {
745 //BASE::virtual_hook( id, data );
748 KWalletDLauncher::KWalletDLauncher()
749 : m_wallet("org.kde.kwalletd", "/modules/kwalletd", QDBusConnection::sessionBus()),
750 m_cgroup(KSharedConfig::openConfig("kwalletrc", KConfig::NoGlobals)->group("Wallet"))
754 KWalletDLauncher::~KWalletDLauncher()
758 org::kde::KWallet &KWalletDLauncher::getInterface()
760 // check if kwalletd is already running
761 if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kwalletd"))
763 // not running! check if it is enabled.
764 bool walletEnabled = m_cgroup.readEntry("Enabled", true);
765 if (walletEnabled) {
766 // wallet is enabled! try launching it
767 QString error;
768 int ret = KToolInvocation::startServiceByDesktopPath("kwalletd.desktop", QStringList(), &error);
769 if (ret > 0)
771 kError(285) << "Couldn't start kwalletd: " << error << endl;
774 if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kwalletd")) {
775 kDebug(285) << "The kwalletd service is still not registered";
776 } else {
777 kDebug(285) << "The kwalletd service has been registered";
779 } else {
780 kError(285) << "The kwalletd service has been disabled";
784 return m_wallet;
787 #include "kwallet.moc"