kio Library API Documentation

kwalletd.cpp

00001 /* 00002 This file is part of the KDE libraries 00003 00004 Copyright (c) 2002-2004 George Staikos <staikos@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00019 Boston, MA 02111-1307, USA. 00020 00021 */ 00022 00023 #include "kbetterthankdialogbase.h" 00024 #include "kwalletwizard.h" 00025 #include "kwalletd.h" 00026 #include "ktimeout.h" 00027 00028 #include <dcopclient.h> 00029 #include <dcopref.h> 00030 #include <kactivelabel.h> 00031 #include <kapplication.h> 00032 #include <kconfig.h> 00033 #include <kdebug.h> 00034 #include <kdirwatch.h> 00035 #include <kglobal.h> 00036 #include <klocale.h> 00037 #include <kmessagebox.h> 00038 #include <kpassdlg.h> 00039 #include <kstandarddirs.h> 00040 #include <kwalletentry.h> 00041 #include <kwin.h> 00042 00043 #include <qdir.h> 00044 #include <qlabel.h> 00045 #include <qlayout.h> 00046 #include <qpushbutton.h> 00047 #include <qregexp.h> 00048 #include <qstylesheet.h> 00049 #include <qvbox.h> 00050 00051 #include <assert.h> 00052 00053 #ifdef Q_WS_X11 00054 #include <X11/Xlib.h> 00055 #endif 00056 00057 extern "C" { 00058 KDE_EXPORT KDEDModule *create_kwalletd(const QCString &name) { 00059 return new KWalletD(name); 00060 } 00061 } 00062 00063 00064 class KWalletTransaction { 00065 public: 00066 KWalletTransaction() { 00067 tType = Unknown; 00068 transaction = 0L; 00069 client = 0L; 00070 } 00071 00072 ~KWalletTransaction() { 00073 // Don't delete these! 00074 transaction = 0L; 00075 client = 0L; 00076 } 00077 00078 enum Type { Unknown, Open, ChangePassword, OpenFail }; 00079 DCOPClient *client; 00080 DCOPClientTransaction *transaction; 00081 Type tType; 00082 QCString rawappid, returnObject; 00083 QCString appid; 00084 uint wId; 00085 QString wallet; 00086 }; 00087 00088 00089 KWalletD::KWalletD(const QCString &name) 00090 : KDEDModule(name), _failed(0) { 00091 srand(time(0)); 00092 _showingFailureNotify = false; 00093 _transactions.setAutoDelete(true); 00094 _timeouts = new KTimeout(17); 00095 _closeIdle = false; 00096 _idleTime = 0; 00097 connect(_timeouts, SIGNAL(timedOut(int)), this, SLOT(timedOut(int))); 00098 reconfigure(); 00099 KGlobal::dirs()->addResourceType("kwallet", "share/apps/kwallet"); 00100 connect(KApplication::dcopClient(), 00101 SIGNAL(applicationRemoved(const QCString&)), 00102 this, 00103 SLOT(slotAppUnregistered(const QCString&))); 00104 _dw = new KDirWatch(this, "KWallet Directory Watcher"); 00105 _dw->addDir(KGlobal::dirs()->saveLocation("kwallet")); 00106 _dw->startScan(true); 00107 connect(_dw, SIGNAL(dirty(const QString&)), this, SLOT(emitWalletListDirty())); 00108 } 00109 00110 00111 KWalletD::~KWalletD() { 00112 delete _timeouts; 00113 _timeouts = 0; 00114 00115 closeAllWallets(); 00116 _transactions.clear(); 00117 } 00118 00119 00120 int KWalletD::generateHandle() { 00121 int rc; 00122 00123 // ASSUMPTION: RAND_MAX is fairly large. 00124 do { 00125 rc = rand(); 00126 } while (_wallets.find(rc) || rc == 0); 00127 00128 return rc; 00129 } 00130 00131 00132 void KWalletD::processTransactions() { 00133 static bool processing = false; 00134 00135 if (processing) { 00136 return; 00137 } 00138 00139 processing = true; 00140 00141 // Process remaining transactions 00142 KWalletTransaction *xact; 00143 while (!_transactions.isEmpty()) { 00144 xact = _transactions.first(); 00145 QCString replyType; 00146 int res; 00147 00148 assert(xact->tType != KWalletTransaction::Unknown); 00149 00150 switch (xact->tType) { 00151 case KWalletTransaction::Open: 00152 res = doTransactionOpen(xact->appid, xact->wallet, xact->wId); 00153 replyType = "int"; 00154 if (!xact->returnObject.isEmpty()) { 00155 DCOPRef(xact->rawappid, xact->returnObject).send("walletOpenResult", res); 00156 } 00157 00158 // multiple requests from the same client 00159 // should not produce multiple password 00160 // dialogs on a failure 00161 if (res < 0) { 00162 QPtrListIterator<KWalletTransaction> it(_transactions); 00163 KWalletTransaction *x; 00164 while ((x = it.current()) && x != xact) { 00165 ++it; 00166 } 00167 if (x) { 00168 ++it; 00169 } 00170 while ((x = it.current())) { 00171 if (xact->appid == x->appid && x->tType == KWalletTransaction::Open && x->wallet == xact->wallet && x->wId == xact->wId) { 00172 x->tType = KWalletTransaction::OpenFail; 00173 } 00174 ++it; 00175 } 00176 } 00177 break; 00178 case KWalletTransaction::OpenFail: 00179 res = -1; 00180 replyType = "int"; 00181 if (!xact->returnObject.isEmpty()) { 00182 DCOPRef(xact->rawappid, xact->returnObject).send("walletOpenResult", res); 00183 } 00184 break; 00185 case KWalletTransaction::ChangePassword: 00186 doTransactionChangePassword(xact->appid, xact->wallet, xact->wId); 00187 // fall through - no return 00188 default: 00189 _transactions.removeRef(xact); 00190 continue; 00191 } 00192 00193 if (xact->returnObject.isEmpty() && xact->tType != KWalletTransaction::ChangePassword) { 00194 QByteArray replyData; 00195 QDataStream stream(replyData, IO_WriteOnly); 00196 stream << res; 00197 xact->client->endTransaction(xact->transaction, replyType, replyData); 00198 } 00199 _transactions.removeRef(xact); 00200 } 00201 00202 processing = false; 00203 } 00204 00205 00206 void KWalletD::openAsynchronous(const QString& wallet, const QCString& returnObject, uint wId) { 00207 DCOPClient *dc = callingDcopClient(); 00208 if (!dc) { 00209 return; 00210 } 00211 00212 QCString appid = dc->senderId(); 00213 if (!_enabled || 00214 !QRegExp("^[A-Za-z0-9]+[A-Za-z0-9\\s\\-_]*$").exactMatch(wallet)) { 00215 DCOPRef(appid, returnObject).send("walletOpenResult", -1); 00216 return; 00217 } 00218 00219 QCString peerName = friendlyDCOPPeerName(); 00220 00221 KWalletTransaction *xact = new KWalletTransaction; 00222 00223 xact->appid = peerName; 00224 xact->rawappid = appid; 00225 xact->client = callingDcopClient(); 00226 xact->wallet = wallet; 00227 xact->wId = wId; 00228 xact->tType = KWalletTransaction::Open; 00229 xact->returnObject = returnObject; 00230 _transactions.append(xact); 00231 00232 DCOPRef(appid, returnObject).send("walletOpenResult", 0); 00233 00234 QTimer::singleShot(0, this, SLOT(processTransactions())); 00235 } 00236 00237 00238 int KWalletD::openPath(const QString& path, uint wId) { 00239 if (!_enabled) { // guard 00240 return -1; 00241 } 00242 00243 // FIXME: setup transaction 00244 int rc = internalOpen(friendlyDCOPPeerName(), path, true, wId); 00245 return rc; 00246 } 00247 00248 00249 int KWalletD::open(const QString& wallet, uint wId) { 00250 if (!_enabled) { // guard 00251 return -1; 00252 } 00253 00254 if (!QRegExp("^[A-Za-z0-9]+[A-Za-z0-9\\s\\-_]*$").exactMatch(wallet)) { 00255 return -1; 00256 } 00257 00258 QCString appid = friendlyDCOPPeerName(); 00259 00260 KWalletTransaction *xact = new KWalletTransaction; 00261 _transactions.append(xact); 00262 00263 if (_transactions.count() > 1) { 00264 xact->appid = appid; 00265 xact->client = callingDcopClient(); 00266 xact->transaction = xact->client->beginTransaction(); 00267 xact->wallet = wallet; 00268 xact->wId = wId; 00269 xact->tType = KWalletTransaction::Open; 00270 return 0; // process later 00271 } 00272 00273 int rc = doTransactionOpen(appid, wallet, wId); 00274 00275 _transactions.remove(xact); 00276 00277 if (rc < 0) { 00278 // multiple requests from the same client should not produce multiple password dialogs on a failure 00279 for (KWalletTransaction *x = _transactions.first(); x; x = _transactions.next()) { 00280 if (appid == x->appid && x->tType == KWalletTransaction::Open && x->wallet == wallet && x->wId == wId) 00281 x->tType = KWalletTransaction::OpenFail; 00282 } 00283 } 00284 00285 processTransactions(); 00286 00287 return rc; 00288 } 00289 00290 00291 int KWalletD::doTransactionOpen(const QCString& appid, const QString& wallet, uint wId) { 00292 if (_firstUse && !wallets().contains(KWallet::Wallet::LocalWallet())) { 00293 // First use wizard 00294 KWalletWizard *wiz = new KWalletWizard(0); 00295 #ifdef Q_WS_X11 00296 XSetTransientForHint(qt_xdisplay(), wiz->winId(), wId); 00297 #endif 00298 int rc = wiz->exec(); 00299 if (rc == QDialog::Accepted) { 00300 KConfig cfg("kwalletrc"); 00301 cfg.setGroup("Wallet"); 00302 cfg.writeEntry("First Use", false); 00303 cfg.writeEntry("Enabled", wiz->_useWallet->isChecked()); 00304 cfg.writeEntry("Close When Idle", wiz->_closeIdle->isChecked()); 00305 cfg.writeEntry("Use One Wallet", !wiz->_networkWallet->isChecked()); 00306 cfg.sync(); 00307 reconfigure(); 00308 00309 if (!wiz->_useWallet->isChecked()) { 00310 delete wiz; 00311 return -1; 00312 } 00313 00314 // Create the wallet 00315 KWallet::Backend *b = new KWallet::Backend(KWallet::Wallet::LocalWallet()); 00316 QByteArray p; 00317 p.duplicate(wiz->_pass1->text().utf8(), wiz->_pass1->text().length()); 00318 b->open(p); 00319 b->createFolder(KWallet::Wallet::PasswordFolder()); 00320 b->createFolder(KWallet::Wallet::FormDataFolder()); 00321 b->close(p); 00322 p.fill(0); 00323 delete b; 00324 delete wiz; 00325 } else { 00326 delete wiz; 00327 return -1; 00328 } 00329 } else if (_firstUse) { 00330 KConfig cfg("kwalletrc"); 00331 _firstUse = false; 00332 cfg.setGroup("Wallet"); 00333 cfg.writeEntry("First Use", false); 00334 cfg.sync(); 00335 } 00336 00337 int rc = internalOpen(appid, wallet, false, wId); 00338 return rc; 00339 } 00340 00341 00342 int KWalletD::internalOpen(const QCString& appid, const QString& wallet, bool isPath, WId w) { 00343 int rc = -1; 00344 bool brandNew = false; 00345 00346 QCString thisApp; 00347 if (appid.isEmpty()) { 00348 thisApp = "KDE System"; 00349 } else { 00350 thisApp = appid; 00351 } 00352 00353 if (implicitDeny(wallet, thisApp)) { 00354 return -1; 00355 } 00356 00357 for (QIntDictIterator<KWallet::Backend> i(_wallets); i.current(); ++i) { 00358 if (i.current()->walletName() == wallet) { 00359 rc = i.currentKey(); 00360 break; 00361 } 00362 } 00363 00364 if (rc == -1) { 00365 if (_wallets.count() > 20) { 00366 kdDebug() << "Too many wallets open." << endl; 00367 return -1; 00368 } 00369 00370 KWallet::Backend *b = new KWallet::Backend(wallet, isPath); 00371 KPasswordDialog *kpd = 0L; 00372 bool emptyPass = false; 00373 if ((isPath && QFile::exists(wallet)) || (!isPath && KWallet::Backend::exists(wallet))) { 00374 int pwless = b->open(QByteArray()); 00375 if (0 != pwless || !b->isOpen()) { 00376 if (pwless == 0) { 00377 // release, start anew 00378 delete b; 00379 b = new KWallet::Backend(wallet, isPath); 00380 } 00381 kpd = new KPasswordDialog(KPasswordDialog::Password, false, 0); 00382 if (appid.isEmpty()) { 00383 kpd->setPrompt(i18n("<qt>KDE has requested to open the wallet '<b>%1</b>'. Please enter the password for this wallet below.").arg(QStyleSheet::escape(wallet))); 00384 } else { 00385 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.").arg(QStyleSheet::escape(appid)).arg(QStyleSheet::escape(wallet))); 00386 } 00387 brandNew = false; 00388 kpd->setButtonOK(KGuiItem(i18n("&Open"),"fileopen")); 00389 } else { 00390 emptyPass = true; 00391 } 00392 } else if (wallet == KWallet::Wallet::LocalWallet() || 00393 wallet == KWallet::Wallet::NetworkWallet()) { 00394 // Auto create these wallets. 00395 kpd = new KPasswordDialog(KPasswordDialog::NewPassword, false, 0); 00396 if (appid.isEmpty()) { 00397 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.")); 00398 } else { 00399 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.").arg(QStyleSheet::escape(appid))); 00400 } 00401 brandNew = true; 00402 kpd->setButtonOK(KGuiItem(i18n("&Open"),"fileopen")); 00403 } else { 00404 kpd = new KPasswordDialog(KPasswordDialog::NewPassword, false, 0); 00405 if (appid.length() == 0) { 00406 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.").arg(QStyleSheet::escape(wallet))); 00407 } else { 00408 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.").arg(QStyleSheet::escape(appid)).arg(QStyleSheet::escape(wallet))); 00409 } 00410 brandNew = true; 00411 kpd->setButtonOK(KGuiItem(i18n("C&reate"),"filenew")); 00412 } 00413 00414 if (kpd) { 00415 kpd->setCaption(i18n("KDE Wallet Service")); 00416 kpd->setAllowEmptyPasswords(true); 00417 } 00418 00419 const char *p = 0L; 00420 while (!b->isOpen()) { 00421 #ifdef Q_WS_X11 00422 XSetTransientForHint(qt_xdisplay(), kpd->winId(), w); 00423 #endif 00424 KWin::setState( kpd->winId(), NET::KeepAbove ); 00425 KWin::setOnAllDesktops(kpd->winId(), true); 00426 if (kpd->exec() == KDialog::Accepted) { 00427 p = kpd->password(); 00428 int rc = b->open(QByteArray().duplicate(p, strlen(p))); 00429 if (!b->isOpen()) { 00430 kpd->setPrompt(i18n("<qt>Error opening the wallet '<b>%1</b>'. Please try again.<br>(Error code %2: %3)").arg(QStyleSheet::escape(wallet)).arg(rc).arg(KWallet::Backend::openRCToString(rc))); 00431 kpd->clearPassword(); 00432 } 00433 } else { 00434 break; 00435 } 00436 } 00437 00438 if (!emptyPass && (!p || !b->isOpen())) { 00439 delete b; 00440 delete kpd; 00441 return -1; 00442 } 00443 00444 if (emptyPass && _openPrompt && !isAuthorizedApp(appid, wallet, w)) { 00445 delete b; 00446 delete kpd; 00447 return -1; 00448 } 00449 00450 _wallets.insert(rc = generateHandle(), b); 00451 if (emptyPass) { 00452 _passwords[wallet] = ""; 00453 } else { 00454 _passwords[wallet] = p; 00455 } 00456 _handles[appid].append(rc); 00457 00458 delete kpd; // don't refactor this!! Argh I hate KPassDlg 00459 00460 if (brandNew) { 00461 createFolder(rc, KWallet::Wallet::PasswordFolder()); 00462 createFolder(rc, KWallet::Wallet::FormDataFolder()); 00463 } 00464 00465 b->ref(); 00466 if (_closeIdle && _timeouts) { 00467 _timeouts->addTimer(rc, _idleTime); 00468 } 00469 QByteArray data; 00470 QDataStream ds(data, IO_WriteOnly); 00471 ds << wallet; 00472 if (brandNew) { 00473 emitDCOPSignal("walletCreated(QString)", data); 00474 } 00475 emitDCOPSignal("walletOpened(QString)", data); 00476 if (_wallets.count() == 1 && _launchManager) { 00477 KApplication::startServiceByDesktopName("kwalletmanager-kwalletd"); 00478 } 00479 } else { 00480 if (!_handles[appid].contains(rc) && _openPrompt && !isAuthorizedApp(appid, wallet, w)) { 00481 return -1; 00482 } 00483 _handles[appid].append(rc); 00484 _wallets.find(rc)->ref(); 00485 } 00486 00487 return rc; 00488 } 00489 00490 00491 bool KWalletD::isAuthorizedApp(const QCString& appid, const QString& wallet, WId w) { 00492 int response = 0; 00493 00494 QCString thisApp; 00495 if (appid.isEmpty()) { 00496 thisApp = "KDE System"; 00497 } else { 00498 thisApp = appid; 00499 } 00500 00501 if (!implicitAllow(wallet, thisApp)) { 00502 KBetterThanKDialogBase *dialog = new KBetterThanKDialogBase; 00503 if (appid.isEmpty()) { 00504 dialog->setLabel(i18n("<qt>KDE has requested access to the open wallet '<b>%1</b>'.").arg(QStyleSheet::escape(wallet))); 00505 } else { 00506 dialog->setLabel(i18n("<qt>The application '<b>%1</b>' has requested access to the open wallet '<b>%2</b>'.").arg(QStyleSheet::escape(QString(appid))).arg(QStyleSheet::escape(wallet))); 00507 } 00508 #ifdef Q_WS_X11 00509 XSetTransientForHint(qt_xdisplay(), dialog->winId(), w); 00510 #endif 00511 KWin::setState(dialog->winId(), NET::KeepAbove); 00512 KWin::setOnAllDesktops(dialog->winId(), true); 00513 00514 response = dialog->exec(); 00515 delete dialog; 00516 } 00517 00518 if (response == 0 || response == 1) { 00519 if (response == 1) { 00520 KConfig cfg("kwalletrc"); 00521 cfg.setGroup("Auto Allow"); 00522 QStringList apps = cfg.readListEntry(wallet); 00523 if (!apps.contains(thisApp)) { 00524 apps += thisApp; 00525 _implicitAllowMap[wallet] += thisApp; 00526 cfg.writeEntry(wallet, apps); 00527 cfg.sync(); 00528 } 00529 } 00530 } else if (response == 3) { 00531 KConfig cfg("kwalletrc"); 00532 cfg.setGroup("Auto Deny"); 00533 QStringList apps = cfg.readListEntry(wallet); 00534 if (!apps.contains(thisApp)) { 00535 apps += thisApp; 00536 _implicitDenyMap[wallet] += thisApp; 00537 cfg.writeEntry(wallet, apps); 00538 cfg.sync(); 00539 } 00540 return false; 00541 } else { 00542 return false; 00543 } 00544 return true; 00545 } 00546 00547 00548 int KWalletD::deleteWallet(const QString& wallet) { 00549 QString path = KGlobal::dirs()->saveLocation("kwallet") + QDir::separator() + wallet + ".kwl"; 00550 00551 if (QFile::exists(path)) { 00552 close(wallet, true); 00553 QFile::remove(path); 00554 QByteArray data; 00555 QDataStream ds(data, IO_WriteOnly); 00556 ds << wallet; 00557 emitDCOPSignal("walletDeleted(QString)", data); 00558 return 0; 00559 } 00560 00561 return -1; 00562 } 00563 00564 00565 void KWalletD::changePassword(const QString& wallet, uint wId) { 00566 QCString appid = friendlyDCOPPeerName(); 00567 00568 KWalletTransaction *xact = new KWalletTransaction; 00569 00570 xact->appid = appid; 00571 xact->client = callingDcopClient(); 00572 xact->wallet = wallet; 00573 xact->wId = wId; 00574 xact->tType = KWalletTransaction::ChangePassword; 00575 00576 _transactions.append(xact); 00577 00578 QTimer::singleShot(0, this, SLOT(processTransactions())); 00579 } 00580 00581 00582 void KWalletD::doTransactionChangePassword(const QCString& appid, const QString& wallet, uint wId) { 00583 QIntDictIterator<KWallet::Backend> it(_wallets); 00584 KWallet::Backend *w = 0L; 00585 int handle = -1; 00586 bool reclose = false; 00587 00588 for (; it.current(); ++it) { 00589 if (it.current()->walletName() == wallet) { 00590 break; 00591 } 00592 } 00593 00594 if (!it.current()) { 00595 handle = doTransactionOpen(appid, wallet, wId); 00596 if (-1 == handle) { 00597 KMessageBox::sorryWId(wId, i18n("Unable to open wallet. The wallet must be opened in order to change the password."), i18n("KDE Wallet Service")); 00598 return; 00599 } 00600 00601 w = _wallets.find(handle); 00602 reclose = true; 00603 } else { 00604 handle = it.currentKey(); 00605 w = it.current(); 00606 } 00607 00608 assert(w); 00609 00610 KPasswordDialog *kpd; 00611 kpd = new KPasswordDialog(KPasswordDialog::NewPassword, false, 0); 00612 kpd->setPrompt(i18n("<qt>Please choose a new password for the wallet '<b>%1</b>'.").arg(QStyleSheet::escape(wallet))); 00613 kpd->setCaption(i18n("KDE Wallet Service")); 00614 kpd->setAllowEmptyPasswords(true); 00615 #ifdef Q_WS_X11 00616 XSetTransientForHint(qt_xdisplay(), kpd->winId(), wId); 00617 #endif 00618 if (kpd->exec() == KDialog::Accepted) { 00619 const char *p = kpd->password(); 00620 if (p) { 00621 _passwords[wallet] = p; 00622 QByteArray pa; 00623 pa.duplicate(p, strlen(p)); 00624 int rc = w->close(pa); 00625 if (rc < 0) { 00626 KMessageBox::sorryWId(wId, i18n("Error re-encrypting the wallet. Password was not changed."), i18n("KDE Wallet Service")); 00627 reclose = true; 00628 } else { 00629 rc = w->open(pa); 00630 if (rc < 0) { 00631 KMessageBox::sorryWId(wId, i18n("Error reopening the wallet. Data may be lost."), i18n("KDE Wallet Service")); 00632 reclose = true; 00633 } 00634 } 00635 } 00636 } 00637 00638 delete kpd; 00639 00640 if (reclose) { 00641 close(handle, true); 00642 } 00643 } 00644 00645 00646 int KWalletD::close(const QString& wallet, bool force) { 00647 int handle = -1; 00648 KWallet::Backend *w = 0L; 00649 00650 for (QIntDictIterator<KWallet::Backend> it(_wallets); 00651 it.current(); 00652 ++it) { 00653 if (it.current()->walletName() == wallet) { 00654 handle = it.currentKey(); 00655 w = it.current(); 00656 break; 00657 } 00658 } 00659 00660 return closeWallet(w, handle, force); 00661 } 00662 00663 00664 int KWalletD::closeWallet(KWallet::Backend *w, int handle, bool force) { 00665 if (w) { 00666 const QString& wallet = w->walletName(); 00667 assert(_passwords.contains(wallet)); 00668 if (w->refCount() == 0 || force) { 00669 invalidateHandle(handle); 00670 if (_closeIdle && _timeouts) { 00671 _timeouts->removeTimer(handle); 00672 } 00673 _wallets.remove(handle); 00674 if (_passwords.contains(wallet)) { 00675 w->close(QByteArray().duplicate(_passwords[wallet].data(), _passwords[wallet].length())); 00676 _passwords[wallet].fill(0); 00677 _passwords.remove(wallet); 00678 } 00679 doCloseSignals(handle, wallet); 00680 delete w; 00681 return 0; 00682 } 00683 return 1; 00684 } 00685 00686 return -1; 00687 } 00688 00689 00690 int KWalletD::close(int handle, bool force) { 00691 QCString appid = friendlyDCOPPeerName(); 00692 KWallet::Backend *w = _wallets.find(handle); 00693 bool contains = false; 00694 00695 if (w) { // the handle is valid 00696 if (_handles.contains(appid)) { // we know this app 00697 if (_handles[appid].contains(handle)) { 00698 // the app owns this handle 00699 _handles[appid].remove(_handles[appid].find(handle)); 00700 contains = true; 00701 if (_handles[appid].isEmpty()) { 00702 _handles.remove(appid); 00703 } 00704 } 00705 } 00706 00707 // watch the side effect of the deref() 00708 if ((contains && w->deref() == 0 && !_leaveOpen) || force) { 00709 if (_closeIdle && _timeouts) { 00710 _timeouts->removeTimer(handle); 00711 } 00712 _wallets.remove(handle); 00713 if (force) { 00714 invalidateHandle(handle); 00715 } 00716 if (_passwords.contains(w->walletName())) { 00717 w->close(QByteArray().duplicate(_passwords[w->walletName()].data(), _passwords[w->walletName()].length())); 00718 _passwords[w->walletName()].fill(0); 00719 _passwords.remove(w->walletName()); 00720 } 00721 doCloseSignals(handle, w->walletName()); 00722 delete w; 00723 return 0; 00724 } 00725 return 1; // not closed 00726 } 00727 00728 return -1; // not open to begin with, or other error 00729 } 00730 00731 00732 bool KWalletD::isOpen(const QString& wallet) const { 00733 for (QIntDictIterator<KWallet::Backend> it(_wallets); 00734 it.current(); 00735 ++it) { 00736 if (it.current()->walletName() == wallet) { 00737 return true; 00738 } 00739 } 00740 return false; 00741 } 00742 00743 00744 bool KWalletD::isOpen(int handle) { 00745 if (handle == 0) { 00746 return false; 00747 } 00748 00749 KWallet::Backend *rc = _wallets.find(handle); 00750 00751 if (rc == 0 && ++_failed > 5) { 00752 _failed = 0; 00753 QTimer::singleShot(0, this, SLOT(notifyFailures())); 00754 } else if (rc != 0) { 00755 _failed = 0; 00756 } 00757 00758 return rc != 0; 00759 } 00760 00761 00762 QStringList KWalletD::wallets() const { 00763 QString path = KGlobal::dirs()->saveLocation("kwallet"); 00764 QDir dir(path, "*.kwl"); 00765 QStringList rc; 00766 00767 dir.setFilter(QDir::Files | QDir::NoSymLinks); 00768 00769 const QFileInfoList *list = dir.entryInfoList(); 00770 QFileInfoListIterator it(*list); 00771 QFileInfo *fi; 00772 while ((fi = it.current()) != 0L) { 00773 QString fn = fi->fileName(); 00774 if (fn.endsWith(".kwl")) { 00775 fn.truncate(fn.length()-4); 00776 } 00777 rc += fn; 00778 ++it; 00779 } 00780 return rc; 00781 } 00782 00783 00784 void KWalletD::sync(int handle) { 00785 KWallet::Backend *b; 00786 00787 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00788 QByteArray p; 00789 QString wallet = b->walletName(); 00790 p.duplicate(_passwords[wallet].data(), _passwords[wallet].length()); 00791 b->sync(p); 00792 p.fill(0); 00793 } 00794 } 00795 00796 00797 QStringList KWalletD::folderList(int handle) { 00798 KWallet::Backend *b; 00799 00800 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00801 return b->folderList(); 00802 } 00803 00804 return QStringList(); 00805 } 00806 00807 00808 bool KWalletD::hasFolder(int handle, const QString& f) { 00809 KWallet::Backend *b; 00810 00811 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00812 return b->hasFolder(f); 00813 } 00814 00815 return false; 00816 } 00817 00818 00819 bool KWalletD::removeFolder(int handle, const QString& f) { 00820 KWallet::Backend *b; 00821 00822 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00823 bool rc = b->removeFolder(f); 00824 QByteArray data; 00825 QDataStream ds(data, IO_WriteOnly); 00826 ds << b->walletName(); 00827 emitDCOPSignal("folderListUpdated(QString)", data); 00828 return rc; 00829 } 00830 00831 return false; 00832 } 00833 00834 00835 bool KWalletD::createFolder(int handle, const QString& f) { 00836 KWallet::Backend *b; 00837 00838 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00839 bool rc = b->createFolder(f); 00840 QByteArray data; 00841 QDataStream ds(data, IO_WriteOnly); 00842 ds << b->walletName(); 00843 emitDCOPSignal("folderListUpdated(QString)", data); 00844 return rc; 00845 } 00846 00847 return false; 00848 } 00849 00850 00851 QByteArray KWalletD::readMap(int handle, const QString& folder, const QString& key) { 00852 KWallet::Backend *b; 00853 00854 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00855 b->setFolder(folder); 00856 KWallet::Entry *e = b->readEntry(key); 00857 if (e && e->type() == KWallet::Wallet::Map) { 00858 return e->map(); 00859 } 00860 } 00861 00862 return QByteArray(); 00863 } 00864 00865 00866 QMap<QString,QByteArray> KWalletD::readMapList(int handle, const QString& folder, const QString& key) { 00867 KWallet::Backend *b; 00868 00869 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00870 b->setFolder(folder); 00871 QPtrList<KWallet::Entry> e = b->readEntryList(key); 00872 QMap<QString, QByteArray> rc; 00873 QPtrListIterator<KWallet::Entry> it(e); 00874 KWallet::Entry *entry; 00875 while ((entry = it.current())) { 00876 if (entry->type() == KWallet::Wallet::Map) { 00877 rc.insert(entry->key(), entry->map()); 00878 } 00879 ++it; 00880 } 00881 return rc; 00882 } 00883 00884 return QMap<QString, QByteArray>(); 00885 } 00886 00887 00888 QByteArray KWalletD::readEntry(int handle, const QString& folder, const QString& key) { 00889 KWallet::Backend *b; 00890 00891 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00892 b->setFolder(folder); 00893 KWallet::Entry *e = b->readEntry(key); 00894 if (e) { 00895 return e->value(); 00896 } 00897 } 00898 00899 return QByteArray(); 00900 } 00901 00902 00903 QMap<QString, QByteArray> KWalletD::readEntryList(int handle, const QString& folder, const QString& key) { 00904 KWallet::Backend *b; 00905 00906 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00907 b->setFolder(folder); 00908 QPtrList<KWallet::Entry> e = b->readEntryList(key); 00909 QMap<QString, QByteArray> rc; 00910 QPtrListIterator<KWallet::Entry> it(e); 00911 KWallet::Entry *entry; 00912 while ((entry = it.current())) { 00913 rc.insert(entry->key(), entry->value()); 00914 ++it; 00915 } 00916 return rc; 00917 } 00918 00919 return QMap<QString, QByteArray>(); 00920 } 00921 00922 00923 QStringList KWalletD::entryList(int handle, const QString& folder) { 00924 KWallet::Backend *b; 00925 00926 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00927 b->setFolder(folder); 00928 return b->entryList(); 00929 } 00930 00931 return QStringList(); 00932 } 00933 00934 00935 QString KWalletD::readPassword(int handle, const QString& folder, const QString& key) { 00936 KWallet::Backend *b; 00937 00938 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00939 b->setFolder(folder); 00940 KWallet::Entry *e = b->readEntry(key); 00941 if (e && e->type() == KWallet::Wallet::Password) { 00942 return e->password(); 00943 } 00944 } 00945 00946 return QString::null; 00947 } 00948 00949 00950 QMap<QString, QString> KWalletD::readPasswordList(int handle, const QString& folder, const QString& key) { 00951 KWallet::Backend *b; 00952 00953 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00954 b->setFolder(folder); 00955 QPtrList<KWallet::Entry> e = b->readEntryList(key); 00956 QMap<QString, QString> rc; 00957 QPtrListIterator<KWallet::Entry> it(e); 00958 KWallet::Entry *entry; 00959 while ((entry = it.current())) { 00960 if (entry->type() == KWallet::Wallet::Password) { 00961 rc.insert(entry->key(), entry->password()); 00962 } 00963 ++it; 00964 } 00965 return rc; 00966 } 00967 00968 return QMap<QString, QString>(); 00969 } 00970 00971 00972 int KWalletD::writeMap(int handle, const QString& folder, const QString& key, const QByteArray& value) { 00973 KWallet::Backend *b; 00974 00975 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00976 b->setFolder(folder); 00977 KWallet::Entry e; 00978 e.setKey(key); 00979 e.setValue(value); 00980 e.setType(KWallet::Wallet::Map); 00981 b->writeEntry(&e); 00982 emitFolderUpdated(b->walletName(), folder); 00983 return 0; 00984 } 00985 00986 return -1; 00987 } 00988 00989 00990 int KWalletD::writeEntry(int handle, const QString& folder, const QString& key, const QByteArray& value, int entryType) { 00991 KWallet::Backend *b; 00992 00993 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 00994 b->setFolder(folder); 00995 KWallet::Entry e; 00996 e.setKey(key); 00997 e.setValue(value); 00998 e.setType(KWallet::Wallet::EntryType(entryType)); 00999 b->writeEntry(&e); 01000 emitFolderUpdated(b->walletName(), folder); 01001 return 0; 01002 } 01003 01004 return -1; 01005 } 01006 01007 01008 int KWalletD::writeEntry(int handle, const QString& folder, const QString& key, const QByteArray& value) { 01009 KWallet::Backend *b; 01010 01011 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 01012 b->setFolder(folder); 01013 KWallet::Entry e; 01014 e.setKey(key); 01015 e.setValue(value); 01016 e.setType(KWallet::Wallet::Stream); 01017 b->writeEntry(&e); 01018 emitFolderUpdated(b->walletName(), folder); 01019 return 0; 01020 } 01021 01022 return -1; 01023 } 01024 01025 01026 int KWalletD::writePassword(int handle, const QString& folder, const QString& key, const QString& value) { 01027 KWallet::Backend *b; 01028 01029 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 01030 b->setFolder(folder); 01031 KWallet::Entry e; 01032 e.setKey(key); 01033 e.setValue(value); 01034 e.setType(KWallet::Wallet::Password); 01035 b->writeEntry(&e); 01036 emitFolderUpdated(b->walletName(), folder); 01037 return 0; 01038 } 01039 01040 return -1; 01041 } 01042 01043 01044 int KWalletD::entryType(int handle, const QString& folder, const QString& key) { 01045 KWallet::Backend *b; 01046 01047 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 01048 if (!b->hasFolder(folder)) { 01049 return KWallet::Wallet::Unknown; 01050 } 01051 b->setFolder(folder); 01052 if (b->hasEntry(key)) { 01053 return b->readEntry(key)->type(); 01054 } 01055 } 01056 01057 return KWallet::Wallet::Unknown; 01058 } 01059 01060 01061 bool KWalletD::hasEntry(int handle, const QString& folder, const QString& key) { 01062 KWallet::Backend *b; 01063 01064 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 01065 if (!b->hasFolder(folder)) { 01066 return false; 01067 } 01068 b->setFolder(folder); 01069 return b->hasEntry(key); 01070 } 01071 01072 return false; 01073 } 01074 01075 01076 int KWalletD::removeEntry(int handle, const QString& folder, const QString& key) { 01077 KWallet::Backend *b; 01078 01079 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 01080 if (!b->hasFolder(folder)) { 01081 return 0; 01082 } 01083 b->setFolder(folder); 01084 bool rc = b->removeEntry(key); 01085 emitFolderUpdated(b->walletName(), folder); 01086 return rc ? 0 : -3; 01087 } 01088 01089 return -1; 01090 } 01091 01092 01093 void KWalletD::slotAppUnregistered(const QCString& app) { 01094 if (_handles.contains(app)) { 01095 QValueList<int> l = _handles[app]; 01096 for (QValueList<int>::Iterator i = l.begin(); i != l.end(); i++) { 01097 _handles[app].remove(*i); 01098 KWallet::Backend *w = _wallets.find(*i); 01099 if (w && !_leaveOpen && 0 == w->deref()) { 01100 close(w->walletName(), true); 01101 } 01102 } 01103 _handles.remove(app); 01104 } 01105 } 01106 01107 01108 void KWalletD::invalidateHandle(int handle) { 01109 for (QMap<QCString,QValueList<int> >::Iterator i = _handles.begin(); 01110 i != _handles.end(); 01111 ++i) { 01112 i.data().remove(handle); 01113 } 01114 } 01115 01116 01117 KWallet::Backend *KWalletD::getWallet(const QCString& appid, int handle) { 01118 if (handle == 0) { 01119 return 0L; 01120 } 01121 01122 KWallet::Backend *w = _wallets.find(handle); 01123 01124 if (w) { // the handle is valid 01125 if (_handles.contains(appid)) { // we know this app 01126 if (_handles[appid].contains(handle)) { 01127 // the app owns this handle 01128 _failed = 0; 01129 if (_closeIdle && _timeouts) { 01130 _timeouts->resetTimer(handle, _idleTime); 01131 } 01132 return w; 01133 } 01134 } 01135 } 01136 01137 if (++_failed > 5) { 01138 _failed = 0; 01139 QTimer::singleShot(0, this, SLOT(notifyFailures())); 01140 } 01141 01142 return 0L; 01143 } 01144 01145 01146 void KWalletD::notifyFailures() { 01147 if (!_showingFailureNotify) { 01148 _showingFailureNotify = true; 01149 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")); 01150 _showingFailureNotify = false; 01151 } 01152 } 01153 01154 01155 void KWalletD::doCloseSignals(int handle, const QString& wallet) { 01156 QByteArray data; 01157 QDataStream ds(data, IO_WriteOnly); 01158 ds << handle; 01159 emitDCOPSignal("walletClosed(int)", data); 01160 01161 QByteArray data2; 01162 QDataStream ds2(data2, IO_WriteOnly); 01163 ds2 << wallet; 01164 emitDCOPSignal("walletClosed(QString)", data2); 01165 01166 if (_wallets.isEmpty()) { 01167 emitDCOPSignal("allWalletsClosed()", QByteArray()); 01168 } 01169 } 01170 01171 01172 int KWalletD::renameEntry(int handle, const QString& folder, const QString& oldName, const QString& newName) { 01173 KWallet::Backend *b; 01174 01175 if ((b = getWallet(friendlyDCOPPeerName(), handle))) { 01176 b->setFolder(folder); 01177 int rc = b->renameEntry(oldName, newName); 01178 emitFolderUpdated(b->walletName(), folder); 01179 return rc; 01180 } 01181 01182 return -1; 01183 } 01184 01185 01186 QStringList KWalletD::users(const QString& wallet) const { 01187 QStringList rc; 01188 01189 for (QIntDictIterator<KWallet::Backend> it(_wallets); 01190 it.current(); 01191 ++it) { 01192 if (it.current()->walletName() == wallet) { 01193 for (QMap<QCString,QValueList<int> >::ConstIterator hit = _handles.begin(); hit != _handles.end(); ++hit) { 01194 if (hit.data().contains(it.currentKey())) { 01195 rc += hit.key(); 01196 } 01197 } 01198 break; 01199 } 01200 } 01201 01202 return rc; 01203 } 01204 01205 01206 bool KWalletD::disconnectApplication(const QString& wallet, const QCString& application) { 01207 for (QIntDictIterator<KWallet::Backend> it(_wallets); 01208 it.current(); 01209 ++it) { 01210 if (it.current()->walletName() == wallet) { 01211 if (_handles[application].contains(it.currentKey())) { 01212 _handles[application].remove(it.currentKey()); 01213 01214 if (_handles[application].isEmpty()) { 01215 _handles.remove(application); 01216 } 01217 01218 if (it.current()->deref() == 0) { 01219 close(it.current()->walletName(), true); 01220 } 01221 01222 QByteArray data; 01223 QDataStream ds(data, IO_WriteOnly); 01224 ds << wallet; 01225 ds << application; 01226 emitDCOPSignal("applicationDisconnected(QString,QCString)", data); 01227 01228 return true; 01229 } 01230 } 01231 } 01232 01233 return false; 01234 } 01235 01236 01237 void KWalletD::emitFolderUpdated(const QString& wallet, const QString& folder) { 01238 QByteArray data; 01239 QDataStream ds(data, IO_WriteOnly); 01240 ds << wallet; 01241 ds << folder; 01242 emitDCOPSignal("folderUpdated(QString,QString)", data); 01243 } 01244 01245 01246 void KWalletD::emitWalletListDirty() { 01247 emitDCOPSignal("walletListDirty()", QByteArray()); 01248 } 01249 01250 01251 void KWalletD::reconfigure() { 01252 KConfig cfg("kwalletrc"); 01253 cfg.setGroup("Wallet"); 01254 _firstUse = cfg.readBoolEntry("First Use", true); 01255 _enabled = cfg.readBoolEntry("Enabled", true); 01256 _launchManager = cfg.readBoolEntry("Launch Manager", true); 01257 _leaveOpen = cfg.readBoolEntry("Leave Open", false); 01258 bool idleSave = _closeIdle; 01259 _closeIdle = cfg.readBoolEntry("Close When Idle", false); 01260 _openPrompt = cfg.readBoolEntry("Prompt on Open", true); 01261 int timeSave = _idleTime; 01262 // in minutes! 01263 _idleTime = cfg.readNumEntry("Idle Timeout", 10) * 60 * 1000; 01264 01265 if (cfg.readBoolEntry("Close on Screensaver", false)) { 01266 connectDCOPSignal("kdesktop", "KScreensaverIface", "KDE_start_screensaver()", "closeAllWallets()", false); 01267 } else { 01268 disconnectDCOPSignal("kdesktop", "KScreensaverIface", "KDE_start_screensaver()", "closeAllWallets()"); 01269 } 01270 01271 // Handle idle changes 01272 if (_closeIdle) { 01273 if (_idleTime != timeSave) { // Timer length changed 01274 QIntDictIterator<KWallet::Backend> it(_wallets); 01275 for (; it.current(); ++it) { 01276 _timeouts->resetTimer(it.currentKey(), _idleTime); 01277 } 01278 } 01279 01280 if (!idleSave) { // add timers for all the wallets 01281 QIntDictIterator<KWallet::Backend> it(_wallets); 01282 for (; it.current(); ++it) { 01283 _timeouts->addTimer(it.currentKey(), _idleTime); 01284 } 01285 } 01286 } else { 01287 _timeouts->clear(); 01288 } 01289 01290 // Update the implicit allow stuff 01291 _implicitAllowMap.clear(); 01292 cfg.setGroup("Auto Allow"); 01293 QStringList entries = cfg.entryMap("Auto Allow").keys(); 01294 for (QStringList::Iterator i = entries.begin(); i != entries.end(); ++i) { 01295 _implicitAllowMap[*i] = cfg.readListEntry(*i); 01296 } 01297 01298 // Update the implicit allow stuff 01299 _implicitDenyMap.clear(); 01300 cfg.setGroup("Auto Deny"); 01301 entries = cfg.entryMap("Auto Deny").keys(); 01302 for (QStringList::Iterator i = entries.begin(); i != entries.end(); ++i) { 01303 _implicitDenyMap[*i] = cfg.readListEntry(*i); 01304 } 01305 01306 // Update if wallet was enabled/disabled 01307 if (!_enabled) { // close all wallets 01308 while (!_wallets.isEmpty()) { 01309 QIntDictIterator<KWallet::Backend> it(_wallets); 01310 if (!it.current()) { // necessary? 01311 break; 01312 } 01313 closeWallet(it.current(), it.currentKey(), true); 01314 } 01315 } 01316 } 01317 01318 01319 bool KWalletD::isEnabled() const { 01320 return _enabled; 01321 } 01322 01323 01324 bool KWalletD::folderDoesNotExist(const QString& wallet, const QString& folder) { 01325 if (!wallets().contains(wallet)) { 01326 return true; 01327 } 01328 01329 for (QIntDictIterator<KWallet::Backend> it(_wallets); it.current(); ++it) { 01330 if (it.current()->walletName() == wallet) { 01331 return it.current()->folderDoesNotExist(folder); 01332 } 01333 } 01334 01335 KWallet::Backend *b = new KWallet::Backend(wallet); 01336 b->open(QByteArray()); 01337 bool rc = b->folderDoesNotExist(folder); 01338 delete b; 01339 return rc; 01340 } 01341 01342 01343 bool KWalletD::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key) { 01344 if (!wallets().contains(wallet)) { 01345 return true; 01346 } 01347 01348 for (QIntDictIterator<KWallet::Backend> it(_wallets); it.current(); ++it) { 01349 if (it.current()->walletName() == wallet) { 01350 return it.current()->entryDoesNotExist(folder, key); 01351 } 01352 } 01353 01354 KWallet::Backend *b = new KWallet::Backend(wallet); 01355 b->open(QByteArray()); 01356 bool rc = b->entryDoesNotExist(folder, key); 01357 delete b; 01358 return rc; 01359 } 01360 01361 01362 bool KWalletD::implicitAllow(const QString& wallet, const QCString& app) { 01363 return _implicitAllowMap[wallet].contains(QString::fromLocal8Bit(app)); 01364 } 01365 01366 01367 bool KWalletD::implicitDeny(const QString& wallet, const QCString& app) { 01368 return _implicitDenyMap[wallet].contains(QString::fromLocal8Bit(app)); 01369 } 01370 01371 01372 QCString KWalletD::friendlyDCOPPeerName() { 01373 DCOPClient *dc = callingDcopClient(); 01374 if (!dc) { 01375 return ""; 01376 } 01377 return dc->senderId().replace(QRegExp("-[0-9]+$"), ""); 01378 } 01379 01380 01381 void KWalletD::timedOut(int id) { 01382 KWallet::Backend *w = _wallets.find(id); 01383 if (w) { 01384 closeWallet(w, id, true); 01385 } 01386 } 01387 01388 01389 void KWalletD::closeAllWallets() { 01390 QIntDict<KWallet::Backend> tw = _wallets; 01391 01392 for (QIntDictIterator<KWallet::Backend> it(tw); it.current(); ++it) { 01393 closeWallet(it.current(), it.currentKey(), true); 01394 } 01395 01396 tw.clear(); 01397 01398 // All of this should be basically noop. Let's just be safe. 01399 _wallets.clear(); 01400 01401 for (QMap<QString,QCString>::Iterator it = _passwords.begin(); 01402 it != _passwords.end(); 01403 ++it) { 01404 it.data().fill(0); 01405 } 01406 _passwords.clear(); 01407 } 01408 01409 01410 QString KWalletD::networkWallet() { 01411 return KWallet::Wallet::NetworkWallet(); 01412 } 01413 01414 01415 QString KWalletD::localWallet() { 01416 return KWallet::Wallet::LocalWallet(); 01417 } 01418 01419 01420 #include "kwalletd.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:09:30 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003