aboutsummaryrefslogtreecommitdiff
path: root/lib/urlfilter/filtertree.cpp
blob: 2cdd6d00d61e3f1f564be09b58040a90113e788e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
 * This file is part of smolbote. It's copyrighted by the contributors recorded
 * in the version control history of the file, available from its original
 * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#include "filtertree.h"
#include "filterleaf.h"
#include "formats/hostlistrule.h"
#include <QTextStream>

bool loadHostlist(QIODevice &from, FilterTree *tree)
{
    Q_ASSERT(from.isReadable());
    QTextStream stream(&from);
    while(!stream.atEnd()) {
        const QString line = stream.readLine().trimmed();
        if(line.isEmpty() || line.startsWith(QLatin1Literal("#")))
            continue;

        const QStringList &parts = line.split(QLatin1Literal(" "));
        if(parts.length() < 2) {
#ifdef QT_DEBUG
            qDebug("Cannot parse: %s", qUtf8Printable(line));
#endif
            return false;
        }

        for(int i = 1; i < parts.length(); ++i) {
            // HostlistRule(domain, redirect)
            auto *rule = new HostlistRule(parts.at(i), parts.constFirst());
            // addRule(rule, enable_on_domain)
            const bool added = tree->addRule(rule, QString());
            if(!added)
                return false;
        }
    }
    return true;
}

FilterTree::~FilterTree()
{
    for(auto &branch : m_branches) {
        qDeleteAll(branch.leaves);
        branch.leaves.clear();
    }
}

const QStringList FilterTree::branches() const
{
    QStringList branches;
    for(auto &branch : m_branches) {
        branches.append(branch.domain.host());
    }
    return branches;
}

QVector<const FilterLeaf *> FilterTree::match(const QUrl &domain, const QUrl &requestUrl) const
{
    QVector<const FilterLeaf *> leaves;
    for(const auto &branch : m_branches) {
        if(branch.domain.matches(domain)) {

            for(const auto leaf : branch.leaves) {
                if(leaf->match(requestUrl)) {
                    leaves.append(leaf);
                }
            }
        }
    }
    return leaves;
}

bool FilterTree::addRule(FilterLeaf *rule, const QString &domain)
{
    branchLock.lock();
    this->branch(domain).leaves.emplace_back(rule);
    branchLock.unlock();
    return true;
}

FilterTree::Branch & FilterTree::branch(const QString& domain)
{
    for(auto &branch : m_branches) {
        if(branch.domain.matches(QUrl(domain)))
            return branch;
    }

    // no branch was found
    Branch branch(domain);
    return m_branches.emplace_back(std::move(branch));
}