]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blobdiff - src/helpers/FilterListHelper.cpp
Finish block list implementation.
[PrivacyBrowserPC.git] / src / helpers / FilterListHelper.cpp
index f84112b58531ad17f1262eb68dd5e7dff5161403..e4ce25f529d3a2cbce839fa7fcac435b6eaaa055 100644 (file)
 #include "FilterListHelper.h"
 #include "structs/OverrideStruct.h"
 
+// KDE Framework headers.
+#include <KLocalizedString>
+
 // Qt toolkit headers.
 #include <QDebug>
 #include <QFile>
+#include <QRegularExpression>
 #include <QTextStream>
 
-// KDE Framework headers.
-#include <KLocalizedString>
-
 // 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);
 }