diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/spamassassin/evolution-spamassassin.c | 544 |
1 files changed, 19 insertions, 525 deletions
diff --git a/modules/spamassassin/evolution-spamassassin.c b/modules/spamassassin/evolution-spamassassin.c index fa08c56e3b..30793ca8a7 100644 --- a/modules/spamassassin/evolution-spamassassin.c +++ b/modules/spamassassin/evolution-spamassassin.c @@ -35,47 +35,16 @@ (G_TYPE_CHECK_INSTANCE_CAST \ ((obj), E_TYPE_SPAM_ASSASSIN, ESpamAssassin)) -/* For starting our own daemon. */ -#define DAEMON_MAX_RETRIES 100 -#define DAEMON_RETRY_DELAY 0.05 /* seconds */ - #define SPAM_ASSASSIN_EXIT_STATUS_SUCCESS 0 #define SPAM_ASSASSIN_EXIT_STATUS_ERROR -1 -#if defined(SPAMC_COMMAND) && defined(SPAMD_COMMAND) -#define HAVE_SPAM_DAEMON 1 -#endif - -/* This is to reduce the number of #if tests in the code. - * The logic should never actually use these fallbacks. */ -#ifndef SPAMC_COMMAND -#define SPAMC_COMMAND NULL -#endif -#ifndef SPAMD_COMMAND -#define SPAMD_COMMAND NULL -#endif - typedef struct _ESpamAssassin ESpamAssassin; typedef struct _ESpamAssassinClass ESpamAssassinClass; struct _ESpamAssassin { EMailJunkFilter parent; - GOnce spamd_testing; - GMutex socket_path_mutex; - - gchar *pid_file; - gchar *socket_path; - gint version; - gboolean local_only; - gboolean use_daemon; - gboolean version_set; - - /* spamd_testing results */ - gboolean spamd_using_allow_tell; - gboolean system_spamd_available; - gboolean use_spamc; }; struct _ESpamAssassinClass { @@ -84,9 +53,7 @@ struct _ESpamAssassinClass { enum { PROP_0, - PROP_LOCAL_ONLY, - PROP_SOCKET_PATH, - PROP_USE_DAEMON + PROP_LOCAL_ONLY }; /* Module Entry Points */ @@ -341,326 +308,6 @@ spam_assassin_set_local_only (ESpamAssassin *extension, g_object_notify (G_OBJECT (extension), "local-only"); } -static const gchar * -spam_assassin_get_socket_path (ESpamAssassin *extension) -{ - return extension->socket_path; -} - -static void -spam_assassin_set_socket_path (ESpamAssassin *extension, - const gchar *socket_path) -{ - if (g_strcmp0 (extension->socket_path, socket_path) == 0) - return; - - g_free (extension->socket_path); - extension->socket_path = g_strdup (socket_path); - - g_object_notify (G_OBJECT (extension), "socket-path"); -} - -static gboolean -spam_assassin_get_use_daemon (ESpamAssassin *extension) -{ - return extension->use_daemon; -} - -static void -spam_assassin_set_use_daemon (ESpamAssassin *extension, - gboolean use_daemon) -{ - if (extension->use_daemon == use_daemon) - return; - - extension->use_daemon = use_daemon; - - g_object_notify (G_OBJECT (extension), "use-daemon"); -} - -#ifdef HAVE_SPAM_DAEMON -static void -spam_assassin_test_spamd_allow_tell (ESpamAssassin *extension) -{ - gint exit_code; - GError *error = NULL; - - const gchar *argv[] = { - SPAMC_COMMAND, - "--learntype=forget", - NULL - }; - - /* Check if spamd is running with --allow-tell. */ - - exit_code = spam_assassin_command (argv, NULL, "\n", NULL, &error); - extension->spamd_using_allow_tell = (exit_code == 0); - - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } -} - -static gboolean -spam_assassin_test_spamd_running (ESpamAssassin *extension, - gboolean system_spamd) -{ - const gchar *argv[5]; - gint exit_code; - gint ii = 0; - GError *error = NULL; - - g_mutex_lock (&extension->socket_path_mutex); - - argv[ii++] = SPAMC_COMMAND; - argv[ii++] = "--no-safe-fallback"; - if (!system_spamd) { - argv[ii++] = "--socket"; - argv[ii++] = extension->socket_path; - } - argv[ii] = NULL; - - g_assert (ii < G_N_ELEMENTS (argv)); - - exit_code = spam_assassin_command ( - argv, NULL, "From test@127.0.0.1", NULL, &error); - - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } - - g_mutex_unlock (&extension->socket_path_mutex); - - return (exit_code == 0); -} - -static void -spam_assassin_kill_our_own_daemon (ESpamAssassin *extension) -{ - gint pid; - gchar *contents = NULL; - GError *error = NULL; - - g_mutex_lock (&extension->socket_path_mutex); - - g_free (extension->socket_path); - extension->socket_path = NULL; - - g_mutex_unlock (&extension->socket_path_mutex); - - if (extension->pid_file == NULL) - return; - - g_file_get_contents (extension->pid_file, &contents, NULL, &error); - - if (error != NULL) { - g_warn_if_fail (contents == NULL); - g_warning ("%s", error->message); - g_error_free (error); - return; - } - - g_return_if_fail (contents != NULL); - - pid = atoi (contents); - g_free (contents); - - if (pid > 0 && kill (pid, SIGTERM) == 0) - waitpid (pid, NULL, 0); -} - -static void -spam_assassin_prepare_for_quit (EShell *shell, - EActivity *activity, - ESpamAssassin *extension) -{ - spam_assassin_kill_our_own_daemon (extension); -} - -static gboolean -spam_assassin_start_our_own_daemon (ESpamAssassin *extension) -{ - const gchar *argv[8]; - const gchar *user_runtime_dir; - gchar *pid_file; - gchar *socket_path; - gboolean started = FALSE; - gint exit_code; - gint ii = 0; - gint fd; - GError *error = NULL; - - g_mutex_lock (&extension->socket_path_mutex); - - /* Don't put the PID files in Evolution's tmp directory - * (as defined in e-mktemp.c) because that gets cleaned - * every few hours, and these files need to persist. */ - user_runtime_dir = g_get_user_runtime_dir (); - - pid_file = g_build_filename ( - user_runtime_dir, "spamd-pid-file-XXXXXX", NULL); - - socket_path = g_build_filename ( - user_runtime_dir, "spamd-socket-path-XXXXXX", NULL); - - /* The template filename is modified in place. */ - fd = g_mkstemp (pid_file); - if (fd >= 0) { - close (fd); - g_unlink (pid_file); - } else { - g_warning ( - "Failed to create spamd-pid-file: %s", - g_strerror (errno)); - goto exit; - } - - /* The template filename is modified in place. */ - fd = g_mkstemp (socket_path); - if (fd >= 0) { - close (fd); - g_unlink (socket_path); - } else { - g_warning ( - "Failed to create spamd-socket-path: %s", - g_strerror (errno)); - goto exit; - } - - argv[ii++] = SPAMD_COMMAND; - argv[ii++] = "--socketpath"; - argv[ii++] = socket_path; - - if (spam_assassin_get_local_only (extension)) - argv[ii++] = "--local"; - - argv[ii++] = "--max-children=1"; - argv[ii++] = "--pidfile"; - argv[ii++] = pid_file; - argv[ii] = NULL; - - g_assert (ii < G_N_ELEMENTS (argv)); - - exit_code = spam_assassin_command_full ( - argv, NULL, NULL, NULL, FALSE, NULL, &error); - - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - goto exit; - } - - if (exit_code == SPAM_ASSASSIN_EXIT_STATUS_SUCCESS) { - /* Wait for the socket path to appear. */ - for (ii = 0; ii < DAEMON_MAX_RETRIES; ii++) { - if (g_file_test (socket_path, G_FILE_TEST_EXISTS)) { - started = TRUE; - break; - } - g_usleep (DAEMON_RETRY_DELAY * G_USEC_PER_SEC); - } - } - - /* Set these directly to avoid emitting "notify" signals. */ - if (started) { - g_free (extension->pid_file); - extension->pid_file = pid_file; - pid_file = NULL; - - g_free (extension->socket_path); - extension->socket_path = socket_path; - socket_path = NULL; - - /* XXX EMailSession is too prone to reference leaks to leave - * this for our finalize() method. We want to be sure to - * kill the spamd process we started when Evolution shuts - * down, so connect to an EShell signal instead. */ - g_signal_connect ( - e_shell_get_default (), "prepare-for-quit", - G_CALLBACK (spam_assassin_prepare_for_quit), - extension); - } - -exit: - g_free (pid_file); - g_free (socket_path); - - g_mutex_unlock (&extension->socket_path_mutex); - - return started; -} - -static void -spam_assassin_test_spamd (ESpamAssassin *extension) -{ - gboolean try_system_spamd = TRUE; - - /* XXX SpamAssassin could really benefit from a D-Bus interface - * these days. These tests are just needlessly painful for - * clients trying to talk to an already-running spamd. */ - - extension->use_spamc = FALSE; - - if (extension->local_only && try_system_spamd) { - gint exit_code; - - /* Run a shell command to check for a running - * spamd process with a -L/--local option or a - * -p/--port option. */ - - const gchar *argv[] = { - "/bin/sh", - "-c", - "ps ax | grep -v grep | " - "grep -E 'spamd.*(\\-L|\\-\\-local)' | " - "grep -E -v '\\ \\-p\\ |\\ \\-\\-port\\ '", - NULL - }; - - exit_code = spam_assassin_command ( - argv, NULL, NULL, NULL, NULL); - try_system_spamd = (exit_code == 0); - } - - /* Try to use the system spamd first. */ - if (try_system_spamd) { - if (spam_assassin_test_spamd_running (extension, TRUE)) { - extension->use_spamc = TRUE; - extension->system_spamd_available = TRUE; - } - } - - /* If there's no system spamd running, try - * to use one with a user specified socket. */ - if (!extension->use_spamc && extension->socket_path != NULL) { - if (spam_assassin_test_spamd_running (extension, FALSE)) { - extension->use_spamc = TRUE; - extension->system_spamd_available = FALSE; - } - } - - /* Still unsuccessful? Try to start our own spamd. */ - if (!extension->use_spamc) { - extension->use_spamc = - spam_assassin_start_our_own_daemon (extension) && - spam_assassin_test_spamd_running (extension, FALSE); - } -} - -static gpointer -spam_assassin_test_spamd_once (gpointer user_data) -{ - ESpamAssassin *extension = E_SPAM_ASSASSIN (user_data); - - spam_assassin_test_spamd (extension); - spam_assassin_test_spamd_allow_tell (extension); - - return NULL; -} -#endif /* HAVE_SPAM_DAEMON */ - static void spam_assassin_set_property (GObject *object, guint property_id, @@ -673,18 +320,6 @@ spam_assassin_set_property (GObject *object, E_SPAM_ASSASSIN (object), g_value_get_boolean (value)); return; - - case PROP_SOCKET_PATH: - spam_assassin_set_socket_path ( - E_SPAM_ASSASSIN (object), - g_value_get_string (value)); - return; - - case PROP_USE_DAEMON: - spam_assassin_set_use_daemon ( - E_SPAM_ASSASSIN (object), - g_value_get_boolean (value)); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -702,37 +337,11 @@ spam_assassin_get_property (GObject *object, value, spam_assassin_get_local_only ( E_SPAM_ASSASSIN (object))); return; - - case PROP_SOCKET_PATH: - g_value_set_string ( - value, spam_assassin_get_socket_path ( - E_SPAM_ASSASSIN (object))); - return; - - case PROP_USE_DAEMON: - g_value_set_boolean ( - value, spam_assassin_get_use_daemon ( - E_SPAM_ASSASSIN (object))); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } -static void -spam_assassin_finalize (GObject *object) -{ - ESpamAssassin *extension = E_SPAM_ASSASSIN (object); - - g_mutex_clear (&extension->socket_path_mutex); - - g_free (extension->pid_file); - g_free (extension->socket_path); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_spam_assassin_parent_class)->finalize (object); -} - static GtkWidget * spam_assassin_new_config_widget (EMailJunkFilter *junk_filter) { @@ -797,34 +406,13 @@ spam_assassin_classify (CamelJunkFilter *junk_filter, gint exit_code; gint ii = 0; -#ifdef HAVE_SPAM_DAEMON - if (extension->use_daemon) - g_once ( - &extension->spamd_testing, - spam_assassin_test_spamd_once, - extension); -#endif /* HAVE_SPAM_DAEMON */ - if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; - g_mutex_lock (&extension->socket_path_mutex); - - if (extension->use_spamc) { - g_assert (SPAMC_COMMAND != NULL); - argv[ii++] = SPAMC_COMMAND; - argv[ii++] = "--check"; - argv[ii++] = "--timeout=60"; - if (!extension->system_spamd_available) { - argv[ii++] = "--socket"; - argv[ii++] = extension->socket_path; - } - } else { - argv[ii++] = SPAMASSASSIN_COMMAND; - argv[ii++] = "--exit-code"; - if (extension->local_only) - argv[ii++] = "--local"; - } + argv[ii++] = SPAMASSASSIN_COMMAND; + argv[ii++] = "--exit-code"; + if (extension->local_only) + argv[ii++] = "--local"; argv[ii] = NULL; g_assert (ii < G_N_ELEMENTS (argv)); @@ -836,22 +424,13 @@ spam_assassin_classify (CamelJunkFilter *junk_filter, if (exit_code == SPAM_ASSASSIN_EXIT_STATUS_ERROR) status = CAMEL_JUNK_STATUS_ERROR; - /* For either program, exit code 0 means the message is ham. */ + /* Zero exit code means the message is ham. */ else if (exit_code == 0) status = CAMEL_JUNK_STATUS_MESSAGE_IS_NOT_JUNK; - /* spamassassin(1) only specifies zero and non-zero exit codes. */ - else if (!extension->use_spamc) - status = CAMEL_JUNK_STATUS_MESSAGE_IS_JUNK; - - /* Whereas spamc(1) explicitly states exit code 1 means spam. */ - else if (exit_code == 1) - status = CAMEL_JUNK_STATUS_MESSAGE_IS_JUNK; - - /* Consider any other spamc(1) exit code to be inconclusive - * since it most likely failed to process the message. */ + /* Non-zero exit code means the message is spam. */ else - status = CAMEL_JUNK_STATUS_INCONCLUSIVE; + status = CAMEL_JUNK_STATUS_MESSAGE_IS_JUNK; /* Check that the return value and GError agree. */ if (status != CAMEL_JUNK_STATUS_ERROR) @@ -859,8 +438,6 @@ spam_assassin_classify (CamelJunkFilter *junk_filter, else g_warn_if_fail (error == NULL || *error != NULL); - g_mutex_unlock (&extension->socket_path_mutex); - return status; } @@ -875,31 +452,14 @@ spam_assassin_learn_junk (CamelJunkFilter *junk_filter, gint exit_code; gint ii = 0; -#ifdef HAVE_SPAM_DAEMON - if (extension->use_daemon) - g_once ( - &extension->spamd_testing, - spam_assassin_test_spamd_once, - extension); -#endif /* HAVE_SPAM_DAEMON */ - if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; - if (extension->spamd_using_allow_tell) { - g_assert (SPAMC_COMMAND != NULL); - argv[ii++] = SPAMC_COMMAND; - argv[ii++] = "--learntype=spam"; - } else { - argv[ii++] = SA_LEARN_COMMAND; - argv[ii++] = "--spam"; - if (extension->version >= 3) - argv[ii++] = "--no-sync"; - else - argv[ii++] = "--no-rebuild"; - if (extension->local_only) - argv[ii++] = "--local"; - } + argv[ii++] = SA_LEARN_COMMAND; + argv[ii++] = "--spam"; + argv[ii++] = "--no-sync"; + if (extension->local_only) + argv[ii++] = "--local"; argv[ii] = NULL; g_assert (ii < G_N_ELEMENTS (argv)); @@ -927,31 +487,14 @@ spam_assassin_learn_not_junk (CamelJunkFilter *junk_filter, gint exit_code; gint ii = 0; -#ifdef HAVE_SPAM_DAEMON - if (extension->use_daemon) - g_once ( - &extension->spamd_testing, - spam_assassin_test_spamd_once, - extension); -#endif /* HAVE_SPAM_DAEMON */ - if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; - if (extension->spamd_using_allow_tell) { - g_assert (SPAMC_COMMAND != NULL); - argv[ii++] = SPAMC_COMMAND; - argv[ii++] = "--learntype=ham"; - } else { - argv[ii++] = SA_LEARN_COMMAND; - argv[ii++] = "--ham"; - if (extension->version >= 3) - argv[ii++] = "--no-sync"; - else - argv[ii++] = "--no-rebuild"; - if (extension->local_only) - argv[ii++] = "--local"; - } + argv[ii++] = SA_LEARN_COMMAND; + argv[ii++] = "--ham"; + argv[ii++] = "--no-sync"; + if (extension->local_only) + argv[ii++] = "--local"; argv[ii] = NULL; g_assert (ii < G_N_ELEMENTS (argv)); @@ -978,27 +521,11 @@ spam_assassin_synchronize (CamelJunkFilter *junk_filter, gint exit_code; gint ii = 0; -#ifdef HAVE_SPAM_DAEMON - if (extension->use_daemon) - g_once ( - &extension->spamd_testing, - spam_assassin_test_spamd_once, - extension); -#endif /* HAVE_SPAM_DAEMON */ - if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; - /* If we're using a spamd that allows learning, - * there's no need to synchronize anything. */ - if (extension->spamd_using_allow_tell) - return TRUE; - argv[ii++] = SA_LEARN_COMMAND; - if (extension->version >= 3) - argv[ii++] = "--sync"; - else - argv[ii++] = "--rebuild"; + argv[ii++] = "--sync"; if (extension->local_only) argv[ii++] = "--local"; argv[ii] = NULL; @@ -1026,7 +553,6 @@ e_spam_assassin_class_init (ESpamAssassinClass *class) object_class = G_OBJECT_CLASS (class); object_class->set_property = spam_assassin_set_property; object_class->get_property = spam_assassin_get_property; - object_class->finalize = spam_assassin_finalize; junk_filter_class = E_MAIL_JUNK_FILTER_CLASS (class); junk_filter_class->filter_name = "SpamAssassin"; @@ -1042,26 +568,6 @@ e_spam_assassin_class_init (ESpamAssassinClass *class) "Do not use tests requiring DNS lookups", TRUE, G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SOCKET_PATH, - g_param_spec_string ( - "socket-path", - "Socket Path", - "Socket path for a SpamAssassin daemon", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_USE_DAEMON, - g_param_spec_boolean ( - "use-daemon", - "Use Daemon", - "Whether to use a SpamAssassin daemon", - FALSE, - G_PARAM_READWRITE)); } static void @@ -1083,24 +589,12 @@ e_spam_assassin_init (ESpamAssassin *extension) { GSettings *settings; - g_mutex_init (&extension->socket_path_mutex); - settings = g_settings_new ("org.gnome.evolution.spamassassin"); g_settings_bind ( settings, "local-only", extension, "local-only", G_SETTINGS_BIND_DEFAULT); - g_settings_bind ( - settings, "socket-path", - extension, "socket-path", - G_SETTINGS_BIND_DEFAULT); -#ifdef HAVE_SPAM_DAEMON - g_settings_bind ( - settings, "use-daemon", - extension, "use-daemon", - G_SETTINGS_BIND_DEFAULT); -#endif /* HAVE_SPAM_DAEMON */ g_object_unref (settings); } |