Skip to content
API Documentation
BastionGuard™
ClamdConfig.cpp
Go to the documentation of this file.
1/*
2 * BastionGuard™
3 * Copyright (C) 2025–2026 Calogero Scarnà
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *
17 * BastionGuard™ is a trademark of Calogero Scarnà.
18 * The BastionGuard™ name and branding are not licensed under the GPL.
19 */
20
21#include "Resource.hpp"
22#include "ClamdConfig.hpp"
23#include <fstream>
24#include <sstream>
25#include <iostream>
26#include <filesystem>
27#include <algorithm>
28#include <cctype>
29#include <glib/gi18n.h>
30
31using namespace std;
32
33bool ClamdConfig::load(const std::string& path) {
34 rawLines.clear();
35 options.clear();
36
37 ifstream file(path);
38 if (!file.is_open()) return false;
39
40 string line;
41 while (getline(file, line)) {
42 Line ln;
43 ln.text = line;
44
45 string trimmed = line;
46 bool commented = false;
47
48 if (!trimmed.empty() && trimmed[0] == '#') {
49 commented = true;
50 trimmed = trimmed.substr(1);
51 }
52
53 istringstream iss(trimmed);
54 string key, value;
55 if (iss >> key >> value) {
56 ln.key = key;
57 ln.value = value;
58 ln.commented = commented;
59
60 if (!commented) {
61 options[key] = value;
62 }
63 }
64 rawLines.push_back(ln);
65 }
66 return true;
67}
68
69bool ClamdConfig::save(const std::string& path) {
70 ofstream file(path);
71 if (!file.is_open()) return false;
72
73 for (auto& ln : rawLines) {
74 if (!ln.key.empty()) {
75 // aggiorna il valore
76 auto it = options.find(ln.key);
77 if (it != options.end()) {
78 if (ln.commented) {
79 file << "#";
80 }
81 file << ln.key << " " << it->second << "\n";
82 continue;
83 }
84 }
85 file << ln.text << "\n";
86 }
87 return true;
88}
89
90bool ClamdConfig::backupFile(const std::string& path) const {
91 try {
92 std::filesystem::path p(path);
93 if (std::filesystem::exists(p)) {
94 auto backup = p;
95 backup += ".bak";
96 std::filesystem::copy_file(p, backup,
97 std::filesystem::copy_options::overwrite_existing);
98 }
99 return true;
100 } catch (std::exception& e) {
101 std::cerr << _("❌ Errore backup: ") << e.what() << std::endl;
102 return false;
103 }
104}
105
106bool ClamdConfig::saveWithBackup(const std::string& path) {
107 if (!backupFile(path)) {
108 std::cerr << _("❌ Impossibile creare il backup di ") << path << std::endl;
109 return false;
110 }
111 return save(path);
112}
113
114void ClamdConfig::setOption(const std::string& key, const std::string& value) {
115 options[key] = value;
116}
117
118std::string ClamdConfig::getOption(const std::string& key) const {
119 auto it = options.find(key);
120 return (it != options.end()) ? it->second : "";
121}
122
123bool ClamdConfig::getOptionBool(const std::string& key) const {
124 auto it = options.find(key);
125 if (it == options.end()) return false;
126 return isYes(it->second);
127}
128
129void ClamdConfig::setOptionBool(const std::string& key, bool enabled) {
130 options[key] = enabled ? "yes" : "no";
131}
132
133std::vector<std::string> ClamdConfig::getOnAccessPaths() const {
134 std::vector<std::string> paths;
135 for (auto& ln : rawLines) {
136 if (!ln.commented && ln.key == "OnAccessIncludePath") {
137 paths.push_back(ln.value);
138 }
139 }
140 return paths;
141}
142
143void ClamdConfig::addOnAccessPath(const std::string& path) {
144 Line ln;
145 ln.key = "OnAccessIncludePath";
146 ln.value = path;
147 ln.text = ln.key + " " + ln.value;
148 ln.commented = false;
149
150 rawLines.push_back(ln);
151 options[ln.key] = ln.value;
152}
153
154void ClamdConfig::removeOnAccessPath(const std::string& path) {
155 rawLines.erase(std::remove_if(rawLines.begin(), rawLines.end(),
156 [&](const Line& ln) {
157 return ln.key == "OnAccessIncludePath" && ln.value == path;
158 }),
159 rawLines.end());
160}
161
162std::map<std::string, bool> ClamdConfig::getScanOptions() const {
163 std::map<std::string, bool> scanOpts;
164 for (auto& ln : rawLines) {
165 if (!ln.key.empty()) {
166 // Consideriamo solo quelli che hanno valore yes/no
167 if (ln.value == "yes" || ln.value == "no") {
168 scanOpts[ln.key] = !ln.commented && isYes(ln.value);
169 }
170 }
171 }
172 return scanOpts;
173}
174
175void ClamdConfig::setScanOption(const std::string& key, bool enabled) {
176 options[key] = enabled ? "yes" : "no";
177 for (auto& ln : rawLines) {
178 if (ln.key == key) {
179 ln.value = enabled ? "yes" : "no";
180 ln.text = (ln.commented ? "#" : "") + ln.key + " " + ln.value;
181 }
182 }
183}
184
185bool ClamdConfig::isYes(const std::string& v) {
186 std::string val = v;
187 std::transform(val.begin(), val.end(), val.begin(), ::tolower);
188 return (val == "yes" || val == "true" || val == "1");
189}
#define _(s)
std::vector< std::string > getOnAccessPaths() const
static bool isYes(const std::string &v)
std::map< std::string, std::string > options
bool saveWithBackup(const std::string &path)
std::string getOption(const std::string &key) const
bool backupFile(const std::string &path) const
std::vector< Line > rawLines
void setOptionBool(const std::string &key, bool enabled)
void setOption(const std::string &key, const std::string &value)
void setScanOption(const std::string &key, bool enabled)
bool getOptionBool(const std::string &key) const
std::map< std::string, bool > getScanOptions() const
void removeOnAccessPath(const std::string &path)
void addOnAccessPath(const std::string &path)
bool load(const std::string &path)
bool save(const std::string &path)
std::string value