aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libutil/str_util.c4
-rw-r--r--src/rspamadm/confighelp.c86
2 files changed, 89 insertions, 1 deletions
diff --git a/src/libutil/str_util.c b/src/libutil/str_util.c
index faa33dc8f..8487e8ef2 100644
--- a/src/libutil/str_util.c
+++ b/src/libutil/str_util.c
@@ -1088,6 +1088,10 @@ rspamd_substring_search (const gchar *in, gsize inlen,
gint d, hash_srch, hash_in;
gsize i, j;
+ if (inlen < srchlen) {
+ return -1;
+ }
+
/* Preprocessing */
for (d = i = 1; i < srchlen; ++i) {
/* computes d = 2^(m-1) with the left-shift operator */
diff --git a/src/rspamadm/confighelp.c b/src/rspamadm/confighelp.c
index 1988989e5..1c2aaaf81 100644
--- a/src/rspamadm/confighelp.c
+++ b/src/rspamadm/confighelp.c
@@ -22,6 +22,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <ucl.h>
#include "config.h"
#include "rspamadm.h"
#include "cfg_file.h"
@@ -31,6 +32,7 @@
static gboolean json = FALSE;
static gboolean compact = FALSE;
+static gboolean keyword = FALSE;
extern struct rspamd_main *rspamd_main;
/* Defined in modules.c */
extern module_t *modules[];
@@ -52,6 +54,8 @@ static GOptionEntry entries[] = {
"Output json", NULL},
{"compact", 'c', 0, G_OPTION_ARG_NONE, &compact,
"Output compacted", NULL},
+ {"keyword", 'k', 0, G_OPTION_ARG_NONE, &keyword,
+ "Search by keyword", NULL},
{NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}
};
@@ -64,6 +68,9 @@ rspamadm_confighelp_help (gboolean full_help)
help_str = "Shows help for the specified configuration options\n\n"
"Usage: rspamadm confighelp [option[, option...]]\n"
"Where options are:\n\n"
+ "-c: output compacted JSON\n"
+ "-j: output pretty formatted JSON\n"
+ "-k: search by keyword in doc string\n"
"--help: shows available options and commands";
}
else {
@@ -105,6 +112,72 @@ rspamadm_confighelp_show (const char *key, const ucl_object_t *obj)
}
static void
+rspamadm_confighelp_search_word_step (const ucl_object_t *obj,
+ ucl_object_t *res,
+ const gchar *str,
+ gsize len,
+ GString *path)
+{
+ ucl_object_iter_t it = NULL;
+ const ucl_object_t *cur, *elt;
+ const gchar *dot_pos;
+
+ while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
+ if (cur->keylen > 0) {
+ rspamd_printf_gstring (path, ".%*s", (int) cur->keylen, cur->key);
+
+ if (rspamd_substring_search (cur->key, cur->keylen, str, len) !=
+ -1) {
+ ucl_object_insert_key (res, ucl_object_ref (cur),
+ path->str, path->len, true);
+ goto fin;
+ }
+ }
+
+ if (ucl_object_type (cur) == UCL_OBJECT) {
+ elt = ucl_object_find_key (cur, "data");
+
+ if (elt != NULL && ucl_object_type (elt) == UCL_STRING) {
+ if (rspamd_substring_search (elt->value.sv,
+ elt->len,
+ str,
+ len) != -1) {
+ ucl_object_insert_key (res, ucl_object_ref (cur),
+ path->str, path->len, true);
+ goto fin;
+ }
+ }
+
+ rspamadm_confighelp_search_word_step (cur, res, str, len, path);
+ }
+
+ fin:
+ /* Remove the last component of the path */
+ dot_pos = strrchr (path->str, '.');
+
+ if (dot_pos) {
+ g_string_erase (path, dot_pos - path->str,
+ path->len - (dot_pos - path->str));
+ }
+ }
+}
+
+static ucl_object_t *
+rspamadm_confighelp_search_word (const ucl_object_t *obj, const gchar *str)
+{
+ gsize len = strlen (str);
+ GString *path = g_string_new ("");
+ ucl_object_t *res;
+
+
+ res = ucl_object_typed_new (UCL_OBJECT);
+
+ rspamadm_confighelp_search_word_step (obj, res, str, len, path);
+
+ return res;
+}
+
+static void
rspamadm_confighelp (gint argc, gchar **argv)
{
struct rspamd_rcl_section *top;
@@ -159,10 +232,21 @@ rspamadm_confighelp (gint argc, gchar **argv)
if (argc > 1) {
while (argc > 1) {
if (argv[i][0] != '-') {
- doc_obj = ucl_lookup_path (cfg->doc_strings, argv[i]);
+
+ if (keyword) {
+ doc_obj = rspamadm_confighelp_search_word (cfg->doc_strings,
+ argv[i]);
+ }
+ else {
+ doc_obj = ucl_lookup_path (cfg->doc_strings, argv[i]);
+ }
if (doc_obj != NULL) {
rspamadm_confighelp_show (argv[i], doc_obj);
+
+ if (keyword) {
+ ucl_object_unref ((ucl_object_t *)doc_obj);
+ }
}
else {
rspamd_fprintf (stderr,