File indexing completed on 2024-05-12 15:41:56

0001 /*
0002     kcookiesmanagement.cpp - Cookies manager
0003 
0004     SPDX-FileCopyrightText: 2000-2001 Marco Pinelli <pinmc@orion.it>
0005     SPDX-FileCopyrightText: 2000-2001 Dawit Alemayehu <adawit@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 // Own
0011 #include "kcookiesmanagement.h"
0012 
0013 // Qt
0014 #include <QDBusConnection>
0015 #include <QDBusInterface>
0016 #include <QDBusReply>
0017 #include <QPushButton>
0018 
0019 // KDE
0020 #include <KLocalizedString>
0021 #include <KMessageBox>
0022 #include <QDateTime>
0023 #include <QLocale>
0024 // Local
0025 #include "kcookiesmain.h"
0026 #include "kcookiespolicies.h"
0027 
0028 QString tolerantFromAce(const QByteArray &_domain);
0029 
0030 struct CookieProp {
0031     QString host;
0032     QString name;
0033     QString value;
0034     QString domain;
0035     QString path;
0036     QString expireDate;
0037     QString secure;
0038     bool allLoaded;
0039 };
0040 
0041 CookieListViewItem::CookieListViewItem(QTreeWidget *parent, const QString &dom)
0042     : QTreeWidgetItem(parent)
0043 {
0044     init(nullptr, dom);
0045 }
0046 
0047 CookieListViewItem::CookieListViewItem(QTreeWidgetItem *parent, CookieProp *cookie)
0048     : QTreeWidgetItem(parent)
0049 {
0050     init(cookie);
0051 }
0052 
0053 CookieListViewItem::~CookieListViewItem()
0054 {
0055     delete mCookie;
0056 }
0057 
0058 void CookieListViewItem::init(CookieProp *cookie, const QString &domain, bool cookieLoaded)
0059 {
0060     mCookie = cookie;
0061     mDomain = domain;
0062     mCookiesLoaded = cookieLoaded;
0063 
0064     if (mCookie) {
0065         if (mDomain.isEmpty()) {
0066             setText(0, tolerantFromAce(mCookie->host.toLatin1()));
0067         } else {
0068             setText(0, tolerantFromAce(mDomain.toLatin1()));
0069         }
0070         setText(1, mCookie->name);
0071     } else {
0072         QString siteName;
0073         if (mDomain.startsWith(QLatin1Char('.'))) {
0074             siteName = mDomain.mid(1);
0075         } else {
0076             siteName = mDomain;
0077         }
0078         setText(0, tolerantFromAce(siteName.toLatin1()));
0079     }
0080 }
0081 
0082 CookieProp *CookieListViewItem::leaveCookie()
0083 {
0084     CookieProp *ret = mCookie;
0085     mCookie = nullptr;
0086     return ret;
0087 }
0088 
0089 KCookiesManagement::KCookiesManagement(QWidget *parent, const QVariantList &args)
0090     : KCModule(parent, args)
0091     , mDeleteAllFlag(false)
0092     , mMainWidget(parent)
0093 {
0094     mUi.setupUi(this);
0095     mUi.searchLineEdit->setTreeWidget(mUi.cookiesTreeWidget);
0096     mUi.cookiesTreeWidget->setColumnWidth(0, 150);
0097 
0098     connect(mUi.deleteButton, &QAbstractButton::clicked, this, &KCookiesManagement::deleteCurrent);
0099     connect(mUi.deleteAllButton, &QAbstractButton::clicked, this, &KCookiesManagement::deleteAll);
0100     connect(mUi.reloadButton, &QAbstractButton::clicked, this, &KCookiesManagement::reload);
0101     connect(mUi.cookiesTreeWidget, &QTreeWidget::itemExpanded, this, &KCookiesManagement::listCookiesForDomain);
0102     connect(mUi.cookiesTreeWidget, &QTreeWidget::currentItemChanged, this, &KCookiesManagement::updateForItem);
0103     connect(mUi.cookiesTreeWidget, &QTreeWidget::itemDoubleClicked, this, &KCookiesManagement::showConfigPolicyDialog);
0104     connect(mUi.configPolicyButton, &QAbstractButton::clicked, this, &KCookiesManagement::showConfigPolicyDialog);
0105 }
0106 
0107 KCookiesManagement::~KCookiesManagement()
0108 {
0109 }
0110 
0111 void KCookiesManagement::load()
0112 {
0113     defaults();
0114 }
0115 
0116 void KCookiesManagement::save()
0117 {
0118     // If delete all cookies was requested!
0119     if (mDeleteAllFlag) {
0120         QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"),
0121                             QStringLiteral("/modules/kcookiejar"),
0122                             QStringLiteral("org.kde.KCookieServer"),
0123                             QDBusConnection::sessionBus());
0124         QDBusReply<void> reply = kded.call(QStringLiteral("deleteAllCookies"));
0125         if (!reply.isValid()) {
0126             const QString title = i18n("D-Bus Communication Error");
0127             const QString message = i18n("Unable to delete all the cookies as requested.");
0128             KMessageBox::error(this, message, title);
0129             return;
0130         }
0131         mDeleteAllFlag = false; // deleted[Cookies|Domains] have been cleared yet
0132     }
0133 
0134     // Certain groups of cookies were deleted...
0135     QMutableStringListIterator it(mDeletedDomains);
0136     while (it.hasNext()) {
0137         QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"),
0138                             QStringLiteral("/modules/kcookiejar"),
0139                             QStringLiteral("org.kde.KCookieServer"),
0140                             QDBusConnection::sessionBus());
0141         QDBusReply<void> reply = kded.call(QStringLiteral("deleteCookiesFromDomain"), (it.next()));
0142         if (!reply.isValid()) {
0143             const QString title = i18n("D-Bus Communication Error");
0144             const QString message = i18n("Unable to delete cookies as requested.");
0145             KMessageBox::error(this, message, title);
0146             return;
0147         }
0148         it.remove();
0149     }
0150 
0151     // Individual cookies were deleted...
0152     bool success = true; // Maybe we can go on...
0153     QMutableHashIterator<QString, CookiePropList> cookiesDom(mDeletedCookies);
0154     while (cookiesDom.hasNext()) {
0155         cookiesDom.next();
0156         CookiePropList list = cookiesDom.value();
0157         for (auto it = list.begin(); it < list.end(); ++it) {
0158             CookieProp *cookie = *it;
0159             QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"),
0160                                 QStringLiteral("/modules/kcookiejar"),
0161                                 QStringLiteral("org.kde.KCookieServer"),
0162                                 QDBusConnection::sessionBus());
0163             QDBusReply<void> reply = kded.call(QStringLiteral("deleteCookie"), cookie->domain, cookie->host, cookie->path, cookie->name);
0164             if (!reply.isValid()) {
0165                 success = false;
0166                 break;
0167             }
0168 
0169             list.removeOne(cookie);
0170         }
0171 
0172         if (!success) {
0173             break;
0174         }
0175 
0176         mDeletedCookies.remove(cookiesDom.key());
0177     }
0178 
0179     Q_EMIT changed(false);
0180 }
0181 
0182 void KCookiesManagement::defaults()
0183 {
0184     reset();
0185     reload();
0186 }
0187 
0188 void KCookiesManagement::reset(bool deleteAll)
0189 {
0190     if (!deleteAll) {
0191         mDeleteAllFlag = false;
0192     }
0193 
0194     clearCookieDetails();
0195     mDeletedDomains.clear();
0196     mDeletedCookies.clear();
0197 
0198     mUi.cookiesTreeWidget->clear();
0199     mUi.deleteButton->setEnabled(false);
0200     mUi.deleteAllButton->setEnabled(false);
0201     mUi.configPolicyButton->setEnabled(false);
0202 }
0203 
0204 void KCookiesManagement::clearCookieDetails()
0205 {
0206     mUi.nameLineEdit->clear();
0207     mUi.valueLineEdit->clear();
0208     mUi.domainLineEdit->clear();
0209     mUi.pathLineEdit->clear();
0210     mUi.expiresLineEdit->clear();
0211     mUi.secureLineEdit->clear();
0212 }
0213 
0214 QString KCookiesManagement::quickHelp() const
0215 {
0216     return i18n("<h1>Cookie Management Quick Help</h1>");
0217 }
0218 
0219 void KCookiesManagement::reload()
0220 {
0221     QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"),
0222                         QStringLiteral("/modules/kcookiejar"),
0223                         QStringLiteral("org.kde.KCookieServer"),
0224                         QDBusConnection::sessionBus());
0225     QDBusReply<QStringList> reply = kded.call(QStringLiteral("findDomains"));
0226 
0227     if (!reply.isValid()) {
0228         const QString title = i18n("Information Lookup Failure");
0229         const QString message = i18n(
0230             "Unable to retrieve information about the "
0231             "cookies stored on your computer.");
0232         KMessageBox::error(this, message, title);
0233         return;
0234     }
0235 
0236     if (mUi.cookiesTreeWidget->topLevelItemCount() > 0) {
0237         reset();
0238     }
0239 
0240     CookieListViewItem *dom;
0241     const QStringList domains(reply.value());
0242     for (const QString &domain : domains) {
0243         const QString siteName = (domain.startsWith(QLatin1Char('.')) ? domain.mid(1) : domain);
0244         if (mUi.cookiesTreeWidget->findItems(siteName, Qt::MatchFixedString).isEmpty()) {
0245             dom = new CookieListViewItem(mUi.cookiesTreeWidget, domain);
0246             dom->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
0247         }
0248     }
0249 
0250     // are there any cookies?
0251     mUi.deleteAllButton->setEnabled(mUi.cookiesTreeWidget->topLevelItemCount() > 0);
0252     mUi.cookiesTreeWidget->sortItems(0, Qt::AscendingOrder);
0253     Q_EMIT changed(false);
0254 }
0255 
0256 Q_DECLARE_METATYPE(QList<int>)
0257 
0258 void KCookiesManagement::listCookiesForDomain(QTreeWidgetItem *item)
0259 {
0260     CookieListViewItem *cookieDom = static_cast<CookieListViewItem *>(item);
0261     if (!cookieDom || cookieDom->cookiesLoaded()) {
0262         return;
0263     }
0264 
0265     QStringList cookies;
0266     const QList<int> fields{0, 1, 2, 3};
0267     // Always check for cookies in both "foo.bar" and ".foo.bar" domains...
0268     const QString domain = cookieDom->domain() + QLatin1String(" .") + cookieDom->domain();
0269     QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"),
0270                         QStringLiteral("/modules/kcookiejar"),
0271                         QStringLiteral("org.kde.KCookieServer"),
0272                         QDBusConnection::sessionBus());
0273     QDBusReply<QStringList> reply = kded.call(QStringLiteral("findCookies"), QVariant::fromValue(fields), domain, QString(), QString(), QString());
0274     if (reply.isValid()) {
0275         cookies.append(reply.value());
0276     }
0277 
0278     QStringListIterator it(cookies);
0279     while (it.hasNext()) {
0280         CookieProp *details = new CookieProp;
0281         details->domain = it.next();
0282         details->path = it.next();
0283         details->name = it.next();
0284         details->host = it.next();
0285         details->allLoaded = false;
0286         new CookieListViewItem(item, details);
0287     }
0288 
0289     if (!cookies.isEmpty()) {
0290         static_cast<CookieListViewItem *>(item)->setCookiesLoaded();
0291         mUi.searchLineEdit->updateSearch();
0292     }
0293 }
0294 
0295 bool KCookiesManagement::cookieDetails(CookieProp *cookie)
0296 {
0297     const QList<int> fields{4, 5, 7};
0298 
0299     QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"),
0300                         QStringLiteral("/modules/kcookiejar"),
0301                         QStringLiteral("org.kde.KCookieServer"),
0302                         QDBusConnection::sessionBus());
0303     QDBusReply<QStringList> reply =
0304         kded.call(QStringLiteral("findCookies"), QVariant::fromValue(fields), cookie->domain, cookie->host, cookie->path, cookie->name);
0305     if (!reply.isValid()) {
0306         return false;
0307     }
0308 
0309     const QStringList fieldVal = reply.value();
0310 
0311     auto c = fieldVal.cbegin();
0312     if (c == fieldVal.cend()) { // empty list, do not crash
0313         return false;
0314     }
0315 
0316     bool ok;
0317     cookie->value = *c++;
0318     qint64 tmp = (*c++).toLongLong(&ok);
0319 
0320     if (!ok || tmp == 0) {
0321         cookie->expireDate = i18n("End of session");
0322     } else {
0323         QDateTime expDate = QDateTime::fromSecsSinceEpoch(tmp);
0324         cookie->expireDate = QLocale().toString((expDate), QLocale::ShortFormat);
0325     }
0326 
0327     tmp = (*c).toUInt(&ok);
0328     cookie->secure = i18n((ok && tmp) ? "Yes" : "No");
0329     cookie->allLoaded = true;
0330     return true;
0331 }
0332 
0333 void KCookiesManagement::updateForItem(QTreeWidgetItem *item)
0334 {
0335     if (item) {
0336         CookieListViewItem *cookieItem = static_cast<CookieListViewItem *>(item);
0337         CookieProp *cookie = cookieItem->cookie();
0338 
0339         if (cookie) {
0340             if (cookie->allLoaded || cookieDetails(cookie)) {
0341                 mUi.nameLineEdit->setText(cookie->name);
0342                 mUi.valueLineEdit->setText(cookie->value);
0343                 mUi.domainLineEdit->setText(cookie->domain);
0344                 mUi.pathLineEdit->setText(cookie->path);
0345                 mUi.expiresLineEdit->setText(cookie->expireDate);
0346                 mUi.secureLineEdit->setText(cookie->secure);
0347             }
0348 
0349             mUi.configPolicyButton->setEnabled(false);
0350         } else {
0351             clearCookieDetails();
0352             mUi.configPolicyButton->setEnabled(true);
0353         }
0354     } else {
0355         mUi.configPolicyButton->setEnabled(false);
0356     }
0357     mUi.deleteButton->setEnabled(item != nullptr);
0358 }
0359 
0360 void KCookiesManagement::showConfigPolicyDialog()
0361 {
0362     // Get current item
0363     CookieListViewItem *item = static_cast<CookieListViewItem *>(mUi.cookiesTreeWidget->currentItem());
0364     Q_ASSERT(item); // the button is disabled otherwise
0365 
0366     if (item) {
0367         KCookiesMain *mainDlg = qobject_cast<KCookiesMain *>(mMainWidget);
0368         // must be present or something is really wrong.
0369         Q_ASSERT(mainDlg);
0370 
0371         KCookiesPolicies *policyDlg = mainDlg->policyDlg();
0372         // must be present unless someone rewrote the widget in which case
0373         // this needs to be re-written as well.
0374         Q_ASSERT(policyDlg);
0375 
0376         policyDlg->setPolicy(item->domain());
0377     }
0378 }
0379 
0380 void KCookiesManagement::deleteCurrent()
0381 {
0382     QTreeWidgetItem *currentItem = mUi.cookiesTreeWidget->currentItem();
0383     Q_ASSERT(currentItem); // the button is disabled otherwise
0384     CookieListViewItem *item = static_cast<CookieListViewItem *>(currentItem);
0385     if (item->cookie()) {
0386         CookieListViewItem *parent = static_cast<CookieListViewItem *>(item->parent());
0387         CookiePropList list = mDeletedCookies.value(parent->domain());
0388         list.append(item->leaveCookie());
0389         mDeletedCookies.insert(parent->domain(), list);
0390         delete item;
0391         if (parent->childCount() == 0) {
0392             delete parent;
0393         }
0394     } else {
0395         mDeletedDomains.append(item->domain());
0396         delete item;
0397     }
0398 
0399     currentItem = mUi.cookiesTreeWidget->currentItem();
0400     if (currentItem) {
0401         mUi.cookiesTreeWidget->setCurrentItem(currentItem);
0402     } else {
0403         clearCookieDetails();
0404     }
0405 
0406     mUi.deleteAllButton->setEnabled(mUi.cookiesTreeWidget->topLevelItemCount() > 0);
0407 
0408     Q_EMIT changed(true);
0409 }
0410 
0411 void KCookiesManagement::deleteAll()
0412 {
0413     mDeleteAllFlag = true;
0414     reset(true);
0415     Q_EMIT changed(true);
0416 }
0417 
0418 #include "moc_kcookiesmanagement.cpp"