Add new adblock sources. Taken from Qupzilla. Will be mentioned in changelog and readme.

This commit is contained in:
Martin Rotter 2017-07-19 11:15:32 +02:00
parent 7e6f4ed446
commit e6080a5289
27 changed files with 4052 additions and 2 deletions

View file

@ -1,3 +1,9 @@
3.4.2
—————
Added:
▪ New Ad-Block feature for internal web browser. Based on Qt examples and QupZilla. Original license GNU GPLv3 is retained.
3.4.1
—————

View file

@ -333,8 +333,8 @@ HEADERS += src/core/feeddownloader.h \
src/core/messagesmodelcache.h \
src/core/messagesmodelsqllayer.h \
src/gui/treeviewcolumnsmenu.h \
src/services/abstract/labelsrootitem.h \
src/services/abstract/label.h
src/services/abstract/labelsrootitem.h \
src/services/abstract/label.h
SOURCES += src/core/feeddownloader.cpp \
src/core/feedsmodel.cpp \
@ -503,6 +503,35 @@ equals(USE_WEBENGINE, true) {
src/gui/discoverfeedsbutton.cpp \
src/network-web/googlesuggest.cpp \
src/network-web/webpage.cpp
# Add Ad-Block sources.
HEADERS += src/network-web/adblock/adblockaddsubscriptiondialog.h \
src/network-web/adblock/adblockdialog.h \
src/network-web/adblock/adblockicon.h \
src/network-web/adblock/adblockmanager.h \
src/network-web/adblock/adblockmatcher.h \
src/network-web/adblock/adblockrule.h \
src/network-web/adblock/adblocksearchtree.h \
src/network-web/adblock/adblocksubscription.h \
src/network-web/adblock/adblocktreewidget.h \
src/network-web/adblock/adblockurlinterceptor.h \
src/network-web/urlinterceptor.h \
src/network-web/networkurlinterceptor.h
SOURCES += src/network-web/adblock/adblockaddsubscriptiondialog.cpp \
src/network-web/adblock/adblockdialog.cpp \
src/network-web/adblock/adblockicon.cpp \
src/network-web/adblock/adblockmanager.cpp \
src/network-web/adblock/adblockmatcher.cpp \
src/network-web/adblock/adblockrule.cpp \
src/network-web/adblock/adblocksearchtree.cpp \
src/network-web/adblock/adblocksubscription.cpp \
src/network-web/adblock/adblocktreewidget.cpp \
src/network-web/adblock/adblockurlinterceptor.cpp \
src/network-web/networkurlinterceptor.cpp
FORMS += src/network-web/adblock/adblockaddsubscriptiondialog.ui \
src/network-web/adblock/adblockdialog.ui
}
else {
HEADERS += src/gui/messagepreviewer.h \

View file

@ -0,0 +1,91 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "adblockaddsubscriptiondialog.h"
#include "ui_adblockaddsubscriptiondialog.h"
AdBlockAddSubscriptionDialog::AdBlockAddSubscriptionDialog(QWidget* parent)
: QDialog(parent)
, ui(new Ui::AdBlockAddSubscriptionDialog)
{
ui->setupUi(this);
m_knownSubscriptions << Subscription("EasyList (English)", ADBLOCK_EASYLIST_URL)
<< Subscription("BSI Lista Polska (Polish)", "http://www.bsi.info.pl/filtrABP.txt")
<< Subscription("Czech List (Czech)", "http://adblock.dajbych.net/adblock.txt")
<< Subscription("dutchblock (Dutch)", "http://groenewoudt.net/dutchblock/list.txt")
<< Subscription("Filtros Nauscopicos (Spanish)", "http://abp.mozilla-hispano.org/nauscopio/filtros.txt")
<< Subscription("IsraelList (Hebrew)", "http://secure.fanboy.co.nz/israelilist/IsraelList.txt")
<< Subscription("NLBlock (Dutch)", "http://www.verzijlbergh.com/adblock/nlblock.txt")
<< Subscription("Peter Lowe's list (English)", "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=adblockplus&mimetype=plaintext")
<< Subscription("PLgeneral (Polish)", "http://www.niecko.pl/adblock/adblock.txt")
<< Subscription("Schacks Adblock Plus liste (Danish)", "http://adblock.schack.dk/block.txt")
<< Subscription("Xfiles (Italian)", "http://mozilla.gfsolone.com/filtri.txt")
<< Subscription("EasyPrivacy (English)", "http://easylist-downloads.adblockplus.org/easyprivacy.txt")
<< Subscription("RU Adlist (Russian)", "https://easylist-downloads.adblockplus.org/advblock.txt")
<< Subscription("ABPindo (Indonesian)", "https://raw.githubusercontent.com/heradhis/indonesianadblockrules/master/subscriptions/abpindo.txt")
<< Subscription("Easylist China (Chinese)", "https://easylist-downloads.adblockplus.org/easylistchina.txt")
<< Subscription("Anti-Adblock Killer", "https://raw.githubusercontent.com/reek/anti-adblock-killer/master/anti-adblock-killer-filters.txt")
<< Subscription(tr("Other..."), QString());
foreach (const Subscription &subscription, m_knownSubscriptions) {
ui->comboBox->addItem(subscription.title);
}
connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(indexChanged(int)));
indexChanged(0);
}
QString AdBlockAddSubscriptionDialog::title() const
{
return ui->title->text();
}
QString AdBlockAddSubscriptionDialog::url() const
{
return ui->url->text();
}
void AdBlockAddSubscriptionDialog::indexChanged(int index)
{
const Subscription subscription = m_knownSubscriptions.at(index);
// "Other..." entry
if (subscription.url.isEmpty()) {
ui->title->clear();
ui->url->clear();
}
else {
int pos = subscription.title.indexOf(QLatin1Char('('));
QString title = subscription.title;
if (pos > 0) {
title = title.left(pos).trimmed();
}
ui->title->setText(title);
ui->title->setCursorPosition(0);
ui->url->setText(subscription.url);
ui->url->setCursorPosition(0);
}
}
AdBlockAddSubscriptionDialog::~AdBlockAddSubscriptionDialog()
{
delete ui;
}

View file

@ -0,0 +1,63 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef ADBLOCKADDSUBSCRIPTIONDIALOG_H
#define ADBLOCKADDSUBSCRIPTIONDIALOG_H
#include <QDialog>
#include <QVector>
#include "qzcommon.h"
namespace Ui
{
class AdBlockAddSubscriptionDialog;
}
class QUPZILLA_EXPORT AdBlockAddSubscriptionDialog : public QDialog
{
Q_OBJECT
public:
explicit AdBlockAddSubscriptionDialog(QWidget* parent = 0);
~AdBlockAddSubscriptionDialog();
QString title() const;
QString url() const;
private slots:
void indexChanged(int index);
private:
Ui::AdBlockAddSubscriptionDialog* ui;
struct Subscription {
QString title;
QString url;
Subscription() {}
Subscription(const QString &t, const QString &u) {
title = t;
url = u;
}
};
QVector<Subscription> m_knownSubscriptions;
};
#endif // ADBLOCKADDSUBSCRIPTIONDIALOG_H

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AdBlockAddSubscriptionDialog</class>
<widget class="QDialog" name="AdBlockAddSubscriptionDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>557</width>
<height>162</height>
</rect>
</property>
<property name="windowTitle">
<string>Add Subscription</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="comboBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Title:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="title"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="url"/>
</item>
<item row="4" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Add new subscription to AdBlock:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AdBlockAddSubscriptionDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AdBlockAddSubscriptionDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,185 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "adblockdialog.h"
#include "adblockmanager.h"
#include "adblocksubscription.h"
#include "adblocktreewidget.h"
#include "adblockaddsubscriptiondialog.h"
#include "mainapplication.h"
#include "qztools.h"
#include <QMenu>
#include <QTimer>
#include <QMessageBox>
#include <QInputDialog>
AdBlockDialog::AdBlockDialog(QWidget* parent)
: QWidget(parent)
, m_manager(AdBlockManager::instance())
, m_currentTreeWidget(0)
, m_currentSubscription(0)
, m_loaded(false)
{
setAttribute(Qt::WA_DeleteOnClose);
setupUi(this);
QzTools::centerWidgetOnScreen(this);
#ifdef Q_OS_MACOS
tabWidget->setDocumentMode(false);
#endif
adblockCheckBox->setChecked(m_manager->isEnabled());
QMenu* menu = new QMenu(buttonOptions);
m_actionAddRule = menu->addAction(tr("Add Rule"), this, SLOT(addRule()));
m_actionRemoveRule = menu->addAction(tr("Remove Rule"), this, SLOT(removeRule()));
menu->addSeparator();
m_actionAddSubscription = menu->addAction(tr("Add Subscription"), this, SLOT(addSubscription()));
m_actionRemoveSubscription = menu->addAction(tr("Remove Subscription"), this, SLOT(removeSubscription()));
menu->addAction(tr("Update Subscriptions"), m_manager, SLOT(updateAllSubscriptions()));
menu->addSeparator();
menu->addAction(tr("Learn about writing rules..."), this, SLOT(learnAboutRules()));
buttonOptions->setMenu(menu);
connect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShowMenu()));
connect(adblockCheckBox, SIGNAL(toggled(bool)), this, SLOT(enableAdBlock(bool)));
connect(search, SIGNAL(textChanged(QString)), this, SLOT(filterString(QString)));
connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentChanged(int)));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
load();
buttonBox->setFocus();
}
void AdBlockDialog::showRule(const AdBlockRule* rule) const
{
AdBlockSubscription* subscription = rule->subscription();
if (!subscription) {
return;
}
for (int i = 0; i < tabWidget->count(); ++i) {
AdBlockTreeWidget* treeWidget = qobject_cast<AdBlockTreeWidget*>(tabWidget->widget(i));
if (subscription == treeWidget->subscription()) {
treeWidget->showRule(rule);
tabWidget->setCurrentIndex(i);
break;
}
}
}
void AdBlockDialog::addRule()
{
m_currentTreeWidget->addRule();
}
void AdBlockDialog::removeRule()
{
m_currentTreeWidget->removeRule();
}
void AdBlockDialog::addSubscription()
{
AdBlockAddSubscriptionDialog dialog(this);
if (dialog.exec() != QDialog::Accepted) {
return;
}
QString title = dialog.title();
QString url = dialog.url();
if (AdBlockSubscription* subscription = m_manager->addSubscription(title, url)) {
AdBlockTreeWidget* tree = new AdBlockTreeWidget(subscription, tabWidget);
int index = tabWidget->insertTab(tabWidget->count() - 1, tree, subscription->title());
tabWidget->setCurrentIndex(index);
}
}
void AdBlockDialog::removeSubscription()
{
if (m_manager->removeSubscription(m_currentSubscription)) {
delete m_currentTreeWidget;
}
}
void AdBlockDialog::currentChanged(int index)
{
if (index != -1) {
m_currentTreeWidget = qobject_cast<AdBlockTreeWidget*>(tabWidget->widget(index));
m_currentSubscription = m_currentTreeWidget->subscription();
}
}
void AdBlockDialog::filterString(const QString &string)
{
if (m_currentTreeWidget && adblockCheckBox->isChecked()) {
m_currentTreeWidget->filterString(string);
}
}
void AdBlockDialog::enableAdBlock(bool state)
{
m_manager->setEnabled(state);
if (state) {
load();
}
}
void AdBlockDialog::aboutToShowMenu()
{
bool subscriptionEditable = m_currentSubscription && m_currentSubscription->canEditRules();
bool subscriptionRemovable = m_currentSubscription && m_currentSubscription->canBeRemoved();
m_actionAddRule->setEnabled(subscriptionEditable);
m_actionRemoveRule->setEnabled(subscriptionEditable);
m_actionRemoveSubscription->setEnabled(subscriptionRemovable);
}
void AdBlockDialog::learnAboutRules()
{
mApp->addNewTab(QUrl("http://adblockplus.org/en/filters"));
}
void AdBlockDialog::loadSubscriptions()
{
for (int i = 0; i < tabWidget->count(); ++i) {
AdBlockTreeWidget* treeWidget = qobject_cast<AdBlockTreeWidget*>(tabWidget->widget(i));
treeWidget->refresh();
}
}
void AdBlockDialog::load()
{
if (m_loaded || !adblockCheckBox->isChecked()) {
return;
}
foreach (AdBlockSubscription* subscription, m_manager->subscriptions()) {
AdBlockTreeWidget* tree = new AdBlockTreeWidget(subscription, tabWidget);
tabWidget->addTab(tree, subscription->title());
}
m_loaded = true;
QTimer::singleShot(50, this, SLOT(loadSubscriptions()));
}

View file

@ -0,0 +1,71 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef ADBLOCKDIALOG_H
#define ADBLOCKDIALOG_H
#include <QWidget>
#include "qzcommon.h"
#include "ui_adblockdialog.h"
class AdBlockSubscription;
class AdBlockTreeWidget;
class AdBlockManager;
class AdBlockRule;
class QUPZILLA_EXPORT AdBlockDialog : public QWidget, public Ui_AdBlockDialog
{
Q_OBJECT
public:
explicit AdBlockDialog(QWidget* parent = 0);
void showRule(const AdBlockRule* rule) const;
private slots:
void addRule();
void removeRule();
void addSubscription();
void removeSubscription();
void currentChanged(int index);
void filterString(const QString &string);
void enableAdBlock(bool state);
void aboutToShowMenu();
void learnAboutRules();
void loadSubscriptions();
void load();
private:
AdBlockManager* m_manager;
AdBlockTreeWidget* m_currentTreeWidget;
AdBlockSubscription* m_currentSubscription;
QAction* m_actionAddRule;
QAction* m_actionRemoveRule;
QAction* m_actionAddSubscription;
QAction* m_actionRemoveSubscription;
bool m_loaded;
};
#endif // ADBLOCKDIALOG_H

View file

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AdBlockDialog</class>
<widget class="QWidget" name="AdBlockDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>546</width>
<height>462</height>
</rect>
</property>
<property name="windowTitle">
<string>AdBlock Configuration</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="adblockCheckBox">
<property name="text">
<string>Enable AdBlock</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="search">
<property name="placeholderText">
<string>Search...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>50</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="adblockWidget" native="true">
<property name="enabled">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="4" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="buttonOptions">
<property name="text">
<string>Options</string>
</property>
<property name="icon">
<iconset resource="../data/icons.qrc">
<normaloff>:/icons/other/adblock.png</normaloff>:/icons/other/adblock.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>AdBlock</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>-1</number>
</property>
<property name="documentMode">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../data/icons.qrc"/>
</resources>
<connections>
<connection>
<sender>adblockCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>adblockWidget</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>106</x>
<y>39</y>
</hint>
<hint type="destinationlabel">
<x>349</x>
<y>74</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,217 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "adblockicon.h"
#include "adblockrule.h"
#include "adblockmanager.h"
#include "adblocksubscription.h"
#include "mainapplication.h"
#include "browserwindow.h"
#include "webpage.h"
#include "tabbedwebview.h"
#include "tabwidget.h"
#include "desktopnotificationsfactory.h"
#include "qztools.h"
#include <QMenu>
#include <QTimer>
AdBlockIcon::AdBlockIcon(BrowserWindow* window, QWidget* parent)
: ClickableLabel(parent)
, m_window(window)
, m_menuAction(0)
, m_flashTimer(0)
, m_timerTicks(0)
, m_enabled(false)
{
setCursor(Qt::PointingHandCursor);
setToolTip(tr("AdBlock lets you block unwanted content on web pages"));
setFixedSize(16, 16);
connect(this, SIGNAL(clicked(QPoint)), this, SLOT(showMenu(QPoint)));
connect(AdBlockManager::instance(), SIGNAL(enabledChanged(bool)), this, SLOT(setEnabled(bool)));
}
AdBlockIcon::~AdBlockIcon()
{
for (int i = 0; i < m_blockedPopups.count(); ++i)
delete m_blockedPopups.at(i).first;
}
void AdBlockIcon::popupBlocked(const QString &ruleString, const QUrl &url)
{
int index = ruleString.lastIndexOf(QLatin1String(" ("));
const QString subscriptionName = ruleString.left(index);
const QString filter = ruleString.mid(index + 2, ruleString.size() - index - 3);
AdBlockSubscription* subscription = AdBlockManager::instance()->subscriptionByName(subscriptionName);
if (filter.isEmpty() || !subscription) {
return;
}
QPair<AdBlockRule*, QUrl> pair;
pair.first = new AdBlockRule(filter, subscription);
pair.second = url;
m_blockedPopups.append(pair);
mApp->desktopNotifications()->showNotification(QPixmap(":html/adblock_big.png"), tr("Blocked popup window"), tr("AdBlock blocked unwanted popup window."));
if (!m_flashTimer) {
m_flashTimer = new QTimer(this);
}
if (m_flashTimer->isActive()) {
stopAnimation();
}
m_flashTimer->setInterval(500);
m_flashTimer->start();
connect(m_flashTimer, SIGNAL(timeout()), this, SLOT(animateIcon()));
}
QAction* AdBlockIcon::menuAction()
{
if (!m_menuAction) {
m_menuAction = new QAction(tr("AdBlock"), this);
m_menuAction->setMenu(new QMenu);
connect(m_menuAction->menu(), SIGNAL(aboutToShow()), this, SLOT(createMenu()));
}
m_menuAction->setIcon(QIcon(m_enabled ? ":icons/other/adblock.png" : ":icons/other/adblock-disabled.png"));
return m_menuAction;
}
void AdBlockIcon::createMenu(QMenu* menu)
{
if (!menu) {
menu = qobject_cast<QMenu*>(sender());
if (!menu) {
return;
}
}
menu->clear();
AdBlockManager* manager = AdBlockManager::instance();
AdBlockCustomList* customList = manager->customList();
WebPage* page = m_window->weView()->page();
const QUrl pageUrl = page->url();
menu->addAction(tr("Show AdBlock &Settings"), manager, SLOT(showDialog()));
menu->addSeparator();
if (!pageUrl.host().isEmpty() && m_enabled && manager->canRunOnScheme(pageUrl.scheme())) {
const QString host = page->url().host().contains(QLatin1String("www.")) ? pageUrl.host().mid(4) : pageUrl.host();
const QString hostFilter = QString("@@||%1^$document").arg(host);
const QString pageFilter = QString("@@|%1|$document").arg(pageUrl.toString());
QAction* act = menu->addAction(tr("Disable on %1").arg(host));
act->setCheckable(true);
act->setChecked(customList->containsFilter(hostFilter));
act->setData(hostFilter);
connect(act, SIGNAL(triggered()), this, SLOT(toggleCustomFilter()));
act = menu->addAction(tr("Disable only on this page"));
act->setCheckable(true);
act->setChecked(customList->containsFilter(pageFilter));
act->setData(pageFilter);
connect(act, SIGNAL(triggered()), this, SLOT(toggleCustomFilter()));
menu->addSeparator();
}
if (!m_blockedPopups.isEmpty()) {
menu->addAction(tr("Blocked Popup Windows"))->setEnabled(false);
for (int i = 0; i < m_blockedPopups.count(); i++) {
const QPair<AdBlockRule*, QUrl> &pair = m_blockedPopups.at(i);
QString address = pair.second.toString().right(55);
QString actionText = tr("%1 with (%2)").arg(address, pair.first->filter()).replace(QLatin1Char('&'), QLatin1String("&&"));
QAction* action = menu->addAction(actionText, manager, SLOT(showRule()));
action->setData(QVariant::fromValue((void*)pair.first));
}
}
}
void AdBlockIcon::showMenu(const QPoint &pos)
{
QMenu menu;
createMenu(&menu);
menu.exec(pos);
}
void AdBlockIcon::toggleCustomFilter()
{
QAction* action = qobject_cast<QAction*>(sender());
if (!action) {
return;
}
const QString filter = action->data().toString();
AdBlockManager* manager = AdBlockManager::instance();
AdBlockCustomList* customList = manager->customList();
if (customList->containsFilter(filter)) {
customList->removeFilter(filter);
}
else {
AdBlockRule* rule = new AdBlockRule(filter, customList);
customList->addRule(rule);
}
}
void AdBlockIcon::animateIcon()
{
++m_timerTicks;
if (m_timerTicks > 10) {
stopAnimation();
return;
}
if (pixmap()->isNull()) {
setPixmap(QIcon(QSL(":icons/other/adblock.png")).pixmap(16));
}
else {
setPixmap(QPixmap());
}
}
void AdBlockIcon::stopAnimation()
{
m_timerTicks = 0;
m_flashTimer->stop();
disconnect(m_flashTimer, SIGNAL(timeout()), this, SLOT(animateIcon()));
setEnabled(m_enabled);
}
void AdBlockIcon::setEnabled(bool enabled)
{
if (enabled) {
setPixmap(QIcon(QSL(":icons/other/adblock.png")).pixmap(16));
}
else {
setPixmap(QIcon(QSL(":icons/other/adblock-disabled.png")).pixmap(16));
}
m_enabled = enabled;
}

View file

@ -0,0 +1,62 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef ADBLOCKICON_H
#define ADBLOCKICON_H
#include "qzcommon.h"
#include "clickablelabel.h"
#include "adblockrule.h"
class QMenu;
class QUrl;
class BrowserWindow;
class QUPZILLA_EXPORT AdBlockIcon : public ClickableLabel
{
Q_OBJECT
public:
explicit AdBlockIcon(BrowserWindow* window, QWidget* parent = 0);
~AdBlockIcon();
void popupBlocked(const QString &ruleString, const QUrl &url);
QAction* menuAction();
public slots:
void setEnabled(bool enabled);
void createMenu(QMenu* menu = 0);
private slots:
void showMenu(const QPoint &pos);
void toggleCustomFilter();
void animateIcon();
void stopAnimation();
private:
BrowserWindow* m_window;
QAction* m_menuAction;
QVector<QPair<AdBlockRule*, QUrl> > m_blockedPopups;
QTimer* m_flashTimer;
int m_timerTicks;
bool m_enabled;
};
#endif // ADBLOCKICON_H

View file

@ -0,0 +1,449 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "adblockmanager.h"
#include "adblockdialog.h"
#include "adblockmatcher.h"
#include "adblocksubscription.h"
#include "adblockurlinterceptor.h"
#include "datapaths.h"
#include "mainapplication.h"
#include "webpage.h"
#include "qztools.h"
#include "browserwindow.h"
#include "settings.h"
#include "networkmanager.h"
#include <QDateTime>
#include <QTextStream>
#include <QDir>
#include <QTimer>
#include <QMessageBox>
#include <QUrlQuery>
#include <QMutexLocker>
#include <QSaveFile>
//#define ADBLOCK_DEBUG
#ifdef ADBLOCK_DEBUG
#include <QElapsedTimer>
#endif
Q_GLOBAL_STATIC(AdBlockManager, qz_adblock_manager)
AdBlockManager::AdBlockManager(QObject* parent)
: QObject(parent)
, m_loaded(false)
, m_enabled(true)
, m_matcher(new AdBlockMatcher(this))
, m_interceptor(new AdBlockUrlInterceptor(this))
{
load();
}
AdBlockManager::~AdBlockManager()
{
qDeleteAll(m_subscriptions);
}
AdBlockManager* AdBlockManager::instance()
{
return qz_adblock_manager();
}
void AdBlockManager::setEnabled(bool enabled)
{
if (m_enabled == enabled) {
return;
}
m_enabled = enabled;
emit enabledChanged(enabled);
Settings settings;
settings.beginGroup("AdBlock");
settings.setValue("enabled", m_enabled);
settings.endGroup();
load();
mApp->reloadUserStyleSheet();
QMutexLocker locker(&m_mutex);
if (m_enabled) {
m_matcher->update();
} else {
m_matcher->clear();
}
}
QList<AdBlockSubscription*> AdBlockManager::subscriptions() const
{
return m_subscriptions;
}
bool AdBlockManager::block(QWebEngineUrlRequestInfo &request)
{
QMutexLocker locker(&m_mutex);
if (!isEnabled()) {
return false;
}
#ifdef ADBLOCK_DEBUG
QElapsedTimer timer;
timer.start();
#endif
const QString urlString = request.requestUrl().toEncoded().toLower();
const QString urlDomain = request.requestUrl().host().toLower();
const QString urlScheme = request.requestUrl().scheme().toLower();
if (!canRunOnScheme(urlScheme) || !canBeBlocked(request.firstPartyUrl())) {
return false;
}
bool res = false;
const AdBlockRule* blockedRule = m_matcher->match(request, urlDomain, urlString);
if (blockedRule) {
res = true;
if (request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeMainFrame) {
QUrl url(QSL("qupzilla:adblock"));
QUrlQuery query;
query.addQueryItem(QSL("rule"), blockedRule->filter());
query.addQueryItem(QSL("subscription"), blockedRule->subscription()->title());
url.setQuery(query);
request.redirect(url);
}
else {
request.block(true);
}
#ifdef ADBLOCK_DEBUG
qDebug() << "BLOCKED: " << timer.elapsed() << blockedRule->filter() << request.requestUrl();
#endif
}
#ifdef ADBLOCK_DEBUG
qDebug() << timer.elapsed() << request.requestUrl();
#endif
return res;
}
QStringList AdBlockManager::disabledRules() const
{
return m_disabledRules;
}
void AdBlockManager::addDisabledRule(const QString &filter)
{
m_disabledRules.append(filter);
}
void AdBlockManager::removeDisabledRule(const QString &filter)
{
m_disabledRules.removeOne(filter);
}
bool AdBlockManager::addSubscriptionFromUrl(const QUrl &url)
{
const QList<QPair<QString, QString> > queryItems = QUrlQuery(url).queryItems(QUrl::FullyDecoded);
QString subscriptionTitle;
QString subscriptionUrl;
for (int i = 0; i < queryItems.count(); ++i) {
QPair<QString, QString> pair = queryItems.at(i);
if (pair.first == QL1S("location"))
subscriptionUrl = pair.second;
else if (pair.first == QL1S("title"))
subscriptionTitle = pair.second;
}
if (subscriptionTitle.isEmpty() || subscriptionUrl.isEmpty())
return false;
const QString message = AdBlockManager::tr("Do you want to add <b>%1</b> subscription?").arg(subscriptionTitle);
QMessageBox::StandardButton result = QMessageBox::question(0, AdBlockManager::tr("AdBlock Subscription"), message, QMessageBox::Yes | QMessageBox::No);
if (result == QMessageBox::Yes) {
AdBlockManager::instance()->addSubscription(subscriptionTitle, subscriptionUrl);
AdBlockManager::instance()->showDialog();
}
return true;
}
AdBlockSubscription* AdBlockManager::addSubscription(const QString &title, const QString &url)
{
if (title.isEmpty() || url.isEmpty()) {
return 0;
}
QString fileName = QzTools::filterCharsFromFilename(title.toLower()) + ".txt";
QString filePath = QzTools::ensureUniqueFilename(DataPaths::currentProfilePath() + "/adblock/" + fileName);
QByteArray data = QString("Title: %1\nUrl: %2\n[Adblock Plus 1.1.1]").arg(title, url).toLatin1();
QSaveFile file(filePath);
if (!file.open(QFile::WriteOnly)) {
qWarning() << "AdBlockManager: Cannot write to file" << filePath;
return 0;
}
file.write(data);
file.commit();
AdBlockSubscription* subscription = new AdBlockSubscription(title, this);
subscription->setUrl(QUrl(url));
subscription->setFilePath(filePath);
subscription->loadSubscription(m_disabledRules);
m_subscriptions.insert(m_subscriptions.count() - 1, subscription);
connect(subscription, SIGNAL(subscriptionUpdated()), mApp, SLOT(reloadUserStyleSheet()));
connect(subscription, SIGNAL(subscriptionChanged()), this, SLOT(updateMatcher()));
return subscription;
}
bool AdBlockManager::removeSubscription(AdBlockSubscription* subscription)
{
QMutexLocker locker(&m_mutex);
if (!m_subscriptions.contains(subscription) || !subscription->canBeRemoved()) {
return false;
}
QFile(subscription->filePath()).remove();
m_subscriptions.removeOne(subscription);
m_matcher->update();
delete subscription;
return true;
}
AdBlockCustomList* AdBlockManager::customList() const
{
foreach (AdBlockSubscription* subscription, m_subscriptions) {
AdBlockCustomList* list = qobject_cast<AdBlockCustomList*>(subscription);
if (list) {
return list;
}
}
return 0;
}
void AdBlockManager::load()
{
QMutexLocker locker(&m_mutex);
if (m_loaded) {
return;
}
#ifdef ADBLOCK_DEBUG
QElapsedTimer timer;
timer.start();
#endif
Settings settings;
settings.beginGroup("AdBlock");
m_enabled = settings.value("enabled", m_enabled).toBool();
m_disabledRules = settings.value("disabledRules", QStringList()).toStringList();
QDateTime lastUpdate = settings.value("lastUpdate", QDateTime()).toDateTime();
settings.endGroup();
if (!m_enabled) {
return;
}
QDir adblockDir(DataPaths::currentProfilePath() + "/adblock");
// Create if neccessary
if (!adblockDir.exists()) {
QDir(DataPaths::currentProfilePath()).mkdir("adblock");
}
foreach (const QString &fileName, adblockDir.entryList(QStringList("*.txt"), QDir::Files)) {
if (fileName == QLatin1String("customlist.txt")) {
continue;
}
const QString absolutePath = adblockDir.absoluteFilePath(fileName);
QFile file(absolutePath);
if (!file.open(QFile::ReadOnly)) {
continue;
}
QTextStream textStream(&file);
textStream.setCodec("UTF-8");
QString title = textStream.readLine(1024).remove(QLatin1String("Title: "));
QUrl url = QUrl(textStream.readLine(1024).remove(QLatin1String("Url: ")));
if (title.isEmpty() || !url.isValid()) {
qWarning() << "AdBlockManager: Invalid subscription file" << absolutePath;
continue;
}
AdBlockSubscription* subscription = new AdBlockSubscription(title, this);
subscription->setUrl(url);
subscription->setFilePath(absolutePath);
m_subscriptions.append(subscription);
}
// Prepend EasyList if subscriptions are empty
if (m_subscriptions.isEmpty()) {
AdBlockSubscription* easyList = new AdBlockSubscription(tr("EasyList"), this);
easyList->setUrl(QUrl(ADBLOCK_EASYLIST_URL));
easyList->setFilePath(DataPaths::currentProfilePath() + QLatin1String("/adblock/easylist.txt"));
m_subscriptions.prepend(easyList);
}
// Append CustomList
AdBlockCustomList* customList = new AdBlockCustomList(this);
m_subscriptions.append(customList);
// Load all subscriptions
foreach (AdBlockSubscription* subscription, m_subscriptions) {
subscription->loadSubscription(m_disabledRules);
connect(subscription, SIGNAL(subscriptionUpdated()), mApp, SLOT(reloadUserStyleSheet()));
connect(subscription, SIGNAL(subscriptionChanged()), this, SLOT(updateMatcher()));
}
if (lastUpdate.addDays(5) < QDateTime::currentDateTime()) {
QTimer::singleShot(1000 * 60, this, SLOT(updateAllSubscriptions()));
}
#ifdef ADBLOCK_DEBUG
qDebug() << "AdBlock loaded in" << timer.elapsed();
#endif
m_matcher->update();
m_loaded = true;
mApp->networkManager()->installUrlInterceptor(m_interceptor);
}
void AdBlockManager::updateMatcher()
{
QMutexLocker locker(&m_mutex);
m_matcher->update();
}
void AdBlockManager::updateAllSubscriptions()
{
foreach (AdBlockSubscription* subscription, m_subscriptions) {
subscription->updateSubscription();
}
Settings settings;
settings.beginGroup("AdBlock");
settings.setValue("lastUpdate", QDateTime::currentDateTime());
settings.endGroup();
}
void AdBlockManager::save()
{
if (!m_loaded) {
return;
}
foreach (AdBlockSubscription* subscription, m_subscriptions) {
subscription->saveSubscription();
}
Settings settings;
settings.beginGroup("AdBlock");
settings.setValue("enabled", m_enabled);
settings.setValue("disabledRules", m_disabledRules);
settings.endGroup();
}
bool AdBlockManager::isEnabled() const
{
return m_enabled;
}
bool AdBlockManager::canRunOnScheme(const QString &scheme) const
{
return !(scheme == QLatin1String("file") || scheme == QLatin1String("qrc")
|| scheme == QLatin1String("qupzilla") || scheme == QLatin1String("data")
|| scheme == QLatin1String("abp"));
}
bool AdBlockManager::canBeBlocked(const QUrl &url) const
{
return !m_matcher->adBlockDisabledForUrl(url);
}
QString AdBlockManager::elementHidingRules(const QUrl &url) const
{
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url))
return QString();
return m_matcher->elementHidingRules();
}
QString AdBlockManager::elementHidingRulesForDomain(const QUrl &url) const
{
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url))
return QString();
return m_matcher->elementHidingRulesForDomain(url.host());
}
AdBlockSubscription* AdBlockManager::subscriptionByName(const QString &name) const
{
foreach (AdBlockSubscription* subscription, m_subscriptions) {
if (subscription->title() == name) {
return subscription;
}
}
return 0;
}
AdBlockDialog* AdBlockManager::showDialog()
{
if (!m_adBlockDialog) {
m_adBlockDialog = new AdBlockDialog;
}
m_adBlockDialog.data()->show();
m_adBlockDialog.data()->raise();
m_adBlockDialog.data()->activateWindow();
return m_adBlockDialog.data();
}
void AdBlockManager::showRule()
{
if (QAction* action = qobject_cast<QAction*>(sender())) {
const AdBlockRule* rule = static_cast<const AdBlockRule*>(action->data().value<void*>());
if (rule) {
showDialog()->showRule(rule);
}
}
}

View file

@ -0,0 +1,101 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef ADBLOCKMANAGER_H
#define ADBLOCKMANAGER_H
#include <QObject>
#include <QStringList>
#include <QPointer>
#include <QMutex>
#include "qzcommon.h"
class QUrl;
class QWebEngineUrlRequestInfo;
class AdBlockRule;
class AdBlockDialog;
class AdBlockMatcher;
class AdBlockCustomList;
class AdBlockSubscription;
class AdBlockUrlInterceptor;
class QUPZILLA_EXPORT AdBlockManager : public QObject
{
Q_OBJECT
public:
AdBlockManager(QObject* parent = 0);
~AdBlockManager();
void load();
void save();
bool isEnabled() const;
bool canRunOnScheme(const QString &scheme) const;
QString elementHidingRules(const QUrl &url) const;
QString elementHidingRulesForDomain(const QUrl &url) const;
AdBlockSubscription* subscriptionByName(const QString &name) const;
QList<AdBlockSubscription*> subscriptions() const;
bool block(QWebEngineUrlRequestInfo &request);
QStringList disabledRules() const;
void addDisabledRule(const QString &filter);
void removeDisabledRule(const QString &filter);
bool addSubscriptionFromUrl(const QUrl &url);
AdBlockSubscription* addSubscription(const QString &title, const QString &url);
bool removeSubscription(AdBlockSubscription* subscription);
AdBlockCustomList* customList() const;
static AdBlockManager* instance();
signals:
void enabledChanged(bool enabled);
public slots:
void setEnabled(bool enabled);
void showRule();
void updateMatcher();
void updateAllSubscriptions();
AdBlockDialog* showDialog();
private:
inline bool canBeBlocked(const QUrl &url) const;
bool m_loaded;
bool m_enabled;
QList<AdBlockSubscription*> m_subscriptions;
AdBlockMatcher* m_matcher;
QStringList m_disabledRules;
AdBlockUrlInterceptor *m_interceptor;
QPointer<AdBlockDialog> m_adBlockDialog;
QMutex m_mutex;
};
#endif // ADBLOCKMANAGER_H

View file

@ -0,0 +1,219 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2014-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "adblockmatcher.h"
#include "adblockmanager.h"
#include "adblockrule.h"
#include "adblocksubscription.h"
AdBlockMatcher::AdBlockMatcher(AdBlockManager* manager)
: QObject(manager)
, m_manager(manager)
{
}
AdBlockMatcher::~AdBlockMatcher()
{
clear();
}
const AdBlockRule* AdBlockMatcher::match(const QWebEngineUrlRequestInfo &request, const QString &urlDomain, const QString &urlString) const
{
// Exception rules
if (m_networkExceptionTree.find(request, urlDomain, urlString))
return 0;
int count = m_networkExceptionRules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = m_networkExceptionRules.at(i);
if (rule->networkMatch(request, urlDomain, urlString))
return 0;
}
// Block rules
if (const AdBlockRule* rule = m_networkBlockTree.find(request, urlDomain, urlString))
return rule;
count = m_networkBlockRules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = m_networkBlockRules.at(i);
if (rule->networkMatch(request, urlDomain, urlString))
return rule;
}
return 0;
}
bool AdBlockMatcher::adBlockDisabledForUrl(const QUrl &url) const
{
int count = m_documentRules.count();
for (int i = 0; i < count; ++i)
if (m_documentRules.at(i)->urlMatch(url))
return true;
return false;
}
bool AdBlockMatcher::elemHideDisabledForUrl(const QUrl &url) const
{
if (adBlockDisabledForUrl(url))
return true;
int count = m_elemhideRules.count();
for (int i = 0; i < count; ++i)
if (m_elemhideRules.at(i)->urlMatch(url))
return true;
return false;
}
QString AdBlockMatcher::elementHidingRules() const
{
return m_elementHidingRules;
}
QString AdBlockMatcher::elementHidingRulesForDomain(const QString &domain) const
{
QString rules;
int addedRulesCount = 0;
int count = m_domainRestrictedCssRules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = m_domainRestrictedCssRules.at(i);
if (!rule->matchDomain(domain))
continue;
if (Q_UNLIKELY(addedRulesCount == 1000)) {
rules.append(rule->cssSelector());
rules.append(QL1S("{display:none !important;}\n"));
addedRulesCount = 0;
}
else {
rules.append(rule->cssSelector() + QLatin1Char(','));
addedRulesCount++;
}
}
if (addedRulesCount != 0) {
rules = rules.left(rules.size() - 1);
rules.append(QL1S("{display:none !important;}\n"));
}
return rules;
}
void AdBlockMatcher::update()
{
clear();
QHash<QString, const AdBlockRule*> cssRulesHash;
QVector<const AdBlockRule*> exceptionCssRules;
foreach (AdBlockSubscription* subscription, m_manager->subscriptions()) {
foreach (const AdBlockRule* rule, subscription->allRules()) {
// Don't add internally disabled rules to cache
if (rule->isInternalDisabled())
continue;
if (rule->isCssRule()) {
// We will add only enabled css rules to cache, because there is no enabled/disabled
// check on match. They are directly embedded to pages.
if (!rule->isEnabled())
continue;
if (rule->isException())
exceptionCssRules.append(rule);
else
cssRulesHash.insert(rule->cssSelector(), rule);
}
else if (rule->isDocument()) {
m_documentRules.append(rule);
}
else if (rule->isElemhide()) {
m_elemhideRules.append(rule);
}
else if (rule->isException()) {
if (!m_networkExceptionTree.add(rule))
m_networkExceptionRules.append(rule);
}
else {
if (!m_networkBlockTree.add(rule))
m_networkBlockRules.append(rule);
}
}
}
foreach (const AdBlockRule* rule, exceptionCssRules) {
const AdBlockRule* originalRule = cssRulesHash.value(rule->cssSelector());
// If we don't have this selector, the exception does nothing
if (!originalRule)
continue;
AdBlockRule* copiedRule = originalRule->copy();
copiedRule->m_options |= AdBlockRule::DomainRestrictedOption;
copiedRule->m_blockedDomains.append(rule->m_allowedDomains);
cssRulesHash[rule->cssSelector()] = copiedRule;
m_createdRules.append(copiedRule);
}
// Apparently, excessive amount of selectors for one CSS rule is not what WebKit likes.
// (In my testings, 4931 is the number that makes it crash)
// So let's split it by 1000 selectors...
int hidingRulesCount = 0;
QHashIterator<QString, const AdBlockRule*> it(cssRulesHash);
while (it.hasNext()) {
it.next();
const AdBlockRule* rule = it.value();
if (rule->isDomainRestricted()) {
m_domainRestrictedCssRules.append(rule);
}
else if (Q_UNLIKELY(hidingRulesCount == 1000)) {
m_elementHidingRules.append(rule->cssSelector());
m_elementHidingRules.append(QL1S("{display:none !important;} "));
hidingRulesCount = 0;
}
else {
m_elementHidingRules.append(rule->cssSelector() + QLatin1Char(','));
hidingRulesCount++;
}
}
if (hidingRulesCount != 0) {
m_elementHidingRules = m_elementHidingRules.left(m_elementHidingRules.size() - 1);
m_elementHidingRules.append(QL1S("{display:none !important;} "));
}
}
void AdBlockMatcher::clear()
{
m_networkExceptionTree.clear();
m_networkExceptionRules.clear();
m_networkBlockTree.clear();
m_networkBlockRules.clear();
m_domainRestrictedCssRules.clear();
m_elementHidingRules.clear();
m_documentRules.clear();
m_elemhideRules.clear();
qDeleteAll(m_createdRules);
m_createdRules.clear();
}

View file

@ -0,0 +1,66 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2014-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef ADBLOCKMATCHER_H
#define ADBLOCKMATCHER_H
#include <QUrl>
#include <QObject>
#include "qzcommon.h"
#include "adblocksearchtree.h"
class QWebEngineUrlRequestInfo;
class AdBlockManager;
class QUPZILLA_EXPORT AdBlockMatcher : public QObject
{
Q_OBJECT
public:
explicit AdBlockMatcher(AdBlockManager* manager);
~AdBlockMatcher();
const AdBlockRule* match(const QWebEngineUrlRequestInfo &request, const QString &urlDomain, const QString &urlString) const;
bool adBlockDisabledForUrl(const QUrl &url) const;
bool elemHideDisabledForUrl(const QUrl &url) const;
QString elementHidingRules() const;
QString elementHidingRulesForDomain(const QString &domain) const;
public slots:
void update();
void clear();
private:
AdBlockManager* m_manager;
QVector<AdBlockRule*> m_createdRules;
QVector<const AdBlockRule*> m_networkExceptionRules;
QVector<const AdBlockRule*> m_networkBlockRules;
QVector<const AdBlockRule*> m_domainRestrictedCssRules;
QVector<const AdBlockRule*> m_documentRules;
QVector<const AdBlockRule*> m_elemhideRules;
QString m_elementHidingRules;
AdBlockSearchTree m_networkBlockTree;
AdBlockSearchTree m_networkExceptionTree;
};
#endif // ADBLOCKMATCHER_H

View file

@ -0,0 +1,757 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
/**
* Copyright (c) 2009, Zsombor Gegesy <gzsombor@gmail.com>
* Copyright (c) 2009, Benjamin C. Meyer <ben@meyerhome.net>
*
* 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 "adblockrule.h"
#include "adblocksubscription.h"
#include "qztools.h"
#include "qzregexp.h"
#include <QUrl>
#include <QString>
#include <QStringList>
#include <QWebEnginePage>
#include <QWebEngineUrlRequestInfo>
static QString toSecondLevelDomain(const QUrl &url)
{
const QString topLevelDomain = url.topLevelDomain();
const QString urlHost = url.host();
if (topLevelDomain.isEmpty() || urlHost.isEmpty()) {
return QString();
}
QString domain = urlHost.left(urlHost.size() - topLevelDomain.size());
if (domain.count(QL1C('.')) == 0) {
return urlHost;
}
while (domain.count(QL1C('.')) != 0) {
domain = domain.mid(domain.indexOf(QL1C('.')) + 1);
}
return domain + topLevelDomain;
}
AdBlockRule::AdBlockRule(const QString &filter, AdBlockSubscription* subscription)
: m_subscription(subscription)
, m_type(StringContainsMatchRule)
, m_caseSensitivity(Qt::CaseInsensitive)
, m_isEnabled(true)
, m_isException(false)
, m_isInternalDisabled(false)
, m_regExp(0)
{
setFilter(filter);
}
AdBlockRule::~AdBlockRule()
{
delete m_regExp;
}
AdBlockRule* AdBlockRule::copy() const
{
AdBlockRule* rule = new AdBlockRule();
rule->m_subscription = m_subscription;
rule->m_type = m_type;
rule->m_options = m_options;
rule->m_exceptions = m_exceptions;
rule->m_filter = m_filter;
rule->m_matchString = m_matchString;
rule->m_caseSensitivity = m_caseSensitivity;
rule->m_isEnabled = m_isEnabled;
rule->m_isException = m_isException;
rule->m_isInternalDisabled = m_isInternalDisabled;
rule->m_allowedDomains = m_allowedDomains;
rule->m_blockedDomains = m_blockedDomains;
if (m_regExp) {
rule->m_regExp = new RegExp;
rule->m_regExp->regExp = m_regExp->regExp;
rule->m_regExp->matchers = m_regExp->matchers;
}
return rule;
}
AdBlockSubscription* AdBlockRule::subscription() const
{
return m_subscription;
}
void AdBlockRule::setSubscription(AdBlockSubscription* subscription)
{
m_subscription = subscription;
}
QString AdBlockRule::filter() const
{
return m_filter;
}
void AdBlockRule::setFilter(const QString &filter)
{
m_filter = filter;
parseFilter();
}
bool AdBlockRule::isCssRule() const
{
return m_type == CssRule;
}
QString AdBlockRule::cssSelector() const
{
return m_matchString;
}
bool AdBlockRule::isDocument() const
{
return hasOption(DocumentOption);
}
bool AdBlockRule::isElemhide() const
{
return hasOption(ElementHideOption);
}
bool AdBlockRule::isDomainRestricted() const
{
return hasOption(DomainRestrictedOption);
}
bool AdBlockRule::isException() const
{
return m_isException;
}
bool AdBlockRule::isComment() const
{
return m_filter.startsWith(QL1C('!'));
}
bool AdBlockRule::isEnabled() const
{
return m_isEnabled;
}
void AdBlockRule::setEnabled(bool enabled)
{
m_isEnabled = enabled;
}
bool AdBlockRule::isSlow() const
{
return m_regExp != 0;
}
bool AdBlockRule::isInternalDisabled() const
{
return m_isInternalDisabled;
}
bool AdBlockRule::urlMatch(const QUrl &url) const
{
if (!hasOption(DocumentOption) && !hasOption(ElementHideOption)) {
return false;
}
const QString encodedUrl = url.toEncoded();
const QString domain = url.host();
return stringMatch(domain, encodedUrl);
}
bool AdBlockRule::networkMatch(const QWebEngineUrlRequestInfo &request, const QString &domain, const QString &encodedUrl) const
{
if (m_type == CssRule || !m_isEnabled || m_isInternalDisabled) {
return false;
}
bool matched = stringMatch(domain, encodedUrl);
if (matched) {
// Check domain restrictions
if (hasOption(DomainRestrictedOption) && !matchDomain(request.firstPartyUrl().host())) {
return false;
}
// Check third-party restriction
if (hasOption(ThirdPartyOption) && !matchThirdParty(request)) {
return false;
}
// Check object restrictions
if (hasOption(ObjectOption) && !matchObject(request)) {
return false;
}
// Check subdocument restriction
if (hasOption(SubdocumentOption) && !matchSubdocument(request)) {
return false;
}
// Check xmlhttprequest restriction
if (hasOption(XMLHttpRequestOption) && !matchXmlHttpRequest(request)) {
return false;
}
// Check image restriction
if (hasOption(ImageOption) && !matchImage(request)) {
return false;
}
// Check script restriction
if (hasOption(ScriptOption) && !matchScript(request)) {
return false;
}
// Check stylesheet restriction
if (hasOption(StyleSheetOption) && !matchStyleSheet(request)) {
return false;
}
// Check object-subrequest restriction
if (hasOption(ObjectSubrequestOption) && !matchObjectSubrequest(request)) {
return false;
}
}
return matched;
}
bool AdBlockRule::matchDomain(const QString &domain) const
{
if (!m_isEnabled) {
return false;
}
if (!hasOption(DomainRestrictedOption)) {
return true;
}
if (m_blockedDomains.isEmpty()) {
foreach (const QString &d, m_allowedDomains) {
if (isMatchingDomain(domain, d)) {
return true;
}
}
}
else if (m_allowedDomains.isEmpty()) {
foreach (const QString &d, m_blockedDomains) {
if (isMatchingDomain(domain, d)) {
return false;
}
}
return true;
}
else {
foreach (const QString &d, m_blockedDomains) {
if (isMatchingDomain(domain, d)) {
return false;
}
}
foreach (const QString &d, m_allowedDomains) {
if (isMatchingDomain(domain, d)) {
return true;
}
}
}
return false;
}
bool AdBlockRule::matchThirdParty(const QWebEngineUrlRequestInfo &request) const
{
// Third-party matching should be performed on second-level domains
const QString firstPartyHost = toSecondLevelDomain(request.firstPartyUrl());
const QString host = toSecondLevelDomain(request.requestUrl());
bool match = firstPartyHost != host;
return hasException(ThirdPartyOption) ? !match : match;
}
bool AdBlockRule::matchObject(const QWebEngineUrlRequestInfo &request) const
{
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeObject;
return hasException(ObjectOption) ? !match : match;
}
bool AdBlockRule::matchSubdocument(const QWebEngineUrlRequestInfo &request) const
{
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeSubFrame;
return hasException(SubdocumentOption) ? !match : match;
}
bool AdBlockRule::matchXmlHttpRequest(const QWebEngineUrlRequestInfo &request) const
{
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeXhr;
return hasException(XMLHttpRequestOption) ? !match : match;
}
bool AdBlockRule::matchImage(const QWebEngineUrlRequestInfo &request) const
{
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeImage;
return hasException(ImageOption) ? !match : match;
}
bool AdBlockRule::matchScript(const QWebEngineUrlRequestInfo &request) const
{
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeScript;
return hasException(ScriptOption) ? !match : match;
}
bool AdBlockRule::matchStyleSheet(const QWebEngineUrlRequestInfo &request) const
{
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeStylesheet;
return hasException(StyleSheetOption) ? !match : match;
}
bool AdBlockRule::matchObjectSubrequest(const QWebEngineUrlRequestInfo &request) const
{
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceTypeSubResource;
return hasException(ObjectSubrequestOption) ? !match : match;
}
void AdBlockRule::parseFilter()
{
QString parsedLine = m_filter;
// Empty rule or just comment
if (m_filter.trimmed().isEmpty() || m_filter.startsWith(QL1C('!'))) {
// We want to differentiate rule disabled by user and rule disabled in subscription file
// m_isInternalDisabled is also used when rule is disabled due to all options not being supported
m_isEnabled = false;
m_isInternalDisabled = true;
m_type = Invalid;
return;
}
// CSS Element hiding rule
if (parsedLine.contains(QL1S("##")) || parsedLine.contains(QL1S("#@#"))) {
m_type = CssRule;
int pos = parsedLine.indexOf(QL1C('#'));
// Domain restricted rule
if (!parsedLine.startsWith(QL1S("##"))) {
QString domains = parsedLine.left(pos);
parseDomains(domains, QL1C(','));
}
m_isException = parsedLine.at(pos + 1) == QL1C('@');
m_matchString = parsedLine.mid(m_isException ? pos + 3 : pos + 2);
// CSS rule cannot have more options -> stop parsing
return;
}
// Exception always starts with @@
if (parsedLine.startsWith(QL1S("@@"))) {
m_isException = true;
parsedLine = parsedLine.mid(2);
}
// Parse all options following $ char
int optionsIndex = parsedLine.indexOf(QL1C('$'));
if (optionsIndex >= 0) {
const QStringList options = parsedLine.mid(optionsIndex + 1).split(QL1C(','), QString::SkipEmptyParts);
int handledOptions = 0;
foreach (const QString &option, options) {
if (option.startsWith(QL1S("domain="))) {
parseDomains(option.mid(7), QL1C('|'));
++handledOptions;
}
else if (option == QL1S("match-case")) {
m_caseSensitivity = Qt::CaseSensitive;
++handledOptions;
}
else if (option.endsWith(QL1S("third-party"))) {
setOption(ThirdPartyOption);
setException(ThirdPartyOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("object"))) {
setOption(ObjectOption);
setException(ObjectOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("subdocument"))) {
setOption(SubdocumentOption);
setException(SubdocumentOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("xmlhttprequest"))) {
setOption(XMLHttpRequestOption);
setException(XMLHttpRequestOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("image"))) {
setOption(ImageOption);
setException(ImageOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("script"))) {
setOption(ScriptOption);
setException(ScriptOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("stylesheet"))) {
setOption(StyleSheetOption);
setException(StyleSheetOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option.endsWith(QL1S("object-subrequest"))) {
setOption(ObjectSubrequestOption);
setException(ObjectSubrequestOption, option.startsWith(QL1C('~')));
++handledOptions;
}
else if (option == QL1S("document") && m_isException) {
setOption(DocumentOption);
++handledOptions;
}
else if (option == QL1S("elemhide") && m_isException) {
setOption(ElementHideOption);
++handledOptions;
}
else if (option == QL1S("collapse")) {
// Hiding placeholders of blocked elements is enabled by default
++handledOptions;
}
}
// If we don't handle all options, it's safer to just disable this rule
if (handledOptions != options.count()) {
m_isInternalDisabled = true;
m_type = Invalid;
return;
}
parsedLine = parsedLine.left(optionsIndex);
}
// Rule is classic regexp
if (parsedLine.startsWith(QL1C('/')) && parsedLine.endsWith(QL1C('/'))) {
parsedLine = parsedLine.mid(1);
parsedLine = parsedLine.left(parsedLine.size() - 1);
m_type = RegExpMatchRule;
m_regExp = new RegExp;
m_regExp->regExp = QzRegExp(parsedLine, m_caseSensitivity);
m_regExp->matchers = createStringMatchers(parseRegExpFilter(parsedLine));
return;
}
// Remove starting and ending wildcards (*)
if (parsedLine.startsWith(QL1C('*'))) {
parsedLine = parsedLine.mid(1);
}
if (parsedLine.endsWith(QL1C('*'))) {
parsedLine = parsedLine.left(parsedLine.size() - 1);
}
// We can use fast string matching for domain here
if (filterIsOnlyDomain(parsedLine)) {
parsedLine = parsedLine.mid(2);
parsedLine = parsedLine.left(parsedLine.size() - 1);
m_type = DomainMatchRule;
m_matchString = parsedLine;
return;
}
// If rule contains only | at end, we can also use string matching
if (filterIsOnlyEndsMatch(parsedLine)) {
parsedLine = parsedLine.left(parsedLine.size() - 1);
m_type = StringEndsMatchRule;
m_matchString = parsedLine;
return;
}
// If we still find a wildcard (*) or separator (^) or (|)
// we must modify parsedLine to comply with QzRegExp
if (parsedLine.contains(QL1C('*')) ||
parsedLine.contains(QL1C('^')) ||
parsedLine.contains(QL1C('|'))
) {
m_type = RegExpMatchRule;
m_regExp = new RegExp;
m_regExp->regExp = QzRegExp(createRegExpFromFilter(parsedLine), m_caseSensitivity);
m_regExp->matchers = createStringMatchers(parseRegExpFilter(parsedLine));
return;
}
// We haven't found anything that needs use of regexp, yay!
m_type = StringContainsMatchRule;
m_matchString = parsedLine;
}
void AdBlockRule::parseDomains(const QString &domains, const QChar &separator)
{
QStringList domainsList = domains.split(separator, QString::SkipEmptyParts);
foreach (const QString domain, domainsList) {
if (domain.isEmpty()) {
continue;
}
if (domain.startsWith(QL1C('~'))) {
m_blockedDomains.append(domain.mid(1));
}
else {
m_allowedDomains.append(domain);
}
}
if (!m_blockedDomains.isEmpty() || !m_allowedDomains.isEmpty()) {
setOption(DomainRestrictedOption);
}
}
bool AdBlockRule::filterIsOnlyDomain(const QString &filter) const
{
if (!filter.endsWith(QL1C('^')) || !filter.startsWith(QL1S("||")))
return false;
for (int i = 0; i < filter.size(); ++i) {
switch (filter.at(i).toLatin1()) {
case '/':
case ':':
case '?':
case '=':
case '&':
case '*':
return false;
default:
break;
}
}
return true;
}
bool AdBlockRule::filterIsOnlyEndsMatch(const QString &filter) const
{
for (int i = 0; i < filter.size(); ++i) {
switch (filter.at(i).toLatin1()) {
case '^':
case '*':
return false;
case '|':
return i == filter.size() - 1;
default:
break;
}
}
return false;
}
static bool wordCharacter(const QChar &c)
{
return c.isLetterOrNumber() || c.isMark() || c == QL1C('_');
}
QString AdBlockRule::createRegExpFromFilter(const QString &filter) const
{
QString parsed;
parsed.reserve(filter.size());
bool hadWildcard = false; // Filter multiple wildcards
for (int i = 0; i < filter.size(); ++i) {
const QChar c = filter.at(i);
switch (c.toLatin1()) {
case '^':
parsed.append(QL1S("(?:[^\\w\\d\\-.%]|$)"));
break;
case '*':
if (!hadWildcard)
parsed.append(QL1S(".*"));
break;
case '|':
if (i == 0) {
if (filter.size() > 1 && filter.at(1) == QL1C('|')) {
parsed.append(QL1S("^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?"));
i++;
}
else {
parsed.append('^');
}
break;
}
else if (i == filter.size() - 1) {
parsed.append(QL1C('$'));
break;
}
// fallthrough
default:
if (!wordCharacter(c))
parsed.append(QL1C('\\') + c);
else
parsed.append(c);
}
hadWildcard = c == QL1C('*');
}
return parsed;
}
QList<QStringMatcher> AdBlockRule::createStringMatchers(const QStringList &filters) const
{
QList<QStringMatcher> matchers;
matchers.reserve(filters.size());
foreach (const QString &filter, filters) {
matchers.append(QStringMatcher(filter, m_caseSensitivity));
}
return matchers;
}
bool AdBlockRule::stringMatch(const QString &domain, const QString &encodedUrl) const
{
if (m_type == StringContainsMatchRule) {
return encodedUrl.contains(m_matchString, m_caseSensitivity);
}
else if (m_type == DomainMatchRule) {
return isMatchingDomain(domain, m_matchString);
}
else if (m_type == StringEndsMatchRule) {
return encodedUrl.endsWith(m_matchString, m_caseSensitivity);
}
else if (m_type == RegExpMatchRule) {
if (!isMatchingRegExpStrings(encodedUrl)) {
return false;
}
return (m_regExp->regExp.indexIn(encodedUrl) != -1);
}
return false;
}
bool AdBlockRule::isMatchingDomain(const QString &domain, const QString &filter) const
{
return QzTools::matchDomain(filter, domain);
}
bool AdBlockRule::isMatchingRegExpStrings(const QString &url) const
{
Q_ASSERT(m_regExp);
foreach (const QStringMatcher &matcher, m_regExp->matchers) {
if (matcher.indexIn(url) == -1)
return false;
}
return true;
}
// Split regexp filter into strings that can be used with QString::contains
// Don't use parts that contains only 1 char and duplicated parts
QStringList AdBlockRule::parseRegExpFilter(const QString &filter) const
{
QStringList list;
int startPos = -1;
for (int i = 0; i < filter.size(); ++i) {
const QChar c = filter.at(i);
// Meta characters in AdBlock rules are | * ^
if (c == QL1C('|') || c == QL1C('*') || c == QL1C('^')) {
const QString sub = filter.mid(startPos, i - startPos);
if (sub.size() > 1)
list.append(sub);
startPos = i + 1;
}
}
const QString sub = filter.mid(startPos);
if (sub.size() > 1)
list.append(sub);
list.removeDuplicates();
return list;
}
bool AdBlockRule::hasOption(const AdBlockRule::RuleOption &opt) const
{
return (m_options & opt);
}
bool AdBlockRule::hasException(const AdBlockRule::RuleOption &opt) const
{
return (m_exceptions & opt);
}
void AdBlockRule::setOption(const AdBlockRule::RuleOption &opt)
{
m_options |= opt;
}
void AdBlockRule::setException(const AdBlockRule::RuleOption &opt, bool on)
{
if (on) {
m_exceptions |= opt;
}
}

View file

@ -0,0 +1,187 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
/**
* Copyright (c) 2009, Benjamin C. Meyer <ben@meyerhome.net>
*
* 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 <QObject>
#include <QStringList>
#include <QStringMatcher>
#include "qzcommon.h"
#include "qzregexp.h"
class QUrl;
class QWebEngineUrlRequestInfo;
class AdBlockSubscription;
class QUPZILLA_EXPORT AdBlockRule
{
Q_DISABLE_COPY(AdBlockRule)
public:
AdBlockRule(const QString &filter = QString(), AdBlockSubscription* subscription = 0);
~AdBlockRule();
AdBlockRule* copy() const;
AdBlockSubscription* subscription() const;
void setSubscription(AdBlockSubscription* subscription);
QString filter() const;
void setFilter(const QString &filter);
bool isCssRule() const;
QString cssSelector() const;
bool isDocument() const;
bool isElemhide() const;
bool isDomainRestricted() const;
bool isException() const;
bool isComment() const;
bool isEnabled() const;
void setEnabled(bool enabled);
bool isSlow() const;
bool isInternalDisabled() const;
bool urlMatch(const QUrl &url) const;
bool networkMatch(const QWebEngineUrlRequestInfo &request, const QString &domain, const QString &encodedUrl) const;
bool matchDomain(const QString &domain) const;
bool matchThirdParty(const QWebEngineUrlRequestInfo &request) const;
bool matchObject(const QWebEngineUrlRequestInfo &request) const;
bool matchSubdocument(const QWebEngineUrlRequestInfo &request) const;
bool matchXmlHttpRequest(const QWebEngineUrlRequestInfo &request) const;
bool matchImage(const QWebEngineUrlRequestInfo &request) const;
bool matchScript(const QWebEngineUrlRequestInfo &request) const;
bool matchStyleSheet(const QWebEngineUrlRequestInfo &request) const;
bool matchObjectSubrequest(const QWebEngineUrlRequestInfo &request) const;
protected:
bool stringMatch(const QString &domain, const QString &encodedUrl) const;
bool isMatchingDomain(const QString &domain, const QString &filter) const;
bool isMatchingRegExpStrings(const QString &url) const;
QStringList parseRegExpFilter(const QString &filter) const;
private:
enum RuleType {
CssRule = 0,
DomainMatchRule = 1,
RegExpMatchRule = 2,
StringEndsMatchRule = 3,
StringContainsMatchRule = 4,
Invalid = 5
};
enum RuleOption {
DomainRestrictedOption = 1,
ThirdPartyOption = 2,
ObjectOption = 4,
SubdocumentOption = 8,
XMLHttpRequestOption = 16,
ImageOption = 32,
ScriptOption = 64,
StyleSheetOption = 128,
ObjectSubrequestOption = 256,
// Exception only options
DocumentOption = 1024,
ElementHideOption = 2048
};
Q_DECLARE_FLAGS(RuleOptions, RuleOption)
inline bool hasOption(const RuleOption &opt) const;
inline bool hasException(const RuleOption &opt) const;
inline void setOption(const RuleOption &opt);
inline void setException(const RuleOption &opt, bool on);
void parseFilter();
void parseDomains(const QString &domains, const QChar &separator);
bool filterIsOnlyDomain(const QString &filter) const;
bool filterIsOnlyEndsMatch(const QString &filter) const;
QString createRegExpFromFilter(const QString &filter) const;
QList<QStringMatcher> createStringMatchers(const QStringList &filters) const;
AdBlockSubscription* m_subscription;
RuleType m_type;
RuleOptions m_options;
RuleOptions m_exceptions;
// Original rule filter
QString m_filter;
// Parsed rule for string matching (CSS Selector for CSS rules)
QString m_matchString;
// Case sensitivity for string matching
Qt::CaseSensitivity m_caseSensitivity;
bool m_isEnabled;
bool m_isException;
bool m_isInternalDisabled;
QStringList m_allowedDomains;
QStringList m_blockedDomains;
struct RegExp {
QzRegExp regExp;
QList<QStringMatcher> matchers;
};
// Use dynamic allocation to save memory
RegExp* m_regExp;
friend class AdBlockMatcher;
friend class AdBlockSearchTree;
friend class AdBlockSubscription;
};
#endif // ADBLOCKRULE_H

View file

@ -0,0 +1,137 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2013-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "adblocksearchtree.h"
#include "adblockrule.h"
#include <QWebEngineUrlRequestInfo>
AdBlockSearchTree::AdBlockSearchTree()
: m_root(new Node)
{
}
AdBlockSearchTree::~AdBlockSearchTree()
{
deleteNode(m_root);
}
void AdBlockSearchTree::clear()
{
deleteNode(m_root);
m_root = new Node;
}
bool AdBlockSearchTree::add(const AdBlockRule* rule)
{
if (rule->m_type != AdBlockRule::StringContainsMatchRule) {
return false;
}
const QString filter = rule->m_matchString;
int len = filter.size();
if (len <= 0) {
qDebug() << "AdBlockSearchTree: Inserting rule with filter len <= 0!";
return false;
}
Node* node = m_root;
for (int i = 0; i < len; ++i) {
const QChar c = filter.at(i);
Node *next = node->children.value(c);
if (!next) {
next = new Node;
next->c = c;
node->children[c] = next;
}
node = next;
}
node->rule = rule;
return true;
}
const AdBlockRule* AdBlockSearchTree::find(const QWebEngineUrlRequestInfo &request, const QString &domain, const QString &urlString) const
{
int len = urlString.size();
if (len <= 0) {
return 0;
}
const QChar* string = urlString.constData();
for (int i = 0; i < len; ++i) {
const AdBlockRule* rule = prefixSearch(request, domain, urlString, string++, len - i);
if (rule) {
return rule;
}
}
return 0;
}
const AdBlockRule* AdBlockSearchTree::prefixSearch(const QWebEngineUrlRequestInfo &request, const QString &domain, const QString &urlString, const QChar* string, int len) const
{
if (len <= 0) {
return 0;
}
QChar c = string[0];
Node* node = m_root->children.value(c);
if (!node) {
return nullptr;
}
for (int i = 1; i < len; ++i) {
const QChar c = (++string)[0];
if (node->rule && node->rule->networkMatch(request, domain, urlString)) {
return node->rule;
}
node = node->children.value(c);
if (!node) {
return nullptr;
}
}
if (node->rule && node->rule->networkMatch(request, domain, urlString)) {
return node->rule;
}
return nullptr;
}
void AdBlockSearchTree::deleteNode(AdBlockSearchTree::Node* node)
{
if (!node) {
return;
}
QHashIterator<QChar, Node*> i(node->children);
while (i.hasNext()) {
i.next();
deleteNode(i.value());
}
delete node;
}

View file

@ -0,0 +1,58 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2013-2014 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef ADBLOCKSEARCHTREE_H
#define ADBLOCKSEARCHTREE_H
#include <QChar>
#include <QHash>
#include "qzcommon.h"
class QWebEngineUrlRequestInfo;
class AdBlockRule;
class QUPZILLA_EXPORT AdBlockSearchTree
{
public:
explicit AdBlockSearchTree();
~AdBlockSearchTree();
void clear();
bool add(const AdBlockRule* rule);
const AdBlockRule* find(const QWebEngineUrlRequestInfo &request, const QString &domain, const QString &urlString) const;
private:
struct Node {
QChar c;
const AdBlockRule* rule;
QHash<QChar, Node*> children;
Node() : c(0) , rule(0) { }
};
const AdBlockRule* prefixSearch(const QWebEngineUrlRequestInfo &request, const QString &domain,
const QString &urlString, const QChar* string, int len) const;
void deleteNode(Node* node);
Node* m_root;
};
#endif // ADBLOCKSEARCHTREE_H

View file

@ -0,0 +1,426 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
/**
* Copyright (c) 2009, Benjamin C. Meyer <ben@meyerhome.net>
*
* 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 "adblockmanager.h"
#include "adblocksearchtree.h"
#include "mainapplication.h"
#include "networkmanager.h"
#include "datapaths.h"
#include "qztools.h"
#include <QFile>
#include <QTimer>
#include <QNetworkReply>
#include <QSaveFile>
AdBlockSubscription::AdBlockSubscription(const QString &title, QObject* parent)
: QObject(parent)
, m_reply(0)
, m_title(title)
, m_updated(false)
{
}
QString AdBlockSubscription::title() const
{
return m_title;
}
QString AdBlockSubscription::filePath() const
{
return m_filePath;
}
void AdBlockSubscription::setFilePath(const QString &path)
{
m_filePath = path;
}
QUrl AdBlockSubscription::url() const
{
return m_url;
}
void AdBlockSubscription::setUrl(const QUrl &url)
{
m_url = url;
}
void AdBlockSubscription::loadSubscription(const QStringList &disabledRules)
{
QFile file(m_filePath);
if (!file.exists()) {
QTimer::singleShot(0, this, SLOT(updateSubscription()));
return;
}
if (!file.open(QFile::ReadOnly)) {
qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "Unable to open adblock file for reading" << m_filePath;
QTimer::singleShot(0, this, SLOT(updateSubscription()));
return;
}
QTextStream textStream(&file);
textStream.setCodec("UTF-8");
// Header is on 3rd line
textStream.readLine(1024);
textStream.readLine(1024);
QString header = textStream.readLine(1024);
if (!header.startsWith(QLatin1String("[Adblock")) || m_title.isEmpty()) {
qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "invalid format of adblock file" << m_filePath;
QTimer::singleShot(0, this, SLOT(updateSubscription()));
return;
}
m_rules.clear();
while (!textStream.atEnd()) {
AdBlockRule* rule = new AdBlockRule(textStream.readLine(), this);
if (disabledRules.contains(rule->filter())) {
rule->setEnabled(false);
}
m_rules.append(rule);
}
// Initial update
if (m_rules.isEmpty() && !m_updated) {
QTimer::singleShot(0, this, SLOT(updateSubscription()));
}
}
void AdBlockSubscription::saveSubscription()
{
}
void AdBlockSubscription::updateSubscription()
{
if (m_reply || !m_url.isValid()) {
return;
}
m_reply = mApp->networkManager()->get(QNetworkRequest(m_url));
connect(m_reply, &QNetworkReply::finished, this, &AdBlockSubscription::subscriptionDownloaded);
}
void AdBlockSubscription::subscriptionDownloaded()
{
if (m_reply != qobject_cast<QNetworkReply*>(sender())) {
return;
}
bool error = false;
const QByteArray response = QString::fromUtf8(m_reply->readAll()).toUtf8();
if (m_reply->error() != QNetworkReply::NoError ||
!response.startsWith(QByteArray("[Adblock")) ||
!saveDownloadedData(response)
) {
error = true;
}
m_reply->deleteLater();
m_reply = 0;
if (error) {
emit subscriptionError(tr("Cannot load subscription!"));
return;
}
loadSubscription(AdBlockManager::instance()->disabledRules());
emit subscriptionUpdated();
emit subscriptionChanged();
}
bool AdBlockSubscription::saveDownloadedData(const QByteArray &data)
{
QSaveFile file(m_filePath);
if (!file.open(QFile::WriteOnly)) {
qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "Unable to open adblock file for writing:" << m_filePath;
return false;
}
// Write subscription header
file.write(QString("Title: %1\nUrl: %2\n").arg(title(), url().toString()).toUtf8());
file.write(data);
file.commit();
return true;
}
const AdBlockRule* AdBlockSubscription::rule(int offset) const
{
if (!QzTools::containsIndex(m_rules, offset)) {
return 0;
}
return m_rules[offset];
}
QVector<AdBlockRule*> AdBlockSubscription::allRules() const
{
return m_rules;
}
const AdBlockRule* AdBlockSubscription::enableRule(int offset)
{
if (!QzTools::containsIndex(m_rules, offset)) {
return 0;
}
AdBlockRule* rule = m_rules[offset];
rule->setEnabled(true);
AdBlockManager::instance()->removeDisabledRule(rule->filter());
emit subscriptionChanged();
if (rule->isCssRule())
mApp->reloadUserStyleSheet();
return rule;
}
const AdBlockRule* AdBlockSubscription::disableRule(int offset)
{
if (!QzTools::containsIndex(m_rules, offset)) {
return 0;
}
AdBlockRule* rule = m_rules[offset];
rule->setEnabled(false);
AdBlockManager::instance()->addDisabledRule(rule->filter());
emit subscriptionChanged();
if (rule->isCssRule())
mApp->reloadUserStyleSheet();
return rule;
}
bool AdBlockSubscription::canEditRules() const
{
return false;
}
bool AdBlockSubscription::canBeRemoved() const
{
return true;
}
int AdBlockSubscription::addRule(AdBlockRule* rule)
{
Q_UNUSED(rule)
return -1;
}
bool AdBlockSubscription::removeRule(int offset)
{
Q_UNUSED(offset)
return false;
}
const AdBlockRule* AdBlockSubscription::replaceRule(AdBlockRule* rule, int offset)
{
Q_UNUSED(rule)
Q_UNUSED(offset)
return 0;
}
AdBlockSubscription::~AdBlockSubscription()
{
qDeleteAll(m_rules);
}
// AdBlockCustomList
AdBlockCustomList::AdBlockCustomList(QObject* parent)
: AdBlockSubscription(tr("Custom Rules"), parent)
{
setFilePath(DataPaths::currentProfilePath() + QLatin1String("/adblock/customlist.txt"));
}
void AdBlockCustomList::loadSubscription(const QStringList &disabledRules)
{
// DuckDuckGo ad whitelist rules
// They cannot be removed, but can be disabled.
// Please consider not disabling them. Thanks!
const QString ddg1 = QSL("@@||duckduckgo.com^$document");
const QString ddg2 = QSL("duckduckgo.com#@#.has-ad");
const QString rules = QzTools::readAllFileContents(filePath());
QFile file(filePath());
if (!file.exists()) {
saveSubscription();
}
if (file.open(QFile::WriteOnly | QFile::Append)) {
QTextStream stream(&file);
stream.setCodec("UTF-8");
if (!rules.contains(ddg1 + QL1S("\n")))
stream << ddg1 << endl;
if (!rules.contains(QL1S("\n") + ddg2))
stream << ddg2 << endl;
}
file.close();
AdBlockSubscription::loadSubscription(disabledRules);
}
void AdBlockCustomList::saveSubscription()
{
QFile file(filePath());
if (!file.open(QFile::ReadWrite | QFile::Truncate)) {
qWarning() << "AdBlockSubscription::" << __FUNCTION__ << "Unable to open adblock file for writing:" << filePath();
return;
}
QTextStream textStream(&file);
textStream.setCodec("UTF-8");
textStream << "Title: " << title() << endl;
textStream << "Url: " << url().toString() << endl;
textStream << "[Adblock Plus 1.1.1]" << endl;
foreach (const AdBlockRule* rule, m_rules) {
textStream << rule->filter() << endl;
}
file.close();
}
bool AdBlockCustomList::canEditRules() const
{
return true;
}
bool AdBlockCustomList::canBeRemoved() const
{
return false;
}
bool AdBlockCustomList::containsFilter(const QString &filter) const
{
foreach (const AdBlockRule* rule, m_rules) {
if (rule->filter() == filter) {
return true;
}
}
return false;
}
bool AdBlockCustomList::removeFilter(const QString &filter)
{
for (int i = 0; i < m_rules.count(); ++i) {
const AdBlockRule* rule = m_rules.at(i);
if (rule->filter() == filter) {
return removeRule(i);
}
}
return false;
}
int AdBlockCustomList::addRule(AdBlockRule* rule)
{
m_rules.append(rule);
emit subscriptionChanged();
if (rule->isCssRule())
mApp->reloadUserStyleSheet();
return m_rules.count() - 1;
}
bool AdBlockCustomList::removeRule(int offset)
{
if (!QzTools::containsIndex(m_rules, offset)) {
return false;
}
AdBlockRule* rule = m_rules.at(offset);
const QString filter = rule->filter();
m_rules.remove(offset);
emit subscriptionChanged();
if (rule->isCssRule())
mApp->reloadUserStyleSheet();
AdBlockManager::instance()->removeDisabledRule(filter);
delete rule;
return true;
}
const AdBlockRule* AdBlockCustomList::replaceRule(AdBlockRule* rule, int offset)
{
if (!QzTools::containsIndex(m_rules, offset)) {
return 0;
}
AdBlockRule* oldRule = m_rules.at(offset);
m_rules[offset] = rule;
emit subscriptionChanged();
if (rule->isCssRule() || oldRule->isCssRule())
mApp->reloadUserStyleSheet();
delete oldRule;
return m_rules[offset];
}

View file

@ -0,0 +1,136 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2016 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
/**
* Copyright (c) 2009, Benjamin C. Meyer <ben@meyerhome.net>
*
* 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 <QVector>
#include <QUrl>
#include "qzcommon.h"
#include "adblockrule.h"
#include "adblocksearchtree.h"
class QUrl;
class QNetworkReply;
class QUPZILLA_EXPORT AdBlockSubscription : public QObject
{
Q_OBJECT
public:
explicit AdBlockSubscription(const QString &title, QObject* parent = 0);
~AdBlockSubscription();
QString title() const;
QString filePath() const;
void setFilePath(const QString &path);
QUrl url() const;
void setUrl(const QUrl &url);
virtual void loadSubscription(const QStringList &disabledRules);
virtual void saveSubscription();
const AdBlockRule* rule(int offset) const;
QVector<AdBlockRule*> allRules() const;
const AdBlockRule* enableRule(int offset);
const AdBlockRule* disableRule(int offset);
virtual bool canEditRules() const;
virtual bool canBeRemoved() const;
virtual int addRule(AdBlockRule* rule);
virtual bool removeRule(int offset);
virtual const AdBlockRule* replaceRule(AdBlockRule* rule, int offset);
public slots:
void updateSubscription();
signals:
void subscriptionChanged();
void subscriptionUpdated();
void subscriptionError(const QString &message);
protected slots:
void subscriptionDownloaded();
protected:
virtual bool saveDownloadedData(const QByteArray &data);
QNetworkReply *m_reply;
QVector<AdBlockRule*> m_rules;
private:
QString m_title;
QString m_filePath;
QUrl m_url;
bool m_updated;
};
class AdBlockCustomList : public AdBlockSubscription
{
Q_OBJECT
public:
explicit AdBlockCustomList(QObject* parent = 0);
void loadSubscription(const QStringList &disabledRules);
void saveSubscription();
bool canEditRules() const;
bool canBeRemoved() const;
bool containsFilter(const QString &filter) const;
bool removeFilter(const QString &filter);
int addRule(AdBlockRule* rule);
bool removeRule(int offset);
const AdBlockRule* replaceRule(AdBlockRule* rule, int offset);
};
#endif // ADBLOCKSUBSCRIPTION_H

View file

@ -0,0 +1,266 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "adblocktreewidget.h"
#include "adblocksubscription.h"
#include <QMenu>
#include <QKeyEvent>
#include <QClipboard>
#include <QApplication>
#include <QInputDialog>
AdBlockTreeWidget::AdBlockTreeWidget(AdBlockSubscription* subscription, QWidget* parent)
: TreeWidget(parent)
, m_subscription(subscription)
, m_topItem(0)
, m_itemChangingBlock(false)
{
setContextMenuPolicy(Qt::CustomContextMenu);
setDefaultItemShowMode(TreeWidget::ItemsExpanded);
setHeaderHidden(true);
setAlternatingRowColors(true);
setLayoutDirection(Qt::LeftToRight);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint)));
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(itemChanged(QTreeWidgetItem*)));
connect(m_subscription, SIGNAL(subscriptionUpdated()), this, SLOT(subscriptionUpdated()));
connect(m_subscription, SIGNAL(subscriptionError(QString)), this, SLOT(subscriptionError(QString)));
}
AdBlockSubscription* AdBlockTreeWidget::subscription() const
{
return m_subscription;
}
void AdBlockTreeWidget::showRule(const AdBlockRule* rule)
{
if (!m_topItem && rule) {
m_ruleToBeSelected = rule->filter();
}
else if (!m_ruleToBeSelected.isEmpty()) {
QList<QTreeWidgetItem*> items = findItems(m_ruleToBeSelected, Qt::MatchRecursive);
if (!items.isEmpty()) {
QTreeWidgetItem* item = items.at(0);
setCurrentItem(item);
scrollToItem(item, QAbstractItemView::PositionAtCenter);
}
m_ruleToBeSelected.clear();
}
}
void AdBlockTreeWidget::contextMenuRequested(const QPoint &pos)
{
if (!m_subscription->canEditRules()) {
return;
}
QTreeWidgetItem* item = itemAt(pos);
if (!item) {
return;
}
QMenu menu;
menu.addAction(tr("Add Rule"), this, SLOT(addRule()));
menu.addSeparator();
QAction* deleteAction = menu.addAction(tr("Remove Rule"), this, SLOT(removeRule()));
if (!item->parent()) {
deleteAction->setDisabled(true);
}
menu.exec(viewport()->mapToGlobal(pos));
}
void AdBlockTreeWidget::itemChanged(QTreeWidgetItem* item)
{
if (!item || m_itemChangingBlock) {
return;
}
m_itemChangingBlock = true;
int offset = item->data(0, Qt::UserRole + 10).toInt();
const AdBlockRule* oldRule = m_subscription->rule(offset);
if (item->checkState(0) == Qt::Unchecked && oldRule->isEnabled()) {
// Disable rule
const AdBlockRule* rule = m_subscription->disableRule(offset);
adjustItemFeatures(item, rule);
}
else if (item->checkState(0) == Qt::Checked && !oldRule->isEnabled()) {
// Enable rule
const AdBlockRule* rule = m_subscription->enableRule(offset);
adjustItemFeatures(item, rule);
}
else if (m_subscription->canEditRules()) {
// Custom rule has been changed
AdBlockRule* newRule = new AdBlockRule(item->text(0), m_subscription);
const AdBlockRule* rule = m_subscription->replaceRule(newRule, offset);
adjustItemFeatures(item, rule);
}
m_itemChangingBlock = false;
}
void AdBlockTreeWidget::copyFilter()
{
QTreeWidgetItem* item = currentItem();
if (!item) {
return;
}
QApplication::clipboard()->setText(item->text(0));
}
void AdBlockTreeWidget::addRule()
{
if (!m_subscription->canEditRules()) {
return;
}
QString newRule = QInputDialog::getText(this, tr("Add Custom Rule"), tr("Please write your rule here:"));
if (newRule.isEmpty()) {
return;
}
AdBlockRule* rule = new AdBlockRule(newRule, m_subscription);
int offset = m_subscription->addRule(rule);
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, newRule);
item->setData(0, Qt::UserRole + 10, offset);
item->setFlags(item->flags() | Qt::ItemIsEditable);
m_itemChangingBlock = true;
m_topItem->addChild(item);
m_itemChangingBlock = false;
adjustItemFeatures(item, rule);
}
void AdBlockTreeWidget::removeRule()
{
QTreeWidgetItem* item = currentItem();
if (!item || !m_subscription->canEditRules() || item == m_topItem) {
return;
}
int offset = item->data(0, Qt::UserRole + 10).toInt();
m_subscription->removeRule(offset);
deleteItem(item);
}
void AdBlockTreeWidget::subscriptionUpdated()
{
refresh();
m_itemChangingBlock = true;
m_topItem->setText(0, tr("%1 (recently updated)").arg(m_subscription->title()));
m_itemChangingBlock = false;
}
void AdBlockTreeWidget::subscriptionError(const QString &message)
{
refresh();
m_itemChangingBlock = true;
m_topItem->setText(0, tr("%1 (Error: %2)").arg(m_subscription->title(), message));
m_itemChangingBlock = false;
}
void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule* rule)
{
if (!rule->isEnabled()) {
QFont font;
font.setItalic(true);
item->setForeground(0, QColor(Qt::gray));
if (!rule->isComment()) {
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(0, Qt::Unchecked);
item->setFont(0, font);
}
return;
}
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(0, Qt::Checked);
if (rule->isException()) {
item->setForeground(0, QColor(Qt::darkGreen));
item->setFont(0, QFont());
}
else if (rule->isCssRule()) {
item->setForeground(0, QColor(Qt::darkBlue));
item->setFont(0, QFont());
}
}
void AdBlockTreeWidget::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_C && event->modifiers() & Qt::ControlModifier) {
copyFilter();
}
if (event->key() == Qt::Key_Delete) {
removeRule();
}
TreeWidget::keyPressEvent(event);
}
void AdBlockTreeWidget::refresh()
{
m_itemChangingBlock = true;
clear();
QFont boldFont;
boldFont.setBold(true);
m_topItem = new QTreeWidgetItem(this);
m_topItem->setText(0, m_subscription->title());
m_topItem->setFont(0, boldFont);
m_topItem->setExpanded(true);
addTopLevelItem(m_topItem);
const QVector<AdBlockRule*> &allRules = m_subscription->allRules();
int index = 0;
foreach (const AdBlockRule* rule, allRules) {
QTreeWidgetItem* item = new QTreeWidgetItem(m_topItem);
item->setText(0, rule->filter());
item->setData(0, Qt::UserRole + 10, index);
if (m_subscription->canEditRules()) {
item->setFlags(item->flags() | Qt::ItemIsEditable);
}
adjustItemFeatures(item, rule);
++index;
}
showRule(0);
m_itemChangingBlock = false;
}

View file

@ -0,0 +1,61 @@
/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef ADBLOCKTREEWIDGET_H
#define ADBLOCKTREEWIDGET_H
#include "qzcommon.h"
#include "treewidget.h"
class AdBlockSubscription;
class AdBlockRule;
class QUPZILLA_EXPORT AdBlockTreeWidget : public TreeWidget
{
Q_OBJECT
public:
explicit AdBlockTreeWidget(AdBlockSubscription* subscription, QWidget* parent = 0);
AdBlockSubscription* subscription() const;
void showRule(const AdBlockRule* rule);
void refresh();
public slots:
void addRule();
void removeRule();
private slots:
void contextMenuRequested(const QPoint &pos);
void itemChanged(QTreeWidgetItem* item);
void copyFilter();
void subscriptionUpdated();
void subscriptionError(const QString &message);
private:
void adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule* rule);
void keyPressEvent(QKeyEvent* event);
AdBlockSubscription* m_subscription;
QTreeWidgetItem* m_topItem;
QString m_ruleToBeSelected;
bool m_itemChangingBlock;
};
#endif // ADBLOCKTREEWIDGET_H

View file

@ -0,0 +1,32 @@
/* ============================================================
* QupZilla - QtWebEngine based browser
* Copyright (C) 2015 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "adblockurlinterceptor.h"
#include "adblockmanager.h"
AdBlockUrlInterceptor::AdBlockUrlInterceptor(AdBlockManager *manager)
: UrlInterceptor(manager)
, m_manager(manager)
{
}
void AdBlockUrlInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info)
{
if (m_manager->block(info))
info.block(true);
}

View file

@ -0,0 +1,38 @@
/* ============================================================
* QupZilla - QtWebEngine based browser
* Copyright (C) 2015 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef ADBLOCKURLINTERCEPTOR_H
#define ADBLOCKURLINTERCEPTOR_H
#include "urlinterceptor.h"
#include "qzcommon.h"
class AdBlockManager;
class QUPZILLA_EXPORT AdBlockUrlInterceptor : public UrlInterceptor
{
public:
explicit AdBlockUrlInterceptor(AdBlockManager* manager);
void interceptRequest(QWebEngineUrlRequestInfo &info);
private:
AdBlockManager *m_manager;
};
#endif // ADBLOCKURLINTERCEPTOR_H

View file

@ -0,0 +1,59 @@
/* ============================================================
* QupZilla - Qt web browser
* Copyright (C) 2015-2017 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "networkurlinterceptor.h"
#include "urlinterceptor.h"
#include "settings.h"
#include "mainapplication.h"
#include "useragentmanager.h"
NetworkUrlInterceptor::NetworkUrlInterceptor(QObject *parent)
: QWebEngineUrlRequestInterceptor(parent)
, m_sendDNT(false)
{
}
void NetworkUrlInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info)
{
if (m_sendDNT)
info.setHttpHeader(QByteArrayLiteral("DNT"), QByteArrayLiteral("1"));
info.setHttpHeader(QByteArrayLiteral("User-Agent"), mApp->userAgentManager()->userAgentForUrl(info.firstPartyUrl()).toUtf8());
foreach (UrlInterceptor *interceptor, m_interceptors) {
interceptor->interceptRequest(info);
}
}
void NetworkUrlInterceptor::installUrlInterceptor(UrlInterceptor *interceptor)
{
if (!m_interceptors.contains(interceptor))
m_interceptors.append(interceptor);
}
void NetworkUrlInterceptor::removeUrlInterceptor(UrlInterceptor *interceptor)
{
m_interceptors.removeOne(interceptor);
}
void NetworkUrlInterceptor::loadSettings()
{
Settings settings;
settings.beginGroup("Web-Browser-Settings");
m_sendDNT = settings.value("DoNotTrack", false).toBool();
settings.endGroup();
}

View file

@ -0,0 +1,45 @@
/* ============================================================
* QupZilla - QtWebEngine based browser
* Copyright (C) 2015 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef NETWORKURLINTERCEPTOR_H
#define NETWORKURLINTERCEPTOR_H
#include <QWebEngineUrlRequestInterceptor>
#include "qzcommon.h"
class UrlInterceptor;
class QUPZILLA_EXPORT NetworkUrlInterceptor : public QWebEngineUrlRequestInterceptor
{
public:
explicit NetworkUrlInterceptor(QObject* parent = Q_NULLPTR);
void interceptRequest(QWebEngineUrlRequestInfo &info) Q_DECL_OVERRIDE;
void installUrlInterceptor(UrlInterceptor *interceptor);
void removeUrlInterceptor(UrlInterceptor *interceptor);
void loadSettings();
private:
QList<UrlInterceptor*> m_interceptors;
bool m_sendDNT;
};
#endif // NETWORKURLINTERCEPTOR_H

View file

@ -0,0 +1,32 @@
/* ============================================================
* QupZilla - QtWebEngine based browser
* Copyright (C) 2015 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#ifndef URLINTERCEPTOR_H
#define URLINTERCEPTOR_H
#include <QObject>
#include <QWebEngineUrlRequestInfo>
class UrlInterceptor : public QObject
{
public:
explicit UrlInterceptor(QObject *parent = Q_NULLPTR) : QObject(parent) { }
virtual void interceptRequest(QWebEngineUrlRequestInfo &info) = 0;
};
#endif // URLINTERCEPTOR_H