From 161a51e4dfb33d6cb2b445d14930a059a8568590 Mon Sep 17 00:00:00 2001 From: Srinivasa Ragavan Date: Tue, 3 Apr 2007 09:06:19 +0000 Subject: Added bogofilter to Evolution. svn path=/trunk/; revision=33364 --- plugins/bogo-junk-plugin/ChangeLog | 21 ++ plugins/bogo-junk-plugin/Makefile.am | 2 + plugins/bogo-junk-plugin/README | 35 +++ plugins/bogo-junk-plugin/bf-junk-filter.c | 301 +++++++++++++++++++++ .../bogo-junk-plugin.schemas.in.in | 18 ++ .../org-gnome-bogo-junk-plugin.eplug.in | 27 ++ 6 files changed, 404 insertions(+) create mode 100644 plugins/bogo-junk-plugin/ChangeLog create mode 100644 plugins/bogo-junk-plugin/Makefile.am create mode 100644 plugins/bogo-junk-plugin/README create mode 100644 plugins/bogo-junk-plugin/bf-junk-filter.c create mode 100644 plugins/bogo-junk-plugin/bogo-junk-plugin.schemas.in.in create mode 100644 plugins/bogo-junk-plugin/org-gnome-bogo-junk-plugin.eplug.in (limited to 'plugins') diff --git a/plugins/bogo-junk-plugin/ChangeLog b/plugins/bogo-junk-plugin/ChangeLog new file mode 100644 index 0000000000..16f0edce05 --- /dev/null +++ b/plugins/bogo-junk-plugin/ChangeLog @@ -0,0 +1,21 @@ +2007-04-03 Srinivasa Ragavan + + ** Added bogofilter part of Evolution source. + +2006-02-19 Mikhail Zabaluev + +* configure.ac: Switched to evolution-plugin-2.6 for plugin configuration. +Bumped version to 0.2.0. + +* org-altlinux-bf-junk-plugin.eplug.in: Templatized the plugin manifesto, +with plugin install directory substituted. +* configure.ac: Added org-altlinux-bf-junk-plugin.eplug to AC_CONFIG_FILES. +* Makefile.am: Added org-altlinux-bf-junk-plugin.eplug.in to EXTRA_DIST. + +* README: Added bug reference to the initial ham training problem. + +2005-11-22 Mikhail Zabaluev + +* README: Added reference to Spam Trainer. + +* README: Reflect on the fix for bug #313096 that made it to Evolution 2.5.2. diff --git a/plugins/bogo-junk-plugin/Makefile.am b/plugins/bogo-junk-plugin/Makefile.am new file mode 100644 index 0000000000..8364a3a463 --- /dev/null +++ b/plugins/bogo-junk-plugin/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = $(plugins_enabled) +DIST_SUBDIRS = $(all_plugins_base) $(all_plugins_standard) $(all_plugins_experimental) profiler diff --git a/plugins/bogo-junk-plugin/README b/plugins/bogo-junk-plugin/README new file mode 100644 index 0000000000..a14bcf6dda --- /dev/null +++ b/plugins/bogo-junk-plugin/README @@ -0,0 +1,35 @@ +Bogofilter plugin for Evolution + +This plugin implements junk filtering for the Evolution mailer, +provided by the bogofilter utility. Bogofilter (http://www.bogofilter.org) +if a fast and nimble mail filter using a so-called Bayesian technique to +classify junk and non-junk email. + +CAVEATS: + +For Evolution versions before 2.5.2, the definition file for the stock +junk filter plugin, 'org-gnome-sa-junk-plugin.eplug', must be removed +from the plugin directory to avoid conflict with any alternate junk plugin. +Simply disabling the SA plugin in the configuration won't help. +This is due to a flaw in the loading code for this hook type +(see GNOME bug #313096). + +To be able to classify emails as spam, bogofilter needs to have some +messages in its ham (non-spam) wordlist. This presents something of a +chicken-and-egg problem for Evolution, because it can feed messages +to the junk filter for learning as non-junk only after these messages have been +classified as junk and moved into a junk folder (GNOME bug #322105). +Thus, if you haven't got a pre-existing bogofilter database, you may need +to feed it some messages known to be non-junk, using its +command line utility: + +bogofilter -n < saved-ham-message + +Alternatively, you may use Spam Trainer, which is a GUI tool that supports +drag-and-drop from Evolution: + +http://spamtrainer.sourceforge.net/ + +Set it up to use bogofilter commands for training: + Ham command: bogofilter -n < %f + Spam command: bogofilter -s < %f diff --git a/plugins/bogo-junk-plugin/bf-junk-filter.c b/plugins/bogo-junk-plugin/bf-junk-filter.c new file mode 100644 index 0000000000..0369ec5500 --- /dev/null +++ b/plugins/bogo-junk-plugin/bf-junk-filter.c @@ -0,0 +1,301 @@ +/* + * Copyright 2005 Mikhail Zabaluev + * + * 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 +#include +#include +#include +#include + +#define G_LOG_DOMAIN "bf-junk-filter" + +#include +#include +#include +#include +#include "mail/em-config.h" +#include +#include +#include +#include +#include + + +#ifndef BOGOFILTER_BINARY +#define BOGOFILTER_BINARY "/usr/bin/bogofilter" +#endif + +#define BOGOFILTER_ERROR 3 + +#define EM_JUNK_BF_GCONF_DIR "/apps/evolution/mail/junk/bogofilter" + + +#define d(x) (camel_debug("junk")?(x):0) + + +static gchar em_junk_bf_binary[] = BOGOFILTER_BINARY; + +static const gchar em_junk_bf_gconf_dir[] = EM_JUNK_BF_GCONF_DIR; +GtkWidget * org_gnome_bogo_convert_unicode (struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data); + +#define EM_JUNK_BF_GCONF_DIR_LENGTH (G_N_ELEMENTS (em_junk_bf_gconf_dir) - 1) + + +static gboolean em_junk_bf_unicode = TRUE; + + +static gint +pipe_to_bogofilter (CamelMimeMessage *msg, gchar **argv) +{ + GPid child_pid; + gint bf_in; + CamelStream *stream; + GError *err = NULL; + gint status; + gint waitres; + + if (camel_debug_start ("junk")) { + int i; + + printf ("pipe_to_bogofilter "); + for (i = 0; argv[i]; i++) + printf ("%s ", argv[i]); + printf ("\n"); + camel_debug_end (); + } + + if (!g_spawn_async_with_pipes (NULL, + argv, + NULL, + G_SPAWN_DO_NOT_REAP_CHILD | + G_SPAWN_STDOUT_TO_DEV_NULL, + NULL, + NULL, + &child_pid, + &bf_in, + NULL, + NULL, + &err)) + { + g_warning ("error occurred while spawning %s: %s", + argv[0], + err->message); + return BOGOFILTER_ERROR; + } + + stream = camel_stream_fs_new_with_fd (bf_in); + camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (msg), stream); + camel_stream_flush (stream); + camel_stream_close (stream); + camel_object_unref (stream); + + waitres = waitpid (child_pid, &status, 0); + if (waitres < 0 && errno == EINTR) { + /* child process is hanging... */ + g_warning ("wait for bogofilter child process interrupted, terminating"); + kill (child_pid, SIGTERM); + sleep (1); + waitres = waitpid (child_pid, &status, WNOHANG); + if (waitres == 0) { + /* ...still hanging, set phasers to KILL */ + g_warning ("bogofilter child process does not respond, killing"); + kill (child_pid, SIGKILL); + sleep (1); + waitres = waitpid (child_pid, &status, WNOHANG); + } + } + + g_spawn_close_pid (child_pid); + + if (waitres >= 0 && WIFEXITED (status)) { + return WEXITSTATUS (status); + } else { + return BOGOFILTER_ERROR; + } +} + +static void +em_junk_bf_setting_notify (GConfClient *gconf, + guint cnxn_id, + GConfEntry *entry, + void *data) +{ + const char *key; + GConfValue *value; + + value = gconf_entry_get_value (entry); + if (value == NULL) { + return; + } + + key = gconf_entry_get_key (entry); + g_return_if_fail (key != NULL); + + g_return_if_fail (!strncmp (key, em_junk_bf_gconf_dir, EM_JUNK_BF_GCONF_DIR_LENGTH)); + key += EM_JUNK_BF_GCONF_DIR_LENGTH; + + g_return_if_fail (*key == '/'); + ++key; + + if (strcmp (key, "unicode") == 0) { + em_junk_bf_unicode = gconf_value_get_bool (value); + } +} + +gboolean +em_junk_bf_check_junk (EPlugin *ep, EMJunkHookTarget *target) +{ + CamelMimeMessage *msg = target->m; + int rv; + + gchar *argv[] = { + em_junk_bf_binary, + NULL, + NULL + }; + + d(fprintf (stderr, "em_junk_bf_check_junk\n")); + + if (em_junk_bf_unicode) { + argv[1] = "--unicode=yes"; + } + + rv = pipe_to_bogofilter (msg, argv); + + d(fprintf (stderr, "em_junk_bf_check_junk rv = %d\n", rv)); + + return (rv == 0); +} + +void +em_junk_bf_report_junk (EPlugin *ep, EMJunkHookTarget *target) +{ + CamelMimeMessage *msg = target->m; + + gchar *argv[] = { + em_junk_bf_binary, + "-s", + NULL, + NULL + }; + + d(fprintf (stderr, "em_junk_bf_report_junk\n")); + + if (em_junk_bf_unicode) { + argv[2] = "--unicode=yes"; + } + + pipe_to_bogofilter (msg, argv); +} + +void +em_junk_bf_report_non_junk (EPlugin *ep, EMJunkHookTarget *target) +{ + CamelMimeMessage *msg = target->m; + + gchar *argv[] = { + em_junk_bf_binary, + "-n", + NULL, + NULL + }; + + d(fprintf (stderr, "em_junk_bf_report_non_junk\n")); + + if (em_junk_bf_unicode) { + argv[2] = "--unicode=yes"; + } + + pipe_to_bogofilter (msg, argv); +} + +void +em_junk_bf_commit_reports (EPlugin *ep, EMJunkHookTarget *target) +{ +} + +gboolean +em_junk_bf_validate_binary (EPlugin *ep, EMJunkHookTarget *target) +{ + + return g_file_test (em_junk_bf_binary, G_FILE_TEST_EXISTS); + +} + +int +e_plugin_lib_enable (EPluginLib *ep, int enable) +{ + GConfClient *gconf; + + if (enable != 1) { + return 0; + } + + gconf = gconf_client_get_default(); + + gconf_client_add_dir (gconf, + em_junk_bf_gconf_dir, + GCONF_CLIENT_PRELOAD_ONELEVEL, + NULL); + + gconf_client_notify_add (gconf, + em_junk_bf_gconf_dir, + em_junk_bf_setting_notify, + NULL, NULL, NULL); + + em_junk_bf_unicode = gconf_client_get_bool (gconf, + EM_JUNK_BF_GCONF_DIR "/unicode", NULL); + + g_object_unref (gconf); + + return 0; +} + +static void +convert_unicode_cb (GtkWidget *widget, gpointer data) +{ + + gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + GConfClient *gconf = gconf_client_get_default(); + + gconf_client_set_bool (gconf, data, active, NULL); +} + +GtkWidget * +org_gnome_bogo_convert_unicode (struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data) +{ + GtkWidget *check; + guint i = ((GtkTable *)data->parent)->nrows; + + if (data->old) + return data->old; + + check = gtk_check_button_new_with_mnemonic (_("Convert mail text to _Unicode")); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), em_junk_bf_unicode); + g_signal_connect (GTK_TOGGLE_BUTTON (check), "toggled", G_CALLBACK (convert_unicode_cb), "/apps/evolution/mail/junk/bogofilter/unicode"); + gtk_table_attach((GtkTable *)data->parent, check, 0, 1, i, i+1, 0, 0, 0, 0); + gtk_widget_show (check); + return (GtkWidget *)check; +} + + diff --git a/plugins/bogo-junk-plugin/bogo-junk-plugin.schemas.in.in b/plugins/bogo-junk-plugin/bogo-junk-plugin.schemas.in.in new file mode 100644 index 0000000000..ad4c67c07a --- /dev/null +++ b/plugins/bogo-junk-plugin/bogo-junk-plugin.schemas.in.in @@ -0,0 +1,18 @@ + + + + /schemas/apps/evolution/mail/junk/bogofilter/unicode + /apps/evolution/mail/junk/bogofilter/unicode + bf-eplugin + bool + true + + Convert mail text to Unicode + + Convert message text to Unicode UTF-8 to unify spam/ham tokens + coming from different character sets. + + + + + diff --git a/plugins/bogo-junk-plugin/org-gnome-bogo-junk-plugin.eplug.in b/plugins/bogo-junk-plugin/org-gnome-bogo-junk-plugin.eplug.in new file mode 100644 index 0000000000..3ce26cc0b7 --- /dev/null +++ b/plugins/bogo-junk-plugin/org-gnome-bogo-junk-plugin.eplug.in @@ -0,0 +1,27 @@ + + + + Filters junk messages using Bogofilter. + + + + + + + + + + + + + + + + -- cgit v1.2.3