diff options
Diffstat (limited to 'src/adblock')
-rw-r--r-- | src/adblock/adblockhostmatcher.cpp | 56 | ||||
-rw-r--r-- | src/adblock/adblockhostmatcher.h | 54 | ||||
-rw-r--r-- | src/adblock/adblockmanager.cpp | 403 | ||||
-rw-r--r-- | src/adblock/adblockmanager.h | 210 | ||||
-rw-r--r-- | src/adblock/adblockrule.cpp | 67 | ||||
-rw-r--r-- | src/adblock/adblockrule.h | 74 | ||||
-rw-r--r-- | src/adblock/adblockrulefallbackimpl.cpp | 180 | ||||
-rw-r--r-- | src/adblock/adblockrulefallbackimpl.h | 56 | ||||
-rw-r--r-- | src/adblock/adblockruleimpl.h | 44 | ||||
-rw-r--r-- | src/adblock/adblockrulenullimpl.cpp | 139 | ||||
-rw-r--r-- | src/adblock/adblockrulenullimpl.h | 51 | ||||
-rw-r--r-- | src/adblock/adblockruletextmatchimpl.cpp | 94 | ||||
-rw-r--r-- | src/adblock/adblockruletextmatchimpl.h | 52 | ||||
-rw-r--r-- | src/adblock/adblockwidget.cpp | 242 | ||||
-rw-r--r-- | src/adblock/adblockwidget.h | 73 | ||||
-rw-r--r-- | src/adblock/blocked_elements.ui | 116 | ||||
-rw-r--r-- | src/adblock/blockedelementswidget.cpp | 116 | ||||
-rw-r--r-- | src/adblock/blockedelementswidget.h | 71 | ||||
-rw-r--r-- | src/adblock/settings_adblock.ui | 178 | ||||
-rw-r--r-- | src/adblock/tests/RULES | 19 | ||||
-rw-r--r-- | src/adblock/tests/divhidingtest.html | 15 |
21 files changed, 2310 insertions, 0 deletions
diff --git a/src/adblock/adblockhostmatcher.cpp b/src/adblock/adblockhostmatcher.cpp new file mode 100644 index 00000000..021fe12d --- /dev/null +++ b/src/adblock/adblockhostmatcher.cpp @@ -0,0 +1,56 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Benjamin Poulain <ikipou at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + +// Self Includes +#include "adblockhostmatcher.h" + +// Rekonq Includes +#include "rekonq_defines.h" + +bool AdBlockHostMatcher::tryAddFilter(const QString &filter) +{ + if (filter.startsWith(QL1S("||"))) + { + + QString domain = filter.mid(2); + + if (!domain.endsWith(QL1C('^'))) + return false; + + if (domain.contains(QL1C('$'))) + return false; + + domain = domain.left(domain.size() - 1); + + if (domain.contains(QL1C('/')) || domain.contains(QL1C('*')) || domain.contains(QL1C('^'))) + return false; + + domain = domain.toLower(); + m_hostList.insert(domain); + m_hostList.insert(QL1S("www.") + domain); + return true; + } + return false; +} diff --git a/src/adblock/adblockhostmatcher.h b/src/adblock/adblockhostmatcher.h new file mode 100644 index 00000000..bdad883c --- /dev/null +++ b/src/adblock/adblockhostmatcher.h @@ -0,0 +1,54 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Benjamin Poulain <ikipou at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + +#ifndef ADBLOCKHOSTMATCHER_H +#define ADBLOCKHOSTMATCHER_H + +#include <QSet> +#include <QString> + +class AdBlockHostMatcher +{ +public: + // Try to add an adblock filter to this host matcher. + // If the filter is not an hostname, the filter is not added + // and the method return false; + bool tryAddFilter(const QString &filter); + + bool match(const QString &host) const + { + return m_hostList.contains(host.toLower()); + } + + void clear() + { + m_hostList.clear(); + } + +private: + QSet<QString> m_hostList; +}; + +#endif // ADBLOCKHOSTMATCHER_H diff --git a/src/adblock/adblockmanager.cpp b/src/adblock/adblockmanager.cpp new file mode 100644 index 00000000..feee243e --- /dev/null +++ b/src/adblock/adblockmanager.cpp @@ -0,0 +1,403 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "adblockmanager.h" +#include "adblockmanager.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "adblockwidget.h" +#include "blockedelementswidget.h" + +#include "webpage.h" + +// KDE Includes +#include <KIO/FileCopyJob> +#include <KStandardDirs> + +// Qt Includes +#include <QUrl> +#include <QWebElement> +#include <QNetworkReply> +#include <QNetworkRequest> + + +QWeakPointer<AdBlockManager> AdBlockManager::s_adBlockManager; + + +AdBlockManager *AdBlockManager::self() +{ + if (s_adBlockManager.isNull()) + { + s_adBlockManager = new AdBlockManager(qApp); + } + return s_adBlockManager.data(); +} + + +// ---------------------------------------------------------------------------------------------- + + +AdBlockManager::AdBlockManager(QObject *parent) + : QObject(parent) + , _isAdblockEnabled(false) + , _isHideAdsEnabled(false) +{ + loadSettings(); +} + + +AdBlockManager::~AdBlockManager() +{ + _whiteList.clear(); + _blackList.clear(); + _hideList.clear(); +} + + +bool AdBlockManager::isEnabled() +{ + return _isAdblockEnabled; +} + + +bool AdBlockManager::isHidingElements() +{ + return _isHideAdsEnabled; +} + + +void AdBlockManager::loadSettings() +{ + // first, check this... + QString adblockFilePath = KStandardDirs::locateLocal("appdata" , QL1S("adblockrc")); + if (!QFile::exists(adblockFilePath)) + { + QString generalAdblockFilePath = KStandardDirs::locate("appdata" , QL1S("adblockrc")); + QFile adblockFile(generalAdblockFilePath); + bool copied = adblockFile.copy(adblockFilePath); + if (!copied) + { + kDebug() << "oh oh... Problems copying default adblock file"; + return; + } + } + _adblockConfig = KSharedConfig::openConfig("adblockrc", KConfig::SimpleConfig, "appdata"); + // ---------------- + + _hostWhiteList.clear(); + _hostBlackList.clear(); + + _whiteList.clear(); + _blackList.clear(); + _hideList.clear(); + + KConfigGroup settingsGroup(_adblockConfig, "Settings"); + _isAdblockEnabled = settingsGroup.readEntry("adBlockEnabled", false); + + // no need to load filters if adblock is not enabled :) + if (!_isAdblockEnabled) + return; + + // just to be sure.. + _isHideAdsEnabled = settingsGroup.readEntry("hideAdsEnabled", false); + + // ---------------------------------------------------------- + + QDateTime today = QDateTime::currentDateTime(); + QDateTime lastUpdate = QDateTime::fromString(settingsGroup.readEntry("lastUpdate", QString())); + int days = settingsGroup.readEntry("updateInterval", 7); + + bool allSubscriptionsNeedUpdate = (today > lastUpdate.addDays(days)); + if (allSubscriptionsNeedUpdate) + { + settingsGroup.writeEntry("lastUpdate", today.toString()); + } + + // (Eventually) update and load automatic rules + KConfigGroup filtersGroup(_adblockConfig, "FiltersList"); + for (int i = 0; i < 60; i++) + { + QString n = QString::number(i + 1); + if (!filtersGroup.hasKey("FilterEnabled-" + n)) + continue; + + bool isFilterEnabled = filtersGroup.readEntry("FilterEnabled-" + n, false); + if (!isFilterEnabled) + continue; + + bool fileExists = subscriptionFileExists(i); + if (allSubscriptionsNeedUpdate || !fileExists) + { + kDebug() << "FILE SHOULDN'T EXIST. updating subscription"; + updateSubscription(i); + } + else + { + QString rulesFilePath = KStandardDirs::locateLocal("appdata" , QL1S("adblockrules_") + n); + loadRules(rulesFilePath); + } + } + + // load local rules + QString localRulesFilePath = KStandardDirs::locateLocal("appdata" , QL1S("adblockrules_local")); + loadRules(localRulesFilePath); +} + + +void AdBlockManager::loadRules(const QString &rulesFilePath) +{ + QFile ruleFile(rulesFilePath); + if (!ruleFile.open(QFile::ReadOnly | QFile::Text)) + { + kDebug() << "Unable to open rule file" << rulesFilePath; + return; + } + + QTextStream in(&ruleFile); + while (!in.atEnd()) + { + QString stringRule = in.readLine(); + loadRuleString(stringRule); + } +} + + +void AdBlockManager::loadRuleString(const QString &stringRule) +{ + // ! rules are comments + if (stringRule.startsWith('!')) + return; + + // [ rules are ABP info + if (stringRule.startsWith('[')) + return; + + // empty rules are just dangerous.. + // (an empty rule in whitelist allows all, in blacklist blocks all..) + if (stringRule.isEmpty()) + return; + + // white rules + if (stringRule.startsWith(QL1S("@@"))) + { + const QString filter = stringRule.mid(2); + if (_hostWhiteList.tryAddFilter(filter)) + return; + + AdBlockRule rule(filter); + _whiteList << rule; + return; + } + + // hide (CSS) rules + if (stringRule.startsWith(QL1S("##"))) + { + _hideList << stringRule.mid(2); + return; + } + + // TODO implement domain-specific hiding + if (stringRule.contains(QL1S("##"))) + return; + + if (_hostBlackList.tryAddFilter(stringRule)) + return; + + AdBlockRule rule(stringRule); + _blackList << rule; +} + + +bool AdBlockManager::blockRequest(const QNetworkRequest &request) +{ + if (!_isAdblockEnabled) + return false; + + // we (ad)block just http traffic + if (request.url().scheme() != QL1S("http")) + return false; + + QString urlString = request.url().toString(); + // We compute a lowercase version of the URL so each rule does not + // have to do it. + const QString urlStringLowerCase = urlString.toLower(); + const QString host = request.url().host(); + + // check white rules before :) + if (_hostWhiteList.match(host)) + { + kDebug() << "ADBLOCK: WHITE RULE (@@) Matched by string: " << urlString; + return false; + } + + Q_FOREACH(const AdBlockRule & filter, _whiteList) + { + if (filter.match(request, urlString, urlStringLowerCase)) + { + kDebug() << "ADBLOCK: WHITE RULE (@@) Matched by string: " << urlString; + return false; + } + } + + // then check the black ones :( + if (_hostBlackList.match(host)) + { + kDebug() << "ADBLOCK: BLACK RULE Matched by string: " << urlString; + return true; + } + + Q_FOREACH(const AdBlockRule & filter, _blackList) + { + if (filter.match(request, urlString, urlStringLowerCase)) + { + kDebug() << "ADBLOCK: BLACK RULE Matched by string: " << urlString; + return true; + } + } + // no match + return false; +} + + +void AdBlockManager::updateSubscription(int i) +{ + KConfigGroup filtersGroup(_adblockConfig, "FiltersList"); + QString n = QString::number(i + 1); + + QString fUrl = filtersGroup.readEntry("FilterURL-" + n, QString()); + KUrl subUrl = KUrl(fUrl); + + QString rulesFilePath = KStandardDirs::locateLocal("appdata" , QL1S("adblockrules_") + n); + KUrl destUrl = KUrl(rulesFilePath); + + KIO::FileCopyJob* job = KIO::file_copy(subUrl , destUrl, -1, KIO::HideProgressInfo); + job->metaData().insert("ssl_no_client_cert", "TRUE"); + job->metaData().insert("ssl_no_ui", "TRUE"); + job->metaData().insert("UseCache", "false"); + job->metaData().insert("cookies", "none"); + job->metaData().insert("no-auth", "true"); + + connect(job, SIGNAL(finished(KJob *)), this, SLOT(slotFinished(KJob *))); +} + + +void AdBlockManager::slotFinished(KJob *job) +{ + if (job->error()) + return; + + KIO::FileCopyJob *fJob = qobject_cast<KIO::FileCopyJob *>(job); + KUrl url = fJob->destUrl(); + url.setProtocol(QString()); // this is needed to load local url well :( + loadRules(url.url()); +} + + +bool AdBlockManager::subscriptionFileExists(int i) +{ + QString n = QString::number(i + 1); + + QString rulesFilePath = KStandardDirs::locateLocal("appdata" , QL1S("adblockrules_") + n); + return QFile::exists(rulesFilePath); +} + + +void AdBlockManager::showSettings() +{ + QPointer<KDialog> dialog = new KDialog(); + dialog->setCaption(i18nc("@title:window", "Ad Block Settings")); + dialog->setButtons(KDialog::Ok | KDialog::Cancel); + + AdBlockWidget widget(_adblockConfig); + dialog->setMainWidget(&widget); + connect(dialog, SIGNAL(okClicked()), &widget, SLOT(save())); + connect(dialog, SIGNAL(okClicked()), this, SLOT(loadSettings())); + dialog->exec(); + + dialog->deleteLater(); +} + + +void AdBlockManager::addCustomRule(const QString &stringRule, bool reloadPage) +{ + // save rule in local filters + QString localRulesFilePath = KStandardDirs::locateLocal("appdata" , QL1S("adblockrules_local")); + + QFile ruleFile(localRulesFilePath); + if (!ruleFile.open(QFile::WriteOnly | QFile::Append)) + { + kDebug() << "Unable to open rule file" << localRulesFilePath; + return; + } + + QTextStream out(&ruleFile); + out << stringRule << '\n'; + + ruleFile.close(); + + // load it + loadRuleString(stringRule); + + // eventually reload page + if (reloadPage) + emit reloadCurrentPage(); +} + + +void AdBlockManager::showBlockedItemDialog() +{ + QPointer<KDialog> dialog = new KDialog(); + dialog->setCaption(i18nc("@title:window", "Blocked elements")); + dialog->setButtons(KDialog::Ok); + + BlockedElementsWidget widget(this); + widget.setBlockedElements(_blockedElements); + widget.setHidedElements(_hidedElements); + + dialog->setMainWidget(&widget); + dialog->exec(); + + Q_FOREACH(const QString & r, widget.rulesToAdd()) + { + addCustomRule(r); + } + + if (widget.pageNeedsReload()) + emit reloadCurrentPage(); + + dialog->deleteLater(); +} + + +void AdBlockManager::clearElementsLists() +{ + _blockedElements.clear(); + _hidedElements = 0; +} diff --git a/src/adblock/adblockmanager.h b/src/adblock/adblockmanager.h new file mode 100644 index 00000000..1946d4ad --- /dev/null +++ b/src/adblock/adblockmanager.h @@ -0,0 +1,210 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + + +#ifndef ADBLOCK_MANAGER_H +#define ADBLOCK_MANAGER_H + + +// NOTE: AdBlockPlus Filters (fast) summary +// +// ### Basic Filter rules +// +// RULE = http://example.com/ads/* +// this should block every link containing all things from that link +// +// ### Exception rules (@@) +// +// RULE = @@advice* +// +// this will save every site, also that matched by other rules, cointaining words +// that starts with "advice". Wildcards && regular expression allowed here. +// +// ### Beginning/end matching rules (||) +// +// RULE=||http://badsite.com +// +// will stop all links starting with http://badsite.com +// +// RULE=*swf|| +// +// will stop all links to direct flash contents +// +// ### Comments (!) +// +// RULE=!azz.. +// +// Every rule starting with a ! is commented out and should not be checked +// +// ### Filter Options +// +// There are 3 kind of filter options: +// +// --- ### TYPE OPTIONS +// +// You can also specify a number of options to modify the behavior of a filter. +// You list these options separated with commas after a dollar sign ($) at the end of the filter +// +// RULE=*/ads/*$element,match-case +// +// where $element can be one of the following: +// $script external scripts loaded via HTML script tag +// $image regular images, typically loaded via HTML img tag +// $background background images, often specified via CSS +// $stylesheet external CSS stylesheet files +// $object content handled by browser plugins, e.g. Flash or Java +// $xbl XBL bindings (typically loaded by -moz-binding CSS property) Firefox 3 or higher required +// $ping link pings Firefox 3 or higher required +// $xmlhttprequest requests started by the XMLHttpRequest object Firefox 3 or higher required +// $object-subrequest requests started plugins like Flash Firefox 3 or higher required +// $dtd DTD files loaded by XML documents Firefox 3 or higher required +// $subdocument embedded pages, usually included via HTML frames +// $document the page itself (only exception rules can be applied to the page) +// $other types of requests not covered in the list above +// +// +// --- ### INVERSE TYPE OPTIONS +// +// Inverse type options are allowed through the ~ sign, for example: +// +// RULE=*/ads/*~$script,match-case +// +// +// --- ### THIRD-PARTY OPTIONS +// +// If "third-party" option is specified, filter is applied just to requests coming from a different +// origin than the currently viewed page. +// In the same way, the "~third-party" option restricts the filter to the requests coming from the +// same origin as the currently viewed page. +// +// +// ### Regular expressions +// +// They usually allow to check for (a lot of) sites, using just one rule, but be careful: +// BASIC FILTERS ARE PROCESSED FASTER THAN REGULAR EXPRESSIONS +// (That's true at least in ABP! In rekonq, I don't know...) +// +// +// ### ELEMENT HIDING (##) +// +// This is quite different from usual adblock (but, for me, more powerful!). Sometimes you will find advertisements +// that can’t be blocked because they are embedded as text in the web page itself. +// All you can do there is HIDE the element :) +// +// RULE=##div.advise +// +// The previous rule will hide every div whose class is named "advise". Usual CSS selectors apply here :) +// +// END NOTE ---------------------------------------------------------------------------------------------------------- + + +// Rekonq Includes +#include "rekonq_defines.h" + +// Local Includes +#include "adblockhostmatcher.h" +#include "adblockrule.h" + +// KDE Includes +#include <KIO/Job> +#include <KSharedConfig> + +// Qt Includes +#include <QObject> +#include <QStringList> +#include <QByteArray> + +// Forward Includes +class QNetworkRequest; +class WebPage; + +// Definitions +typedef QList<AdBlockRule> AdBlockRuleList; + + +class REKONQ_TESTS_EXPORT AdBlockManager : public QObject +{ + Q_OBJECT + +public: + /** + * Entry point. + * Access to AdBlockManager class by using + * AdBlockManager::self()->thePublicMethodYouNeed() + */ + static AdBlockManager *self(); + + ~AdBlockManager(); + + bool isEnabled(); + bool isHidingElements(); + + bool blockRequest(const QNetworkRequest &request); + + void addCustomRule(const QString &, bool reloadPage = true); + void clearElementsLists(); + +private: + AdBlockManager(QObject *parent = 0); + + void updateSubscription(int); + bool subscriptionFileExists(int); + + // load a file rule, given a path + void loadRules(const QString &rulesFilePath); + + // load a single rule + void loadRuleString(const QString &stringRule); + +private Q_SLOTS: + void loadSettings(); + void showSettings(); + void showBlockedItemDialog(); + + void slotFinished(KJob *); + +Q_SIGNALS: + void reloadCurrentPage(); + +private: + bool _isAdblockEnabled; + bool _isHideAdsEnabled; + + AdBlockHostMatcher _hostBlackList; + AdBlockHostMatcher _hostWhiteList; + AdBlockRuleList _blackList; + AdBlockRuleList _whiteList; + QStringList _hideList; + + QStringList _blockedElements; + int _hidedElements; + + KSharedConfig::Ptr _adblockConfig; + + static QWeakPointer<AdBlockManager> s_adBlockManager; +}; + +#endif diff --git a/src/adblock/adblockrule.cpp b/src/adblock/adblockrule.cpp new file mode 100644 index 00000000..d65c340d --- /dev/null +++ b/src/adblock/adblockrule.cpp @@ -0,0 +1,67 @@ +/* ============================================================ + * + * This file is a part of the rekonq project + * + * Copyright (c) 2009 by Zsombor Gegesy <gzsombor@gmail.com> + * Copyright (c) 2009 by Benjamin C. Meyer <ben@meyerhome.net> + * Copyright (C) 2010-2012 by Andrea Diamantini <adjam7 at gmail dot com> + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * ============================================================ */ + + +// Self Includes +#include "adblockrule.h" + +// Local Includes +#include "adblockrulefallbackimpl.h" +#include "adblockrulenullimpl.h" +#include "adblockruletextmatchimpl.h" + + +AdBlockRule::AdBlockRule(const QString &filter) +{ + switch (AdBlockRule::ruleType(filter)) + { + case TextRule: + m_implementation = QSharedPointer<AdBlockRuleImpl>(new AdBlockRuleTextMatchImpl(filter)); + break; + + case FallbackRule: + m_implementation = QSharedPointer<AdBlockRuleImpl>(new AdBlockRuleFallbackImpl(filter)); + break; + + case NullRule: + default: + m_implementation = QSharedPointer<AdBlockRuleImpl>(new AdBlockRuleNullImpl(filter)); + break; + } +} + + +RuleTypes AdBlockRule::ruleType(const QString &filter) +{ + if (AdBlockRuleTextMatchImpl::isTextMatchFilter(filter)) + return TextRule; + + if (AdBlockRuleNullImpl::isNullFilter(filter)) + return NullRule; + + return FallbackRule; +} diff --git a/src/adblock/adblockrule.h b/src/adblock/adblockrule.h new file mode 100644 index 00000000..15dea344 --- /dev/null +++ b/src/adblock/adblockrule.h @@ -0,0 +1,74 @@ +/* + * This file is a part of the rekonq project + * + * Copyright (c) 2009 by Benjamin C. Meyer <ben@meyerhome.net> + * Copyright (C) 2010-2012 by Andrea Diamantini <adjam7 at gmail dot com> + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * ============================================================ */ + + +#ifndef ADBLOCKRULE_H +#define ADBLOCKRULE_H + + +// Rekonq Includes +#include "rekonq_defines.h" + +#include "adblockruleimpl.h" + +#include <QSharedPointer> + +// Forward Includes +class QNetworkRequest; +class QString; + + +enum RuleTypes +{ + TextRule, + FallbackRule, + NullRule +}; + + +class AdBlockRule +{ +public: + AdBlockRule(const QString &filter); + + bool match(const QNetworkRequest &request, const QString &encodedUrl, const QString &encodedUrlLowerCase) const + { + Q_ASSERT(encodedUrl.toLower() == encodedUrlLowerCase); + bool b = m_implementation->match(request, encodedUrl, encodedUrlLowerCase); + if (b) + { + kDebug() << m_implementation->ruleType() << ": rule string = " << m_implementation->ruleString(); + } + return b; + } + + static RuleTypes ruleType(const QString &filter); + +private: + QSharedPointer<AdBlockRuleImpl> m_implementation; +}; + + +#endif // ADBLOCKRULE_H diff --git a/src/adblock/adblockrulefallbackimpl.cpp b/src/adblock/adblockrulefallbackimpl.cpp new file mode 100644 index 00000000..b547beb0 --- /dev/null +++ b/src/adblock/adblockrulefallbackimpl.cpp @@ -0,0 +1,180 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Benjamin Poulain <ikipou at gmail dot com> +* Copyright (C) 2011-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "adblockrulefallbackimpl.h" + +// Rekonq Includes +#include "rekonq_defines.h" + +// Qt Includes +#include <QWebFrame> +#include <QNetworkReply> +#include <QStringList> + + + +static inline bool isRegExpFilter(const QString &filter) +{ + return filter.startsWith(QL1C('/')) && filter.endsWith(QL1C('/')); +} + + +AdBlockRuleFallbackImpl::AdBlockRuleFallbackImpl(const QString &filter) + : AdBlockRuleImpl(filter) + , m_thirdPartyOption(false) +{ + m_regExp.setCaseSensitivity(Qt::CaseInsensitive); + m_regExp.setPatternSyntax(QRegExp::RegExp2); + + QString parsedLine = filter; + + const int optionsNumber = parsedLine.lastIndexOf(QL1C('$')); + if (optionsNumber >= 0 && !isRegExpFilter(parsedLine)) + { + const QStringList options(parsedLine.mid(optionsNumber + 1).split(QL1C(','))); + parsedLine = parsedLine.left(optionsNumber); + + if (options.contains(QL1S("match-case"))) + m_regExp.setCaseSensitivity(Qt::CaseSensitive); + + if (options.contains(QL1S("third-party"))) + m_thirdPartyOption = true; + + Q_FOREACH(const QString & option, options) + { + // Domain restricted filter + const QString domainKeyword(QL1S("domain=")); + if (option.startsWith(domainKeyword)) + { + QStringList domainList = option.mid(domainKeyword.length()).split(QL1C('|')); + Q_FOREACH(const QString & domain, domainList) + { + if (domain.startsWith(QL1C('~'))) + m_whiteDomains.insert(domain.toLower()); + else + m_blackDomains.insert(domain.toLower()); + } + } + } + } + + if (isRegExpFilter(parsedLine)) + parsedLine = parsedLine.mid(1, parsedLine.length() - 2); + else + parsedLine = convertPatternToRegExp(parsedLine); + + m_regExp.setPattern(parsedLine); +} + + +bool AdBlockRuleFallbackImpl::match(const QNetworkRequest &request, const QString &encodedUrl, const QString &) const +{ + if (m_thirdPartyOption) + { + const QString referer = request.rawHeader("referer"); + const QString host = request.url().host(); + + if (referer.contains(host)) // is NOT third party + return false; + } + + const bool regexpMatch = m_regExp.indexIn(encodedUrl) != -1; + + if (regexpMatch && (!m_whiteDomains.isEmpty() || !m_blackDomains.isEmpty())) + { + Q_ASSERT(qobject_cast<QWebFrame*>(request.originatingObject())); + const QWebFrame *const origin = static_cast<QWebFrame * const>(request.originatingObject()); + + const QString originDomain = origin->url().host(); + + if (!m_whiteDomains.isEmpty()) + { + // In this context, white domains means we block anything but what is in the list. + if (m_whiteDomains.contains(originDomain)) + return false; + return true; + } + else if (m_blackDomains.contains(originDomain)) + { + return true; + } + return false; + } + return regexpMatch; +} + + +QString AdBlockRuleFallbackImpl::convertPatternToRegExp(const QString &wildcardPattern) +{ + QString pattern = wildcardPattern; + + // remove multiple wildcards + pattern.replace(QRegExp(QL1S("\\*+")), QL1S("*")); + + // remove anchors following separator placeholder + pattern.replace(QRegExp(QL1S("\\^\\|$")), QL1S("^")); + + // remove leading wildcards + pattern.replace(QRegExp(QL1S("^(\\*)")), QL1S("")); + + // remove trailing wildcards + pattern.replace(QRegExp(QL1S("(\\*)$")), QL1S("")); + + // escape special symbols + pattern.replace(QRegExp(QL1S("(\\W)")), QL1S("\\\\1")); + + // process extended anchor at expression start + pattern.replace(QRegExp(QL1S("^\\\\\\|\\\\\\|")), QL1S("^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?")); + + // process separator placeholders + pattern.replace(QRegExp(QL1S("\\\\\\^")), QL1S("(?:[^\\w\\d\\-.%]|$)")); + + // process anchor at expression start + pattern.replace(QRegExp(QL1S("^\\\\\\|")), QL1S("^")); + + // process anchor at expression end + pattern.replace(QRegExp(QL1S("\\\\\\|$")), QL1S("$")); + + // replace wildcards by .* + pattern.replace(QRegExp(QL1S("\\\\\\*")), QL1S(".*")); + + // Finally, return... + return pattern; +} + + +QString AdBlockRuleFallbackImpl::ruleString() const +{ + return m_regExp.pattern(); +} + + +QString AdBlockRuleFallbackImpl::ruleType() const +{ + return QL1S("AdBlockRuleFallbackImpl"); +} diff --git a/src/adblock/adblockrulefallbackimpl.h b/src/adblock/adblockrulefallbackimpl.h new file mode 100644 index 00000000..4b5716f8 --- /dev/null +++ b/src/adblock/adblockrulefallbackimpl.h @@ -0,0 +1,56 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Benjamin Poulain <ikipou at gmail dot com> +* Copyright (C) 2011-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + +#ifndef ADBLOCKRULEFALLBACKIMPL_H +#define ADBLOCKRULEFALLBACKIMPL_H + +#include "adblockruleimpl.h" + +// Qt Includes +#include <QRegExp> +#include <QString> +#include <QSet> + +class AdBlockRuleFallbackImpl : public AdBlockRuleImpl +{ +public: + AdBlockRuleFallbackImpl(const QString &filter); + bool match(const QNetworkRequest &request, const QString &encodedUrl, const QString &encodedUrlLowerCase) const; + + QString ruleString() const; + QString ruleType() const; + +private: + QString convertPatternToRegExp(const QString &wildcardPattern); + + QRegExp m_regExp; + QSet<QString> m_whiteDomains; + QSet<QString> m_blackDomains; + + bool m_thirdPartyOption; +}; + +#endif // ADBLOCKRULEFALLBACKIMPL_H diff --git a/src/adblock/adblockruleimpl.h b/src/adblock/adblockruleimpl.h new file mode 100644 index 00000000..f1d428d5 --- /dev/null +++ b/src/adblock/adblockruleimpl.h @@ -0,0 +1,44 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Benjamin Poulain <ikipou at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + +#ifndef ADBLOCKRULEIMPL_H +#define ADBLOCKRULEIMPL_H + +class QString; +class QNetworkRequest; + +class AdBlockRuleImpl +{ +public: + AdBlockRuleImpl(const QString &) {} + virtual ~AdBlockRuleImpl() {} + virtual bool match(const QNetworkRequest &request, const QString &encodedUrl, const QString &encodedUrlLowerCase) const = 0; + + // This are added just for debugging purposes + virtual QString ruleString() const = 0; + virtual QString ruleType() const = 0; +}; + +#endif // ADBLOCKRULEIMPL_H diff --git a/src/adblock/adblockrulenullimpl.cpp b/src/adblock/adblockrulenullimpl.cpp new file mode 100644 index 00000000..e16b56db --- /dev/null +++ b/src/adblock/adblockrulenullimpl.cpp @@ -0,0 +1,139 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "adblockrulenullimpl.h" + +// Rekonq Includes +#include "rekonq_defines.h" + +// Qt Includes +#include <QStringList> + + +AdBlockRuleNullImpl::AdBlockRuleNullImpl(const QString &filter) + : AdBlockRuleImpl(filter) +{ +} + + +bool AdBlockRuleNullImpl::match(const QNetworkRequest &, const QString &, const QString &) const +{ + return false; +} + + +bool AdBlockRuleNullImpl::isNullFilter(const QString &filter) +{ + QString parsedLine = filter; + + const int optionsNumber = parsedLine.lastIndexOf(QL1C('$')); + if (optionsNumber == 0) + return false; + + const QStringList options(parsedLine.mid(optionsNumber + 1).split(QL1C(','))); + + Q_FOREACH(const QString & option, options) + { + // NOTE: + // I moved the check from option == QL1S to option.endsWith() + // to check option && ~option. Hope it will NOT be a problem... + + // third_party: managed inside adblockrulefallbackimpl + if (option.endsWith(QL1S("third-party"))) + return false; + + // script + if (option.endsWith(QL1S("script"))) + return true; + + // image + if (option.endsWith(QL1S("image"))) + return true; + + // background + if (option.endsWith(QL1S("background"))) + return true; + + // stylesheet + if (option.endsWith(QL1S("stylesheet"))) + return true; + + // object + if (option.endsWith(QL1S("object"))) + return true; + + // xbl + if (option.endsWith(QL1S("xbl"))) + return true; + + // ping + if (option.endsWith(QL1S("ping"))) + return true; + + // xmlhttprequest + if (option.endsWith(QL1S("xmlhttprequest"))) + return true; + + // object_subrequest + if (option.endsWith(QL1S("object-subrequest"))) + return true; + + // dtd + if (option.endsWith(QL1S("dtd"))) + return true; + + // subdocument + if (option.endsWith(QL1S("subdocument"))) + return true; + + // document + if (option.endsWith(QL1S("document"))) + return true; + + // other + if (option.endsWith(QL1S("other"))) + return true; + + // collapse + if (option.endsWith(QL1S("collapse"))) + return true; + } + + return false; +} + + +QString AdBlockRuleNullImpl::ruleString() const +{ + return QString(); +} + + +QString AdBlockRuleNullImpl::ruleType() const +{ + return QL1S("AdBlockRuleNullImpl"); +} diff --git a/src/adblock/adblockrulenullimpl.h b/src/adblock/adblockrulenullimpl.h new file mode 100644 index 00000000..a8f69652 --- /dev/null +++ b/src/adblock/adblockrulenullimpl.h @@ -0,0 +1,51 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef ADBLOCKRULE_NULL_IMPL_H +#define ADBLOCKRULE_NULL_IMPL_H + + +// Local Includes +#include "adblockruleimpl.h" + +// Qt Includes +#include <QString> + + +class AdBlockRuleNullImpl : public AdBlockRuleImpl +{ + +public: + AdBlockRuleNullImpl(const QString &filter); + bool match(const QNetworkRequest &, const QString &, const QString &) const; + + static bool isNullFilter(const QString &filter); + + QString ruleString() const; + QString ruleType() const; +}; + +#endif // ADBLOCKRULE_NULL_IMPL_H diff --git a/src/adblock/adblockruletextmatchimpl.cpp b/src/adblock/adblockruletextmatchimpl.cpp new file mode 100644 index 00000000..fd901e9c --- /dev/null +++ b/src/adblock/adblockruletextmatchimpl.cpp @@ -0,0 +1,94 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Benjamin Poulain <ikipou at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "adblockruletextmatchimpl.h" + +// Rekonq Includes +#include "rekonq_defines.h" + +// Qt Includes +#include <QNetworkRequest> + + +AdBlockRuleTextMatchImpl::AdBlockRuleTextMatchImpl(const QString &filter) + : AdBlockRuleImpl(filter) +{ + Q_ASSERT(AdBlockRuleTextMatchImpl::isTextMatchFilter(filter)); + + m_textToMatch = filter.toLower(); + m_textToMatch.remove(QL1C('*')); +} + + +bool AdBlockRuleTextMatchImpl::match(const QNetworkRequest &request, const QString &encodedUrl, const QString &encodedUrlLowerCase) const +{ + Q_UNUSED(request); + Q_UNUSED(encodedUrl); + // Case sensitive compare is faster, but would be incorrect with encodedUrl since + // we do want case insensitive. + // What we do is work on a lowercase version of m_textToMatch, and compare to the lowercase + // version of encodedUrl. + return encodedUrlLowerCase.contains(m_textToMatch, Qt::CaseSensitive); +} + + +bool AdBlockRuleTextMatchImpl::isTextMatchFilter(const QString &filter) +{ + // We don't deal with options just yet + if (filter.contains(QL1C('$'))) + return false; + + // We don't deal with element matching + if (filter.contains(QL1S("##"))) + return false; + + // We don't deal with the begin-end matching + if (filter.startsWith(QL1C('|')) || filter.endsWith(QL1C('|'))) + return false; + + // We only handle * at the beginning or the end + int starPosition = filter.indexOf(QL1C('*')); + while (starPosition >= 0) + { + if (starPosition != 0 && starPosition != (filter.length() - 1)) + return false; + starPosition = filter.indexOf(QL1C('*'), starPosition + 1); + } + return true; +} + + +QString AdBlockRuleTextMatchImpl::ruleString() const +{ + return m_textToMatch; +} + + +QString AdBlockRuleTextMatchImpl::ruleType() const +{ + return QL1S("AdBlockRuleTextMatchImpl"); +} diff --git a/src/adblock/adblockruletextmatchimpl.h b/src/adblock/adblockruletextmatchimpl.h new file mode 100644 index 00000000..8600543d --- /dev/null +++ b/src/adblock/adblockruletextmatchimpl.h @@ -0,0 +1,52 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Benjamin Poulain <ikipou at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef ADBLOCKRULETEXTMATCHIMPL_H +#define ADBLOCKRULETEXTMATCHIMPL_H + +#include "adblockruleimpl.h" + +// Qt Includes +#include <QString> + + +// Simple rule to find a string in the URL +class AdBlockRuleTextMatchImpl : public AdBlockRuleImpl +{ +public: + AdBlockRuleTextMatchImpl(const QString &filter); + bool match(const QNetworkRequest &request, const QString &encodedUrl, const QString &encodedUrlLowerCase) const; + + static bool isTextMatchFilter(const QString &filter); + + QString ruleString() const; + QString ruleType() const; + +private: + QString m_textToMatch; +}; + +#endif // ADBLOCKRULETEXTMATCHIMPL_H diff --git a/src/adblock/adblockwidget.cpp b/src/adblock/adblockwidget.cpp new file mode 100644 index 00000000..5ada506e --- /dev/null +++ b/src/adblock/adblockwidget.cpp @@ -0,0 +1,242 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "adblockwidget.h" +#include "adblockwidget.moc" + +// Auto Includes +#include "rekonq.h" + +// KDE Includes +#include <KSharedConfig> +#include <KStandardDirs> +#include <KIcon> + +// Qt Includes +#include <QString> +#include <QWhatsThis> +#include <QListWidgetItem> + + +AdBlockWidget::AdBlockWidget(KSharedConfig::Ptr config, QWidget *parent) + : QWidget(parent) + , _changed(false) + , _adblockConfig(config) +{ + setupUi(this); + + hintLabel->setText(i18n("<qt>Filter expression (e.g. <tt>http://www.example.com/ad/*</tt>, <a href=\"filterhelp\">more information</a>):")); + connect(hintLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotInfoLinkActivated(QString))); + + manualFiltersListWidget->setSortingEnabled(true); + manualFiltersListWidget->setSelectionMode(QAbstractItemView::SingleSelection); + + searchLine->setListWidget(manualFiltersListWidget); + + insertButton->setIcon(KIcon("list-add")); + connect(insertButton, SIGNAL(clicked()), this, SLOT(insertRule())); + + removeButton->setIcon(KIcon("list-remove")); + connect(removeButton, SIGNAL(clicked()), this, SLOT(removeRule())); + + load(); + + spinBox->setSuffix(ki18np(" day", " days")); + + // emit changed signal + connect(insertButton, SIGNAL(clicked()), this, SLOT(hasChanged())); + connect(removeButton, SIGNAL(clicked()), this, SLOT(hasChanged())); + connect(checkEnableAdblock, SIGNAL(stateChanged(int)), this, SLOT(hasChanged())); + connect(checkHideAds, SIGNAL(stateChanged(int)), this, SLOT(hasChanged())); + connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(hasChanged())); + + connect(automaticFiltersListWidget, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(hasChanged())); +} + + +void AdBlockWidget::slotInfoLinkActivated(const QString &url) +{ + Q_UNUSED(url) + + QString hintHelpString = i18n("<qt><p>Enter an expression to filter. Filters can be defined as either:" + "<ul><li>a shell-style wildcard, e.g. <tt>http://www.example.com/ads*</tt>, " + "the wildcards <tt>*?[]</tt> may be used</li>" + "<li>a full regular expression by surrounding the string with '<tt>/</tt>', " + "e.g. <tt>/\\/(ad|banner)\\./</tt></li></ul>" + "<p>Any filter string can be preceded by '<tt>@@</tt>' to whitelist (allow) any matching URL, " + "which takes priority over any blacklist (blocking) filter."); + + QWhatsThis::showText(QCursor::pos(), hintHelpString); +} + + +void AdBlockWidget::insertRule() +{ + QString rule = addFilterLineEdit->text(); + if (rule.isEmpty()) + return; + + manualFiltersListWidget->addItem(rule); + addFilterLineEdit->clear(); +} + + +void AdBlockWidget::removeRule() +{ + manualFiltersListWidget->takeItem(manualFiltersListWidget->currentRow()); +} + + +void AdBlockWidget::load() +{ + // General settings + KConfigGroup settingsGroup(_adblockConfig, "Settings"); + + const bool isAdBlockEnabled = settingsGroup.readEntry("adBlockEnabled", false); + checkEnableAdblock->setChecked(isAdBlockEnabled); + + // update enabled status + checkHideAds->setEnabled(isAdBlockEnabled); + tabWidget->setEnabled(isAdBlockEnabled); + + const bool areImageFiltered = settingsGroup.readEntry("hideAdsEnabled", false); + checkHideAds->setChecked(areImageFiltered); + + const int days = settingsGroup.readEntry("updateInterval", 7); + spinBox->setValue(days); + + // ------------------------------------------------------------------------------ + + // automatic filters + KConfigGroup autoFiltersGroup(_adblockConfig, "FiltersList"); + + int i = 1; + QString n = QString::number(i); + + while (autoFiltersGroup.hasKey("FilterName-" + n)) + { + bool filterEnabled = autoFiltersGroup.readEntry("FilterEnabled-" + n, false); + QString filterName = autoFiltersGroup.readEntry("FilterName-" + n, QString()); + + QListWidgetItem *subItem = new QListWidgetItem(automaticFiltersListWidget); + subItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + if (filterEnabled) + subItem->setCheckState(Qt::Checked); + else + subItem->setCheckState(Qt::Unchecked); + + subItem->setText(filterName); + + i++; + n = QString::number(i); + } + + // ------------------------------------------------------------------------------ + + // local filters + QString localRulesFilePath = KStandardDirs::locateLocal("appdata" , QL1S("adblockrules_local")); + + QFile ruleFile(localRulesFilePath); + if (!ruleFile.open(QFile::ReadOnly | QFile::Text)) + { + kDebug() << "Unable to open rule file" << localRulesFilePath; + return; + } + + QTextStream in(&ruleFile); + while (!in.atEnd()) + { + QString stringRule = in.readLine(); + QListWidgetItem *subItem = new QListWidgetItem(manualFiltersListWidget); + subItem->setText(stringRule); + } +} + + +void AdBlockWidget::save() +{ + if (!_changed) + return; + + // General settings + KConfigGroup settingsGroup(_adblockConfig, "Settings"); + + settingsGroup.writeEntry("adBlockEnabled", checkEnableAdblock->isChecked()); + settingsGroup.writeEntry("hideAdsEnabled", checkHideAds->isChecked()); + settingsGroup.writeEntry("updateInterval", spinBox->value()); + + // automatic filters + KConfigGroup autoFiltersGroup(_adblockConfig, "FiltersList"); + for (int i = 0; i < automaticFiltersListWidget->count(); i++) + { + QListWidgetItem *subItem = automaticFiltersListWidget->item(i); + bool active = true; + if (subItem->checkState() == Qt::Unchecked) + active = false; + + QString n = QString::number(i + 1); + autoFiltersGroup.writeEntry("FilterEnabled-" + n, active); + } + + // local filters + QString localRulesFilePath = KStandardDirs::locateLocal("appdata" , QL1S("adblockrules_local")); + + QFile ruleFile(localRulesFilePath); + if (!ruleFile.open(QFile::WriteOnly | QFile::Text)) + { + kDebug() << "Unable to open rule file" << localRulesFilePath; + return; + } + + QTextStream out(&ruleFile); + for (int i = 0; i < manualFiltersListWidget->count(); i++) + { + QListWidgetItem *subItem = manualFiltersListWidget->item(i); + QString stringRule = subItem->text(); + out << stringRule << '\n'; + } + + // ------------------------------------------------------------------------------- + _changed = false; + emit changed(false); +} + + +void AdBlockWidget::hasChanged() +{ + // update enabled status + checkHideAds->setEnabled(checkEnableAdblock->isChecked()); + tabWidget->setEnabled(checkEnableAdblock->isChecked()); + _changed = true; + emit changed(true); +} + + +bool AdBlockWidget::changed() +{ + return _changed; +} diff --git a/src/adblock/adblockwidget.h b/src/adblock/adblockwidget.h new file mode 100644 index 00000000..37f29f93 --- /dev/null +++ b/src/adblock/adblockwidget.h @@ -0,0 +1,73 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef ADBLOCK_WIDGET_H +#define ADBLOCK_WIDGET_H + + +// Rekonq Includes +#include "rekonq_defines.h" + +// Ui Includes +#include "ui_settings_adblock.h" + +// KDE Includes +#include <KSharedConfig> + +// Qt Includes +#include <QWidget> + + +class AdBlockWidget : public QWidget, private Ui::adblock +{ + Q_OBJECT + +public: + explicit AdBlockWidget(KSharedConfig::Ptr config, QWidget *parent = 0); + + bool changed(); + +Q_SIGNALS: + void changed(bool); + +public Q_SLOTS: + void save(); + +private Q_SLOTS: + void hasChanged(); + + void slotInfoLinkActivated(const QString &); + void insertRule(); + void removeRule(); + +private: + void load(); + + bool _changed; + KSharedConfig::Ptr _adblockConfig; +}; + +#endif // ADBLOCK_WIDGET_H diff --git a/src/adblock/blocked_elements.ui b/src/adblock/blocked_elements.ui new file mode 100644 index 00000000..204bf81f --- /dev/null +++ b/src/adblock/blocked_elements.ui @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BlockedElements</class> + <widget class="QWidget" name="BlockedElements"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>527</width> + <height>407</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="BlockedLabel"> + <property name="text"> + <string><html><head/><body><p><span style=" font-weight:600;">Blocked elements</span></p></body></html></string> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="frame"> + <property name="palette"> + <palette> + <active> + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + </active> + <inactive> + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + </inactive> + <disabled> + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> + <red>255</red> + <green>255</green> + <blue>255</blue> + </color> + </brush> + </colorrole> + </disabled> + </palette> + </property> + <property name="autoFillBackground"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="HidedLabel"> + <property name="text"> + <string><b>Hidden elements</b></string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/adblock/blockedelementswidget.cpp b/src/adblock/blockedelementswidget.cpp new file mode 100644 index 00000000..141dd203 --- /dev/null +++ b/src/adblock/blockedelementswidget.cpp @@ -0,0 +1,116 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "blockedelementswidget.h" +#include "blockedelementswidget.moc" + +// Local Includes +#include "adblockmanager.h" + +// Qt Includes +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QPushButton> + + +BlockedElementsWidget::BlockedElementsWidget(QObject *manager, QWidget *parent) + : QWidget(parent) + , _manager(manager) + , _reloadPage(false) +{ + setupUi(this); +} + + +void BlockedElementsWidget::setBlockedElements(const QStringList &list) +{ + QVBoxLayout *frameLayout = new QVBoxLayout(frame); + + Q_FOREACH(const QString & block, list) + { + QString truncatedUrl = block; + const int maxTextSize = 73; + if (truncatedUrl.length() > maxTextSize) + { + const int truncateSize = 70; + truncatedUrl.truncate(truncateSize); + truncatedUrl += QL1S("..."); + } + QWidget *w = new QWidget(this); + QHBoxLayout *l = new QHBoxLayout(w); + l->addWidget(new QLabel(truncatedUrl, this)); + + QPushButton *button = new QPushButton(KIcon("dialog-ok-apply"), i18n("Unblock"), this); + button->setProperty("URLTOUNBLOCK", block); + button->setFixedWidth(100); + connect(button, SIGNAL(clicked()), this, SLOT(unblockElement())); + l->addWidget(button); + + w->setMinimumWidth(500); + frameLayout->addWidget(w); + } +} + + +void BlockedElementsWidget::setHidedElements(int n) +{ + AdBlockManager *m = qobject_cast<AdBlockManager *>(_manager); + if (m->isHidingElements()) + label->setText(i18np("There is %1 hidden element in this page.", "There are %1 hidden elements in this page.", QString::number(n))); + else + label->setText(i18n("Hiding elements is disabled.")); +} + + +void BlockedElementsWidget::unblockElement() +{ + QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender()); + if (!buttonClicked) + return; + + QString urlString = QL1S("@@") + buttonClicked->property("URLTOUNBLOCK").toString(); + kDebug() << "urlString: " << urlString; + + QString newText = i18n("Unblocked"); + QString buttonText = buttonClicked->text().remove('&'); + if (buttonText == newText) + { + buttonClicked->setText(i18n("Unblock")); + buttonClicked->setIcon(KIcon("dialog-ok-apply")); + + _rulesToAdd.removeOne(urlString); + } + else + { + buttonClicked->setText(newText); + buttonClicked->setIcon(KIcon("dialog-ok")); + + _rulesToAdd << urlString; + } + + _reloadPage = true; +} diff --git a/src/adblock/blockedelementswidget.h b/src/adblock/blockedelementswidget.h new file mode 100644 index 00000000..d26ee849 --- /dev/null +++ b/src/adblock/blockedelementswidget.h @@ -0,0 +1,71 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2012 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef BLOCKED_ELEMENTS_WIDGET_H +#define BLOCKED_ELEMENTS_WIDGET_H + + +// Rekonq Includes +#include "rekonq_defines.h" + +// Ui Includes +#include "ui_blocked_elements.h" + +// Qt Includes +#include <QWidget> + + +class BlockedElementsWidget : public QWidget, private Ui::BlockedElements +{ + Q_OBJECT + +public: + explicit BlockedElementsWidget(QObject *manager, QWidget *parent = 0); + + void setBlockedElements(const QStringList &); + void setHidedElements(int); + + bool pageNeedsReload() + { + return _reloadPage; + }; + + QStringList rulesToAdd() + { + return _rulesToAdd; + }; + +private Q_SLOTS: + void unblockElement(); + +private: + QObject *_manager; + + bool _reloadPage; + QStringList _rulesToAdd; +}; + +#endif // BLOCKED_ELEMENTS_WIDGET_H diff --git a/src/adblock/settings_adblock.ui b/src/adblock/settings_adblock.ui new file mode 100644 index 00000000..e4f06339 --- /dev/null +++ b/src/adblock/settings_adblock.ui @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>adblock</class> + <widget class="QWidget" name="adblock"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>601</width> + <height>507</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="checkEnableAdblock"> + <property name="text"> + <string>&Enable Ad Block</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkHideAds"> + <property name="text"> + <string>&Hide filtered elements</string> + </property> + </widget> + </item> + <item> + <widget class="KTabWidget" name="tabWidget"> + <property name="toolTip"> + <string/> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab_3"> + <attribute name="title"> + <string>Automatic Filters</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QListWidget" name="automaticFiltersListWidget"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Update enabled automatic filters every:</string> + </property> + </widget> + </item> + <item> + <widget class="KIntSpinBox" name="spinBox"> + <property name="minimumSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="suffix"> + <string/> + </property> + <property name="value"> + <number>7</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Manual Filters</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Search:</string> + </property> + </widget> + </item> + <item> + <widget class="KListWidgetSearchLine" name="searchLine"/> + </item> + </layout> + </item> + <item> + <widget class="KListWidget" name="manualFiltersListWidget"/> + </item> + <item> + <widget class="QLabel" name="hintLabel"> + <property name="text"> + <string comment="KDE::DoNotExtract">TextLabel</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="KLineEdit" name="addFilterLineEdit"/> + </item> + <item> + <widget class="QToolButton" name="insertButton"> + <property name="toolTip"> + <string>Add filter expression</string> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="removeButton"> + <property name="toolTip"> + <string>Remove filter expression</string> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KListWidgetSearchLine</class> + <extends>KLineEdit</extends> + <header>klistwidgetsearchline.h</header> + </customwidget> + <customwidget> + <class>KLineEdit</class> + <extends>QLineEdit</extends> + <header>klineedit.h</header> + </customwidget> + <customwidget> + <class>KIntSpinBox</class> + <extends>QSpinBox</extends> + <header>knuminput.h</header> + </customwidget> + <customwidget> + <class>KListWidget</class> + <extends>QListWidget</extends> + <header>klistwidget.h</header> + </customwidget> + <customwidget> + <class>KTabWidget</class> + <extends>QTabWidget</extends> + <header>ktabwidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/adblock/tests/RULES b/src/adblock/tests/RULES new file mode 100644 index 00000000..8dfdf8fa --- /dev/null +++ b/src/adblock/tests/RULES @@ -0,0 +1,19 @@ +! cancel ALL your rules in the adblock, +! load these and test rekonq against +! the proposed sites +! Good Luck! +! +! This rule will block EVERY site containing adv +adv +! +! This one will wildcard EVERY site containing the word "advice" +@@advice +! +! Block every google site :) +||http://google* +! +! Block every pdf file! +*pdf|| +! +! Block every div of the class "advise" +##div.advise
\ No newline at end of file diff --git a/src/adblock/tests/divhidingtest.html b/src/adblock/tests/divhidingtest.html new file mode 100644 index 00000000..a38e9ea1 --- /dev/null +++ b/src/adblock/tests/divhidingtest.html @@ -0,0 +1,15 @@ +<html> + +<head> +</head> + +<body> + +<div class="advise"> +<h1>Oh oh.. an advise!!</h1> +</div> +<h2>no advises here :)</h2> +At least, I hope so... +</body> + +</html>
\ No newline at end of file |