From 579bed3772e6fdc3183b9460e542e133f07fb3d9 Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Sun, 27 Aug 2006 09:44:59 +0000 Subject: [PATCH] 2006-08-27 [colin] 2.4.0cvs96 * configure.ac * src/plugins/Makefile.am * src/plugins/bogofilter/.cvsignore * src/plugins/bogofilter/Makefile.am * src/plugins/bogofilter/bogofilter.c * src/plugins/bogofilter/bogofilter.h * src/plugins/bogofilter/bogofilter_gtk.c New Bogofilter plugin, provides filtering and learning. Spamassassin will go to extra plugins. --- ChangeLog | 12 + PATCHSETS | 1 + configure.ac | 17 +- src/plugins/Makefile.am | 5 + src/plugins/bogofilter/.cvsignore | 8 + src/plugins/bogofilter/Makefile.am | 33 +++ src/plugins/bogofilter/bogofilter.c | 365 ++++++++++++++++++++++++ src/plugins/bogofilter/bogofilter.h | 45 +++ src/plugins/bogofilter/bogofilter_gtk.c | 257 +++++++++++++++++ 9 files changed, 742 insertions(+), 1 deletion(-) create mode 100644 src/plugins/bogofilter/.cvsignore create mode 100644 src/plugins/bogofilter/Makefile.am create mode 100644 src/plugins/bogofilter/bogofilter.c create mode 100644 src/plugins/bogofilter/bogofilter.h create mode 100644 src/plugins/bogofilter/bogofilter_gtk.c diff --git a/ChangeLog b/ChangeLog index 2e1e4640c..41de3b50c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-08-27 [colin] 2.4.0cvs96 + + * configure.ac + * src/plugins/Makefile.am + * src/plugins/bogofilter/.cvsignore + * src/plugins/bogofilter/Makefile.am + * src/plugins/bogofilter/bogofilter.c + * src/plugins/bogofilter/bogofilter.h + * src/plugins/bogofilter/bogofilter_gtk.c + New Bogofilter plugin, provides filtering and + learning. Spamassassin will go to extra plugins. + 2006-08-26 [mones] 2.4.0cvs95 * manual/handling.xml diff --git a/PATCHSETS b/PATCHSETS index e8a143f0e..d69f5c88a 100644 --- a/PATCHSETS +++ b/PATCHSETS @@ -1787,3 +1787,4 @@ ( cvs diff -u -r 1.15.2.30 -r 1.15.2.31 src/summary_search.c; ) > 2.4.0cvs93.patchset ( cvs diff -u -r 1.1.2.12 -r 1.1.2.13 manual/glossary.xml; cvs diff -u -r 1.1.2.9 -r 1.1.2.10 manual/handling.xml; cvs diff -u -r 1.1.2.13 -r 1.1.2.14 manual/plugins.xml; cvs diff -u -r 1.1.2.7 -r 1.1.2.8 manual/starting.xml; ) > 2.4.0cvs94.patchset ( cvs diff -u -r 1.1.2.10 -r 1.1.2.11 manual/handling.xml; ) > 2.4.0cvs95.patchset +( cvs diff -u -r 1.654.2.1834 -r 1.654.2.1835 configure.ac; cvs diff -u -r 1.8.2.5 -r 1.8.2.6 src/plugins/Makefile.am; diff -u /dev/null src/plugins/bogofilter/.cvsignore; diff -u /dev/null src/plugins/bogofilter/Makefile.am; diff -u /dev/null src/plugins/bogofilter/bogofilter.c; diff -u /dev/null src/plugins/bogofilter/bogofilter.h; diff -u /dev/null src/plugins/bogofilter/bogofilter_gtk.c; ) > 2.4.0cvs96.patchset diff --git a/configure.ac b/configure.ac index 741e1379f..cadce5a05 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ MINOR_VERSION=4 MICRO_VERSION=0 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=95 +EXTRA_VERSION=96 EXTRA_RELEASE= EXTRA_GTK2_VERSION= @@ -643,6 +643,20 @@ else fi AM_CONDITIONAL(BUILD_SPAMASSASSIN_PLUGIN, test x"$ac_cv_enable_spamassassin_plugin" = xyes) +dnl --- Bogofilter --- +AC_MSG_CHECKING([whether to build Bogofilter plugin]) +AC_ARG_ENABLE(bogofilter-plugin, + [ --disable-bogofilter-plugin Build bogofilter plugin [default=yes]], + [ac_cv_enable_bogofilter_plugin=$enableval], [ac_cv_enable_bogofilter_plugin=yes]) +if test x"$ac_cv_enable_bogofilter_plugin" = xyes; then + AC_MSG_RESULT(yes) + PLUGINS="bogofilter $PLUGINS" + AC_DEFINE(USE_BOGOFILTER_PLUGIN, 1, Define if bogofilter plugin is being build.) +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(BUILD_BOGOFILTER_PLUGIN, test x"$ac_cv_enable_bogofilter_plugin" = xyes) + dnl --- PGP/CORE --- AC_MSG_CHECKING([whether to build PGP/CORE plugin]) AC_ARG_ENABLE(pgpcore-plugin, @@ -824,6 +838,7 @@ src/gtk/Makefile src/etpan/Makefile src/plugins/Makefile src/plugins/demo/Makefile +src/plugins/bogofilter/Makefile src/plugins/spamassassin/Makefile src/plugins/dillo_viewer/Makefile src/plugins/trayicon/Makefile diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 1fb853f4b..bf62e5e59 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -6,6 +6,10 @@ if BUILD_SPAMASSASSIN_PLUGIN spamassasssin_dir = spamassassin endif +if BUILD_BOGOFILTER_PLUGIN +bogofilter_dir = bogofilter +endif + if BUILD_DILLO_VIEWER_PLUGIN dillo_viewer_dir = dillo_viewer endif @@ -30,6 +34,7 @@ endif SUBDIRS = $(demo_dir) \ $(spamassasssin_dir) \ + $(bogofilter_dir) \ $(dillo_viewer_dir) \ $(trayicon_dir) \ $(clamav_dir) \ diff --git a/src/plugins/bogofilter/.cvsignore b/src/plugins/bogofilter/.cvsignore new file mode 100644 index 000000000..5cb43f408 --- /dev/null +++ b/src/plugins/bogofilter/.cvsignore @@ -0,0 +1,8 @@ +.deps +.libs +Makefile +Makefile.in +*.o +*.lo +*.la +*.loT diff --git a/src/plugins/bogofilter/Makefile.am b/src/plugins/bogofilter/Makefile.am new file mode 100644 index 000000000..dcee87d70 --- /dev/null +++ b/src/plugins/bogofilter/Makefile.am @@ -0,0 +1,33 @@ +plugindir = $(pkglibdir)/plugins + +plugin_LTLIBRARIES = bogofilter.la + +bogofilter_la_SOURCES = \ + bogofilter.c bogofilter.h \ + bogofilter_gtk.c + +bogofilter_la_LDFLAGS = \ + -avoid-version -module -no-undefined + +if CYGWIN +cygwin_export_lib = -L$(top_builddir)/src -lsylpheed-claws +else +cygwin_export_lib = +endif +bogofilter_la_LIBADD = $(cygwin_export_lib) \ + $(GTK_LIBS) \ + $(OPENSSL_LIBS) + +INCLUDES = \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/common \ + -I$(top_srcdir)/src/gtk + +AM_CPPFLAGS = \ + $(ASPELL_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GTK_CFLAGS) \ + $(OPENSSL_CFLAGS) + +EXTRA_DIST = \ + README diff --git a/src/plugins/bogofilter/bogofilter.c b/src/plugins/bogofilter/bogofilter.c new file mode 100644 index 000000000..5f8eff2db --- /dev/null +++ b/src/plugins/bogofilter/bogofilter.c @@ -0,0 +1,365 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include + +#include +#include + +#if HAVE_LOCALE_H +# include +#endif + +#include "common/sylpheed.h" +#include "common/version.h" +#include "plugin.h" +#include "common/utils.h" +#include "hooks.h" +#include "procmsg.h" +#include "folder.h" +#include "prefs.h" +#include "prefs_gtk.h" + +#include "bogofilter.h" +#include "inc.h" +#include "log.h" +#include "prefs_common.h" +#include "alertpanel.h" + +#ifdef HAVE_SYSEXITS_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SYS_ERRNO_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SIGNAL_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif + +enum { + CHILD_RUNNING = 1 << 0, + TIMEOUT_RUNNING = 1 << 1, +}; + +static guint hook_id = -1; +static MessageCallback message_callback; + +static BogofilterConfig config; + +static PrefParam param[] = { + {"process_emails", "TRUE", &config.process_emails, P_BOOL, + NULL, NULL, NULL}, + {"receive_spam", "TRUE", &config.receive_spam, P_BOOL, + NULL, NULL, NULL}, + {"save_folder", NULL, &config.save_folder, P_STRING, + NULL, NULL, NULL}, + {"max_size", "250", &config.max_size, P_INT, + NULL, NULL, NULL}, + + {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL} +}; + +static gboolean mail_filtering_hook(gpointer source, gpointer data) +{ + MailFilteringData *mail_filtering_data = (MailFilteringData *) source; + MsgInfo *msginfo = mail_filtering_data->msginfo; + gboolean is_spam = FALSE; + static gboolean warned_error = FALSE; + gchar *file = NULL, *cmd = NULL; + int status = 3; + + if (!config.process_emails) { + return FALSE; + } + debug_print("Filtering message %d\n", msginfo->msgnum); + if (message_callback != NULL) + message_callback(_("Bogofilter: filtering message..."), 0, 0); + + file = procmsg_get_message_file(msginfo); + + if (file) + cmd = g_strdup_printf("bogofilter -I %s", file); + + if (cmd) + status = system(cmd); + + if (status == -1) + status = 3; + else + status = WEXITSTATUS(status); + + g_free(cmd); + g_free(file); + printf("bogofilter status %d\n", status); + is_spam = (status == 0); + + if (is_spam) { + debug_print("message is spam\n"); + procmsg_msginfo_set_flags(msginfo, MSG_SPAM, 0); + if (config.receive_spam) { + FolderItem *save_folder; + + if ((!config.save_folder) || + (config.save_folder[0] == '\0') || + ((save_folder = folder_find_item_from_identifier(config.save_folder)) == NULL)) + save_folder = folder_get_default_trash(); + + procmsg_msginfo_unset_flags(msginfo, ~0, 0); + procmsg_msginfo_set_flags(msginfo, MSG_SPAM, 0); + folder_item_move_msg(save_folder, msginfo); + } else { + folder_item_remove_msg(msginfo->folder, msginfo->msgnum); + } + + return TRUE; + } else { + debug_print("message is ham\n"); + procmsg_msginfo_unset_flags(msginfo, MSG_SPAM, 0); + } + + if (status == 3) { /* I/O or other errors */ + if (!warned_error) { + alertpanel_error(_("The Bogofilter plugin couldn't filter " + "a message. The probable error cause is " + "that it didn't learn from any mail.\n" + "Use \"Mark/As Spam(Ham)\" from messages' " + "contextual menu to train Bogofilter with " + "a few hundreds spam and ham messages.")); + } + warned_error = TRUE; + } + + return FALSE; +} + +BogofilterConfig *bogofilter_get_config(void) +{ + return &config; +} + +int bogofilter_learn(MsgInfo *msginfo, GSList *msglist, gboolean spam) +{ + gchar *cmd = NULL; + gchar *file = NULL; + + if (msginfo == NULL && msglist == NULL) { + return -1; + } + + if (msginfo) { + file = procmsg_get_message_file(msginfo); + if (file == NULL) { + return -1; + } else { + if (message_callback != NULL) + message_callback(_("Bogofilter: learning from message..."), 0, 0); + cmd = g_strdup_printf("bogofilter -%c -I %s", + spam ? 's':'n', file); + execute_command_line(cmd, FALSE); + g_free(cmd); + g_free(file); + if (message_callback != NULL) + message_callback(NULL, 0, 0); + return 0; + } + } + if (msglist) { + GSList *cur = msglist; + MsgInfo *info; + int total = g_slist_length(msglist); + int done = 0; + if (message_callback != NULL) + message_callback(_("Bogofilter: learning from messages..."), total, 0); + + for (; cur; cur = cur->next) { + info = (MsgInfo *)cur->data; + file = procmsg_get_message_file(info); + + cmd = g_strdup_printf("bogofilter -%c -I %s", + spam ? 's':'n', file); + execute_command_line(cmd, FALSE); + g_free(cmd); + g_free(file); + done++; + if (message_callback != NULL) + message_callback(NULL, total, done); + } + if (message_callback != NULL) + message_callback(NULL, 0, 0); + return 0; + } + return -1; +} + +void bogofilter_save_config(void) +{ + PrefFile *pfile; + gchar *rcpath; + + debug_print("Saving Bogofilter Page\n"); + + rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL); + pfile = prefs_write_open(rcpath); + g_free(rcpath); + if (!pfile || (prefs_set_block_label(pfile, "Bogofilter") < 0)) + return; + + if (prefs_write_param(param, pfile->fp) < 0) { + g_warning("Failed to write Bogofilter configuration to file\n"); + prefs_file_close_revert(pfile); + return; + } + fprintf(pfile->fp, "\n"); + + prefs_file_close(pfile); +} + +void bogofilter_set_message_callback(MessageCallback callback) +{ + message_callback = callback; +} + +gint plugin_init(gchar **error) +{ + gchar *rcpath; + + hook_id = -1; + + if ((sylpheed_get_version() > VERSION_NUMERIC)) { + *error = g_strdup("Your version of Sylpheed-Claws is newer than the version the Bogofilter plugin was built with"); + return -1; + } + + if ((sylpheed_get_version() < MAKE_NUMERIC_VERSION(0, 9, 3, 86))) { + *error = g_strdup("Your version of Sylpheed-Claws is too old for the Bogofilter plugin"); + return -1; + } + + prefs_set_default(param); + rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL); + prefs_read_config(param, "Bogofilter", rcpath, NULL); + g_free(rcpath); + + bogofilter_gtk_init(); + + debug_print("Bogofilter plugin loaded\n"); + + if (config.process_emails) { + bogofilter_register_hook(); + } + + procmsg_register_spam_learner(bogofilter_learn); + procmsg_spam_set_folder(config.save_folder); + + return 0; + +} + +void plugin_done(void) +{ + if (hook_id != -1) { + bogofilter_unregister_hook(); + } + g_free(config.save_folder); + bogofilter_gtk_done(); + procmsg_unregister_spam_learner(bogofilter_learn); + procmsg_spam_set_folder(NULL); + debug_print("Bogofilter plugin unloaded\n"); +} + +const gchar *plugin_name(void) +{ + return _("Bogofilter"); +} + +const gchar *plugin_desc(void) +{ + return _("This plugin can check all messages that are received from an " + "IMAP, LOCAL or POP account for spam using a Bogofilter " + "server. You will need Bogofilter installed locally.\n " + "\n" + "Before Bogofilter can recognize spam messages, you have to " + "train it by marking a few hundreds spam and ham messages. " + "Use \"Mark/As Spam(Ham)\" from messages' contextual menu " + "to train Bogofilter.\n" + "\n" + "When a message is identified as spam it can be deleted or " + "saved in a specially designated folder.\n" + "\n" + "Options can be found in /Configuration/Preferences/Plugins/Bogofilter"); +} + +const gchar *plugin_type(void) +{ + return "GTK2"; +} + +const gchar *plugin_licence(void) +{ + return "GPL"; +} + +const gchar *plugin_version(void) +{ + return VERSION; +} + +struct PluginFeature *plugin_provides(void) +{ + static struct PluginFeature features[] = + { {PLUGIN_FILTERING, N_("Spam detection")}, + {PLUGIN_FILTERING, N_("Spam learning")}, + {PLUGIN_NOTHING, NULL}}; + return features; +} + +void bogofilter_register_hook(void) +{ + hook_id = hooks_register_hook(MAIL_FILTERING_HOOKLIST, mail_filtering_hook, NULL); + if (hook_id == -1) { + g_warning("Failed to register mail filtering hook"); + config.process_emails = FALSE; + } +} + +void bogofilter_unregister_hook(void) +{ + if (hook_id != -1) { + hooks_unregister_hook(MAIL_FILTERING_HOOKLIST, hook_id); + } +} diff --git a/src/plugins/bogofilter/bogofilter.h b/src/plugins/bogofilter/bogofilter.h new file mode 100644 index 000000000..588b33776 --- /dev/null +++ b/src/plugins/bogofilter/bogofilter.h @@ -0,0 +1,45 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BOGOFILTER_H +#define BOGOFILTER_H 1 + +#include + +typedef struct _BogofilterConfig BogofilterConfig; + +typedef void (*MessageCallback) (gchar *, gint total, gint done); + +struct _BogofilterConfig +{ + gboolean process_emails; + gboolean receive_spam; + gchar *save_folder; + guint max_size; +}; + +BogofilterConfig *bogofilter_get_config (void); +void bogofilter_save_config (void); +void bogofilter_set_message_callback (MessageCallback callback); +gint bogofilter_gtk_init(void); +void bogofilter_gtk_done(void); +int bogofilter_learn(MsgInfo *msginfo, GSList *msglist, gboolean spam); +void bogofilter_register_hook(void); +void bogofilter_unregister_hook(void); +#endif diff --git a/src/plugins/bogofilter/bogofilter_gtk.c b/src/plugins/bogofilter/bogofilter_gtk.c new file mode 100644 index 000000000..e7b05c2fa --- /dev/null +++ b/src/plugins/bogofilter/bogofilter_gtk.c @@ -0,0 +1,257 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws Team + * This file Copyright (C) 2006 Colin Leroy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include +#include +#include +#include + +#include "common/sylpheed.h" +#include "common/version.h" +#include "plugin.h" +#include "common/utils.h" +#include "prefs.h" +#include "folder.h" +#include "prefs_gtk.h" +#include "foldersel.h" +#include "statusbar.h" +#include "bogofilter.h" +#include "menu.h" + +struct BogofilterPage +{ + PrefsPage page; + + GtkWidget *process_emails; + GtkWidget *receive_spam; + GtkWidget *save_folder; + GtkWidget *save_folder_select; + GtkWidget *max_size; +}; + +static void foldersel_cb(GtkWidget *widget, gpointer data) +{ + struct BogofilterPage *page = (struct BogofilterPage *) data; + FolderItem *item; + gchar *item_id; + gint newpos = 0; + + item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL); + if (item && (item_id = folder_item_get_identifier(item)) != NULL) { + gtk_editable_delete_text(GTK_EDITABLE(page->save_folder), 0, -1); + gtk_editable_insert_text(GTK_EDITABLE(page->save_folder), item_id, strlen(item_id), &newpos); + g_free(item_id); + } +} + +static void bogofilter_create_widget_func(PrefsPage * _page, + GtkWindow * window, + gpointer data) +{ + struct BogofilterPage *page = (struct BogofilterPage *) _page; + BogofilterConfig *config; + + GtkWidget *vbox1, *vbox2; + GtkWidget *hbox_max_size; + GtkWidget *hbox_process_emails, *hbox_save_spam; + + GtkWidget *max_size_label; + GtkObject *max_size_spinbtn_adj; + GtkWidget *max_size_spinbtn; + GtkWidget *max_size_kb_label; + + GtkWidget *process_emails_checkbtn; + + GtkWidget *save_spam_checkbtn; + GtkWidget *save_spam_folder_entry; + GtkWidget *save_spam_folder_select; + + GtkTooltips *tooltips; + + tooltips = gtk_tooltips_new(); + + vbox1 = gtk_vbox_new (FALSE, VSPACING); + gtk_widget_show (vbox1); + gtk_container_set_border_width (GTK_CONTAINER (vbox1), VBOX_BORDER); + + vbox2 = gtk_vbox_new (FALSE, 4); + gtk_widget_show (vbox2); + gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, FALSE, 0); + + hbox_process_emails = gtk_hbox_new(FALSE, 8); + gtk_widget_show(hbox_process_emails); + gtk_box_pack_start (GTK_BOX (vbox2), hbox_process_emails, TRUE, TRUE, 0); + + process_emails_checkbtn = gtk_check_button_new_with_label( + _("Process messages on receiving")); + gtk_widget_show(process_emails_checkbtn); + gtk_box_pack_start(GTK_BOX(hbox_process_emails), process_emails_checkbtn, TRUE, TRUE, 0); + + hbox_max_size = gtk_hbox_new(FALSE, 8); + gtk_widget_show(hbox_max_size); + gtk_box_pack_start (GTK_BOX (vbox2), hbox_max_size, TRUE, TRUE, 0); + + max_size_label = gtk_label_new(_("Maximum size")); + gtk_widget_show(max_size_label); + gtk_box_pack_start(GTK_BOX(hbox_max_size), max_size_label, FALSE, FALSE, 0); + + max_size_spinbtn_adj = gtk_adjustment_new(250, 0, 10000, 10, 10, 10); + max_size_spinbtn = gtk_spin_button_new(GTK_ADJUSTMENT(max_size_spinbtn_adj), 1, 0); + gtk_widget_show(max_size_spinbtn); + gtk_box_pack_start(GTK_BOX(hbox_max_size), max_size_spinbtn, FALSE, FALSE, 0); + gtk_tooltips_set_tip(tooltips, max_size_spinbtn, + _("Messages larger than this will not be checked"), NULL); + gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(max_size_spinbtn), TRUE); + + max_size_kb_label = gtk_label_new(_("kB")); + gtk_widget_show(max_size_kb_label); + gtk_box_pack_start(GTK_BOX(hbox_max_size), max_size_kb_label, FALSE, FALSE, 0); + + hbox_save_spam = gtk_hbox_new(FALSE, 8); + gtk_widget_show(hbox_save_spam); + gtk_box_pack_start (GTK_BOX (vbox2), hbox_save_spam, TRUE, TRUE, 0); + + save_spam_checkbtn = gtk_check_button_new_with_label(_("Save spam in")); + gtk_widget_show(save_spam_checkbtn); + gtk_box_pack_start(GTK_BOX(hbox_save_spam), save_spam_checkbtn, FALSE, FALSE, 0); + + save_spam_folder_entry = gtk_entry_new(); + gtk_widget_show (save_spam_folder_entry); + gtk_box_pack_start (GTK_BOX (hbox_save_spam), save_spam_folder_entry, TRUE, TRUE, 0); + gtk_tooltips_set_tip(tooltips, save_spam_folder_entry, + _("Folder for storing identified spam. Leave empty to use the default trash folder"), + NULL); + + save_spam_folder_select = gtkut_get_browse_directory_btn(_("_Browse")); + gtk_widget_show (save_spam_folder_select); + gtk_box_pack_start (GTK_BOX (hbox_save_spam), save_spam_folder_select, FALSE, FALSE, 0); + gtk_tooltips_set_tip(tooltips, save_spam_folder_select, + _("Click this button to select a folder for storing spam"), + NULL); + + SET_TOGGLE_SENSITIVITY(save_spam_checkbtn, save_spam_folder_entry); + SET_TOGGLE_SENSITIVITY(save_spam_checkbtn, save_spam_folder_select); + + config = bogofilter_get_config(); + + g_signal_connect(G_OBJECT(save_spam_folder_select), "clicked", + G_CALLBACK(foldersel_cb), page); + + gtk_spin_button_set_value(GTK_SPIN_BUTTON(max_size_spinbtn), (float) config->max_size); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(process_emails_checkbtn), config->process_emails); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(save_spam_checkbtn), config->receive_spam); + if (config->save_folder != NULL) + gtk_entry_set_text(GTK_ENTRY(save_spam_folder_entry), config->save_folder); + + page->max_size = max_size_spinbtn; + page->process_emails = process_emails_checkbtn; + page->receive_spam = save_spam_checkbtn; + page->save_folder = save_spam_folder_entry; + page->save_folder_select = save_spam_folder_select; + + page->page.widget = vbox1; +} + +static void bogofilter_destroy_widget_func(PrefsPage *_page) +{ + debug_print("Destroying Bogofilter widget\n"); +} + +static void bogofilter_save_func(PrefsPage *_page) +{ + struct BogofilterPage *page = (struct BogofilterPage *) _page; + BogofilterConfig *config; + + debug_print("Saving Bogofilter Page\n"); + + config = bogofilter_get_config(); + + /* process_emails */ + config->process_emails = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->process_emails)); + + /* receive_spam */ + config->receive_spam = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->receive_spam)); + + /* save_folder */ + g_free(config->save_folder); + config->save_folder = gtk_editable_get_chars(GTK_EDITABLE(page->save_folder), 0, -1); + + /* max_size */ + config->max_size = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(page->max_size)); + + if (config->process_emails) { + bogofilter_register_hook(); + } else { + bogofilter_unregister_hook(); + } + + procmsg_register_spam_learner(bogofilter_learn); + procmsg_spam_set_folder(config->save_folder); + + bogofilter_save_config(); +} + +static void gtk_message_callback(gchar *message, gint total, gint done) +{ + if (message) + statusbar_print_all(message); + else if (total == 0) { + statusbar_pop_all(); + } + if (total && done) + statusbar_progress_all(done, total, 10); + else + statusbar_progress_all(0,0,0); + GTK_EVENTS_FLUSH(); +} + +static struct BogofilterPage bogofilter_page; + +gint bogofilter_gtk_init(void) +{ + static gchar *path[3]; + + path[0] = _("Plugins"); + path[1] = _("Bogofilter"); + path[2] = NULL; + + bogofilter_page.page.path = path; + bogofilter_page.page.create_widget = bogofilter_create_widget_func; + bogofilter_page.page.destroy_widget = bogofilter_destroy_widget_func; + bogofilter_page.page.save_page = bogofilter_save_func; + bogofilter_page.page.weight = 35.0; + + prefs_gtk_register_page((PrefsPage *) &bogofilter_page); + bogofilter_set_message_callback(gtk_message_callback); + + debug_print("Bogofilter GTK plugin loaded\n"); + return 0; +} + +void bogofilter_gtk_done(void) +{ + prefs_gtk_unregister_page((PrefsPage *) &bogofilter_page); +}