save¨
This commit is contained in:
parent
068183f0a6
commit
3a21265f0c
32 changed files with 132 additions and 3071 deletions
|
@ -1,5 +1,4 @@
|
||||||
// Simple local HTTP server providing ad-blocking
|
// Simple local HTTP server providing ad-blocking functionality via https://github.com/cliqz-oss/adblocker
|
||||||
// functionality via https://github.com/cliqz-oss/adblocker
|
|
||||||
//
|
//
|
||||||
// How to install:
|
// How to install:
|
||||||
// npm i -g @cliqz/adblocker
|
// npm i -g @cliqz/adblocker
|
||||||
|
@ -8,10 +7,16 @@
|
||||||
// npm i -g node-fetch
|
// npm i -g node-fetch
|
||||||
//
|
//
|
||||||
// How to run:
|
// How to run:
|
||||||
// NODE_PATH="C:\Users\<user>\AppData\Roaming\npm\node_modules" node ./adblock-server.js
|
// NODE_PATH="C:\Users\<user>\AppData\Roaming\npm\node_modules" node ./adblock-server.js "<port>" "<filters-file-path>"
|
||||||
//
|
//
|
||||||
// How to use:
|
// How to use:
|
||||||
// curl -i -X POST --data '{"url": "http://gompoozu.net", "url_type": "main_frame"}' 'http://localhost:48484'
|
// curl -i -X POST --data '
|
||||||
|
// {
|
||||||
|
// "url": "http://gompoozu.net",
|
||||||
|
// "url_type": "main_frame",
|
||||||
|
// "filter": true,
|
||||||
|
// "cosmetic": true
|
||||||
|
// }' 'http://localhost:<port>'
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const psl = require('psl');
|
const psl = require('psl');
|
||||||
|
@ -21,15 +26,10 @@ const concat = require('concat-stream');
|
||||||
const constants = require('node:http2');
|
const constants = require('node:http2');
|
||||||
const fetch = require("node-fetch");
|
const fetch = require("node-fetch");
|
||||||
|
|
||||||
let engine;
|
const port = process.argv[2];
|
||||||
|
const filtersFile = process.argv[3];
|
||||||
adblock.FiltersEngine.fromLists(fetch, [
|
const engine = adblock.FiltersEngine.parse(fs.readFileSync(filtersFile, 'utf-8'));
|
||||||
'https://easylist.to/easylist/easylist.txt',
|
|
||||||
'https://raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters.txt',
|
|
||||||
]).then(function (res) { engine = res; });
|
|
||||||
|
|
||||||
const hostname = '127.0.0.1';
|
const hostname = '127.0.0.1';
|
||||||
const port = 48484;
|
|
||||||
|
|
||||||
const server = http.createServer((req, res) => {
|
const server = http.createServer((req, res) => {
|
||||||
try {
|
try {
|
||||||
|
@ -41,19 +41,22 @@ const server = http.createServer((req, res) => {
|
||||||
const jsonStruct = JSON.parse(jsonData.toString());
|
const jsonStruct = JSON.parse(jsonData.toString());
|
||||||
|
|
||||||
const askUrl = jsonStruct['url'];
|
const askUrl = jsonStruct['url'];
|
||||||
|
const askFilter = jsonStruct['filter'];
|
||||||
const askCosmetic = jsonStruct['cosmetic'];
|
const askCosmetic = jsonStruct['cosmetic'];
|
||||||
const askUrlType = jsonStruct['url_type'];
|
const askUrlType = jsonStruct['url_type'];
|
||||||
const fullUrl = new URL(askUrl);
|
const fullUrl = new URL(askUrl);
|
||||||
|
|
||||||
resultJson = {};
|
resultJson = {};
|
||||||
|
|
||||||
const adblockMatch = engine.match(adblock.Request.fromRawDetails({
|
if (askFilter) {
|
||||||
type: askUrlType,
|
const adblockMatch = engine.match(adblock.Request.fromRawDetails({
|
||||||
url: askUrl,
|
type: askUrlType,
|
||||||
}));
|
url: askUrl,
|
||||||
|
}));
|
||||||
|
|
||||||
resultJson["filter"] = adblockMatch;
|
resultJson["filter"] = adblockMatch;
|
||||||
console.log(`adblocker: Filter is:\n${JSON.stringify(adblockMatch)}.`)
|
console.log(`adblocker: Filter is:\n${JSON.stringify(adblockMatch)}.`)
|
||||||
|
}
|
||||||
|
|
||||||
if (askCosmetic) {
|
if (askCosmetic) {
|
||||||
const adblockCosmetic = engine.getCosmeticsFilters({
|
const adblockCosmetic = engine.getCosmeticsFilters({
|
||||||
|
@ -65,7 +68,7 @@ const server = http.createServer((req, res) => {
|
||||||
resultJson["cosmetic"] = adblockCosmetic;
|
resultJson["cosmetic"] = adblockCosmetic;
|
||||||
console.log(`adblocker: Cosmetic is:\n${JSON.stringify(adblockCosmetic)}.`)
|
console.log(`adblocker: Cosmetic is:\n${JSON.stringify(adblockCosmetic)}.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
res.statusCode = 200;
|
res.statusCode = 200;
|
||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
res.end(JSON.stringify(resultJson));
|
res.end(JSON.stringify(resultJson));
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#define SERVICE_CODE_INOREADER "inoreader"
|
#define SERVICE_CODE_INOREADER "inoreader"
|
||||||
#define SERVICE_CODE_GMAIL "gmail"
|
#define SERVICE_CODE_GMAIL "gmail"
|
||||||
|
|
||||||
#define ADBLOCK_HOWTO_FILTERS "https://help.eyeo.com/en/adblockplus/how-to-write-filters"
|
#define ADBLOCK_HOWTO "https://github.com/martinrotter/rssguard/blob/master/resources/docs/Documentation.md#adblock"
|
||||||
#define ADBLOCK_UPDATE_DAYS_INTERVAL 14
|
#define ADBLOCK_UPDATE_DAYS_INTERVAL 14
|
||||||
#define ADBLOCK_ICON_ACTIVE "adblock"
|
#define ADBLOCK_ICON_ACTIVE "adblock"
|
||||||
#define ADBLOCK_ICON_DISABLED "adblock-disabled"
|
#define ADBLOCK_ICON_DISABLED "adblock-disabled"
|
||||||
|
|
|
@ -1,202 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "gui/reusable/treewidget.h"
|
|
||||||
|
|
||||||
#include <QMouseEvent>
|
|
||||||
|
|
||||||
TreeWidget::TreeWidget(QWidget* parent)
|
|
||||||
: QTreeWidget(parent), m_refreshAllItemsNeeded(true), m_showMode(ItemShowMode::ItemsCollapsed) {
|
|
||||||
connect(this, &TreeWidget::itemChanged, this, &TreeWidget::sheduleRefresh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::clear() {
|
|
||||||
QTreeWidget::clear();
|
|
||||||
m_allTreeItems.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::sheduleRefresh() {
|
|
||||||
m_refreshAllItemsNeeded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::addTopLevelItem(QTreeWidgetItem* item) {
|
|
||||||
m_allTreeItems.append(item);
|
|
||||||
QTreeWidget::addTopLevelItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::addTopLevelItems(const QList<QTreeWidgetItem*>& items) {
|
|
||||||
m_allTreeItems.append(items);
|
|
||||||
QTreeWidget::addTopLevelItems(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::insertTopLevelItem(int index, QTreeWidgetItem* item) {
|
|
||||||
m_allTreeItems.append(item);
|
|
||||||
QTreeWidget::insertTopLevelItem(index, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::insertTopLevelItems(int index, const QList<QTreeWidgetItem*>& items) {
|
|
||||||
m_allTreeItems.append(items);
|
|
||||||
QTreeWidget::insertTopLevelItems(index, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::mousePressEvent(QMouseEvent* event) {
|
|
||||||
if (event->modifiers() == Qt::ControlModifier) {
|
|
||||||
emit itemControlClicked(itemAt(event->pos()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->buttons() == Qt::MiddleButton) {
|
|
||||||
emit itemMiddleButtonClicked(itemAt(event->pos()));
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidget::mousePressEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::iterateAllItems(QTreeWidgetItem* parent) {
|
|
||||||
int count = parent ? parent->childCount() : topLevelItemCount();
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QTreeWidgetItem* item = parent ? parent->child(i) : topLevelItem(i);
|
|
||||||
|
|
||||||
if (item->childCount() == 0) {
|
|
||||||
m_allTreeItems.append(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
iterateAllItems(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QTreeWidgetItem*> TreeWidget::allItems() {
|
|
||||||
if (m_refreshAllItemsNeeded) {
|
|
||||||
m_allTreeItems.clear();
|
|
||||||
iterateAllItems(0);
|
|
||||||
m_refreshAllItemsNeeded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_allTreeItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::filterString(const QString& string) {
|
|
||||||
QList<QTreeWidgetItem*> _allItems = allItems();
|
|
||||||
QList<QTreeWidgetItem*> parents;
|
|
||||||
bool stringIsEmpty = string.isEmpty();
|
|
||||||
|
|
||||||
for (QTreeWidgetItem* item : _allItems) {
|
|
||||||
bool containsString = stringIsEmpty || item->text(0).contains(string, Qt::CaseSensitivity::CaseInsensitive);
|
|
||||||
|
|
||||||
if (containsString) {
|
|
||||||
item->setHidden(false);
|
|
||||||
|
|
||||||
if (item->parent()) {
|
|
||||||
if (!parents.contains(item->parent())) {
|
|
||||||
parents << item->parent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item->setHidden(true);
|
|
||||||
|
|
||||||
if (item->parent()) {
|
|
||||||
item->parent()->setHidden(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < parents.size(); ++i) {
|
|
||||||
QTreeWidgetItem* parentItem = parents.at(i);
|
|
||||||
|
|
||||||
parentItem->setHidden(false);
|
|
||||||
|
|
||||||
if (stringIsEmpty) {
|
|
||||||
parentItem->setExpanded(m_showMode == ItemShowMode::ItemsExpanded);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
parentItem->setExpanded(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentItem->parent() && !parents.contains(parentItem->parent())) {
|
|
||||||
parents << parentItem->parent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TreeWidget::appendToParentItem(const QString& parentText, QTreeWidgetItem* item) {
|
|
||||||
QList<QTreeWidgetItem*> list = findItems(parentText, Qt::MatchFlag::MatchExactly);
|
|
||||||
|
|
||||||
if (list.count() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidgetItem* parentItem = list.at(0);
|
|
||||||
|
|
||||||
if (!parentItem) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_allTreeItems.append(item);
|
|
||||||
parentItem->addChild(item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TreeWidget::appendToParentItem(QTreeWidgetItem* parent, QTreeWidgetItem* item) {
|
|
||||||
if (!parent || parent->treeWidget() != this) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_allTreeItems.append(item);
|
|
||||||
parent->addChild(item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TreeWidget::prependToParentItem(const QString& parentText, QTreeWidgetItem* item) {
|
|
||||||
QList<QTreeWidgetItem*> list = findItems(parentText, Qt::MatchFlag::MatchExactly);
|
|
||||||
|
|
||||||
if (list.count() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidgetItem* parentItem = list.at(0);
|
|
||||||
|
|
||||||
if (!parentItem) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_allTreeItems.append(item);
|
|
||||||
parentItem->insertChild(0, item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TreeWidget::prependToParentItem(QTreeWidgetItem* parent, QTreeWidgetItem* item) {
|
|
||||||
if (!parent || parent->treeWidget() != this) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_allTreeItems.append(item);
|
|
||||||
parent->insertChild(0, item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::deleteItem(QTreeWidgetItem* item) {
|
|
||||||
m_refreshAllItemsNeeded = true;
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TreeWidget::deleteItems(const QList<QTreeWidgetItem*>& items) {
|
|
||||||
m_refreshAllItemsNeeded = true;
|
|
||||||
qDeleteAll(items);
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#ifndef BOOKMARKSTREEWIDGET_H
|
|
||||||
#define BOOKMARKSTREEWIDGET_H
|
|
||||||
|
|
||||||
#include <QTreeWidget>
|
|
||||||
|
|
||||||
class TreeWidget : public QTreeWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit TreeWidget(QWidget* parent = nullptr);
|
|
||||||
|
|
||||||
enum class ItemShowMode {
|
|
||||||
ItemsCollapsed = 0,
|
|
||||||
ItemsExpanded = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
ItemShowMode defaultItemShowMode();
|
|
||||||
void setDefaultItemShowMode(ItemShowMode mode);
|
|
||||||
QList<QTreeWidgetItem*> allItems();
|
|
||||||
|
|
||||||
bool appendToParentItem(const QString& parentText, QTreeWidgetItem* item);
|
|
||||||
bool appendToParentItem(QTreeWidgetItem* parent, QTreeWidgetItem* item);
|
|
||||||
bool prependToParentItem(const QString& parentText, QTreeWidgetItem* item);
|
|
||||||
bool prependToParentItem(QTreeWidgetItem* parent, QTreeWidgetItem* item);
|
|
||||||
|
|
||||||
void addTopLevelItem(QTreeWidgetItem* item);
|
|
||||||
void addTopLevelItems(const QList<QTreeWidgetItem*>& items);
|
|
||||||
void insertTopLevelItem(int index, QTreeWidgetItem* item);
|
|
||||||
void insertTopLevelItems(int index, const QList<QTreeWidgetItem*>& items);
|
|
||||||
|
|
||||||
void deleteItem(QTreeWidgetItem* item);
|
|
||||||
void deleteItems(const QList<QTreeWidgetItem*>& items);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void itemControlClicked(QTreeWidgetItem* item);
|
|
||||||
void itemMiddleButtonClicked(QTreeWidgetItem* item);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void filterString(const QString& string);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void sheduleRefresh();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void mousePressEvent(QMouseEvent* event);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void iterateAllItems(QTreeWidgetItem* parent);
|
|
||||||
|
|
||||||
bool m_refreshAllItemsNeeded;
|
|
||||||
QList<QTreeWidgetItem*> m_allTreeItems;
|
|
||||||
ItemShowMode m_showMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline TreeWidget::ItemShowMode TreeWidget::defaultItemShowMode() {
|
|
||||||
return m_showMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void TreeWidget::setDefaultItemShowMode(TreeWidget::ItemShowMode mode) {
|
|
||||||
m_showMode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // BOOKMARKSTREEWIDGET_H
|
|
|
@ -74,7 +74,6 @@ HEADERS += core/feeddownloader.h \
|
||||||
gui/dialogs/formrestoredatabasesettings.h \
|
gui/dialogs/formrestoredatabasesettings.h \
|
||||||
gui/dialogs/formsettings.h \
|
gui/dialogs/formsettings.h \
|
||||||
gui/dialogs/formupdate.h \
|
gui/dialogs/formupdate.h \
|
||||||
gui/reusable/edittableview.h \
|
|
||||||
gui/feedmessageviewer.h \
|
gui/feedmessageviewer.h \
|
||||||
gui/toolbars/feedstoolbar.h \
|
gui/toolbars/feedstoolbar.h \
|
||||||
gui/feedsview.h \
|
gui/feedsview.h \
|
||||||
|
@ -82,6 +81,8 @@ HEADERS += core/feeddownloader.h \
|
||||||
gui/reusable/labelsmenu.h \
|
gui/reusable/labelsmenu.h \
|
||||||
gui/reusable/labelwithstatus.h \
|
gui/reusable/labelwithstatus.h \
|
||||||
gui/reusable/lineeditwithstatus.h \
|
gui/reusable/lineeditwithstatus.h \
|
||||||
|
gui/reusable/squeezelabel.h \
|
||||||
|
gui/reusable/edittableview.h \
|
||||||
gui/messagebox.h \
|
gui/messagebox.h \
|
||||||
gui/reusable/messagecountspinbox.h \
|
gui/reusable/messagecountspinbox.h \
|
||||||
gui/messagepreviewer.h \
|
gui/messagepreviewer.h \
|
||||||
|
@ -101,7 +102,6 @@ HEADERS += core/feeddownloader.h \
|
||||||
gui/settings/settingslocalization.h \
|
gui/settings/settingslocalization.h \
|
||||||
gui/settings/settingspanel.h \
|
gui/settings/settingspanel.h \
|
||||||
gui/settings/settingsshortcuts.h \
|
gui/settings/settingsshortcuts.h \
|
||||||
gui/reusable/squeezelabel.h \
|
|
||||||
gui/toolbars/statusbar.h \
|
gui/toolbars/statusbar.h \
|
||||||
gui/reusable/styleditemdelegatewithoutfocus.h \
|
gui/reusable/styleditemdelegatewithoutfocus.h \
|
||||||
gui/systemtrayicon.h \
|
gui/systemtrayicon.h \
|
||||||
|
@ -252,13 +252,14 @@ SOURCES += core/feeddownloader.cpp \
|
||||||
gui/dialogs/formrestoredatabasesettings.cpp \
|
gui/dialogs/formrestoredatabasesettings.cpp \
|
||||||
gui/dialogs/formsettings.cpp \
|
gui/dialogs/formsettings.cpp \
|
||||||
gui/dialogs/formupdate.cpp \
|
gui/dialogs/formupdate.cpp \
|
||||||
gui/reusable/edittableview.cpp \
|
|
||||||
gui/feedmessageviewer.cpp \
|
gui/feedmessageviewer.cpp \
|
||||||
gui/toolbars/feedstoolbar.cpp \
|
gui/toolbars/feedstoolbar.cpp \
|
||||||
gui/feedsview.cpp \
|
gui/feedsview.cpp \
|
||||||
gui/guiutilities.cpp \
|
gui/guiutilities.cpp \
|
||||||
gui/reusable/labelsmenu.cpp \
|
gui/reusable/labelsmenu.cpp \
|
||||||
|
gui/reusable/edittableview.cpp \
|
||||||
gui/reusable/labelwithstatus.cpp \
|
gui/reusable/labelwithstatus.cpp \
|
||||||
|
gui/reusable/squeezelabel.cpp \
|
||||||
gui/reusable/lineeditwithstatus.cpp \
|
gui/reusable/lineeditwithstatus.cpp \
|
||||||
gui/messagebox.cpp \
|
gui/messagebox.cpp \
|
||||||
gui/reusable/messagecountspinbox.cpp \
|
gui/reusable/messagecountspinbox.cpp \
|
||||||
|
@ -279,7 +280,6 @@ SOURCES += core/feeddownloader.cpp \
|
||||||
gui/settings/settingslocalization.cpp \
|
gui/settings/settingslocalization.cpp \
|
||||||
gui/settings/settingspanel.cpp \
|
gui/settings/settingspanel.cpp \
|
||||||
gui/settings/settingsshortcuts.cpp \
|
gui/settings/settingsshortcuts.cpp \
|
||||||
gui/reusable/squeezelabel.cpp \
|
|
||||||
gui/toolbars/statusbar.cpp \
|
gui/toolbars/statusbar.cpp \
|
||||||
gui/reusable/styleditemdelegatewithoutfocus.cpp \
|
gui/reusable/styleditemdelegatewithoutfocus.cpp \
|
||||||
gui/systemtrayicon.cpp \
|
gui/systemtrayicon.cpp \
|
||||||
|
@ -445,30 +445,18 @@ equals(USE_WEBENGINE, true) {
|
||||||
network-web/adblock/adblockdialog.h \
|
network-web/adblock/adblockdialog.h \
|
||||||
network-web/adblock/adblockicon.h \
|
network-web/adblock/adblockicon.h \
|
||||||
network-web/adblock/adblockmanager.h \
|
network-web/adblock/adblockmanager.h \
|
||||||
network-web/adblock/adblockmatcher.h \
|
|
||||||
network-web/adblock/adblockrule.h \
|
|
||||||
network-web/adblock/adblocksearchtree.h \
|
|
||||||
network-web/adblock/adblocksubscription.h \
|
|
||||||
network-web/adblock/adblocktreewidget.h \
|
|
||||||
network-web/adblock/adblockurlinterceptor.h \
|
network-web/adblock/adblockurlinterceptor.h \
|
||||||
network-web/adblock/adblockrequestinfo.h \
|
network-web/adblock/adblockrequestinfo.h \
|
||||||
network-web/urlinterceptor.h \
|
network-web/urlinterceptor.h \
|
||||||
network-web/networkurlinterceptor.h \
|
network-web/networkurlinterceptor.h
|
||||||
gui/reusable/treewidget.h
|
|
||||||
|
|
||||||
SOURCES += network-web/adblock/adblockaddsubscriptiondialog.cpp \
|
SOURCES += network-web/adblock/adblockaddsubscriptiondialog.cpp \
|
||||||
network-web/adblock/adblockdialog.cpp \
|
network-web/adblock/adblockdialog.cpp \
|
||||||
network-web/adblock/adblockicon.cpp \
|
network-web/adblock/adblockicon.cpp \
|
||||||
network-web/adblock/adblockmanager.cpp \
|
network-web/adblock/adblockmanager.cpp \
|
||||||
network-web/adblock/adblockmatcher.cpp \
|
|
||||||
network-web/adblock/adblockrule.cpp \
|
|
||||||
network-web/adblock/adblocksearchtree.cpp \
|
|
||||||
network-web/adblock/adblocksubscription.cpp \
|
|
||||||
network-web/adblock/adblocktreewidget.cpp \
|
|
||||||
network-web/adblock/adblockurlinterceptor.cpp \
|
network-web/adblock/adblockurlinterceptor.cpp \
|
||||||
network-web/adblock/adblockrequestinfo.cpp \
|
network-web/adblock/adblockrequestinfo.cpp \
|
||||||
network-web/networkurlinterceptor.cpp \
|
network-web/networkurlinterceptor.cpp
|
||||||
gui/reusable/treewidget.cpp
|
|
||||||
|
|
||||||
FORMS += network-web/adblock/adblockaddsubscriptiondialog.ui \
|
FORMS += network-web/adblock/adblockaddsubscriptiondialog.ui \
|
||||||
network-web/adblock/adblockdialog.ui
|
network-web/adblock/adblockdialog.ui
|
||||||
|
|
|
@ -500,10 +500,6 @@ void Application::onAboutToQuit() {
|
||||||
|
|
||||||
m_quitLogicDone = true;
|
m_quitLogicDone = true;
|
||||||
|
|
||||||
#if defined(USE_WEBENGINE)
|
|
||||||
m_webFactory->adBlock()->save();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Make sure that we obtain close lock BEFORE even trying to quit the application.
|
// Make sure that we obtain close lock BEFORE even trying to quit the application.
|
||||||
const bool locked_safely = feedUpdateLock()->tryLock(4 * CLOSE_LOCK_TIMEOUT);
|
const bool locked_safely = feedUpdateLock()->tryLock(4 * CLOSE_LOCK_TIMEOUT);
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,14 @@ DKEY Cookies::ID = "cookies";
|
||||||
// AdBlock.
|
// AdBlock.
|
||||||
DKEY AdBlock::ID = "adblock";
|
DKEY AdBlock::ID = "adblock";
|
||||||
|
|
||||||
DKEY AdBlock::DisabledRules = "disabled_rules";
|
|
||||||
DVALUE(QStringList) AdBlock::DisabledRulesDef = QStringList();
|
|
||||||
|
|
||||||
DKEY AdBlock::AdBlockEnabled = "enabled";
|
DKEY AdBlock::AdBlockEnabled = "enabled";
|
||||||
DVALUE(bool) AdBlock::AdBlockEnabledDef = false;
|
DVALUE(bool) AdBlock::AdBlockEnabledDef = false;
|
||||||
|
|
||||||
DKEY AdBlock::LastUpdatedOn = "last_updated_on";
|
DKEY AdBlock::FilterLists = "filter_lists";
|
||||||
DVALUE(QDateTime) AdBlock::LastUpdatedOnDef = QDateTime();
|
DVALUE(QStringList) AdBlock::FilterListsDef = {};
|
||||||
|
|
||||||
|
DKEY AdBlock::CustomFilters = "custom_filters";
|
||||||
|
DVALUE(QStringList) AdBlock::CustomFiltersDef = {};
|
||||||
|
|
||||||
// Feeds.
|
// Feeds.
|
||||||
DKEY Feeds::ID = "feeds";
|
DKEY Feeds::ID = "feeds";
|
||||||
|
|
|
@ -42,11 +42,11 @@ namespace AdBlock {
|
||||||
KEY AdBlockEnabled;
|
KEY AdBlockEnabled;
|
||||||
VALUE(bool) AdBlockEnabledDef;
|
VALUE(bool) AdBlockEnabledDef;
|
||||||
|
|
||||||
KEY DisabledRules;
|
KEY FilterLists;
|
||||||
VALUE(QStringList) DisabledRulesDef;
|
VALUE(QStringList) FilterListsDef;
|
||||||
|
|
||||||
KEY LastUpdatedOn;
|
KEY CustomFilters;
|
||||||
VALUE(QDateTime) LastUpdatedOnDef;
|
VALUE(QStringList) CustomFiltersDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Feeds.
|
// Feeds.
|
||||||
|
|
|
@ -60,10 +60,9 @@ QString SkinFactory::selectedSkinName() const {
|
||||||
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::Skin)).toString();
|
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::Skin)).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SkinFactory::adBlockedPage(const QString& subscription, const QString& rule) {
|
QString SkinFactory::adBlockedPage(const QString& url) {
|
||||||
const QString& adblocked = currentSkin().m_adblocked.arg(tr("This page was blocked by AdBlock"),
|
const QString& adblocked = currentSkin().m_adblocked.arg(tr("This page was blocked by AdBlock"),
|
||||||
tr(R"(Blocked by set: "%1"<br/>Blocked by filter: "%2")")
|
tr(R"(Blocked URL: "%1")").arg(url));
|
||||||
.arg(subscription, rule));
|
|
||||||
|
|
||||||
return currentSkin().m_layoutMarkupWrapper.arg(tr("This page was blocked by AdBlock"), adblocked);
|
return currentSkin().m_layoutMarkupWrapper.arg(tr("This page was blocked by AdBlock"), adblocked);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ class RSSGUARD_DLLSPEC SkinFactory : public QObject {
|
||||||
// after application restart.
|
// after application restart.
|
||||||
QString selectedSkinName() const;
|
QString selectedSkinName() const;
|
||||||
|
|
||||||
QString adBlockedPage(const QString& subscription, const QString& rule);
|
QString adBlockedPage(const QString& url);
|
||||||
|
|
||||||
// Gets skin about a particular skin.
|
// Gets skin about a particular skin.
|
||||||
Skin skinInfo(const QString& skin_name, bool* ok = nullptr) const;
|
Skin skinInfo(const QString& skin_name, bool* ok = nullptr) const;
|
||||||
|
|
|
@ -48,37 +48,23 @@ AdBlockAddSubscriptionDialog::AdBlockAddSubscriptionDialog(QWidget* parent)
|
||||||
tr("Add subscription"));
|
tr("Add subscription"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AdBlockAddSubscriptionDialog::title() const {
|
|
||||||
return m_ui->m_txtTitle->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AdBlockAddSubscriptionDialog::url() const {
|
QString AdBlockAddSubscriptionDialog::url() const {
|
||||||
return m_ui->m_txtUrl->text();
|
return m_ui->m_txtUrl->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockAddSubscriptionDialog::indexChanged(int index) {
|
void AdBlockAddSubscriptionDialog::indexChanged(int index) {
|
||||||
const Subscription subscription = m_knownSubscriptions.at(index);
|
const Subscription subscription = m_knownSubscriptions.at(index);
|
||||||
const int pos = subscription.m_title.indexOf(QLatin1Char('('));
|
|
||||||
|
|
||||||
if (pos > 0) {
|
|
||||||
m_ui->m_txtTitle->setText(subscription.m_title.left(pos).trimmed());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_ui->m_txtTitle->setText(subscription.m_title);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ui->m_txtUrl->setText(subscription.m_url);
|
m_ui->m_txtUrl->setText(subscription.m_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockAddSubscriptionDialog::presetsEnabledChanged(bool enabled) {
|
void AdBlockAddSubscriptionDialog::presetsEnabledChanged(bool enabled) {
|
||||||
m_ui->m_txtTitle->setEnabled(!enabled);
|
|
||||||
m_ui->m_txtUrl->setEnabled(!enabled);
|
m_ui->m_txtUrl->setEnabled(!enabled);
|
||||||
m_ui->m_cmbPresets->setEnabled(enabled);
|
m_ui->m_cmbPresets->setEnabled(enabled);
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
m_ui->m_txtTitle->clear();
|
|
||||||
m_ui->m_txtUrl->clear();
|
m_ui->m_txtUrl->clear();
|
||||||
m_ui->m_txtTitle->setFocus();
|
m_ui->m_txtUrl->setFocus();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
indexChanged(m_ui->m_cmbPresets->currentIndex());
|
indexChanged(m_ui->m_cmbPresets->currentIndex());
|
||||||
|
|
|
@ -36,7 +36,6 @@ class AdBlockAddSubscriptionDialog : public QDialog {
|
||||||
explicit AdBlockAddSubscriptionDialog(QWidget* parent = nullptr);
|
explicit AdBlockAddSubscriptionDialog(QWidget* parent = nullptr);
|
||||||
virtual ~AdBlockAddSubscriptionDialog();
|
virtual ~AdBlockAddSubscriptionDialog();
|
||||||
|
|
||||||
QString title() const;
|
|
||||||
QString url() const;
|
QString url() const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
@ -33,23 +33,6 @@
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="m_lblTitle">
|
|
||||||
<property name="text">
|
|
||||||
<string>Title</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>m_txtTitle</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLineEdit" name="m_txtTitle">
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Title of subscription</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="m_lblUrl">
|
<widget class="QLabel" name="m_lblUrl">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>URL</string>
|
<string>URL</string>
|
||||||
|
@ -59,14 +42,14 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QLineEdit" name="m_txtUrl">
|
<widget class="QLineEdit" name="m_txtUrl">
|
||||||
<property name="placeholderText">
|
<property name="placeholderText">
|
||||||
<string>Absolute URL to online subscription file</string>
|
<string>Absolute URL to online subscription file</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" colspan="2">
|
<item row="2" column="0" colspan="2">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
|
@ -79,7 +62,7 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0" colspan="2">
|
<item row="3" column="0" colspan="2">
|
||||||
<widget class="QDialogButtonBox" name="m_buttonBox">
|
<widget class="QDialogButtonBox" name="m_buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
|
@ -94,7 +77,6 @@
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>m_cbUsePredefined</tabstop>
|
<tabstop>m_cbUsePredefined</tabstop>
|
||||||
<tabstop>m_cmbPresets</tabstop>
|
<tabstop>m_cmbPresets</tabstop>
|
||||||
<tabstop>m_txtTitle</tabstop>
|
|
||||||
<tabstop>m_txtUrl</tabstop>
|
<tabstop>m_txtUrl</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
#include "network-web/adblock/adblockaddsubscriptiondialog.h"
|
#include "network-web/adblock/adblockaddsubscriptiondialog.h"
|
||||||
#include "network-web/adblock/adblockmanager.h"
|
#include "network-web/adblock/adblockmanager.h"
|
||||||
#include "network-web/adblock/adblocksubscription.h"
|
|
||||||
#include "network-web/adblock/adblocktreewidget.h"
|
|
||||||
|
|
||||||
#include "definitions/definitions.h"
|
#include "definitions/definitions.h"
|
||||||
#include "gui/guiutilities.h"
|
#include "gui/guiutilities.h"
|
||||||
|
@ -36,8 +34,7 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
AdBlockDialog::AdBlockDialog(QWidget* parent)
|
AdBlockDialog::AdBlockDialog(QWidget* parent)
|
||||||
: QDialog(parent), m_manager(qApp->web()->adBlock()), m_currentTreeWidget(nullptr), m_currentSubscription(nullptr),
|
: QDialog(parent), m_manager(qApp->web()->adBlock()), m_loaded(false), m_ui(new Ui::AdBlockDialog) {
|
||||||
m_loaded(false), m_ui(new Ui::AdBlockDialog) {
|
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
m_ui->m_cbEnable->setChecked(m_manager->isEnabled());
|
m_ui->m_cbEnable->setChecked(m_manager->isEnabled());
|
||||||
|
|
||||||
|
@ -50,50 +47,19 @@ AdBlockDialog::AdBlockDialog(QWidget* parent)
|
||||||
btn_options->setText(tr("Options"));
|
btn_options->setText(tr("Options"));
|
||||||
auto* menu = new QMenu(btn_options);
|
auto* menu = new QMenu(btn_options);
|
||||||
|
|
||||||
m_actionAddRule = menu->addAction(tr("Add rule"), this, &AdBlockDialog::addRule);
|
|
||||||
m_actionRemoveRule = menu->addAction(tr("Remove rule"), this, &AdBlockDialog::removeRule);
|
|
||||||
menu->addSeparator();
|
|
||||||
m_actionAddSubscription = menu->addAction(tr("Add subscription"), this, &AdBlockDialog::addSubscription);
|
m_actionAddSubscription = menu->addAction(tr("Add subscription"), this, &AdBlockDialog::addSubscription);
|
||||||
m_actionRemoveSubscription = menu->addAction(tr("Remove subscription"), this, &AdBlockDialog::removeSubscription);
|
|
||||||
menu->addAction(tr("Update subscriptions"), m_manager, &AdBlockManager::updateAllSubscriptions);
|
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
menu->addAction(tr("Learn about writing rules..."), this, &AdBlockDialog::learnAboutRules);
|
menu->addAction(tr("Learn about writing rules..."), this, &AdBlockDialog::learnAboutRules);
|
||||||
|
|
||||||
btn_options->setMenu(menu);
|
btn_options->setMenu(menu);
|
||||||
|
|
||||||
connect(menu, &QMenu::aboutToShow, this, &AdBlockDialog::aboutToShowMenu);
|
|
||||||
connect(m_ui->m_cbEnable, &QCheckBox::toggled, this, &AdBlockDialog::enableAdBlock);
|
connect(m_ui->m_cbEnable, &QCheckBox::toggled, this, &AdBlockDialog::enableAdBlock);
|
||||||
connect(m_ui->m_tabSubscriptions, &QTabWidget::currentChanged, this, &AdBlockDialog::currentChanged);
|
|
||||||
connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &AdBlockDialog::close);
|
connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &AdBlockDialog::close);
|
||||||
|
|
||||||
load();
|
load();
|
||||||
m_ui->m_buttonBox->setFocus();
|
m_ui->m_buttonBox->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockDialog::showRule(const AdBlockRule* rule) const {
|
|
||||||
AdBlockSubscription* subscription = rule->subscription();
|
|
||||||
|
|
||||||
if (subscription != nullptr) {
|
|
||||||
for (int i = 0; i < m_ui->m_tabSubscriptions->count(); ++i) {
|
|
||||||
auto* tree_widget = qobject_cast<AdBlockTreeWidget*>(m_ui->m_tabSubscriptions->widget(i));
|
|
||||||
|
|
||||||
if (subscription == tree_widget->subscription()) {
|
|
||||||
tree_widget->showRule(rule);
|
|
||||||
m_ui->m_tabSubscriptions->setCurrentIndex(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockDialog::addRule() {
|
|
||||||
m_currentTreeWidget->addRule();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockDialog::removeRule() {
|
|
||||||
m_currentTreeWidget->removeRule();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockDialog::addSubscription() {
|
void AdBlockDialog::addSubscription() {
|
||||||
AdBlockAddSubscriptionDialog dialog(this);
|
AdBlockAddSubscriptionDialog dialog(this);
|
||||||
|
|
||||||
|
@ -101,28 +67,9 @@ void AdBlockDialog::addSubscription() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString title = dialog.title();
|
|
||||||
QString url = dialog.url();
|
QString url = dialog.url();
|
||||||
|
|
||||||
if (AdBlockSubscription* subscription = m_manager->addSubscription(title, url)) {
|
// TODO: add filter list.
|
||||||
auto* tree = new AdBlockTreeWidget(subscription, m_ui->m_tabSubscriptions);
|
|
||||||
int index = m_ui->m_tabSubscriptions->insertTab(m_ui->m_tabSubscriptions->count() - 1, tree, subscription->title());
|
|
||||||
|
|
||||||
m_ui->m_tabSubscriptions->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*>(m_ui->m_tabSubscriptions->widget(index));
|
|
||||||
m_currentSubscription = m_currentTreeWidget->subscription();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockDialog::enableAdBlock(bool state) {
|
void AdBlockDialog::enableAdBlock(bool state) {
|
||||||
|
@ -133,25 +80,8 @@ void AdBlockDialog::enableAdBlock(bool state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockDialog::aboutToShowMenu() {
|
|
||||||
bool subscriptionEditable = (m_currentSubscription != nullptr) && m_currentSubscription->canEditRules();
|
|
||||||
bool subscriptionRemovable = (m_currentSubscription != nullptr) && m_currentSubscription->canBeRemoved();
|
|
||||||
|
|
||||||
m_actionAddRule->setEnabled(subscriptionEditable);
|
|
||||||
m_actionRemoveRule->setEnabled(subscriptionEditable);
|
|
||||||
m_actionRemoveSubscription->setEnabled(subscriptionRemovable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockDialog::learnAboutRules() {
|
void AdBlockDialog::learnAboutRules() {
|
||||||
qApp->web()->openUrlInExternalBrowser(QSL(ADBLOCK_HOWTO_FILTERS));
|
qApp->web()->openUrlInExternalBrowser(QSL(ADBLOCK_HOWTO));
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockDialog::loadSubscriptions() {
|
|
||||||
for (int i = 0; i < m_ui->m_tabSubscriptions->count(); ++i) {
|
|
||||||
auto* tree_widget = qobject_cast<AdBlockTreeWidget*>(m_ui->m_tabSubscriptions->widget(i));
|
|
||||||
|
|
||||||
tree_widget->refresh();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockDialog::load() {
|
void AdBlockDialog::load() {
|
||||||
|
@ -159,14 +89,5 @@ void AdBlockDialog::load() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto subs = m_manager->subscriptions();
|
// TODO: load
|
||||||
|
|
||||||
for (AdBlockSubscription* subscription : qAsConst(subs)) {
|
|
||||||
auto* tree = new AdBlockTreeWidget(subscription, m_ui->m_tabSubscriptions);
|
|
||||||
|
|
||||||
m_ui->m_tabSubscriptions->addTab(tree, subscription->title());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_loaded = true;
|
|
||||||
QTimer::singleShot(50, this, &AdBlockDialog::loadSubscriptions);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,7 @@
|
||||||
|
|
||||||
#include "ui_adblockdialog.h"
|
#include "ui_adblockdialog.h"
|
||||||
|
|
||||||
class AdBlockSubscription;
|
|
||||||
class AdBlockTreeWidget;
|
|
||||||
class AdBlockManager;
|
class AdBlockManager;
|
||||||
class AdBlockRule;
|
|
||||||
|
|
||||||
class AdBlockDialog : public QDialog {
|
class AdBlockDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -35,34 +32,17 @@ class AdBlockDialog : public QDialog {
|
||||||
public:
|
public:
|
||||||
explicit AdBlockDialog(QWidget* parent = nullptr);
|
explicit AdBlockDialog(QWidget* parent = nullptr);
|
||||||
|
|
||||||
void showRule(const AdBlockRule* rule) const;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addRule();
|
|
||||||
void removeRule();
|
|
||||||
|
|
||||||
void addSubscription();
|
void addSubscription();
|
||||||
void removeSubscription();
|
|
||||||
|
|
||||||
void currentChanged(int index);
|
|
||||||
void enableAdBlock(bool state);
|
void enableAdBlock(bool state);
|
||||||
|
|
||||||
void aboutToShowMenu();
|
|
||||||
void learnAboutRules();
|
void learnAboutRules();
|
||||||
|
|
||||||
void loadSubscriptions();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AdBlockManager* m_manager;
|
AdBlockManager* m_manager;
|
||||||
AdBlockTreeWidget* m_currentTreeWidget;
|
|
||||||
AdBlockSubscription* m_currentSubscription;
|
|
||||||
QAction* m_actionAddRule;
|
|
||||||
QAction* m_actionRemoveRule;
|
|
||||||
QAction* m_actionAddSubscription;
|
QAction* m_actionAddSubscription;
|
||||||
QAction* m_actionRemoveSubscription;
|
|
||||||
bool m_loaded;
|
bool m_loaded;
|
||||||
|
|
||||||
Ui::AdBlockDialog* m_ui;
|
Ui::AdBlockDialog* m_ui;
|
||||||
|
|
|
@ -25,10 +25,30 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="m_tabSubscriptions">
|
<widget class="QTabWidget" name="m_tcSubscriptions">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>-1</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="QWidget" name="m_tabPredefinedLists">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Filter lists (list per line)</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="m_txtPredefined"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="m_tabCustomFilters">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Custom filters</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="m_txtCustom"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -24,14 +24,11 @@
|
||||||
#include "gui/webviewer.h"
|
#include "gui/webviewer.h"
|
||||||
#include "miscellaneous/application.h"
|
#include "miscellaneous/application.h"
|
||||||
#include "network-web/adblock/adblockmanager.h"
|
#include "network-web/adblock/adblockmanager.h"
|
||||||
#include "network-web/adblock/adblockrule.h"
|
|
||||||
#include "network-web/adblock/adblocksubscription.h"
|
|
||||||
#include "network-web/webpage.h"
|
#include "network-web/webpage.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
AdBlockIcon::AdBlockIcon(AdBlockManager* parent)
|
AdBlockIcon::AdBlockIcon(AdBlockManager* parent) : QAction(parent), m_manager(parent) {
|
||||||
: QAction(parent), m_manager(parent) {
|
|
||||||
setToolTip(tr("AdBlock lets you block unwanted content on web pages"));
|
setToolTip(tr("AdBlock lets you block unwanted content on web pages"));
|
||||||
setText(QSL("AdBlock"));
|
setText(QSL("AdBlock"));
|
||||||
setMenu(new QMenu());
|
setMenu(new QMenu());
|
||||||
|
@ -61,32 +58,34 @@ void AdBlockIcon::createMenu(QMenu* menu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
menu->clear();
|
menu->clear();
|
||||||
AdBlockCustomList* custom_list = m_manager->customList();
|
|
||||||
WebPage* page = qApp->mainForm()->tabWidget()->currentWidget()->webBrowser()->viewer()->page();
|
|
||||||
const QUrl page_url = page->url();
|
|
||||||
|
|
||||||
menu->addAction(tr("Show AdBlock &settings"), m_manager, &AdBlockManager::showDialog);
|
menu->addAction(tr("Show AdBlock &settings"), m_manager, &AdBlockManager::showDialog);
|
||||||
menu->addSeparator();
|
|
||||||
|
|
||||||
if (!page_url.host().isEmpty() && m_manager->isEnabled() && m_manager->canRunOnScheme(page_url.scheme())) {
|
/*
|
||||||
const QString host = page->url().host().contains(QLatin1String("www.")) ? page_url.host().mid(4) : page_url.host();
|
WebPage* page = qApp->mainForm()->tabWidget()->currentWidget()->webBrowser()->viewer()->page();
|
||||||
const QString host_filter = QString("@@||%1^$document").arg(host);
|
const QUrl page_url = page->url();
|
||||||
const QString page_filter = QString("@@|%1|$document").arg(page_url.toString());
|
AdBlockCustomList* custom_list = m_manager->customList();
|
||||||
QAction* act = menu->addAction(tr("Disable on %1").arg(host));
|
|
||||||
|
|
||||||
act->setCheckable(true);
|
menu->addSeparator();
|
||||||
act->setChecked(custom_list->containsFilter(host_filter));
|
|
||||||
act->setData(host_filter);
|
|
||||||
connect(act, &QAction::triggered, this, &AdBlockIcon::toggleCustomFilter);
|
|
||||||
|
|
||||||
act = menu->addAction(tr("Disable only on this page"));
|
if (!page_url.host().isEmpty() && m_manager->isEnabled() && m_manager->canRunOnScheme(page_url.scheme())) {
|
||||||
act->setCheckable(true);
|
const QString host = page->url().host().contains(QLatin1String("www.")) ? page_url.host().mid(4) : page_url.host();
|
||||||
act->setChecked(custom_list->containsFilter(page_filter));
|
const QString host_filter = QString("@@||%1^$document").arg(host);
|
||||||
act->setData(page_filter);
|
const QString page_filter = QString("@@|%1|$document").arg(page_url.toString());
|
||||||
connect(act, &QAction::triggered, this, &AdBlockIcon::toggleCustomFilter);
|
QAction* act = menu->addAction(tr("Disable on %1").arg(host));
|
||||||
|
|
||||||
menu->addSeparator();
|
act->setCheckable(true);
|
||||||
}
|
act->setChecked(custom_list->containsFilter(host_filter));
|
||||||
|
act->setData(host_filter);
|
||||||
|
connect(act, &QAction::triggered, this, &AdBlockIcon::toggleCustomFilter);
|
||||||
|
|
||||||
|
act = menu->addAction(tr("Disable only on this page"));
|
||||||
|
act->setCheckable(true);
|
||||||
|
act->setChecked(custom_list->containsFilter(page_filter));
|
||||||
|
act->setData(page_filter);
|
||||||
|
connect(act, &QAction::triggered, this, &AdBlockIcon::toggleCustomFilter);
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockIcon::showMenu(const QPoint& pos) {
|
void AdBlockIcon::showMenu(const QPoint& pos) {
|
||||||
|
@ -96,26 +95,6 @@ void AdBlockIcon::showMenu(const QPoint& pos) {
|
||||||
menu.exec(pos);
|
menu.exec(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockIcon::toggleCustomFilter() {
|
|
||||||
auto* action = qobject_cast<QAction*>(sender());
|
|
||||||
|
|
||||||
if (action == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString filter = action->data().toString();
|
|
||||||
AdBlockCustomList* custom_list = m_manager->customList();
|
|
||||||
|
|
||||||
if (custom_list->containsFilter(filter)) {
|
|
||||||
custom_list->removeFilter(filter);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto* rule = new AdBlockRule(filter, custom_list);
|
|
||||||
|
|
||||||
custom_list->addRule(rule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockIcon::setEnabled(bool enabled) {
|
void AdBlockIcon::setEnabled(bool enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
setIcon(qApp->icons()->miscIcon(ADBLOCK_ICON_ACTIVE));
|
setIcon(qApp->icons()->miscIcon(ADBLOCK_ICON_ACTIVE));
|
||||||
|
|
|
@ -37,7 +37,6 @@ class AdBlockIcon : public QAction {
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void showMenu(const QPoint& pos);
|
void showMenu(const QPoint& pos);
|
||||||
void toggleCustomFilter();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createMenu(QMenu* menu = nullptr);
|
void createMenu(QMenu* menu = nullptr);
|
||||||
|
|
|
@ -23,9 +23,7 @@
|
||||||
#include "miscellaneous/settings.h"
|
#include "miscellaneous/settings.h"
|
||||||
#include "network-web/adblock/adblockdialog.h"
|
#include "network-web/adblock/adblockdialog.h"
|
||||||
#include "network-web/adblock/adblockicon.h"
|
#include "network-web/adblock/adblockicon.h"
|
||||||
#include "network-web/adblock/adblockmatcher.h"
|
|
||||||
#include "network-web/adblock/adblockrequestinfo.h"
|
#include "network-web/adblock/adblockrequestinfo.h"
|
||||||
#include "network-web/adblock/adblocksubscription.h"
|
|
||||||
#include "network-web/adblock/adblockurlinterceptor.h"
|
#include "network-web/adblock/adblockurlinterceptor.h"
|
||||||
#include "network-web/networkurlinterceptor.h"
|
#include "network-web/networkurlinterceptor.h"
|
||||||
#include "network-web/webfactory.h"
|
#include "network-web/webfactory.h"
|
||||||
|
@ -41,111 +39,30 @@
|
||||||
#include <QWebEngineProfile>
|
#include <QWebEngineProfile>
|
||||||
|
|
||||||
AdBlockManager::AdBlockManager(QObject* parent)
|
AdBlockManager::AdBlockManager(QObject* parent)
|
||||||
: QObject(parent), m_loaded(false), m_enabled(false), m_matcher(new AdBlockMatcher(this)),
|
: QObject(parent), m_loaded(false), m_enabled(false), m_interceptor(new AdBlockUrlInterceptor(this)) {
|
||||||
m_interceptor(new AdBlockUrlInterceptor(this)) {
|
|
||||||
m_adblockIcon = new AdBlockIcon(this);
|
m_adblockIcon = new AdBlockIcon(this);
|
||||||
m_adblockIcon->setObjectName(QSL("m_adblockIconAction"));
|
m_adblockIcon->setObjectName(QSL("m_adblockIconAction"));
|
||||||
|
|
||||||
|
m_unifiedFiltersFile = qApp->userDataFolder() + QDir::separator() + QSL("adblock-unified-filters.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
AdBlockManager::~AdBlockManager() {
|
bool AdBlockManager::block(const AdblockRequestInfo& request) {
|
||||||
qDeleteAll(m_subscriptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<AdBlockSubscription*> AdBlockManager::subscriptions() const {
|
|
||||||
return m_subscriptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdBlockRule* AdBlockManager::block(const AdblockRequestInfo& request) {
|
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
|
|
||||||
if (!isEnabled()) {
|
if (!isEnabled()) {
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString url_string = request.requestUrl().toEncoded().toLower();
|
|
||||||
const QString url_domain = request.requestUrl().host().toLower();
|
|
||||||
const QString url_scheme = request.requestUrl().scheme().toLower();
|
|
||||||
|
|
||||||
if (!canRunOnScheme(url_scheme) || !canBeBlocked(request.firstPartyUrl())) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const AdBlockRule* blocked_rule = m_matcher->match(request, url_domain, url_string);
|
|
||||||
|
|
||||||
return blocked_rule;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
AdBlockSubscription* AdBlockManager::addSubscription(const QString& title, const QString& url) {
|
|
||||||
if (title.isEmpty() || url.isEmpty()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString fileName = title + QSL(".txt");
|
|
||||||
QString filePath = storedListsPath() + QDir::separator() + 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)) {
|
|
||||||
qWarningNN << LOGSEC_ADBLOCK
|
|
||||||
<< "Cannot save AdBlock subscription to file"
|
|
||||||
<< QUOTE_W_SPACE_DOT(filePath);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.write(data);
|
|
||||||
file.commit();
|
|
||||||
auto* 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, &AdBlockSubscription::subscriptionChanged, this, &AdBlockManager::updateMatcher);
|
|
||||||
return subscription;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockManager::removeSubscription(AdBlockSubscription* subscription) {
|
|
||||||
QMutexLocker locker(&m_mutex);
|
|
||||||
|
|
||||||
if (!m_subscriptions.contains(subscription) || !subscription->canBeRemoved()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile(subscription->filePath()).remove();
|
const QString url_string = request.requestUrl().toEncoded().toLower();
|
||||||
m_subscriptions.removeOne(subscription);
|
const QString url_scheme = request.requestUrl().scheme().toLower();
|
||||||
m_matcher->update();
|
|
||||||
delete subscription;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
AdBlockCustomList* AdBlockManager::customList() const {
|
if (!canRunOnScheme(url_scheme)) {
|
||||||
for (AdBlockSubscription* subscription : m_subscriptions) {
|
return false;
|
||||||
auto* list = qobject_cast<AdBlockCustomList*>(subscription);
|
}
|
||||||
|
else {
|
||||||
if (list != nullptr) {
|
// TODO: start server if needed, call it.
|
||||||
return list;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AdBlockManager::storedListsPath() {
|
|
||||||
return qApp->userDataFolder() + QDir::separator() + ADBLOCK_LISTS_SUBDIRECTORY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockManager::load(bool initial_load) {
|
void AdBlockManager::load(bool initial_load) {
|
||||||
|
@ -168,133 +85,33 @@ void AdBlockManager::load(bool initial_load) {
|
||||||
m_enabled = new_enabled;
|
m_enabled = new_enabled;
|
||||||
|
|
||||||
if (!m_loaded) {
|
if (!m_loaded) {
|
||||||
m_disabledRules = qApp->settings()->value(GROUP(AdBlock), SETTING(AdBlock::DisabledRules)).toStringList();
|
|
||||||
|
|
||||||
QDateTime last_update = qApp->settings()->value(GROUP(AdBlock), SETTING(AdBlock::LastUpdatedOn)).toDateTime();
|
|
||||||
QDir adblock_dir(storedListsPath());
|
|
||||||
|
|
||||||
// Create if neccessary
|
|
||||||
if (!adblock_dir.exists()) {
|
|
||||||
QDir().mkpath(storedListsPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto subs_files = adblock_dir.entryList({ QSL("*.txt") }, QDir::Filter::Files);
|
|
||||||
|
|
||||||
for (const QString& subscription_file_name : qAsConst(subs_files)) {
|
|
||||||
if (subscription_file_name == ADBLOCK_CUSTOMLIST_NAME) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString absolute_path = adblock_dir.absoluteFilePath(subscription_file_name);
|
|
||||||
QFile file(absolute_path);
|
|
||||||
|
|
||||||
if (!file.open(QFile::OpenModeFlag::ReadOnly)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextStream subscription_stream(&file);
|
|
||||||
|
|
||||||
subscription_stream.setCodec("UTF-8");
|
|
||||||
QString title = subscription_stream.readLine(1024).remove(QLatin1String("Title: "));
|
|
||||||
QUrl url = QUrl(subscription_stream.readLine(1024).remove(QLatin1String("Url: ")));
|
|
||||||
|
|
||||||
if (title.isEmpty() || !url.isValid()) {
|
|
||||||
qWarningNN << LOGSEC_ADBLOCK
|
|
||||||
<< "Invalid AdBlock subscription file"
|
|
||||||
<< QUOTE_W_SPACE_DOT(absolute_path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* subscription = new AdBlockSubscription(title, this);
|
|
||||||
|
|
||||||
subscription->setUrl(url);
|
|
||||||
subscription->setFilePath(absolute_path);
|
|
||||||
m_subscriptions.append(subscription);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append CustomList.
|
|
||||||
auto* custom_list = new AdBlockCustomList(this);
|
|
||||||
|
|
||||||
m_subscriptions.append(custom_list);
|
|
||||||
|
|
||||||
// Load all subscriptions.
|
|
||||||
for (AdBlockSubscription* subscription : qAsConst(m_subscriptions)) {
|
|
||||||
subscription->loadSubscription(m_disabledRules);
|
|
||||||
connect(subscription, &AdBlockSubscription::subscriptionChanged, this, &AdBlockManager::updateMatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_update.addDays(ADBLOCK_UPDATE_DAYS_INTERVAL) < QDateTime::currentDateTime()) {
|
|
||||||
QTimer::singleShot(1000 * 60, this, &AdBlockManager::updateAllSubscriptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
qApp->web()->urlIinterceptor()->installUrlInterceptor(m_interceptor);
|
qApp->web()->urlIinterceptor()->installUrlInterceptor(m_interceptor);
|
||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
m_matcher->update();
|
if (!QFile::exists(m_unifiedFiltersFile)) {
|
||||||
|
updateUnifiedFiltersFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_matcher->clear();
|
if (QFile::exists(m_unifiedFiltersFile)) {
|
||||||
|
QFile::remove(m_unifiedFiltersFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdBlockManager::updateMatcher() {
|
|
||||||
QMutexLocker locker(&m_mutex);
|
|
||||||
|
|
||||||
m_matcher->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockManager::updateAllSubscriptions() {
|
|
||||||
for (AdBlockSubscription* subscription : qAsConst(m_subscriptions)) {
|
|
||||||
subscription->updateSubscription();
|
|
||||||
}
|
|
||||||
|
|
||||||
qApp->settings()->setValue(GROUP(AdBlock), AdBlock::LastUpdatedOn, QDateTime::currentDateTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockManager::save() {
|
|
||||||
if (!m_loaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (AdBlockSubscription* subscription : qAsConst(m_subscriptions)) {
|
|
||||||
subscription->saveSubscription();
|
|
||||||
}
|
|
||||||
|
|
||||||
qApp->settings()->setValue(GROUP(AdBlock), AdBlock::AdBlockEnabled, m_enabled);
|
|
||||||
qApp->settings()->setValue(GROUP(AdBlock), AdBlock::DisabledRules, m_disabledRules);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockManager::isEnabled() const {
|
bool AdBlockManager::isEnabled() const {
|
||||||
return m_enabled;
|
return m_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AdBlockManager::canRunOnScheme(const QString& scheme) const {
|
bool AdBlockManager::canRunOnScheme(const QString& scheme) const {
|
||||||
return !(scheme == QSL("file") || scheme == QSL("qrc") ||
|
return !(scheme == QSL("file") || scheme == QSL("qrc") || scheme == QSL("data") || scheme == QSL("abp"));
|
||||||
scheme == QSL("data") || scheme == QSL("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();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return m_matcher->elementHidingRules();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AdBlockManager::elementHidingRulesForDomain(const QUrl& url) const {
|
QString AdBlockManager::elementHidingRulesForDomain(const QUrl& url) const {
|
||||||
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url)) {
|
// TODO: call service for cosmetic rules.
|
||||||
return QString();
|
return {};
|
||||||
}
|
|
||||||
else {
|
|
||||||
return m_matcher->elementHidingRulesForDomain(url.host());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AdBlockManager::generateJsForElementHiding(const QString& css) const {
|
QString AdBlockManager::generateJsForElementHiding(const QString& css) const {
|
||||||
|
@ -317,3 +134,8 @@ QString AdBlockManager::generateJsForElementHiding(const QString& css) const {
|
||||||
void AdBlockManager::showDialog() {
|
void AdBlockManager::showDialog() {
|
||||||
AdBlockDialog(qApp->mainFormWidget()).exec();
|
AdBlockDialog(qApp->mainFormWidget()).exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdBlockManager::updateUnifiedFiltersFile() {
|
||||||
|
// TODO: download contents of all filter lists + append custom filters
|
||||||
|
// and combine into single file.
|
||||||
|
}
|
||||||
|
|
|
@ -27,10 +27,6 @@
|
||||||
|
|
||||||
class QUrl;
|
class QUrl;
|
||||||
class AdblockRequestInfo;
|
class AdblockRequestInfo;
|
||||||
class AdBlockMatcher;
|
|
||||||
class AdBlockCustomList;
|
|
||||||
class AdBlockSubscription;
|
|
||||||
class AdBlockRule;
|
|
||||||
class AdBlockUrlInterceptor;
|
class AdBlockUrlInterceptor;
|
||||||
class AdBlockIcon;
|
class AdBlockIcon;
|
||||||
|
|
||||||
|
@ -39,62 +35,40 @@ class AdBlockManager : public QObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AdBlockManager(QObject* parent = nullptr);
|
explicit AdBlockManager(QObject* parent = nullptr);
|
||||||
virtual ~AdBlockManager();
|
|
||||||
|
|
||||||
// If "initial_load" is true, then we want to explicitly turn off
|
// If "initial_load" is false, then we want to explicitly turn off
|
||||||
// Adblock if it is running or turn on when not running.
|
// Adblock if it is running or turn on when not running.
|
||||||
// if "initial_load" is true, then we want to forcefully perform
|
// if "initial_load" is true, then we want to forcefully perform
|
||||||
// initial loading of Adblock.
|
// initial loading of Adblock.
|
||||||
void load(bool initial_load);
|
void load(bool initial_load);
|
||||||
|
|
||||||
// Save all subscriptions to file(s).
|
// General method for adblocking. Returns true if request should be blocked.
|
||||||
void save();
|
bool block(const AdblockRequestInfo& request);
|
||||||
|
|
||||||
// General method for adblocking. Returns pointer to rule if request should
|
|
||||||
// be blocked.
|
|
||||||
const AdBlockRule* block(const AdblockRequestInfo& request);
|
|
||||||
|
|
||||||
bool isEnabled() const;
|
bool isEnabled() const;
|
||||||
bool canRunOnScheme(const QString& scheme) const;
|
bool canRunOnScheme(const QString& scheme) const;
|
||||||
|
|
||||||
QString elementHidingRules(const QUrl& url) const;
|
|
||||||
QString elementHidingRulesForDomain(const QUrl& url) const;
|
QString elementHidingRulesForDomain(const QUrl& url) const;
|
||||||
QString generateJsForElementHiding(const QString& css) const;
|
QString generateJsForElementHiding(const QString& css) const;
|
||||||
|
|
||||||
QList<AdBlockSubscription*> subscriptions() const;
|
|
||||||
|
|
||||||
QStringList disabledRules() const;
|
|
||||||
void addDisabledRule(const QString& filter);
|
|
||||||
void removeDisabledRule(const QString& filter);
|
|
||||||
|
|
||||||
AdBlockSubscription* addSubscription(const QString& title, const QString& url);
|
|
||||||
bool removeSubscription(AdBlockSubscription* subscription);
|
|
||||||
|
|
||||||
AdBlockCustomList* customList() const;
|
|
||||||
AdBlockIcon* adBlockIcon() const;
|
AdBlockIcon* adBlockIcon() const;
|
||||||
|
|
||||||
static QString storedListsPath();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateMatcher();
|
|
||||||
void updateAllSubscriptions();
|
|
||||||
void showDialog();
|
void showDialog();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void enabledChanged(bool enabled);
|
void enabledChanged(bool enabled);
|
||||||
|
|
||||||
private:
|
private slots:
|
||||||
inline bool canBeBlocked(const QUrl& url) const;
|
void updateUnifiedFiltersFile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_loaded;
|
bool m_loaded;
|
||||||
bool m_enabled;
|
bool m_enabled;
|
||||||
AdBlockIcon* m_adblockIcon;
|
AdBlockIcon* m_adblockIcon;
|
||||||
QList<AdBlockSubscription*> m_subscriptions;
|
|
||||||
AdBlockMatcher* m_matcher;
|
|
||||||
QStringList m_disabledRules;
|
|
||||||
AdBlockUrlInterceptor* m_interceptor;
|
AdBlockUrlInterceptor* m_interceptor;
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
|
QString m_unifiedFiltersFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline AdBlockIcon* AdBlockManager::adBlockIcon() const {
|
inline AdBlockIcon* AdBlockManager::adBlockIcon() const {
|
||||||
|
|
|
@ -1,237 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "network-web/adblock/adblockmatcher.h"
|
|
||||||
|
|
||||||
#include "definitions/definitions.h"
|
|
||||||
#include "network-web/adblock/adblockmanager.h"
|
|
||||||
#include "network-web/adblock/adblockrule.h"
|
|
||||||
#include "network-web/adblock/adblocksubscription.h"
|
|
||||||
|
|
||||||
AdBlockMatcher::AdBlockMatcher(AdBlockManager* manager)
|
|
||||||
: QObject(manager), m_manager(manager) {}
|
|
||||||
|
|
||||||
AdBlockMatcher::~AdBlockMatcher() {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdBlockRule* AdBlockMatcher::match(const AdblockRequestInfo& request, const QString& urlDomain,
|
|
||||||
const QString& urlString) const {
|
|
||||||
// Exception rules.
|
|
||||||
if (m_networkExceptionTree.find(request, urlDomain, urlString) != nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(QSL("{display:none !important;}\n"));
|
|
||||||
addedRulesCount = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rules.append(rule->cssSelector() + QLatin1Char(','));
|
|
||||||
addedRulesCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addedRulesCount != 0) {
|
|
||||||
rules = rules.left(rules.size() - 1);
|
|
||||||
rules.append(QSL("{display:none !important;}\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockMatcher::update() {
|
|
||||||
clear();
|
|
||||||
QHash<QString, const AdBlockRule*> cssRulesHash;
|
|
||||||
QVector<const AdBlockRule*> exceptionCssRules;
|
|
||||||
auto subs = m_manager->subscriptions();
|
|
||||||
|
|
||||||
for (AdBlockSubscription* subscription : qAsConst(subs)) {
|
|
||||||
auto rls = subscription->allRules();
|
|
||||||
|
|
||||||
for (const AdBlockRule* rule : qAsConst(rls)) {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const AdBlockRule* rule : exceptionCssRules) {
|
|
||||||
const AdBlockRule* originalRule = cssRulesHash.value(rule->cssSelector());
|
|
||||||
|
|
||||||
// If we don't have this selector, the exception does nothing.
|
|
||||||
if (originalRule == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AdBlockRule* copiedRule = originalRule->copy();
|
|
||||||
|
|
||||||
copiedRule->m_options |= AdBlockRule::RuleOption::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();
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#ifndef ADBLOCKMATCHER_H
|
|
||||||
#define ADBLOCKMATCHER_H
|
|
||||||
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
#include "network-web/adblock/adblocksearchtree.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
class AdblockRequestInfo;
|
|
||||||
class AdBlockManager;
|
|
||||||
|
|
||||||
class AdBlockMatcher : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AdBlockMatcher(AdBlockManager* manager);
|
|
||||||
virtual ~AdBlockMatcher();
|
|
||||||
|
|
||||||
const AdBlockRule* match(const AdblockRequestInfo& request, const QString& url_domain, const QString& url_string) 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
|
|
|
@ -1,742 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. 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 "network-web/adblock/adblockrule.h"
|
|
||||||
|
|
||||||
#include "definitions/definitions.h"
|
|
||||||
#include "network-web/adblock/adblockrequestinfo.h"
|
|
||||||
#include "network-web/adblock/adblocksubscription.h"
|
|
||||||
|
|
||||||
#include "network-web/urltld.cpp"
|
|
||||||
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QWebEnginePage>
|
|
||||||
|
|
||||||
static QString toSecondLevelDomain(const QUrl& url) {
|
|
||||||
const QString tld = topLevelDomain(url);
|
|
||||||
const QString urlHost = url.host();
|
|
||||||
|
|
||||||
if (tld.isEmpty() || urlHost.isEmpty()) {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString domain = urlHost.left(urlHost.size() - tld.size());
|
|
||||||
|
|
||||||
if (domain.count(QL1C('.')) == 0) {
|
|
||||||
return urlHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (domain.count(QL1C('.')) != 0) {
|
|
||||||
domain = domain.mid(domain.indexOf(QL1C('.')) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain + tld;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
setFilter(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
rule->matchers = 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_regexPattern.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::isInternalDisabled() const {
|
|
||||||
return m_isInternalDisabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::urlMatch(const QUrl& url) const {
|
|
||||||
if (!hasOption(DocumentOption) && !hasOption(ElementHideOption)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const QString encodedUrl = url.toEncoded();
|
|
||||||
const QString domain = url.host();
|
|
||||||
|
|
||||||
return stringMatch(domain, encodedUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::networkMatch(const AdblockRequestInfo& request,
|
|
||||||
const QString& domain,
|
|
||||||
const QString& encoded_url) const {
|
|
||||||
if (m_type == CssRule || !m_isEnabled || m_isInternalDisabled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matched = stringMatch(domain, encoded_url);
|
|
||||||
|
|
||||||
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()) {
|
|
||||||
for (const QString& d : m_allowedDomains) {
|
|
||||||
if (isMatchingDomain(domain, d)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_allowedDomains.isEmpty()) {
|
|
||||||
for (const QString& d : m_blockedDomains) {
|
|
||||||
if (isMatchingDomain(domain, d)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (const QString& d : m_blockedDomains) {
|
|
||||||
if (isMatchingDomain(domain, d)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const QString& d : m_allowedDomains) {
|
|
||||||
if (isMatchingDomain(domain, d)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::matchThirdParty(const AdblockRequestInfo& 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 AdblockRequestInfo& request) const {
|
|
||||||
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceType::ResourceTypeObject;
|
|
||||||
|
|
||||||
return hasException(ObjectOption) ? !match : match;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::matchSubdocument(const AdblockRequestInfo& request) const {
|
|
||||||
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceType::ResourceTypeSubFrame;
|
|
||||||
|
|
||||||
return hasException(SubdocumentOption) ? !match : match;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::matchXmlHttpRequest(const AdblockRequestInfo& request) const {
|
|
||||||
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceType::ResourceTypeXhr;
|
|
||||||
|
|
||||||
return hasException(XMLHttpRequestOption) ? !match : match;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::matchImage(const AdblockRequestInfo& request) const {
|
|
||||||
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceType::ResourceTypeImage;
|
|
||||||
|
|
||||||
return hasException(ImageOption) ? !match : match;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::matchScript(const AdblockRequestInfo& request) const {
|
|
||||||
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceType::ResourceTypeScript;
|
|
||||||
|
|
||||||
return hasException(ScriptOption) ? !match : match;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::matchStyleSheet(const AdblockRequestInfo& request) const {
|
|
||||||
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceType::ResourceTypeStylesheet;
|
|
||||||
|
|
||||||
return hasException(StyleSheetOption) ? !match : match;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::matchObjectSubrequest(const AdblockRequestInfo& request) const {
|
|
||||||
bool match = request.resourceType() == QWebEngineUrlRequestInfo::ResourceType::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(','),
|
|
||||||
#if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
|
|
||||||
Qt::SplitBehaviorFlags::SkipEmptyParts);
|
|
||||||
#else
|
|
||||||
QString::SplitBehavior::SkipEmptyParts);
|
|
||||||
#endif
|
|
||||||
int handledOptions = 0;
|
|
||||||
|
|
||||||
for (const QString& option : options) {
|
|
||||||
if (option.startsWith(QL1S("domain="))) {
|
|
||||||
parseDomains(option.mid(7), QL1C('|'));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option == QL1S("match-case")) {
|
|
||||||
m_caseSensitivity = Qt::CaseSensitivity::CaseSensitive;
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option.endsWith(QL1S("third-party"))) {
|
|
||||||
setOption(RuleOption::ThirdPartyOption);
|
|
||||||
setException(RuleOption::ThirdPartyOption, option.startsWith(QL1C('~')));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option.endsWith(QL1S("object"))) {
|
|
||||||
setOption(RuleOption::ObjectOption);
|
|
||||||
setException(RuleOption::ObjectOption, option.startsWith(QL1C('~')));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option.endsWith(QL1S("subdocument"))) {
|
|
||||||
setOption(RuleOption::SubdocumentOption);
|
|
||||||
setException(RuleOption::SubdocumentOption, option.startsWith(QL1C('~')));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option.endsWith(QL1S("xmlhttprequest"))) {
|
|
||||||
setOption(RuleOption::XMLHttpRequestOption);
|
|
||||||
setException(RuleOption::XMLHttpRequestOption, option.startsWith(QL1C('~')));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option.endsWith(QL1S("image"))) {
|
|
||||||
setOption(RuleOption::ImageOption);
|
|
||||||
setException(RuleOption::ImageOption, option.startsWith(QL1C('~')));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option.endsWith(QL1S("script"))) {
|
|
||||||
setOption(RuleOption::ScriptOption);
|
|
||||||
setException(RuleOption::ScriptOption, option.startsWith(QL1C('~')));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option.endsWith(QL1S("stylesheet"))) {
|
|
||||||
setOption(RuleOption::StyleSheetOption);
|
|
||||||
setException(RuleOption::StyleSheetOption, option.startsWith(QL1C('~')));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option.endsWith(QL1S("object-subrequest"))) {
|
|
||||||
setOption(RuleOption::ObjectSubrequestOption);
|
|
||||||
setException(RuleOption::ObjectSubrequestOption, option.startsWith(QL1C('~')));
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option == QL1S("document") && m_isException) {
|
|
||||||
setOption(RuleOption::DocumentOption);
|
|
||||||
++handledOptions;
|
|
||||||
}
|
|
||||||
else if (option == QL1S("elemhide") && m_isException) {
|
|
||||||
setOption(RuleOption::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 = RuleType::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 = RuleType::RegExpMatchRule;
|
|
||||||
m_regexPattern = parsedLine;
|
|
||||||
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 = RuleType::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 = RuleType::StringEndsMatchRule;
|
|
||||||
m_matchString = parsedLine;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we still find a wildcard (*) or separator (^) or (|)
|
|
||||||
// we must modify parsedLine to comply with SimpleRegExp.
|
|
||||||
if (parsedLine.contains(QL1C('*')) || parsedLine.contains(QL1C('^')) || parsedLine.contains(QL1C('|'))) {
|
|
||||||
m_type = RuleType::RegExpMatchRule;
|
|
||||||
m_regexPattern = createRegExpFromFilter(parsedLine);
|
|
||||||
matchers = createStringMatchers(parseRegExpFilter(parsedLine));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We haven't found anything that needs use of regexp, yay!
|
|
||||||
m_type = RuleType::StringContainsMatchRule;
|
|
||||||
m_matchString = parsedLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockRule::parseDomains(const QString& domains, const QChar& separator) {
|
|
||||||
QStringList domainsList = domains.split(separator,
|
|
||||||
#if QT_VERSION >= 0x050F00 // Qt >= 5.15.0
|
|
||||||
Qt::SplitBehaviorFlags::SkipEmptyParts);
|
|
||||||
#else
|
|
||||||
QString::SplitBehavior::SkipEmptyParts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (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(RuleOption::DomainRestrictedOption);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::filterIsOnlyDomain(const QString& filter) const {
|
|
||||||
if (!filter.endsWith(QL1C('^')) || !filter.startsWith(QL1S("||"))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto i : filter) {
|
|
||||||
switch (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> mtchrs;
|
|
||||||
|
|
||||||
mtchrs.reserve(filters.size());
|
|
||||||
|
|
||||||
for (const QString& filter : filters) {
|
|
||||||
mtchrs.append(QStringMatcher(filter, m_caseSensitivity));
|
|
||||||
}
|
|
||||||
|
|
||||||
return mtchrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AdBlockRule::regexMatched(const QString& str, int offset) const {
|
|
||||||
QRegularExpression exp(m_regexPattern);
|
|
||||||
|
|
||||||
if (m_caseSensitivity == Qt::CaseSensitivity::CaseInsensitive) {
|
|
||||||
exp.setPatternOptions(exp.patternOptions() | QRegularExpression::PatternOption::CaseInsensitiveOption);
|
|
||||||
}
|
|
||||||
|
|
||||||
QRegularExpressionMatch m = exp.match(str, offset);
|
|
||||||
|
|
||||||
if (!m.hasMatch()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return m.capturedStart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::stringMatch(const QString& domain, const QString& encodedUrl) const {
|
|
||||||
if (m_type == RuleType::StringContainsMatchRule) {
|
|
||||||
return encodedUrl.contains(m_matchString, m_caseSensitivity);
|
|
||||||
}
|
|
||||||
else if (m_type == RuleType::DomainMatchRule) {
|
|
||||||
return isMatchingDomain(domain, m_matchString);
|
|
||||||
}
|
|
||||||
else if (m_type == RuleType::StringEndsMatchRule) {
|
|
||||||
return encodedUrl.endsWith(m_matchString, m_caseSensitivity);
|
|
||||||
}
|
|
||||||
else if (m_type == RuleType::RegExpMatchRule) {
|
|
||||||
if (!isMatchingRegExpStrings(encodedUrl)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (regexMatched(encodedUrl) != -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::matchDomain(const QString& pattern, const QString& domain) const {
|
|
||||||
if (pattern == domain) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!domain.endsWith(pattern)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int index = domain.indexOf(pattern);
|
|
||||||
|
|
||||||
return index > 0 && domain[index - 1] == QLatin1Char('.');
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::isMatchingDomain(const QString& domain, const QString& filter) const {
|
|
||||||
return matchDomain(filter, domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockRule::isMatchingRegExpStrings(const QString& url) const {
|
|
||||||
for (const QStringMatcher& matcher : 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;
|
|
||||||
}
|
|
|
@ -1,195 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. 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>
|
|
||||||
|
|
||||||
class QUrl;
|
|
||||||
class AdblockRequestInfo;
|
|
||||||
class AdBlockSubscription;
|
|
||||||
|
|
||||||
class AdBlockRule {
|
|
||||||
Q_DISABLE_COPY(AdBlockRule)
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AdBlockRule(const QString& filter = QString(), AdBlockSubscription* subscription = nullptr);
|
|
||||||
virtual ~AdBlockRule() = default;
|
|
||||||
|
|
||||||
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 AdblockRequestInfo& request, const QString& domain, const QString& encoded_url) const;
|
|
||||||
|
|
||||||
bool matchDomain(const QString& domain) const;
|
|
||||||
bool matchThirdParty(const AdblockRequestInfo& request) const;
|
|
||||||
bool matchObject(const AdblockRequestInfo& request) const;
|
|
||||||
bool matchSubdocument(const AdblockRequestInfo& request) const;
|
|
||||||
bool matchXmlHttpRequest(const AdblockRequestInfo& request) const;
|
|
||||||
bool matchImage(const AdblockRequestInfo& request) const;
|
|
||||||
bool matchScript(const AdblockRequestInfo& request) const;
|
|
||||||
bool matchStyleSheet(const AdblockRequestInfo& request) const;
|
|
||||||
bool matchObjectSubrequest(const AdblockRequestInfo& request) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool matchDomain(const QString& pattern, const QString& domain) const;
|
|
||||||
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)
|
|
||||||
|
|
||||||
bool hasOption(const RuleOption& opt) const;
|
|
||||||
bool hasException(const RuleOption& opt) const;
|
|
||||||
void setOption(const RuleOption& opt);
|
|
||||||
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;
|
|
||||||
int regexMatched(const QString& str, int offset = 0) 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;
|
|
||||||
QString m_regexPattern;
|
|
||||||
QList<QStringMatcher> matchers;
|
|
||||||
|
|
||||||
friend class AdBlockMatcher;
|
|
||||||
friend class AdBlockSearchTree;
|
|
||||||
friend class AdBlockSubscription;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool AdBlockRule::hasOption(const AdBlockRule::RuleOption& opt) const {
|
|
||||||
return (m_options & opt) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool AdBlockRule::hasException(const AdBlockRule::RuleOption& opt) const {
|
|
||||||
return (m_exceptions & opt) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void AdBlockRule::setOption(const AdBlockRule::RuleOption& opt) {
|
|
||||||
m_options |= opt;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void AdBlockRule::setException(const AdBlockRule::RuleOption& opt, bool on) {
|
|
||||||
if (on) {
|
|
||||||
m_exceptions |= opt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // ADBLOCKRULE_H
|
|
|
@ -1,136 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "network-web/adblock/adblocksearchtree.h"
|
|
||||||
|
|
||||||
#include "definitions/definitions.h"
|
|
||||||
#include "network-web/adblock/adblockrequestinfo.h"
|
|
||||||
#include "network-web/adblock/adblockrule.h"
|
|
||||||
|
|
||||||
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) {
|
|
||||||
qWarningNN << LOGSEC_ADBLOCK << "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 == nullptr) {
|
|
||||||
next = new Node;
|
|
||||||
next->c = c;
|
|
||||||
node->children[c] = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->rule = rule;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdBlockRule* AdBlockSearchTree::find(const AdblockRequestInfo& request,
|
|
||||||
const QString& domain,
|
|
||||||
const QString& urlString) const {
|
|
||||||
int len = urlString.size();
|
|
||||||
|
|
||||||
if (len <= 0) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
const AdBlockRule* rule = prefixSearch(request, domain, urlString, urlString.mid(i), len - i);
|
|
||||||
|
|
||||||
if (rule != nullptr) {
|
|
||||||
return rule;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdBlockRule* AdBlockSearchTree::prefixSearch(const AdblockRequestInfo& request, const QString& domain,
|
|
||||||
const QString& urlString, const QString& choppedUrlString,
|
|
||||||
int len) const {
|
|
||||||
if (len <= 0) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* node = m_root->children.value(choppedUrlString.at(0));
|
|
||||||
|
|
||||||
if (node == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < len; ++i) {
|
|
||||||
const QChar c = choppedUrlString.at(i);
|
|
||||||
|
|
||||||
if ((node->rule != nullptr) && node->rule->networkMatch(request, domain, urlString)) {
|
|
||||||
return node->rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = node->children.value(c);
|
|
||||||
|
|
||||||
if (node == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((node->rule != nullptr) && node->rule->networkMatch(request, domain, urlString)) {
|
|
||||||
return node->rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockSearchTree::deleteNode(AdBlockSearchTree::Node* node) {
|
|
||||||
if (node == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QHashIterator<QChar, Node*> i(node->children);
|
|
||||||
|
|
||||||
while (i.hasNext()) {
|
|
||||||
i.next();
|
|
||||||
deleteNode(i.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
delete node;
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#ifndef ADBLOCKSEARCHTREE_H
|
|
||||||
#define ADBLOCKSEARCHTREE_H
|
|
||||||
|
|
||||||
#include <QChar>
|
|
||||||
#include <QHash>
|
|
||||||
|
|
||||||
class AdblockRequestInfo;
|
|
||||||
class AdBlockRule;
|
|
||||||
|
|
||||||
class AdBlockSearchTree {
|
|
||||||
public:
|
|
||||||
explicit AdBlockSearchTree();
|
|
||||||
virtual ~AdBlockSearchTree();
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
bool add(const AdBlockRule* rule);
|
|
||||||
const AdBlockRule* find(const AdblockRequestInfo& request, const QString& domain, const QString& urlString) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Node {
|
|
||||||
Node() : c(0), rule(0) {}
|
|
||||||
|
|
||||||
QChar c;
|
|
||||||
const AdBlockRule* rule;
|
|
||||||
QHash<QChar, Node*> children;
|
|
||||||
};
|
|
||||||
|
|
||||||
const AdBlockRule* prefixSearch(const AdblockRequestInfo& request, const QString& domain,
|
|
||||||
const QString& urlString, const QString& choppedUrlString,
|
|
||||||
int len) const;
|
|
||||||
|
|
||||||
void deleteNode(Node* node);
|
|
||||||
|
|
||||||
Node* m_root;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ADBLOCKSEARCHTREE_H
|
|
|
@ -1,404 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. 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 "network-web/adblock/adblocksubscription.h"
|
|
||||||
|
|
||||||
#include "definitions/definitions.h"
|
|
||||||
#include "exceptions/applicationexception.h"
|
|
||||||
#include "miscellaneous/application.h"
|
|
||||||
#include "miscellaneous/iofactory.h"
|
|
||||||
#include "network-web/adblock/adblockmanager.h"
|
|
||||||
#include "network-web/adblock/adblocksearchtree.h"
|
|
||||||
#include "network-web/silentnetworkaccessmanager.h"
|
|
||||||
#include "network-web/webfactory.h"
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QSaveFile>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
AdBlockSubscription::AdBlockSubscription(QString title, QObject* parent)
|
|
||||||
: QObject(parent), m_reply(nullptr), m_title(std::move(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, &AdBlockSubscription::updateSubscription);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file.open(QFile::ReadOnly)) {
|
|
||||||
qWarningNN << LOGSEC_ADBLOCK
|
|
||||||
<< "Unable to open adblock file"
|
|
||||||
<< QUOTE_W_SPACE(m_filePath)
|
|
||||||
<< "for reading.";
|
|
||||||
QTimer::singleShot(0, this, &AdBlockSubscription::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(QL1S("[Adblock")) || m_title.isEmpty()) {
|
|
||||||
qWarningNN << LOGSEC_ADBLOCK
|
|
||||||
<< "Invalid format of AdBlock file"
|
|
||||||
<< QUOTE_W_SPACE_DOT(m_filePath);
|
|
||||||
QTimer::singleShot(0, this, &AdBlockSubscription::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, &AdBlockSubscription::updateSubscription);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockSubscription::saveSubscription() {}
|
|
||||||
|
|
||||||
void AdBlockSubscription::updateSubscription() {
|
|
||||||
if ((m_reply != nullptr) || !m_url.isValid()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* mgs = new SilentNetworkAccessManager(this);
|
|
||||||
|
|
||||||
m_reply = mgs->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->manager()->deleteLater();
|
|
||||||
m_reply->deleteLater();
|
|
||||||
m_reply = nullptr;
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
emit subscriptionError(tr("Cannot load subscription!"));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadSubscription(qApp->web()->adBlock()->disabledRules());
|
|
||||||
emit subscriptionUpdated();
|
|
||||||
emit subscriptionChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockSubscription::saveDownloadedData(const QByteArray& data) {
|
|
||||||
QSaveFile file(m_filePath);
|
|
||||||
|
|
||||||
if (!file.open(QFile::WriteOnly)) {
|
|
||||||
qWarningNN << LOGSEC_ADBLOCK
|
|
||||||
<< "Unable to open AdBlock file"
|
|
||||||
<< QUOTE_W_SPACE(m_filePath)
|
|
||||||
<< "for writing.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// 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 (IS_IN_ARRAY(offset, m_rules)) {
|
|
||||||
return m_rules[offset];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<AdBlockRule*> AdBlockSubscription::allRules() const {
|
|
||||||
return m_rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdBlockRule* AdBlockSubscription::enableRule(int offset) {
|
|
||||||
if (IS_IN_ARRAY(offset, m_rules)) {
|
|
||||||
AdBlockRule* rule = m_rules[offset];
|
|
||||||
|
|
||||||
rule->setEnabled(true);
|
|
||||||
qApp->web()->adBlock()->removeDisabledRule(rule->filter());
|
|
||||||
emit subscriptionChanged();
|
|
||||||
|
|
||||||
return rule;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdBlockRule* AdBlockSubscription::disableRule(int offset) {
|
|
||||||
if (!IS_IN_ARRAY(offset, m_rules)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AdBlockRule* rule = m_rules[offset];
|
|
||||||
|
|
||||||
rule->setEnabled(false);
|
|
||||||
qApp->web()->adBlock()->addDisabledRule(rule->filter());
|
|
||||||
emit subscriptionChanged();
|
|
||||||
|
|
||||||
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 nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AdBlockSubscription::~AdBlockSubscription() {
|
|
||||||
qDeleteAll(m_rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdBlockCustomList
|
|
||||||
|
|
||||||
AdBlockCustomList::AdBlockCustomList(QObject* parent)
|
|
||||||
: AdBlockSubscription(tr("Custom rules"), parent) {
|
|
||||||
setFilePath(AdBlockManager::storedListsPath() + QDir::separator() + ADBLOCK_CUSTOMLIST_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
QString rules;
|
|
||||||
|
|
||||||
try {
|
|
||||||
rules = QString::fromUtf8(IOFactory::readFile(filePath()));
|
|
||||||
}
|
|
||||||
catch (ApplicationException&) {}
|
|
||||||
|
|
||||||
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 + QL1C('\n'))) {
|
|
||||||
stream << ddg1 << QL1C('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rules.contains(QL1C('\n') + ddg2)) {
|
|
||||||
stream << ddg2 << QL1C('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
AdBlockSubscription::loadSubscription(disabledRules);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockCustomList::saveSubscription() {
|
|
||||||
QFile file(filePath());
|
|
||||||
|
|
||||||
if (!file.open(QFile::ReadWrite | QFile::Truncate)) {
|
|
||||||
qWarningNN << LOGSEC_ADBLOCK
|
|
||||||
<< "Unable to open AdBlock file"
|
|
||||||
<< QUOTE_W_SPACE(filePath())
|
|
||||||
<< "for writing.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextStream textStream(&file);
|
|
||||||
|
|
||||||
textStream.setCodec("UTF-8");
|
|
||||||
textStream << "Title: " << title() << QL1C('\n');
|
|
||||||
textStream << "Url: " << url().toString() << QL1C('\n');
|
|
||||||
textStream << "[Adblock Plus 1.1.1]" << QL1C('\n');
|
|
||||||
|
|
||||||
for (const AdBlockRule* rule : qAsConst(m_rules)) {
|
|
||||||
textStream << rule->filter() << QL1C('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockCustomList::canEditRules() const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockCustomList::canBeRemoved() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockCustomList::containsFilter(const QString& filter) const {
|
|
||||||
for (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();
|
|
||||||
|
|
||||||
return m_rules.count() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdBlockCustomList::removeRule(int offset) {
|
|
||||||
if (!IS_IN_ARRAY(offset, m_rules)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AdBlockRule* rule = m_rules.at(offset);
|
|
||||||
const QString filter = rule->filter();
|
|
||||||
|
|
||||||
m_rules.remove(offset);
|
|
||||||
emit subscriptionChanged();
|
|
||||||
|
|
||||||
qApp->web()->adBlock()->removeDisabledRule(filter);
|
|
||||||
delete rule;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdBlockRule* AdBlockCustomList::replaceRule(AdBlockRule* rule, int offset) {
|
|
||||||
if (!IS_IN_ARRAY(offset, m_rules)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AdBlockRule* oldRule = m_rules.at(offset);
|
|
||||||
|
|
||||||
m_rules[offset] = rule;
|
|
||||||
emit subscriptionChanged();
|
|
||||||
|
|
||||||
delete oldRule;
|
|
||||||
return m_rules[offset];
|
|
||||||
}
|
|
|
@ -1,134 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. 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 <QUrl>
|
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
#include "network-web/adblock/adblockrule.h"
|
|
||||||
#include "network-web/adblock/adblocksearchtree.h"
|
|
||||||
|
|
||||||
class QUrl;
|
|
||||||
class QNetworkReply;
|
|
||||||
|
|
||||||
class AdBlockSubscription : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AdBlockSubscription(QString title, QObject* parent = nullptr);
|
|
||||||
virtual ~AdBlockSubscription();
|
|
||||||
|
|
||||||
QString title() const;
|
|
||||||
|
|
||||||
QString filePath() const;
|
|
||||||
void setFilePath(const QString& path);
|
|
||||||
|
|
||||||
QUrl url() const;
|
|
||||||
void setUrl(const QUrl& url);
|
|
||||||
|
|
||||||
const AdBlockRule* rule(int offset) const;
|
|
||||||
|
|
||||||
QVector<AdBlockRule*> allRules() const;
|
|
||||||
|
|
||||||
const AdBlockRule* enableRule(int offset);
|
|
||||||
const AdBlockRule* disableRule(int offset);
|
|
||||||
virtual void loadSubscription(const QStringList& disabledRules);
|
|
||||||
virtual void saveSubscription();
|
|
||||||
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);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
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 = nullptr);
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,258 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "network-web/adblock/adblocktreewidget.h"
|
|
||||||
|
|
||||||
#include "network-web/adblock/adblocksubscription.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QClipboard>
|
|
||||||
#include <QInputDialog>
|
|
||||||
#include <QKeyEvent>
|
|
||||||
#include <QMenu>
|
|
||||||
|
|
||||||
AdBlockTreeWidget::AdBlockTreeWidget(AdBlockSubscription* subscription, QWidget* parent)
|
|
||||||
: TreeWidget(parent), m_subscription(subscription), m_topItem(nullptr), m_itemChangingBlock(false) {
|
|
||||||
setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
|
|
||||||
setDefaultItemShowMode(TreeWidget::ItemShowMode::ItemsExpanded);
|
|
||||||
setHeaderHidden(true);
|
|
||||||
setAlternatingRowColors(true);
|
|
||||||
setLayoutDirection(Qt::LayoutDirection::LeftToRight);
|
|
||||||
setIndentation(5);
|
|
||||||
|
|
||||||
connect(this, &QWidget::customContextMenuRequested, this, &AdBlockTreeWidget::contextMenuRequested);
|
|
||||||
connect(this, &QTreeWidget::itemChanged, this, &AdBlockTreeWidget::itemChanged);
|
|
||||||
connect(m_subscription, &AdBlockSubscription::subscriptionUpdated, this, &AdBlockTreeWidget::subscriptionUpdated);
|
|
||||||
connect(m_subscription, &AdBlockSubscription::subscriptionError, this, &AdBlockTreeWidget::subscriptionError);
|
|
||||||
}
|
|
||||||
|
|
||||||
AdBlockSubscription* AdBlockTreeWidget::subscription() const {
|
|
||||||
return m_subscription;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockTreeWidget::showRule(const AdBlockRule* rule) {
|
|
||||||
if ((m_topItem == nullptr) && (rule != nullptr)) {
|
|
||||||
m_ruleToBeSelected = rule->filter();
|
|
||||||
}
|
|
||||||
else if (!m_ruleToBeSelected.isEmpty()) {
|
|
||||||
QList<QTreeWidgetItem*> items = findItems(m_ruleToBeSelected, Qt::MatchFlag::MatchRecursive);
|
|
||||||
|
|
||||||
if (!items.isEmpty()) {
|
|
||||||
QTreeWidgetItem* item = items.at(0);
|
|
||||||
|
|
||||||
setCurrentItem(item);
|
|
||||||
scrollToItem(item, QAbstractItemView::ScrollHint::PositionAtCenter);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ruleToBeSelected.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockTreeWidget::contextMenuRequested(const QPoint& pos) {
|
|
||||||
if (!m_subscription->canEditRules()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidgetItem* item = itemAt(pos);
|
|
||||||
|
|
||||||
if (item == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMenu menu;
|
|
||||||
|
|
||||||
menu.addAction(tr("Add rule"), this, &AdBlockTreeWidget::addRule);
|
|
||||||
menu.addSeparator();
|
|
||||||
QAction* deleteAction = menu.addAction(tr("Remove rule"), this, &AdBlockTreeWidget::removeRule);
|
|
||||||
|
|
||||||
if (item->parent() == nullptr) {
|
|
||||||
deleteAction->setDisabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.exec(viewport()->mapToGlobal(pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockTreeWidget::itemChanged(QTreeWidgetItem* item) {
|
|
||||||
if ((item == nullptr) || 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 == nullptr) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* rule = new AdBlockRule(newRule, m_subscription);
|
|
||||||
int offset = m_subscription->addRule(rule);
|
|
||||||
auto* item = new QTreeWidgetItem();
|
|
||||||
|
|
||||||
item->setText(0, newRule);
|
|
||||||
item->setData(0, Qt::ItemDataRole::UserRole + 10, offset);
|
|
||||||
item->setFlags(item->flags() | Qt::ItemFlag::ItemIsEditable);
|
|
||||||
m_itemChangingBlock = true;
|
|
||||||
m_topItem->addChild(item);
|
|
||||||
m_itemChangingBlock = false;
|
|
||||||
adjustItemFeatures(item, rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockTreeWidget::removeRule() {
|
|
||||||
QTreeWidgetItem* item = currentItem();
|
|
||||||
|
|
||||||
if ((item == nullptr) || !m_subscription->canEditRules() || item == m_topItem) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = item->data(0, Qt::ItemDataRole::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::GlobalColor::gray));
|
|
||||||
|
|
||||||
if (!rule->isComment()) {
|
|
||||||
item->setFlags(item->flags() | Qt::ItemFlag::ItemIsUserCheckable);
|
|
||||||
item->setCheckState(0, Qt::CheckState::Unchecked);
|
|
||||||
item->setFont(0, font);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item->setFlags(item->flags() | Qt::ItemFlag::ItemIsUserCheckable);
|
|
||||||
item->setCheckState(0, Qt::CheckState::Checked);
|
|
||||||
|
|
||||||
if (rule->isException()) {
|
|
||||||
item->setForeground(0, QColor(Qt::GlobalColor::darkGreen));
|
|
||||||
item->setFont(0, QFont());
|
|
||||||
}
|
|
||||||
else if (rule->isCssRule()) {
|
|
||||||
item->setForeground(0, QColor(Qt::GlobalColor::darkBlue));
|
|
||||||
item->setFont(0, QFont());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
item->setForeground(0, QColor(Qt::GlobalColor::black));
|
|
||||||
item->setFont(0, QFont());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdBlockTreeWidget::keyPressEvent(QKeyEvent* event) {
|
|
||||||
if (event->key() == Qt::Key::Key_C && (event->modifiers() & Qt::KeyboardModifier::ControlModifier) != 0) {
|
|
||||||
copyFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->key() == Qt::Key::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;
|
|
||||||
|
|
||||||
for (const AdBlockRule* rule : allRules) {
|
|
||||||
auto* item = new QTreeWidgetItem(m_topItem);
|
|
||||||
|
|
||||||
item->setText(0, rule->filter());
|
|
||||||
item->setData(0, Qt::ItemDataRole::UserRole + 10, index);
|
|
||||||
|
|
||||||
if (m_subscription->canEditRules()) {
|
|
||||||
item->setFlags(item->flags() | Qt::ItemFlag::ItemIsEditable);
|
|
||||||
}
|
|
||||||
|
|
||||||
adjustItemFeatures(item, rule);
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
|
|
||||||
showRule(nullptr);
|
|
||||||
m_itemChangingBlock = false;
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
|
||||||
|
|
||||||
//
|
|
||||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
|
||||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
|
||||||
//
|
|
||||||
// RSS Guard 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.
|
|
||||||
//
|
|
||||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#ifndef ADBLOCKTREEWIDGET_H
|
|
||||||
#define ADBLOCKTREEWIDGET_H
|
|
||||||
|
|
||||||
#include "gui/reusable/treewidget.h"
|
|
||||||
|
|
||||||
class AdBlockSubscription;
|
|
||||||
class AdBlockRule;
|
|
||||||
|
|
||||||
class AdBlockTreeWidget : public TreeWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AdBlockTreeWidget(AdBlockSubscription* subscription, QWidget* parent = nullptr);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void keyPressEvent(QKeyEvent* event);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule* rule);
|
|
||||||
|
|
||||||
AdBlockSubscription* m_subscription;
|
|
||||||
QTreeWidgetItem* m_topItem;
|
|
||||||
QString m_ruleToBeSelected;
|
|
||||||
bool m_itemChangingBlock;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ADBLOCKTREEWIDGET_H
|
|
|
@ -27,7 +27,7 @@ AdBlockUrlInterceptor::AdBlockUrlInterceptor(AdBlockManager* manager)
|
||||||
: UrlInterceptor(manager), m_manager(manager) {}
|
: UrlInterceptor(manager), m_manager(manager) {}
|
||||||
|
|
||||||
void AdBlockUrlInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
void AdBlockUrlInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||||
if (m_manager->block(AdblockRequestInfo(info)) != nullptr) {
|
if (m_manager->block(AdblockRequestInfo(info))) {
|
||||||
info.block(true);
|
info.block(true);
|
||||||
|
|
||||||
qWarningNN << LOGSEC_ADBLOCK << "Blocked request:" << QUOTE_W_SPACE_DOT(info.requestUrl().toString());
|
qWarningNN << LOGSEC_ADBLOCK << "Blocked request:" << QUOTE_W_SPACE_DOT(info.requestUrl().toString());
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
#include "miscellaneous/application.h"
|
#include "miscellaneous/application.h"
|
||||||
#include "network-web/adblock/adblockmanager.h"
|
#include "network-web/adblock/adblockmanager.h"
|
||||||
#include "network-web/adblock/adblockrequestinfo.h"
|
#include "network-web/adblock/adblockrequestinfo.h"
|
||||||
#include "network-web/adblock/adblockrule.h"
|
|
||||||
#include "network-web/adblock/adblocksubscription.h"
|
|
||||||
#include "network-web/webfactory.h"
|
#include "network-web/webfactory.h"
|
||||||
#include "services/abstract/rootitem.h"
|
#include "services/abstract/rootitem.h"
|
||||||
#include "services/abstract/serviceroot.h"
|
#include "services/abstract/serviceroot.h"
|
||||||
|
@ -34,16 +32,7 @@ void WebPage::hideUnwantedElements() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto css = qApp->web()->adBlock()->elementHidingRules(url());
|
auto css = qApp->web()->adBlock()->elementHidingRulesForDomain(url());
|
||||||
|
|
||||||
if (!css.isEmpty()) {
|
|
||||||
auto js = qApp->web()->adBlock()->generateJsForElementHiding(css);
|
|
||||||
|
|
||||||
runJavaScript(js);
|
|
||||||
qDebugNN << LOGSEC_JS << "Running global JS for element hiding rules.";
|
|
||||||
}
|
|
||||||
|
|
||||||
css = qApp->web()->adBlock()->elementHidingRulesForDomain(url());
|
|
||||||
|
|
||||||
if (!css.isEmpty()) {
|
if (!css.isEmpty()) {
|
||||||
auto js = qApp->web()->adBlock()->generateJsForElementHiding(css);
|
auto js = qApp->web()->adBlock()->generateJsForElementHiding(css);
|
||||||
|
@ -57,11 +46,11 @@ bool WebPage::acceptNavigationRequest(const QUrl& url, NavigationType type, bool
|
||||||
const RootItem* root = view()->root();
|
const RootItem* root = view()->root();
|
||||||
|
|
||||||
if (is_main_frame) {
|
if (is_main_frame) {
|
||||||
auto* adblock_rule = qApp->web()->adBlock()->block(AdblockRequestInfo(url));
|
auto blocked = qApp->web()->adBlock()->block(AdblockRequestInfo(url));
|
||||||
|
|
||||||
if (adblock_rule != nullptr) {
|
if (blocked) {
|
||||||
// This website is entirely blocked.
|
// This website is entirely blocked.
|
||||||
setHtml(qApp->skins()->adBlockedPage(adblock_rule->subscription()->title(), adblock_rule->filter()),
|
setHtml(qApp->skins()->adBlockedPage(url.toString()),
|
||||||
QUrl::fromUserInput(INTERNAL_URL_ADBLOCKED));
|
QUrl::fromUserInput(INTERNAL_URL_ADBLOCKED));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue