From 2872db14ef3052bffcdd66d78b20c4b519b3aee0 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sun, 25 Jun 2023 19:37:58 +0100 Subject: [PATCH] [Feature] Preliminary implementation of dynamic composites --- .../composites/composites_internal.hxx | 2 +- .../composites/composites_manager.cxx | 111 +++++++++++++++++- 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/src/libserver/composites/composites_internal.hxx b/src/libserver/composites/composites_internal.hxx index 5b311fc6c..af05b95df 100644 --- a/src/libserver/composites/composites_internal.hxx +++ b/src/libserver/composites/composites_internal.hxx @@ -72,7 +72,7 @@ public: } auto add_composite(std::string_view, const ucl_object_t *, bool silent_duplicate) -> rspamd_composite *; - auto add_composite(std::string_view name, std::string_view expression, bool silent_duplicate) -> rspamd_composite *; + auto add_composite(std::string_view name, std::string_view expression, bool silent_duplicate, double score = NAN) -> rspamd_composite *; private: ~composites_manager() = default; static void composites_manager_dtor(void *ptr) { diff --git a/src/libserver/composites/composites_manager.cxx b/src/libserver/composites/composites_manager.cxx index bf4491097..c0f6d3a49 100644 --- a/src/libserver/composites/composites_manager.cxx +++ b/src/libserver/composites/composites_manager.cxx @@ -23,6 +23,8 @@ #include "composites_internal.hxx" #include "libserver/cfg_file.h" #include "libserver/logger.h" +#include "libserver/maps/map.h" +#include "libutil/cxx/util.hxx" namespace rspamd::composites { @@ -149,7 +151,7 @@ composites_manager::add_composite(std::string_view composite_name, const ucl_obj auto composites_manager::add_composite(std::string_view composite_name, std::string_view composite_expression, - bool silent_duplicate) -> rspamd_composite * + bool silent_duplicate, double score) -> rspamd_composite * { GError *err = nullptr; rspamd_expression *expr = nullptr; @@ -178,8 +180,8 @@ composites_manager::add_composite(std::string_view composite_name, return nullptr; } - auto score = std::isnan(cfg->unknown_weight) ? 0.0 : cfg->unknown_weight; - rspamd_config_add_symbol(cfg, composite_name.data(), score, + auto final_score = std::isnan(score) ? (std::isnan(cfg->unknown_weight) ? 0.0 : cfg->unknown_weight) : score; + rspamd_config_add_symbol(cfg, composite_name.data(), final_score, composite_name.data(), "composite", 0, 0, @@ -188,6 +190,89 @@ composites_manager::add_composite(std::string_view composite_name, return new_composite(composite_name, expr, composite_expression).get(); } +struct map_cbdata { + composites_manager *cm; + struct rspamd_config *cfg; + std::string buf; + + explicit map_cbdata(struct rspamd_config *cfg) : cfg(cfg) { + cm = COMPOSITE_MANAGER_FROM_PTR(cfg->composites_manager); + } + + static char *map_read(char *chunk, int len, + struct map_cb_data *data, + gboolean _final) { + + if (data->cur_data == nullptr) { + data->cur_data = data->prev_data; + reinterpret_cast(data->cur_data)->buf.clear(); + } + + auto *cbd = reinterpret_cast(data->cur_data); + + cbd->buf.append(chunk, len); + return nullptr; + } + + static void + map_fin(struct map_cb_data *data, void **target) { + auto *cbd = reinterpret_cast(data->cur_data); + + if (data->errored) { + if (cbd) { + cbd->buf.clear(); + } + } + else if (cbd != nullptr) { + if (target) { + *target = data->cur_data; + } + + rspamd::string_foreach_line(cbd->buf, [&](std::string_view line) { + auto [name_and_score, expr] = rspamd::string_split_on(line, ' '); + auto [name, score] = rspamd::string_split_on(name_and_score, ':'); + + if (!score.empty()) { + /* I wish it was supported properly */ + //auto conv_res = std::from_chars(value->data(), value->size(), num); + char numbuf[128], *endptr = nullptr; + rspamd_strlcpy(numbuf, score.data(), MIN(score.size(), sizeof(numbuf))); + auto num = g_ascii_strtod(numbuf, &endptr); + + if (fabs(num) >= G_MAXFLOAT || std::isnan(num)) { + msg_err("invalid score for %*s", (int)name_and_score.size(), name_and_score.data()); + return; + } + + auto ret = cbd->cm->add_composite(name, expr, true, num); + + if (ret == nullptr) { + msg_err("cannot add composite %*s", (int)name_and_score.size(), name_and_score.data()); + return; + } + } + else { + msg_err("missing score for %*s", (int)name_and_score.size(), name_and_score.data()); + return; + } + }); + + } + else { + msg_err ("no data read for composites map"); + } + } + + static void + map_dtor (struct map_cb_data *data) { + auto *cbd = reinterpret_cast(data->cur_data); + + if (cbd) { + delete cbd; + } + } +}; + } @@ -229,3 +314,23 @@ rspamd_composites_manager_add_from_string_silent(void *cm, const char *sym, cons { return reinterpret_cast(COMPOSITE_MANAGER_FROM_PTR(cm)->add_composite(sym, expr, true)); } + + + +bool +rspamd_composites_add_map_handlers(const ucl_object_t *obj, struct rspamd_config *cfg) +{ + auto **pcbdata = rspamd_mempool_alloc_type(cfg->cfg_pool, rspamd::composites::map_cbdata *); + auto *cbdata = new rspamd::composites::map_cbdata{cfg}; + *pcbdata = cbdata; + + if (struct rspamd_map *m; (m = rspamd_map_add_from_ucl(cfg, obj, "composites map", + rspamd::composites::map_cbdata::map_read, rspamd::composites::map_cbdata::map_fin, + rspamd::composites::map_cbdata::map_dtor, (void **)pcbdata, + nullptr, RSPAMD_MAP_DEFAULT)) == nullptr) { + msg_err_config("cannot load composites map from %s", ucl_object_key(obj)); + return false; + } + + return true; +} \ No newline at end of file -- 2.39.5