File indexing completed on 2024-05-12 15:41:57
0001 /** 0002 kcookiespolicies.cpp - Cookies configuration 0003 0004 Original Authors 0005 SPDX-FileCopyrightText: Waldo Bastian <bastian@kde.org> 0006 SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org> 0007 SPDX-FileCopyrightText: 2008 Urs Wolfer <uwolfer @ kde.org> 0008 0009 Re-written by: 0010 SPDX-FileCopyrightText: 2000 Dawit Alemayehu <adawit@kde.org> 0011 0012 SPDX-License-Identifier: GPL-2.0-or-later 0013 */ 0014 0015 // Own 0016 #include "kcookiespolicies.h" 0017 0018 // Local 0019 #include "../ksaveioconfig.h" 0020 0021 // Qt 0022 #include <QCheckBox> 0023 #include <QDBusInterface> 0024 #include <QDBusReply> 0025 #include <QPushButton> 0026 0027 // KDE 0028 #include <KConfig> 0029 #include <KConfigGroup> 0030 #include <KLocalizedString> 0031 #include <KMessageBox> 0032 #include <QUrl> 0033 0034 // QUrl::fromAce/toAce don't accept a domain that starts with a '.', like we do here. 0035 // So we use these wrappers. 0036 QString tolerantFromAce(const QByteArray &_domain) 0037 { 0038 QByteArray domain(_domain); 0039 const bool hasDot = domain.startsWith('.'); 0040 if (hasDot) { 0041 domain.remove(0, 1); 0042 } 0043 QString ret = QUrl::fromAce(domain); 0044 if (hasDot) { 0045 ret.prepend(QLatin1Char('.')); 0046 } 0047 return ret; 0048 } 0049 0050 static QByteArray tolerantToAce(const QString &_domain) 0051 { 0052 QString domain(_domain); 0053 const bool hasDot = domain.startsWith(QLatin1Char('.')); 0054 if (hasDot) { 0055 domain.remove(0, 1); 0056 } 0057 QByteArray ret = QUrl::toAce(domain); 0058 if (hasDot) { 0059 ret.prepend('.'); 0060 } 0061 return ret; 0062 } 0063 0064 KCookiesPolicies::KCookiesPolicies(QWidget *parent, const QVariantList &args) 0065 : KCModule(parent, args) 0066 , mSelectedItemsCount(0) 0067 { 0068 mUi.setupUi(this); 0069 mUi.kListViewSearchLine->setTreeWidget(mUi.policyTreeWidget); 0070 QList<int> columns; 0071 columns.append(0); 0072 mUi.kListViewSearchLine->setSearchColumns(columns); 0073 0074 mUi.pbNew->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); 0075 mUi.pbChange->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); 0076 mUi.pbDelete->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); 0077 mUi.pbDeleteAll->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); 0078 0079 // Connect the main switch :) Enable/disable cookie support 0080 connect(mUi.cbEnableCookies, &QAbstractButton::toggled, this, &KCookiesPolicies::cookiesEnabled); 0081 connect(mUi.cbEnableCookies, &QAbstractButton::toggled, this, &KCookiesPolicies::configChanged); 0082 0083 // Connect the preference check boxes... 0084 connect(mUi.cbRejectCrossDomainCookies, &QAbstractButton::toggled, this, &KCookiesPolicies::configChanged); 0085 connect(mUi.cbAutoAcceptSessionCookies, &QAbstractButton::toggled, this, &KCookiesPolicies::configChanged); 0086 0087 connect(mUi.rbPolicyAsk, &QAbstractButton::toggled, this, &KCookiesPolicies::configChanged); 0088 connect(mUi.rbPolicyAccept, &QAbstractButton::toggled, this, &KCookiesPolicies::configChanged); 0089 connect(mUi.rbPolicyAcceptForSession, &QAbstractButton::toggled, this, &KCookiesPolicies::configChanged); 0090 connect(mUi.rbPolicyReject, &QAbstractButton::toggled, this, &KCookiesPolicies::configChanged); 0091 // Connect signals from the domain specific policy listview. 0092 connect(mUi.policyTreeWidget, &QTreeWidget::itemSelectionChanged, this, &KCookiesPolicies::selectionChanged); 0093 connect(mUi.policyTreeWidget, &QTreeWidget::itemDoubleClicked, this, qOverload<>(&KCookiesPolicies::changePressed)); 0094 0095 // Connect the buttons... 0096 connect(mUi.pbNew, &QAbstractButton::clicked, this, qOverload<>(&KCookiesPolicies::addPressed)); 0097 connect(mUi.pbChange, &QAbstractButton::clicked, this, qOverload<>(&KCookiesPolicies::changePressed)); 0098 connect(mUi.pbDelete, &QAbstractButton::clicked, this, &KCookiesPolicies::deletePressed); 0099 connect(mUi.pbDeleteAll, &QAbstractButton::clicked, this, &KCookiesPolicies::deleteAllPressed); 0100 } 0101 0102 KCookiesPolicies::~KCookiesPolicies() 0103 { 0104 } 0105 0106 void KCookiesPolicies::configChanged() 0107 { 0108 // kDebug() << "KCookiesPolicies::configChanged..."; 0109 Q_EMIT changed(true); 0110 } 0111 0112 void KCookiesPolicies::cookiesEnabled(bool enable) 0113 { 0114 mUi.bgDefault->setEnabled(enable); 0115 mUi.bgPreferences->setEnabled(enable); 0116 mUi.gbDomainSpecific->setEnabled(enable); 0117 } 0118 0119 void KCookiesPolicies::setPolicy(const QString &domain) 0120 { 0121 QTreeWidgetItemIterator it(mUi.policyTreeWidget); 0122 bool hasExistingPolicy = false; 0123 while (*it) { 0124 if ((*it)->text(0) == domain) { 0125 hasExistingPolicy = true; 0126 break; 0127 } 0128 ++it; 0129 } 0130 0131 if (hasExistingPolicy) { 0132 changePressed((*it), false); 0133 } else { 0134 addPressed(domain); 0135 } 0136 } 0137 0138 void KCookiesPolicies::changePressed() 0139 { 0140 changePressed(mUi.policyTreeWidget->currentItem()); 0141 } 0142 0143 void KCookiesPolicies::addPressed() 0144 { 0145 addPressed(QString()); 0146 } 0147 0148 void KCookiesPolicies::changePressed(QTreeWidgetItem *item, bool state) 0149 { 0150 Q_ASSERT(item); 0151 const QString oldDomain(item->text(0)); 0152 0153 KCookiesPolicySelectionDlg pdlg(this); 0154 pdlg.setWindowTitle(i18nc("@title:window", "Change Cookie Policy")); 0155 pdlg.setPolicy(KCookieAdvice::strToAdvice(QString::fromLatin1(mDomainPolicyMap.value(oldDomain)))); 0156 pdlg.setEnableHostEdit(state, oldDomain); 0157 0158 if (pdlg.exec() && !pdlg.domain().isEmpty()) { 0159 const QString newDomain = tolerantFromAce(pdlg.domain().toLatin1()); 0160 int advice = pdlg.advice(); 0161 if (newDomain == oldDomain || !handleDuplicate(newDomain, advice)) { 0162 mDomainPolicyMap[newDomain] = KCookieAdvice::adviceToStr(advice); 0163 item->setText(0, newDomain); 0164 item->setText(1, i18n(mDomainPolicyMap.value(newDomain))); 0165 configChanged(); 0166 } 0167 } 0168 } 0169 0170 void KCookiesPolicies::addPressed(const QString &domain, bool state) 0171 { 0172 KCookiesPolicySelectionDlg pdlg(this); 0173 pdlg.setWindowTitle(i18nc("@title:window", "New Cookie Policy")); 0174 pdlg.setEnableHostEdit(state, domain); 0175 0176 if (mUi.rbPolicyAccept->isChecked()) { 0177 pdlg.setPolicy(KCookieAdvice::Reject); 0178 } else { 0179 pdlg.setPolicy(KCookieAdvice::Accept); 0180 } 0181 0182 if (pdlg.exec() && !pdlg.domain().isEmpty()) { 0183 const QString domain = tolerantFromAce(pdlg.domain().toLatin1()); 0184 int advice = pdlg.advice(); 0185 0186 if (!handleDuplicate(domain, advice)) { 0187 const char *strAdvice = KCookieAdvice::adviceToStr(advice); 0188 const QStringList items{ 0189 domain, 0190 i18n(strAdvice), 0191 }; 0192 QTreeWidgetItem *item = new QTreeWidgetItem(mUi.policyTreeWidget, items); 0193 mDomainPolicyMap.insert(item->text(0), strAdvice); 0194 configChanged(); 0195 updateButtons(); 0196 } 0197 } 0198 } 0199 0200 bool KCookiesPolicies::handleDuplicate(const QString &domain, int advice) 0201 { 0202 QTreeWidgetItem *item = mUi.policyTreeWidget->topLevelItem(0); 0203 while (item != nullptr) { 0204 if (item->text(0) == domain) { 0205 const int res = KMessageBox::warningContinueCancel(this, 0206 i18n("<qt>A policy already exists for" 0207 "<center><b>%1</b></center>" 0208 "Do you want to replace it?</qt>", 0209 domain), 0210 i18nc("@title:window", "Duplicate Policy"), 0211 KGuiItem(i18n("Replace"))); 0212 if (res == KMessageBox::Continue) { 0213 mDomainPolicyMap[domain] = KCookieAdvice::adviceToStr(advice); 0214 item->setText(0, domain); 0215 item->setText(1, i18n(mDomainPolicyMap.value(domain))); 0216 configChanged(); 0217 return true; 0218 } else { 0219 return true; // User Cancelled!! 0220 } 0221 } 0222 item = mUi.policyTreeWidget->itemBelow(item); 0223 } 0224 return false; 0225 } 0226 0227 void KCookiesPolicies::deletePressed() 0228 { 0229 QTreeWidgetItem *nextItem = nullptr; 0230 0231 const QList<QTreeWidgetItem *> selectedItems = mUi.policyTreeWidget->selectedItems(); 0232 for (const QTreeWidgetItem *item : selectedItems) { 0233 nextItem = mUi.policyTreeWidget->itemBelow(item); 0234 if (!nextItem) { 0235 nextItem = mUi.policyTreeWidget->itemAbove(item); 0236 } 0237 0238 mDomainPolicyMap.remove(item->text(0)); 0239 delete item; 0240 } 0241 0242 if (nextItem) { 0243 nextItem->setSelected(true); 0244 } 0245 0246 updateButtons(); 0247 configChanged(); 0248 } 0249 0250 void KCookiesPolicies::deleteAllPressed() 0251 { 0252 mDomainPolicyMap.clear(); 0253 mUi.policyTreeWidget->clear(); 0254 updateButtons(); 0255 configChanged(); 0256 } 0257 0258 void KCookiesPolicies::updateButtons() 0259 { 0260 bool hasItems = mUi.policyTreeWidget->topLevelItemCount() > 0; 0261 0262 mUi.pbChange->setEnabled((hasItems && mSelectedItemsCount == 1)); 0263 mUi.pbDelete->setEnabled((hasItems && mSelectedItemsCount > 0)); 0264 mUi.pbDeleteAll->setEnabled(hasItems); 0265 } 0266 0267 void KCookiesPolicies::updateDomainList(const QStringList &domainConfig) 0268 { 0269 mUi.policyTreeWidget->clear(); 0270 0271 QStringList::ConstIterator it = domainConfig.begin(); 0272 for (; it != domainConfig.end(); ++it) { 0273 QString domain; 0274 KCookieAdvice::Value advice = KCookieAdvice::Dunno; 0275 splitDomainAdvice(*it, domain, advice); 0276 if (!domain.isEmpty()) { 0277 const QStringList items{ 0278 tolerantFromAce(domain.toLatin1()), 0279 i18n(KCookieAdvice::adviceToStr(advice)), 0280 }; 0281 QTreeWidgetItem *item = new QTreeWidgetItem(mUi.policyTreeWidget, items); 0282 mDomainPolicyMap[item->text(0)] = KCookieAdvice::adviceToStr(advice); 0283 } 0284 } 0285 0286 mUi.policyTreeWidget->sortItems(0, Qt::AscendingOrder); 0287 } 0288 0289 void KCookiesPolicies::selectionChanged() 0290 { 0291 mSelectedItemsCount = mUi.policyTreeWidget->selectedItems().count(); 0292 updateButtons(); 0293 } 0294 0295 void KCookiesPolicies::load() 0296 { 0297 mSelectedItemsCount = 0; 0298 0299 KConfig cfg(QStringLiteral("kcookiejarrc")); 0300 KConfigGroup group = cfg.group("Cookie Policy"); 0301 0302 bool enableCookies = group.readEntry("Cookies", true); 0303 mUi.cbEnableCookies->setChecked(enableCookies); 0304 cookiesEnabled(enableCookies); 0305 0306 // Warning: the default values are duplicated in kcookiejar.cpp 0307 KCookieAdvice::Value advice = KCookieAdvice::strToAdvice(group.readEntry("CookieGlobalAdvice", "Accept")); 0308 switch (advice) { 0309 case KCookieAdvice::Accept: 0310 mUi.rbPolicyAccept->setChecked(true); 0311 break; 0312 case KCookieAdvice::AcceptForSession: 0313 mUi.rbPolicyAcceptForSession->setChecked(true); 0314 break; 0315 case KCookieAdvice::Reject: 0316 mUi.rbPolicyReject->setChecked(true); 0317 break; 0318 case KCookieAdvice::Ask: 0319 case KCookieAdvice::Dunno: 0320 default: 0321 mUi.rbPolicyAsk->setChecked(true); 0322 } 0323 0324 bool enable = group.readEntry("RejectCrossDomainCookies", true); 0325 mUi.cbRejectCrossDomainCookies->setChecked(enable); 0326 0327 bool sessionCookies = group.readEntry("AcceptSessionCookies", true); 0328 mUi.cbAutoAcceptSessionCookies->setChecked(sessionCookies); 0329 updateDomainList(group.readEntry("CookieDomainAdvice", QStringList())); 0330 0331 if (enableCookies) { 0332 updateButtons(); 0333 } 0334 } 0335 0336 void KCookiesPolicies::save() 0337 { 0338 KConfig cfg(QStringLiteral("kcookiejarrc")); 0339 KConfigGroup group = cfg.group("Cookie Policy"); 0340 0341 bool state = mUi.cbEnableCookies->isChecked(); 0342 group.writeEntry("Cookies", state); 0343 state = mUi.cbRejectCrossDomainCookies->isChecked(); 0344 group.writeEntry("RejectCrossDomainCookies", state); 0345 state = mUi.cbAutoAcceptSessionCookies->isChecked(); 0346 group.writeEntry("AcceptSessionCookies", state); 0347 0348 QString advice; 0349 if (mUi.rbPolicyAccept->isChecked()) { 0350 advice = QString::fromLatin1(KCookieAdvice::adviceToStr(KCookieAdvice::Accept)); 0351 } else if (mUi.rbPolicyAcceptForSession->isChecked()) { 0352 advice = QString::fromLatin1(KCookieAdvice::adviceToStr(KCookieAdvice::AcceptForSession)); 0353 } else if (mUi.rbPolicyReject->isChecked()) { 0354 advice = QString::fromLatin1(KCookieAdvice::adviceToStr(KCookieAdvice::Reject)); 0355 } else { 0356 advice = QString::fromLatin1(KCookieAdvice::adviceToStr(KCookieAdvice::Ask)); 0357 } 0358 0359 group.writeEntry("CookieGlobalAdvice", advice); 0360 0361 QStringList domainConfig; 0362 QMapIterator<QString, const char *> it(mDomainPolicyMap); 0363 while (it.hasNext()) { 0364 it.next(); 0365 const QString policy = QLatin1String(tolerantToAce(it.key())) + QLatin1Char(':') + QLatin1String(it.value()); 0366 domainConfig << policy; 0367 } 0368 0369 group.writeEntry("CookieDomainAdvice", domainConfig); 0370 group.sync(); 0371 0372 // Update the cookiejar... 0373 if (!mUi.cbEnableCookies->isChecked()) { 0374 QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"), 0375 QStringLiteral("/modules/kcookiejar"), 0376 QStringLiteral("org.kde.KCookieServer"), 0377 QDBusConnection::sessionBus()); 0378 kded.call(QStringLiteral("shutdown")); 0379 } else { 0380 QDBusInterface kded(QStringLiteral("org.kde.kcookiejar5"), 0381 QStringLiteral("/modules/kcookiejar"), 0382 QStringLiteral("org.kde.KCookieServer"), 0383 QDBusConnection::sessionBus()); 0384 QDBusReply<void> reply = kded.call(QStringLiteral("reloadPolicy")); 0385 if (!reply.isValid()) { 0386 KMessageBox::error(nullptr, 0387 i18n("Unable to communicate with the cookie handler service.\n" 0388 "Any changes you made will not take effect until the service " 0389 "is restarted.")); 0390 } 0391 } 0392 0393 // Force running KIO workers to reload configurations... 0394 KSaveIOConfig::updateRunningWorkers(this); 0395 Q_EMIT changed(false); 0396 } 0397 0398 void KCookiesPolicies::defaults() 0399 { 0400 mUi.cbEnableCookies->setChecked(true); 0401 mUi.rbPolicyAsk->setChecked(true); 0402 mUi.rbPolicyAccept->setChecked(false); 0403 mUi.rbPolicyAcceptForSession->setChecked(false); 0404 mUi.rbPolicyReject->setChecked(false); 0405 mUi.cbRejectCrossDomainCookies->setChecked(true); 0406 mUi.cbAutoAcceptSessionCookies->setChecked(false); 0407 mUi.policyTreeWidget->clear(); 0408 mDomainPolicyMap.clear(); 0409 0410 cookiesEnabled(mUi.cbEnableCookies->isChecked()); 0411 updateButtons(); 0412 } 0413 0414 void KCookiesPolicies::splitDomainAdvice(const QString &cfg, QString &domain, KCookieAdvice::Value &advice) 0415 { 0416 int sepPos = cfg.lastIndexOf(QLatin1Char(':')); 0417 0418 // Ignore any policy that does not contain a domain... 0419 if (sepPos <= 0) { 0420 return; 0421 } 0422 0423 domain = cfg.left(sepPos); 0424 advice = KCookieAdvice::strToAdvice(cfg.mid(sepPos + 1)); 0425 } 0426 0427 QString KCookiesPolicies::quickHelp() const 0428 { 0429 return i18n( 0430 "<h1>Cookies</h1><p>Cookies contain information that KDE" 0431 " application using the HTTP protocol (like Konqueror) stores" 0432 " on your computer from a remote Internet server. This means" 0433 " that a web server can store information about you and your" 0434 " browsing activities on your machine for later use. You might" 0435 " consider this an invasion of privacy.</p><p>However, cookies are" 0436 " useful in certain situations. For example, they are often used" 0437 " by Internet shops, so you can 'put things into a shopping" 0438 " basket'. Some sites require you have a browser that supports" 0439 " cookies.</p><p>Because most people want a compromise between privacy" 0440 " and the benefits cookies offer, KDE offers you the ability to" 0441 " customize the way it handles cookies. You might, for example" 0442 " want to set KDE's default policy to ask you whenever a server" 0443 " wants to set a cookie or simply reject or accept everything." 0444 " For example, you might choose to accept all cookies from your" 0445 " favorite shopping web site. For this all you have to do is" 0446 " either browse to that particular site and when you are presented" 0447 " with the cookie dialog box, click on <i> This domain </i> under" 0448 " the 'apply to' tab and choose accept or simply specify the name" 0449 " of the site in the <i> Domain Specific Policy </i> tab and set" 0450 " it to accept. This enables you to receive cookies from trusted" 0451 " web sites without being asked every time KDE receives a cookie.</p>"); 0452 } 0453 0454 #include "moc_kcookiespolicies.cpp"