diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2011-01-31 20:33:12 +0300 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2011-01-31 20:33:12 +0300 |
commit | 2a383446ab6254777693544e5acda2a805947f81 (patch) | |
tree | b929dc0b151cfda62f0c1256673ede9d8cdf5de0 /src | |
parent | bc15f7bcfbe45c51917d153b8174e6b76b5e00bb (diff) | |
download | rspamd-2a383446ab6254777693544e5acda2a805947f81.tar.gz rspamd-2a383446ab6254777693544e5acda2a805947f81.zip |
* Add C client for rspamd that is using librspamdclient
Diffstat (limited to 'src')
-rw-r--r-- | src/client/CMakeLists.txt | 8 | ||||
-rw-r--r-- | src/client/rspamc.c | 361 |
2 files changed, 369 insertions, 0 deletions
diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt new file mode 100644 index 000000000..186b458f3 --- /dev/null +++ b/src/client/CMakeLists.txt @@ -0,0 +1,8 @@ +# rspamc +SET(RSPAMCSRC rspamc.c) + +ADD_EXECUTABLE(rspamc ${RSPAMCSRC}) +SET_TARGET_PROPERTIES(rspamc PROPERTIES COMPILE_FLAGS "-I.. -I../../lib") +TARGET_LINK_LIBRARIES(rspamc rspamdclient) +TARGET_LINK_LIBRARIES(rspamc ${CMAKE_REQUIRED_LIBRARIES}) +TARGET_LINK_LIBRARIES(rspamc ${GLIB2_LIBRARIES}) diff --git a/src/client/rspamc.c b/src/client/rspamc.c new file mode 100644 index 000000000..1bae2970c --- /dev/null +++ b/src/client/rspamc.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2011, 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 ''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 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 "librspamdclient.h" + +#define PRINT_FUNC printf + +#define DEFAULT_PORT 11333 +#define DEFAULT_CONTROL_PORT 11334 + +static gchar *connect_str = "localhost"; +static gchar *password; +static gchar *statfile; +static gchar *ip; +static gdouble weight; +static gboolean pass_all; +static gboolean tty = FALSE; + +static GOptionEntry entries[] = +{ + { "connect", 'h', 0, G_OPTION_ARG_STRING, &connect_str, "Specify host and port", NULL }, + { "password", 'P', 0, G_OPTION_ARG_STRING, &password, "Specify control password", NULL }, + { "statfile", 's', 0, G_OPTION_ARG_STRING, &statfile, "Statfile to learn (symbol name)", NULL }, + { "weight", 'w', 0, G_OPTION_ARG_DOUBLE, &weight, "Weight for fuzzy operations", NULL }, + { "pass", 'p', 0, G_OPTION_ARG_NONE, &pass_all, "Pass all filters", NULL }, + { "ip", 'i', 0, G_OPTION_ARG_STRING, &ip, "Emulate that message was received from specified ip address", NULL }, + { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL } +}; + +enum rspamc_command { + RSPAMC_COMMAND_UNKNOWN = 0, + RSPAMC_COMMAND_SYMBOLS, + RSPAMC_COMMAND_LEARN +}; + +/* + * Parse command line + */ +static void +read_cmd_line (gint *argc, gchar ***argv) +{ + GError *error = NULL; + GOptionContext *context; + + /* Prepare parser */ + context = g_option_context_new ("- run rspamc client"); + g_option_context_set_summary (context, "Summary:\n Rspamd client version " RVERSION "\n Release id: " RID); + g_option_context_add_main_entries (context, entries, NULL); + + /* Parse options */ + if (!g_option_context_parse (context, argc, argv, &error)) { + fprintf (stderr, "option parsing failed: %s\n", error->message); + exit (EXIT_FAILURE); + } + + /* Argc and argv are shifted after this function */ +} + +/* + * Check rspamc command from string (used for arguments parsing) + */ +static enum rspamc_command +check_rspamc_command (const gchar *cmd) +{ + if (g_ascii_strcasecmp (cmd, "SYMBOLS") == 0 || + g_ascii_strcasecmp (cmd, "CHECK") == 0 || + g_ascii_strcasecmp (cmd, "REPORT") == 0) { + /* These all are symbols, don't use other commands */ + return RSPAMC_COMMAND_SYMBOLS; + } + else if (g_ascii_strcasecmp (cmd, "LEARN") == 0) { + return RSPAMC_COMMAND_LEARN; + } + + return RSPAMC_COMMAND_UNKNOWN; +} + +/* + * Parse connect_str and add server to librspamdclient + */ +static void +add_rspamd_server (gboolean is_control) +{ + gchar **vec, *err_str; + guint16 port; + GError *err = NULL; + + if (connect_str == NULL) { + fprintf (stderr, "cannot connect to rspamd server - empty string\n"); + exit (EXIT_FAILURE); + } + vec = g_strsplit_set (connect_str, ":", 2); + if (vec == NULL || *vec == NULL) { + fprintf (stderr, "cannot connect to rspamd server: %s\n", connect_str); + exit (EXIT_FAILURE); + } + + if (vec[1] == NULL) { + port = is_control ? DEFAULT_CONTROL_PORT : DEFAULT_PORT; + } + else { + port = strtoul (vec[1], &err_str, 10); + if (*err_str != '\0') { + fprintf (stderr, "cannot connect to rspamd server: %s, at pos %s\n", connect_str, err_str); + exit (EXIT_FAILURE); + } + } + + if (! rspamd_add_server (vec[0], port, port, &err)) { + fprintf (stderr, "cannot connect to rspamd server: %s, error: %s\n", connect_str, err->message); + exit (EXIT_FAILURE); + } +} + +static void +show_metric_result (gpointer key, gpointer value, gpointer ud) +{ + struct rspamd_metric *metric = value; + struct rspamd_symbol *s; + GList *cur; + GHashTableIter it; + gpointer k, v; + gboolean first; + + if (metric->is_skipped) { + PRINT_FUNC ("%s: Skipped\n", key); + } + else { + if (tty) { + PRINT_FUNC ("\033[1m%s:\033[0m %s [ %.2f / %.2f ]\n", key, + metric->score > metric->required_score ? "True" : "False", + metric->score, metric->required_score); + } + else { + PRINT_FUNC ("%s: %s [ %.2f / %.2f ]\n", key, + metric->score > metric->required_score ? "True" : "False", + metric->score, metric->required_score); + } + if (tty) { + if (metric->action) { + PRINT_FUNC ("\033[1mAction:\033[0m %s\n", metric->action); + } + PRINT_FUNC ("\033[1mSymbols: \033[0m"); + } + else { + if (metric->action) { + PRINT_FUNC ("Action: %s\n", metric->action); + } + PRINT_FUNC ("Symbols: "); + } + if (metric->symbols) { + first = TRUE; + g_hash_table_iter_init (&it, metric->symbols); + while (g_hash_table_iter_next (&it, &k, &v)) { + s = v; + if (! first) { + PRINT_FUNC (", "); + } + else { + first = FALSE; + } + PRINT_FUNC ("%s(%.2f)", s->name, s->weight); + if (s->options) { + PRINT_FUNC ("("); + cur = g_list_first (s->options); + while (cur) { + if (cur->next) { + PRINT_FUNC ("%s,", cur->data); + } + else { + PRINT_FUNC ("%s)", cur->data); + } + cur = g_list_next (cur); + } + } + + } + } + PRINT_FUNC ("\n"); + } +} + +static void +print_rspamd_result (struct rspamd_result *res) +{ + GHashTableIter it; + gpointer k, v; + + g_assert (res != 0); + + if (tty) { + printf ("\033[1m"); + } + PRINT_FUNC ("Results for host: %s\n\n", connect_str); + if (tty) { + printf ("\033[0m"); + } + g_hash_table_foreach (res->metrics, show_metric_result, NULL); + /* Show other headers */ + g_hash_table_iter_init (&it, res->headers); + PRINT_FUNC ("\n"); + while (g_hash_table_iter_next (&it, &k, &v)) { + if (tty) { + PRINT_FUNC ("\033[1m%s:\033[0m %s\n", k, v); + } + else { + PRINT_FUNC ("%s: %s\n", k, v); + } + } + PRINT_FUNC ("\n"); +} + +static void +add_options (GHashTable *opts) +{ + if (ip != NULL) { + g_hash_table_insert (opts, "Ip", ip); + } + if (pass_all) { + g_hash_table_insert (opts, "Pass", "all"); + } +} + +/* + * Scan STDIN + */ +static void +scan_rspamd_stdin () +{ + gchar *in_buf; + + gint r = 0, len; + GError *err = NULL; + struct rspamd_result *res; + GHashTable *opts; + + /* Init options hash */ + opts = g_hash_table_new (g_str_hash, g_str_equal); + add_options (opts); + /* Add server */ + add_rspamd_server (FALSE); + + /* Allocate input buffer */ + len = BUFSIZ; + in_buf = g_malloc (len); + + /* Read stdin */ + while (!feof (stdin)) { + r += fread (in_buf + r, 1, len - r, stdin); + if (len - r < len / 2) { + /* Grow buffer */ + len *= 2; + in_buf = g_realloc (in_buf, len); + } + } + res = rspamd_scan_memory (in_buf, r, opts, &err); + g_hash_table_destroy (opts); + if (err != NULL) { + fprintf (stderr, "cannot scan message: %s\n", err->message); + exit (EXIT_FAILURE); + } + print_rspamd_result (res); +} + +static void +scan_rspamd_file (const gchar *file) +{ + GError *err = NULL; + struct rspamd_result *res; + GHashTable *opts; + + /* Init options hash */ + opts = g_hash_table_new (g_str_hash, g_str_equal); + add_options (opts); + + /* Add server */ + add_rspamd_server (FALSE); + + res = rspamd_scan_file (file, opts, &err); + g_hash_table_destroy (opts); + if (err != NULL) { + fprintf (stderr, "cannot scan message: %s\n", err->message); + exit (EXIT_FAILURE); + } + print_rspamd_result (res); +} + +gint +main (gint argc, gchar **argv, gchar **env) +{ + enum rspamc_command cmd; + gint i; + + rspamd_client_init (); + + read_cmd_line (&argc, &argv); + tty = isatty (STDOUT_FILENO); + /* Now read other args from argc and argv */ + if (argc == 1) { + /* No args, just read stdin */ + scan_rspamd_stdin (); + } + else if (argc == 2) { + /* One argument is whether command or filename */ + if ((cmd = check_rspamc_command (argv[1])) != RSPAMC_COMMAND_UNKNOWN) { + /* In case of command read stdin */ + if (cmd == RSPAMC_COMMAND_SYMBOLS) { + scan_rspamd_stdin (); + } + else { + /* XXX: implement this */ + } + } + else { + scan_rspamd_file (argv[1]); + } + } + else { + if ((cmd = check_rspamc_command (argv[1])) != RSPAMC_COMMAND_UNKNOWN) { + /* In case of command read arguments starting from 2 */ + for (i = 2; i < argc; i ++) { + if (cmd == RSPAMC_COMMAND_SYMBOLS) { + scan_rspamd_file (argv[i]); + } + else { + /* XXX: implement this */ + } + } + } + else { + for (i = 1; i < argc; i ++) { + scan_rspamd_file (argv[i]); + } + } + } + + + return 0; +} |