aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Jain <jvivek@novell.com>2005-07-06 13:20:38 +0800
committerJain Vivek <jvivek@src.gnome.org>2005-07-06 13:20:38 +0800
commitf1bb8634282308d6747f303454329345bdcf9e76 (patch)
treee1637c7451d938222695ea7b8efe7d2fe70551fb
parent8cb64d5172526847b3d6da722c207924b836a066 (diff)
downloadgsoc2013-evolution-f1bb8634282308d6747f303454329345bdcf9e76.tar.gz
gsoc2013-evolution-f1bb8634282308d6747f303454329345bdcf9e76.tar.zst
gsoc2013-evolution-f1bb8634282308d6747f303454329345bdcf9e76.zip
sa-junk-plugin : plugin that uses spam assasin for junk mail handling
2005-07-06 Vivek Jain <jvivek@novell.com> sa-junk-plugin : plugin that uses spam assasin for junk mail handling moved em-junk-filter.c from mail/ to here and modified it to listen to the callbacks from the plugin. svn path=/trunk/; revision=29645
-rw-r--r--plugins/sa-junk-plugin/ChangeLog8
-rw-r--r--plugins/sa-junk-plugin/Makefile.am21
-rw-r--r--plugins/sa-junk-plugin/em-junk-filter.c760
-rw-r--r--plugins/sa-junk-plugin/org-gnome-sa-junk-plugin.eplug.xml18
4 files changed, 807 insertions, 0 deletions
diff --git a/plugins/sa-junk-plugin/ChangeLog b/plugins/sa-junk-plugin/ChangeLog
new file mode 100644
index 0000000000..ce0d30b805
--- /dev/null
+++ b/plugins/sa-junk-plugin/ChangeLog
@@ -0,0 +1,8 @@
+2005-07-06 Vivek Jain <jvivek@novell.com>
+
+ sa-junk-plugin : plugin that uses spam assasin for junk mail
+ handling
+ moved em-junk-filter.c from mail/ to here and modified it to listen
+ to the callbacks from the plugin.
+
+
diff --git a/plugins/sa-junk-plugin/Makefile.am b/plugins/sa-junk-plugin/Makefile.am
new file mode 100644
index 0000000000..a3bf4e67f1
--- /dev/null
+++ b/plugins/sa-junk-plugin/Makefile.am
@@ -0,0 +1,21 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(EVOLUTION_MAIL_CFLAGS)
+
+@EVO_PLUGIN_RULE@
+
+plugin_DATA = org-gnome-sa-junk-plugin.eplug
+plugin_LTLIBRARIES = liborg-gnome-sa-junk-plugin.la
+
+liborg_gnome_sa_junk_plugin_la_SOURCES = em-junk-filter.c
+liborg_gnome_sa_junk_plugin_la_LDFLAGS = -module -avoid-version
+
+
+BUILT_SOURCES = $(plugin_DATA) $(error_DATA)
+
+CLEANFILES = $(BUILT_SOURCES)
+
+EXTRA_DIST = \
+ org-gnome-sa-junk-plugin.eplug.xml
+
+
diff --git a/plugins/sa-junk-plugin/em-junk-filter.c b/plugins/sa-junk-plugin/em-junk-filter.c
new file mode 100644
index 0000000000..af61f9ed94
--- /dev/null
+++ b/plugins/sa-junk-plugin/em-junk-filter.c
@@ -0,0 +1,760 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Author:
+ * Radek Doulik <rodo@ximian.com>
+ *
+ * Copyright 2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include <time.h>
+
+#include <camel/camel-debug.h>
+#include <camel/camel-file-utils.h>
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-stream-fs.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-i18n.h>
+#include <mail/em-junk-hook.h>
+#include <mail/em-utils.h>
+#include <e-util/e-mktemp.h>
+
+#include <gconf/gconf-client.h>
+
+#define d(x) (camel_debug("junk")?(x):0)
+
+static pthread_mutex_t em_junk_sa_init_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t em_junk_sa_report_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t em_junk_sa_preferred_socket_path_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t em_junk_sa_spamd_restart_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static const char *em_junk_sa_get_name (void);
+gboolean em_junk_sa_check_junk (EPlugin *ep, EMJunkHookTarget *target);
+void em_junk_sa_report_junk (EPlugin *ep, EMJunkHookTarget *target);
+void em_junk_sa_report_notjunk (EPlugin *ep, EMJunkHookTarget *target);
+void em_junk_sa_commit_reports (EPlugin *ep, EMJunkHookTarget *target);
+static void em_junk_sa_init (void);
+static void em_junk_sa_finalize (void);
+static void em_junk_sa_kill_spamd (void);
+
+
+static gboolean em_junk_sa_tested = FALSE;
+static gboolean em_junk_sa_spamd_tested = FALSE;
+static gboolean em_junk_sa_use_spamc = FALSE;
+static gboolean em_junk_sa_available = FALSE;
+static gboolean em_junk_sa_system_spamd_available = FALSE;
+static gboolean em_junk_sa_new_daemon_started = FALSE;
+static char *em_junk_sa_socket_path = NULL;
+static char *em_junk_sa_spamd_pidfile = NULL;
+static char *em_junk_sa_spamc_binary = NULL;
+static GConfClient *em_junk_sa_gconf = NULL;
+
+/* volatile so not cached between threads */
+static volatile gboolean em_junk_sa_local_only;
+static volatile gboolean em_junk_sa_use_daemon;
+static char * em_junk_sa_preferred_socket_path;
+
+static char *em_junk_sa_spamc_binaries [3] = {"spamc", "/usr/sbin/spamc", NULL};
+static char *em_junk_sa_spamd_binaries [3] = {"spamd", "/usr/sbin/spamd", NULL};
+
+#define SPAMD_RESTARTS_SIZE 8
+static time_t em_junk_sa_spamd_restarts [SPAMD_RESTARTS_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0};
+static int em_junk_sa_spamd_restarts_count = 0;
+
+char *em_junk_sa_spamc_gconf_binary = NULL;
+char *em_junk_sa_spamd_gconf_binary = NULL;
+
+static const char *
+em_junk_sa_get_name (void)
+{
+ return _("Spamassassin (built-in)");
+}
+
+static int
+pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err, int wait_for_termination, GByteArray *output_buffer)
+{
+ int result, status, errnosav, fds[2], out_fds[2];
+ CamelStream *stream;
+ char *program;
+ pid_t pid;
+
+
+ if (camel_debug_start ("junk")) {
+ int i;
+
+ printf ("pipe_to_sa ");
+ for (i = 0; argv[i]; i++)
+ printf ("%s ", argv[i]);
+ printf ("\n");
+ camel_debug_end ();
+ }
+
+ program = g_find_program_in_path (argv [0]);
+ if (program == NULL) {
+ d(printf ("program not found, returning %d\n", rv_err));
+ return rv_err;
+ }
+ g_free (program);
+
+ if (pipe (fds) == -1) {
+ errnosav = errno;
+ d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno)));
+ errno = errnosav;
+ return rv_err;
+ }
+
+ if (output_buffer && pipe (out_fds) == -1) {
+ errnosav = errno;
+ d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno)));
+ errno = errnosav;
+ return rv_err;
+ }
+
+ if (!(pid = fork ())) {
+ /* child process */
+ int maxfd, fd, nullfd;
+
+ nullfd = open ("/dev/null", O_WRONLY);
+
+ if (dup2 (fds[0], STDIN_FILENO) == -1 ||
+ dup2 (nullfd, STDERR_FILENO) == -1 ||
+ (output_buffer == NULL && dup2 (nullfd, STDOUT_FILENO) == -1) ||
+ (output_buffer != NULL && dup2 (out_fds[1], STDOUT_FILENO) == -1))
+ _exit (rv_err & 0377);
+ close (fds [0]);
+ if (output_buffer)
+ close (out_fds [1]);
+
+ setsid ();
+
+ maxfd = sysconf (_SC_OPEN_MAX);
+ for (fd = 3; fd < maxfd; fd++)
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+
+ execvp (argv[0], argv);
+ _exit (rv_err & 0377);
+ } else if (pid < 0) {
+ errnosav = errno;
+ close (fds[0]);
+ close (fds[1]);
+ errno = errnosav;
+ return rv_err;
+ }
+
+ /* parent process */
+ close (fds[0]);
+ if (output_buffer)
+ close (out_fds [1]);
+
+ if (msg) {
+ stream = camel_stream_fs_new_with_fd (fds[1]);
+
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (msg), stream);
+ camel_stream_flush (stream);
+ camel_stream_close (stream);
+ camel_object_unref (stream);
+ } else if (in) {
+ camel_write (fds[1], in, strlen (in));
+ close (fds[1]);
+ }
+
+ if (output_buffer) {
+ CamelStreamMem *memstream;
+
+ stream = camel_stream_fs_new_with_fd (out_fds[0]);
+
+ memstream = (CamelStreamMem *) camel_stream_mem_new ();
+ camel_stream_mem_set_byte_array (memstream, output_buffer);
+
+ camel_stream_write_to_stream (stream, (CamelStream *) memstream);
+ camel_object_unref (stream);
+ g_byte_array_append (output_buffer, "", 1);
+
+ d(printf ("child process output: %s len: %d\n", output_buffer->data, output_buffer->len));
+ }
+
+ if (wait_for_termination) {
+ d(printf ("wait for child %d termination\n", pid));
+ result = waitpid (pid, &status, 0);
+
+ d(printf ("child %d terminated with result %d status %d exited %d exitstatus %d\n", pid, result, status, WIFEXITED (status), WEXITSTATUS (status)));
+
+ if (result == -1 && errno == EINTR) {
+ /* child process is hanging... */
+ kill (pid, SIGTERM);
+ sleep (1);
+ result = waitpid (pid, &status, WNOHANG);
+ if (result == 0) {
+ /* ...still hanging, set phasers to KILL */
+ kill (pid, SIGKILL);
+ sleep (1);
+ result = waitpid (pid, &status, WNOHANG);
+ }
+ }
+
+ if (result != -1 && WIFEXITED (status))
+ return WEXITSTATUS (status);
+ else
+ return rv_err;
+ } else
+ return 0;
+}
+
+static int
+pipe_to_sa (CamelMimeMessage *msg, const char *in, char **argv)
+{
+ return pipe_to_sa_full (msg, in, argv, -1, 1, NULL);
+}
+
+static char *
+em_junk_sa_get_socket_path ()
+{
+ if (em_junk_sa_preferred_socket_path)
+ return em_junk_sa_preferred_socket_path;
+ else
+ return em_junk_sa_socket_path;
+}
+
+static gboolean
+em_junk_sa_test_spamd_running (char *binary, gboolean system)
+{
+ char *argv[5];
+ int i = 0;
+ gboolean rv;
+
+ pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+
+ d(fprintf (stderr, "test if spamd is running (system %d) or using socket path %s\n", system, em_junk_sa_get_socket_path ()));
+
+ argv[i++] = binary;
+ argv[i++] = "-x";
+
+ if (!system) {
+ argv[i++] = "-U";
+ argv[i++] = em_junk_sa_get_socket_path ();
+ }
+
+ argv[i] = NULL;
+
+ rv = pipe_to_sa (NULL, "From test@127.0.0.1", argv) == 0;
+
+ d(fprintf (stderr, "result: %d (%s)\n", rv, rv ? "success" : "failed"));
+
+ pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+ return rv;
+}
+
+static void
+em_junk_sa_test_spamassassin (void)
+{
+ char *argv [3] = {
+ "spamassassin",
+ "--version",
+ NULL,
+ };
+
+ if (pipe_to_sa (NULL, NULL, argv) != 0)
+ em_junk_sa_available = FALSE;
+ else
+ em_junk_sa_available = TRUE;
+
+ em_junk_sa_tested = TRUE;
+}
+
+#define MAX_SPAMD_PORTS 1
+
+static gboolean
+em_junk_sa_run_spamd (char *binary)
+{
+ char *argv[8];
+ int i;
+ gboolean rv = FALSE;
+
+ pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+
+ d(fprintf (stderr, "looks like spamd is not running\n"));
+
+ i = 0;
+ argv[i++] = binary;
+ argv[i++] = "--socketpath";
+ argv[i++] = em_junk_sa_get_socket_path ();
+
+ if (em_junk_sa_local_only)
+ argv[i++] = "--local";
+
+ //argv[i++] = "--daemonize";
+ argv[i++] = "--pidfile";
+ argv[i++] = em_junk_sa_spamd_pidfile;
+ argv[i] = NULL;
+
+ d(fprintf (stderr, "trying to run %s with socket path %s\n", binary, em_junk_sa_get_socket_path ()));
+
+ if (!pipe_to_sa_full (NULL, NULL, argv, -1, 0, NULL)) {
+ int i;
+ struct timespec time_req;
+ struct stat stat_buf;
+
+ d(fprintf (stderr, "success\n"));
+ d(fprintf (stderr, "waiting for spamd to come up\n"));
+
+ time_req.tv_sec = 0;
+ time_req.tv_nsec = 50000000;
+
+ for (i = 0; i < 100; i ++) {
+ if (stat (em_junk_sa_get_socket_path (), &stat_buf) == 0) {
+ d(fprintf (stderr, "socket created\n"));
+ break;
+ }
+ nanosleep (&time_req, NULL);
+ }
+ d(fprintf (stderr, "waiting is over (after %dms)\n", 50*i));
+
+ rv = TRUE;
+ }
+
+ pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+ return rv;
+}
+
+static void
+em_junk_sa_start_own_daemon ()
+{
+ int b;
+
+ em_junk_sa_new_daemon_started = FALSE;
+
+ em_junk_sa_socket_path = e_mktemp ("spamd-socket-path-XXXXXX");
+ em_junk_sa_spamd_pidfile = e_mktemp ("spamd-pid-file-XXXXXX");
+
+ for (b = 0; em_junk_sa_spamd_binaries [b]; b ++) {
+ em_junk_sa_use_spamc = em_junk_sa_run_spamd (em_junk_sa_spamd_binaries [b]);
+ if (em_junk_sa_use_spamc) {
+ em_junk_sa_new_daemon_started = TRUE;
+ break;
+ }
+ }
+}
+
+static void
+em_junk_sa_find_spamc ()
+{
+ if (em_junk_sa_use_spamc && em_junk_sa_new_daemon_started) {
+ int b;
+
+ em_junk_sa_use_spamc = FALSE;
+ for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
+ em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
+ if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, FALSE)) {
+ em_junk_sa_use_spamc = TRUE;
+ break;
+ }
+ }
+ }
+}
+
+static void
+em_junk_sa_test_spamd (void)
+{
+ char *argv[4];
+ int i, b;
+ gboolean try_system_spamd = TRUE;
+
+ if (em_junk_sa_spamc_gconf_binary) {
+ em_junk_sa_spamc_binaries [0] = em_junk_sa_spamc_gconf_binary;
+ em_junk_sa_spamc_binaries [1] = NULL;
+ }
+
+ if (em_junk_sa_spamd_gconf_binary) {
+ em_junk_sa_spamd_binaries [0] = em_junk_sa_spamd_gconf_binary;
+ em_junk_sa_spamd_binaries [1] = NULL;
+ try_system_spamd = FALSE;
+ }
+
+ em_junk_sa_use_spamc = FALSE;
+
+ if (em_junk_sa_local_only && try_system_spamd) {
+ i = 0;
+ argv [i++] = "/bin/sh";
+ argv [i++] = "-c";
+ argv [i++] = "ps ax|grep -v grep|grep -E 'spamd.*(\\-L|\\-\\-local)'|grep -E -v '\\ \\-p\\ |\\ \\-\\-port\\ '";
+ argv[i] = NULL;
+
+ if (pipe_to_sa (NULL, NULL, argv) != 0) {
+ try_system_spamd = FALSE;
+ d(fprintf (stderr, "there's no system spamd with -L/--local parameter running\n"));
+ }
+ }
+
+ /* try to use sytem spamd first */
+ if (try_system_spamd) {
+ for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
+ em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
+ if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, TRUE)) {
+ em_junk_sa_use_spamc = TRUE;
+ em_junk_sa_system_spamd_available = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* if there's no system spamd running, try to use user one with user specified socket */
+ if (!em_junk_sa_use_spamc && em_junk_sa_preferred_socket_path) {
+ for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
+ em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
+ if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, FALSE)) {
+ em_junk_sa_use_spamc = TRUE;
+ em_junk_sa_system_spamd_available = FALSE;
+ break;
+ }
+ }
+ }
+
+ /* unsuccessful? try to run one ourselfs */
+ if (!em_junk_sa_use_spamc)
+ em_junk_sa_start_own_daemon ();
+
+ /* new daemon started => let find spamc binary */
+ em_junk_sa_find_spamc ();
+
+ d(fprintf (stderr, "use spamd: %s\n", em_junk_sa_use_spamc ? "yes" : "no"));
+
+ em_junk_sa_spamd_tested = TRUE;
+}
+
+static gboolean
+em_junk_sa_is_available (void)
+{
+ pthread_mutex_lock (&em_junk_sa_init_lock);
+
+ if (!em_junk_sa_tested)
+ em_junk_sa_test_spamassassin ();
+
+ if (em_junk_sa_available && !em_junk_sa_spamd_tested && em_junk_sa_use_daemon)
+ em_junk_sa_test_spamd ();
+
+ pthread_mutex_unlock (&em_junk_sa_init_lock);
+
+ return em_junk_sa_available;
+}
+
+static gboolean
+em_junk_sa_check_respawn_too_fast ()
+{
+ time_t time_now = time (NULL);
+ gboolean rv;
+
+ pthread_mutex_lock (&em_junk_sa_spamd_restart_lock);
+
+ if (em_junk_sa_spamd_restarts_count >= SPAMD_RESTARTS_SIZE) {
+ /* all restarts in last 5 minutes */
+ rv = (time_now - em_junk_sa_spamd_restarts [em_junk_sa_spamd_restarts_count % SPAMD_RESTARTS_SIZE] < 5*60);
+ } else
+ rv = FALSE;
+
+ em_junk_sa_spamd_restarts [em_junk_sa_spamd_restarts_count % SPAMD_RESTARTS_SIZE] = time_now;
+ em_junk_sa_spamd_restarts_count ++;
+
+ pthread_mutex_unlock (&em_junk_sa_spamd_restart_lock);
+
+ d(printf ("em_junk_sa_check_respawn_too_fast: %d\n", rv));
+
+ return rv;
+}
+
+static gboolean
+em_junk_sa_respawn_spamd ()
+{
+ d(printf ("em_junk_sa_respawn_spamd\n"));
+ if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, em_junk_sa_system_spamd_available)) {
+ /* false alert */
+ d(printf ("false alert, spamd still running\n"));
+
+ return FALSE;
+ }
+
+ d(printf ("going to kill old spamd and start new one\n"));
+ em_junk_sa_kill_spamd ();
+
+ if (em_junk_sa_check_respawn_too_fast ()) {
+ g_warning ("respawning of spamd too fast => fallback to use spamassassin directly");
+
+ em_junk_sa_use_spamc = em_junk_sa_use_daemon = FALSE;
+ return FALSE;
+ }
+
+ em_junk_sa_start_own_daemon ();
+ em_junk_sa_find_spamc ();
+
+ d(printf ("%s\n", em_junk_sa_use_spamc ? "success" : "failed"));
+
+ return em_junk_sa_use_spamc;
+}
+
+gboolean
+em_junk_sa_check_junk(EPlugin *ep, EMJunkHookTarget *target)
+{
+ GByteArray *out = NULL;
+ char *argv[7], *to_free = NULL;
+ int i = 0, socket_i;
+ gboolean rv;
+ CamelMimeMessage *msg = target->m;
+
+ d(fprintf (stderr, "em_junk_sa_check_junk\n"));
+ g_print ("checking for junk..?\n");
+
+ if (!em_junk_sa_is_available ())
+ return FALSE;
+
+ if (em_junk_sa_use_spamc && em_junk_sa_use_daemon) {
+ out = g_byte_array_new ();
+ argv[i++] = em_junk_sa_spamc_binary;
+ argv[i++] = "-c";
+ argv[i++] = "-t";
+ argv[i++] = "60";
+ if (!em_junk_sa_system_spamd_available) {
+ argv[i++] = "-U";
+
+ pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+ socket_i = i;
+ argv[i++] = to_free = g_strdup (em_junk_sa_get_socket_path ());
+ pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+ }
+ } else {
+ argv [i++] = "spamassassin";
+ argv [i++] = "--exit-code";
+ if (em_junk_sa_local_only)
+ argv [i++] = "--local";
+ }
+
+ argv[i] = NULL;
+
+ rv = pipe_to_sa_full (msg, NULL, argv, 0, 1, out) != 0;
+
+ if (!rv && out && !strcmp (out->data, "0/0\n")) {
+ /* an error occured */
+ if (em_junk_sa_respawn_spamd ()) {
+ g_byte_array_set_size (out, 0);
+
+ pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+ g_free (to_free);
+ argv [socket_i] = to_free = g_strdup (em_junk_sa_get_socket_path ());
+ pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+ rv = pipe_to_sa_full (msg, NULL, argv, 0, 1, out) != 0;
+ } else if (!em_junk_sa_use_spamc)
+ /* in case respawning were too fast we fallback to spamassassin */
+ rv = em_junk_sa_check_junk (ep, target);
+ }
+
+ g_free (to_free);
+
+ d(fprintf (stderr, "em_junk_sa_check_junk rv = %d\n", rv));
+
+ if (out)
+ g_byte_array_free (out, TRUE);
+
+ return rv;
+}
+
+void
+em_junk_sa_report_junk (EPlugin *ep, EMJunkHookTarget *target)
+{
+ char *argv[6] = {
+ "sa-learn",
+ "--no-rebuild",
+ "--spam",
+ "--single",
+ NULL,
+ NULL
+ };
+ gchar *sub = NULL;
+ CamelMimeMessage *msg = target->m;
+
+ sub = g_strdup (camel_mime_message_get_subject (msg));
+ g_print ("\nreport junk?? %s\n", sub);
+
+ d(fprintf (stderr, "em_junk_sa_report_junk\n"));
+
+ if (em_junk_sa_is_available ()) {
+ if (em_junk_sa_local_only)
+ argv[4] = "--local";
+
+ pthread_mutex_lock (&em_junk_sa_report_lock);
+ pipe_to_sa (msg, NULL, argv);
+ pthread_mutex_unlock (&em_junk_sa_report_lock);
+ }
+}
+
+void
+em_junk_sa_report_non_junk (EPlugin *ep, EMJunkHookTarget *target)
+{
+ char *argv[6] = {
+ "sa-learn",
+ "--no-rebuild",
+ "--ham",
+ "--single",
+ NULL,
+ NULL
+ };
+ CamelMimeMessage *msg = target->m;
+
+ d(fprintf (stderr, "em_junk_sa_report_notjunk\n"));
+
+ if (em_junk_sa_is_available ()) {
+ if (em_junk_sa_local_only)
+ argv[4] = "--local";
+
+ pthread_mutex_lock (&em_junk_sa_report_lock);
+ pipe_to_sa (msg, NULL, argv);
+ pthread_mutex_unlock (&em_junk_sa_report_lock);
+ }
+}
+
+void
+em_junk_sa_commit_reports (EPlugin *ep, EMJunkHookTarget *target)
+{
+ char *argv[4] = {
+ "sa-learn",
+ "--rebuild",
+ NULL,
+ NULL
+ };
+
+ d(fprintf (stderr, "em_junk_sa_commit_reports\n"));
+
+ if (em_junk_sa_is_available ()) {
+ if (em_junk_sa_local_only)
+ argv[2] = "--local";
+
+ pthread_mutex_lock (&em_junk_sa_report_lock);
+ pipe_to_sa (NULL, NULL, argv);
+ pthread_mutex_unlock (&em_junk_sa_report_lock);
+ }
+}
+
+static void
+em_junk_sa_setting_notify(GConfClient *gconf, guint cnxn_id, GConfEntry *entry, void *data)
+{
+ GConfValue *value;
+ char *tkey;
+
+ g_return_if_fail (gconf_entry_get_key (entry) != NULL);
+
+ if (!(value = gconf_entry_get_value (entry)))
+ return;
+
+ tkey = strrchr(entry->key, '/');
+ g_return_if_fail (tkey != NULL);
+
+ if (!strcmp(tkey, "local_only"))
+ em_junk_sa_local_only = gconf_value_get_bool(value);
+ else if (!strcmp(tkey, "use_daemon"))
+ em_junk_sa_use_daemon = gconf_value_get_bool(value);
+ else if (!strcmp(tkey, "socket_path")) {
+ pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+ g_free (em_junk_sa_preferred_socket_path);
+ em_junk_sa_preferred_socket_path = g_strdup (gconf_value_get_string(value));
+ pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+ }
+}
+
+static void
+em_junk_sa_init (void)
+{
+ pthread_mutex_lock (&em_junk_sa_init_lock);
+
+ if (!em_junk_sa_gconf) {
+ em_junk_sa_gconf = gconf_client_get_default();
+ gconf_client_add_dir (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+ em_junk_sa_local_only = gconf_client_get_bool (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/local_only", NULL);
+ em_junk_sa_use_daemon = gconf_client_get_bool (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/use_daemon", NULL);
+
+ pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+ g_free (em_junk_sa_preferred_socket_path);
+ em_junk_sa_preferred_socket_path = g_strdup (gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/socket_path", NULL));
+ pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+ gconf_client_notify_add(em_junk_sa_gconf, "/apps/evolution/mail/junk/sa",
+ (GConfClientNotifyFunc)em_junk_sa_setting_notify,
+ NULL, NULL, NULL);
+
+ em_junk_sa_spamc_gconf_binary = gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/spamc_binary", NULL);
+ em_junk_sa_spamd_gconf_binary = gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/spamd_binary", NULL);
+ }
+
+ pthread_mutex_unlock (&em_junk_sa_init_lock);
+
+ atexit (em_junk_sa_finalize);
+}
+
+static void
+em_junk_sa_kill_spamd (void)
+{
+ pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+ g_free (em_junk_sa_preferred_socket_path);
+ em_junk_sa_preferred_socket_path = NULL;
+ pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+ if (em_junk_sa_new_daemon_started) {
+ int fd = open (em_junk_sa_spamd_pidfile, O_RDONLY);
+
+ if (fd != -1) {
+ char pid_str [16];
+ int bytes;
+
+ bytes = read (fd, pid_str, 15);
+ if (bytes > 0) {
+ int pid;
+
+ pid_str [bytes] = 0;
+ pid = atoi (pid_str);
+
+ if (pid > 0) {
+ kill (pid, SIGTERM);
+ d(fprintf (stderr, "em_junk_sa_finalize send SIGTERM to daemon with pid %d\n", pid));
+ waitpid (pid, NULL, 0);
+ }
+ }
+
+ close (fd);
+ }
+ }
+}
+
+static void
+em_junk_sa_finalize (void)
+{
+ d(fprintf (stderr, "em_junk_sa_finalize\n"));
+
+ em_junk_sa_kill_spamd ();
+}
diff --git a/plugins/sa-junk-plugin/org-gnome-sa-junk-plugin.eplug.xml b/plugins/sa-junk-plugin/org-gnome-sa-junk-plugin.eplug.xml
new file mode 100644
index 0000000000..7e15b41c76
--- /dev/null
+++ b/plugins/sa-junk-plugin/org-gnome-sa-junk-plugin.eplug.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<e-plugin-list>
+ <e-plugin id="org.gnome.evolution.sa_junk_plugin"
+ type="shlib" _name="Sa junk-plugin"
+ location="@PLUGINDIR@/liborg-gnome-sa-junk-plugin@SOEXT@">
+ <_description>learns junk messages using spamd.</_description>
+ <author name="Vivek Jain" email="jvivek@novell.com"/>
+ <hook class="org.gnome.evolution.mail.junk:1.0">
+ <group id="EMJunk">
+ <item
+ check_junk="em_junk_sa_check_junk"
+ report_junk="em_junk_sa_report_junk"
+ report_non_junk="em_junk_sa_report_non_junk"
+ commit_reports="em_junk_sa_commit_reports"/>
+ </group>
+ </hook>
+ </e-plugin>
+</e-plugin-list>