2006-08-30 [cleroy] 2.4.0cvs114
authorColin Leroy <colin@colino.net>
Wed, 30 Aug 2006 18:29:32 +0000 (18:29 +0000)
committerColin Leroy <colin@colino.net>
Wed, 30 Aug 2006 18:29:32 +0000 (18:29 +0000)
* src/procmsg.c
* src/procmsg.h
Provide a way to filter a list of
messages in an optimised manner, and
add a list-filtering hook
* src/folder.c
* src/inc.c
* src/mbox.c
Use the list filtering
* src/plugins/bogofilter/bogofilter.c
Use the list-filtering hook
Use -b (bulk) mode for more speed
when learning and filtering
* src/etpan/imap-thread.c
Make log output shorter in UID SEARCH

ChangeLog
PATCHSETS
configure.ac
src/etpan/imap-thread.c
src/folder.c
src/inc.c
src/mbox.c
src/plugins/bogofilter/bogofilter.c
src/procmsg.c
src/procmsg.h

index 895e73a1904f1fb80d7910be9bab106222b9fd56..1c522f28c85b30302e91614c213db96f3a1f478b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2006-08-30 [colin]     2.4.0cvs114
+
+       * src/procmsg.c
+       * src/procmsg.h
+               Provide a way to filter a list of
+               messages in an optimised manner, and
+               add a list-filtering hook
+       * src/folder.c
+       * src/inc.c
+       * src/mbox.c
+               Use the list filtering
+       * src/plugins/bogofilter/bogofilter.c
+               Use the list-filtering hook
+               Use -b (bulk) mode for more speed
+               when learning and filtering
+       * src/etpan/imap-thread.c
+               Make log output shorter in UID SEARCH
+
+
 2006-08-30 [colin]     2.4.0cvs113
 
        * src/plugins/bogofilter/bogofilter.c
index 0320445d91f097061179bfb616f100cf4dcf3b77..19c59dab04a0133da89c06292e8a76f67b867739 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.207.2.113 -r 1.207.2.114 src/folderview.c;  cvs diff -u -r 1.83.2.82 -r 1.83.2.83 src/mimeview.c;  cvs diff -u -r 1.20.2.14 -r 1.20.2.15 src/mimeview.h;  cvs diff -u -r 1.395.2.236 -r 1.395.2.237 src/summaryview.c;  cvs diff -u -r 1.96.2.141 -r 1.96.2.142 src/textview.c;  cvs diff -u -r 1.5.2.39 -r 1.5.2.40 src/gtk/gtkutils.c;  cvs diff -u -r 1.4.2.24 -r 1.4.2.25 src/gtk/gtkutils.h;  ) > 2.4.0cvs111.patchset
 ( cvs diff -u -r 1.16.2.38 -r 1.16.2.39 src/msgcache.c;  ) > 2.4.0cvs112.patchset
 ( cvs diff -u -r 1.1.2.4 -r 1.1.2.5 src/plugins/bogofilter/bogofilter.c;  ) > 2.4.0cvs113.patchset
+( cvs diff -u -r 1.213.2.111 -r 1.213.2.112 src/folder.c;  cvs diff -u -r 1.149.2.55 -r 1.149.2.56 src/inc.c;  cvs diff -u -r 1.28.2.24 -r 1.28.2.25 src/mbox.c;  cvs diff -u -r 1.150.2.76 -r 1.150.2.77 src/procmsg.c;  cvs diff -u -r 1.60.2.34 -r 1.60.2.35 src/procmsg.h;  cvs diff -u -r 1.1.4.47 -r 1.1.4.48 src/etpan/imap-thread.c;  cvs diff -u -r 1.1.2.5 -r 1.1.2.6 src/plugins/bogofilter/bogofilter.c;  ) > 2.4.0cvs114.patchset
index 3d0d5aee6aba0c1c1f882f105beaa41f6cfb75c9..faf5c88e422f2eed583b9358ca7c0f7620d20207 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=4
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=113
+EXTRA_VERSION=114
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
index 263e0dcbee70be25ead47a26aecc8c22bd63c6f9..8154736415eaed976c88c1a4c4838c9f8cf2a121 100644 (file)
@@ -106,6 +106,43 @@ void imap_logger_fetch(int direction, const char * str, size_t size)
        free(buf);
 }
 
+void imap_logger_uid(int direction, const char * str, size_t size) 
+{
+       gchar *buf;
+       gchar **lines;
+       int i = 0;
+
+       buf = malloc(size+1);
+       memset(buf, 0, size+1);
+       strncpy(buf, str, size);
+       buf[size] = '\0';
+       if (!strncmp(buf, "<<<<<<<", 7) 
+       ||  !strncmp(buf, ">>>>>>>", 7)) {
+               free(buf);
+               return;
+       }
+       while (strstr(buf, "\r"))
+               *strstr(buf, "\r") = ' ';
+       while (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
+               buf[strlen(buf)-1] = '\0';
+
+       lines = g_strsplit(buf, "\n", -1);
+
+       if (direction == 0 && size > 64) {
+               gchar tmp[32];
+               strncpy2(tmp, lines[0], 31);
+               log_print("IMAP4%c %s[... - %zd bytes more]\n", direction?'>':'<', tmp,
+                       size-32);
+       } else {
+               while (lines[i] && *lines[i]) {
+                       log_print("IMAP4%c %s\n", direction?'>':'<', lines[i]);
+                       i++;
+               }
+       }
+       g_strfreev(lines);
+       free(buf);
+}
+
 void imap_logger_append(int direction, const char * str, size_t size) 
 {
        gchar *buf;
@@ -1226,8 +1263,12 @@ static void search_run(struct etpan_thread_op * op)
                result->error = -1;
                result->search_result = NULL;
        } else {
+               mailstream_logger = imap_logger_uid;
+
                r = mailimap_uid_search(param->imap, NULL, key, &search_result);
 
+               mailstream_logger = imap_logger_cmd;
+
                /* free the key (with the imapset) */
                mailimap_search_key_free(key);
 
index cc2e53d65102aed1a2c0899afcf158d0cc21462d..2ff4c77130400eced1d1c34db8d6506632adbab8 100644 (file)
@@ -1934,47 +1934,57 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering)
        folder_item_update_freeze();
        if (newmsg_list != NULL) {
                GSList *elem, *to_filter = NULL;
-               int total = g_slist_length(newmsg_list), cur = 0;
-               
-               if ((filtering == TRUE) &&
-                   (item->stype == F_INBOX) &&
-                   (item->folder->account != NULL) && 
-                   (item->folder->account->filter_on_recv)) 
-                       statusbar_print_all(_("Filtering messages...\n"));
+               gboolean do_filter = (filtering == TRUE) &&
+                                       (item->stype == F_INBOX) &&
+                                       (item->folder->account != NULL) && 
+                                       (item->folder->account->filter_on_recv);
                
                for (elem = newmsg_list; elem != NULL; elem = g_slist_next(elem)) {
                        MsgInfo *msginfo = (MsgInfo *) elem->data;
 
-                       statusbar_progress_all(cur++,total, 10);
-
                        msgcache_add_msg(item->cache, msginfo);
-                       if ((filtering == TRUE) &&
-                           (item->stype == F_INBOX) &&
-                           (item->folder->account != NULL) && 
-                           (item->folder->account->filter_on_recv) &&
-                           procmsg_msginfo_filter(msginfo,  item->folder->account))
-                               to_filter = g_slist_prepend(to_filter, msginfo);
-                       else {
+                       if (!do_filter) {
                                exists_list = g_slist_prepend(exists_list, msginfo);
-                               
+
                                if(prefs_common.thread_by_subject &&
                                        MSG_IS_IGNORE_THREAD(msginfo->flags) &&
                                        !subject_table_lookup(subject_table, msginfo->subject)) {
                                        subject_table_insert(subject_table, msginfo->subject, msginfo);
-                               }
+                               }                       
                        }
                }
-               filtering_move_and_copy_msgs(to_filter);
-               for (elem = to_filter; elem; elem = g_slist_next(elem)) {
-                       MsgInfo *msginfo = (MsgInfo *)elem->data;
-                       procmsg_msginfo_free(msginfo);
-               }
 
-               g_slist_free(to_filter);
+               if (do_filter) {
+                       GSList *unfiltered;
+                       procmsg_msglist_filter(newmsg_list, item->folder->account, 
+                                       &to_filter, &unfiltered, 
+                                       TRUE);
+                       
+                       if (to_filter != NULL) {
+                               filtering_move_and_copy_msgs(to_filter);
+                               for (elem = to_filter; elem; elem = g_slist_next(elem)) {
+                                       MsgInfo *msginfo = (MsgInfo *)elem->data;
+                                       procmsg_msginfo_free(msginfo);
+                               }
+                               g_slist_free(to_filter);
+                       }
+                       if (unfiltered != NULL) {
+                               for (elem = unfiltered; elem; elem = g_slist_next(elem)) {
+                                       MsgInfo *msginfo = (MsgInfo *)elem->data;
+                                       exists_list = g_slist_prepend(exists_list, msginfo);
+
+                                       if(prefs_common.thread_by_subject &&
+                                               MSG_IS_IGNORE_THREAD(msginfo->flags) &&
+                                               !subject_table_lookup(subject_table, msginfo->subject)) {
+                                               subject_table_insert(subject_table, msginfo->subject, msginfo);
+                                       }
+                               }
+                               g_slist_free(unfiltered);
+                       }
+               } 
+
                g_slist_free(newmsg_list);
 
-               statusbar_progress_all(0,0,0);
-               statusbar_pop_all();
                update_flags |= F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_CONTENT;
        }
 
index 7d8162f5e8624d956c5defd534e31b165aaf9027..180959208f90ed5bad5e2ac711ff515b2dcde7e7 100644 (file)
--- a/src/inc.c
+++ b/src/inc.c
@@ -488,7 +488,6 @@ static gint inc_start(IncProgressDialog *inc_dialog)
        gchar *msg;
        gchar *fin_msg;
        FolderItem *processing, *inbox;
-       MsgInfo *msginfo;
        GSList *msglist, *msglist_element;
        gboolean cancelled = FALSE;
 
@@ -542,9 +541,9 @@ static gint inc_start(IncProgressDialog *inc_dialog)
 }
 
        for (; inc_dialog->queue_list != NULL && !cancelled; inc_dialog->cur_row++) {
-               int cur = 1, total = 0;
                session = inc_dialog->queue_list->data;
                pop3_session = POP3_SESSION(session->session);
+               GSList *filtered, *unfiltered;
 
                if (pop3_session->pass == NULL) {
                        SET_PIXMAP_AND_TEXT(okpix, _("Cancelled"));
@@ -630,25 +629,16 @@ static gint inc_start(IncProgressDialog *inc_dialog)
 
                /* process messages */
                folder_item_update_freeze();
-               if (pop3_session->ac_prefs->filter_on_recv)
-                       statusbar_print_all(_("Filtering messages...\n"));
-               total = g_slist_length(msglist);
-
-               for(msglist_element = msglist; msglist_element != NULL; 
-                   msglist_element = msglist_element->next) {
-                       gchar *filename;
-                       msginfo = (MsgInfo *) msglist_element->data;
-                       filename = folder_item_fetch_msg(processing, msginfo->msgnum);
-                       g_free(filename);
+               
+               procmsg_msglist_filter(msglist, pop3_session->ac_prefs, 
+                               &filtered, &unfiltered, 
+                               pop3_session->ac_prefs->filter_on_recv);
 
-                       if (pop3_session->ac_prefs->filter_on_recv)
-                               statusbar_progress_all(cur++,total, prefs_common.statusbar_update_step);
+               if (filtered != NULL)
+                       filtering_move_and_copy_msgs(filtered);
+               if (unfiltered != NULL)
+                       folder_item_move_msgs(inbox, unfiltered);
 
-                       if (!pop3_session->ac_prefs->filter_on_recv || 
-                           !procmsg_msginfo_filter(msginfo, pop3_session->ac_prefs))
-                               folder_item_move_msg(inbox, msginfo);
-               }
-               filtering_move_and_copy_msgs(msglist);
                for(msglist_element = msglist; msglist_element != NULL; 
                    msglist_element = msglist_element->next) {
                        MsgInfo *msginfo = (MsgInfo *)msglist_element->data;
@@ -656,10 +646,9 @@ static gint inc_start(IncProgressDialog *inc_dialog)
                }
                folder_item_update_thaw();
                
-               statusbar_progress_all(0,0,0);
-               statusbar_pop_all();
-
                g_slist_free(msglist);
+               g_slist_free(filtered);
+               g_slist_free(unfiltered);
 
                statusbar_pop_all();
 
index 53de346757778f58a276de747ca919cbeeeb8ebb..a704db11cf626e6e6611b04ee8c021fa1869bfee 100644 (file)
@@ -70,7 +70,7 @@ gint proc_mbox(FolderItem *dest, const gchar *mbox, gboolean apply_filter)
        gint lines;
        MsgInfo *msginfo;
        gboolean more;
-       GSList *to_filter = NULL, *to_drop = NULL, *cur, *to_add = NULL;
+       GSList *to_filter = NULL, *filtered = NULL, *unfiltered = NULL, *cur, *to_add = NULL;
        gboolean printed = FALSE;
        FolderItem *dropfolder;
 
@@ -226,10 +226,7 @@ gint proc_mbox(FolderItem *dest, const gchar *mbox, gboolean apply_filter)
                                return -1;
                        }
                        msginfo = folder_item_get_msginfo(dropfolder, msgnum);
-                       if (!procmsg_msginfo_filter(msginfo, NULL))
-                               to_drop = g_slist_prepend(to_drop, msginfo);
-                       else
-                               to_filter = g_slist_prepend(to_filter, msginfo);
+                       to_filter = g_slist_prepend(to_filter, msginfo);
                } else {
                        MsgFileInfo *finfo = g_new0(MsgFileInfo, 1);
                        finfo->file = tmp_file;
@@ -251,21 +248,23 @@ gint proc_mbox(FolderItem *dest, const gchar *mbox, gboolean apply_filter)
                statusbar_pop_all();
 
        if (apply_filter) {
-               to_drop = g_slist_reverse(to_drop);
-               folder_item_move_msgs(dest, to_drop);
-               for (cur = to_drop; cur; cur = g_slist_next(cur)) {
+               procmsg_msglist_filter(to_filter, NULL, &filtered, &unfiltered, TRUE);
+               unfiltered = g_slist_reverse(unfiltered);
+               folder_item_move_msgs(dest, unfiltered);
+               for (cur = unfiltered; cur; cur = g_slist_next(cur)) {
                        MsgInfo *info = (MsgInfo *)cur->data;
                        procmsg_msginfo_free(info);
                }
 
-               to_filter = g_slist_reverse(to_filter);
-               filtering_move_and_copy_msgs(to_filter);
-               for (cur = to_filter; cur; cur = g_slist_next(cur)) {
+               filtered = g_slist_reverse(filtered);
+               filtering_move_and_copy_msgs(filtered);
+               for (cur = filtered; cur; cur = g_slist_next(cur)) {
                        MsgInfo *info = (MsgInfo *)cur->data;
                        procmsg_msginfo_free(info);
                }
 
-               g_slist_free(to_drop);
+               g_slist_free(unfiltered);
+               g_slist_free(filtered);
                g_slist_free(to_filter);
        } else if (to_add) {
                folder_item_add_msgs(dropfolder, to_add, TRUE);
index 0c6a38853eb18847aa96a8f402147a9edf010a63..e38ef19c9c633b4011482ab3363dd62a98ff3ca7 100644 (file)
 #include <pwd.h>
 #endif
 
-enum {
-    CHILD_RUNNING = 1 << 0,
-    TIMEOUT_RUNNING = 1 << 1,
-};
+#define MAILS_PER_BATCH 20
 
 static guint hook_id = -1;
 static MessageCallback message_callback;
@@ -96,72 +93,160 @@ static PrefParam param[] = {
        {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL}
 };
 
+/*
+ * Helper function for spawn_with_input() - write an entire
+ * string to a fd.
+ */
+static gboolean
+write_all (int         fd,
+          const char *buf,
+          gsize       to_write)
+{
+  while (to_write > 0)
+    {
+      gssize count = write (fd, buf, to_write);
+      if (count < 0)
+       {
+         if (errno != EINTR)
+           return FALSE;
+       }
+      else
+       {
+         to_write -= count;
+         buf += count;
+       }
+    }
+
+  return TRUE;
+}
+
 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;
+       GSList *msglist = mail_filtering_data->msglist;
+       GSList *cur = NULL;
        static gboolean warned_error = FALSE;
        gchar *file = NULL, *cmd = NULL;
-       int status = 3;
+       int status = 0;
        gchar *bogo_exec = (config.bogopath && *config.bogopath) ? config.bogopath:"bogofilter";
+       int total = 0, curnum = 0;
+       GSList *spams = NULL;
+       gchar buf[BUFSIZ];
+
+       gchar *bogo_args[4];
+       GPid bogo_pid;
+       gint bogo_stdin, bogo_stdout;
+       GError *error = NULL;
+       gboolean bogo_forked;
 
        if (!config.process_emails) {
                return FALSE;
        }
-       debug_print("Filtering message %d\n", msginfo->msgnum);
+       
+       if (msglist == NULL && msginfo != NULL) {
+               g_warning("wrong call to bogofilter mail_filtering_hook");
+               return FALSE;
+       }
+       
+       total = g_slist_length(msglist);
        if (message_callback != NULL)
-               message_callback(_("Bogofilter: filtering message..."), 0, 0);
+               message_callback(_("Bogofilter: filtering messages..."), total, 0);
 
-       file = procmsg_get_message_file(msginfo);
+       cmd = g_strdup_printf("%s -T -b", bogo_exec);
 
-       if (file)
-               cmd = g_strdup_printf("%s -I %s", bogo_exec, file);
-       
-       if (cmd)
-               status = system(cmd);
-       
-       if (status == -1)
-               status = 3;
-       else 
-               status = WEXITSTATUS(status);
-
-       g_free(cmd);
-       g_free(file);
-       debug_print("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);
-               }
+       bogo_args[0] = bogo_exec;
+       bogo_args[1] = "-T";
+       bogo_args[2] = "-b";
+       bogo_args[3] = NULL;
 
-               return TRUE;
+       bogo_forked = g_spawn_async_with_pipes(
+                       NULL, bogo_args,NULL, G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
+                       NULL, NULL, &bogo_pid, &bogo_stdin,
+                       &bogo_stdout, NULL, &error);
+               
+       if (bogo_forked == FALSE) {
+               g_warning("%s\n", error ? error->message:"ERROR???");
+               g_error_free(error);
+               error = NULL;
+               status = -1;
        } else {
-               debug_print("message is ham\n");
-               procmsg_msginfo_unset_flags(msginfo, MSG_SPAM, 0);
+               for (cur = msglist; cur; cur = cur->next) {
+                       msginfo = (MsgInfo *)cur->data;
+                       debug_print("Filtering message %d (%d/%d)\n", msginfo->msgnum, curnum, total);
+
+                       if (message_callback != NULL)
+                               message_callback(NULL, total, curnum++);
+
+                       file = procmsg_get_message_file(msginfo);
+
+                       if (file) {
+                               gchar *tmp = g_strdup_printf("%s\n",file);
+                               write_all(bogo_stdin, tmp, strlen(tmp));
+                               g_free(tmp);
+                               memset(buf, 0, sizeof(buf));
+                               if (read(bogo_stdout, buf, sizeof(buf)-1) < 0) {
+                                       printf("ERROR 2\n");
+                               } else {
+                                       gchar **parts = NULL;
+                                       if (strchr(buf, '/')) {
+                                               tmp = strrchr(buf, '/')+1;
+                                       } else {
+                                               tmp = buf;
+                                       }
+                                       parts = g_strsplit(tmp, " ", 0);
+                                       debug_print("read %s\n", buf);
+                                       if (parts && parts[0] && parts[1] && *parts[1] == 'S') {
+                                               debug_print("message %d is spam\n", msginfo->msgnum);
+                                               procmsg_msginfo_set_flags(msginfo, MSG_SPAM, 0);
+                                               if (config.receive_spam) {
+                                                       procmsg_msginfo_unset_flags(msginfo, ~0, 0);
+                                                       procmsg_msginfo_set_flags(msginfo, MSG_SPAM, 0);
+                                                       spams = g_slist_prepend(spams, msginfo);
+                                               } else {
+                                                       folder_item_remove_msg(msginfo->folder, msginfo->msgnum);
+                                               }
+                                               mail_filtering_data->filtered = g_slist_prepend(
+                                                       mail_filtering_data->filtered, msginfo);
+                                       } else {
+                                               debug_print("message %d is ham\n", msginfo->msgnum);
+                                               procmsg_msginfo_unset_flags(msginfo, MSG_SPAM, 0);
+                                               mail_filtering_data->unfiltered = g_slist_prepend(
+                                                       mail_filtering_data->unfiltered, msginfo);
+                                       }
+                                       g_strfreev(parts);
+                               }
+                               g_free(file);
+                       } else {
+                               mail_filtering_data->unfiltered = g_slist_prepend(
+                                       mail_filtering_data->unfiltered, msginfo);
+                       }
+               }
        }
        
-       if (status == 3) { /* I/O or other errors */
-               gchar *msg = _("The Bogofilter plugin couldn't filter "
+       if (status != -1) {
+               close(bogo_stdout);
+               close(bogo_stdin);
+               waitpid(bogo_pid, &status, 0);
+               if (!WIFEXITED(status))
+                       status = -1;
+               else
+                       status = WEXITSTATUS(status);
+       } 
+
+       if (status < 0 || status > 2) { /* I/O or other errors */
+               gchar *msg = NULL;
+               
+               if (status == 3)
+                       msg =  g_strdup_printf(_("The Bogofilter plugin couldn't filter "
                                           "a message. The probable cause of the "
                                           "error is that it didn't learn from any mail.\n"
                                           "Use \"/Mark/Mark as spam\" and \"/Mark/Mark as "
                                           "ham\" to train Bogofilter with a few hundred "
-                                          "spam and ham messages.");
+                                          "spam and ham messages."));
+               else
+                       msg =  g_strdup_printf(_("The Bogofilter plugin couldn't filter "
+                                          "a message. the command `%s` couldn't be run."), cmd);
                if (!prefs_common.no_recv_err_panel) {
                        if (!warned_error) {
                                alertpanel_error(msg);
@@ -172,7 +257,31 @@ static gboolean mail_filtering_hook(gpointer source, gpointer data)
                        log_error(tmp);
                        g_free(tmp);
                }
+               g_free(msg);
        }
+       if (status < 0 || status > 2) {
+               g_slist_free(mail_filtering_data->filtered);
+               g_slist_free(mail_filtering_data->unfiltered);
+               g_slist_free(spams);
+               mail_filtering_data->filtered = NULL;
+               mail_filtering_data->unfiltered = NULL;
+       } else if (config.receive_spam && spams) {
+               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();
+
+               folder_item_move_msgs(save_folder, spams);
+       } 
+
+       if (message_callback != NULL)
+               message_callback(NULL, 0, 0);
+       mail_filtering_data->filtered = g_slist_reverse(
+               mail_filtering_data->filtered);
+       mail_filtering_data->unfiltered = g_slist_reverse(
+               mail_filtering_data->unfiltered);
        
        return FALSE;
 }
@@ -267,46 +376,58 @@ int bogofilter_learn(MsgInfo *msginfo, GSList *msglist, gboolean spam)
                                        message_callback(NULL, total, done);
                        }
                } else if (some_correction || some_no_correction) {
-                       int count = 0;
-                       gchar *file_list = NULL;
                        cur = msglist;
                        
-                       while (cur && status == 0) {
+                       gchar *bogo_args[4];
+                       GPid bogo_pid;
+                       gint bogo_stdin;
+                       GError *error = NULL;
+                       gboolean bogo_forked;
+
+                       bogo_args[0] = (gchar *)bogo_exec;
+                       if (some_correction && !some_no_correction)
+                               bogo_args[1] = "-Sn";
+                       else if (some_no_correction && !some_correction)
+                               bogo_args[1] = spam ? "-s":"-n";
+                       bogo_args[2] = "-b";
+                       bogo_args[3] = NULL;
+
+                       bogo_forked = g_spawn_async_with_pipes(
+                                       NULL, bogo_args,NULL, G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
+                                       NULL, NULL, &bogo_pid, &bogo_stdin,
+                                       NULL, NULL, &error);
+
+                       while (bogo_forked && cur) {
                                gchar *tmp = NULL;
                                info = (MsgInfo *)cur->data;
                                file = procmsg_get_message_file(info);
                                if (file) {
-                                       tmp = g_strdup_printf("%s%s'%s'", 
-                                               file_list?file_list:"",
-                                               file_list?" ":"",
+                                       tmp = g_strdup_printf("%s\n", 
                                                file);
-                                       g_free(file_list);
-                                       file_list = tmp;
+                                       write_all(bogo_stdin, tmp, strlen(tmp));
+                                       g_free(tmp);
                                }
                                g_free(file);
-                               count ++;
                                done++;
-                               if (count > 10 || cur->next == NULL) {
-                                       /* flush */
-                                       if (some_correction && !some_no_correction)
-                                               cmd = g_strdup_printf("%s -Sn -B %s", bogo_exec, file_list);
-                                       else if (some_no_correction && !some_correction)
-                                               cmd = g_strdup_printf("%s -%c -B %s", bogo_exec, spam?'s':'n', file_list);
-                                       else
-                                               g_warning("duuh bogofilter plugin shouldn't be there!\n");
-                                       if ((status = execute_command_line(cmd, FALSE)) != 0)
-                                               alertpanel_error(_("Learning failed; `%s` returned with status %d."),
-                                                               cmd, status);
-                                       count = 0;
-                                       g_free(cmd);
-                                       g_free(file_list);
-                                       file_list = NULL;
-                               }
                                if (message_callback != NULL)
                                        message_callback(NULL, total, done);
                                cur = cur->next;
                        }
-                       g_free(file_list);
+                       if (bogo_forked) {
+                               close(bogo_stdin);
+                               waitpid(bogo_pid, &status, 0);
+                               if (!WIFEXITED(status))
+                                       status = -1;
+                               else
+                                       status = WEXITSTATUS(status);
+                       }
+                       if (!bogo_forked || status != 0) {
+                               alertpanel_error(_("Learning failed; `%s` returned with error:\n%s"),
+                                               cmd, error ? error->message:_("Unknown error"));
+                               if (error)
+                                       g_error_free(error);
+                       }
+
                }
 
                if (message_callback != NULL)
@@ -440,7 +561,7 @@ struct PluginFeature *plugin_provides(void)
 
 void bogofilter_register_hook(void)
 {
-       hook_id = hooks_register_hook(MAIL_FILTERING_HOOKLIST, mail_filtering_hook, NULL);
+       hook_id = hooks_register_hook(MAIL_LISTFILTERING_HOOKLIST, mail_filtering_hook, NULL);
        if (hook_id == -1) {
                g_warning("Failed to register mail filtering hook");
                config.process_emails = FALSE;
@@ -450,6 +571,6 @@ void bogofilter_register_hook(void)
 void bogofilter_unregister_hook(void)
 {
        if (hook_id != -1) {
-               hooks_unregister_hook(MAIL_FILTERING_HOOKLIST, hook_id);
+               hooks_unregister_hook(MAIL_LISTFILTERING_HOOKLIST, hook_id);
        }
 }
index 4879c1b94895f8cd4345f144b2df9c45b287d06d..f91a206bb0aff9c4a780fe13955cf283edf7307d 100644 (file)
@@ -2146,6 +2146,9 @@ gboolean procmsg_msginfo_filter(MsgInfo *msginfo, PrefsAccount* ac_prefs)
        MailFilteringData mail_filtering_data;
                        
        mail_filtering_data.msginfo = msginfo;                  
+       mail_filtering_data.msglist = NULL;                     
+       mail_filtering_data.filtered = NULL;                    
+       mail_filtering_data.unfiltered = NULL;                  
        if (hooks_invoke(MAIL_FILTERING_HOOKLIST, &mail_filtering_data)) {
                return TRUE;
        }
@@ -2159,6 +2162,84 @@ gboolean procmsg_msginfo_filter(MsgInfo *msginfo, PrefsAccount* ac_prefs)
        return FALSE;
 }
 
+void procmsg_msglist_filter(GSList *list, PrefsAccount *ac, 
+                           GSList **filtered, GSList **unfiltered,
+                           gboolean do_filter)
+{
+       GSList *cur, *to_do = NULL;
+       gint total = 0, curnum = 0;
+       MailFilteringData mail_filtering_data;
+                       
+       g_return_if_fail(filtered != NULL);
+       g_return_if_fail(unfiltered != NULL);
+
+       *filtered = NULL;
+       *unfiltered = NULL;
+       
+       if (list == NULL)
+               return;
+
+       total = g_slist_length(list);
+
+       if (!do_filter) {
+               *filtered = NULL;
+               *unfiltered = g_slist_copy(list);
+               return;
+       }
+
+       statusbar_print_all(_("Filtering messages...\n"));
+
+       mail_filtering_data.msginfo = NULL;                     
+       mail_filtering_data.msglist = list;                     
+       mail_filtering_data.filtered = NULL;                    
+       mail_filtering_data.unfiltered = NULL;  
+                       
+       hooks_invoke(MAIL_LISTFILTERING_HOOKLIST, &mail_filtering_data);
+       
+       if (mail_filtering_data.filtered == NULL &&
+           mail_filtering_data.unfiltered == NULL) {
+               /* nothing happened */
+               debug_print(MAIL_LISTFILTERING_HOOKLIST " did nothing. filtering whole list normally.\n");
+               to_do = list;
+       } 
+       if (mail_filtering_data.filtered != NULL) {
+               /* keep track of what's been filtered by the hooks */
+               debug_print(MAIL_LISTFILTERING_HOOKLIST " filtered some stuff. total %d filtered %d unfilt %d.\n",
+                       g_slist_length(list),
+                       g_slist_length(mail_filtering_data.filtered),
+                       g_slist_length(mail_filtering_data.unfiltered));
+
+               *filtered = g_slist_copy(mail_filtering_data.filtered);
+       }
+       if (mail_filtering_data.unfiltered != NULL) {
+               /* what the hooks didn't handle will go in filtered or 
+                * unfiltered in the next loop */
+               debug_print(MAIL_LISTFILTERING_HOOKLIST " left unfiltered stuff. total %d filtered %d unfilt %d.\n",
+                       g_slist_length(list),
+                       g_slist_length(mail_filtering_data.filtered),
+                       g_slist_length(mail_filtering_data.unfiltered));
+               to_do = mail_filtering_data.unfiltered;
+       } 
+
+       for (cur = to_do; cur; cur = cur->next) {
+               MsgInfo *info = (MsgInfo *)cur->data;
+               if (procmsg_msginfo_filter(info, ac))
+                       *filtered = g_slist_prepend(*filtered, info);
+               else
+                       *unfiltered = g_slist_prepend(*unfiltered, info);
+               statusbar_progress_all(curnum++, total, prefs_common.statusbar_update_step);
+       }
+
+       g_slist_free(mail_filtering_data.filtered);
+       g_slist_free(mail_filtering_data.unfiltered);
+       
+       *filtered = g_slist_reverse(*filtered);
+       *unfiltered = g_slist_reverse(*unfiltered);
+
+       statusbar_progress_all(0,0,0);
+       statusbar_pop_all();
+}
+
 MsgInfo *procmsg_msginfo_new_from_mimeinfo(MsgInfo *src_msginfo, MimeInfo *mimeinfo)
 {
        MsgInfo *tmp_msginfo = NULL;
index ed364125e9a77d425369ca2b929b683c5bc632e4..c1edc2ed22a21f7b778c33708169d615cb380f57 100644 (file)
@@ -152,6 +152,7 @@ typedef guint32 MsgTmpFlags;
 
 #define MSGINFO_UPDATE_HOOKLIST "msginfo_update"
 #define MAIL_FILTERING_HOOKLIST "mail_filtering_hooklist"
+#define MAIL_LISTFILTERING_HOOKLIST "mail_listfiltering_hooklist"
 #define MAIL_POSTFILTERING_HOOKLIST "mail_postfiltering_hooklist"
 
 typedef enum {
@@ -260,6 +261,9 @@ struct _MsgInfoUpdate {
 struct _MailFilteringData
 {
        MsgInfo *msginfo;
+       GSList  *msglist;
+       GSList  *filtered;
+       GSList  *unfiltered;
 };
 
 GHashTable *procmsg_msg_hash_table_create      (GSList         *mlist);
@@ -349,8 +353,14 @@ void procmsg_update_unread_children        (MsgInfo        *info,
                                         gboolean        newly_marked);
 void procmsg_msginfo_set_to_folder     (MsgInfo        *msginfo,
                                         FolderItem     *to_folder);
-gboolean procmsg_msginfo_filter                (MsgInfo                *msginfo,
-                                                                        PrefsAccount   *ac_prefs);
+gboolean procmsg_msginfo_filter                (MsgInfo        *msginfo,
+                                        PrefsAccount   *ac_prefs);
+void procmsg_msglist_filter            (GSList         *list, 
+                                        PrefsAccount   *ac, 
+                                        GSList         **filtered,
+                                        GSList         **unfiltered,
+                                        gboolean        do_filter);
+
 MsgInfo *procmsg_msginfo_new_from_mimeinfo
                                        (MsgInfo        *src_msginfo, 
                                         MimeInfo       *mimeinfo);