Browse Source

* Add C client for rspamd that is using librspamdclient

tags/0.3.7
Vsevolod Stakhov 13 years ago
parent
commit
2a383446ab
5 changed files with 563 additions and 39 deletions
  1. 1
    0
      CMakeLists.txt
  2. 1
    1
      lib/CMakeLists.txt
  3. 192
    38
      lib/librspamdclient.c
  4. 8
    0
      src/client/CMakeLists.txt
  5. 361
    0
      src/client/rspamc.c

+ 1
- 0
CMakeLists.txt View File

@@ -584,6 +584,7 @@ IF(ENABLE_PERL MATCHES "ON")
ENDIF(ENABLE_PERL MATCHES "ON")
ADD_SUBDIRECTORY(src/lua)
ADD_SUBDIRECTORY(lib)
ADD_SUBDIRECTORY(src/client)

ADD_SUBDIRECTORY(src/json)
# ADD_SUBDIRECTORY(src/evdns)

+ 1
- 1
lib/CMakeLists.txt View File

@@ -1,5 +1,5 @@
# Librspamd
SET(LIBRSPAMDSRC librspamdclient.c ../src/util.c ../src/upstream.c)
SET(LIBRSPAMDSRC librspamdclient.c ../src/util.c ../src/upstream.c ../src/mem_pool.c)

ADD_LIBRARY(rspamdclient SHARED ${LIBRSPAMDSRC})
ADD_LIBRARY(rspamdclient_static STATIC ${LIBRSPAMDSRC})

+ 192
- 38
lib/librspamdclient.c View File

@@ -92,7 +92,7 @@ symbol_free_func (gpointer arg)
}

static struct rspamd_connection *
rspamd_connect_random_server (guint16 port, GError **err)
rspamd_connect_random_server (gboolean is_control, GError **err)
{
struct rspamd_server *selected = NULL;
struct rspamd_connection *new;
@@ -122,7 +122,9 @@ rspamd_connect_random_server (guint16 port, GError **err)
new->server = selected;
new->connection_time = now;
/* Create socket */
new->socket = make_tcp_socket (&selected->addr, port, FALSE, TRUE);
new->socket = make_tcp_socket (&selected->addr,
is_control ? selected->controller_port : selected->client_port,
FALSE, TRUE);
if (new->socket == -1) {
goto err;
}
@@ -159,13 +161,27 @@ rspamd_create_metric (const gchar *begin, guint len)
return new;
}

static struct rspamd_result *
rspamd_create_result (struct rspamd_connection *c)
{
struct rspamd_result *new;

new = g_malloc (sizeof (struct rspamd_result));
new->conn = c;
new->headers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
new->metrics = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, metric_free_func);
new->is_ok = FALSE;

return new;
}

/*
* Parse line like RSPAMD/{version} {code} {message}
*/
static gboolean
parse_rspamd_first_line (struct rspamd_connection *c, guint len, GError **err)
parse_rspamd_first_line (struct rspamd_connection *conn, guint len, GError **err)
{
gchar *b = c->in_buf->str + sizeof("RSPAMD/") - 1, *p;
gchar *b = conn->in_buf->str + sizeof("RSPAMD/") - 1, *p, *c;
guint remain = len - sizeof("RSPAMD/") + 1, state = 0, next_state;

p = b;
@@ -187,6 +203,9 @@ parse_rspamd_first_line (struct rspamd_connection *c, guint len, GError **err)
if (g_ascii_isspace (*p)) {
state = 99;
next_state = 2;
if (*c == '0') {
conn->result->is_ok = TRUE;
}
}
else if (!g_ascii_isdigit (*p)) {
goto err;
@@ -207,6 +226,7 @@ parse_rspamd_first_line (struct rspamd_connection *c, guint len, GError **err)
/* Skip spaces */
if (!g_ascii_isspace (*p)) {
state = next_state;
c = p;
}
else {
p ++;
@@ -219,12 +239,13 @@ parse_rspamd_first_line (struct rspamd_connection *c, guint len, GError **err)
goto err;
}

return TRUE;
err:
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid protocol line: %*s at pos: %d",
len, b, (int)(p - b));
remain, b, (int)(p - b));
}
upstream_fail (&c->server->up, c->connection_time);
upstream_fail (&conn->server->up, conn->connection_time);
return FALSE;
}

@@ -255,7 +276,7 @@ parse_rspamd_metric_line (struct rspamd_connection *conn, guint len, GError **er
}
else {
/* Create new metric */
new = rspamd_create_metric (c, p - c - 1);
new = rspamd_create_metric (c, p - c);
if (g_hash_table_lookup (conn->result->metrics, new->name) != NULL) {
/* Duplicate metric */
metric_free_func (new);
@@ -272,13 +293,13 @@ parse_rspamd_metric_line (struct rspamd_connection *conn, guint len, GError **er
case 1:
/* Read boolean result */
if (*p == ';') {
if (p - c > sizeof("Skip")) {
if (p - c >= sizeof("Skip")) {
if (memcmp (c, "Skip", p - c - 1) == 0) {
new->is_skipped = TRUE;
}
state = 99;
next_state = 2;
}
state = 99;
next_state = 2;
}
p ++;
break;
@@ -297,18 +318,18 @@ parse_rspamd_metric_line (struct rspamd_connection *conn, guint len, GError **er
break;
case 3:
/* Read / */
if (*p != '/') {
goto err;
}
else if (g_ascii_isspace (*p)) {
if (g_ascii_isspace (*p)) {
state = 99;
next_state = 4;
}
else if (*p != '/') {
goto err;
}
p ++;
break;
case 4:
/* Read required score */
if (g_ascii_isspace (*p)) {
if (g_ascii_isspace (*p) || p - b == remain - 1) {
new->required_score = strtod (c, &err_str);
if (*err_str != *p) {
/* Invalid score */
@@ -321,13 +342,13 @@ parse_rspamd_metric_line (struct rspamd_connection *conn, guint len, GError **er
break;
case 5:
/* Read / if it exists */
if (*p != '/') {
goto err;
}
else if (g_ascii_isspace (*p)) {
if (g_ascii_isspace (*p)) {
state = 99;
next_state = 6;
}
else if (*p != '/') {
goto err;
}
p ++;
break;
case 6:
@@ -358,11 +379,12 @@ parse_rspamd_metric_line (struct rspamd_connection *conn, guint len, GError **er
if (state != 99) {
goto err;
}
return TRUE;

err:
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid metric line: %*s at pos: %d",
len, b, (int)(p - b));
*err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid metric line: %*s at pos: %d, state: %d",
remain, b, (int)(p - b), state);
}
upstream_fail (&conn->server->up, conn->connection_time);
return FALSE;
@@ -395,9 +417,9 @@ parse_rspamd_symbol_line (struct rspamd_connection *conn, guint len, GError **er
}
else {
/* Create new symbol */
sym = g_malloc (p - c);
sym[p - c - 1] = '\0';
memcpy (sym, c, p - c - 1);
sym = g_malloc (p - c + 1);
sym[p - c] = '\0';
memcpy (sym, c, p - c);

if (g_hash_table_lookup (conn->cur_metric->symbols, sym) != NULL) {
/* Duplicate symbol */
@@ -405,6 +427,7 @@ parse_rspamd_symbol_line (struct rspamd_connection *conn, guint len, GError **er
goto err;
}
new = g_malloc0 (sizeof (struct rspamd_symbol));
new->name = sym;
g_hash_table_insert (conn->cur_metric->symbols, sym, new);
state = 99;
if (*p == '(') {
@@ -467,11 +490,12 @@ parse_rspamd_symbol_line (struct rspamd_connection *conn, guint len, GError **er
if (state != 99) {
goto err;
}
return TRUE;

err:
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid symbol line: %*s at pos: %d",
len, b, (int)(p - b));
remain, b, (int)(p - b));
}
upstream_fail (&conn->server->up, conn->connection_time);
return FALSE;
@@ -494,18 +518,23 @@ parse_rspamd_action_line (struct rspamd_connection *conn, guint len, GError **er
/* Read action */
if (g_ascii_isspace (*p)) {
state = 99;
next_state = 0;
next_state = 1;
}
else {
state = 1;
}
else if (p - b == remain - 1) {
break;
case 1:
if (p - b == remain - 1) {
if (p - c <= 1) {
/* Empty action name */
goto err;
}
else {
/* Create new action */
sym = g_malloc (p - c + 1);
sym[p - c] = '\0';
memcpy (sym, c, p - c);
sym = g_malloc (p - c + 2);
sym[p - c + 1] = '\0';
memcpy (sym, c, p - c + 1);

conn->cur_metric->action = sym;
state = 99;
@@ -529,11 +558,12 @@ parse_rspamd_action_line (struct rspamd_connection *conn, guint len, GError **er
if (state != 99) {
goto err;
}
return TRUE;

err:
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid action line: %*s at pos: %d",
len, b, (int)(p - b));
remain, b, (int)(p - b));
}
upstream_fail (&conn->server->up, conn->connection_time);
return FALSE;
@@ -561,9 +591,9 @@ parse_rspamd_header_line (struct rspamd_connection *conn, guint len, GError **er
}
else {
/* Create header name */
hname = g_malloc (p - c);
hname[p - c - 1] = '\0';
memcpy (hname, c, p - c - 1);
hname = g_malloc (p - c + 1);
hname[p - c] = '\0';
memcpy (hname, c, p - c);
next_state = 1;
state = 99;
}
@@ -603,11 +633,12 @@ parse_rspamd_header_line (struct rspamd_connection *conn, guint len, GError **er
if (state != 99) {
goto err;
}
return TRUE;

err:
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid header line: %*s at pos: %d",
len, b, (int)(p - b));
remain, b, (int)(p - b));
}
if (hname) {
g_free (hname);
@@ -682,6 +713,7 @@ read_rspamd_reply_line (struct rspamd_connection *c, GError **err)
}
/* Move remaining buffer to the begin of string */
c->in_buf = g_string_erase (c->in_buf, 0, len);
len = 0;
}
else {
return FALSE;
@@ -706,12 +738,13 @@ read_rspamd_reply_line (struct rspamd_connection *c, GError **err)
/* Read new data to a string */
if ((r = read (c->socket,
c->in_buf->str + c->in_buf->len,
c->in_buf->allocated_len - c->in_buf->len)) < 0) {
c->in_buf->allocated_len - c->in_buf->len)) > 0) {
/* Try to parse remaining data */
return parse_rspamd_reply_line (c, c->in_buf->len, err);
c->in_buf->len += r;
return read_rspamd_reply_line (c, err);
}

return TRUE;
return FALSE;
}

/*
@@ -721,6 +754,7 @@ static gboolean
rspamd_sendfile (gint sock, gint fd, GError **err)
{

/* Make socket blocking for further operations */
make_socket_blocking (sock);
#ifdef HAVE_SENDFILE
# if defined(FREEBSD) || defined(DARWIN)
@@ -769,6 +803,38 @@ err:
return FALSE;
}

static gboolean
rspamd_send_normal_command (struct rspamd_connection *c, const gchar *command,
gsize clen, GHashTable *headers, GError **err)
{
static gchar outbuf[16384];
GHashTableIter it;
gpointer key, value;
gint r;

/* Write command */
r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s RSPAMC/1.2\r\n", command);
r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, "Content-Length: %uz\r\n", clen);
/* Iterate through headers */
if (headers != NULL) {
g_hash_table_iter_init (&it, headers);
while (g_hash_table_iter_next (&it, &key, &value)) {
r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, "%s: %s\r\n", key, value);
}
}
r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, "\r\n");

if ((r = write (c->socket, outbuf, r)) == -1) {
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Write error: %s",
strerror (errno));
}
return FALSE;
}

return TRUE;
}

static void
rspamd_free_connection (struct rspamd_connection *c)
{
@@ -856,8 +922,44 @@ rspamd_set_timeout (guint connect_timeout, guint read_timeout)
struct rspamd_result *
rspamd_scan_memory (const guchar *message, gsize length, GHashTable *headers, GError **err)
{
struct rspamd_connection *c;
struct rspamd_result *res = NULL;

g_assert (client != NULL);

/* Connect to server */
c = rspamd_connect_random_server (FALSE, err);

if (c == NULL) {
return NULL;
}

/* Set socket blocking for writing */
make_socket_blocking (c->socket);
/* Send command */
if (!rspamd_send_normal_command (c, "SYMBOLS", length, headers, err)) {
return NULL;
}

/* Send message */
if (write (c->socket, message, length) == -1) {
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Write error: %s",
strerror (errno));
}
return NULL;
}

/* Create result structure */
res = rspamd_create_result (c);
c->result = res;
/* Restore non-blocking mode for reading operations */
make_socket_nonblocking (c->socket);

/* Read result cycle */
while (read_rspamd_reply_line (c, err));

return res;
}

/*
@@ -866,8 +968,19 @@ rspamd_scan_memory (const guchar *message, gsize length, GHashTable *headers, GE
struct rspamd_result *
rspamd_scan_file (const guchar *filename, GHashTable *headers, GError **err)
{
gint fd;
g_assert (client != NULL);

/* Open file */
if ((fd = open (filename, O_RDONLY | O_CLOEXEC)) == -1) {
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Open error for file %s: %s",
filename, strerror (errno));
}
return NULL;
}

return rspamd_scan_fd (fd, headers, err);
}

/*
@@ -876,8 +989,49 @@ rspamd_scan_file (const guchar *filename, GHashTable *headers, GError **err)
struct rspamd_result *
rspamd_scan_fd (int fd, GHashTable *headers, GError **err)
{
struct rspamd_connection *c;
struct rspamd_result *res = NULL;
struct stat st;

g_assert (client != NULL);

/* Connect to server */
c = rspamd_connect_random_server (FALSE, err);

if (c == NULL) {
return NULL;
}

/* Get length */
if (fstat (fd, &st) == -1) {
if (*err == NULL) {
*err = g_error_new (G_RSPAMD_ERROR, errno, "Stat error: %s",
strerror (errno));
}
return NULL;
}
/* Set socket blocking for writing */
make_socket_blocking (c->socket);
/* Send command */
if (!rspamd_send_normal_command (c, "SYMBOLS", (gsize)st.st_size, headers, err)) {
return NULL;
}

/* Send message */
if (!rspamd_sendfile (c->socket, fd, err)) {
return NULL;
}

/* Create result structure */
res = rspamd_create_result (c);
c->result = res;
/* Restore non-blocking mode for reading operations */
make_socket_nonblocking (c->socket);

/* Read result cycle */
while (read_rspamd_reply_line (c, err));

return res;
}

/*

+ 8
- 0
src/client/CMakeLists.txt View File

@@ -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})

+ 361
- 0
src/client/rspamc.c View File

@@ -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;
}

Loading…
Cancel
Save