SET(RSPAMD_VERSION_MAJOR 0)
SET(RSPAMD_VERSION_MINOR 3)
-SET(RSPAMD_VERSION_PATCH 4)
+SET(RSPAMD_VERSION_PATCH 5)
SET(RSPAMD_VERSION "${RSPAMD_VERSION_MAJOR}.${RSPAMD_VERSION_MINOR}.${RSPAMD_VERSION_PATCH}")
OPTION(DEBUG_MODE "Enable debug output [default: ON]" ON)
OPTION(ENABLE_OPTIMIZATION "Enable optimization [default: OFF]" OFF)
+OPTION(ENABLE_PERL "Enable perl client API [default: OFF]" OFF)
OPTION(SKIP_RELINK_RPATH "Skip relinking and full RPATH for the install tree" OFF)
OPTION(ENABLE_REDIRECTOR "Enable redirector install [default: OFF]" OFF)
OPTION(ENABLE_PROFILING "Enable profiling [default: OFF]" OFF)
src/view.c
src/worker.c)
-IF(ENABLE_PERL MATCHES "ON")
- LIST(APPEND RSPAMDSRC src/perl.c)
-ENDIF(ENABLE_PERL MATCHES "ON")
ADD_SUBDIRECTORY(src/lua)
ADD_SUBDIRECTORY(lib)
ADD_SUBDIRECTORY(src/client)
COMMAND ../utils/gen-modules.sh ${PLUGINSSRC}
WORKING_DIRECTORY src)
-IF(PERL_EXECUTABLE)
+IF(ENABLE_PERL MATCHES "ON")
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_SOURCE_DIR}/perl/Makefile
DEPENDS ${CMAKE_SOURCE_DIR}/perl/Makefile.PL
COMMAND ${PERL_EXECUTABLE} ./Makefile.PL DESTDIR=${DESTDIR} PREFIX=${PREFIX} INSTALLMAN3DIR=${MAN_PREFIX}/man3
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/perl
VERBATIM)
-ENDIF(PERL_EXECUTABLE)
+ENDIF(ENABLE_PERL MATCHES "ON")
CONFIGURE_FILE(config.h.in src/config.h)
CONFIGURE_FILE(contrib/exim/local_scan.c.in contrib/exim/local_scan_rspamd.c @ONLY)
-CONFIGURE_FILE(rspamc.pl.in rspamc.pl @ONLY)
CONFIGURE_FILE(rspamd.xml.sample conf/rspamd.xml.sample @ONLY)
######################### LINK SECTION ###############################
ENDIF(PERL_DYNALOADER)
ENDIF(ENABLE_PERL MATCHES "ON")
-IF(PERL_EXECUTABLE)
+IF(ENABLE_PERL MATCHES "ON")
ADD_DEPENDENCIES(rspamd perlmodule)
-ENDIF(PERL_EXECUTABLE)
+ENDIF(ENABLE_PERL MATCHES "ON")
TARGET_LINK_LIBRARIES(rspamd rspamd_lua)
TARGET_LINK_LIBRARIES(rspamd "${LUA_LIBRARY}")
# Binaries
INSTALL(PROGRAMS rspamd-${RSPAMD_VERSION} DESTINATION bin RENAME rspamd)
-IF(PERL_EXECUTABLE)
- INSTALL(PROGRAMS rspamc.pl DESTINATION bin RENAME rspamc)
-ENDIF(PERL_EXECUTABLE)
+INSTALL(PROGRAMS src/client/rspamc DESTINATION bin)
# Configs
ENDFOREACH(LUA_CONF)
# Perl lib
-IF(PERL_EXECUTABLE)
+IF(ENABLE_PERL MATCHES "ON")
INSTALL(CODE "EXECUTE_PROCESS(COMMAND make install WORKING_DIRECTORY perl)")
-ENDIF(PERL_EXECUTABLE)
+ENDIF(ENABLE_PERL MATCHES "ON")
# Redirector
-IF(ENABLE_REDIRECTOR MATCHES "ON" AND PERL_EXECUTABLE)
+IF(ENABLE_REDIRECTOR MATCHES "ON" AND ENABLE_PERL MATCHES "ON")
INSTALL(PROGRAMS utils/redirector.pl DESTINATION bin RENAME rspamd-redirector)
-ENDIF(ENABLE_REDIRECTOR MATCHES "ON" AND PERL_EXECUTABLE)
+ENDIF(ENABLE_REDIRECTOR MATCHES "ON" AND ENABLE_PERL MATCHES "ON")
# Start scripts
IF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT BUILD_PORT)
off_t off = 0;
# if defined(FREEBSD)
/* FreeBSD version */
- if (sendfile (sock, fd, 0, 0, NULL, &off, 0) != 0) {
+ if (sendfile (fd, sock, 0, 0, NULL, &off, 0) != 0) {
# elif defined(DARWIN)
/* Darwin version */
- if (sendfile (sock, fd, 0, &off, NULL, 0) != 0) {
+ if (sendfile (fd, sock, 0, &off, NULL, 0) != 0) {
# endif
goto err;
}
fstat (fd, &st);
/* Linux version */
- r = sendfile (fd, sock, &off, st.st_size);
+ r = sendfile (sock, fd, &off, st.st_size);
if (r == -1) {
goto err;
}
g_free (c);
}
+/*
+ * Send a single command to controller and get reply
+ */
+static GString *
+rspamd_send_controller_command (struct rspamd_connection *c, const gchar *line, gsize len, gint fd, GError **err)
+{
+ GString *res = NULL;
+ static gchar tmpbuf[BUFSIZ];
+ gint r = 0;
+ static const gchar end_marker[] = "END\r\n";
+
+ /* Set blocking for writing */
+ make_socket_blocking (c->socket);
+ if (write (c->socket, line, len) == -1) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Write error: %s",
+ strerror (errno));
+ }
+ return NULL;
+ }
+ if (fd != -1) {
+ if (!rspamd_sendfile (c->socket, fd, err)) {
+ return NULL;
+ }
+ }
+ /* Now set non-blocking mode and read buffer till END\r\n marker */
+ make_socket_nonblocking (c->socket);
+ /* Poll socket */
+ do {
+ if (poll_sync_socket (c->socket, client->read_timeout, POLL_IN) == -1) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Cannot read reply from controller %s: %s",
+ c->server->name, strerror (errno));
+ }
+ upstream_fail (&c->server->up, c->connection_time);
+ return NULL;
+ }
+ if ((r = read (c->socket, tmpbuf, sizeof (tmpbuf))) > 0) {
+ /* Check the end of the buffer for END marker */
+ if (r >= sizeof (end_marker) - 1 &&
+ memcmp (tmpbuf + r - sizeof (end_marker) + 1, end_marker, sizeof (end_marker) - 1) == 0) {
+ r -= sizeof (end_marker) - 1;
+ /* Copy the rest to the result string */
+ if (res == NULL) {
+ res = g_string_new_len (tmpbuf, r);
+ return res;
+ }
+ else {
+ /* Append data to string */
+ if (r > 0) {
+ res = g_string_append_len (res, tmpbuf, r);
+ }
+ return res;
+ }
+ }
+ else {
+ /* Store data inside res */
+ if (res == NULL) {
+ res = g_string_new_len (tmpbuf, r);
+ }
+ else {
+ /* Append data to string */
+ res = g_string_append_len (res, tmpbuf, r);
+ }
+ }
+ }
+ } while (r > 0);
+
+ /* Incomplete reply, so store error */
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Cannot read reply from controller %s: %s",
+ c->server->name, strerror (errno));
+ }
+ upstream_fail (&c->server->up, c->connection_time);
+ return NULL;
+}
+
+/*
+ * Authenticate on the controller
+ */
+static gboolean
+rspamd_controller_auth (struct rspamd_connection *c, const gchar *password, GError **err)
+{
+ gchar outbuf[BUFSIZ];
+ static const gchar success_str[] = "password accepted";
+ gint r;
+ GString *in;
+
+ r = rspamd_snprintf (outbuf, sizeof (outbuf), "password %s\r\n", password);
+ in = rspamd_send_controller_command (c, outbuf, r, -1, err);
+
+ if (in == NULL) {
+ return FALSE;
+ }
+
+ if (in->len >= sizeof (success_str) - 1 &&
+ memcmp (in->str, success_str, sizeof (success_str) - 1) == 0) {
+ g_string_free (in, TRUE);
+ return TRUE;
+ }
+
+ g_string_free (in, TRUE);
+ return FALSE;
+}
+
+/*
+ * Read greeting from the controller
+ */
+static gboolean
+rspamd_read_controller_greeting (struct rspamd_connection *c, GError **err)
+{
+ gchar inbuf[BUFSIZ];
+ gint r;
+ static const gchar greeting_str[] = "Rspamd";
+
+ if (poll_sync_socket (c->socket, client->read_timeout, POLL_IN) == -1) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Cannot read reply from controller %s: %s",
+ c->server->name, strerror (errno));
+ }
+ upstream_fail (&c->server->up, c->connection_time);
+ return FALSE;
+ }
+ if ((r = read (c->socket, inbuf, sizeof (inbuf))) > 0) {
+ if (r >= sizeof (greeting_str) - 1 &&
+ memcmp (inbuf, greeting_str, sizeof (greeting_str) - 1) == 0) {
+ return TRUE;
+ }
+ }
+ else {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Cannot read reply from controller %s: %s",
+ c->server->name, strerror (errno));
+ }
+ upstream_fail (&c->server->up, c->connection_time);
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
/** Public API **/
/*
/* Read result cycle */
while (read_rspamd_reply_line (c, err));
+ upstream_ok (&c->server->up, c->connection_time);
return res;
}
/* Read result cycle */
while (read_rspamd_reply_line (c, err));
+ upstream_ok (&c->server->up, c->connection_time);
return res;
}
* Learn message from memory
*/
gboolean
-rspamd_learn_memory (const guchar *message, gsize length, const gchar *symbol, GError **err)
+rspamd_learn_memory (const guchar *message, gsize length, const gchar *symbol, const gchar *password, GError **err)
{
+ struct rspamd_connection *c;
+ GString *in;
+ gchar *outbuf;
+ guint r;
+ static const gchar ok_str[] = "learn ok";
+
g_assert (client != NULL);
+ /* Connect to server */
+ c = rspamd_connect_random_server (TRUE, err);
+
+ if (c == NULL) {
+ return FALSE;
+ }
+
+ /* Read greeting */
+ if (! rspamd_read_controller_greeting(c, err)) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid greeting");
+ }
+ return FALSE;
+ }
+ /* Perform auth */
+ if (! rspamd_controller_auth (c, password, err)) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Authentication error");
+ }
+ return FALSE;
+ }
+
+ r = length + sizeof ("learn %s %uz\r\n") + strlen (symbol) + sizeof ("4294967296");
+ outbuf = g_malloc (r);
+ r = rspamd_snprintf (outbuf, r, "learn %s %uz\r\n%s", symbol, length, message);
+ in = rspamd_send_controller_command (c, outbuf, r, -1, err);
+ g_free (outbuf);
+ if (in == NULL) {
+ return FALSE;
+ }
+
+ /* Search for string learn ok */
+ if (in->len > sizeof (ok_str) - 1 && memcmp (in->str, ok_str, sizeof (ok_str) - 1) == 0) {
+ upstream_ok (&c->server->up, c->connection_time);
+ return TRUE;
+ }
+ else {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Bad reply: %s", in->str);
+ }
+ }
+ return FALSE;
}
/*
* Learn message from file
*/
gboolean
-rspamd_learn_file (const guchar *filename, const gchar *symbol, GError **err)
+rspamd_learn_file (const guchar *filename, const gchar *symbol, const gchar *password, 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 FALSE;
+ }
+
+ return rspamd_learn_fd (fd, symbol, password, err);
}
/*
* Learn message from fd
*/
gboolean
-rspamd_learn_fd (int fd, const gchar *symbol, GError **err)
+rspamd_learn_fd (int fd, const gchar *symbol, const gchar *password, GError **err)
{
+ struct rspamd_connection *c;
+ GString *in;
+ gchar *outbuf;
+ guint r;
+ struct stat st;
+ static const gchar ok_str[] = "learn ok";
+
g_assert (client != NULL);
+ /* Connect to server */
+ c = rspamd_connect_random_server (TRUE, err);
+
+ if (c == NULL) {
+ return FALSE;
+ }
+
+ /* Read greeting */
+ if (! rspamd_read_controller_greeting(c, err)) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid greeting");
+ }
+ return FALSE;
+ }
+ /* Perform auth */
+ if (! rspamd_controller_auth (c, password, err)) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Authentication error");
+ }
+ return FALSE;
+ }
+
+ /* Get length */
+ if (fstat (fd, &st) == -1) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Stat error: %s",
+ strerror (errno));
+ }
+ return FALSE;
+ }
+ r = sizeof ("learn %s %uz\r\n") + strlen (symbol) + sizeof ("4294967296");
+ outbuf = g_malloc (r);
+ r = rspamd_snprintf (outbuf, r, "learn %s %uz\r\n", symbol, st.st_size);
+ in = rspamd_send_controller_command (c, outbuf, r, fd, err);
+ g_free (outbuf);
+ if (in == NULL) {
+ return FALSE;
+ }
+
+ /* Search for string learn ok */
+ if (in->len > sizeof (ok_str) - 1 && memcmp (in->str, ok_str, sizeof (ok_str) - 1) == 0) {
+ upstream_ok (&c->server->up, c->connection_time);
+ return TRUE;
+ }
+ else {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Bad reply: %s", in->str);
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Learn message fuzzy from memory
+ */
+gboolean
+rspamd_fuzzy_memory (const guchar *message, gsize length, const gchar *password, gint weight, gint flag, gboolean delete, GError **err)
+{
+ struct rspamd_connection *c;
+ GString *in;
+ gchar *outbuf;
+ guint r;
+ static const gchar ok_str[] = "OK";
+
+ g_assert (client != NULL);
+
+ /* Connect to server */
+ c = rspamd_connect_random_server (TRUE, err);
+
+ if (c == NULL) {
+ return FALSE;
+ }
+
+ /* Read greeting */
+ if (! rspamd_read_controller_greeting(c, err)) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid greeting");
+ }
+ return FALSE;
+ }
+ /* Perform auth */
+ if (! rspamd_controller_auth (c, password, err)) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Authentication error");
+ }
+ return FALSE;
+ }
+
+ r = length + sizeof ("fuzzy_add %uz %d %d\r\n") + sizeof ("4294967296") * 3;
+ outbuf = g_malloc (r);
+ if (delete) {
+ r = rspamd_snprintf (outbuf, r, "fuzzy_del %uz %d %d\r\n%s", length, weight, flag, message);
+ }
+ else {
+ r = rspamd_snprintf (outbuf, r, "fuzzy_add %uz %d %d\r\n%s", length, weight, flag, message);
+ }
+ in = rspamd_send_controller_command (c, outbuf, r, -1, err);
+ g_free (outbuf);
+ if (in == NULL) {
+ return FALSE;
+ }
+
+ /* Search for string "OK" */
+ if (in->len > sizeof (ok_str) - 1 && memcmp (in->str, ok_str, sizeof (ok_str) - 1) == 0) {
+ upstream_ok (&c->server->up, c->connection_time);
+ return TRUE;
+ }
+ else {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Bad reply: %s", in->str);
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Learn message fuzzy from file
+ */
+gboolean
+rspamd_fuzzy_file (const guchar *filename, const gchar *password, gint weight, gint flag, gboolean delete, 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 FALSE;
+ }
+
+ return rspamd_fuzzy_fd (fd, password, weight, flag, delete, err);
+}
+
+/*
+ * Learn message fuzzy from fd
+ */
+gboolean
+rspamd_fuzzy_fd (int fd, const gchar *password, gint weight, gint flag, gboolean delete, GError **err)
+{
+ struct rspamd_connection *c;
+ GString *in;
+ gchar *outbuf;
+ guint r;
+ struct stat st;
+ static const gchar ok_str[] = "OK";
+
+ g_assert (client != NULL);
+
+ /* Connect to server */
+ c = rspamd_connect_random_server (TRUE, err);
+
+ if (c == NULL) {
+ return FALSE;
+ }
+
+ /* Read greeting */
+ if (! rspamd_read_controller_greeting(c, err)) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid greeting");
+ }
+ return FALSE;
+ }
+ /* Perform auth */
+ if (! rspamd_controller_auth (c, password, err)) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Authentication error");
+ }
+ return FALSE;
+ }
+ /* Get length */
+ if (fstat (fd, &st) == -1) {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Stat error: %s",
+ strerror (errno));
+ }
+ return FALSE;
+ }
+ r = sizeof ("fuzzy_add %uz %d %d\r\n") + sizeof ("4294967296") * 3;
+ outbuf = g_malloc (r);
+ if (delete) {
+ r = rspamd_snprintf (outbuf, r, "fuzzy_del %uz %d %d\r\n", st.st_size, weight, flag);
+ }
+ else {
+ r = rspamd_snprintf (outbuf, r, "fuzzy_add %uz %d %d\r\n", st.st_size, weight, flag);
+ }
+ in = rspamd_send_controller_command (c, outbuf, r, fd, err);
+
+ g_free (outbuf);
+ if (in == NULL) {
+ return FALSE;
+ }
+
+ /* Search for string "OK" */
+ if (in->len > sizeof (ok_str) - 1 && memcmp (in->str, ok_str, sizeof (ok_str) - 1) == 0) {
+ upstream_ok (&c->server->up, c->connection_time);
+ return TRUE;
+ }
+ else {
+ if (*err == NULL) {
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Bad reply: %s", in->str);
+ }
+ }
+ return FALSE;
+}
+
+GString *
+rspamd_get_stat (GError **err)
+{
+ struct rspamd_connection *c;
+ GString *res;
+ static const gchar outcmd[] = "stat\r\n";
+
+ g_assert (client != NULL);
+
+ /* Connect to server */
+ c = rspamd_connect_random_server (TRUE, err);
+
+ if (c == NULL) {
+ return NULL;
+ }
+
+ res = rspamd_send_controller_command (c, outcmd, strlen (outcmd), -1, err);
+
+ return res;
}
/*
rspamd_free_result (struct rspamd_result *result)
{
g_assert (client != NULL);
+ g_assert (result != NULL);
+ g_hash_table_destroy (result->headers);
+ g_hash_table_destroy (result->metrics);
+ rspamd_free_connection (result->conn);
}
/*
rspamd_client_close (void)
{
g_assert (client != NULL);
+
+ g_free (client);
+ client = NULL;
}
/*
* Learn message from memory
*/
-gboolean rspamd_learn_memory (const guchar *message, gsize length, const gchar *symbol, GError **err);
+gboolean rspamd_learn_memory (const guchar *message, gsize length, const gchar *symbol, const gchar *password, GError **err);
/*
* Learn message from file
*/
-gboolean rspamd_learn_file (const guchar *filename, const gchar *symbol, GError **err);
+gboolean rspamd_learn_file (const guchar *filename, const gchar *symbol, const gchar *password, GError **err);
/*
* Learn message from fd
*/
-gboolean rspamd_learn_fd (int fd, const gchar *symbol, GError **err);
+gboolean rspamd_learn_fd (int fd, const gchar *symbol, const gchar *password, GError **err);
+
+/*
+ * Learn message fuzzy from memory
+ */
+gboolean rspamd_fuzzy_memory (const guchar *message, gsize length, const gchar *password, gint weight, gint flag, gboolean delete, GError **err);
+
+/*
+ * Learn message fuzzy from file
+ */
+gboolean rspamd_fuzzy_file (const guchar *filename, const gchar *password, gint weight, gint flag, gboolean delete, GError **err);
+
+/*
+ * Learn message fuzzy from fd
+ */
+gboolean rspamd_fuzzy_fd (int fd, const gchar *password, gint weight, gint flag, gboolean delete, GError **err);
+
+/*
+ * Get statistic from server
+ */
+GString *rspamd_get_stat (GError **err);
/*
* Free results
static gchar *password;
static gchar *statfile;
static gchar *ip;
-static gdouble weight;
+static gint weight = 1;
+static gint flag;
static gboolean pass_all;
static gboolean tty = FALSE;
{ "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 },
+ { "weight", 'w', 0, G_OPTION_ARG_INT, &weight, "Weight for fuzzy operations", NULL },
+ { "flag", 'f', 0, G_OPTION_ARG_INT, &flag, "Flag 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
+ RSPAMC_COMMAND_LEARN,
+ RSPAMC_COMMAND_FUZZY_ADD,
+ RSPAMC_COMMAND_FUZZY_DEL,
+ RSPAMC_COMMAND_STAT
};
/*
else if (g_ascii_strcasecmp (cmd, "LEARN") == 0) {
return RSPAMC_COMMAND_LEARN;
}
+ else if (g_ascii_strcasecmp (cmd, "FUZZY_ADD") == 0) {
+ return RSPAMC_COMMAND_FUZZY_ADD;
+ }
+ else if (g_ascii_strcasecmp (cmd, "FUZZY_DEL") == 0) {
+ return RSPAMC_COMMAND_FUZZY_DEL;
+ }
+ else if (g_ascii_strcasecmp (cmd, "STAT") == 0) {
+ return RSPAMC_COMMAND_STAT;
+ }
return RSPAMC_COMMAND_UNKNOWN;
}
exit (EXIT_FAILURE);
}
print_rspamd_result (res);
+ rspamd_free_result (res);
}
static void
g_hash_table_destroy (opts);
if (err != NULL) {
fprintf (stderr, "cannot scan message: %s\n", err->message);
- exit (EXIT_FAILURE);
}
print_rspamd_result (res);
+ if (res) {
+ rspamd_free_result (res);
+ }
+}
+
+static void
+learn_rspamd_stdin ()
+{
+ gchar *in_buf;
+ gint r = 0, len;
+ GError *err = NULL;
+
+ if (password == NULL || statfile == NULL) {
+ fprintf (stderr, "cannot learn message without password and symbol name\n");
+ exit (EXIT_FAILURE);
+ }
+ /* Add server */
+ add_rspamd_server (TRUE);
+
+ /* 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);
+ }
+ }
+ if (!rspamd_learn_memory (in_buf, r, statfile, password, &err)) {
+ if (err != NULL) {
+ fprintf (stderr, "cannot learn message: %s\n", err->message);
+ }
+ else {
+ fprintf (stderr, "cannot learn message\n");
+ }
+ exit (EXIT_FAILURE);
+ }
+ else {
+ if (tty) {
+ printf ("\033[1m");
+ }
+ PRINT_FUNC ("Results for host: %s: learn ok\n", connect_str);
+ if (tty) {
+ printf ("\033[0m");
+ }
+ }
+}
+
+static void
+learn_rspamd_file (const gchar *file)
+{
+ GError *err = NULL;
+
+ if (password == NULL || statfile == NULL) {
+ fprintf (stderr, "cannot learn message without password and symbol name\n");
+ exit (EXIT_FAILURE);
+ }
+ /* Add server */
+ add_rspamd_server (TRUE);
+
+ if (!rspamd_learn_file (file, statfile, password, &err)) {
+ if (err != NULL) {
+ fprintf (stderr, "cannot learn message: %s\n", err->message);
+ }
+ else {
+ fprintf (stderr, "cannot learn message\n");
+ }
+ }
+ else {
+ if (tty) {
+ printf ("\033[1m");
+ }
+ PRINT_FUNC ("learn ok\n");
+ if (tty) {
+ printf ("\033[0m");
+ }
+ }
+}
+
+static void
+fuzzy_rspamd_stdin (gboolean delete)
+{
+ gchar *in_buf;
+ gint r = 0, len;
+ GError *err = NULL;
+
+ if (password == NULL) {
+ fprintf (stderr, "cannot learn message without password\n");
+ exit (EXIT_FAILURE);
+ }
+ /* Add server */
+ add_rspamd_server (TRUE);
+
+ /* 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);
+ }
+ }
+ if (!rspamd_fuzzy_memory (in_buf, r, password, weight, flag, delete, &err)) {
+ if (err != NULL) {
+ fprintf (stderr, "cannot learn message: %s\n", err->message);
+ }
+ else {
+ fprintf (stderr, "cannot learn message\n");
+ }
+ exit (EXIT_FAILURE);
+ }
+ else {
+ if (tty) {
+ printf ("\033[1m");
+ }
+ PRINT_FUNC ("Results for host: %s: learn ok\n", connect_str);
+ if (tty) {
+ printf ("\033[0m");
+ }
+ }
+}
+
+static void
+fuzzy_rspamd_file (const gchar *file, gboolean delete)
+{
+ GError *err = NULL;
+
+ if (password == NULL) {
+ fprintf (stderr, "cannot learn message without password\n");
+ exit (EXIT_FAILURE);
+ }
+ /* Add server */
+ add_rspamd_server (TRUE);
+
+ if (!rspamd_fuzzy_file (file, password, weight, flag, delete, &err)) {
+ if (err != NULL) {
+ fprintf (stderr, "cannot learn message: %s\n", err->message);
+ }
+ else {
+ fprintf (stderr, "cannot learn message\n");
+ }
+ }
+ else {
+ if (tty) {
+ printf ("\033[1m");
+ }
+ PRINT_FUNC ("learn ok\n");
+ if (tty) {
+ printf ("\033[0m");
+ }
+ }
+}
+
+static void
+rspamd_do_stat ()
+{
+ GError *err = NULL;
+ GString *res;
+
+ /* Add server */
+ add_rspamd_server (TRUE);
+
+ res = rspamd_get_stat (&err);
+ if (res == NULL) {
+ if (err != NULL) {
+ fprintf (stderr, "cannot learn message: %s\n", err->message);
+ }
+ else {
+ fprintf (stderr, "cannot learn message\n");
+ }
+ exit (EXIT_FAILURE);
+ }
+ if (tty) {
+ printf ("\033[1m");
+ }
+ PRINT_FUNC ("Results for host: %s\n\n", connect_str);
+ if (tty) {
+ printf ("\033[0m");
+ }
+ res = g_string_append_c (res, '\0');
+ printf ("%s\n", res->str);
}
gint
/* 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) {
+ switch (cmd) {
+ case RSPAMC_COMMAND_SYMBOLS:
scan_rspamd_stdin ();
- }
- else {
- /* XXX: implement this */
+ break;
+ case RSPAMC_COMMAND_LEARN:
+ learn_rspamd_stdin ();
+ break;
+ case RSPAMC_COMMAND_FUZZY_ADD:
+ fuzzy_rspamd_stdin (FALSE);
+ break;
+ case RSPAMC_COMMAND_FUZZY_DEL:
+ fuzzy_rspamd_stdin (TRUE);
+ break;
+ case RSPAMC_COMMAND_STAT:
+ rspamd_do_stat ();
+ default:
+ fprintf (stderr, "invalid arguments\n");
+ exit (EXIT_FAILURE);
}
}
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]);
+ if (tty) {
+ printf ("\033[1m");
}
- else {
- /* XXX: implement this */
+ PRINT_FUNC ("Results for file: %s\n\n", argv[i]);
+ if (tty) {
+ printf ("\033[0m");
+ }
+ switch (cmd) {
+ case RSPAMC_COMMAND_SYMBOLS:
+ scan_rspamd_file (argv[i]);
+ break;
+ case RSPAMC_COMMAND_LEARN:
+ learn_rspamd_file (argv[i]);
+ break;
+ case RSPAMC_COMMAND_FUZZY_ADD:
+ fuzzy_rspamd_file (argv[i], FALSE);
+ break;
+ case RSPAMC_COMMAND_FUZZY_DEL:
+ fuzzy_rspamd_file (argv[i], TRUE);
+ break;
+ default:
+ fprintf (stderr, "invalid arguments\n");
+ exit (EXIT_FAILURE);
}
}
}
}
}
+ rspamd_client_close ();
return 0;
}
/* Handle messages without text */
if (tokens == NULL) {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, no tokens can be extracted (no text data)" CRLF);
+ i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, no tokens can be extracted (no text data)" CRLF END);
msg_info ("learn failed for message <%s>, no tokens to extract", task->message_id);
free_task (task, FALSE);
if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
session->learn_symbol, tokens, session->in_class, &sum,
session->learn_multiplier, &err)) {
if (err) {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, learn classifier error: %s" CRLF, err->message);
+ i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, learn classifier error: %s" CRLF END, err->message);
msg_info ("learn failed for message <%s>, learn error: %s", task->message_id, err->message);
g_error_free (err);
}
else {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, unknown learn classifier error" CRLF);
+ i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, unknown learn classifier error" CRLF END);
msg_info ("learn failed for message <%s>, unknown learn error", task->message_id);
}
free_task (task, FALSE);
task->message_id, session->learn_symbol, sum);
statfile_pool_plan_invalidate (session->worker->srv->statfile_pool, DEFAULT_STATFILE_INVALIDATE_TIME, DEFAULT_STATFILE_INVALIDATE_JITTER);
free_task (task, FALSE);
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn ok, sum weight: %.2f" CRLF, sum);
+ i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn ok, sum weight: %.2f" CRLF END, sum);
if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
return FALSE;
}
msg_warn ("processing of message failed");
free_task (task, FALSE);
session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot process message" CRLF);
+ r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot process message" CRLF END);
if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
return FALSE;
}
c.begin = part->content->data;
c.len = part->content->len;
if (!session->learn_classifier->tokenizer->tokenize_func (session->learn_classifier->tokenizer, session->session_pool, &c, &tokens)) {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "weights failed, tokenizer error" CRLF);
+ i = rspamd_snprintf (out_buf, sizeof (out_buf), "weights failed, tokenizer error" CRLF END);
free_task (task, FALSE);
if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
return FALSE;
/* Handle messages without text */
if (tokens == NULL) {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "weights failed, no tokens can be extracted (no text data)" CRLF);
+ i = rspamd_snprintf (out_buf, sizeof (out_buf), "weights failed, no tokens can be extracted (no text data)" CRLF END);
free_task (task, FALSE);
if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
return FALSE;
i += rspamd_snprintf (out_buf + i, sizeof (out_buf) - i, "%s: %G" CRLF, w->name, w->weight);
cur = g_list_next (cur);
}
+ i += rspamd_snprintf (out_buf + i, sizeof (out_buf) - i, END);
if (i != 0) {
if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
return FALSE;
}
}
else {
- if (!rspamd_dispatcher_write (session->dispatcher, "weights failed: classifier error", 0, FALSE, TRUE)) {
+ if (!rspamd_dispatcher_write (session->dispatcher, "weights failed: classifier error" CRLF END, 0, FALSE, TRUE)) {
return FALSE;
}
}
else if (buf[0] == 'O' && buf[1] == 'K') {
msg_info ("added fuzzy hash '%s' to list: %d for message <%s>",
fuzzy_to_string (session->h), session->flag, session->task->message_id);
- r = rspamd_snprintf (buf, sizeof (buf), "OK" CRLF);
+ r = rspamd_snprintf (buf, sizeof (buf), "OK" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->session->dispatcher, buf, r, FALSE, FALSE)) {
return;
}
}
else {
msg_info ("cannot add fuzzy hash for message <%s>", session->task->message_id);
- r = rspamd_snprintf (buf, sizeof (buf), "ERR" CRLF);
+ r = rspamd_snprintf (buf, sizeof (buf), "ERR" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->session->dispatcher, buf, r, FALSE, FALSE)) {
return;
}
err:
msg_err ("got error in IO with server %s:%d, %d, %s", session->server->name, session->server->port, errno, strerror (errno));
- r = rspamd_snprintf (buf, sizeof (buf), "Error" CRLF);
+ r = rspamd_snprintf (buf, sizeof (buf), "Error" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->session->dispatcher, buf, r, FALSE, FALSE)) {
return;
}
if ((sock = make_udp_socket (&selected->addr, selected->port, FALSE, TRUE)) == -1) {
msg_warn ("cannot connect to %s, %d, %s", selected->name, errno, strerror (errno));
session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "no hashes written" CRLF);
+ r = rspamd_snprintf (out_buf, sizeof (out_buf), "no hashes written" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
return FALSE;
}
msg_warn ("processing of message failed");
free_task (task, FALSE);
session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot process message" CRLF);
+ r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot process message" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
msg_warn ("write error");
}
if (! register_fuzzy_controller_call (session, task, part->fuzzy, cmd, value, flag, saved)) {
/* Cannot write hash */
session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot write fuzzy hash" CRLF);
+ r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot write fuzzy hash" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
return;
}
if (! register_fuzzy_controller_call (session, task, &fake_fuzzy, cmd, value, flag, saved)) {
/* Cannot write hash */
session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot write fuzzy hash" CRLF);
+ r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot write fuzzy hash" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
return;
}
if (! register_fuzzy_controller_call (session, task, &fake_fuzzy, cmd, value, flag, saved)) {
/* Cannot write hash */
session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot write fuzzy hash" CRLF);
+ r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot write fuzzy hash" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
return;
}
if (*saved == 0) {
session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "no hashes written" CRLF);
+ r = rspamd_snprintf (out_buf, sizeof (out_buf), "no hashes written" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
return;
}
arg = args[0];
if (!arg || *arg == '\0') {
msg_info ("empty content length");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "fuzzy command requires length as argument" CRLF);
+ r = rspamd_snprintf (out_buf, sizeof (out_buf), "fuzzy command requires length as argument" CRLF "END" CRLF);
if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
return;
}