From fd2a265b1d80bbd395bfc27d27eef596a50af198 Mon Sep 17 00:00:00 2001 From: Benjamin C Meyer Date: Sat, 19 Sep 2009 12:08:13 -0400 Subject: [PATCH] Add support for AdBlock Overall design: AdBlockManager (QObject) - One per browser with a property saying if adblock is enabled. - Owns all of the subscriptions AdBlockSubscription (QObject) - Constructed from an abp: url - Owns all of the rules for this subscription - Downloads rules when needed. AdBlockRule - Has a bool networkMatch(const QString &) function. - Various properties such as if enabled, is a css rule etc. AdBlockNetwork (applies network rules) - QNetworkAccessManager uses this to see if a connection should be blocked. AdBlockPage (applies css rules) - WebPage uses this to hide elements. AdBlockModel/AdBlockDialog - Sits on top of AdBlockManager and presents a dialog to the user so they can add rules, subscriptions etc. AdBlockScheme - Handle the abp url scheme to subscribe to a new adblock subscriptions. Misc: - Added right click action to block --- autotests/adblock/adblock.pro | 9 + autotests/adblock/adblockmanager/.gitignore | 1 + .../adblock/adblockmanager/adblockmanager.pro | 10 + .../adblockmanager/tst_adblockmanager.cpp | 238 +++++++++++ autotests/adblock/adblocknetwork/.gitignore | 1 + .../adblock/adblocknetwork/adblocknetwork.pro | 10 + .../adblocknetwork/tst_adblocknetwork.cpp | 224 ++++++++++ autotests/adblock/adblockpage/.gitignore | 1 + autotests/adblock/adblockpage/adblockpage.pro | 10 + autotests/adblock/adblockpage/test.html | 8 + .../adblock/adblockpage/tst_adblockpage.cpp | 160 ++++++++ autotests/adblock/adblockrule/.gitignore | 1 + autotests/adblock/adblockrule/adblockrule.pro | 10 + .../adblock/adblockrule/tst_adblockrule.cpp | 385 ++++++++++++++++++ .../adblock/adblocksubscription/.gitignore | 2 + .../adblocksubscription.pro | 10 + .../adblock/adblocksubscription/rules.txt | 3 + .../tst_adblocksubscription.cpp | 358 ++++++++++++++++ autotests/autotests.pro | 1 + manualtests/adblock/adblock.pro | 6 + manualtests/adblock/adblockdialog/.gitignore | 1 + .../adblock/adblockdialog/adblockdialog.pro | 11 + .../adblockdialog/main_adblockdialog.cpp | 44 ++ manualtests/adblock/adblockmodel/.gitignore | 1 + .../adblock/adblockmodel/adblockmodel.pro | 11 + .../adblockmodel/main_adblockmodel.cpp | 46 +++ manualtests/manualtests.pro | 1 + src/adblock/adblock.pri | 28 ++ src/adblock/adblockblockednetworkreply.cpp | 58 +++ src/adblock/adblockblockednetworkreply.h | 52 +++ src/adblock/adblockdialog.cpp | 150 +++++++ src/adblock/adblockdialog.h | 61 +++ src/adblock/adblockdialog.ui | 127 ++++++ src/adblock/adblockmanager.cpp | 228 +++++++++++ src/adblock/adblockmanager.h | 88 ++++ src/adblock/adblockmodel.cpp | 267 ++++++++++++ src/adblock/adblockmodel.h | 67 +++ src/adblock/adblocknetwork.cpp | 80 ++++ src/adblock/adblocknetwork.h | 48 +++ src/adblock/adblockpage.cpp | 116 ++++++ src/adblock/adblockpage.h | 50 +++ src/adblock/adblockrule.cpp | 216 ++++++++++ src/adblock/adblockrule.h | 68 ++++ src/adblock/adblockschemeaccesshandler.cpp | 69 ++++ src/adblock/adblockschemeaccesshandler.h | 42 ++ src/adblock/adblocksubscription.cpp | 375 +++++++++++++++++ src/adblock/adblocksubscription.h | 102 +++++ src/browsermainwindow.cpp | 7 + src/browsermainwindow.h | 1 + src/data/128x128/run.license | 2 + src/data/128x128/run.png | Bin 0 -> 16493 bytes src/data/data.qrc | 1 + src/network/networkaccessmanager.cpp | 14 + src/network/networkaccessmanager.h | 2 + src/src.pri | 1 + src/webpage.cpp | 3 + src/webview.cpp | 15 + src/webview.h | 1 + 58 files changed, 3902 insertions(+) create mode 100644 autotests/adblock/adblock.pro create mode 100644 autotests/adblock/adblockmanager/.gitignore create mode 100644 autotests/adblock/adblockmanager/adblockmanager.pro create mode 100644 autotests/adblock/adblockmanager/tst_adblockmanager.cpp create mode 100644 autotests/adblock/adblocknetwork/.gitignore create mode 100644 autotests/adblock/adblocknetwork/adblocknetwork.pro create mode 100644 autotests/adblock/adblocknetwork/tst_adblocknetwork.cpp create mode 100644 autotests/adblock/adblockpage/.gitignore create mode 100644 autotests/adblock/adblockpage/adblockpage.pro create mode 100644 autotests/adblock/adblockpage/test.html create mode 100644 autotests/adblock/adblockpage/tst_adblockpage.cpp create mode 100644 autotests/adblock/adblockrule/.gitignore create mode 100644 autotests/adblock/adblockrule/adblockrule.pro create mode 100644 autotests/adblock/adblockrule/tst_adblockrule.cpp create mode 100644 autotests/adblock/adblocksubscription/.gitignore create mode 100644 autotests/adblock/adblocksubscription/adblocksubscription.pro create mode 100644 autotests/adblock/adblocksubscription/rules.txt create mode 100644 autotests/adblock/adblocksubscription/tst_adblocksubscription.cpp create mode 100644 manualtests/adblock/adblock.pro create mode 100644 manualtests/adblock/adblockdialog/.gitignore create mode 100644 manualtests/adblock/adblockdialog/adblockdialog.pro create mode 100644 manualtests/adblock/adblockdialog/main_adblockdialog.cpp create mode 100644 manualtests/adblock/adblockmodel/.gitignore create mode 100644 manualtests/adblock/adblockmodel/adblockmodel.pro create mode 100644 manualtests/adblock/adblockmodel/main_adblockmodel.cpp create mode 100644 src/adblock/adblock.pri create mode 100644 src/adblock/adblockblockednetworkreply.cpp create mode 100644 src/adblock/adblockblockednetworkreply.h create mode 100644 src/adblock/adblockdialog.cpp create mode 100644 src/adblock/adblockdialog.h create mode 100644 src/adblock/adblockdialog.ui create mode 100644 src/adblock/adblockmanager.cpp create mode 100644 src/adblock/adblockmanager.h create mode 100644 src/adblock/adblockmodel.cpp create mode 100644 src/adblock/adblockmodel.h create mode 100644 src/adblock/adblocknetwork.cpp create mode 100644 src/adblock/adblocknetwork.h create mode 100644 src/adblock/adblockpage.cpp create mode 100644 src/adblock/adblockpage.h create mode 100644 src/adblock/adblockrule.cpp create mode 100644 src/adblock/adblockrule.h create mode 100644 src/adblock/adblockschemeaccesshandler.cpp create mode 100644 src/adblock/adblockschemeaccesshandler.h create mode 100644 src/adblock/adblocksubscription.cpp create mode 100644 src/adblock/adblocksubscription.h create mode 100644 src/data/128x128/run.license create mode 100644 src/data/128x128/run.png diff --git a/autotests/adblock/adblock.pro b/autotests/adblock/adblock.pro new file mode 100644 index 00000000..e00136d1 --- /dev/null +++ b/autotests/adblock/adblock.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs +SUBDIRS = \ + adblockmanager \ + adblocknetwork \ + adblockpage \ + adblockrule \ + adblocksubscription + +CONFIG += ordered diff --git a/autotests/adblock/adblockmanager/.gitignore b/autotests/adblock/adblockmanager/.gitignore new file mode 100644 index 00000000..956108dc --- /dev/null +++ b/autotests/adblock/adblockmanager/.gitignore @@ -0,0 +1 @@ +adblockmanager diff --git a/autotests/adblock/adblockmanager/adblockmanager.pro b/autotests/adblock/adblockmanager/adblockmanager.pro new file mode 100644 index 00000000..025c3a5a --- /dev/null +++ b/autotests/adblock/adblockmanager/adblockmanager.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +include(../../autotests.pri) + +# Input +SOURCES += tst_adblockmanager.cpp +HEADERS += diff --git a/autotests/adblock/adblockmanager/tst_adblockmanager.cpp b/autotests/adblock/adblockmanager/tst_adblockmanager.cpp new file mode 100644 index 00000000..0674a077 --- /dev/null +++ b/autotests/adblock/adblockmanager/tst_adblockmanager.cpp @@ -0,0 +1,238 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "adblockdialog.h" +#include "adblockmanager.h" +#include "adblocksubscription.h" + +#include + +class tst_AdBlockManager : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void adblockmanager_data(); + void adblockmanager(); + + void addSubscription(); + void customRules(); + void isEnabled_data(); + void isEnabled(); + void load(); + void removeSubscription(); + void showDialog(); + void rulesChanged(); +}; + +// Subclass that exposes the protected functions. +class SubAdBlockManager : public AdBlockManager +{ +public: + ~SubAdBlockManager() { + QList list = subscriptions(); + foreach (AdBlockSubscription *s, list) + removeSubscription(s); + setEnabled(false); + } + + void call_rulesChanged() + { return SubAdBlockManager::rulesChanged(); } +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_AdBlockManager::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_AdBlockManager::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_AdBlockManager::init() +{ +} + +// This will be called after every test function. +void tst_AdBlockManager::cleanup() +{ +} + +void tst_AdBlockManager::adblockmanager_data() +{ +} + +void tst_AdBlockManager::adblockmanager() +{ + SubAdBlockManager manager; + manager.addSubscription((AdBlockSubscription*)0); + QVERIFY(manager.customRules()); + QVERIFY(manager.instance() != (AdBlockManager*)0); + QCOMPARE(manager.isEnabled(), false); + manager.load(); + QVERIFY(manager.network()); + QVERIFY(manager.page()); + manager.removeSubscription((AdBlockSubscription*)0); + manager.setEnabled(false); + QVERIFY(manager.showDialog()); + QList list; + list.append(manager.customRules()); + QCOMPARE(manager.subscriptions(), list); +} + +// public void addSubscription(AdBlockSubscription *subscription) +void tst_AdBlockManager::addSubscription() +{ + SubAdBlockManager manager; + + QList list = manager.subscriptions(); + + QSignalSpy spy0(&manager, SIGNAL(rulesChanged())); + + AdBlockSubscription *subscription = new AdBlockSubscription(QUrl(), &manager); + manager.addSubscription(subscription); + QCOMPARE(manager.subscriptions(), (list += subscription)); + + QCOMPARE(spy0.count(), 1); +} + +// public AdBlockSubscription *customRules() +void tst_AdBlockManager::customRules() +{ + SubAdBlockManager manager; + QSignalSpy spy0(&manager, SIGNAL(rulesChanged())); + + AdBlockSubscription *subscription = manager.customRules(); + QVERIFY(subscription); + QVERIFY(!subscription->title().isEmpty()); + QVERIFY(subscription->allRules().isEmpty()); + + QCOMPARE(spy0.count(), 1); + + subscription = manager.customRules(); + QCOMPARE(spy0.count(), 1); +} + +void tst_AdBlockManager::isEnabled_data() +{ + QTest::addColumn("isEnabled"); + QTest::newRow("true") << true; + QTest::newRow("false") << false; +} + +// public bool isEnabled() const +void tst_AdBlockManager::isEnabled() +{ + QFETCH(bool, isEnabled); + + SubAdBlockManager manager; + + QSignalSpy spy0(&manager, SIGNAL(rulesChanged())); + + bool before = manager.isEnabled(); + + manager.setEnabled(isEnabled); + manager.setEnabled(isEnabled); + QCOMPARE(manager.isEnabled(), isEnabled); + + QCOMPARE(spy0.count(), before == isEnabled ? 0 : 1); +} + +// public void load() +void tst_AdBlockManager::load() +{ + SubAdBlockManager manager; + + QSignalSpy spy0(&manager, SIGNAL(rulesChanged())); + + manager.load(); + + QCOMPARE(spy0.count(), 0); +} + +// public void removeSubscription(AdBlockSubscription *subscription) +void tst_AdBlockManager::removeSubscription() +{ + SubAdBlockManager manager; + + QSignalSpy spy0(&manager, SIGNAL(rulesChanged())); + + QList list = manager.subscriptions(); + AdBlockSubscription *subscription = new AdBlockSubscription(QUrl(), &manager); + manager.addSubscription(subscription); + manager.removeSubscription(subscription); + QCOMPARE(manager.subscriptions(), list); + + QCOMPARE(spy0.count(), 2); +} + + +// public AdBlockDialog *showDialog() +void tst_AdBlockManager::showDialog() +{ + SubAdBlockManager manager; + + QSignalSpy spy0(&manager, SIGNAL(rulesChanged())); + + AdBlockDialog *dialog = manager.showDialog(); + QVERIFY(dialog); + QTRY_VERIFY(dialog->isVisible()); +} + +void tst_AdBlockManager::rulesChanged() +{ + SubAdBlockManager manager; + + QSignalSpy spy0(&manager, SIGNAL(rulesChanged())); + + + AdBlockSubscription *subscription = new AdBlockSubscription(QUrl(), &manager); + manager.addSubscription(subscription); + subscription->setEnabled(true); + subscription->addRule(AdBlockRule()); + + QCOMPARE(spy0.count(), 3); +} + +QTEST_MAIN(tst_AdBlockManager) +#include "tst_adblockmanager.moc" + diff --git a/autotests/adblock/adblocknetwork/.gitignore b/autotests/adblock/adblocknetwork/.gitignore new file mode 100644 index 00000000..dcb473fd --- /dev/null +++ b/autotests/adblock/adblocknetwork/.gitignore @@ -0,0 +1 @@ +adblocknetwork diff --git a/autotests/adblock/adblocknetwork/adblocknetwork.pro b/autotests/adblock/adblocknetwork/adblocknetwork.pro new file mode 100644 index 00000000..2ae14cc2 --- /dev/null +++ b/autotests/adblock/adblocknetwork/adblocknetwork.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +include(../../autotests.pri) + +# Input +SOURCES += tst_adblocknetwork.cpp +HEADERS += diff --git a/autotests/adblock/adblocknetwork/tst_adblocknetwork.cpp b/autotests/adblock/adblocknetwork/tst_adblocknetwork.cpp new file mode 100644 index 00000000..90b2ea6e --- /dev/null +++ b/autotests/adblock/adblocknetwork/tst_adblocknetwork.cpp @@ -0,0 +1,224 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "adblocknetwork.h" +#include "adblockmanager.h" +#include "adblocksubscription.h" +#include "adblockrule.h" + +#include + +class tst_AdBlockNetwork : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void adblocknetwork_data(); + void adblocknetwork(); + + void data(); + + void enabled_data(); + void enabled(); + + void block_data(); + void block(); +}; + +// Subclass that exposes the protected functions. +class SubAdBlockNetwork : public AdBlockNetwork +{ +public: + +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_AdBlockNetwork::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_AdBlockNetwork::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_AdBlockNetwork::init() +{ +} + +// This will be called after every test function. +void tst_AdBlockNetwork::cleanup() +{ + AdBlockManager *manager = AdBlockManager::instance(); + QList list = manager->subscriptions(); + foreach (AdBlockSubscription *s, list) + manager->removeSubscription(s); +} + +void tst_AdBlockNetwork::adblocknetwork_data() +{ +} + +void tst_AdBlockNetwork::adblocknetwork() +{ + SubAdBlockNetwork network; + QCOMPARE(network.block(QNetworkRequest()), (QNetworkReply*)0); +} + +void tst_AdBlockNetwork::data() +{ + SubAdBlockNetwork network; + + AdBlockManager *manager = AdBlockManager::instance(); + manager->setEnabled(true); + + AdBlockSubscription *subscription = new AdBlockSubscription(QUrl(), manager); + subscription->setEnabled(true); + manager->addSubscription(subscription); + + AdBlockRule rule("/"); + rule.setEnabled(true); + subscription->addRule(rule); + + QNetworkReply *reply = 0; + QNetworkRequest request = QNetworkRequest(QUrl("data://foobar")); + + reply = network.block(request); + QVERIFY(!reply); +} + +void tst_AdBlockNetwork::enabled_data() +{ + QTest::addColumn("enableManager"); + QTest::addColumn("enableSubscription"); + QTest::addColumn("enableRule"); + QTest::addColumn("block"); + QTest::newRow("null") << true << true << true << true; + QTest::newRow("m") << false << true << true << false; + QTest::newRow("s") << true << false << true << false; + QTest::newRow("r") << true << true << false << false; +} + +void tst_AdBlockNetwork::enabled() +{ + QFETCH(bool, enableManager); + QFETCH(bool, enableSubscription); + QFETCH(bool, enableRule); + QFETCH(bool, block); + + SubAdBlockNetwork network; + + AdBlockManager *manager = AdBlockManager::instance(); + manager->setEnabled(enableManager); + + AdBlockSubscription *subscription = new AdBlockSubscription(QUrl(), manager); + subscription->setEnabled(enableSubscription); + manager->addSubscription(subscription); + + AdBlockRule rule("/"); + rule.setEnabled(enableRule); + subscription->addRule(rule); + + QNetworkReply *reply = 0; + QNetworkRequest grequest = QNetworkRequest(QUrl("http://www.google.com")); + + reply = network.block(grequest); + QCOMPARE((reply != 0), block); +} + +// check that block block and !block blocks other sites +void tst_AdBlockNetwork::block_data() +{ + QTest::addColumn("ruleList"); + QTest::addColumn("url"); + QTest::addColumn("block"); + + QTest::newRow("null") << QString() + << QUrl() + << false; + + QUrl google("http://www.google.com"); + QTest::newRow("google") << QString("/") + << google + << true; + + // defining exception rules + QTest::newRow("exception0") << QString("@@advice,advice") + << QUrl("http://example.com/advice.html") + << false; + QTest::newRow("exception1") << QString("@@|http://example.com") + << QUrl("http://example.com/advice.html") + << false; + QTest::newRow("exception2") << QString("@@http://example.com") + << QUrl("http://example.com/advice.html") + << false; + + QTest::newRow("order0") << QString("advice,@@advice") + << QUrl("http://example.com/advice.html") + << false; +} + +// public QNetworkReply *block(QNetworkRequest const &request) +void tst_AdBlockNetwork::block() +{ + QFETCH(QString, ruleList); + QFETCH(QUrl, url); + QFETCH(bool, block); + + SubAdBlockNetwork network; + + AdBlockManager *manager = AdBlockManager::instance(); + manager->setEnabled(true); + + AdBlockSubscription *subscription = new AdBlockSubscription(QUrl(), manager); + subscription->setEnabled(true); + manager->addSubscription(subscription); + + QStringList rules = ruleList.split(","); + foreach (const QString &rule, rules) + subscription->addRule(AdBlockRule(rule)); + + QNetworkReply *reply = network.block(QNetworkRequest(url)); + bool blocked = (reply != 0); + QCOMPARE(blocked, block); +} + +QTEST_MAIN(tst_AdBlockNetwork) +#include "tst_adblocknetwork.moc" + diff --git a/autotests/adblock/adblockpage/.gitignore b/autotests/adblock/adblockpage/.gitignore new file mode 100644 index 00000000..ed880152 --- /dev/null +++ b/autotests/adblock/adblockpage/.gitignore @@ -0,0 +1 @@ +adblockpage diff --git a/autotests/adblock/adblockpage/adblockpage.pro b/autotests/adblock/adblockpage/adblockpage.pro new file mode 100644 index 00000000..a6a6b207 --- /dev/null +++ b/autotests/adblock/adblockpage/adblockpage.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +include(../../autotests.pri) + +# Input +SOURCES += tst_adblockpage.cpp +HEADERS += diff --git a/autotests/adblock/adblockpage/test.html b/autotests/adblock/adblockpage/test.html new file mode 100644 index 00000000..39cb99d1 --- /dev/null +++ b/autotests/adblock/adblockpage/test.html @@ -0,0 +1,8 @@ + +
Cheapest tofu, only here and now!
+
Really cheap tofu, click here!
+Only here you get the best tofu! +
tofu!
+
Cheapest tofu, only here and now!
+
Cheapest tofu, only here and now!
+
tofu!
diff --git a/autotests/adblock/adblockpage/tst_adblockpage.cpp b/autotests/adblock/adblockpage/tst_adblockpage.cpp new file mode 100644 index 00000000..ee8d16ac --- /dev/null +++ b/autotests/adblock/adblockpage/tst_adblockpage.cpp @@ -0,0 +1,160 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "adblockpage.h" + +#include "adblockmanager.h" +#include "adblocksubscription.h" +#include "adblockrule.h" + +#include +#include +#include +#include + +class tst_AdBlockPage : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void adblockpage_data(); + void adblockpage(); + + void applyRulesToPage_data(); + void applyRulesToPage(); +}; + +// Subclass that exposes the protected functions. +class SubAdBlockPage : public AdBlockPage +{ +public: + +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_AdBlockPage::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_AdBlockPage::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_AdBlockPage::init() +{ +} + +// This will be called after every test function. +void tst_AdBlockPage::cleanup() +{ + AdBlockManager *manager = AdBlockManager::instance(); + QList list = manager->subscriptions(); + foreach (AdBlockSubscription *s, list) + manager->removeSubscription(s); +} + +void tst_AdBlockPage::adblockpage_data() +{ +} + +void tst_AdBlockPage::adblockpage() +{ + SubAdBlockPage page; + page.applyRulesToPage((QWebPage*)0); +} + +void tst_AdBlockPage::applyRulesToPage_data() +{ + QTest::addColumn("ruleList"); + QTest::addColumn("count"); + + int start = 7; + QTest::newRow("null") << QString() << start; + + //Examples taken from http://adblockplus.org/en/filters + + QTest::newRow("basic-0") << QString("##div.textad") << start - 1; + QTest::newRow("basic-1") << QString("##div#sponsorad") << start - 1; + QTest::newRow("basic-2") << QString("##*#sponsorad") << start - 1; + QTest::newRow("basic-3") << QString("##textad") << start -1; + + // Attribute selectors + QTest::newRow("attribute-0") << QString("##table[width=\"80%\"]") << start - 2; + QTest::newRow("attribute-1") << QString("##table[width=\"80%\"][bgcolor=\"white\"]") << start - 1; + QTest::newRow("attribute-2") << QString("##div[title*=\"adv\"]") << start - 2; + QTest::newRow("attribute-3") << QString("##div[title^=\"adv\"][title$=\"ert\"]") << start - 1; + + // Advanced selectors +} + +// public void applyRulesToPage(QWebPage *page) +void tst_AdBlockPage::applyRulesToPage() +{ + QFETCH(QString, ruleList); + QFETCH(int, count); + + AdBlockManager *manager = AdBlockManager::instance(); + manager->setEnabled(true); + + AdBlockSubscription *subscription = new AdBlockSubscription(QUrl(), manager); + subscription->setEnabled(true); + manager->addSubscription(subscription); + + QStringList rules = ruleList.split(","); + foreach (const QString &rule, rules) + subscription->addRule(AdBlockRule(rule)); + + QWebView view; + QSignalSpy spy1(view.page(), SIGNAL(loadFinished(bool))); + view.load(QUrl::fromLocalFile(QDir::currentPath() + "/test.html")); + QTRY_COMPARE(spy1.count(), 1); + + SubAdBlockPage page; + page.applyRulesToPage(view.page()); + if (view.page()->mainFrame()->toHtml().count("tofu") != count) + qDebug() << view.page()->mainFrame()->toHtml(); + QCOMPARE(view.page()->mainFrame()->toHtml().count("tofu"), count); +} + +QTEST_MAIN(tst_AdBlockPage) +#include "tst_adblockpage.moc" + diff --git a/autotests/adblock/adblockrule/.gitignore b/autotests/adblock/adblockrule/.gitignore new file mode 100644 index 00000000..3b9e3229 --- /dev/null +++ b/autotests/adblock/adblockrule/.gitignore @@ -0,0 +1 @@ +adblockrule diff --git a/autotests/adblock/adblockrule/adblockrule.pro b/autotests/adblock/adblockrule/adblockrule.pro new file mode 100644 index 00000000..52435394 --- /dev/null +++ b/autotests/adblock/adblockrule/adblockrule.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +include(../../autotests.pri) + +# Input +SOURCES += tst_adblockrule.cpp +HEADERS += diff --git a/autotests/adblock/adblockrule/tst_adblockrule.cpp b/autotests/adblock/adblockrule/tst_adblockrule.cpp new file mode 100644 index 00000000..1ba1a046 --- /dev/null +++ b/autotests/adblock/adblockrule/tst_adblockrule.cpp @@ -0,0 +1,385 @@ +/* + * Copyright 2009 Benjamin C. Meyer + * Copyright 2009 Zsombor Gegesy + * + * 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) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include + +#include "adblockrule.h" + +#include +#include + +class tst_AdBlockRule : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void regexpCreation_data(); + void regexpCreation(); + void networkMatch_data(); + void networkMatch(); + +}; + +// Subclass that exposes the protected functions. +class SubAdBlockRule : public AdBlockRule +{ +public: + SubAdBlockRule(const QString &filter); +}; + +SubAdBlockRule::SubAdBlockRule(const QString &filter) + : AdBlockRule(filter) +{ +} + +// This will be called before the first test function is executed. +// It is only called once. +void tst_AdBlockRule::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_AdBlockRule::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_AdBlockRule::init() +{ +} + +// This will be called after every test function. +void tst_AdBlockRule::cleanup() +{ +} + +void tst_AdBlockRule::networkMatch_data() +{ + QTest::addColumn("filter"); + QTest::addColumn("url"); + QTest::addColumn("networkMatch"); + QTest::newRow("null") << QString() << QUrl() << false; + + //Examples taken from http://adblockplus.org/en/filters + + // Basic filter rules + QTest::newRow("basic0") << QString("http://example.com/ads/banner123.gif") + << QUrl("http://example.com/ads/banner123.gif") + << true; + QTest::newRow("basic1") << QString("http://example.com/ads/banner*.gif") + << QUrl("http://example.com/ads/banner123.gif") + << true; + QTest::newRow("basic2") << QString("http://example.com/ads/*") + << QUrl("http://example.com/ads/banner123.gif") + << true; + QTest::newRow("basic3") << QString("http://example.com/*") + << QUrl("http://example.com/ads/banner123.gif") + << true; + + // defining exception rules + QTest::newRow("exception0") << QString("@@advice") + << QUrl("http://example.com/advice.html") + << true; + QTest::newRow("exception1") << QString("@@|http://example.com") + << QUrl("http://example.com/advice.html") + << true; + QTest::newRow("exception2") << QString("@@http://example.com") + << QUrl("http://example.com/advice.html") + << true; + + // matching at beginning/end of an address + QTest::newRow("m0") << QString("ad") + << QUrl("http://example.com/advice.html") + << true; + QTest::newRow("m1") << QString("*ad*") + << QUrl("http://example.com/advice.html") + << true; + QTest::newRow("m2") << QString("swf") + << QUrl("http://example.com/swf/index.html") + << true; + QTest::newRow("m3") << QString("swf|") + << QUrl("http://example.com/annoyingflash.swf") + << true; + QTest::newRow("m4") << QString("swf|") + << QUrl("http://example.com/swf/index.html") + << false; + + QTest::newRow("m5") << QString("http://baddomain.example/") + << QUrl("http://baddomain.example/banner.gif") + << true; + QTest::newRow("m6") << QString("http://baddomain.example/") + << QUrl("http://gooddomain.example/analyze?http://baddomain.example.") + << false; + + QTest::newRow("m7") << QString("||example.com/banner.gif") + << QUrl("http://example.com/banner.gif") + << true; + QTest::newRow("m8") << QString("||example.com/banner.gif") + << QUrl("https://example.com/banner.gif") + << true; + QTest::newRow("m9") << QString("||example.com/banner.gif") + << QUrl("http://www.example.com/banner.gif") + << true; + + QTest::newRow("m10") << QString("||example.com/banner.gif") + << QUrl("http://badexample.com/banner.gif") + << false; + QTest::newRow("m10") << QString("||example.com/banner.gif") + << QUrl("http://gooddomain.example/analyze?http://example.com/banner.gif") + << false; + + QTest::newRow("m11") << QString("/getad.php|") + << QUrl("http://adblockplus.mozdev.org/easylist/easylist.txt") + << false; + + // Matching separators + QTest::newRow("sep_1") << QString("a^") + << QUrl("a/") + << true; + QTest::newRow("sep_2") << QString("a^") + << QUrl("a:") + << true; + QTest::newRow("sep_3") << QString("a^") + << QUrl("a.") + << false; + QTest::newRow("sep_4") << QString("a^") + << QUrl("a?") + << true; + QTest::newRow("sep_5") << QString("a^") + << QUrl("a=") + << true; + QTest::newRow("sep_6") << QString("a^") + << QUrl("a&") + << true; + + QTest::newRow("s1_s") << QString("com^") + << QUrl("com:") + << true; + QTest::newRow("s2_s") << QString("ab^cd") + << QUrl("ab.cd") + << false; + + // Marking separate characters + QTest::newRow("s0") << QString("http://example.com^") + << QUrl("http://example.com/") + << true; + QTest::newRow("s1") << QString("http://example.com^") + << QUrl("http://example.com:8000/") + << true; + QTest::newRow("s2") << QString("http://example.com^") + << QUrl("http://example.com.ar/") + << false; + QTest::newRow("s3") << QString("^example.com^") + << QUrl("http://example.com:8000/foo.bar?a=12&b=%D1%82%D0%B5%D1%81%D1%82") + << true; + QTest::newRow("s4") << QString("^%D1^") + << QUrl::fromEncoded("http://example.com:8000/foo.bar?a=12&b=%D1") + << true; + QTest::newRow("s5") << QString("^foo.bar^") + << QUrl("http://example.com:8000/foo.bar?a=12&b=%D1%82%D0%B5%D1%81%D1%82") + << true; + QTest::newRow("s6") << QString("^%D1%82%D0%B5%D1%81%D1%82^") + << QUrl::fromEncoded("http://example.com:8000/foo.bar?a=12&b=%D1%82%D0%B5%D1%81%D1%82") + << true; + // Comments + QTest::newRow("c0") << QString("!foo.bar") + << QUrl("!foo.bar") + << false; + QTest::newRow("c1") << QString("!foo.bar") + << QUrl("foo.bar") + << false; + + // Specifying filter options + // type + QTest::newRow("o0") << QString("*/ads/*$script,image,background,stylesheet,object,xbl,ping,xmlhttprequest,object-subrequest,object-subrequest,dtd,subdocument,document,other") + << QUrl("foo.bar/ads/foo.jpg") + << false; + // Inverse type + QTest::newRow("o1") << QString("*/ads/*$~script, ~image, ~background, ~stylesheet, ~object, ~xbl, ~ping, ~xmlhttprequest, ~object-subrequest, ~dtd, ~subdocument, ~document, ~other") + << QUrl("foo.bar/ads/foo.jpg") + << false; + // Restriction to third-party/first-party requests + QTest::newRow("o2") << QString("*/ads/*$third-party") + << QUrl("foo.bar/ads/foo.jpg") + << false; + QTest::newRow("o3") << QString("*/ads/*$first-party") + << QUrl("foo.bar/ads/foo.jpg") + << false; + // Domain restrictions + QTest::newRow("o4") << QString("*/ads/*$domain=example.com|example.net") + << QUrl("http://example.com/ads/foo.jpg") + << true; + QTest::newRow("o5") << QString("*/ads/*$domain=example.com") + << QUrl("http://foo.com/ads/foo.jpg") + << false; + + QTest::newRow("o6") << QString("*/ads/*$domain=~example.com") + << QUrl("http://foo.com/ads/foo.jpg") + << true; + QTest::newRow("o7") << QString("*/ads/*$domain=~example.com") + << QUrl("http://example.com/ads/foo.jpg") + << false; + QTest::newRow("o8") << QString("*/ads/*$domain=example.com|~foo.example.com") + << QUrl("http://example.com/ads/foo.jpg") + << true; + QTest::newRow("o9") << QString("*/ads/*$domain=example.com|~foo.example.com") + << QUrl("http://foo.example.com/ads/foo.jpg") + << false; + QTest::newRow("o10") << QString("*/ads/*$domain=example.com|~foo.example.com") + << QUrl("http://bar.example.com/ads/foo.jpg") + << true; + // match-case + QTest::newRow("o11") << QString("*/BannerAd.gif$match-case") + << QUrl("http://example.com/BannerAd.gif") + << true; + QTest::newRow("o12") << QString("*/BannerAd.gif$match-case") + << QUrl("http://example.com/bannerad.gif") + << false; + // collapse + // TODO test collapse somehow + QTest::newRow("o13") << QString("*/BannerAd.gif$collapse") + << QUrl("http://example.com/bannerad.gif") + << false; + QTest::newRow("o14") << QString("*/BannerAd.gif$~collapse") + << QUrl("http://example.com/bannerad.gif") + << false; + // Regular expressions + QTest::newRow("r0") << QString("/banner\\d+/") + << QUrl("banner123") + << true; + QTest::newRow("r1") << QString("/banner\\d+/") + << QUrl("banner321") + << true; + QTest::newRow("r2") << QString("/banner\\d+/") + << QUrl("banners") + << false; + + // See the AdBlockPage autotest for CSS testing + // Basic Element hiding the network matching should never pass + QTest::newRow("e0") << QString("##div.textad") + << QUrl() + << false; + QTest::newRow("e1") << QString("##div#sponsorad") + << QUrl() + << false; + QTest::newRow("e1") << QString("##*#sponsorad") + << QUrl() + << false; + QTest::newRow("e1") << QString("##textad") + << QUrl() + << false; + QTest::newRow("e1") << QString("example.com##*.sponsor") + << QUrl("example.com") + << false; + QTest::newRow("e1") << QString("example.com,example.net##*.sponsor") + << QUrl("example.com") + << false; + + // Seen on the internet + QTest::newRow("i0") << QString("||snap.com^$third-party") + << QUrl("http://spa.snap.com/snap_preview_anywhere.js?ap=1&key=89743df349c6c38afc3094e9566cb98e&sb=1&link_icon=off&domain=pub-6332280-www.techcrunch.com") + << true; + + QTest::newRow("i1") << QString("|http://ads.") + << QUrl("http://ads.cnn.com/html.ng/site=cnn&cnn_pagetype=main&cnn_position=336x280_adlinks&cnn_rollup=homepage&page.allowcompete=yes¶ms.styles=fs&tile=8837285713521&domId=463050") + << true; + + QTest::newRow("i2") << QString("/adverti$~object_subrequest,~stylesheet,domain=~advertise4free.org|~amarillas.cl|~bnet.com|~catalysttelecom.com|~cod4central.com|~scansource.com|~scansourcecommunications.com|~scansourcesecurity.com") + << QUrl("http://i2.cdn.turner.com/cnn/.element/img/2.0/content/ads/advertisement.gif") + << true; + + QTest::newRow("i3") << QString("/adspace") + << QUrl("http://i.cdn.turner.com/cnn/cnn_adspaces/cnn_adspaces.js") + << false; +} + +// public bool networkMatch(const QUrl &url) const +void tst_AdBlockRule::networkMatch() +{ + QFETCH(QString, filter); + QFETCH(QUrl, url); + QFETCH(bool, networkMatch); + + SubAdBlockRule AdBlockRule(filter); + bool result = AdBlockRule.networkMatch(url.toEncoded()); + if (result != networkMatch) { + qDebug() << "Match error."; + qDebug() << "\tFilter:" << filter; + qDebug() << "\tUrl: " << url; + qDebug() << "\tResult : " << (result ? "match" : "NOT match"); + } + QCOMPARE(AdBlockRule.networkMatch(url.toEncoded()), networkMatch); +} + +void tst_AdBlockRule::regexpCreation_data() +{ + QTest::addColumn("input"); + QTest::addColumn("output"); + + QTest::newRow("null") << QString("test") << QString("test"); + QTest::newRow("m1") << QString("abc*") << QString("abc"); + QTest::newRow("m2") << QString("*abc*") << QString("abc"); + QTest::newRow("m3") << QString("abc**") << QString("abc"); + QTest::newRow("m4") << QString("abc***") << QString("abc"); + QTest::newRow("m5") << QString("**abc**") << QString("abc"); + QTest::newRow("m6") << QString("**a*bc**") << QString("a.*bc"); + QTest::newRow("h1") << QString("abc.com") << QString("abc\\.com"); + + QTest::newRow("a2") << QString("abc^|def") << QString("abc(?:[^\\w\\d\\-.%]|$)\\|def"); + QTest::newRow("a3") << QString("^|def") << QString("(?:[^\\w\\d\\-.%]|$)\\|def"); + + QTest::newRow("s1") << QString("de|f") << QString("de\\|f"); + + QTest::newRow("e1") << QString("|abc") << QString("^abc"); + QTest::newRow("e2") << QString("d|abc") << QString("d\\|abc"); + QTest::newRow("e3") << QString("abc|") << QString("abc$"); + + QTest::newRow("z1") << QString("^abc") << QString("(?:[^\\w\\d\\-.%]|$)abc"); + QTest::newRow("z2") << QString("a^bc") << QString("a(?:[^\\w\\d\\-.%]|$)bc"); + QTest::newRow("z3") << QString("abc^|") << QString("abc(?:[^\\w\\d\\-.%]|$)"); + QTest::newRow("z4") << QString("http://example.com^") + << QString("http\\:\\/\\/example\\.com(?:[^\\w\\d\\-.%]|$)"); + + + QTest::newRow("d0") << QString("||example.com") + << QString("^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?example\\.com"); + QTest::newRow("d1") << QString("||example.com/banner.gif") + << QString("^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?example\\.com\\/banner\\.gif"); +} + +void tst_AdBlockRule::regexpCreation() +{ + QFETCH(QString, input); + QFETCH(QString, output); + + SubAdBlockRule rule(input); + QCOMPARE(rule.regExpPattern(), output); +} + +QTEST_MAIN(tst_AdBlockRule) +#include "tst_adblockrule.moc" + diff --git a/autotests/adblock/adblocksubscription/.gitignore b/autotests/adblock/adblocksubscription/.gitignore new file mode 100644 index 00000000..aea23ae2 --- /dev/null +++ b/autotests/adblock/adblocksubscription/.gitignore @@ -0,0 +1,2 @@ +adblocksubscription +rules2.txt diff --git a/autotests/adblock/adblocksubscription/adblocksubscription.pro b/autotests/adblock/adblocksubscription/adblocksubscription.pro new file mode 100644 index 00000000..2ad5e053 --- /dev/null +++ b/autotests/adblock/adblocksubscription/adblocksubscription.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +include(../../autotests.pri) + +# Input +SOURCES += tst_adblocksubscription.cpp +HEADERS += diff --git a/autotests/adblock/adblocksubscription/rules.txt b/autotests/adblock/adblocksubscription/rules.txt new file mode 100644 index 00000000..6a13a94c --- /dev/null +++ b/autotests/adblock/adblocksubscription/rules.txt @@ -0,0 +1,3 @@ +[Adblock Plus 0.7.1] +http://example.com/ads/* +@@advice diff --git a/autotests/adblock/adblocksubscription/tst_adblocksubscription.cpp b/autotests/adblock/adblocksubscription/tst_adblocksubscription.cpp new file mode 100644 index 00000000..81decc53 --- /dev/null +++ b/autotests/adblock/adblocksubscription/tst_adblocksubscription.cpp @@ -0,0 +1,358 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +#include + +class tst_AdBlockSubscription : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void adblocksubscription_data(); + void adblocksubscription(); + + void isEnabled_data(); + void isEnabled(); + void location_data(); + void location(); + void saveRules_data(); + void saveRules(); + void title_data(); + void title(); + void updateNow_data(); + void updateNow(); + void allow_data(); + void allow(); + void block_data(); + void block(); + void addRule(); + void removeRule(); +}; + +// Subclass that exposes the protected functions. +class SubAdBlockSubscription : public AdBlockSubscription +{ +public: + SubAdBlockSubscription(const QUrl &url = QUrl()) : AdBlockSubscription(url) {} + +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_AdBlockSubscription::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_AdBlockSubscription::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_AdBlockSubscription::init() +{ +} + +// This will be called after every test function. +void tst_AdBlockSubscription::cleanup() +{ +} + +void tst_AdBlockSubscription::adblocksubscription_data() +{ + QTest::addColumn("url"); + QTest::addColumn("title"); + QTest::addColumn("location"); + QTest::addColumn("enabled"); + QTest::addColumn("lastUpdate"); + QTest::newRow("basic0") << QUrl::fromEncoded("abp:subscribe?location=http://easylist.adblockplus.org/easylist.txt&title=EasyList") + << "EasyList" + << QUrl("http://easylist.adblockplus.org/easylist.txt") + << true + << QDateTime(); + + + QTest::addColumn("url"); + QTest::addColumn("title"); + QTest::addColumn("location"); + QTest::addColumn("enabled"); + QTest::addColumn("lastUpdate"); + QTest::newRow("basic1") << QUrl::fromEncoded("abp:subscribe?location=http://easylist.adblockplus.org/easylist.txt&title=EasyList&enabled=false&lastUpdate=2009-01-16T12%3A10%3A55") + << "EasyList" + << QUrl("http://easylist.adblockplus.org/easylist.txt") + << false + << QDateTime(QDate(2009, 1, 16), QTime(12, 10, 55)); +} + +void tst_AdBlockSubscription::adblocksubscription() +{ + QFETCH(QUrl, url); + QFETCH(QString, title); + QFETCH(QUrl, location); + QFETCH(bool, enabled); + QFETCH(QDateTime, lastUpdate); + + SubAdBlockSubscription subscription(url); + QCOMPARE(subscription.title(), title); + QCOMPARE(subscription.location(), location); + QCOMPARE(subscription.isEnabled(), enabled); + QCOMPARE(subscription.lastUpdate(), lastUpdate); + QVERIFY(subscription.url().isValid()); + //QCOMPARE(subscription.url(), url); + QCOMPARE(subscription.block(QString()), (AdBlockRule const*)0); + subscription.saveRules(); + subscription.setEnabled(false); + subscription.setLocation(QUrl()); + subscription.setTitle(QString()); + subscription.updateNow(); + subscription.allRules(); + subscription.removeRule(-1); + subscription.removeRule(0); + subscription.removeRule(1); + subscription.addRule(AdBlockRule()); +} + +Q_DECLARE_METATYPE(AdBlockRule const*) +void tst_AdBlockSubscription::allow_data() +{ + QTest::addColumn("url"); + QTest::addColumn("allow"); + QTest::newRow("block") << QUrl("http://example.com/ads/banner123.gif") << false; + QTest::newRow("allow") << QUrl("http://example.com/ads/advice.html") << true; +} + +// public AdBlockRule const *block(QString const &urlString) const +void tst_AdBlockSubscription::allow() +{ + QFETCH(QUrl, url); + QFETCH(bool, allow); + + SubAdBlockSubscription subscription; + subscription.setLocation(QUrl::fromLocalFile(QDir::currentPath() + "/rules.txt")); + subscription.setEnabled(true); + subscription.updateNow(); + + const AdBlockRule *rule = subscription.allow(QString::fromUtf8(url.toEncoded())); + if (rule) + QVERIFY(rule->isException()); + QCOMPARE((0 != rule), allow); +} + +void tst_AdBlockSubscription::block_data() +{ + QTest::addColumn("url"); + QTest::addColumn("block"); + QTest::newRow("block") << QUrl("http://example.com/ads/banner123.gif") << true; + QTest::newRow("allow") << QUrl("http://example.com/ads/advice.html") << true; +} + +// public AdBlockRule const *block(QString const &urlString) const +void tst_AdBlockSubscription::block() +{ + QFETCH(QUrl, url); + QFETCH(bool, block); + + SubAdBlockSubscription subscription; + subscription.setLocation(QUrl::fromLocalFile(QDir::currentPath() + "/rules.txt")); + subscription.setEnabled(true); + subscription.updateNow(); + + const AdBlockRule *rule = subscription.block(QString::fromUtf8(url.toEncoded())); + if (rule) + QVERIFY(!rule->isException()); + QCOMPARE((0 != rule), block); +} + +void tst_AdBlockSubscription::isEnabled_data() +{ + QTest::addColumn("isEnabled"); + QTest::newRow("true") << true; + QTest::newRow("false") << false; +} + +// public bool isEnabled() const +void tst_AdBlockSubscription::isEnabled() +{ + QFETCH(bool, isEnabled); + + SubAdBlockSubscription subscription; + + QSignalSpy spy0(&subscription, SIGNAL(rulesChanged())); + QSignalSpy spy1(&subscription, SIGNAL(changed())); + + bool changed = subscription.isEnabled() != isEnabled; + subscription.setEnabled(isEnabled); + QCOMPARE(subscription.isEnabled(), isEnabled); + + QCOMPARE(spy0.count(), 0); + QCOMPARE(spy1.count(), changed ? 1 : 0); +} + +void tst_AdBlockSubscription::location_data() +{ + QTest::addColumn("location"); + QTest::newRow("null") << QUrl(); + QTest::newRow("x") << QUrl("x"); +} + +// public QUrl location() const +void tst_AdBlockSubscription::location() +{ + QFETCH(QUrl, location); + + SubAdBlockSubscription subscription(QUrl("abp:subscribe")); + + QSignalSpy spy0(&subscription, SIGNAL(rulesChanged())); + QSignalSpy spy1(&subscription, SIGNAL(changed())); + + bool changed = location != subscription.location(); + subscription.setLocation(location); + QCOMPARE(subscription.location(), location); + QCOMPARE(subscription.url(), QUrl(QString("abp:subscribe?location=%1&title=").arg(location.toString()))); + + QCOMPARE(spy0.count(), 0); + QCOMPARE(spy1.count(), changed ? 1 : 0); +} + +void tst_AdBlockSubscription::saveRules_data() +{ + QTest::addColumn("location"); + QTest::newRow("file") << QUrl::fromLocalFile(QDir::currentPath() + "/rules2.txt"); +} + +// public void saveRules() +void tst_AdBlockSubscription::saveRules() +{ + QFETCH(QUrl, location); + SubAdBlockSubscription subscription; + subscription.setLocation(location); + + subscription.addRule(AdBlockRule()); + subscription.saveRules(); + subscription.removeRule(0); + subscription.updateNow(); + QCOMPARE(subscription.allRules().count(), 1); +} + +void tst_AdBlockSubscription::title_data() +{ + QTest::addColumn("title"); + QTest::newRow("null") << QString(); + QTest::newRow("foo") << QString("foo"); +} + +// public QString title() const +void tst_AdBlockSubscription::title() +{ + QFETCH(QString, title); + + SubAdBlockSubscription subscription; + + QSignalSpy spy0(&subscription, SIGNAL(rulesChanged())); + QSignalSpy spy1(&subscription, SIGNAL(changed())); + + bool changed = title != subscription.title(); + subscription.setTitle(title); + QCOMPARE(subscription.title(), title); + + QCOMPARE(spy0.count(), 0); + QCOMPARE(spy1.count(), changed ? 1 : 0); +} + +void tst_AdBlockSubscription::updateNow_data() +{ + QTest::addColumn("location"); + QTest::newRow("file") << QUrl::fromLocalFile(QDir::currentPath() + "/rules.txt"); +} + +// public void updateNow() +void tst_AdBlockSubscription::updateNow() +{ + QFETCH(QUrl, location); + + SubAdBlockSubscription subscription; + subscription.setLocation(location); + + QSignalSpy spy0(&subscription, SIGNAL(rulesChanged())); + QSignalSpy spy1(&subscription, SIGNAL(changed())); + + subscription.updateNow(); + + QTRY_COMPARE(spy0.count(), 1); + QCOMPARE(spy1.count(), 1); + QVERIFY(subscription.lastUpdate() != QDateTime()); + QCOMPARE(subscription.allRules().count(), 2); +} + +void tst_AdBlockSubscription::addRule() +{ + SubAdBlockSubscription subscription; + + QSignalSpy spy0(&subscription, SIGNAL(rulesChanged())); + QSignalSpy spy1(&subscription, SIGNAL(changed())); + + subscription.addRule(AdBlockRule()); + subscription.addRule(AdBlockRule("/test")); + + QTRY_COMPARE(spy0.count(), 2); + QCOMPARE(spy1.count(), 0); + QCOMPARE(subscription.allRules().count(), 2); +} + +void tst_AdBlockSubscription::removeRule() +{ + SubAdBlockSubscription subscription; + + QSignalSpy spy0(&subscription, SIGNAL(rulesChanged())); + QSignalSpy spy1(&subscription, SIGNAL(changed())); + + subscription.addRule(AdBlockRule("/test")); + subscription.removeRule(0); + + QTRY_COMPARE(spy0.count(), 2); + QCOMPARE(spy1.count(), 0); + QCOMPARE(subscription.allRules().count(), 0); +} + + +QTEST_MAIN(tst_AdBlockSubscription) +#include "tst_adblocksubscription.moc" + diff --git a/autotests/autotests.pro b/autotests/autotests.pro index 047391e8..5e31e945 100644 --- a/autotests/autotests.pro +++ b/autotests/autotests.pro @@ -1,5 +1,6 @@ TEMPLATE = subdirs SUBDIRS = \ + adblock \ addbookmarkdialog \ autosaver \ cookiejar \ diff --git a/manualtests/adblock/adblock.pro b/manualtests/adblock/adblock.pro new file mode 100644 index 00000000..d0811c75 --- /dev/null +++ b/manualtests/adblock/adblock.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs +SUBDIRS = \ + adblockdialog \ + adblockmodel + +CONFIG += ordered diff --git a/manualtests/adblock/adblockdialog/.gitignore b/manualtests/adblock/adblockdialog/.gitignore new file mode 100644 index 00000000..ad6f3475 --- /dev/null +++ b/manualtests/adblock/adblockdialog/.gitignore @@ -0,0 +1 @@ +adblockdialog diff --git a/manualtests/adblock/adblockdialog/adblockdialog.pro b/manualtests/adblock/adblockdialog/adblockdialog.pro new file mode 100644 index 00000000..415d82fc --- /dev/null +++ b/manualtests/adblock/adblockdialog/adblockdialog.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +include(../../manualtests.pri) +include(../../../autotests/modeltest/modeltest.pri) + +# Input +SOURCES += main_adblockdialog.cpp +HEADERS += diff --git a/manualtests/adblock/adblockdialog/main_adblockdialog.cpp b/manualtests/adblock/adblockdialog/main_adblockdialog.cpp new file mode 100644 index 00000000..ab233169 --- /dev/null +++ b/manualtests/adblock/adblockdialog/main_adblockdialog.cpp @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "adblockdialog.h" +#include "modeltest.h" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + AdBlockDialog dialog; + new ModelTest(dialog.treeView->model()); + dialog.show(); + return app.exec(); +} + diff --git a/manualtests/adblock/adblockmodel/.gitignore b/manualtests/adblock/adblockmodel/.gitignore new file mode 100644 index 00000000..c2bb9418 --- /dev/null +++ b/manualtests/adblock/adblockmodel/.gitignore @@ -0,0 +1 @@ +adblockmodel diff --git a/manualtests/adblock/adblockmodel/adblockmodel.pro b/manualtests/adblock/adblockmodel/adblockmodel.pro new file mode 100644 index 00000000..453974d1 --- /dev/null +++ b/manualtests/adblock/adblockmodel/adblockmodel.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +include(../../manualtests.pri) +include(../../../autotests/modeltest/modeltest.pri) + +# Input +SOURCES += main_adblockmodel.cpp +HEADERS += diff --git a/manualtests/adblock/adblockmodel/main_adblockmodel.cpp b/manualtests/adblock/adblockmodel/main_adblockmodel.cpp new file mode 100644 index 00000000..f3a50418 --- /dev/null +++ b/manualtests/adblock/adblockmodel/main_adblockmodel.cpp @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "adblockmodel.h" +#include "modeltest.h" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + QTreeView view; + AdBlockModel *model = new AdBlockModel; + new ModelTest(model); + view.setModel(model); + view.show(); + return app.exec(); +} + diff --git a/manualtests/manualtests.pro b/manualtests/manualtests.pro index 6e2ca9ad..52817cad 100644 --- a/manualtests/manualtests.pro +++ b/manualtests/manualtests.pro @@ -1,5 +1,6 @@ TEMPLATE = subdirs SUBDIRS = \ + adblock \ bookmarks \ downloadmanager \ history \ diff --git a/src/adblock/adblock.pri b/src/adblock/adblock.pri new file mode 100644 index 00000000..c373a684 --- /dev/null +++ b/src/adblock/adblock.pri @@ -0,0 +1,28 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD + +HEADERS += \ + adblockblockednetworkreply.h \ + adblockdialog.h \ + adblockmanager.h \ + adblockmodel.h \ + adblocknetwork.h \ + adblockpage.h \ + adblockrule.h \ + adblockschemeaccesshandler.h \ + adblocksubscription.h + +SOURCES += \ + adblockblockednetworkreply.cpp \ + adblockdialog.cpp \ + adblockmanager.cpp \ + adblockmodel.cpp \ + adblocknetwork.cpp \ + adblockpage.cpp \ + adblockrule.cpp \ + adblockschemeaccesshandler.cpp \ + adblocksubscription.cpp + +FORMS += \ + adblockdialog.ui + diff --git a/src/adblock/adblockblockednetworkreply.cpp b/src/adblock/adblockblockednetworkreply.cpp new file mode 100644 index 00000000..22bc323c --- /dev/null +++ b/src/adblock/adblockblockednetworkreply.cpp @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "adblockblockednetworkreply.h" + +#include "adblockrule.h" + +#include +#include + +AdBlockBlockedNetworkReply::AdBlockBlockedNetworkReply(const QNetworkRequest &request, const AdBlockRule *rule, QObject *parent) + : QNetworkReply(parent) +{ + setOperation(QNetworkAccessManager::GetOperation); + setRequest(request); + setUrl(request.url()); + setError(QNetworkReply::ContentAccessDenied, tr("Blocked by AdBlockRule: %1").arg(rule->filter())); + QTimer::singleShot(0, this, SLOT(delayedFinished())); +} + +qint64 AdBlockBlockedNetworkReply::readData(char *data, qint64 maxSize) +{ + Q_UNUSED(data); + Q_UNUSED(maxSize); + return -1; +} + +void AdBlockBlockedNetworkReply::delayedFinished() +{ + emit error(QNetworkReply::ContentAccessDenied); + emit finished(); +} + diff --git a/src/adblock/adblockblockednetworkreply.h b/src/adblock/adblockblockednetworkreply.h new file mode 100644 index 00000000..67695846 --- /dev/null +++ b/src/adblock/adblockblockednetworkreply.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKBLOCKEDNETWORKREPLY_H +#define ADBLOCKBLOCKEDNETWORKREPLY_H + +#include + +class AdBlockRule; +class AdBlockBlockedNetworkReply : public QNetworkReply +{ + Q_OBJECT + +public: + AdBlockBlockedNetworkReply(const QNetworkRequest &request, const AdBlockRule *rule, QObject *parent = 0); + void abort() {}; + +protected: + qint64 readData(char *data, qint64 maxSize); + +private slots: + void delayedFinished(); + +}; + +#endif // ADBLOCKBLOCKEDNETWORKREPLY_H + diff --git a/src/adblock/adblockdialog.cpp b/src/adblock/adblockdialog.cpp new file mode 100644 index 00000000..a82694c3 --- /dev/null +++ b/src/adblock/adblockdialog.cpp @@ -0,0 +1,150 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "adblockdialog.h" + +#include "adblockmodel.h" +#include "adblockmanager.h" +#include "adblocksubscription.h" +#include "treesortfilterproxymodel.h" + +#include +#include +#include + +#include + +AdBlockDialog::AdBlockDialog(QWidget *parent) + : QDialog(parent) +{ + setupUi(this); + m_adBlockModel = new AdBlockModel(this); + m_proxyModel = new TreeSortFilterProxyModel(this); + m_proxyModel->setSourceModel(m_adBlockModel); + treeView->setModel(m_proxyModel); + connect(search, SIGNAL(textChanged(QString)), + m_proxyModel, SLOT(setFilterFixedString(QString))); + + AdBlockManager *manager = AdBlockManager::instance(); + adblockGroupBox->setChecked(manager->isEnabled()); + connect(adblockGroupBox, SIGNAL(toggled(bool)), + AdBlockManager::instance(), SLOT(setEnabled(bool))); + + QMenu *menu = new QMenu(this); + connect(menu, SIGNAL(aboutToShow()), + this, SLOT(aboutToShowActionMenu())); + actionToolButton->setMenu(menu); + actionToolButton->setIcon(QIcon(QLatin1String(":128x128/run.png"))); + actionToolButton->setPopupMode(QToolButton::InstantPopup); + + AdBlockSubscription *subscription = manager->customRules(); + QModelIndex subscriptionIndex = m_adBlockModel->index(subscription); + treeView->expand(m_proxyModel->mapFromSource(subscriptionIndex)); +} + +void AdBlockDialog::aboutToShowActionMenu() +{ + QMenu *menu = actionToolButton->menu(); + menu->clear(); + + QAction *addRule = menu->addAction(tr("Add Custom Rule")); + connect(addRule, SIGNAL(triggered()), this, SLOT(addCustomRule())); + + QAction *learnRule = menu->addAction(tr("Learn more about writing rules...")); + connect(learnRule, SIGNAL(triggered()), this, SLOT(learnAboutWritingFilters())); + + menu->addSeparator(); + + QModelIndex idx = m_proxyModel->mapToSource(treeView->currentIndex()); + + QAction *updateSubscription = menu->addAction(tr("Update Subscription")); + connect(updateSubscription, SIGNAL(triggered()), this, SLOT(updateSubscription())); + if (!idx.isValid()) + updateSubscription->setEnabled(false); + + QAction *addSubscription = menu->addAction(tr("Browse Subscriptions...")); + connect(addSubscription, SIGNAL(triggered()), this, SLOT(browseSubscriptions())); + + menu->addSeparator(); + + QAction *removeSubscription = menu->addAction(tr("Remove Subscription")); + connect(removeSubscription, SIGNAL(triggered()), this, SLOT(removeSubscription())); + if (!idx.isValid()) + removeSubscription->setEnabled(false); +} + +void AdBlockDialog::addCustomRule(const QString &rule) +{ + AdBlockManager *manager = AdBlockManager::instance(); + AdBlockSubscription *subscription = manager->customRules(); + Q_ASSERT(subscription); + subscription->addRule(AdBlockRule(rule)); + // reset the model + qApp->processEvents(); + + QModelIndex parent = m_adBlockModel->index(subscription); + int x = m_adBlockModel->rowCount(parent); + QModelIndex ruleIndex = m_adBlockModel->index(x - 1, 0, parent); + treeView->expand(m_proxyModel->mapFromSource(parent)); + treeView->edit(m_proxyModel->mapFromSource(ruleIndex)); +} + +void AdBlockDialog::updateSubscription() +{ + QModelIndex idx = m_proxyModel->mapToSource(treeView->currentIndex()); + if (!idx.isValid()) + return; + if (idx.parent().isValid()) + idx = idx.parent(); + AdBlockSubscription *subscription = (AdBlockSubscription*)m_adBlockModel->subscription(idx); + subscription->updateNow(); +} + +void AdBlockDialog::browseSubscriptions() +{ + QUrl url(QLatin1String("http://adblockplus.org/en/subscriptions")); + QDesktopServices::openUrl(url); +} + +void AdBlockDialog::learnAboutWritingFilters() +{ + QUrl url(QLatin1String("http://adblockplus.org/en/filters")); + QDesktopServices::openUrl(url); +} + +void AdBlockDialog::removeSubscription() +{ + QModelIndex idx = m_proxyModel->mapToSource(treeView->currentIndex()); + if (!idx.isValid()) + return; + if (idx.parent().isValid()) + idx = idx.parent(); + AdBlockSubscription *subscription = (AdBlockSubscription*)m_adBlockModel->subscription(idx); + AdBlockManager::instance()->removeSubscription(subscription); +} + diff --git a/src/adblock/adblockdialog.h b/src/adblock/adblockdialog.h new file mode 100644 index 00000000..b428d2a0 --- /dev/null +++ b/src/adblock/adblockdialog.h @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKDIALOG_H +#define ADBLOCKDIALOG_H + +#include +#include "ui_adblockdialog.h" + +class AdBlockModel; +class TreeSortFilterProxyModel; +class AdBlockDialog : public QDialog, public Ui_AdBlockDialog +{ + Q_OBJECT + +public: + AdBlockDialog(QWidget *parent = 0); + +public slots: + void addCustomRule(const QString &rule = QString()); + +private slots: + void learnAboutWritingFilters(); + void aboutToShowActionMenu(); + void updateSubscription(); + void browseSubscriptions(); + void removeSubscription(); + +private: + AdBlockModel *m_adBlockModel; + TreeSortFilterProxyModel *m_proxyModel; + +}; + +#endif // ADBLOCKDIALOG_H + diff --git a/src/adblock/adblockdialog.ui b/src/adblock/adblockdialog.ui new file mode 100644 index 00000000..71c73be5 --- /dev/null +++ b/src/adblock/adblockdialog.ui @@ -0,0 +1,127 @@ + + + AdBlockDialog + + + + 0 + 0 + 627 + 639 + + + + AdBlock Configuration + + + + + + Enable AdBlock + + + true + + + + + + Qt::Horizontal + + + + 398 + 23 + + + + + + + + + + + + + + Action + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + SearchLineEdit + QLineEdit +
searchlineedit.h
+
+ + EditTreeView + QTreeView +
edittreeview.h
+
+
+ + + + buttonBox + accepted() + AdBlockDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AdBlockDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/adblock/adblockmanager.cpp b/src/adblock/adblockmanager.cpp new file mode 100644 index 00000000..857ffa2b --- /dev/null +++ b/src/adblock/adblockmanager.cpp @@ -0,0 +1,228 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "adblockmanager.h" + +#include "autosaver.h" +#include "adblockdialog.h" +#include "adblocknetwork.h" +#include "adblockpage.h" +#include "adblocksubscription.h" +#include "browserapplication.h" +#include "networkaccessmanager.h" + +#include +#include + +#include + +// #define ADBLOCKMANAGER_DEBUG + +AdBlockManager *AdBlockManager::s_adBlockManager = 0; + +AdBlockManager::AdBlockManager(QObject *parent) + : QObject(parent) + , m_loaded(false) + , m_enabled(false) + , m_saveTimer(new AutoSaver(this)) + , m_adBlockDialog(0) + , m_adBlockNetwork(0) +{ + connect(this, SIGNAL(rulesChanged()), + m_saveTimer, SLOT(changeOccurred())); +} + +AdBlockManager::~AdBlockManager() +{ + m_saveTimer->saveIfNeccessary(); +} + +AdBlockManager *AdBlockManager::instance() +{ + if (!s_adBlockManager) { + // Set a parent that will delete us before the application exits + s_adBlockManager = new AdBlockManager(BrowserApplication::networkAccessManager()); + } + return s_adBlockManager; +} + +bool AdBlockManager::isEnabled() const +{ + if (!m_loaded) { + AdBlockManager *that = const_cast(this); + that->load(); + } + return m_enabled; +} + +void AdBlockManager::setEnabled(bool enabled) +{ + if (isEnabled() == enabled) + return; + m_enabled = enabled; + emit rulesChanged(); +} + +AdBlockNetwork *AdBlockManager::network() +{ + if (!m_adBlockNetwork) + m_adBlockNetwork = new AdBlockNetwork(this); + return m_adBlockNetwork; +} + +AdBlockPage *AdBlockManager::page() +{ + if (!m_adBlockPage) + m_adBlockPage = new AdBlockPage(this); + return m_adBlockPage; +} + +static QUrl customSubscriptionLocation() +{ + QString fileName = BrowserApplication::dataFilePath(QLatin1String("adblock_subscription_custom")); + return QUrl::fromLocalFile(fileName); +} + +QUrl AdBlockManager::customSubscriptionUrl() +{ + QUrl location = customSubscriptionLocation(); + QString encodedUrl = QString::fromUtf8(location.toEncoded()); + QUrl url(QString(QLatin1String("abp:subscribe?location=%1&title=%2")) + .arg(encodedUrl) + .arg(tr("Custom Rules"))); + return url; +} + +AdBlockSubscription *AdBlockManager::customRules() +{ + QUrl location = customSubscriptionLocation(); + foreach (AdBlockSubscription *subscription, m_subscriptions) { + if (subscription->location() == location) + return subscription; + } + QUrl url = customSubscriptionUrl(); + AdBlockSubscription *customAdBlockSubscription = new AdBlockSubscription(url, this); + addSubscription(customAdBlockSubscription); + return customAdBlockSubscription; +} + +QList AdBlockManager::subscriptions() const +{ + if (!m_loaded) { + AdBlockManager *that = const_cast(this); + that->load(); + } + return m_subscriptions; +} + +void AdBlockManager::removeSubscription(AdBlockSubscription *subscription) +{ + if (!subscription) + return; +#if defined(ADBLOCKMANAGER_DEBUG) + qDebug() << "AdBlockManager::" << __FUNCTION__ << subscription->location(); +#endif + m_saveTimer->saveIfNeccessary(); + m_subscriptions.removeOne(subscription); + if (subscription->parent() == this) + subscription->deleteLater(); + emit rulesChanged(); +} + +void AdBlockManager::addSubscription(AdBlockSubscription *subscription) +{ + if (!subscription) + return; +#if defined(ADBLOCKMANAGER_DEBUG) + qDebug() << "AdBlockManager::" << __FUNCTION__ << subscription->location(); +#endif + m_subscriptions.append(subscription); + connect(subscription, SIGNAL(rulesChanged()), this, SIGNAL(rulesChanged())); + connect(subscription, SIGNAL(changed()), this, SIGNAL(rulesChanged())); + emit rulesChanged(); +} + +void AdBlockManager::save() +{ +#if defined(ADBLOCKMANAGER_DEBUG) + qDebug() << "AdBlockManager::" << __FUNCTION__ << m_loaded; +#endif + if (!m_loaded) + return; + + QSettings settings; + settings.beginGroup(QLatin1String("AdBlock")); + settings.setValue(QLatin1String("enabled"), m_enabled); + QStringList subscriptions; + foreach (AdBlockSubscription *subscription, m_subscriptions) { + if (!subscription) + continue; + subscriptions.append(QString::fromUtf8(subscription->url().toEncoded())); + subscription->saveRules(); + } + settings.setValue(QLatin1String("subscriptions"), subscriptions); +} + +void AdBlockManager::load() +{ +#if defined(ADBLOCKMANAGER_DEBUG) + qDebug() << "AdBlockManager::" << __FUNCTION__ << m_loaded; +#endif + + if (m_loaded) + return; + m_loaded = true; + + QSettings settings; + settings.beginGroup(QLatin1String("AdBlock")); + m_enabled = settings.value(QLatin1String("enabled"), m_enabled).toBool(); + + QStringList defaultSubscriptions; + defaultSubscriptions.append(QString::fromUtf8(customSubscriptionUrl().toEncoded())); + defaultSubscriptions.append(QLatin1String("abp:subscribe?location=http://adblockplus.mozdev.org/easylist/easylist.txt&title=EasyList")); + + QStringList subscriptions = settings.value(QLatin1String("subscriptions"), defaultSubscriptions).toStringList(); + foreach (const QString &subscription, subscriptions) { + QUrl url = QUrl::fromEncoded(subscription.toUtf8()); + AdBlockSubscription *adBlockSubscription = new AdBlockSubscription(url, this); + connect(adBlockSubscription, SIGNAL(rulesChanged()), this, SIGNAL(rulesChanged())); + connect(adBlockSubscription, SIGNAL(changed()), this, SIGNAL(rulesChanged())); + m_subscriptions.append(adBlockSubscription); + } +} + +AdBlockDialog *AdBlockManager::showDialog() +{ + if (!m_adBlockDialog) { + m_adBlockDialog = new AdBlockDialog(0); + m_adBlockDialog->setAttribute(Qt::WA_DeleteOnClose, true); + } + m_adBlockDialog->show(); + return m_adBlockDialog; +} + diff --git a/src/adblock/adblockmanager.h b/src/adblock/adblockmanager.h new file mode 100644 index 00000000..d16e3bf3 --- /dev/null +++ b/src/adblock/adblockmanager.h @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKMANAGER_H +#define ADBLOCKMANAGER_H + +#include + +#include + +class QUrl; +class AutoSaver; +class AdBlockDialog; +class AdBlockNetwork; +class AdBlockPage; +class AdBlockSubscription; +class AdBlockManager : public QObject +{ + Q_OBJECT + +signals: + void rulesChanged(); + +public: + AdBlockManager(QObject *parent = 0); + ~AdBlockManager(); + + void load(); + + static AdBlockManager *instance(); + bool isEnabled() const; + + QList subscriptions() const; + void removeSubscription(AdBlockSubscription *subscription); + void addSubscription(AdBlockSubscription *subscription); + + AdBlockNetwork *network(); + AdBlockPage *page(); + AdBlockSubscription *customRules(); + +public slots: + void setEnabled(bool enabled); + AdBlockDialog *showDialog(); + +private slots: + void save(); + +private: + static QUrl customSubscriptionUrl(); + static AdBlockManager *s_adBlockManager; + + bool m_loaded; + bool m_enabled; + AutoSaver *m_saveTimer; + QPointer m_adBlockDialog; + AdBlockNetwork *m_adBlockNetwork; + AdBlockPage *m_adBlockPage; + QList m_subscriptions; + +}; + +#endif // ADBLOCKMANAGER_H + diff --git a/src/adblock/adblockmodel.cpp b/src/adblock/adblockmodel.cpp new file mode 100644 index 00000000..8e548139 --- /dev/null +++ b/src/adblock/adblockmodel.cpp @@ -0,0 +1,267 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "adblockmodel.h" + +#include "adblockrule.h" +#include "adblocksubscription.h" +#include "adblockmanager.h" + +AdBlockModel::AdBlockModel(QObject *parent) + : QAbstractItemModel(parent) + , m_manager(AdBlockManager::instance()) +{ + connect(m_manager, SIGNAL(rulesChanged()), this, SLOT(rulesChanged())); +} + +void AdBlockModel::rulesChanged() +{ + reset(); +} + +const AdBlockRule AdBlockModel::rule(const QModelIndex &index) const +{ + const AdBlockSubscription *parent = static_cast(index.internalPointer()); + Q_ASSERT(parent); + return parent->allRules().at(index.row()); +} + +AdBlockSubscription *AdBlockModel::subscription(const QModelIndex &index) const +{ + const AdBlockSubscription *parent = static_cast(index.internalPointer()); + if (parent) + return 0; + int row = index.row(); + if (row < 0 || row >= m_manager->subscriptions().count()) + return 0; + return m_manager->subscriptions().at(row); +} + +QModelIndex AdBlockModel::index(AdBlockSubscription *subscription) +{ + int row = m_manager->subscriptions().indexOf(subscription); + if (row < 0 || row >= m_manager->subscriptions().count()) + return QModelIndex(); + return createIndex(row, 0, 0); +} + +QVariant AdBlockModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case 0: return tr("Rule"); + } + } + return QAbstractItemModel::headerData(section, orientation, role); +} + +QVariant AdBlockModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() + || index.model() != this + || index.column() != 0) + return QVariant(); + + switch (role) { + case Qt::EditRole: + case Qt::DisplayRole: + if (index.parent().isValid()) { + const AdBlockRule r = rule(index); + return r.filter(); + } else { + AdBlockSubscription *sub = subscription(index); + if (sub) + return sub->title(); + } + break; + case Qt::CheckStateRole: + if (index.parent().isValid()) { + const AdBlockRule r = rule(index); + return r.isEnabled() ? Qt::Checked : Qt::Unchecked; + } else { + AdBlockSubscription *sub = subscription(index); + if (sub) + return sub->isEnabled() ? Qt::Checked : Qt::Unchecked; + } + break; + default: + break; + } + + return QVariant(); +} + +int AdBlockModel::columnCount(const QModelIndex &parent) const +{ + return (parent.column() > 0) ? 0 : 1; +} + +int AdBlockModel::rowCount(const QModelIndex &parent) const +{ + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + return m_manager->subscriptions().count(); + + if (parent.internalPointer() != 0) + return 0; + + const AdBlockSubscription *parentNode = subscription(parent); + return parentNode ? parentNode->allRules().count() : 0; +} + +QModelIndex AdBlockModel::index(int row, int column, const QModelIndex &parent) const +{ + if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent)) + return QModelIndex(); + + if (!parent.isValid()) + return createIndex(row, column, (void*)0); + + // get the parent node + const AdBlockSubscription *parentNode = subscription(parent); + return createIndex(row, column, (void*)parentNode); +} + +QModelIndex AdBlockModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + AdBlockSubscription *parent = static_cast(index.internalPointer()); + if (!parent) + return QModelIndex(); + + int parentRow = m_manager->subscriptions().indexOf(parent); + return createIndex(parentRow, 0, 0); +} + +Qt::ItemFlags AdBlockModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::NoItemFlags; + + Qt::ItemFlags flags = Qt::ItemIsSelectable; + + if (index.parent().isValid()) { + flags |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable; + const AdBlockSubscription *parentNode = subscription(index.parent()); + if (parentNode && parentNode->isEnabled()) + flags |= Qt::ItemIsEnabled; + } else { + flags |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled; + } + + return flags; +} + +bool AdBlockModel::removeRows(int row, int count, const QModelIndex &parent) +{ + if (row < 0 || count <= 0 || row + count > rowCount(parent)) + return false; + + if (!parent.isValid()) { + disconnect(m_manager, SIGNAL(rulesChanged()), this, SLOT(rulesChanged())); + beginRemoveRows(QModelIndex(), row, row + count - 1); + for (int i = row + count - 1; i >= row; --i) { + AdBlockManager *manager = AdBlockManager::instance(); + manager->removeSubscription(manager->subscriptions().at(i)); + } + endRemoveRows(); + connect(m_manager, SIGNAL(rulesChanged()), this, SLOT(rulesChanged())); + return true; + } else { + AdBlockSubscription *sub = subscription(parent); + if (sub) { + disconnect(m_manager, SIGNAL(rulesChanged()), this, SLOT(rulesChanged())); + beginRemoveRows(parent, row, row + count - 1); + QList rules = sub->allRules(); + for (int i = row + count - 1; i >= row; --i) + sub->removeRule(i); + endRemoveRows(); + connect(m_manager, SIGNAL(rulesChanged()), this, SLOT(rulesChanged())); + return true; + } + } + + return false; +} + +bool AdBlockModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() + || index.model() != this + || index.column() != 0 + || (flags(index) & Qt::ItemIsEditable) == 0) + return false; + switch (role) { + case Qt::EditRole: + case Qt::DisplayRole: + if (index.parent().isValid()) { + AdBlockSubscription *sub = subscription(index.parent()); + if (sub) { + AdBlockRule r = rule(index); + r.setFilter(value.toString()); + sub->replaceRule(r, index.row()); + } + } else { + AdBlockSubscription *sub = subscription(index); + if (sub) + sub->setTitle(value.toString()); + } + break; + case Qt::CheckStateRole: + if (index.parent().isValid()) { + AdBlockSubscription *sub = subscription(index.parent()); + if (sub) { + AdBlockRule r = rule(index); + r.setEnabled(value == Qt::Checked); + sub->replaceRule(r, index.row()); + } + } else { + AdBlockSubscription *sub = subscription(index); + if (sub) + sub->setEnabled(value == Qt::Checked); + } + break; + default: + break; + } + return false; +} + +bool AdBlockModel::hasChildren(const QModelIndex &parent) const +{ + if (!parent.isValid()) + return true; + if (parent.internalPointer() == 0) + return true; + return false; +} + diff --git a/src/adblock/adblockmodel.h b/src/adblock/adblockmodel.h new file mode 100644 index 00000000..36066211 --- /dev/null +++ b/src/adblock/adblockmodel.h @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKMODEL_H +#define ADBLOCKMODEL_H + +#include + +class AdBlockRule; +class AdBlockSubscription; +class AdBlockManager; +class AdBlockModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + AdBlockModel(QObject *parent = 0); + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + bool hasChildren(const QModelIndex &parent = QModelIndex()) const; + + const AdBlockRule rule(const QModelIndex &index) const; + AdBlockSubscription *subscription(const QModelIndex &index) const; + QModelIndex index(AdBlockSubscription *subscription); + +private slots: + void rulesChanged(); + +private: + AdBlockManager *m_manager; +}; + +#endif // ADBLOCKMODEL_H + diff --git a/src/adblock/adblocknetwork.cpp b/src/adblock/adblocknetwork.cpp new file mode 100644 index 00000000..e811a406 --- /dev/null +++ b/src/adblock/adblocknetwork.cpp @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "adblocknetwork.h" + +#include "adblockblockednetworkreply.h" +#include "adblockmanager.h" +#include "adblocksubscription.h" + +#include + +// #define ADBLOCKNETWORK_DEBUG + +AdBlockNetwork::AdBlockNetwork(QObject *parent) + : QObject(parent) +{ +} + +QNetworkReply *AdBlockNetwork::block(const QNetworkRequest &request) +{ + QUrl url = request.url(); + + if (url.scheme() == QLatin1String("data")) + return 0; + + AdBlockManager *manager = AdBlockManager::instance(); + if (!manager->isEnabled()) + return 0; + + QString urlString = QString::fromUtf8(url.toEncoded()); + const AdBlockRule *blockedRule = 0; + const AdBlockSubscription *blockingSubscription = 0; + + QList subscriptions = manager->subscriptions(); + foreach (AdBlockSubscription *subscription, subscriptions) { + if (subscription->allow(urlString)) + return 0; + + if (const AdBlockRule *rule = subscription->block(urlString)) { + blockedRule = rule; + blockingSubscription = subscription; + break; + } + } + + if (blockedRule) { +#if defined(ADBLOCKNETWORK_DEBUG) + qDebug() << "AdBlockNetwork::" << __FUNCTION__ << "rule:" << blockedRule->filter() << "subscription:" << blockingSubscription->title() << url; +#endif + AdBlockBlockedNetworkReply *reply = new AdBlockBlockedNetworkReply(request, blockedRule, this); + return reply; + } + return 0; +} + diff --git a/src/adblock/adblocknetwork.h b/src/adblock/adblocknetwork.h new file mode 100644 index 00000000..7616a5ae --- /dev/null +++ b/src/adblock/adblocknetwork.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKNETWORK_H +#define ADBLOCKNETWORK_H + +#include + +class QNetworkRequest; +class QNetworkReply; +class AdBlockNetwork : public QObject +{ + Q_OBJECT + +public: + AdBlockNetwork(QObject *parent = 0); + + QNetworkReply *block(const QNetworkRequest &request); + +}; + +#endif // ADBLOCKNETWORK_H + diff --git a/src/adblock/adblockpage.cpp b/src/adblock/adblockpage.cpp new file mode 100644 index 00000000..e4566ba0 --- /dev/null +++ b/src/adblock/adblockpage.cpp @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "adblockpage.h" + +#include "adblockmanager.h" +#include "adblocksubscription.h" +#include "adblockrule.h" + +#if QT_VERSION >= 0x040600 +#include +#endif +#include +#include + +#include + +// #define ADBLOCKPAGE_DEBUG + +AdBlockPage::AdBlockPage(QObject *parent) + : QObject(parent) +{ +} + +void AdBlockPage::checkRule(const AdBlockRule *rule, QWebPage *page, const QString &host) +{ + if (!rule->isEnabled()) + return; + + QString filter = rule->filter(); + int offset = filter.indexOf(QLatin1String("##")); + if (offset == -1) + return; + + QString selectorQuery; + if (offset > 0) { + QString domainRules = filter.mid(0, offset); + selectorQuery = filter.mid(offset + 2); + QStringList domains = domainRules.split(QLatin1Char(',')); + + bool match = false; + foreach (const QString &domain, domains) { + bool reverse = (domain[0] == QLatin1Char('~')); + if (reverse) { + QString xdomain = domain.mid(1); + if (host.endsWith(xdomain)) + return; + match = true; + } + if (host.endsWith(domain)) + match = true; + } + if (!match) + return; + } + + if (offset == 0) + selectorQuery = filter.mid(2); + + Q_UNUSED(page); +#if QT_VERSION >= 0x040600 + QWebElement document = page->mainFrame()->documentElement(); + QList elements = document.findAll(selectorQuery); +#if defined(ADBLOCKPAGE_DEBUG) + if (elements.count() != 0) + qDebug() << "AdBlockPage::" << __FUNCTION__ << "blocking" << elements.count() << "items" << selectorQuery << elements.count() << "rule:" << rule->filter(); +#endif + foreach (QWebElement element, elements) { + element.setStyleProperty(QLatin1String("visibility"), QLatin1String("hidden")); + element.removeFromDocument(); + } + +#endif +} + +void AdBlockPage::applyRulesToPage(QWebPage *page) +{ + if (!page || !page->mainFrame()) + return; +#if QT_VERSION >= 0x040600 + QString host = page->mainFrame()->url().host(); + QList subscriptions = AdBlockManager::instance()->subscriptions(); + foreach (AdBlockSubscription *subscription, subscriptions) { + QList rules = subscription->pageRules(); + foreach (const AdBlockRule *rule, rules) { + checkRule(rule, page, host); + } + } +#endif +} + diff --git a/src/adblock/adblockpage.h b/src/adblock/adblockpage.h new file mode 100644 index 00000000..a1f3b0d2 --- /dev/null +++ b/src/adblock/adblockpage.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKPAGE_H +#define ADBLOCKPAGE_H + +#include + +class AdBlockRule; +class QWebPage; +class AdBlockPage : public QObject +{ + Q_OBJECT + +public: + AdBlockPage(QObject *parent = 0); + + void applyRulesToPage(QWebPage *page); + +private: + void checkRule(const AdBlockRule *rule, QWebPage *page, const QString &host); +}; + +#endif // ADBLOCKPAGE_H + diff --git a/src/adblock/adblockrule.cpp b/src/adblock/adblockrule.cpp new file mode 100644 index 00000000..05da3313 --- /dev/null +++ b/src/adblock/adblockrule.cpp @@ -0,0 +1,216 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2009, Zsombor Gegesy + * + * 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) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "adblockrule.h" + +#include "adblocksubscription.h" + +#include +#include +#include + +// #define ADBLOCKRULE_DEBUG + +AdBlockRule::AdBlockRule(const QString &filter) +{ + setFilter(filter); +} + +QString AdBlockRule::filter() const +{ + return m_filter; +} + +void AdBlockRule::setFilter(const QString &filter) +{ + m_filter = filter; + + m_cssRule = false; + m_enabled = true; + m_exception = false; + bool regExpRule = false; + + if (filter.startsWith(QLatin1String("!")) + || filter.trimmed().isEmpty()) + m_enabled = false; + + if (filter.contains(QLatin1String("##"))) + m_cssRule = true; + + QString parsedLine = filter; + if (parsedLine.startsWith(QLatin1String("@@"))) { + m_exception = true; + parsedLine = parsedLine.mid(2); + } + if (parsedLine.startsWith(QLatin1Char('/'))) { + if (parsedLine.endsWith(QLatin1Char('/'))) { + parsedLine = parsedLine.mid(1); + parsedLine = parsedLine.left(parsedLine.size() - 1); + regExpRule = true; + } + } + int options = parsedLine.indexOf(QLatin1String("$"), 0); + if (options >= 0) { + m_options = parsedLine.mid(options + 1).split(QLatin1Char(',')); + parsedLine = parsedLine.left(options); + } + + setPattern(parsedLine, regExpRule); + + if (m_options.contains(QLatin1String("match-case"))) { + m_regExp.setCaseSensitivity(Qt::CaseSensitive); + m_options.removeOne(QLatin1String("match-case")); + } +} + +bool AdBlockRule::networkMatch(const QString &encodedUrl) const +{ + if (m_cssRule) { +#if defined(ADBLOCKRULE_DEBUG) + qDebug() << "AdBlockRule::" << __FUNCTION__ << "m_cssRule" << m_cssRule; +#endif + return false; + } + + if (!m_enabled) { +#if defined(ADBLOCKRULE_DEBUG) + qDebug() << "AdBlockRule::" << __FUNCTION__ << "is not enabled"; +#endif + return false; + } + + bool matched = m_regExp.indexIn(encodedUrl) != -1; + + if (matched + && !m_options.isEmpty()) { + + // we only support domain right now + if (m_options.count() == 1) { + foreach (const QString &option, m_options) { + if (option.startsWith(QLatin1String("domain="))) { + QUrl url = QUrl::fromEncoded(encodedUrl.toUtf8()); + QString host = url.host(); + QStringList domainOptions = option.mid(7).split(QLatin1Char('|')); + foreach (QString domainOption, domainOptions) { + bool negate = domainOption.at(0) == QLatin1Char('~'); + if (negate) + domainOption = domainOption.mid(1); + bool hostMatched = domainOption == host; + if (hostMatched && !negate) + return true; + if (!hostMatched && negate) + return true; + } + } + } + } + +//#if defined(ADBLOCKRULE_DEBUG) + qDebug() << "AdBlockRule::" << __FUNCTION__ << "options are currently not supported" << m_options; +//#endif + return false; + } +#if defined(ADBLOCKRULE_DEBUG) + //qDebug() << "AdBlockRule::" << __FUNCTION__ << encodedUrl << "MATCHED" << matched << filter(); +#endif + + return matched; +} + +bool AdBlockRule::isException() const +{ + return m_exception; +} + +void AdBlockRule::setException(bool exception) +{ + m_exception = exception; +} + +bool AdBlockRule::isEnabled() const +{ + return m_enabled; +} + +void AdBlockRule::setEnabled(bool enabled) +{ + m_enabled = enabled; + if (!enabled) { + m_filter = QLatin1String("!") + m_filter; + } else { + m_filter = m_filter.mid(1); + } +} + +QString AdBlockRule::regExpPattern() const +{ + return m_regExp.pattern(); +} + +static QString convertPatternToRegExp(const QString &wildcardPattern) { + QString pattern = wildcardPattern; + return pattern.replace(QRegExp(QLatin1String("\\*+")), QLatin1String("*")) // remove multiple wildcards + .replace(QRegExp(QLatin1String("\\^\\|$")), QLatin1String("^")) // remove anchors following separator placeholder + .replace(QRegExp(QLatin1String("^(\\*)")), QLatin1String("")) // remove leading wildcards + .replace(QRegExp(QLatin1String("(\\*)$")), QLatin1String("")) // remove trailing wildcards + .replace(QRegExp(QLatin1String("(\\W)")), QLatin1String("\\\\1")) // escape special symbols + .replace(QRegExp(QLatin1String("^\\\\\\|\\\\\\|")), + QLatin1String("^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?")) // process extended anchor at expression start + .replace(QRegExp(QLatin1String("\\\\\\^")), + QLatin1String("(?:[^\\w\\d\\-.%]|$)")) // process separator placeholders + .replace(QRegExp(QLatin1String("^\\\\\\|")), QLatin1String("^")) // process anchor at expression start + .replace(QRegExp(QLatin1String("\\\\\\|$")), QLatin1String("$")) // process anchor at expression end + .replace(QRegExp(QLatin1String("\\\\\\*")), QLatin1String(".*")) // replace wildcards by .* + ; +} + +void AdBlockRule::setPattern(const QString &pattern, bool isRegExp) +{ + m_regExp = QRegExp(isRegExp ? pattern : convertPatternToRegExp(pattern), + Qt::CaseInsensitive, QRegExp::RegExp2); +} + diff --git a/src/adblock/adblockrule.h b/src/adblock/adblockrule.h new file mode 100644 index 00000000..98ff4ad9 --- /dev/null +++ b/src/adblock/adblockrule.h @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKRULE_H +#define ADBLOCKRULE_H + +#include + +class QUrl; +class QRegExp; +class AdBlockRule +{ + +public: + AdBlockRule(const QString &filter = QString()); + + QString filter() const; + void setFilter(const QString &filter); + + bool isCSSRule() const { return m_cssRule; } + bool networkMatch(const QString &encodedUrl) const; + + bool isException() const; + void setException(bool exception); + + bool isEnabled() const; + void setEnabled(bool enabled); + + QString regExpPattern() const; + void setPattern(const QString &pattern, bool isRegExp); + +private: + QString m_filter; + + bool m_cssRule; + bool m_exception; + bool m_enabled; + QRegExp m_regExp; + QStringList m_options; +}; + +#endif // ADBLOCKRULE_H + diff --git a/src/adblock/adblockschemeaccesshandler.cpp b/src/adblock/adblockschemeaccesshandler.cpp new file mode 100644 index 00000000..6acecaf5 --- /dev/null +++ b/src/adblock/adblockschemeaccesshandler.cpp @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "adblockschemeaccesshandler.h" + +#include "adblockmanager.h" +#include "adblocksubscription.h" +#include "adblockdialog.h" + +#include +#include + +AdBlockSchemeAccessHandler::AdBlockSchemeAccessHandler(QObject *parent) + : SchemeAccessHandler(parent) +{ +} + +QNetworkReply *AdBlockSchemeAccessHandler::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) +{ + Q_UNUSED(outgoingData); + if (op != QNetworkAccessManager::GetOperation) + return 0; + + if (request.url().path() != QLatin1String("subscribe")) + return 0; + + AdBlockSubscription *subscription = new AdBlockSubscription(request.url(), AdBlockManager::instance()); + + QMessageBox::StandardButton result = QMessageBox::question(0 + , tr("Subscribe?") + , tr("Subscribe to this AdBlock subscription?\n%1").arg(subscription->title()) + , QMessageBox::Yes | QMessageBox::No); + if (result == QMessageBox::No) { + delete subscription; + } else { + AdBlockManager::instance()->addSubscription(subscription); + AdBlockDialog *dialog = AdBlockManager::instance()->showDialog(); + QAbstractItemModel *model = dialog->treeView->model(); + dialog->treeView->setCurrentIndex(model->index(model->rowCount() -1, 0)); + dialog->setFocus(); + } + return 0; +} + diff --git a/src/adblock/adblockschemeaccesshandler.h b/src/adblock/adblockschemeaccesshandler.h new file mode 100644 index 00000000..bcec735c --- /dev/null +++ b/src/adblock/adblockschemeaccesshandler.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKSCHEMEACCESSHANDLER_H +#define ADBLOCKSCHEMEACCESSHANDLER_H + +#include "schemeaccesshandler.h" + +class AdBlockSchemeAccessHandler : public SchemeAccessHandler +{ +public: + AdBlockSchemeAccessHandler(QObject *parent = 0); + + virtual QNetworkReply *createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData = 0); +}; + +#endif // ADBLOCKSCHEMEACCESSHANDLER_H diff --git a/src/adblock/adblocksubscription.cpp b/src/adblock/adblocksubscription.cpp new file mode 100644 index 00000000..d28c590d --- /dev/null +++ b/src/adblock/adblocksubscription.cpp @@ -0,0 +1,375 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "adblocksubscription.h" + +#include "browserapplication.h" +#include "networkaccessmanager.h" + +#include +#include +#include +#include +#include + +// #define ADBLOCKSUBSCRIPTION_DEBUG + +AdBlockSubscription::AdBlockSubscription(const QUrl &url, QObject *parent) + : QObject(parent) + , m_url(url.toEncoded()) + , m_enabled(false) + , m_downloading(0) +{ + parseUrl(url); +} + +void AdBlockSubscription::parseUrl(const QUrl &url) +{ +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << url; +#endif + if (url.scheme() != QLatin1String("abp")) + return; + if (url.path() != QLatin1String("subscribe")) + return; + + m_title = QUrl::fromPercentEncoding(url.encodedQueryItemValue("title")); + m_enabled = QUrl::fromPercentEncoding(url.encodedQueryItemValue("enabled")) != QLatin1String("false"); + m_location = QUrl::fromPercentEncoding(url.encodedQueryItemValue("location")).toUtf8(); + QByteArray lastUpdateByteArray = url.encodedQueryItemValue("lastUpdate"); + QString lastUpdateString = QUrl::fromPercentEncoding(lastUpdateByteArray); + m_lastUpdate = QDateTime::fromString(lastUpdateString, Qt::ISODate); + loadRules(); +} + +QUrl AdBlockSubscription::url() const +{ + QUrl url; + url.setScheme(QLatin1String("abp")); + url.setPath(QLatin1String("subscribe")); + + typedef QPair Query; + QList queryItems; + + queryItems.append(Query(QLatin1String("location"), QString::fromUtf8(m_location))); + queryItems.append(Query(QLatin1String("title"), m_title)); + if (!m_enabled) + queryItems.append(Query(QLatin1String("enabled"), QLatin1String("false"))); + if (m_lastUpdate.isValid()) + queryItems.append(Query(QLatin1String("lastUpdate"), m_lastUpdate.toString(Qt::ISODate))); + url.setQueryItems(queryItems); + return url; +} + +bool AdBlockSubscription::isEnabled() const +{ + return m_enabled; +} + +void AdBlockSubscription::setEnabled(bool enabled) +{ + if (m_enabled == enabled) + return; + m_enabled = enabled; + populateCache(); + emit changed(); +} + +QString AdBlockSubscription::title() const +{ + return m_title; +} + +void AdBlockSubscription::setTitle(const QString &title) +{ + if (m_title == title) + return; + m_title = title; + emit changed(); +} + +QUrl AdBlockSubscription::location() const +{ + return QUrl::fromEncoded(m_location); +} + +void AdBlockSubscription::setLocation(const QUrl &url) +{ + if (url == location()) + return; + m_location = url.toEncoded(); + m_lastUpdate = QDateTime(); + emit changed(); +} + +QDateTime AdBlockSubscription::lastUpdate() const +{ + return m_lastUpdate; +} + +QString AdBlockSubscription::rulesFileName() const +{ + if (location().scheme() == QLatin1String("file")) + return location().toLocalFile(); + + if (m_location.isEmpty()) + return QString(); + + QByteArray sha1 = QCryptographicHash::hash(m_location, QCryptographicHash::Sha1).toHex(); + QString fileName = BrowserApplication::dataFilePath(QString(QLatin1String("adblock_subscription_%1")).arg(QLatin1String(sha1))); + return fileName; +} + +void AdBlockSubscription::loadRules() +{ + QString fileName = rulesFileName(); +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << fileName; +#endif + QFile file(fileName); + if (file.exists()) { + if (!file.open(QFile::ReadOnly)) { + qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "Unable to open adblock file for reading" << fileName; + } else { + QTextStream textStream(&file); + QString header = textStream.readLine(1024); + if (!header.startsWith(QLatin1String("[Adblock"))) { + qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "adblock file does not start with [Adblock" << fileName << "Header:" << header; + file.close(); + file.remove(); + m_lastUpdate = QDateTime(); + } else { + m_rules.clear(); + while (!textStream.atEnd()) { + QString line = textStream.readLine(); + m_rules.append(AdBlockRule(line)); + } + populateCache(); + emit rulesChanged(); + } + } + } + + if (!m_lastUpdate.isValid() + || m_lastUpdate.addDays(7) < QDateTime::currentDateTime()) { + updateNow(); + } +} + +void AdBlockSubscription::updateNow() +{ +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << location(); +#endif + if (m_downloading) { +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << "already downloading, stopping"; +#endif + return; + } + + if (!location().isValid()) { +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << location() << "isn't valid"; +#endif + return; + } + + if (location().scheme() == QLatin1String("file")) { +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << "local file, not downloading"; +#endif + m_lastUpdate = QDateTime::currentDateTime(); + loadRules(); + emit changed(); + return; + } + + QNetworkRequest request(location()); + QNetworkReply *reply = BrowserApplication::networkAccessManager()->get(request); + m_downloading = reply; + connect(reply, SIGNAL(finished()), this, SLOT(rulesDownloaded())); +} + +void AdBlockSubscription::rulesDownloaded() +{ +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << rulesFileName(); +#endif + QNetworkReply *reply = qobject_cast(sender()); + if (!reply) { +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << "no reply?"; +#endif + return; + } + + QByteArray response = reply->readAll(); + QUrl redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + reply->close(); + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "error" << reply->errorString(); + return; + } + + if (redirect.isValid()) { +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << "redirect to:" << redirect; +#endif + QNetworkRequest request(redirect); + m_downloading = BrowserApplication::networkAccessManager()->get(request); + connect(m_downloading, SIGNAL(finished()), this, SLOT(rulesDownloaded())); + return; + } + + if (response.isEmpty()) { + qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "empty response"; + return; + } + + QString fileName = rulesFileName(); + QFile file(fileName); + if (!file.open(QFile::ReadWrite)) { + qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "Unable to open adblock file for writing:" << fileName; + return; + } + file.write(response); + m_lastUpdate = QDateTime::currentDateTime(); + loadRules(); + emit changed(); + m_downloading = 0; +} + +void AdBlockSubscription::saveRules() +{ +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << rulesFileName() << m_rules.count(); +#endif + QString fileName = rulesFileName(); + if (fileName.isEmpty()) + return; + + QFile file(fileName); + if (!file.open(QFile::ReadWrite | QIODevice::Truncate)) { + qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "Unable to open adblock file for writing:" << fileName; + return; + } + + QTextStream textStream(&file); + textStream << "[Adblock Plus 0.7.1]" << endl; + foreach (const AdBlockRule &rule, m_rules) + textStream << rule.filter() << endl; +} + +QList AdBlockSubscription::pageRules() const +{ + return m_pageRules; +} + +const AdBlockRule *AdBlockSubscription::allow(const QString &urlString) const +{ + foreach (const AdBlockRule *rule, m_networkExceptionRules) { + if (rule->networkMatch(urlString)) + return rule; + } + return 0; +} + +const AdBlockRule *AdBlockSubscription::block(const QString &urlString) const +{ + foreach (const AdBlockRule *rule, m_networkBlockRules) { + if (rule->networkMatch(urlString)) + return rule; + } + return 0; +} + +QList AdBlockSubscription::allRules() const +{ + return m_rules; +} + +void AdBlockSubscription::addRule(const AdBlockRule &rule) +{ +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << rule.filter(); +#endif + m_rules.append(rule); + populateCache(); + emit rulesChanged(); +} + +void AdBlockSubscription::removeRule(int offset) +{ +#if defined(ADBLOCKSUBSCRIPTION_DEBUG) + qDebug() << "AdBlockSubscription::" << __FUNCTION__ << offset << m_rules.count(); +#endif + if (offset < 0 || offset >= m_rules.count()) + return; + m_rules.removeAt(offset); + populateCache(); + emit rulesChanged(); +} + +void AdBlockSubscription::replaceRule(const AdBlockRule &rule, int offset) +{ + if (offset < 0 || offset >= m_rules.count()) + return; + m_rules[offset] = rule; + populateCache(); + emit rulesChanged(); +} + +void AdBlockSubscription::populateCache() +{ + m_networkExceptionRules.clear(); + m_networkBlockRules.clear(); + m_pageRules.clear(); + if (!isEnabled()) + return; + + for (int i = 0; i < m_rules.count(); ++i) { + const AdBlockRule *rule = &m_rules.at(i); + if (!rule->isEnabled()) + continue; + + if (rule->isCSSRule()) { + m_pageRules.append(rule); + continue; + } + + if (rule->isException()) { + m_networkExceptionRules.append(rule); + } else { + m_networkBlockRules.append(rule); + } + } +} + diff --git a/src/adblock/adblocksubscription.h b/src/adblock/adblocksubscription.h new file mode 100644 index 00000000..43639a47 --- /dev/null +++ b/src/adblock/adblocksubscription.h @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2009, Benjamin C. Meyer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Benjamin Meyer nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ADBLOCKSUBSCRIPTION_H +#define ADBLOCKSUBSCRIPTION_H + +#include + +#include "adblockrule.h" + +#include +#include + +class QNetworkReply; +class QUrl; +class AdBlockSubscription : public QObject +{ + Q_OBJECT + +signals: + void changed(); + void rulesChanged(); + +public: + AdBlockSubscription(const QUrl &url, QObject *parent = 0); + QUrl url() const; + + bool isEnabled() const; + void setEnabled(bool enabled); + + QString title() const; + void setTitle(const QString &title); + + QUrl location() const; + void setLocation(const QUrl &url); + + void updateNow(); + QDateTime lastUpdate() const; + + void saveRules(); + + const AdBlockRule *allow(const QString &urlString) const; + const AdBlockRule *block(const QString &urlString) const; + QList pageRules() const; + + QList allRules() const; + void addRule(const AdBlockRule &rule); + void removeRule(int offset); + void replaceRule(const AdBlockRule &rule, int offset); + +private slots: + void rulesDownloaded(); + +private: + void populateCache(); + QString rulesFileName() const; + void parseUrl(const QUrl &url); + void loadRules(); + + QByteArray m_url; + + QString m_title; + QByteArray m_location; + QDateTime m_lastUpdate; + bool m_enabled; + + QNetworkReply *m_downloading; + QList m_rules; + + // sorted list + QList m_networkExceptionRules; + QList m_networkBlockRules; + QList m_pageRules; +}; + +#endif // ADBLOCKSUBSCRIPTION_H + diff --git a/src/browsermainwindow.cpp b/src/browsermainwindow.cpp index a07a4161..b170b027 100644 --- a/src/browsermainwindow.cpp +++ b/src/browsermainwindow.cpp @@ -65,6 +65,7 @@ #include "browsermainwindow.h" #include "aboutdialog.h" +#include "adblockmanager.h" #include "addbookmarkdialog.h" #include "autosaver.h" #include "bookmarksdialog.h" @@ -801,6 +802,11 @@ void BrowserMainWindow::setupMenu() this, SLOT(showSearchDialog())); m_toolsMenu->addAction(m_toolsSearchManagerAction); + m_adBlockDialogAction = new QAction(m_toolsMenu); + connect(m_adBlockDialogAction, SIGNAL(triggered()), + AdBlockManager::instance(), SLOT(showDialog())); + m_toolsMenu->addAction(m_adBlockDialogAction); + m_toolsMenu->addSeparator(); m_toolsPreferencesAction = new QAction(m_editMenu); connect(m_toolsPreferencesAction, SIGNAL(triggered()), @@ -956,6 +962,7 @@ void BrowserMainWindow::retranslate() m_toolsPreferencesAction->setText(tr("Options...")); m_toolsPreferencesAction->setShortcut(tr("Ctrl+,")); m_toolsSearchManagerAction->setText(tr("Configure Search Engines...")); + m_adBlockDialogAction->setText(tr("&Ad Block...")); m_helpMenu->setTitle(tr("&Help")); m_helpChangeLanguageAction->setText(tr("Switch application language ")); diff --git a/src/browsermainwindow.h b/src/browsermainwindow.h index 4c0b75d8..eed35813 100644 --- a/src/browsermainwindow.h +++ b/src/browsermainwindow.h @@ -235,6 +235,7 @@ private slots: QAction *m_toolsEnableInspectorAction; QAction *m_toolsPreferencesAction; QAction *m_toolsSearchManagerAction; + QAction *m_adBlockDialogAction; QMenu *m_helpMenu; QAction *m_helpChangeLanguageAction; diff --git a/src/data/128x128/run.license b/src/data/128x128/run.license new file mode 100644 index 00000000..7925f44d --- /dev/null +++ b/src/data/128x128/run.license @@ -0,0 +1,2 @@ +run.png was created by Everaldo Coelho and YellowIcon from the crystal icon set +Crystal icons were posted by the author as LGPL on kde-look under the name (Crystal_Clear_action_run.png) diff --git a/src/data/128x128/run.png b/src/data/128x128/run.png new file mode 100644 index 0000000000000000000000000000000000000000..e32edb74d0d6eeceda4bcc0ea93da19cbee8f0de GIT binary patch literal 16493 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 128x128/arora.png + 128x128/run.png arora.svg defaultbookmarks.xbel fetchLinks.js diff --git a/src/network/networkaccessmanager.cpp b/src/network/networkaccessmanager.cpp index 46a04c21..e3c46f1d 100644 --- a/src/network/networkaccessmanager.cpp +++ b/src/network/networkaccessmanager.cpp @@ -62,6 +62,9 @@ #include "networkaccessmanager.h" +#include "adblockmanager.h" +#include "adblocknetwork.h" +#include "adblockschemeaccesshandler.h" #include "acceptlanguagedialog.h" #include "browserapplication.h" #include "browsermainwindow.h" @@ -86,6 +89,7 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent) + , m_adblockNetwork(0) { connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), SLOT(authenticationRequired(QNetworkReply*, QAuthenticator*))); @@ -101,6 +105,7 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent) // Register custom scheme handlers setSchemeHandler(QLatin1String("file"), new FileAccessHandler(this)); + setSchemeHandler(QLatin1String("abp"), new AdBlockSchemeAccessHandler(this)); setCookieJar(new CookieJar); } @@ -342,6 +347,15 @@ QNetworkReply *NetworkAccessManager::createRequest(QNetworkAccessManager::Operat if (!m_acceptLanguage.isEmpty()) req.setRawHeader("Accept-Language", m_acceptLanguage); + // Adblock + if (op == QNetworkAccessManager::GetOperation) { + if (!m_adblockNetwork) + m_adblockNetwork = AdBlockManager::instance()->network(); + reply = m_adblockNetwork->block(req); + if (reply) + return reply; + } + reply = QNetworkAccessManager::createRequest(op, req, outgoingData); emit requestCreated(op, req, reply); return reply; diff --git a/src/network/networkaccessmanager.h b/src/network/networkaccessmanager.h index 295625e3..5ab63c2f 100644 --- a/src/network/networkaccessmanager.h +++ b/src/network/networkaccessmanager.h @@ -69,6 +69,7 @@ class SchemeAccessHandler; +class AdBlockNetwork; class NetworkAccessManager : public QNetworkAccessManager { Q_OBJECT @@ -103,6 +104,7 @@ private slots: QHash m_schemeHandlers; QNetworkCookieJar *m_privateCookieJar; + AdBlockNetwork *m_adblockNetwork; }; #endif // NETWORKACCESSMANAGER_H diff --git a/src/src.pri b/src/src.pri index 7318349e..4a0e5587 100644 --- a/src/src.pri +++ b/src/src.pri @@ -91,6 +91,7 @@ SOURCES += \ webview.cpp \ webviewsearch.cpp +include(adblock/adblock.pri) include(bookmarks/bookmarks.pri) include(history/history.pri) include(locationbar/locationbar.pri) diff --git a/src/webpage.cpp b/src/webpage.cpp index 9b1c7786..cdd63f26 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -312,6 +312,9 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply) QUrl replyUrl = reply->url(); + if (replyUrl.scheme() == QLatin1String("abp")) + return; + switch (reply->error()) { case QNetworkReply::NoError: if (reply->header(QNetworkRequest::ContentTypeHeader).isValid()) { diff --git a/src/webview.cpp b/src/webview.cpp index 159793d9..ac15e251 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -64,6 +64,9 @@ #include "webview.h" +#include "adblockdialog.h" +#include "adblockmanager.h" +#include "adblockpage.h" #include "addbookmarkdialog.h" #include "bookmarksmanager.h" #include "browserapplication.h" @@ -223,6 +226,8 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) menu->addAction(tr("&Save Image"), this, SLOT(downloadImageToDisk())); menu->addAction(tr("&Copy Image"), this, SLOT(copyImageToClipboard())); menu->addAction(tr("C&opy Image Location"), this, SLOT(copyImageLocationToClipboard()))->setData(r.imageUrl().toString()); + menu->addSeparator(); + menu->addAction(tr("Block Image"), this, SLOT(blockImage()))->setData(r.imageUrl().toString()); } if (!page()->selectedText().isEmpty()) { @@ -360,6 +365,15 @@ void WebView::copyImageLocationToClipboard() } } +void WebView::blockImage() +{ + if (QAction *action = qobject_cast(sender())) { + QString imageUrl = action->data().toString(); + AdBlockDialog *dialog = AdBlockManager::instance()->showDialog(); + dialog->addCustomRule(imageUrl); + } +} + void WebView::bookmarkLink() { if (QAction *action = qobject_cast(sender())) { @@ -542,6 +556,7 @@ void WebView::loadFinished() << "Url:" << url(); } m_progress = 0; + AdBlockManager::instance()->page()->applyRulesToPage(page()); } void WebView::loadUrl(const QUrl &url, const QString &title) diff --git a/src/webview.h b/src/webview.h index ef892cb8..60f0cd38 100644 --- a/src/webview.h +++ b/src/webview.h @@ -137,6 +137,7 @@ private slots: void downloadImageToDisk(); void copyImageToClipboard(); void copyImageLocationToClipboard(); + void blockImage(); void bookmarkLink(); void searchRequested(QAction *action); #if QT_VERSION >= 0x040600 || defined(WEBKIT_TRUNK)