--- /dev/null
+/*
+ * Copyright (c) 2015, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "rspamadm.h"
+
+const struct rspamadm_command *commands[] = {
+ &help_command,
+ NULL
+};
+
+
+const struct rspamadm_command *
+rspamadm_search_command (const gchar *name)
+{
+ const struct rspamadm_command *ret = NULL;
+ guint i;
+
+ if (name == NULL) {
+ name = "help";
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (commands); i ++) {
+ if (commands[i] != NULL) {
+ if (strcmp (name, commands[i]->name) == 0) {
+ ret = commands[i];
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "rspamadm.h"
+#include "rspamd.h"
+#include "ottery.h"
+
+static gboolean verbose = FALSE;
+static gboolean list_commands = FALSE;
+static gboolean show_help = FALSE;
+static gboolean show_version = FALSE;
+GHashTable *ucl_vars = NULL;
+
+static void rspamadm_help (gint argc, gchar **argv);
+static const char* rspamadm_help_help (gboolean full_help);
+
+struct rspamadm_command help_command = {
+ .name = "help",
+ .flags = RSPAMADM_FLAG_NOHELP,
+ .help = rspamadm_help_help,
+ .run = rspamadm_help
+};
+
+static gboolean rspamadm_parse_ucl_var (const gchar *option_name,
+ const gchar *value, gpointer data,
+ GError **error);
+
+static GOptionEntry entries[] = {
+ {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+ "Enable verbose logging", NULL},
+ {"list-commands", 'l', 0, G_OPTION_ARG_NONE, &list_commands,
+ "List available commands", NULL},
+ {"var", 0, 0, G_OPTION_ARG_CALLBACK, rspamadm_parse_ucl_var,
+ "Redefine UCL variable", NULL},
+ {"help", 'h', 0, G_OPTION_ARG_NONE, &show_help,
+ "Show help", NULL},
+ {"version", 'h', 0, G_OPTION_ARG_NONE, &show_version,
+ "Show version", NULL},
+ {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}
+};
+
+GQuark
+rspamadm_error (void)
+{
+ return g_quark_from_static_string ("rspamadm");
+}
+
+static void
+rspamadm_version (void)
+{
+ printf ("Rspamadm %s\n", RVERSION);
+ exit (EXIT_SUCCESS);
+}
+
+static void
+rspamadm_usage (GOptionContext *context)
+{
+ gchar *help_str;
+
+ help_str = g_option_context_get_help (context, TRUE, NULL);
+ printf ("%s", help_str);
+
+ exit (EXIT_SUCCESS);
+}
+
+static void
+rspamadm_commands (GOptionContext *context)
+{
+ gchar *help_str;
+ const struct rspamadm_command **cmd;
+
+ printf ("Rspamadm %s\n", RVERSION);
+ printf ("Usage: rspamadm [global_options] command [command_options]\n");
+ printf ("\nAvailable commands:\n");
+
+ cmd = commands;
+
+ while (*cmd) {
+ printf (" %-18s %-60s\n", (*cmd)->name, (*cmd)->help (FALSE));
+ cmd ++;
+ }
+
+ exit (EXIT_SUCCESS);
+}
+
+static const char *
+rspamadm_help_help (gboolean full_help)
+{
+ const char *help_str;
+
+ if (full_help) {
+ help_str = "Shows help for a specified command\n"
+ "Usage: rspamadm help <command>";
+ }
+ else {
+ help_str = "Shows help for a specified command";
+ }
+
+ return help_str;
+}
+
+static void
+rspamadm_help (gint argc, gchar **argv)
+{
+ const gchar *cmd_name;
+ const struct rspamadm_command *cmd;
+
+ if (argc == 0) {
+ cmd_name = "help";
+ }
+ else {
+ cmd_name = argv[1];
+ }
+
+ cmd = rspamadm_search_command (cmd_name);
+
+ if (cmd == NULL) {
+ fprintf (stderr, "Invalid command name: %s\n", cmd_name);
+ exit (EXIT_FAILURE);
+ }
+
+ printf ("%s\n", cmd->help (TRUE));
+}
+
+static gboolean
+rspamadm_parse_ucl_var (const gchar *option_name,
+ const gchar *value, gpointer data,
+ GError **error)
+{
+ gchar *k, *v, *t;
+
+ t = strchr (value, '=');
+
+ if (t != NULL) {
+ k = g_strdup (value);
+ t = k + (t - value);
+ v = g_strdup (t + 1);
+ *t = '\0';
+
+ g_hash_table_insert (ucl_vars, k, v);
+ }
+ else {
+ g_set_error (error, rspamadm_error (), EINVAL,
+ "Bad variable format: %s", value);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gint
+main (gint argc, gchar **argv, gchar **env)
+{
+ GError *error = NULL;
+ GOptionContext *context;
+ GOptionGroup *og;
+ struct rspamd_config *cfg;
+ struct rspamd_main *rspamd_main;
+ GQuark process_quark;
+ gchar **nargv;
+ const gchar *cmd_name;
+ const struct rspamadm_command *cmd;
+ gint i, nargc;
+
+ ucl_vars = g_hash_table_new_full (rspamd_strcase_hash,
+ rspamd_strcase_equal, g_free, g_free);
+ ottery_init (NULL);
+ process_quark = g_quark_from_static_string ("rspamadm");
+ cfg = g_slice_alloc0 (sizeof (*cfg));
+ rspamd_main = g_slice_alloc0 (sizeof (*rspamd_main));
+ rspamd_init_libs ();
+ rspamd_init_cfg (cfg, TRUE);
+ rspamd_main->cfg = cfg;
+ rspamd_main->pid = getpid ();
+ rspamd_main->type = process_quark;
+ rspamd_main->server_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (),
+ "rspamadm");
+
+ /* Setup logger */
+ if (verbose) {
+ cfg->log_level = G_LOG_LEVEL_DEBUG;
+ }
+ else {
+ cfg->log_level = G_LOG_LEVEL_INFO;
+ }
+
+ cfg->log_type = RSPAMD_LOG_CONSOLE;
+ rspamd_set_logger (cfg, process_quark, rspamd_main);
+ (void) rspamd_log_open (rspamd_main->logger);
+ g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger);
+ g_set_printerr_handler (rspamd_glib_printerr_function);
+
+ gperf_profiler_init (cfg, "rspamadm");
+ setproctitle ("rspamdadm");
+
+ /* Now read options and store everything till the first non-dash argument */
+ nargv = g_slice_alloc0 (sizeof (gchar *) * (argc + 1));
+ nargv[0] = g_strdup (argv[0]);
+
+ for (i = 1, nargc = 1; i < argc; i ++) {
+ if (argv[i] && argv[i][0] == '-') {
+ /* Copy to nargv */
+ nargv[nargc] = g_strdup (argv[i]);
+ nargc ++;
+ }
+ else {
+ break;
+ }
+ }
+
+ context = g_option_context_new ("command - rspamd administration utility");
+ og = g_option_group_new ("global", "global options", "global options",
+ NULL, NULL);
+ g_option_context_set_help_enabled (context, FALSE);
+ g_option_group_add_entries (og, entries);
+ g_option_context_set_summary (context,
+ "Summary:\n Rspamd administration utility version "
+ RVERSION
+ "\n Release id: "
+ RID);
+ g_option_context_set_main_group (context, og);
+
+ if (!g_option_context_parse (context, &nargc, &nargv, &error)) {
+ fprintf (stderr, "option parsing failed: %s\n", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+ if (show_version) {
+ rspamadm_version ();
+ }
+ if (show_help) {
+ rspamadm_usage (context);
+ }
+ if (list_commands) {
+ rspamadm_commands (context);
+ }
+
+ cmd_name = argv[nargc];
+
+ if (cmd_name == NULL) {
+ cmd_name = "help";
+ }
+
+ cmd = rspamadm_search_command (cmd_name);
+
+ if (cmd == NULL) {
+ fprintf (stderr, "Invalid command name: %s\n", cmd_name);
+ exit (EXIT_FAILURE);
+ }
+
+ if (nargc < argc) {
+ cmd->run (argc - nargc - 1, &argv[nargc]);
+ }
+ else {
+ cmd->run (0, NULL);
+ }
+
+ rspamd_log_close (rspamd_main->logger);
+ rspamd_config_free (rspamd_main->cfg);
+ g_free (rspamd_main->cfg);
+ g_free (rspamd_main);
+
+ g_mime_shutdown ();
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2015, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RSPAMD_RSPAMDADM_H
+#define RSPAMD_RSPAMDADM_H
+
+#include "config.h"
+
+extern GHashTable *ucl_vars;
+
+GQuark rspamadm_error (void);
+
+typedef const gchar* (*rspamadm_help_func) (gboolean full_help);
+typedef void (*rspamadm_run_func) (gint argc, gchar **argv);
+
+#define RSPAMADM_FLAG_NOHELP (1 << 0)
+
+struct rspamadm_command {
+ const gchar *name;
+ guint flags;
+ rspamadm_help_func help;
+ rspamadm_run_func run;
+};
+
+extern const struct rspamadm_command *commands[];
+extern struct rspamadm_command help_command;
+
+const struct rspamadm_command *rspamadm_search_command (const gchar *name);
+
+#endif