From be625d0fcb1f4e8184ed62a28d23629f8c246d8e Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Fri, 14 Jun 2024 17:07:01 -0700 Subject: [PATCH] Finish block list implementation. --- src/CMakeLists.txt | 1 + src/delegates/CMakeLists.txt | 1 - src/delegates/ViewAndCopyDelegate.cpp | 44 - src/delegates/ViewAndCopyDelegate.h | 38 - src/dialogs/CMakeLists.txt | 1 + src/dialogs/FilterEntryDialog.cpp | 245 ++++ src/dialogs/FilterEntryDialog.h | 78 ++ src/dialogs/FilterListsDialog.cpp | 384 +++--- src/dialogs/FilterListsDialog.h | 3 + src/dialogs/RequestDetailDialog.cpp | 20 +- src/dialogs/RequestDetailDialog.h | 4 +- src/dialogs/RequestsDialog.cpp | 2 +- src/helpers/FilterListHelper.cpp | 1298 +++++++++++++------- src/helpers/FilterListHelper.h | 16 +- src/interceptors/UrlRequestInterceptor.cpp | 7 +- src/structs/EntryStruct.h | 21 +- src/structs/FilterListStruct.h | 10 +- src/structs/UrlStruct.h | 1 + src/uis/FilterEntryDialog.ui | 680 ++++++++++ src/uis/RequestDetailDialog.ui | 6 +- 20 files changed, 2120 insertions(+), 740 deletions(-) delete mode 100644 src/delegates/ViewAndCopyDelegate.cpp delete mode 100644 src/delegates/ViewAndCopyDelegate.h create mode 100644 src/dialogs/FilterEntryDialog.cpp create mode 100644 src/dialogs/FilterEntryDialog.h create mode 100644 src/uis/FilterEntryDialog.ui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac2b39c..86bf000 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -45,6 +45,7 @@ ki18n_wrap_ui(privacybrowser uis/DurableCookiesDialog.ui uis/EditBookmarkDialog.ui uis/EditFolderDialog.ui + uis/FilterEntryDialog.ui uis/FilterListsDialog.ui uis/HttpAuthenticationDialog.ui uis/RequestDetailDialog.ui diff --git a/src/delegates/CMakeLists.txt b/src/delegates/CMakeLists.txt index 440ec44..5e795b9 100644 --- a/src/delegates/CMakeLists.txt +++ b/src/delegates/CMakeLists.txt @@ -18,6 +18,5 @@ # List the sources to include in the executable. target_sources(privacybrowser PRIVATE - ViewAndCopyDelegate.cpp ViewOnlyDelegate.cpp ) diff --git a/src/delegates/ViewAndCopyDelegate.cpp b/src/delegates/ViewAndCopyDelegate.cpp deleted file mode 100644 index d3eb1f3..0000000 --- a/src/delegates/ViewAndCopyDelegate.cpp +++ /dev/null @@ -1,44 +0,0 @@ - /* - * Copyright 2024 Soren Stoutner . - * - * This file is part of Privacy Browser PC . - * - * Privacy Browser PC 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. - * - * Privacy Browser PC 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 Privacy Browser PC. If not, see . - */ - -// Application headers. -#include "ViewAndCopyDelegate.h" - -// Qt toolkit headers. -#include - -ViewAndCopyDelegate::ViewAndCopyDelegate(QObject *parentObjectPointer) : QStyledItemDelegate(parentObjectPointer) {} - -QWidget* ViewAndCopyDelegate::createEditor(QWidget *parentWidgetPointer, const QStyleOptionViewItem &styleOptionViewItem, const QModelIndex &modelIndex) const -{ - // Instruct the compiler to ignore the unused variables. - (void) styleOptionViewItem; - - // Get the data string from the model index. - QString dataString = modelIndex.data().toString(); - - // Create a line edit. - QLineEdit *lineEditPointer = new QLineEdit(dataString, parentWidgetPointer); - - // Set the line edit to be read only. - lineEditPointer->setReadOnly(true); - - // Return the line edit. - return lineEditPointer; -} diff --git a/src/delegates/ViewAndCopyDelegate.h b/src/delegates/ViewAndCopyDelegate.h deleted file mode 100644 index 722add4..0000000 --- a/src/delegates/ViewAndCopyDelegate.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2024 Soren Stoutner . - * - * This file is part of Privacy Browser PC . - * - * Privacy Browser PC 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. - * - * Privacy Browser PC 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 Privacy Browser PC. If not, see . - */ - -#ifndef VIEWANDCOPYDELEGATE_H -#define VIEWANDCOPYDELEGATE_H - -// Qt toolkit headers. -#include - -class ViewAndCopyDelegate : public QStyledItemDelegate -{ - // Include the Q_OBJECT macro. - Q_OBJECT - -public: - // The default constructor. - explicit ViewAndCopyDelegate(QObject *parenObjectPointer = nullptr); - - // The public functions. - QWidget* createEditor(QWidget *parentWidgetPointer, const QStyleOptionViewItem &styleOptionViewItem, const QModelIndex &modelIndex) const override; -}; -#endif diff --git a/src/dialogs/CMakeLists.txt b/src/dialogs/CMakeLists.txt index 264624f..a0bc9eb 100644 --- a/src/dialogs/CMakeLists.txt +++ b/src/dialogs/CMakeLists.txt @@ -27,6 +27,7 @@ target_sources(privacybrowser PRIVATE DurableCookiesDialog.cpp EditBookmarkDialog.cpp EditFolderDialog.cpp + FilterEntryDialog.cpp FilterListsDialog.cpp HttpAuthenticationDialog.cpp RequestDetailDialog.cpp diff --git a/src/dialogs/FilterEntryDialog.cpp b/src/dialogs/FilterEntryDialog.cpp new file mode 100644 index 0000000..703ca04 --- /dev/null +++ b/src/dialogs/FilterEntryDialog.cpp @@ -0,0 +1,245 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of Privacy Browser PC . + * + * Privacy Browser PC 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. + * + * Privacy Browser PC 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 Privacy Browser PC. If not, see . + */ + +// Application headers. +#include "FilterEntryDialog.h" +#include "GlobalVariables.h" +#include "ui_FilterEntryDialog.h" + +// KDE Framework headers. +#include + +// Qt toolkit headers. +#include + +// Construct the class. +FilterEntryDialog::FilterEntryDialog(QWidget *parentWidgetPointer, QTableWidget *tableWidgetPointer, const int initialRow, const QString &filterListTitle, const QString &sublistTitle) : + QDialog(parentWidgetPointer), currentRow(initialRow), tableWidgetPointer(tableWidgetPointer) +{ + // Set the window modality. + setWindowModality(Qt::WindowModality::ApplicationModal); + + // Instantiate the filter entry dialog UI. + Ui::FilterEntryDialog filterEntryDialogUi; + + // Setup the UI. + filterEntryDialogUi.setupUi(this); + + // Get handles for the views. + QLineEdit *filterListLineEditPointer = filterEntryDialogUi.filterListLineEdit; + QLineEdit *sublistLineEditPointer = filterEntryDialogUi.sublistListLineEdit; + appliedEntryListLineEditPointer = filterEntryDialogUi.appliedEntryListLineEdit; + initialMatchLineEditPointer = filterEntryDialogUi.initialMatchLineEdit; + finalMatchLineEditPointer = filterEntryDialogUi.finalMatchLineEdit; + domainLineEditPointer = filterEntryDialogUi.domainLineEdit; + domainListLineEditPointer = filterEntryDialogUi.domainListLineEdit; + thirdPartyLineEditPointer = filterEntryDialogUi.thirdPartyLineEdit; + hasRequestOptionsCheckBoxPointer = filterEntryDialogUi.hasRequestOptionsCheckBox; + fontLineEditPointer = filterEntryDialogUi.fontLineEdit; + imageLineEditPointer = filterEntryDialogUi.imageLineEdit; + mainFrameLineEditPointer = filterEntryDialogUi.mainFrameLineEdit; + mediaLineEditPointer = filterEntryDialogUi.mediaLineEdit; + objectLineEditPointer = filterEntryDialogUi.objectLineEdit; + otherLineEditPointer = filterEntryDialogUi.otherLineEdit; + pingLineEditPointer = filterEntryDialogUi.pingLineEdit; + scriptLineEditPointer = filterEntryDialogUi.scriptLineEdit; + styleSheetLineEditPointer = filterEntryDialogUi.styleSheetLineEdit; + subFrameLineEditPointer = filterEntryDialogUi.subFrameLineEdit; + xmlHttpRequestLineEditPointer = filterEntryDialogUi.xmlHttpRequestLineEdit; + appliedFilterOptionsLineEditPointer = filterEntryDialogUi.appliedFilterOptionsLineEdit; + originalFilterOptionsLineEditPointer = filterEntryDialogUi.originalFilterOptionsLineEdit; + originalEntryLineEditPointer = filterEntryDialogUi.originalEntryLineEdit; + previousButtonPointer = filterEntryDialogUi.previousButton; + nextButtonPointer = filterEntryDialogUi.nextButton; + QDialogButtonBox *dialogButtonBoxPointer = filterEntryDialogUi.dialogButtonBox; + QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::StandardButton::Close); + + // Populate the views. + filterListLineEditPointer->setText(filterListTitle); + sublistLineEditPointer->setText(sublistTitle); + + // Disable changing the checkbox checked status. + hasRequestOptionsCheckBoxPointer->setAttribute(Qt::WA_TransparentForMouseEvents); + + // Make the close button the default. + closeButtonPointer->setDefault(true); + + // Get the disposition line edit palettes. + normalBackgroundPalette = appliedEntryListLineEditPointer->palette(); + negativeBackgroundPalette = normalBackgroundPalette; + positiveBackgroundPalette = normalBackgroundPalette; + + // Modify the palettes. + KColorScheme::adjustBackground(negativeBackgroundPalette, KColorScheme::NegativeBackground); + KColorScheme::adjustBackground(positiveBackgroundPalette, KColorScheme::PositiveBackground); + + // Set the sublist background palette. TODO Add logic for allow lists. + sublistLineEditPointer->setPalette(negativeBackgroundPalette); + + // Set the applied entry background palette to be the same as the sublist. + appliedEntryListLineEditPointer->setPalette(sublistLineEditPointer->palette()); + + // Connect the buttons. + connect(previousButtonPointer, SIGNAL(clicked()), this, SLOT(previous())); + connect(nextButtonPointer, SIGNAL(clicked()), this, SLOT(next())); + connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(close())); + + // Create the keyboard shortcuts. + QShortcut *previousShortcutPointer = new QShortcut(Qt::Key_Left, this); + QShortcut *nextShortcutPointer = new QShortcut(Qt::Key_Right, this); + + // Connect the keyboard shortcuts to the buttons. + connect(previousShortcutPointer, SIGNAL(activated()), previousButtonPointer, SLOT(click())); + connect(nextShortcutPointer, SIGNAL(activated()), nextButtonPointer, SLOT(click())); + + // Populate the dialog. + populateDialog(currentRow); +} + +void FilterEntryDialog::populateDialog(const int row) +{ + // Set the window title. + setWindowTitle(i18nc("The filter entry dialog window title", "Filter Entry %1 Detail", row + 1)); + + // Select the row in the table widget (this displays the correct row highlighted in the background of the dialog). + tableWidgetPointer->selectRow(row); + + // Determine if previous should be enabled. + bool previousEnabled = (row > 0); + + // Determine if next should be enabled. + bool nextEnabled = (row < (tableWidgetPointer->rowCount() - 1)); + + // Populate the line edits. + appliedEntryListLineEditPointer->setText(tableWidgetPointer->item(row, 0)->text()); + initialMatchLineEditPointer->setText(tableWidgetPointer->item(row, 1)->text()); + finalMatchLineEditPointer->setText(tableWidgetPointer->item(row, 2)->text()); + domainLineEditPointer->setText(tableWidgetPointer->item(row, 3)->text()); + domainListLineEditPointer->setText(tableWidgetPointer->item(row, 4)->text()); + thirdPartyLineEditPointer->setText(tableWidgetPointer->item(row, 5)->text()); + fontLineEditPointer->setText(tableWidgetPointer->item(row, 7)->text()); + imageLineEditPointer->setText(tableWidgetPointer->item(row, 8)->text()); + mainFrameLineEditPointer->setText(tableWidgetPointer->item(row, 9)->text()); + mediaLineEditPointer->setText(tableWidgetPointer->item(row, 10)->text()); + objectLineEditPointer->setText(tableWidgetPointer->item(row, 11)->text()); + otherLineEditPointer->setText(tableWidgetPointer->item(row, 12)->text()); + pingLineEditPointer->setText(tableWidgetPointer->item(row, 13)->text()); + scriptLineEditPointer->setText(tableWidgetPointer->item(row, 14)->text()); + styleSheetLineEditPointer->setText(tableWidgetPointer->item(row, 15)->text()); + subFrameLineEditPointer->setText(tableWidgetPointer->item(row, 16)->text()); + xmlHttpRequestLineEditPointer->setText(tableWidgetPointer->item(row, 17)->text()); + appliedFilterOptionsLineEditPointer->setText(tableWidgetPointer->item(row, 18)->text()); + originalFilterOptionsLineEditPointer->setText(tableWidgetPointer->item(row, 19)->text()); + originalEntryLineEditPointer->setText(tableWidgetPointer->item(row, 20)->text()); + + // Populate the check boxes. + hasRequestOptionsCheckBoxPointer->setChecked(tableWidgetPointer->item(row, 6)->text() == i18n("Yes")); + + // Set the initial and final match background palettes. + setInitialAndFinalMatchBackgroundPalette(initialMatchLineEditPointer); + setInitialAndFinalMatchBackgroundPalette(finalMatchLineEditPointer); + + // Set the request option background palettes and status. + setFilterOptionBackgroundPalette(domainLineEditPointer); + setFilterOptionBackgroundPalette(thirdPartyLineEditPointer); + setFilterOptionBackgroundPalette(fontLineEditPointer); + setFilterOptionBackgroundPalette(imageLineEditPointer); + setFilterOptionBackgroundPalette(mainFrameLineEditPointer); + setFilterOptionBackgroundPalette(mediaLineEditPointer); + setFilterOptionBackgroundPalette(objectLineEditPointer); + setFilterOptionBackgroundPalette(otherLineEditPointer); + setFilterOptionBackgroundPalette(pingLineEditPointer); + setFilterOptionBackgroundPalette(scriptLineEditPointer); + setFilterOptionBackgroundPalette(styleSheetLineEditPointer); + setFilterOptionBackgroundPalette(subFrameLineEditPointer); + setFilterOptionBackgroundPalette(xmlHttpRequestLineEditPointer); + + // Set the request option status. + fontLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + imageLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + mainFrameLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + mediaLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + objectLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + otherLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + pingLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + scriptLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + styleSheetLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + subFrameLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + xmlHttpRequestLineEditPointer->setEnabled(hasRequestOptionsCheckBoxPointer->isChecked()); + + // Set the domain list line edit to have the same palette as the domain line edit. + domainListLineEditPointer->setPalette(domainLineEditPointer->palette()); + + // Set the button status. + previousButtonPointer->setEnabled(previousEnabled); + nextButtonPointer->setEnabled(nextEnabled); +} + +void FilterEntryDialog::previous() +{ + // Update the current row. + --currentRow; + + // Populate the dialog. + populateDialog(currentRow); +} + +void FilterEntryDialog::next() +{ + // Update the current row. + ++currentRow; + + // Populate the dialog. + populateDialog(currentRow); +} + +void FilterEntryDialog::setFilterOptionBackgroundPalette(QLineEdit *lineEditPointer) +{ + // Set the background palette according to the text. + if (lineEditPointer->text() == globalFilterListHelperPointer->getRequestOptionDispositionString(FilterOptionEnum::Disposition::Null)) // Not text is displayed. + { + // Set the normal background palette. + lineEditPointer->setPalette(normalBackgroundPalette); + } + else if (lineEditPointer->text() == globalFilterListHelperPointer->getRequestOptionDispositionString(FilterOptionEnum::Disposition::Apply)) // `Apply` is displayed. + { + // Set the negative (red) background palette. + lineEditPointer->setPalette(negativeBackgroundPalette); + } + else // `Override` is displayed. + { + // Set the positive (green) background palette. + lineEditPointer->setPalette(positiveBackgroundPalette); + } +} + +void FilterEntryDialog::setInitialAndFinalMatchBackgroundPalette(QLineEdit *lineEditPointer) +{ + // Set the background palette according to the text. + if (lineEditPointer->text() == i18n("Yes")) // `Yes` is displayed. + { + // Set the negative (red) background palette. + lineEditPointer->setPalette(negativeBackgroundPalette); + } + else // No text is displayed. + { + // Set the normal background palette. + lineEditPointer->setPalette(normalBackgroundPalette); + } +} diff --git a/src/dialogs/FilterEntryDialog.h b/src/dialogs/FilterEntryDialog.h new file mode 100644 index 0000000..fef1ce1 --- /dev/null +++ b/src/dialogs/FilterEntryDialog.h @@ -0,0 +1,78 @@ +/* + * Copyright 2024 Soren Stoutner . + * + * This file is part of Privacy Browser PC . + * + * Privacy Browser PC 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. + * + * Privacy Browser PC 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 Privacy Browser PC. If not, see . + */ + +#ifndef FILTERENTRYDIALOG_H +#define FILTERENTRYDIALOG_H + +// Qt toolkit headers. +#include +#include +#include + +class FilterEntryDialog : public QDialog +{ + // Include the Q_OBJECT macro. + Q_OBJECT + +public: + // The primary constructor. + explicit FilterEntryDialog(QWidget *parentWidgetPointer, QTableWidget *tableWidgetPointer, const int initialRow, const QString &filterListTitle, const QString &sublistTitle); + +private Q_SLOTS: + // The private slots. + void next(); + void previous(); + +private: + // The private variables. + QLineEdit *appliedEntryListLineEditPointer; + QLineEdit *appliedFilterOptionsLineEditPointer; + int currentRow; + QLineEdit *domainLineEditPointer; + QLineEdit *domainListLineEditPointer; + QLineEdit *finalMatchLineEditPointer; + QLineEdit *fontLineEditPointer; + QCheckBox *hasRequestOptionsCheckBoxPointer; + QLineEdit *imageLineEditPointer; + QLineEdit *initialMatchLineEditPointer; + QLineEdit *mainFrameLineEditPointer; + QLineEdit *mediaLineEditPointer; + QPalette negativeBackgroundPalette; + QPushButton *nextButtonPointer; + QPalette normalBackgroundPalette; + QLineEdit *objectLineEditPointer; + QLineEdit *originalEntryLineEditPointer; + QLineEdit *originalFilterOptionsLineEditPointer; + QLineEdit *otherLineEditPointer; + QLineEdit *pingLineEditPointer; + QPalette positiveBackgroundPalette; + QPushButton *previousButtonPointer; + QLineEdit *scriptLineEditPointer; + QLineEdit *styleSheetLineEditPointer; + QLineEdit *subFrameLineEditPointer; + QTableWidget *tableWidgetPointer; + QLineEdit *thirdPartyLineEditPointer; + QLineEdit *xmlHttpRequestLineEditPointer; + + // The private functions. + void populateDialog(const int row); + void setFilterOptionBackgroundPalette(QLineEdit *lineEditPointer); + void setInitialAndFinalMatchBackgroundPalette(QLineEdit *lineEditPointer); +}; +#endif diff --git a/src/dialogs/FilterListsDialog.cpp b/src/dialogs/FilterListsDialog.cpp index 0ab6753..2d019d8 100644 --- a/src/dialogs/FilterListsDialog.cpp +++ b/src/dialogs/FilterListsDialog.cpp @@ -21,9 +21,10 @@ #include "FilterListsDialog.h" #include "GlobalVariables.h" #include "ui_FilterListsDialog.h" -#include "delegates/ViewAndCopyDelegate.h" +#include "dialogs/FilterEntryDialog.h" // Qt toolkit headers. +#include #include #include @@ -49,11 +50,11 @@ FilterListsDialog::FilterListsDialog(QWidget *parentWidgetPointer) : QDialog(par sublistTableWidgetPointer = filterListsDialogUi.sublistTableWidget; QDialogButtonBox *dialogButtonBoxPointer = filterListsDialogUi.dialogButtonBox; - // Create a view and copy delegate. - ViewAndCopyDelegate *viewAndCopyDelegate = new ViewAndCopyDelegate(this); + // Select an entire row at a time. + sublistTableWidgetPointer->setSelectionBehavior(QAbstractItemView::SelectRows); - // Set the sublist table widget allow copying but not editing. - sublistTableWidgetPointer->setItemDelegate(viewAndCopyDelegate); + // Open the filter entry dialog when a cell is clicked. + connect(sublistTableWidgetPointer, SIGNAL(cellClicked(int, int)), this, SLOT(showFilterEntryDialog(int))); // Connect the combo boxes. connect(filterListComboBoxPointer, SIGNAL(currentIndexChanged(int)), this, SLOT(populateFilterListTextEdit(int))); @@ -63,47 +64,54 @@ FilterListsDialog::FilterListsDialog(QWidget *parentWidgetPointer) : QDialog(par connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(close())); // Populate the filter list combo box. - populateFilterListComboBox(globalFilterListHelperPointer->ultraListStructPointer); populateFilterListComboBox(globalFilterListHelperPointer->ultraPrivacyStructPointer); - populateFilterListComboBox(globalFilterListHelperPointer->easyListStructPointer); + populateFilterListComboBox(globalFilterListHelperPointer->ultraListStructPointer); populateFilterListComboBox(globalFilterListHelperPointer->easyPrivacyStructPointer); + populateFilterListComboBox(globalFilterListHelperPointer->easyListStructPointer); populateFilterListComboBox(globalFilterListHelperPointer->fanboyAnnoyanceStructPointer); } -void FilterListsDialog::populateFilterListComboBox(const FilterListStruct *filterListStructPointer) const +std::forward_list* FilterListsDialog::getFilterListForwardList(FilterListStruct *filterListStructPointer) const { - // Populate the filter list combo box. - filterListComboBoxPointer->addItem(i18nc("Filter list combo box items", "%1 - %2", filterListStructPointer->title, filterListStructPointer->version)); + // Return the filter list forward list. + switch (sublistComboBoxPointer->currentIndex()) + { + case FilterListHelper::MAIN_ALLOWLIST: return filterListStructPointer->mainAllowListPointer; // The main allow list. + case FilterListHelper::MAIN_BLOCKLIST: return filterListStructPointer->mainBlockListPointer; // The main block list. + case FilterListHelper::INITIAL_DOMAIN_BLOCKLIST: return filterListStructPointer->initialDomainBlockListPointer; // The initial domain block list. + case FilterListHelper::REGULAR_EXPRESSION_BLOCKLIST: return filterListStructPointer->regularExpressionBlockListPointer; // The regular expression block list. + } + + // This return statement should never be reached. + return new std::forward_list; } -void FilterListsDialog::populateFilterListTextEdit(int filterListComboBoxInt) const +FilterListStruct *FilterListsDialog::getFilterListStruct(int filterListComboBoxIndex) const { - // Create the filter list struct pointer. - FilterListStruct *filterListStructPointer; - - // Get the indicated filter list map. - switch (filterListComboBoxInt) + // Return the filer list struct. + switch (filterListComboBoxIndex) { - case 0: // UltraList. - filterListStructPointer = globalFilterListHelperPointer->ultraListStructPointer; - break; - - case 1: // UltraPrivacy. - filterListStructPointer = globalFilterListHelperPointer->ultraPrivacyStructPointer; - break; + case 0: return globalFilterListHelperPointer->ultraPrivacyStructPointer; // UltraPrivacy. + case 1: return globalFilterListHelperPointer->ultraListStructPointer; // UltraList. + case 2: return globalFilterListHelperPointer->easyPrivacyStructPointer; // EasyPrivacy. + case 3: return globalFilterListHelperPointer->easyListStructPointer; // EasyList. + case 4: return globalFilterListHelperPointer->fanboyAnnoyanceStructPointer; // Fanboy's Annoyance List. + } - case 2: // EasyList. - filterListStructPointer = globalFilterListHelperPointer->easyListStructPointer; - break; + // This return statement should never be reached. + return new FilterListStruct; +} - case 3: // EasyPrivacy. - filterListStructPointer = globalFilterListHelperPointer->easyPrivacyStructPointer; - break; +void FilterListsDialog::populateFilterListComboBox(const FilterListStruct *filterListStructPointer) const +{ + // Populate the filter list combo box. + filterListComboBoxPointer->addItem(i18nc("Filter list combo box items", "%1 - %2", filterListStructPointer->title, filterListStructPointer->version)); +} - case 4: // Fanboy's Annoyance List. - filterListStructPointer = globalFilterListHelperPointer->fanboyAnnoyanceStructPointer; - break; - } +void FilterListsDialog::populateFilterListTextEdit(int filterListComboBoxIndex) const +{ + // Get the filter list struct. + FilterListStruct *filterListStructPointer = getFilterListStruct(filterListComboBoxIndex); // Get the filter list file. QFile filterListFile(filterListStructPointer->filePath); @@ -121,168 +129,194 @@ void FilterListsDialog::populateFilterListTextEdit(int filterListComboBoxInt) co sublistComboBoxPointer->clear(); // Calculate the size of the filter lists. - int mainAllowListSize = distance(filterListStructPointer->mainAllowList.begin(), filterListStructPointer->mainAllowList.end()); - int mainBlockListSize = distance(filterListStructPointer->mainBlockList.begin(), filterListStructPointer->mainBlockList.end()); - int initialDomainBlockListSize = distance(filterListStructPointer->initialDomainBlockList.begin(), filterListStructPointer->initialDomainBlockList.end()); + int mainAllowListSize = distance(filterListStructPointer->mainAllowListPointer->begin(), filterListStructPointer->mainAllowListPointer->end()); + int mainBlockListSize = distance(filterListStructPointer->mainBlockListPointer->begin(), filterListStructPointer->mainBlockListPointer->end()); + int initialDomainBlockListSize = distance(filterListStructPointer->initialDomainBlockListPointer->begin(), filterListStructPointer->initialDomainBlockListPointer->end()); + int regularExpressionBlockListSize = distance(filterListStructPointer->regularExpressionBlockListPointer->begin(), filterListStructPointer->regularExpressionBlockListPointer->end()); // Get the translated filter list names. QString mainAllowListName = globalFilterListHelperPointer->getSublistName(FilterListHelper::MAIN_ALLOWLIST); QString mainBlockListName = globalFilterListHelperPointer->getSublistName(FilterListHelper::MAIN_BLOCKLIST); QString initialDomainBlockListName = globalFilterListHelperPointer->getSublistName(FilterListHelper::INITIAL_DOMAIN_BLOCKLIST); + QString regularExpressionBlockListName = globalFilterListHelperPointer->getSublistName(FilterListHelper::REGULAR_EXPRESSION_BLOCKLIST); // Populate the sublist combo box. sublistComboBoxPointer->addItem(i18nc("The main allow list", "%1 - %2", mainAllowListName, mainAllowListSize)); sublistComboBoxPointer->addItem(i18nc("The main block list", "%1 - %2", mainBlockListName, mainBlockListSize)); sublistComboBoxPointer->addItem(i18nc("The initial domain block list", "%1 - %2", initialDomainBlockListName, initialDomainBlockListSize)); + sublistComboBoxPointer->addItem(i18nc("the regular expression block list", "%1 - %2", regularExpressionBlockListName, regularExpressionBlockListSize)); } void FilterListsDialog::populateTableWidget(int sublistComboBoxIndex) const { - // Wipe the current table. - sublistTableWidgetPointer->clear(); - sublistTableWidgetPointer->setColumnCount(0); - sublistTableWidgetPointer->setRowCount(0); - - // Create the filter list struct. - FilterListStruct *filterListStructPointer; - - // Populate the filer list array. - switch (filterListComboBoxPointer->currentIndex()) - { - case 0: // UltraList. - filterListStructPointer = globalFilterListHelperPointer->ultraListStructPointer; - break; - - case 1: // UltraPrivacy. - filterListStructPointer = globalFilterListHelperPointer->ultraPrivacyStructPointer; - break; - - case 2: // EasyList. - filterListStructPointer = globalFilterListHelperPointer->easyListStructPointer; - break; - - case 3: // EasyPrivacy. - filterListStructPointer = globalFilterListHelperPointer->easyPrivacyStructPointer; - break; - - case 4: // Fanboy's Annoyance List. - filterListStructPointer = globalFilterListHelperPointer->fanboyAnnoyanceStructPointer; - break; - } - - // Create a filter list forward list. - std::forward_list filterListForwardList; - - // Populate the filter list forward list. - switch (sublistComboBoxIndex) + // Populate the table widget if there is at least one item in teh sublist combo box. + if (sublistComboBoxIndex >= 0) { - case FilterListHelper::MAIN_ALLOWLIST: // The main allow list. - filterListForwardList = filterListStructPointer->mainAllowList; - break; - - case FilterListHelper::MAIN_BLOCKLIST: // The main block list. - filterListForwardList = filterListStructPointer->mainBlockList; - break; - - case FilterListHelper::INITIAL_DOMAIN_BLOCKLIST: // The initial domain block list. - filterListForwardList = filterListStructPointer->initialDomainBlockList; - break; + // Wipe the current table. + sublistTableWidgetPointer->clear(); + sublistTableWidgetPointer->setColumnCount(0); + sublistTableWidgetPointer->setRowCount(0); + + // Get the filter list struct. + FilterListStruct *filterListStructPointer = getFilterListStruct(filterListComboBoxPointer->currentIndex()); + + // Create a filter list forward list. + std::forward_list *filterListForwardListPointer; + + // Populate the filter list forward list. + switch (sublistComboBoxIndex) + { + case FilterListHelper::MAIN_ALLOWLIST: // The main allow list. + filterListForwardListPointer = filterListStructPointer->mainAllowListPointer; + break; + + case FilterListHelper::MAIN_BLOCKLIST: // The main block list. + filterListForwardListPointer = filterListStructPointer->mainBlockListPointer; + break; + + case FilterListHelper::INITIAL_DOMAIN_BLOCKLIST: // The initial domain block list. + filterListForwardListPointer = filterListStructPointer->initialDomainBlockListPointer; + break; + + case FilterListHelper::REGULAR_EXPRESSION_BLOCKLIST: // the regular expression block list. + filterListForwardListPointer = filterListStructPointer->regularExpressionBlockListPointer; + break; + } + + // Create the columns. + sublistTableWidgetPointer->setColumnCount(21); + + // Create the table headers. + QTableWidgetItem *appliedEntryListHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist applied entry list header", "Applied Entry List")); + QTableWidgetItem *initialMatchHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist initial match header", "Initial Match")); + QTableWidgetItem *finalMatchHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist final match header", "Final Match")); + QTableWidgetItem *domainHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist domain header", "Domain")); + QTableWidgetItem *domainListHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist domain list Header", "Domain List")); + QTableWidgetItem *thirdPartyHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist third-party header", "Third Party")); + QTableWidgetItem *hasRequestOptionsHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist has request options header", "Has Request Options")); + QTableWidgetItem *fontHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist font header", "Font")); + QTableWidgetItem *imageHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist image header", "Image")); + QTableWidgetItem *mainFrameHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist main frame header", "Main Frame")); + QTableWidgetItem *mediaHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist media header", "Media")); + QTableWidgetItem *objectHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist object header", "Object")); + QTableWidgetItem *otherHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist object header", "Other")); + QTableWidgetItem *pingHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist ping header", "Ping")); + QTableWidgetItem *scriptHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist script header", "Script")); + QTableWidgetItem *styleSheetHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist style sheet header", "Style Sheet")); + QTableWidgetItem *subFrameHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist sub frame header", "Sub Frame")); + QTableWidgetItem *xmlHttpRequestHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist XML HTTP request header", "XML HTTP Request")); + QTableWidgetItem *appliedFilterOptionsHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist applied filter options header", "Applied Filter Options")); + QTableWidgetItem *originalFilterOptionsHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist original filter options header", "Original Filter Options")); + QTableWidgetItem *originalEntryHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist original entry header", "Original Entry")); + + // Set the horizontal headers. + sublistTableWidgetPointer->setHorizontalHeaderItem(0, appliedEntryListHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(1, initialMatchHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(2, finalMatchHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(3, domainHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(4, domainListHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(5, thirdPartyHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(6, hasRequestOptionsHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(7, fontHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(8, imageHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(9, mainFrameHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(10, mediaHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(11, objectHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(12, otherHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(13, pingHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(14, scriptHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(15, styleSheetHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(16, subFrameHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(17, xmlHttpRequestHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(18, appliedFilterOptionsHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(19, originalFilterOptionsHeaderItemPointer); + sublistTableWidgetPointer->setHorizontalHeaderItem(20, originalEntryHeaderItemPointer); + + // Initialize the row counter. + int rowCounter = 0; + + // Populate the table. + for (auto filterListEntry = filterListForwardListPointer->begin(); filterListEntry != filterListForwardListPointer->end(); ++filterListEntry) { + // Get the entry struct. + EntryStruct *entryStructPointer = *filterListEntry; + + // Add a new row. + sublistTableWidgetPointer->insertRow(rowCounter); + + // Create the entry items. + QTableWidgetItem *appliedEntryListItemPointer = new QTableWidgetItem(entryStructPointer->appliedEntryList.join(QLatin1String(" * "))); + QTableWidgetItem *initialMatchItemPointer = new QTableWidgetItem(entryStructPointer->initialMatch ? i18n("Yes") : QLatin1String()); + QTableWidgetItem *finalMatchItemPointer = new QTableWidgetItem(entryStructPointer->finalMatch ? i18n("Yes") : QLatin1String()); + QTableWidgetItem *domainItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->domain)); + QTableWidgetItem *domainListItemPointer = new QTableWidgetItem(entryStructPointer->domainList.join(QLatin1String(" | "))); + QTableWidgetItem *thirdPartyItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->thirdParty)); + QTableWidgetItem *hasRequestOptionsItemPointer = new QTableWidgetItem(entryStructPointer->hasRequestOptions ? i18n("Yes") : QLatin1String()); + QTableWidgetItem *fontItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->font)); + QTableWidgetItem *imageItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->image)); + QTableWidgetItem *mainFrameItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->mainFrame)); + QTableWidgetItem *mediaItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->media)); + QTableWidgetItem *objectItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->object)); + QTableWidgetItem *otherItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->other)); + QTableWidgetItem *pingItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->ping)); + QTableWidgetItem *scriptItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->script)); + QTableWidgetItem *styleSheetItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->styleSheet)); + QTableWidgetItem *subFrameItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->subFrame)); + QTableWidgetItem *xmlHttpRequestItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getRequestOptionDispositionString(entryStructPointer->xmlHttpRequest)); + QTableWidgetItem *appliedFilterOptionsItemPointer = new QTableWidgetItem(entryStructPointer->appliedFilterOptionsList.join(QLatin1String(" , "))); + QTableWidgetItem *originalFilterOptionsItemPointer = new QTableWidgetItem(entryStructPointer->originalFilterOptions); + QTableWidgetItem *originalEntryItemPointer = new QTableWidgetItem(entryStructPointer->originalEntry); + + // Add the entries to the table. + sublistTableWidgetPointer->setItem(rowCounter, 0, appliedEntryListItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 1, initialMatchItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 2, finalMatchItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 3, domainItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 4, domainListItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 5, thirdPartyItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 6, hasRequestOptionsItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 7, fontItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 8, imageItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 9, mainFrameItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 10, mediaItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 11, objectItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 12, otherItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 13, pingItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 14, scriptItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 15, styleSheetItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 16, subFrameItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 17, xmlHttpRequestItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 18, appliedFilterOptionsItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 19, originalFilterOptionsItemPointer); + sublistTableWidgetPointer->setItem(rowCounter, 20, originalEntryItemPointer); + + // Increment the row counter. + ++rowCounter; + } + + // Get the table header view. + QHeaderView *headerViewPointer = sublistTableWidgetPointer->horizontalHeader(); + + // Resize the header to fit the contents. + headerViewPointer->resizeSections(QHeaderView::ResizeToContents); + + // Connect changes in the sort order. + connect(headerViewPointer, SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(sortTable(int, Qt::SortOrder))); } +} - // Create the columns. - sublistTableWidgetPointer->setColumnCount(15); - - // Create the table headers. - QTableWidgetItem *appliedEntryHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist applied entry header", "Applied Entry")); - QTableWidgetItem *thirdPartyHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist third-party header", "Third-Party")); - QTableWidgetItem *fontHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist font header", "Font")); - QTableWidgetItem *imageHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist image header", "Image")); - QTableWidgetItem *mainFrameHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist main frame header", "Main Frame")); - QTableWidgetItem *mediaHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist media header", "Media")); - QTableWidgetItem *objectHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist object header", "Object")); - QTableWidgetItem *otherHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist object header", "Other")); - QTableWidgetItem *pingHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist ping header", "Ping")); - QTableWidgetItem *scriptHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist script header", "Script")); - QTableWidgetItem *styleSheetHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist style sheet header", "Style Sheet")); - QTableWidgetItem *subFrameHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist sub frame header", "Sub Frame")); - QTableWidgetItem *xmlHttpRequestHeaderItemPointer = new QTableWidgetItem(i18nc("XML HTTP request header", "XML HTTP Request")); - QTableWidgetItem *filterOptionsHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist filter options header", "Filter Options")); - QTableWidgetItem *originalEntryHeaderItemPointer = new QTableWidgetItem(i18nc("Sublist original entry header", "Original Entry")); - - // Set the horizontal headers. - sublistTableWidgetPointer->setHorizontalHeaderItem(0, appliedEntryHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(1, thirdPartyHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(2, fontHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(3, imageHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(4, mainFrameHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(5, mediaHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(6, objectHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(7, otherHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(8, pingHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(9, scriptHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(10, styleSheetHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(11, subFrameHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(12, xmlHttpRequestHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(13, filterOptionsHeaderItemPointer); - sublistTableWidgetPointer->setHorizontalHeaderItem(14, originalEntryHeaderItemPointer); - - // Initialize the row counter. - int rowCounter = 0; - - // Populate the table. - for (auto filterListEntry = filterListForwardList.begin(); filterListEntry != filterListForwardList.end(); ++filterListEntry) { - // Get the entry struct. - EntryStruct *entryStructPointer = *filterListEntry; - - // Add a new row. - sublistTableWidgetPointer->insertRow(rowCounter); - - // Create the entry items. - QTableWidgetItem *appliedEntryItemPointer = new QTableWidgetItem(entryStructPointer->appliedEntry); - QTableWidgetItem *thirdPartyItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->thirdParty)); - QTableWidgetItem *fontItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->font)); - QTableWidgetItem *imageItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->image)); - QTableWidgetItem *mainFrameItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->mainFrame)); - QTableWidgetItem *mediaItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->media)); - QTableWidgetItem *objectItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->object)); - QTableWidgetItem *otherItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->other)); - QTableWidgetItem *pingItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->ping)); - QTableWidgetItem *scriptItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->script)); - QTableWidgetItem *styleSheetItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->styleSheet)); - QTableWidgetItem *subFrameItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->subFrame)); - QTableWidgetItem *xmlHttpRequestItemPointer = new QTableWidgetItem(globalFilterListHelperPointer->getFilterOptionDispositionString(entryStructPointer->xmlHttpRequest)); - QTableWidgetItem *filterOptionsItemPointer = new QTableWidgetItem(entryStructPointer->filterOptions); - QTableWidgetItem *originalEntryItemPointer = new QTableWidgetItem(entryStructPointer->originalEntry); - - // Add the entries to the table. - sublistTableWidgetPointer->setItem(rowCounter, 0, appliedEntryItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 1, thirdPartyItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 2, fontItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 3, imageItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 4, mainFrameItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 5, mediaItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 6, objectItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 7, otherItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 8, pingItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 9, scriptItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 10, styleSheetItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 11, subFrameItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 12, xmlHttpRequestItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 13, filterOptionsItemPointer); - sublistTableWidgetPointer->setItem(rowCounter, 14, originalEntryItemPointer); - - // Increment the row counter. - ++rowCounter; - } +void FilterListsDialog::showFilterEntryDialog(int row) +{ + // Get the filter list struct. + FilterListStruct *filterListStructPointer = getFilterListStruct(filterListComboBoxPointer->currentIndex()); - // Get the table header view. - QHeaderView *headerViewPointer = sublistTableWidgetPointer->horizontalHeader(); + // Create a sublist title. + QString sublistTitle = globalFilterListHelperPointer->getSublistName(sublistComboBoxPointer->currentIndex()); - // Resize the header to fit the contents. - headerViewPointer->resizeSections(QHeaderView::ResizeToContents); + // Instantiate the filter entry dialog. + FilterEntryDialog *filterEntryDialogPointer = new FilterEntryDialog(this, sublistTableWidgetPointer, row, filterListStructPointer->title, sublistTitle); - // Connect changes in the sort order. - connect(headerViewPointer, SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(sortTable(int, Qt::SortOrder))); + // Show the dialog. + filterEntryDialogPointer->show(); } void FilterListsDialog::sortTable(int column, Qt::SortOrder sortOrder) const diff --git a/src/dialogs/FilterListsDialog.h b/src/dialogs/FilterListsDialog.h index 980af28..ba87f72 100644 --- a/src/dialogs/FilterListsDialog.h +++ b/src/dialogs/FilterListsDialog.h @@ -41,6 +41,7 @@ public: private Q_SLOTS: void populateFilterListTextEdit(int filterListComboBoxIndex) const; void populateTableWidget(int sublistComboBoxIndex) const; + void showFilterEntryDialog(int row); void sortTable(int column, Qt::SortOrder sortOrder) const; private: @@ -51,6 +52,8 @@ private: QTableWidget *sublistTableWidgetPointer; // The private functions. + std::forward_list* getFilterListForwardList(FilterListStruct *filterListStructPointer) const; + FilterListStruct* getFilterListStruct(int filterListComboBoxIndex) const; void populateFilterListComboBox(const FilterListStruct *filterListStructPointer) const; }; #endif diff --git a/src/dialogs/RequestDetailDialog.cpp b/src/dialogs/RequestDetailDialog.cpp index 14947fd..78e2f00 100644 --- a/src/dialogs/RequestDetailDialog.cpp +++ b/src/dialogs/RequestDetailDialog.cpp @@ -54,8 +54,8 @@ RequestDetailDialog::RequestDetailDialog(QWidget *parentWidgetPointer, QTableWid filterListLineEditPointer = requestDetailDialogUi.filterListLineEdit; sublistLabelPointer = requestDetailDialogUi.sublistLabel; sublistLineEditPointer = requestDetailDialogUi.sublistListLineEdit; - appliedEntryLabelPointer = requestDetailDialogUi.appliedEntryLabel; - appliedEntryLineEditPointer = requestDetailDialogUi.appliedEntryLineEdit; + appliedEntryListLabelPointer = requestDetailDialogUi.appliedEntryListLabel; + appliedEntryListLineEditPointer = requestDetailDialogUi.appliedEntryListLineEdit; originalEntryLabelPointer = requestDetailDialogUi.originalEntryLabel; originalEntryLineEditPointer = requestDetailDialogUi.originalEntryLineEdit; previousButtonPointer = requestDetailDialogUi.previousButton; @@ -123,7 +123,7 @@ void RequestDetailDialog::populateDialog(const int row) // Populate the new request struct. requestStructDataStreamReader >> requestStructPointer->dispositionInt; - requestStructDataStreamReader >> requestStructPointer->entryStruct.appliedEntry; + requestStructDataStreamReader >> requestStructPointer->entryStruct.appliedEntryList; requestStructDataStreamReader >> requestStructPointer->entryStruct.originalEntry; requestStructDataStreamReader >> requestStructPointer->filterListTitle; requestStructDataStreamReader >> requestStructPointer->navigationTypeInt; @@ -140,7 +140,7 @@ void RequestDetailDialog::populateDialog(const int row) resourceTypeLineEditPointer->setText(globalFilterListHelperPointer->getResourceTypeString(requestStructPointer->resourceTypeInt)); filterListLineEditPointer->setText(requestStructPointer->filterListTitle); sublistLineEditPointer->setText(globalFilterListHelperPointer->getSublistName(requestStructPointer->sublistInt)); - appliedEntryLineEditPointer->setText(requestStructPointer->entryStruct.appliedEntry); + appliedEntryListLineEditPointer->setText(requestStructPointer->entryStruct.appliedEntryList.join(QLatin1String(" * "))); originalEntryLineEditPointer->setText(requestStructPointer->entryStruct.originalEntry); // Set the button status. @@ -161,8 +161,8 @@ void RequestDetailDialog::populateDialog(const int row) filterListLineEditPointer->hide(); sublistLabelPointer->hide(); sublistLineEditPointer->hide(); - appliedEntryLabelPointer->hide(); - appliedEntryLineEditPointer->hide(); + appliedEntryListLabelPointer->hide(); + appliedEntryListLineEditPointer->hide(); originalEntryLabelPointer->hide(); originalEntryLineEditPointer->hide(); @@ -180,8 +180,8 @@ void RequestDetailDialog::populateDialog(const int row) filterListLineEditPointer->show(); sublistLabelPointer->show(); sublistLineEditPointer->show(); - appliedEntryLabelPointer->show(); - appliedEntryLineEditPointer->show(); + appliedEntryListLabelPointer->show(); + appliedEntryListLineEditPointer->show(); originalEntryLabelPointer->show(); originalEntryLineEditPointer->show(); @@ -199,8 +199,8 @@ void RequestDetailDialog::populateDialog(const int row) filterListLineEditPointer->show(); sublistLabelPointer->show(); sublistLineEditPointer->show(); - appliedEntryLabelPointer->show(); - appliedEntryLineEditPointer->show(); + appliedEntryListLabelPointer->show(); + appliedEntryListLineEditPointer->show(); originalEntryLabelPointer->show(); originalEntryLineEditPointer->show(); diff --git a/src/dialogs/RequestDetailDialog.h b/src/dialogs/RequestDetailDialog.h index c15fcad..8fb21c4 100644 --- a/src/dialogs/RequestDetailDialog.h +++ b/src/dialogs/RequestDetailDialog.h @@ -41,8 +41,8 @@ private Q_SLOTS: private: // The private variables. - QLabel *appliedEntryLabelPointer; - QLineEdit *appliedEntryLineEditPointer; + QLabel *appliedEntryListLabelPointer; + QLineEdit *appliedEntryListLineEditPointer; int currentRow; QLineEdit *dispositionLineEditPointer; QLabel *filterListLabelPointer; diff --git a/src/dialogs/RequestsDialog.cpp b/src/dialogs/RequestsDialog.cpp index 82535e8..43e1809 100644 --- a/src/dialogs/RequestsDialog.cpp +++ b/src/dialogs/RequestsDialog.cpp @@ -100,7 +100,7 @@ RequestsDialog::RequestsDialog(QWidget *parentWidgetPointer, QListdispositionInt; - requestStructDataStream << requestStructPointer->entryStruct.appliedEntry; + requestStructDataStream << requestStructPointer->entryStruct.appliedEntryList; requestStructDataStream << requestStructPointer->entryStruct.originalEntry; requestStructDataStream << requestStructPointer->filterListTitle; requestStructDataStream << requestStructPointer->navigationTypeInt; diff --git a/src/helpers/FilterListHelper.cpp b/src/helpers/FilterListHelper.cpp index f84112b..e4ce25f 100644 --- a/src/helpers/FilterListHelper.cpp +++ b/src/helpers/FilterListHelper.cpp @@ -21,14 +21,15 @@ #include "FilterListHelper.h" #include "structs/OverrideStruct.h" +// KDE Framework headers. +#include + // Qt toolkit headers. #include #include +#include #include -// KDE Framework headers. -#include - // Construct the class. FilterListHelper::FilterListHelper() { @@ -78,18 +79,19 @@ FilterListHelper::FilterListHelper() MAIN_ALLOWLIST_STRING = i18nc("Main allowlist sublist", "Main Allow List"); MAIN_BLOCKLIST_STRING = i18nc("Main blocklist sublist", "Main Block List"); INITIAL_DOMAIN_BLOCKLIST_STRING = i18nc("Initial domain blocklist string", "Initial Domain Block List"); + REGULAR_EXPRESSION_BLOCKLIST_STRING = i18nc("Regular expression blocklist string", "Regular Expression Block List"); // Populate the filter lists. - ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt")); ultraPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/ultraprivacy.txt")); - easyListStructPointer = populateFilterList(QLatin1String(":/filterlists/easylist.txt")); + ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt")); easyPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/easyprivacy.txt")); + easyListStructPointer = populateFilterList(QLatin1String(":/filterlists/easylist.txt")); fanboyAnnoyanceStructPointer = populateFilterList(QLatin1String(":/filterlists/fanboy-annoyance.txt")); } bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const { - // Initiate a continue checking tracker. If the tracker changes to false, all process of the request will be stopped. + // Initiate a continue checking tracker. If the tracker changes to false, all processing of the request will be stopped. bool continueChecking = true; // Create a URL struct. @@ -101,10 +103,10 @@ bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo // Get the hosts. QString firstPartyHost = firstPartyUrl.host(); - QString requestHost = requestUrl.host(); + urlStruct.fqdn = requestUrl.host(); // Determine if this is a third-party request. - urlStruct.isThirdPartyRequest = (firstPartyHost != requestHost); + urlStruct.isThirdPartyRequest = (firstPartyHost != urlStruct.fqdn); // Get the request URL string. urlStruct.urlString = requestUrl.toString(); @@ -119,8 +121,9 @@ bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo urlStruct.urlStringWithSeparators.replace(QLatin1Char('='), QLatin1Char('^')); urlStruct.urlStringWithSeparators.replace(QLatin1Char('&'), QLatin1Char('^')); - // Add a `^` to the end of the string. - urlStruct.urlStringWithSeparators.append(QLatin1Char('^')); + // Add a `^` to the end of the string it it doesn't already contain one. + if (!urlStruct.urlStringWithSeparators.endsWith(QLatin1Char('^'))) + urlStruct.urlStringWithSeparators.append(QLatin1Char('^')); // Create truncated URL strings and initially populate it with the original URL strings. urlStruct.truncatedUrlString = urlStruct.urlString; @@ -134,20 +137,21 @@ bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo urlStruct.truncatedUrlStringWithSeparators.remove(0, fqdnIndex); // Check UltraList. - continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraListStructPointer); + continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraPrivacyStructPointer); // Check UltraPrivacy. if (continueChecking) - continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraPrivacyStructPointer); - - // Check EasyList. - if (continueChecking) - continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyListStructPointer); + continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraListStructPointer); // Check EasyPrivacy. if (continueChecking) continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyPrivacyStructPointer); + // Check EasyList. + if (continueChecking) + continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyListStructPointer); + + // Check Fanboy's Annoyance list. if (continueChecking) continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, fanboyAnnoyanceStructPointer); @@ -155,35 +159,22 @@ bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo return continueChecking; } -bool FilterListHelper::blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, - EntryStruct *entryStructPointer) const -{ - // Block the request. - urlRequestInfo.block(true); - - // Populate the request struct. - populateRequestStruct(requestStructPointer, BLOCKED, filterListTitle, sublistInt, entryStructPointer); - - // Log the block. - //qDebug().noquote().nospace() << "Blocked request: " << urlRequestInfo.firstPartyUrl() << ", Filter list entry: " << entryStructPointer->appliedEntry; - - // Returning `false` stops all processing of the request. - return false; -} - bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, FilterListStruct *filterListStructPointer) const { + // Initiate a continue checking tracker. If the tracker changes to false, all process of the request will be stopped. + bool continueChecking = true; + // Check the main allow list. - for (auto filterListEntry = filterListStructPointer->mainAllowList.begin(); filterListEntry != filterListStructPointer->mainAllowList.end(); ++filterListEntry) + for (auto filterListEntry = filterListStructPointer->mainAllowListPointer->begin(); filterListEntry != filterListStructPointer->mainAllowListPointer->end(); ++filterListEntry) { // Get the entry struct. EntryStruct *entryStructPointer = *filterListEntry; // TODO. Temporarily ignore empty applied entries. - if (!entryStructPointer->appliedEntry.isEmpty()) + if (!entryStructPointer->appliedEntryList[0].isEmpty()) { - // Check if the URL string contains the applied entry. - if (urlStruct.urlString.contains(entryStructPointer->appliedEntry) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntry)) + // Check if the URL string contains the applied entry. TODO. + if (urlStruct.urlString.contains(entryStructPointer->appliedEntryList[0]) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntryList[0])) { // Allow the request. urlRequestInfo.block(false); @@ -200,47 +191,384 @@ bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestI } } + // Get the main block list end. + auto mainBlockListEnd = filterListStructPointer->mainBlockListPointer->end(); + // Check the main block list. - for (auto filterListEntry = filterListStructPointer->mainBlockList.begin(); filterListEntry != filterListStructPointer->mainBlockList.end(); ++filterListEntry) + for (auto mainBlockListEntry = filterListStructPointer->mainBlockListPointer->begin(); mainBlockListEntry != mainBlockListEnd; ++mainBlockListEntry) { + // Exit the loop if continue checking is false. + if (!continueChecking) + break; + // Get the entry struct. - EntryStruct *entryStructPointer = *filterListEntry; + EntryStruct *entryStructPointer = *mainBlockListEntry; - // TODO. Temporarily ignore empty applied entries. - if (!entryStructPointer->appliedEntry.isEmpty()) + // Check the applied entries. + continueChecking = checkAppliedEntry(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, MAIN_BLOCKLIST, entryStructPointer, urlStruct.urlString, + urlStruct.urlStringWithSeparators); + } + + // Get the initial domain block list end. + auto initialDomainBlockListEnd = filterListStructPointer->initialDomainBlockListPointer->end(); + + // Check the initial domain block list. + for (auto initialDomainBlockListEntry = filterListStructPointer->initialDomainBlockListPointer->begin(); initialDomainBlockListEntry != initialDomainBlockListEnd; + ++initialDomainBlockListEntry) + { + // Exit the loop if continue checking is false. + if (!continueChecking) + break; + + // Get the entry struct. + EntryStruct *entryStructPointer = *initialDomainBlockListEntry; + + // Check the applied entries. + continueChecking = checkAppliedEntry(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, INITIAL_DOMAIN_BLOCKLIST, entryStructPointer, + urlStruct.truncatedUrlString, urlStruct.truncatedUrlStringWithSeparators); + } + + // Get the regular expression block list end. + auto regularExpressionBlockListEnd = filterListStructPointer->regularExpressionBlockListPointer->end(); + + // Check the regular expression block list. + for (auto regularExpressionBlockListEntry = filterListStructPointer->regularExpressionBlockListPointer->begin(); regularExpressionBlockListEntry != regularExpressionBlockListEnd; + ++regularExpressionBlockListEntry) + { + // Exit the loop if continue checking is false. + if (!continueChecking) + break; + + // Get the entry struct. + EntryStruct *entryStructPointer = *regularExpressionBlockListEntry; + + // Check the applied entries. + continueChecking = checkRegularExpression(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, REGULAR_EXPRESSION_BLOCKLIST, entryStructPointer); + } + + // Return the continue checking status. + return continueChecking; +} + +bool FilterListHelper::checkAppliedEntry(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, + const int sublistInt, EntryStruct *entryStructPointer, QString &urlString, QString &urlStringWithSeparators) const +{ + // Check the entries according to the number. + if (entryStructPointer->singleAppliedEntry) + { + // Process initial and final matches. + if (entryStructPointer->initialMatch && entryStructPointer->finalMatch) // This is both an initial and final match. + { + // Check the URL against the applied entry. + if ((urlString == entryStructPointer->appliedEntryList[0]) || (urlStringWithSeparators == entryStructPointer->appliedEntryList[0])) + { + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + } + else if (entryStructPointer->initialMatch) // This is an initial match. + { + // Check the URL against the applied entry. + if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0])) + { + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + } + else if (entryStructPointer->finalMatch) // This is a final match. + { + // Check the URL against the applied entry. + if (urlString.endsWith(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[0])) + { + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + } + else // There is no initial or final matching. { // Check if the URL string contains the applied entry. - if (urlStruct.urlString.contains(entryStructPointer->appliedEntry) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntry)) + if (urlString.contains(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.contains(entryStructPointer->appliedEntryList[0])) { - // Check the third-party status. - bool continueChecking = checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListStructPointer->title, MAIN_BLOCKLIST, entryStructPointer); + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + } + } + else // There are multiple entries. + { + // Create a URL matches flag. + bool urlMatches = true; + + // Process initial and final matches. + if (entryStructPointer->initialMatch && entryStructPointer->finalMatch) // This is both an initial and final match. + { + // Check the first entry. + if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) || + urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0])) // The URL string starts with the first applied entry. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = entryStructPointer->appliedEntryList[0].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The URL string does not end with the last applied entry. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + + // Check the other entries if the URL still matches. + if (urlMatches) + { + // Calculate the penultimate entry. + int penultimateEntryNumber = (entryStructPointer->sizeOfAppliedEntryList - 1); + int ultimateEntryIndex = penultimateEntryNumber; + + // Check all the middle entries. + for (int i = 1; i < penultimateEntryNumber; ++i) + { + // Get the index of the applied entry, which will be `-1` if it doesn't exist. + int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]); + int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]); + + // Get the larger of the two indexes. + int index = std::max(stringIndex, stringWithSeparatorsIndex); + + // Check if the entry was found. + if (index >= 0) // The entry is contained in the URL string. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The entry is not contained in the URL string. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } + + // Check the final entry if the URL still matches. + if (urlMatches) + { + if (urlString.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex]) || + urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex])) // The URL string ends with the last applied entry. + { + // There is no need to modify the URL string copies as no further checks will be performed. + } + else // The URL string does not end with the last applied entry. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } + } + } + else if (entryStructPointer->initialMatch) // This is an initial match. + { + // Check the first entry. + if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) || + urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0])) // The URL string starts with the first applied entry. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = entryStructPointer->appliedEntryList[0].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The URL string does not end with the last applied entry. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + + // Check the other entries if the URL still matches. + if (urlMatches) + { + for (int i = 1; i < entryStructPointer->sizeOfAppliedEntryList; ++i) + { + // Get the index of the applied entry, which will be `-1` if it doesn't exist. + int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]); + int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]); + + // Get the larger of the two indexes. + int index = std::max(stringIndex, stringWithSeparatorsIndex); + + // Check if the entry was found. + if (index >= 0) // The entry is contained in the URL string. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The entry is not contained in the URL string. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } + } + } + else if (entryStructPointer->finalMatch) // This is a final match. + { + // Calculate the penultimate entry. + int penultimateEntryNumber = (entryStructPointer->sizeOfAppliedEntryList - 1); + int ultimateEntryIndex = penultimateEntryNumber; + + // Check all the entries except the last one. + for (int i = 0; i < penultimateEntryNumber; ++i) + { + // Get the index of the applied entry, which will be `-1` if it doesn't exist. + int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]); + int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]); + + // Get the larger of the two indexes. + int index = std::max(stringIndex, stringWithSeparatorsIndex); + + // Check if the entry was found. + if (index >= 0) // The entry is contained in the URL string. + { + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The entry is not contained in the URL string. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } - // Stop processing the filter lists if continue checking is `false`. Returning false halts all processing at upper levels. - if (continueChecking == false) - return false; + // Check the final entry if the URL still matches. + if (urlMatches) + { + if (urlString.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex]) || + urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex])) // The URL string ends with the last applied entry. + { + // There is no need to modify the URL string copies as no further checks will be performed. + } + else // The URL string does not end with the last applied entry. + { + // Mark the URL matches flag as false. + urlMatches = false; + } } } + else // There is no initial or final matching. + { + for (int i = 0; i < entryStructPointer->sizeOfAppliedEntryList; ++i) + { + // Get the index of the applied entry, which will be `-1` if it doesn't exist. + int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]); + int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]); + + // Get the larger of the two indexes. + int index = std::max(stringIndex, stringWithSeparatorsIndex); + + // Check if the entry was found. + if (index >= 0) // The entry is contained in the URL string. + { + + // Get the number of characters to remove from the front of the URL strings. + int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size(); + + // Remove the entry from the front of the URL string copies. + urlString.remove(0, charactersToRemove); + urlStringWithSeparators.remove(0, charactersToRemove); + } + else // The entry is not contained in the URL string. + { + // Mark the URL matches flag as false. + urlMatches = false; + } + } + } + + // Check the domain status if the URL matches. + if (urlMatches) + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } - // Check the initial domain block list. - for (auto filterListEntry = filterListStructPointer->initialDomainBlockList.begin(); filterListEntry != filterListStructPointer->initialDomainBlockList.end(); ++filterListEntry) + // If the applied entry doesn't match, return `true` to continue processing the URL request. + return true; +} + +bool FilterListHelper::checkRegularExpression(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, + const int sublistInt, EntryStruct *entryStructPointer) const +{ + // Create an applied entry regular expression. + QRegularExpression appliedEntryRegularExpression(entryStructPointer->appliedEntryList[0]); + + // Check if the regular expression matches the applied entry. + if (urlStruct.urlString.contains(appliedEntryRegularExpression)) { - // Get the entry struct. - EntryStruct *entryStructPointer = *filterListEntry; + // Check the domain status. + return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } - // Check if the truncated URL string begins with the applied entry. - if (urlStruct.truncatedUrlString.startsWith(entryStructPointer->appliedEntry) || urlStruct.truncatedUrlStringWithSeparators.startsWith(entryStructPointer->appliedEntry)) + // If the regular expression doesn't match, return `true` to continue processing the URL request. + return true; +} + +bool FilterListHelper::checkDomain(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const +{ + // Check domain status. + if (entryStructPointer->domain == FilterOptionEnum::Disposition::Null) // Ignore domain status. + { + // Check the third-party status. + return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer); + } + else if (entryStructPointer->domain == FilterOptionEnum::Disposition::Apply) // Block requests from listed domains. + { + // Check each domain. + foreach (QString blockedDomain, entryStructPointer->domainList) { - // Check the third-party status. - bool continueChecking = checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListStructPointer->title, INITIAL_DOMAIN_BLOCKLIST, entryStructPointer); + // Check if the request came from a blocked domain. + if (urlStruct.fqdn.endsWith(blockedDomain)) + { + // Check the third-party status. + return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer); + } + } + } + else if (entryStructPointer->domain == FilterOptionEnum::Disposition::Override) // Block domains that are not overridden. + { + // Create a block domain flag. + bool blockDomain = true; - // Stop processing the filter lists if continue checking is `false`. Returning false halts all processing at upper levels. - if (continueChecking == false) - return false; + // Check each overridden domain. + foreach (QString overriddenDomain, entryStructPointer->domainList) + { + // Check if the request came from an overridden domain. + if (urlStruct.fqdn.endsWith(overriddenDomain)) + { + // Don't block the domain. + blockDomain = false; + } + } + + // Continue checking if the domain is blocked. + if (blockDomain) + { + // Check the third-party status. + return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer); } } - // Return `true` to continue processing the URL request. + // There is a domain specified that doesn't match this request. Return `true` to continue processing the URL request. return true; } @@ -250,13 +578,13 @@ bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, // Check third-party status. if (entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Null) // Ignore third-party status. { - // Check if filter options are applied. - if (entryStructPointer->hasFilterOptions) // Filter options are applied. + // Check if request options are applied. + if (entryStructPointer->hasRequestOptions) // Request options are applied. { - // Process the filter options. - return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Check the request options. + return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } - else // Filter options are not applied. + else // Request options are not applied. { // Block the request. return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); @@ -264,13 +592,13 @@ bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, } else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Apply) && isThirdPartyRequest) // Block third-party request. { - // Check if filter options are applied. - if (entryStructPointer->hasFilterOptions) // Filter options are applied. + // Check if request options are applied. + if (entryStructPointer->hasRequestOptions) // Request options are applied. { - // Process the filter options. - return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Check the request options. + return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } - else // Filter options are not applied. + else // Request options are not applied. { // Block the request. return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); @@ -278,23 +606,133 @@ bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, } else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Override) && !isThirdPartyRequest) // Block first-party requests. { - // Check if filter options are applied. - if (entryStructPointer->hasFilterOptions) // Filter options are applied. + // Check if request options are applied. + if (entryStructPointer->hasRequestOptions) // Request options are applied. { - // Process the filter options. - return processFilterOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Check the request options. + return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } - else // Filter options are not applied. + else // Request options are not applied. { // Block the request. return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); } } - // Returning `true` continues to process the filter lists. Returning `false` halts all processing of the filter lists. + // The third-party option specified doesn't match this request. Return `true` to continue processing the URL request. + return true; +} + +bool FilterListHelper::checkRequestOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const +{ + // Block font requests. + if ((entryStructPointer->font == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFontResource)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block image requests. + if ((entryStructPointer->image == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeImage)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block main frame requests. + if ((entryStructPointer->mainFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMainFrame) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame))) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block media requests. + if ((entryStructPointer->media == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMedia)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block object requests. + if ((entryStructPointer->object == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeObject)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block other requests. + if ((entryStructPointer->other == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubResource) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeWorker) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSharedWorker) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePrefetch) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFavicon) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeServiceWorker) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeCspReport) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePluginResource) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeUnknown))) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block ping requests + if ((entryStructPointer->ping == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePing)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block script requests. + if ((entryStructPointer->script == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeScript)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block style sheet requests. + if ((entryStructPointer->styleSheet == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeStylesheet)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block sub resource requests. + if ((entryStructPointer->subFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubFrame) || + (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame))) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // Block XML HTTP requests. + if ((entryStructPointer->xmlHttpRequest == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeXhr)) + { + // Block the request. + return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + } + + // The request options specified don't match this request. Return `true` to continue processing the URL request. return true; } +bool FilterListHelper::blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const +{ + // Block the request. + urlRequestInfo.block(true); + + // Populate the request struct. + populateRequestStruct(requestStructPointer, BLOCKED, filterListTitle, sublistInt, entryStructPointer); + + // Log the block. + //qDebug().noquote().nospace() << "Blocked request: " << urlRequestInfo.firstPartyUrl() << ", Filter list entry: " << entryStructPointer->appliedEntry; + + // Returning `false` stops all processing of the request. + return false; +} + QString FilterListHelper::getDispositionString(int dispositionInt) const { // Return the translated disposition string. @@ -306,17 +744,6 @@ QString FilterListHelper::getDispositionString(int dispositionInt) const } } -QString FilterListHelper::getFilterOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const -{ - // Return the translated filter option disposition string. - switch (filterOptionDisposition) - { - case FilterOptionEnum::Disposition::Apply: return FILTER_OPTION_APPLY; - case FilterOptionEnum::Disposition::Override: return FILTER_OPTION_OVERRIDE; - default: return FILTER_OPTION_NULL; - } -} - QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const { // Return the translated navigation type string. @@ -332,6 +759,17 @@ QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const } } +QString FilterListHelper::getRequestOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const +{ + // Return the translated filter option disposition string. + switch (filterOptionDisposition) + { + case FilterOptionEnum::Disposition::Apply: return FILTER_OPTION_APPLY; + case FilterOptionEnum::Disposition::Override: return FILTER_OPTION_OVERRIDE; + default: return FILTER_OPTION_NULL; + } +} + QString FilterListHelper::getResourceTypeString(int resourceTypeInt) const { // Return the translated resource type string. @@ -369,6 +807,7 @@ QString FilterListHelper::getSublistName(int sublistInt) const case MAIN_ALLOWLIST: return MAIN_ALLOWLIST_STRING; case MAIN_BLOCKLIST: return MAIN_BLOCKLIST_STRING; case INITIAL_DOMAIN_BLOCKLIST: return INITIAL_DOMAIN_BLOCKLIST_STRING; + case REGULAR_EXPRESSION_BLOCKLIST: return REGULAR_EXPRESSION_BLOCKLIST_STRING; default: return QString(); // The default return should never be reached. } } @@ -452,342 +891,362 @@ FilterListStruct* FilterListHelper::populateFilterList(const QString &filterList } else // Process the filter options. { - // Split any filter options from the end of the string. - QStringList splitEntryStringList = filterListString.split(QLatin1Char('$')); - - // Store the entry without the filter options as the filter list string. - filterListString = splitEntryStringList[0]; - - // Create a popup only filter option tracker. - bool popupOnlyFilterOption = false; + // Get the index of the last dollar sign. + int indexOfLastDollarSign = filterListString.lastIndexOf(QLatin1Char('$')); // Process the filter options if they exist. - if (splitEntryStringList.size() > 1) + if (indexOfLastDollarSign > -1) { - // Store the filter options. - entryStructPointer->filterOptions = splitEntryStringList[1]; + // Get the filter options. + entryStructPointer->originalFilterOptions = filterListString.section(QLatin1Char('$'), -1); + + // Store the entry without the filter options as the filter list string. + filterListString.truncate(indexOfLastDollarSign); // Split the filter options. - QStringList filterOptionsList = splitEntryStringList[1].split(QLatin1Char(',')); + QStringList originalFilterOptionsList = entryStructPointer->originalFilterOptions.split(QLatin1Char(',')); - // Check if the entry has a single popup filter option as Qt WebEngine doesn't know how to process them. - if ((filterOptionsList.size() == 1) && (filterOptionsList[0] == QLatin1String("popup"))) // This entry has a single popup filter option. + // Create an applied filter options list. + QStringList appliedFilterOptionsList; + + // Populate the applied filter options list. + foreach (QString filterOption, originalFilterOptionsList) { - // Set the popup only filter option flag. - popupOnlyFilterOption = true; + // Only add filter options that are handled by Privacy Browser. + if (!(filterOption.startsWith(QLatin1String("csp=")) || + filterOption.startsWith(QLatin1String("method=")) || + filterOption.startsWith(QLatin1String("redirect=")) || + filterOption.startsWith(QLatin1String("rewrite=")))) + appliedFilterOptionsList.append(filterOption); } - else // This entry has filter options besides popup. - { - // Initialize an override struct. - OverrideStruct overrideStruct; - // Populate the filter options entries. - foreach (QString filterOption, filterOptionsList) - { - // Populate the third-party options. - if (filterOption == QLatin1String("third-party")) entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("~third-party")) entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Override; - - // Populate the filter options. - if (filterOption == QLatin1String("document")) - { - // Populate the main frame option. - entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply; - - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } - - if (filterOption == QLatin1String("font")) - { - // Populate the font option. - entryStructPointer->font = FilterOptionEnum::Disposition::Apply; - - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } - - if (filterOption == QLatin1String("image")) - { - // Populate the image option. - entryStructPointer->image = FilterOptionEnum::Disposition::Apply; + // Store the applied filter options list. + entryStructPointer->appliedFilterOptionsList = appliedFilterOptionsList; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Initialize an override struct. + OverrideStruct overrideStruct; - if (filterOption == QLatin1String("media")) - { - // Populate the media option. - entryStructPointer->media = FilterOptionEnum::Disposition::Apply; + // Populate the filter options entries. + foreach (QString filterOption, appliedFilterOptionsList) + { + // Parse the filter options. + if (filterOption.startsWith(QLatin1String("domain="))) // Domain. + { + // Remove `domain=` from the filter option. + filterOption.remove(0, 7); - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Store the domain list. + entryStructPointer->domainList = filterOption.split(QLatin1Char('|')); - if (filterOption == QLatin1String("object")) + // Set the disposition. + if (entryStructPointer->domainList[0].startsWith(QLatin1Char('~'))) // Override domains. { - // Populate the object option. - entryStructPointer->object = FilterOptionEnum::Disposition::Apply; + // Populate the domain filter disposition. + entryStructPointer->domain = FilterOptionEnum::Disposition::Override; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; + // Remove the initial `~` from each domain. + entryStructPointer->domainList.replaceInStrings(QLatin1String("~"), QLatin1String("")); } - - if (filterOption == QLatin1String("other")) + else // Standard domains. { - // Populate the other option. - entryStructPointer->other = FilterOptionEnum::Disposition::Apply; - - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; + // Populate the domain filter disposition. + entryStructPointer->domain = FilterOptionEnum::Disposition::Apply; } + } + else if (filterOption == QLatin1String("third-party")) // Third-party. + { + // Populate the third-party filter disposition. + entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Apply; + } + else if (filterOption == QLatin1String("~third-party")) // Third-party override. + { + // Populate the third-party filter disposition. + entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Override; + } + else if ((filterOption == QLatin1String("document")) || (filterOption == QLatin1String("popup"))) // Document (and popup). + { + // Populate the main frame disposition. + entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("ping")) - { - // Populate the ping option. - entryStructPointer->ping = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("font")) // Font. + { + // Populate the font disposition. + entryStructPointer->font = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("image")) // Image. + { + // Populate the image disposition. + entryStructPointer->image = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("script")) - { - // Populate the script option. - entryStructPointer->script = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("media")) // Media. + { + // Populate the media disposition. + entryStructPointer->media = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("object")) // Object. + { + // Populate the object disposition. + entryStructPointer->object = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("stylesheet")) - { - // Populate the script option. - entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if ((filterOption == QLatin1String("other")) || (filterOption == QLatin1String("webrtc")) || (filterOption == QLatin1String("websocket"))) // Other. + { // `websocket` will get its own section in Qt6. + // Populate the other disposition. + entryStructPointer->other = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("ping")) // Ping. + { + // Populate the ping disposition. + entryStructPointer->ping = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("subdocument")) - { - // Populate the sub resource option. - entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("script")) // Script. + { + // Populate the script disposition. + entryStructPointer->script = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("stylesheet")) // Style sheet. + { + // Populate the script disposition. + entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply; - if (filterOption == QLatin1String("xmlhttprequest")) - { - //Populate the XML HTTP request option. - entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("subdocument")) // Sub document. + { + // Populate the sub resource disposition. + entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply; - // Set the filter options flag. - entryStructPointer->hasFilterOptions = true; - } + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("xmlhttprequest")) // XML HTTP request. + { + //Populate the XML HTTP request disposition. + entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply; + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + } + else if (filterOption == QLatin1String("~document")) // Document override. + { // Populate the override struct. - if (filterOption == QLatin1String("~document")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.mainFrame = true; - } - - if (filterOption == QLatin1String("~font")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.font = true; - } - - if (filterOption == QLatin1String("~image")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.image = true; - } - - if (filterOption == QLatin1String("~media")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.media = true; - } - - if (filterOption == QLatin1String("~object")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.object = true; - } - - if (filterOption == QLatin1String("~other")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.other = true; - } - - if (filterOption == QLatin1String("~ping")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.ping = true; - } - - if (filterOption == QLatin1String("~script")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.script = true; - } - - if (filterOption == QLatin1String("~stylesheet")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.styleSheet = true; - } - - if (filterOption == QLatin1String("~subdocument")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.subFrame = true; - } - - if (filterOption == QLatin1String("~xmlhttprequest")) - { - // Populate the override struct. - overrideStruct.hasOverride = true; - overrideStruct.xmlHttpRequest = true; - } + overrideStruct.hasOverride = true; + overrideStruct.mainFrame = true; } - - // Apply the overrides. - if (overrideStruct.hasOverride) + else if (filterOption == QLatin1String("~font")) // Font override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.font = true; + } + else if (filterOption == QLatin1String("~image")) // Image override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.image = true; + } + else if (filterOption == QLatin1String("~media")) // Media override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.media = true; + } + else if (filterOption == QLatin1String("~object")) // Object override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.object = true; + } + else if ((filterOption == QLatin1String("~other")) || (filterOption == QLatin1String("~webrtc")) || (filterOption == QLatin1String("~websocket"))) // Other override. + { // `websocket` will get its own section in Qt6. + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.other = true; + } + else if (filterOption == QLatin1String("~ping")) // Ping override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.ping = true; + } + else if (filterOption == QLatin1String("~script")) // Script override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.script = true; + } + else if (filterOption == QLatin1String("~stylesheet")) // Style sheet override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.styleSheet = true; + } + else if (filterOption == QLatin1String("~subdocument")) // Sub document override. + { + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.subFrame = true; + } + else if (filterOption == QLatin1String("~xmlhttprequest")) // XML HTTP request override. { - // Font. - if (overrideStruct.font) - entryStructPointer->font = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->font = FilterOptionEnum::Disposition::Apply; - - // Image. - if (overrideStruct.image) - entryStructPointer->image = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->image = FilterOptionEnum::Disposition::Apply; - - // Main Frame (document). - if (overrideStruct.mainFrame) - entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply; - - // Media. - if (overrideStruct.media) - entryStructPointer->media = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->media = FilterOptionEnum::Disposition::Apply; - - // Object. - if (overrideStruct.object) - entryStructPointer->object = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->object = FilterOptionEnum::Disposition::Apply; - - // Other. - if (overrideStruct.other) - entryStructPointer->other = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->other = FilterOptionEnum::Disposition::Apply; - - // Ping. - if (overrideStruct.ping) - entryStructPointer->ping = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->ping = FilterOptionEnum::Disposition::Apply; - - // Script. - if (overrideStruct.script) - entryStructPointer->script = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->script = FilterOptionEnum::Disposition::Apply; - - // Style Sheet. - if (overrideStruct.styleSheet) - entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply; - - // Sub Resource. - if (overrideStruct.subFrame) - entryStructPointer->subFrame = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply; - - // XML HTTP Request. - if (overrideStruct.xmlHttpRequest) - entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Override; - else - entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply; + // Populate the override struct. + overrideStruct.hasOverride = true; + overrideStruct.xmlHttpRequest = true; } } - } - // Drop entries that only have a single popup filter option as Qt WebEngine doesn't know how to process them. - if (popupOnlyFilterOption) // This entry has a single popup filter option. + // Apply the overrides. + if (overrideStruct.hasOverride) + { + // Set the has request options flag. + entryStructPointer->hasRequestOptions = true; + + // Font. + if (overrideStruct.font) + entryStructPointer->font = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->font = FilterOptionEnum::Disposition::Apply; + + // Image. + if (overrideStruct.image) + entryStructPointer->image = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->image = FilterOptionEnum::Disposition::Apply; + + // Main Frame (document). + if (overrideStruct.mainFrame) + entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply; + + // Media. + if (overrideStruct.media) + entryStructPointer->media = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->media = FilterOptionEnum::Disposition::Apply; + + // Object. + if (overrideStruct.object) + entryStructPointer->object = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->object = FilterOptionEnum::Disposition::Apply; + + // Other. + if (overrideStruct.other) + entryStructPointer->other = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->other = FilterOptionEnum::Disposition::Apply; + + // Ping. + if (overrideStruct.ping) + entryStructPointer->ping = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->ping = FilterOptionEnum::Disposition::Apply; + + // Script. + if (overrideStruct.script) + entryStructPointer->script = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->script = FilterOptionEnum::Disposition::Apply; + + // Style Sheet. + if (overrideStruct.styleSheet) + entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply; + + // Sub Resource. + if (overrideStruct.subFrame) + entryStructPointer->subFrame = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply; + + // XML HTTP Request. + if (overrideStruct.xmlHttpRequest) + entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Override; + else + entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply; + } + } // Finish processing filter options. + + + if (filterListString.isEmpty() && !entryStructPointer->hasRequestOptions) // There are no applied entries and no request options. { - // Do nothing. + // Ignore these entries as they will block all requests generally or for a specified domain. Typically these are left over after removing `csp=` filter options. - // Log the dropping of the line. - //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " NOT added from " << filterListFileName << " (single popup filter option)."; + // Log the dropping of the entry. + //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " NOT added from " << filterListFileName << "."; } else if (filterListString.startsWith(QLatin1String("@@"))) // Process an allow list entry. { // Remove the initial `@@`. filterListString.remove(0, 2); - // Remove any initial and trailing asterisks. - removeInitialAndTrailingAsterisks(filterListString); + // Prepare the filter list string. TODO. Initial allow lists must be processed first. + prepareFilterListString(filterListString, entryStructPointer); - // Add the applied entry to the struct. - entryStructPointer->appliedEntry = filterListString; - - // Add the filter list entry struct to the main allow list. - filterListStructPointer->mainAllowList.push_front(entryStructPointer); + // Add the entry struct to the main allow list. + filterListStructPointer->mainAllowListPointer->push_front(entryStructPointer); // Log the addition to the filter list. //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Allow List from " << filterListFileName << "."; } - else if (filterListString.startsWith(QLatin1String("||"))) // Process an initial domain allow list entry. + else if (filterListString.startsWith(QLatin1String("||"))) // Process an initial domain block list entry. { // Remove the initial `||`. filterListString.remove(0, 2); - // Add the applied entry to the struct. - entryStructPointer->appliedEntry = filterListString; + // Set the initial match flag. + entryStructPointer->initialMatch = true; + + // Prepare the filter list string. + prepareFilterListString(filterListString, entryStructPointer); - // Add the filter list entry struct to the initial domain block list. - filterListStructPointer->initialDomainBlockList.push_front(entryStructPointer); + // Add the entry struct to the initial domain block list. + filterListStructPointer->initialDomainBlockListPointer->push_front(entryStructPointer); // Log the addition to the filter list. //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Initial Domain Block List from " << filterListFileName << "."; } - else // Process a block list entry. + else if (filterListString.contains(QLatin1String("\\"))) // Process a regular expression block list entry. { - // Remove any initial and trailing asterisks. - removeInitialAndTrailingAsterisks(filterListString); + // Add the regular expression to the applied entry list. + entryStructPointer->appliedEntryList.append(filterListString); - // Add the applied entry to the struct. - entryStructPointer->appliedEntry = filterListString; + // Add the entry struct to the regular expression block list. + filterListStructPointer->regularExpressionBlockListPointer->push_front(entryStructPointer); + } + else // Process a main block list entry. + { + // Prepare the filter list string. + prepareFilterListString(filterListString, entryStructPointer); - // Add the filter list entry struct to the main block list. - filterListStructPointer->mainBlockList.push_front(entryStructPointer); + // Add the entry struct to the main block list. + filterListStructPointer->mainBlockListPointer->push_front(entryStructPointer); // Log the addition to the filter list. //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Block List from " << filterListFileName << "."; @@ -808,111 +1267,46 @@ void FilterListHelper::populateRequestStruct(RequestStruct *requestStructPointer requestStructPointer->dispositionInt = disposition; requestStructPointer->filterListTitle = filterListTitle; requestStructPointer->sublistInt = sublistInt; - requestStructPointer->entryStruct.appliedEntry = entryStructPointer->appliedEntry; + requestStructPointer->entryStruct.appliedEntryList = entryStructPointer->appliedEntryList; requestStructPointer->entryStruct.originalEntry = entryStructPointer->originalEntry; } -bool FilterListHelper::processFilterOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, - EntryStruct *entryStructPointer) const +void FilterListHelper::prepareFilterListString(QString &filterListString, EntryStruct *entryStructPointer) const { - // Block font requests. - if ((entryStructPointer->font == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFontResource)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block image requests. - if ((entryStructPointer->image == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeImage)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block main frame requests. - if ((entryStructPointer->mainFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMainFrame) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame))) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block media requests. - if ((entryStructPointer->media == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMedia)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block object requests. - if ((entryStructPointer->object == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeObject)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } - - // Block other requests. - if ((entryStructPointer->other == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubResource) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeWorker) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSharedWorker) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePrefetch) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFavicon) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeServiceWorker) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeCspReport) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePluginResource) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeUnknown))) + // Check if this is an initial match. + if (filterListString.startsWith(QLatin1Char('|'))) { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } + // Strip the initial `|`. + filterListString.remove(0, 1); - // Block ping requests - if ((entryStructPointer->ping == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePing)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Set the initial match flag. + entryStructPointer->initialMatch = true; } - // Block script requests. - if ((entryStructPointer->script == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeScript)) + // Check if this is a final match. + if (filterListString.endsWith(QLatin1Char('|'))) { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } + // Strip the final `|`. + filterListString.chop(1); - // Block style sheet requests. - if ((entryStructPointer->styleSheet == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeStylesheet)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); + // Set the final match flag. + entryStructPointer->finalMatch = true; } - // Block sub resource requests. - if ((entryStructPointer->subFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubFrame) || - (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame))) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } + // Remove the initial asterisk if it exists. + if (filterListString.startsWith(QLatin1Char('*'))) + filterListString.remove(0, 1); - // Block XML HTTP requests. - if ((entryStructPointer->xmlHttpRequest == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeXhr)) - { - // Block the request. - return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer); - } + // Remove the final asterisk if it exists. + if (filterListString.endsWith(QLatin1Char('*'))) + filterListString.chop(1); - // Returning true continues processing the filter list. - return true; -} + // Split the filter list string and set it as the applied entry list. + entryStructPointer->appliedEntryList = filterListString.split(QLatin1Char('*')); -void FilterListHelper::removeInitialAndTrailingAsterisks(QString &filterListEntry) const -{ - // Remove the initial asterisk if it exists. - if (filterListEntry.startsWith(QLatin1Char('*'))) - filterListEntry.remove(0, 1); + // Store the size of the applied entry list. + entryStructPointer->sizeOfAppliedEntryList = entryStructPointer->appliedEntryList.size(); - // Remove the final asterisk if it exists. - if (filterListEntry.endsWith(QLatin1Char('*'))) - filterListEntry.chop(1); + // Determine if this is a single applied entry (including an empty entry). + entryStructPointer->singleAppliedEntry = (entryStructPointer->sizeOfAppliedEntryList == 1); } diff --git a/src/helpers/FilterListHelper.h b/src/helpers/FilterListHelper.h index f8bfdf1..772d86a 100644 --- a/src/helpers/FilterListHelper.h +++ b/src/helpers/FilterListHelper.h @@ -44,6 +44,7 @@ public: static const int MAIN_ALLOWLIST = 0; static const int MAIN_BLOCKLIST = 1; static const int INITIAL_DOMAIN_BLOCKLIST = 2; + static const int REGULAR_EXPRESSION_BLOCKLIST = 3; // The public variables. FilterListStruct *easyListStructPointer; @@ -55,8 +56,8 @@ public: // The public functions. bool checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const; QString getDispositionString(int dispositionInt) const; - QString getFilterOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const; QString getNavigationTypeString(int navigationTypeInt) const; + QString getRequestOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const; QString getResourceTypeString(int resourceTypeInt) const; QString getSublistName(int sublistInt) const; @@ -107,16 +108,23 @@ private: QString MAIN_ALLOWLIST_STRING; QString MAIN_BLOCKLIST_STRING; QString INITIAL_DOMAIN_BLOCKLIST_STRING; + QString REGULAR_EXPRESSION_BLOCKLIST_STRING; // The private functions. bool blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, EntryStruct *entryStructPointer) const; + bool checkAppliedEntry(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer, QString &urlString, QString &urlStringWithSeparators) const; + bool checkDomain(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const; bool checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, FilterListStruct *filterListStructPointer) const; + bool checkRegularExpression(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const; + bool checkRequestOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, + EntryStruct *entryStructPointer) const; bool checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const bool isThirdPartyRequest, const QString &filterListTitle, const int sublistInt, EntryStruct *entryStructPointer) const; FilterListStruct* populateFilterList(const QString &filterListFileName) const; void populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, EntryStruct *entryStructPointer) const; - bool processFilterOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt, - EntryStruct *entryStructPointer) const; - void removeInitialAndTrailingAsterisks(QString &filterListEntry) const; + void prepareFilterListString(QString &filterListString, EntryStruct *entryStructPointer) const; }; #endif diff --git a/src/interceptors/UrlRequestInterceptor.cpp b/src/interceptors/UrlRequestInterceptor.cpp index 3b47e7e..18944ea 100644 --- a/src/interceptors/UrlRequestInterceptor.cpp +++ b/src/interceptors/UrlRequestInterceptor.cpp @@ -45,10 +45,10 @@ void UrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &urlReques requestStructPointer->urlString = urlRequestInfo.requestUrl().toString(); // Check the filter lists. - bool requestNotHandled = globalFilterListHelperPointer->checkFilterLists(urlRequestInfo, requestStructPointer); + bool continueProcessing = globalFilterListHelperPointer->checkFilterLists(urlRequestInfo, requestStructPointer); // Further process the request if it hasn't already been handled. - if (requestNotHandled) { + if (continueProcessing) { // Handle the request according to the resource type. switch (urlRequestInfo.resourceType()) { @@ -61,6 +61,9 @@ void UrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &urlReques // Mark the request struct as blocked. requestStructPointer->dispositionInt = FilterListHelper::BLOCKED; + // Mark the ping as blocked by the default behavior. + requestStructPointer->filterListTitle = i18nc("Default HTTP ping blocking", "Default blocking of all HTTP ping requests."); + // Display the HTTP Ping blocked dialog. emit displayHttpPingDialog(urlRequestInfo.requestUrl().toString()); diff --git a/src/structs/EntryStruct.h b/src/structs/EntryStruct.h index 67a43eb..3354a6a 100644 --- a/src/structs/EntryStruct.h +++ b/src/structs/EntryStruct.h @@ -24,19 +24,30 @@ #include "enums/FilterOptionEnum.h" // Qt toolkit headers. -#include +#include struct EntryStruct { // The strings. - QString appliedEntry; - QString filterOptions; QString originalEntry; + QString originalFilterOptions; - // The filter options flag. - bool hasFilterOptions = false; + // The string lists. + QStringList appliedEntryList; + QStringList appliedFilterOptionsList; + QStringList domainList; + + // The booleans. + bool finalMatch = false; + bool hasRequestOptions = false; + bool initialMatch = false; + bool singleAppliedEntry = false; + + // The ints. + int sizeOfAppliedEntryList; // The filter options. + FilterOptionEnum::Disposition domain = FilterOptionEnum::Disposition::Null; FilterOptionEnum::Disposition font = FilterOptionEnum::Disposition::Null; FilterOptionEnum::Disposition image = FilterOptionEnum::Disposition::Null; FilterOptionEnum::Disposition mainFrame = FilterOptionEnum::Disposition::Null; diff --git a/src/structs/FilterListStruct.h b/src/structs/FilterListStruct.h index ef560d1..e216068 100644 --- a/src/structs/FilterListStruct.h +++ b/src/structs/FilterListStruct.h @@ -31,11 +31,15 @@ struct FilterListStruct { + // The strings. QString title; QString version; QString filePath; - std::forward_list mainAllowList; - std::forward_list mainBlockList; - std::forward_list initialDomainBlockList; + + // The filter lists. + std::forward_list *mainAllowListPointer = new std::forward_list; + std::forward_list *mainBlockListPointer = new std::forward_list; + std::forward_list *initialDomainBlockListPointer = new std::forward_list; + std::forward_list *regularExpressionBlockListPointer = new std::forward_list; }; #endif diff --git a/src/structs/UrlStruct.h b/src/structs/UrlStruct.h index ea135d0..76a0371 100644 --- a/src/structs/UrlStruct.h +++ b/src/structs/UrlStruct.h @@ -29,6 +29,7 @@ struct UrlStruct QString urlStringWithSeparators; QString truncatedUrlString; QString truncatedUrlStringWithSeparators; + QString fqdn; bool isThirdPartyRequest; }; #endif diff --git a/src/uis/FilterEntryDialog.ui b/src/uis/FilterEntryDialog.ui new file mode 100644 index 0000000..c465d16 --- /dev/null +++ b/src/uis/FilterEntryDialog.ui @@ -0,0 +1,680 @@ + + + + + + FilterEntryDialog + + + + + + + + + + Filter List + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Sublist + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + + + + + Applied Entry List + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + + + + + Domain + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Third Party + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Initial Match + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Final Match + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + + + + + Domain List + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + + Has Request Options + + + + + Qt::NoFocus + + + + + + + + Qt::Horizontal + + + + + + + + + + + + + Font + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Image + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Main Frame + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Media + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Object + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Other + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Ping + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Script + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Style Sheet + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + Sub Frame + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + XML HTTP Request + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + + + + + + + + Applied Filter Options + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + + + + + Original Filter Options + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + + + + + Original Entry + + + + + + + + true + + + + + Qt::NoFocus + + + + + + + + + + + Qt::Vertical + + + + + + + + + + + Previous + + + + + + + + + + + + + Next + + + + + + + + + + + + + QDialogButtonBox::Close + + + + + + + + diff --git a/src/uis/RequestDetailDialog.ui b/src/uis/RequestDetailDialog.ui index 899fe31..d0a471d 100644 --- a/src/uis/RequestDetailDialog.ui +++ b/src/uis/RequestDetailDialog.ui @@ -210,15 +210,15 @@ - + - Applied Entry + Applied Entry List - + true -- 2.43.0