File indexing completed on 2023-11-26 04:55:47

0001 /*
0002  * This file is part of telepathy-accounts-kcm
0003  *
0004  * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public
0017  * License along with this library; if not, write to the Free Software
0018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0019  */
0020 
0021 #include "wallet-interface.h"
0022 #include "pending-wallet.h"
0023 
0024 #include "ktp-debug.h"
0025 
0026 
0027 class KTp::WalletInterfacePrivate : public QObject
0028 {
0029     Q_OBJECT
0030 
0031 public:
0032     WalletInterfacePrivate();
0033     void ensureWalletIsReady();
0034 
0035     QScopedPointer<KWallet::Wallet> wallet;
0036     static const QLatin1String folderName;
0037     static const QLatin1String mapsPrefix;
0038 
0039     bool isOpening;
0040 
0041 private Q_SLOTS:
0042     void onWalletOpened(bool success);
0043 };
0044 
0045 using KTp::WalletInterface;
0046 using KTp::WalletInterfacePrivate;
0047 
0048 const QLatin1String WalletInterfacePrivate::folderName = QLatin1String("telepathy-kde");
0049 const QLatin1String WalletInterfacePrivate::mapsPrefix = QLatin1String("maps/");
0050 
0051 void WalletInterfacePrivate::ensureWalletIsReady()
0052 {
0053     // If wallet was force-closed since last WalletInterface::openWallet(),
0054     // try to reopen it.
0055     if (!wallet || !wallet->isOpen()) {
0056         // If the wallet is not already being opened, we try to open it
0057         if (!isOpening) {
0058             isOpening = true;
0059             wallet.reset(KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Asynchronous));
0060             connect(wallet.data(), SIGNAL(walletOpened(bool)), SLOT(onWalletOpened(bool)));
0061         }
0062     }
0063 }
0064 
0065 
0066 WalletInterfacePrivate::WalletInterfacePrivate() :
0067     wallet(nullptr),
0068     isOpening(false)
0069 {
0070     ensureWalletIsReady();
0071 }
0072 
0073 KTp::PendingWallet* WalletInterface::openWallet()
0074 {
0075     static KTp::WalletInterface s_instance;
0076 
0077     s_instance.d->ensureWalletIsReady();
0078     return new PendingWallet(&s_instance);
0079 }
0080 
0081 void WalletInterfacePrivate::onWalletOpened(bool success)
0082 {
0083     if (!success) {
0084         qCWarning(KTP_COMMONINTERNALS) << "Couldn't open wallet";
0085     }
0086 
0087     disconnect(wallet.data(), SIGNAL(walletOpened(bool)), this, SLOT(onWalletOpened(bool)));
0088     isOpening = false;
0089 }
0090 
0091 
0092 WalletInterface::WalletInterface():
0093     d(new WalletInterfacePrivate)
0094 {
0095 }
0096 
0097 WalletInterface::~WalletInterface()
0098 {
0099     delete d;
0100 }
0101 
0102 bool WalletInterface::hasPassword(const Tp::AccountPtr &account)
0103 {
0104     if (d->wallet.isNull() || !d->wallet->hasFolder(d->folderName)) {
0105         return false;
0106     }
0107 
0108     d->wallet->setFolder(d->folderName);
0109     return d->wallet->hasEntry(account->uniqueIdentifier());
0110 }
0111 
0112 QString WalletInterface::password(const Tp::AccountPtr &account)
0113 {
0114     if (d->wallet.isNull() || !d->wallet->hasFolder(d->folderName)) {
0115         return QString();
0116     }
0117 
0118     d->wallet->setFolder(d->folderName);
0119     QString password;
0120     if (d->wallet->hasEntry(account->uniqueIdentifier())) {
0121         int rc = d->wallet->readPassword(account->uniqueIdentifier(), password);
0122         if (rc != 0) {
0123             password.clear();
0124             qCWarning(KTP_COMMONINTERNALS) << "failed to read password from KWallet";
0125         }
0126     }
0127     return password;
0128 }
0129 
0130 void WalletInterface::setPassword(const Tp::AccountPtr &account, const QString &password)
0131 {
0132     if (d->wallet.isNull()) {
0133         return;
0134     }
0135 
0136     if (!d->wallet->hasFolder(d->folderName)) {
0137         d->wallet->createFolder(d->folderName);
0138     }
0139 
0140     d->wallet->setFolder(d->folderName);
0141     d->wallet->writePassword(account->uniqueIdentifier(), password);
0142 
0143     setLastLoginFailed(account, false);
0144 
0145     //sync normally happens on close, but in this case we need it to happen /now/ as it needs to be synced before the auth-client starts
0146     d->wallet->sync();
0147 }
0148 
0149 void WalletInterface::setLastLoginFailed(const Tp::AccountPtr &account, bool failed)
0150 {
0151     if (failed) {
0152         setEntry(account, QLatin1String("lastLoginFailed"), QLatin1String("true"));
0153     } else {
0154         if (hasEntry(account, QLatin1String("lastLoginFailed"))) {
0155             removeEntry(account, QLatin1String("lastLoginFailed"));
0156         }
0157     }
0158 }
0159 
0160 bool WalletInterface::lastLoginFailed(const Tp::AccountPtr &account)
0161 {
0162     if (d->wallet.isNull()) {
0163         return false;
0164     }
0165     return hasEntry(account, QLatin1String("lastLoginFailed"));
0166 }
0167 
0168 void WalletInterface::removePassword(const Tp::AccountPtr &account)
0169 {
0170     if (d->wallet.isNull() || !d->wallet->hasFolder(d->folderName)) {
0171         return;
0172     }
0173 
0174     d->wallet->setFolder(d->folderName);
0175     d->wallet->removeEntry(account->uniqueIdentifier());
0176     d->wallet->sync();
0177 }
0178 
0179 bool WalletInterface::hasEntry(const Tp::AccountPtr &account, const QString &key)
0180 {
0181     if (d->wallet.isNull() || !d->wallet->hasFolder(d->folderName)) {
0182         return false;
0183     }
0184 
0185     d->wallet->setFolder(d->folderName);
0186     QMap< QString, QString > map;
0187     if (d->wallet->hasEntry(d->mapsPrefix + account->uniqueIdentifier())) {
0188         int rc = d->wallet->readMap(d->mapsPrefix + account->uniqueIdentifier(), map);
0189         if (rc != 0) {
0190             qCWarning(KTP_COMMONINTERNALS) << "failed to read map from KWallet (probably it is not a map)";
0191             return false;
0192         }
0193     }
0194     return map.contains(key);
0195 }
0196 
0197 QString WalletInterface::entry(const Tp::AccountPtr &account, const QString &key)
0198 {
0199     if (d->wallet.isNull() || !d->wallet->hasFolder(d->folderName)) {
0200         return QString();
0201     }
0202 
0203     d->wallet->setFolder(d->folderName);
0204     QString value;
0205     QMap< QString, QString > map;
0206     if (d->wallet->hasEntry(d->mapsPrefix + account->uniqueIdentifier())) {
0207         int rc = d->wallet->readMap(d->mapsPrefix + account->uniqueIdentifier(), map);
0208         if (rc != 0) {
0209             qCWarning(KTP_COMMONINTERNALS) << "failed to read map from KWallet (probably it is not a map)";
0210             return QString();
0211         }
0212     }
0213     return map.value(key);
0214 }
0215 
0216 void WalletInterface::setEntry(const Tp::AccountPtr &account, const QString &key, const QString &value)
0217 {
0218     if (d->wallet.isNull()) {
0219         return;
0220     }
0221 
0222     if (! d->wallet->hasFolder(d->folderName)) {
0223         d->wallet->createFolder(d->folderName);
0224     }
0225 
0226     d->wallet->setFolder(d->folderName);
0227     QMap< QString, QString > map;
0228     if (d->wallet->hasEntry(d->mapsPrefix + account->uniqueIdentifier())) {
0229         int rc = d->wallet->readMap(d->mapsPrefix + account->uniqueIdentifier(), map);
0230         if (rc != 0) {
0231             qCWarning(KTP_COMMONINTERNALS) << "failed to read map from KWallet (probably it is not a map)";
0232             return;
0233         }
0234     }
0235     map[key] = value;
0236 
0237     d->wallet->writeMap(d->mapsPrefix + account->uniqueIdentifier(), map);
0238     //sync normally happens on close, but in this case we need it to happen /now/ as it needs to be synced before the auth-client starts
0239     d->wallet->sync();
0240 }
0241 
0242 void WalletInterface::removeEntry(const Tp::AccountPtr &account, const QString &key)
0243 {
0244     if (d->wallet.isNull() || !d->wallet->hasFolder(d->folderName)) {
0245         return;
0246     }
0247 
0248     d->wallet->setFolder(d->folderName);
0249     QMap< QString, QString > map;
0250     if (d->wallet->hasEntry(d->mapsPrefix + account->uniqueIdentifier())) {
0251         int rc = d->wallet->readMap(d->mapsPrefix + account->uniqueIdentifier(), map);
0252         if (rc != 0) {
0253             qCWarning(KTP_COMMONINTERNALS) << "failed to read map from KWallet (probably it is not a map)";
0254             return;
0255         }
0256     }
0257     map.remove(key);
0258 
0259     if (!map.empty()) {
0260         d->wallet->writeMap(d->mapsPrefix + account->uniqueIdentifier(), map);
0261     } else {
0262         d->wallet->removeEntry(d->mapsPrefix + account->uniqueIdentifier());
0263     }
0264     //sync normally happens on close, but in this case we need it to happen /now/ as it needs to be synced before the auth-client starts
0265     d->wallet->sync();
0266 }
0267 
0268 void WalletInterface::removeAllEntries(const Tp::AccountPtr& account)
0269 {
0270     if (d->wallet.isNull() || !d->wallet->hasFolder(d->folderName)) {
0271         return;
0272     }
0273 
0274     d->wallet->setFolder(d->folderName);
0275     d->wallet->removeEntry(d->mapsPrefix + account->uniqueIdentifier());
0276 }
0277 
0278 void WalletInterface::removeAccount(const Tp::AccountPtr& account)
0279 {
0280     removePassword(account);
0281     removeAllEntries(account);
0282 }
0283 
0284 bool WalletInterface::isOpen()
0285 {
0286     return (!d->wallet.isNull() && d->wallet->isOpen());
0287 }
0288 
0289 KWallet::Wallet *WalletInterface::wallet() const
0290 {
0291     return d->wallet.data();
0292 }
0293 
0294 #include "wallet-interface.moc"