24 |
24 |
25 #include "settings.h" |
25 #include "settings.h" |
26 |
26 |
27 #include <format> |
27 #include <format> |
28 #include <algorithm> |
28 #include <algorithm> |
|
29 #include <fstream> |
29 |
30 |
30 using namespace fm; |
31 using namespace fm; |
|
32 |
|
33 static bool check_author(std::string_view author, std::string_view allowed) { |
|
34 // check for exact match |
|
35 if (author == allowed) return true; |
|
36 |
|
37 // check mail address matching |
|
38 if (author.contains(std::format("<{}>", allowed))) return true; |
|
39 |
|
40 // check local-part from mail address matching |
|
41 if (author.contains(std::format("<{}@", allowed))) return true; |
|
42 |
|
43 return false; |
|
44 } |
31 |
45 |
32 [[nodiscard]] bool settings::exclude_author(const std::string &author) const { |
46 [[nodiscard]] bool settings::exclude_author(const std::string &author) const { |
33 // no allow-list means: always allowed |
47 // no allow-list means: always allowed |
34 if (authors.empty()) return false; |
48 if (authors.empty()) return false; |
35 |
49 |
36 // check all allowed authors |
50 // check all allowed authors |
37 return std::ranges::all_of(authors, [&](const auto &allowed) { |
51 return !std::ranges::any_of(authors, [&](const auto &allowed) { |
38 // check for exact match |
52 return check_author(author, allowed); |
39 if (author == allowed) return false; |
|
40 |
|
41 // check mail address matching |
|
42 if (author.contains(std::format("<{}>", allowed))) return false; |
|
43 |
|
44 // check local-part from mail address matching |
|
45 if (author.contains(std::format("<{}@", allowed))) return false; |
|
46 |
|
47 return true; |
|
48 }); |
53 }); |
49 } |
54 } |
|
55 |
|
56 std::string_view trim(const std::string& str) { |
|
57 size_t s = str.find_first_not_of(" \t"); |
|
58 size_t l = str.find_last_not_of(" \t") + 1 - s; |
|
59 return std::string_view{str}.substr(s, l); |
|
60 } |
|
61 |
|
62 int settings::parse_authormap(const std::string& path) { |
|
63 std::ifstream file(path); |
|
64 |
|
65 if (!file.is_open()) { |
|
66 return -1; |
|
67 } |
|
68 |
|
69 std::string line; |
|
70 while (std::getline(file, line)) { |
|
71 line = trim(line); |
|
72 |
|
73 // skip empty lines and comments |
|
74 if (line.empty() || line[0] == '#') { |
|
75 continue; |
|
76 } |
|
77 |
|
78 // find delimiter |
|
79 size_t delimPos = line.find('='); |
|
80 if (delimPos == std::string::npos) { |
|
81 return -1; |
|
82 } |
|
83 |
|
84 auto key = std::string{trim(line.substr(0, delimPos))}; |
|
85 auto value = std::string{trim(line.substr(delimPos + 1))}; |
|
86 authormap[std::move(key)] = std::move(value); |
|
87 } |
|
88 |
|
89 return 0; |
|
90 } |
|
91 |
|
92 std::string settings::map_author(std::string_view author) const { |
|
93 if (authormap.empty()) return std::string{author}; |
|
94 |
|
95 for (const auto &[old_name, new_name] : authormap) { |
|
96 if (check_author(author, old_name)) return new_name; |
|
97 } |
|
98 |
|
99 return std::string{author}; |
|
100 } |