aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRadek Doulik <rodo@src.gnome.org>2003-11-13 05:13:05 +0800
committerRadek Doulik <rodo@src.gnome.org>2003-11-13 05:13:05 +0800
commit8e1251fa17b522d0539a8fcfb7463ba8cef1b31a (patch)
tree9be2f3a8a184446361a8c72879947f7a6e7d8d75
parent8187001a14295b4b64cc3e973fb1ab1e551133f2 (diff)
downloadgsoc2013-evolution-8e1251fa17b522d0539a8fcfb7463ba8cef1b31a.tar.gz
gsoc2013-evolution-8e1251fa17b522d0539a8fcfb7463ba8cef1b31a.tar.zst
gsoc2013-evolution-8e1251fa17b522d0539a8fcfb7463ba8cef1b31a.zip
merged spam filtering branch
svn path=/trunk/; revision=23302
-rw-r--r--art/Makefile.am2
-rw-r--r--art/evolution-junk-mini.pngbin0 -> 926 bytes
-rw-r--r--art/evolution-junk.pngbin0 -> 4083 bytes
-rw-r--r--camel/Makefile.am2
-rw-r--r--camel/camel-digest-store.c21
-rw-r--r--camel/camel-filter-driver.c1
-rw-r--r--camel/camel-filter-search.c19
-rw-r--r--camel/camel-folder-summary.c1
-rw-r--r--camel/camel-folder-summary.h1
-rw-r--r--camel/camel-folder.c2
-rw-r--r--camel/camel-folder.h1
-rw-r--r--camel/camel-junk-plugin.c75
-rw-r--r--camel/camel-junk-plugin.h59
-rw-r--r--camel/camel-session.h3
-rw-r--r--camel/camel-store.c121
-rw-r--r--camel/camel-store.h7
-rw-r--r--camel/camel-vee-store.c23
-rw-r--r--camel/camel-vtrash-folder.h1
-rw-r--r--configure.in3
-rw-r--r--default_user/local/Makefile.am1
-rw-r--r--filter/filtertypes.xml6
-rw-r--r--filter/libfilter-i18n.h1
-rw-r--r--mail/Makefile.am4
-rw-r--r--mail/em-folder-tree.c6
-rw-r--r--mail/em-folder-view.c20
-rw-r--r--mail/em-junk-filter.c327
-rw-r--r--mail/em-junk-filter.h30
-rw-r--r--mail/em-junk-plugin.c24
-rw-r--r--mail/em-junk-plugin.h47
-rw-r--r--mail/em-popup.c5
-rw-r--r--mail/em-popup.h4
-rw-r--r--mail/mail-component.c11
-rw-r--r--mail/mail-folder-cache.c14
-rw-r--r--mail/mail-ops.c151
-rw-r--r--mail/mail-ops.h4
-rw-r--r--mail/mail-session.c7
-rw-r--r--mail/mail-tools.c13
-rw-r--r--mail/mail-vfolder.c6
-rw-r--r--mail/message-list.c112
-rw-r--r--mail/message-list.h3
-rw-r--r--shell/e-local-storage.c1
-rw-r--r--shell/e-shortcuts.c1
-rw-r--r--ui/evolution-mail-message.xml9
43 files changed, 1056 insertions, 93 deletions
diff --git a/art/Makefile.am b/art/Makefile.am
index bd96fd0759..e17e7bba91 100644
--- a/art/Makefile.am
+++ b/art/Makefile.am
@@ -45,6 +45,8 @@ images_DATA = \
evolution-today.png \
evolution-trash-mini.png \
evolution-trash.png \
+ evolution-junk.png \
+ evolution-junk-mini.png \
executive-summary-bg.png \
executive-summary-curve.png \
info-bulb.png \
diff --git a/art/evolution-junk-mini.png b/art/evolution-junk-mini.png
new file mode 100644
index 0000000000..64d488ca1c
--- /dev/null
+++ b/art/evolution-junk-mini.png
Binary files differ
diff --git a/art/evolution-junk.png b/art/evolution-junk.png
new file mode 100644
index 0000000000..5fefbefc56
--- /dev/null
+++ b/art/evolution-junk.png
Binary files differ
diff --git a/camel/Makefile.am b/camel/Makefile.am
index a1d00a1323..eee87b84db 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -47,6 +47,7 @@ libcamel_la_SOURCES = \
camel-http-stream.c \
camel-index.c \
camel-internet-address.c \
+ camel-junk-plugin.c \
camel-lock.c \
camel-lock-client.c \
camel-medium.c \
@@ -148,6 +149,7 @@ libcamelinclude_HEADERS = \
camel-index.h \
camel-internet-address.h \
camel-i18n.h \
+ camel-junk-plugin.h \
camel-lock.h \
camel-lock-client.h \
camel-medium.h \
diff --git a/camel/camel-digest-store.c b/camel/camel-digest-store.c
index e3870e3672..833593ac9f 100644
--- a/camel/camel-digest-store.c
+++ b/camel/camel-digest-store.c
@@ -40,6 +40,8 @@ static void digest_delete_folder (CamelStore *store, const char *folder_name, Ca
static void digest_rename_folder (CamelStore *store, const char *old, const char *new, CamelException *ex);
static void digest_init_trash (CamelStore *store);
static CamelFolder *digest_get_trash (CamelStore *store, CamelException *ex);
+static void digest_init_junk (CamelStore *store);
+static CamelFolder *digest_get_junk (CamelStore *store, CamelException *ex);
static CamelFolderInfo *digest_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex);
@@ -92,6 +94,8 @@ camel_digest_store_class_init (CamelDigestStoreClass *klass)
store_class->init_trash = digest_init_trash;
store_class->get_trash = digest_get_trash;
+ store_class->init_junk = digest_init_junk;
+ store_class->get_junk = digest_get_junk;
}
static void
@@ -99,8 +103,8 @@ camel_digest_store_init (CamelDigestStore *obj)
{
CamelStore *store = (CamelStore *) obj;
- /* we dont want a vtrash on this one */
- store->flags &= ~(CAMEL_STORE_VTRASH);
+ /* we dont want a vtrash and vjunk on this one */
+ store->flags &= ~(CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK);
}
static void
@@ -167,6 +171,19 @@ digest_get_trash (CamelStore *store, CamelException *ex)
return NULL;
}
+static void
+digest_init_junk (CamelStore *store)
+{
+ /* no-op */
+ ;
+}
+
+static CamelFolder *
+digest_get_junk (CamelStore *store, CamelException *ex)
+{
+ return NULL;
+}
+
static CamelFolderInfo *
digest_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
{
diff --git a/camel/camel-filter-driver.c b/camel/camel-filter-driver.c
index ff6a8a88d2..bd3478e64e 100644
--- a/camel/camel-filter-driver.c
+++ b/camel/camel-filter-driver.c
@@ -809,7 +809,6 @@ pipe_message (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilte
return NULL;
}
-
static ESExpResult *
do_shell (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFilterDriver *driver)
{
diff --git a/camel/camel-filter-search.c b/camel/camel-filter-search.c
index 8af3392e71..5897239164 100644
--- a/camel/camel-filter-search.c
+++ b/camel/camel-filter-search.c
@@ -91,6 +91,7 @@ static ESExpResult *get_current_date (struct _ESExp *f, int argc, struct _ESExpR
static ESExpResult *header_source (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
static ESExpResult *get_size (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
static ESExpResult *pipe_message (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
+static ESExpResult *junk_test (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms);
/* builtin functions */
static struct {
@@ -119,6 +120,7 @@ static struct {
{ "header-source", (ESExpFunc *) header_source, 0 },
{ "get-size", (ESExpFunc *) get_size, 0 },
{ "pipe-message", (ESExpFunc *) pipe_message, 0 },
+ { "junk-test", (ESExpFunc *) junk_test, 0 },
};
@@ -609,6 +611,23 @@ pipe_message (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMess
return r;
}
+static ESExpResult *
+junk_test (struct _ESExp *f, int argc, struct _ESExpResult **argv, FilterMessageSearch *fms)
+{
+ ESExpResult *r;
+ gboolean retval = FALSE;
+
+ if (fms->session->junk_plugin != NULL) {
+ retval = camel_junk_plugin_check_junk (fms->session->junk_plugin, camel_filter_search_get_message (fms, f));
+
+ fprintf (stderr, "junk filter => %s\n", retval ? "*JUNK*" : "clean");
+ }
+ r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+ r->value.number = retval;
+
+ return r;
+}
+
/**
* camel_filter_search_match:
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index 3ad9eb31ad..05b3f3a056 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -2503,6 +2503,7 @@ struct flag_names_t {
{ "flagged", CAMEL_MESSAGE_FLAGGED },
{ "seen", CAMEL_MESSAGE_SEEN },
{ "attachments", CAMEL_MESSAGE_ATTACHMENTS },
+ { "junk", CAMEL_MESSAGE_JUNK },
{ NULL, 0 }
};
diff --git a/camel/camel-folder-summary.h b/camel/camel-folder-summary.h
index 48713b1a3c..e57be75ae1 100644
--- a/camel/camel-folder-summary.h
+++ b/camel/camel-folder-summary.h
@@ -64,6 +64,7 @@ enum _CamelMessageFlags {
CAMEL_MESSAGE_SEEN = 1<<4,
CAMEL_MESSAGE_ATTACHMENTS = 1<<5,
CAMEL_MESSAGE_ANSWERED_ALL = 1<<6,
+ CAMEL_MESSAGE_JUNK = 1<<7,
/* following flags are for the folder, and are not really permanent flags */
CAMEL_MESSAGE_FOLDER_FLAGGED = 1<<16, /* for use by the folder implementation */
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index f682ee25ca..d8fe518f71 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -549,7 +549,7 @@ get_unread_message_count(CamelFolder *folder)
CamelMessageInfo *info = camel_folder_summary_index(folder->summary, i);
if (info) {
- if (!(info->flags & CAMEL_MESSAGE_SEEN))
+ if (!(info->flags & CAMEL_MESSAGE_SEEN) && (!(info->flags & CAMEL_MESSAGE_JUNK) || (folder->folder_flags & CAMEL_FOLDER_IS_JUNK)))
unread++;
camel_folder_summary_info_free(folder->summary, info);
}
diff --git a/camel/camel-folder.h b/camel/camel-folder.h
index f1fe9bfb63..83df665147 100644
--- a/camel/camel-folder.h
+++ b/camel/camel-folder.h
@@ -103,6 +103,7 @@ struct _CamelFolder
#define CAMEL_FOLDER_FILTER_RECENT (1<<2)
#define CAMEL_FOLDER_HAS_BEEN_DELETED (1<<3)
#define CAMEL_FOLDER_IS_TRASH (1<<4)
+#define CAMEL_FOLDER_IS_JUNK (1<<5)
typedef struct {
CamelObjectClass parent_class;
diff --git a/camel/camel-junk-plugin.c b/camel/camel-junk-plugin.c
new file mode 100644
index 0000000000..a203b45c3e
--- /dev/null
+++ b/camel/camel-junk-plugin.c
@@ -0,0 +1,75 @@
+/* -*- 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
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <camel/camel-junk-plugin.h>
+#include <camel/camel-mime-message.h>
+
+#define d(x) x
+
+const char *
+camel_junk_plugin_get_name (CamelJunkPlugin *csp)
+{
+ g_return_val_if_fail (csp->get_name != NULL, NULL);
+
+ d(fprintf (stderr, "camel_junk_plugin_get_namen");)
+
+ return (*csp->get_name) ();
+}
+
+int
+camel_junk_plugin_check_junk (CamelJunkPlugin *csp, CamelMimeMessage *message)
+{
+ g_return_val_if_fail (csp->check_junk != NULL, FALSE);
+
+ d(fprintf (stderr, "camel_junk_plugin_check_junk\n");)
+
+ return (*csp->check_junk) (message);
+}
+
+void
+camel_junk_plugin_report_junk (CamelJunkPlugin *csp, CamelMimeMessage *message)
+{
+ d(fprintf (stderr, "camel_junk_plugin_report_junk\n");)
+
+ if (csp->report_junk)
+ (*csp->report_junk) (message);
+}
+
+void
+camel_junk_plugin_report_notjunk (CamelJunkPlugin *csp, CamelMimeMessage *message)
+{
+ d(fprintf (stderr, "camel_junk_plugin_report_notjunk\n");)
+
+ if (csp->report_notjunk)
+ (*csp->report_notjunk) (message);
+}
+
+void
+camel_junk_plugin_commit_reports (CamelJunkPlugin *csp)
+{
+ d(fprintf (stderr, "camel_junk_plugin_commit_reports\n");)
+
+ if (csp->commit_reports)
+ (*csp->commit_reports) ();
+}
diff --git a/camel/camel-junk-plugin.h b/camel/camel-junk-plugin.h
new file mode 100644
index 0000000000..79d1bf6331
--- /dev/null
+++ b/camel/camel-junk-plugin.h
@@ -0,0 +1,59 @@
+/* -*- 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
+ */
+
+#ifndef _CAMEL_JUNK_PLUGIN_H
+#define _CAMEL_JUNK_PLUGIN_H
+
+#define CAMEL_JUNK_PLUGIN(x) ((CamelJunkPlugin *) x)
+
+typedef struct _CamelJunkPlugin CamelJunkPlugin;
+struct _CamelMimeMessage;
+
+struct _CamelJunkPlugin
+{
+ /* junk filter human readable name, translated */
+ const char * (*get_name) (void);
+
+ /* should be set to 1 */
+ int api_version;
+
+ /* when called, it should return TRUE if message is identified as junk,
+ FALSE otherwise */
+ int (*check_junk) (struct _CamelMimeMessage *message);
+
+ /* called when user identified a message to be junk */
+ void (*report_junk) (struct _CamelMimeMessage *message);
+
+ /* called when user identified a message not to be junk */
+ void (*report_notjunk) (struct _CamelMimeMessage *message);
+
+ /* called after one or more junk/ham(s) reported */
+ void (*commit_reports) (void);
+};
+
+const char * camel_junk_plugin_get_name (CamelJunkPlugin *csp);
+int camel_junk_plugin_check_junk (CamelJunkPlugin *csp, struct _CamelMimeMessage *message);
+void camel_junk_plugin_report_junk (CamelJunkPlugin *csp, struct _CamelMimeMessage *message);
+void camel_junk_plugin_report_notjunk (CamelJunkPlugin *csp, struct _CamelMimeMessage *message);
+void camel_junk_plugin_commit_reports (CamelJunkPlugin *csp);
+
+#endif
diff --git a/camel/camel-session.h b/camel/camel-session.h
index b9416ddc8d..43abc614a8 100644
--- a/camel/camel-session.h
+++ b/camel/camel-session.h
@@ -35,6 +35,7 @@ extern "C" {
#include <camel/camel-object.h>
#include <camel/camel-provider.h>
+#include <camel/camel-junk-plugin.h>
#include <e-util/e-msgport.h>
@@ -59,6 +60,8 @@ struct _CamelSession
char *storage_path;
GHashTable *providers, *modules;
gboolean online;
+
+ CamelJunkPlugin *junk_plugin;
};
#ifdef ENABLE_THREADS
diff --git a/camel/camel-store.c b/camel/camel-store.c
index 96d840d2d3..ee51def91a 100644
--- a/camel/camel-store.c
+++ b/camel/camel-store.c
@@ -53,6 +53,9 @@ static CamelFolder *get_inbox (CamelStore *store, CamelException *ex);
static void init_trash (CamelStore *store);
static CamelFolder *get_trash (CamelStore *store, CamelException *ex);
+static void init_junk (CamelStore *store);
+static CamelFolder *get_junk (CamelStore *store, CamelException *ex);
+
static CamelFolderInfo *create_folder (CamelStore *store,
const char *parent_name,
const char *folder_name,
@@ -95,6 +98,8 @@ camel_store_class_init (CamelStoreClass *camel_store_class)
camel_store_class->get_inbox = get_inbox;
camel_store_class->init_trash = init_trash;
camel_store_class->get_trash = get_trash;
+ camel_store_class->init_junk = init_junk;
+ camel_store_class->get_junk = get_junk;
camel_store_class->create_folder = create_folder;
camel_store_class->delete_folder = delete_folder;
camel_store_class->rename_folder = rename_folder;
@@ -132,8 +137,8 @@ camel_store_init (void *o)
} else
store->folders = NULL;
- /* set vtrash on by default */
- store->flags = CAMEL_STORE_VTRASH;
+ /* set vtrash and vjunk on by default */
+ store->flags = CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK;
store->dir_sep = '/';
@@ -239,9 +244,11 @@ camel_store_get_folder (CamelStore *store, const char *folder_name, guint32 flag
if (!folder) {
folder = CS_CLASS (store)->get_folder (store, folder_name, flags, ex);
if (folder) {
- /* Add the folder to the vTrash folder if this store implements it */
+ /* Add the folder to the vTrash/vJunk folder if this store implements it */
if (store->vtrash)
camel_vee_folder_add_folder (CAMEL_VEE_FOLDER (store->vtrash), folder);
+ if (store->vjunk)
+ camel_vee_folder_add_folder (CAMEL_VEE_FOLDER (store->vjunk), folder);
if (store->folders)
camel_object_bag_add(store->folders, folder_name, folder);
@@ -319,12 +326,14 @@ camel_store_delete_folder (CamelStore *store, const char *folder_name, CamelExce
/* NB: Note similarity of this code to unsubscribe_folder */
- /* if we deleted a folder, force it out of the cache, and also out of the vtrash if setup */
+ /* if we deleted a folder, force it out of the cache, and also out of the vtrash/vjunk if setup */
if (store->folders) {
folder = camel_object_bag_get(store->folders, folder_name);
if (folder) {
if (store->vtrash)
camel_vee_folder_remove_folder((CamelVeeFolder *)store->vtrash, folder);
+ if (store->vjunk)
+ camel_vee_folder_remove_folder((CamelVeeFolder *)store->vjunk, folder);
camel_folder_delete (folder);
}
}
@@ -480,26 +489,44 @@ trash_finalize (CamelObject *trash, gpointer event_data, gpointer user_data)
}
static void
-init_trash (CamelStore *store)
+junk_finalize (CamelObject *junk, gpointer event_data, gpointer user_data)
{
- if ((store->flags & CAMEL_STORE_VTRASH) == 0)
- return;
+ CamelStore *store = CAMEL_STORE (user_data);
+
+ store->vjunk = NULL;
+}
- store->vtrash = camel_vtrash_folder_new (store, CAMEL_VTRASH_NAME);
+/* FIXME: derive vjunk folder object from vee_folder */
+#include "camel-vee-store.h"
+static CamelFolder *
+camel_vjunk_folder_new (CamelStore *parent_store, const char *name)
+{
+ CamelFolder *vjunk;
- if (store->vtrash) {
+ vjunk = (CamelFolder *)camel_object_new (camel_vee_folder_get_type ());
+ vjunk->folder_flags |= CAMEL_FOLDER_IS_JUNK;
+ camel_vee_folder_construct (CAMEL_VEE_FOLDER (vjunk), parent_store, name,
+ CAMEL_STORE_FOLDER_PRIVATE | CAMEL_STORE_FOLDER_CREATE | CAMEL_STORE_VEE_FOLDER_AUTO);
+ camel_vee_folder_set_expression((CamelVeeFolder *)vjunk, "(match-all (system-flag \"Junk\"))");
+
+ return vjunk;
+}
+
+static void
+init_trash_or_junk (CamelStore *store, CamelFolder *folder, void (*finalize) (CamelObject *o, gpointer event_data, gpointer user_data))
+{
+ if (folder) {
/* FIXME: this should probably use the object bag or another one ? ... */
- /* attach to the finalise event of the vtrash */
- camel_object_hook_event (store->vtrash, "finalize",
- trash_finalize, store);
+ /* attach to the finalise event of the vtrash/vjunk */
+ camel_object_hook_event (folder, "finalize", finalize, store);
- /* add all the pre-opened folders to the vtrash */
+ /* add all the pre-opened folders to the vtrash/vjunk */
if (store->folders) {
GPtrArray *folders = camel_object_bag_list(store->folders);
int i;
for (i=0;i<folders->len;i++) {
- camel_vee_folder_add_folder (CAMEL_VEE_FOLDER (store->vtrash), (CamelFolder *)folders->pdata[i]);
+ camel_vee_folder_add_folder (CAMEL_VEE_FOLDER (folder), (CamelFolder *)folders->pdata[i]);
camel_object_unref(folders->pdata[i]);
}
g_ptr_array_free(folders, TRUE);
@@ -507,6 +534,25 @@ init_trash (CamelStore *store)
}
}
+static void
+init_trash (CamelStore *store)
+{
+ if ((store->flags & CAMEL_STORE_VTRASH) == 0)
+ return;
+
+ store->vtrash = camel_vtrash_folder_new (store, CAMEL_VTRASH_NAME);
+ init_trash_or_junk (store, store->vtrash, trash_finalize);
+}
+
+static void
+init_junk (CamelStore *store)
+{
+ if ((store->flags & CAMEL_STORE_VJUNK) == 0)
+ return;
+
+ store->vjunk = camel_vjunk_folder_new (store, CAMEL_VJUNK_NAME);
+ init_trash_or_junk (store, store->vjunk, junk_finalize);
+}
static CamelFolder *
get_trash (CamelStore *store, CamelException *ex)
@@ -528,6 +574,26 @@ get_trash (CamelStore *store, CamelException *ex)
}
}
+static CamelFolder *
+get_junk (CamelStore *store, CamelException *ex)
+{
+ if (store->vjunk) {
+ camel_object_ref (CAMEL_OBJECT (store->vjunk));
+ return store->vjunk;
+ } else {
+ CS_CLASS (store)->init_junk (store);
+ if (store->vjunk) {
+ /* We don't ref here because we don't want the
+ store to own a ref on the junk folder */
+ /*camel_object_ref (CAMEL_OBJECT (store->vjunk));*/
+ return store->vjunk;
+ } else {
+ w(g_warning ("This store does not support vJunk."));
+ return NULL;
+ }
+ }
+}
+
/**
* camel_store_get_trash:
* @store: a CamelStore
@@ -551,6 +617,29 @@ camel_store_get_trash (CamelStore *store, CamelException *ex)
return folder;
}
+/**
+ * camel_store_get_junk:
+ * @store: a CamelStore
+ * @ex: a CamelException
+ *
+ * Return value: the folder in the store into which junk is
+ * delivered, or %NULL if no such folder exists.
+ **/
+CamelFolder *
+camel_store_get_junk (CamelStore *store, CamelException *ex)
+{
+ CamelFolder *folder;
+
+ if ((store->flags & CAMEL_STORE_VJUNK) == 0)
+ return NULL;
+
+ CAMEL_STORE_LOCK(store, folder_lock);
+ folder = CS_CLASS (store)->get_junk (store, ex);
+ CAMEL_STORE_UNLOCK(store, folder_lock);
+
+ return folder;
+}
+
static void
store_sync (CamelStore *store, CamelException *ex)
{
@@ -1015,12 +1104,14 @@ camel_store_unsubscribe_folder (CamelStore *store,
/* NB: Note similarity of this code to delete_folder */
- /* if we deleted a folder, force it out of the cache, and also out of the vtrash if setup */
+ /* if we deleted a folder, force it out of the cache, and also out of the vtrash/vjunk if setup */
if (store->folders) {
folder = camel_object_bag_get(store->folders, folder_name);
if (folder) {
if (store->vtrash)
camel_vee_folder_remove_folder((CamelVeeFolder *)store->vtrash, folder);
+ if (store->vjunk)
+ camel_vee_folder_remove_folder((CamelVeeFolder *)store->vjunk, folder);
camel_folder_delete (folder);
}
}
diff --git a/camel/camel-store.h b/camel/camel-store.h
index 4a0fb416f0..2b65751aac 100644
--- a/camel/camel-store.h
+++ b/camel/camel-store.h
@@ -83,6 +83,7 @@ typedef struct _CamelRenameInfo {
#define CAMEL_STORE_SUBSCRIPTIONS (1 << 0)
#define CAMEL_STORE_VTRASH (1 << 1)
#define CAMEL_STORE_FILTER_INBOX (1 << 2)
+#define CAMEL_STORE_VJUNK (1 << 3)
struct _CamelStore
{
@@ -90,6 +91,7 @@ struct _CamelStore
struct _CamelStorePrivate *priv;
CamelFolder *vtrash;
+ CamelFolder *vjunk;
CamelObjectBag *folders;
@@ -127,6 +129,9 @@ typedef struct {
void (*init_trash) (CamelStore *store);
CamelFolder * (*get_trash) (CamelStore *store,
CamelException *ex);
+ void (*init_junk) (CamelStore *store);
+ CamelFolder * (*get_junk) (CamelStore *store,
+ CamelException *ex);
CamelFolderInfo *(*create_folder) (CamelStore *store,
const char *parent_name,
@@ -175,6 +180,8 @@ CamelFolder * camel_store_get_inbox (CamelStore *store,
CamelException *ex);
CamelFolder * camel_store_get_trash (CamelStore *store,
CamelException *ex);
+CamelFolder * camel_store_get_junk (CamelStore *store,
+ CamelException *ex);
CamelFolderInfo *camel_store_create_folder (CamelStore *store,
const char *parent_name,
diff --git a/camel/camel-vee-store.c b/camel/camel-vee-store.c
index 3ad39237e0..b13522b8de 100644
--- a/camel/camel-vee-store.c
+++ b/camel/camel-vee-store.c
@@ -37,6 +37,8 @@ static void vee_delete_folder(CamelStore *store, const char *folder_name, CamelE
static void vee_rename_folder(CamelStore *store, const char *old, const char *new, CamelException *ex);
static void vee_init_trash (CamelStore *store);
static CamelFolder *vee_get_trash (CamelStore *store, CamelException *ex);
+static void vee_init_junk (CamelStore *store);
+static CamelFolder *vee_get_junk (CamelStore *store, CamelException *ex);
static CamelFolderInfo *vee_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex);
@@ -80,6 +82,8 @@ camel_vee_store_class_init (CamelVeeStoreClass *klass)
store_class->init_trash = vee_init_trash;
store_class->get_trash = vee_get_trash;
+ store_class->init_junk = vee_init_junk;
+ store_class->get_junk = vee_get_junk;
}
static void
@@ -87,8 +91,8 @@ camel_vee_store_init (CamelVeeStore *obj)
{
CamelStore *store = (CamelStore *)obj;
- /* we dont want a vtrash on this one */
- store->flags &= ~(CAMEL_STORE_VTRASH);
+ /* we dont want a vtrash/vjunk on this one */
+ store->flags &= ~(CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK);
}
static void
@@ -183,6 +187,19 @@ vee_get_trash (CamelStore *store, CamelException *ex)
return NULL;
}
+static void
+vee_init_junk (CamelStore *store)
+{
+ /* no-op */
+ ;
+}
+
+static CamelFolder *
+vee_get_junk (CamelStore *store, CamelException *ex)
+{
+ return NULL;
+}
+
static CamelFolderInfo *
vee_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelException *ex)
{
@@ -268,6 +285,8 @@ vee_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex
if (store->vtrash)
camel_vee_folder_remove_folder((CamelVeeFolder *)store->vtrash, folder);
+ if (store->vjunk)
+ camel_vee_folder_remove_folder((CamelVeeFolder *)store->vjunk, folder);
if ((((CamelVeeFolder *)folder)->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
/* what about now-empty parents? ignore? */
diff --git a/camel/camel-vtrash-folder.h b/camel/camel-vtrash-folder.h
index f0441c4c82..089c969e71 100644
--- a/camel/camel-vtrash-folder.h
+++ b/camel/camel-vtrash-folder.h
@@ -33,6 +33,7 @@ extern "C" {
#include <camel/camel-vee-folder.h>
#define CAMEL_VTRASH_NAME "Trash"
+#define CAMEL_VJUNK_NAME "Junk"
#define CAMEL_VTRASH_FOLDER(obj) CAMEL_CHECK_CAST (obj, camel_vtrash_folder_get_type (), CamelVTrashFolder)
#define CAMEL_VTRASH_FOLDER_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_vtrash_folder_get_type (), CamelVTrashFolderClass)
diff --git a/configure.in b/configure.in
index 63d7c8182a..7b64db1d98 100644
--- a/configure.in
+++ b/configure.in
@@ -1094,7 +1094,7 @@ AC_DEFUN(EVO_SET_COMPILE_FLAGS, [
dnl --- Required version numbers
GAL_REQUIRED=2.1.0
-GTKHTML_REQUIRED=3.1.1
+GTKHTML_REQUIRED=3.1.0
AC_SUBST(GAL_REQUIRED)
AC_SUBST(GTKHTML_REQUIRED)
@@ -1423,6 +1423,7 @@ default_user/local/Calendar/Makefile
default_user/local/Contacts/Makefile
default_user/local/Drafts/Makefile
default_user/local/Inbox/Makefile
+default_user/local/Junk/Makefile
default_user/local/Outbox/Makefile
default_user/local/Sent/Makefile
default_user/local/Tasks/Makefile
diff --git a/default_user/local/Makefile.am b/default_user/local/Makefile.am
index a1baef5052..71fc42640a 100644
--- a/default_user/local/Makefile.am
+++ b/default_user/local/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = \
Contacts \
Drafts \
Inbox \
+ Junk \
Outbox \
Sent \
Tasks \
diff --git a/filter/filtertypes.xml b/filter/filtertypes.xml
index 012ba62274..440cd6dddd 100644
--- a/filter/filtertypes.xml
+++ b/filter/filtertypes.xml
@@ -671,6 +671,9 @@
<option value="Seen">
<title>Read</title>
</option>
+ <option value="Spam">
+ <title>Spam</title>
+ </option>
</input>
</part>
<part name="unset-status">
@@ -694,6 +697,9 @@
<option value="Seen">
<title>Read</title>
</option>
+ <option value="Spam">
+ <title>Spam</title>
+ </option>
</input>
</part>
<part name="beep">
diff --git a/filter/libfilter-i18n.h b/filter/libfilter-i18n.h
index ea7ff03b0e..410ea7945f 100644
--- a/filter/libfilter-i18n.h
+++ b/filter/libfilter-i18n.h
@@ -32,6 +32,7 @@ char *s = N_("Set Status");
char *s = N_("Shell Command");
char *s = N_("Size (kB)");
char *s = N_("Source Account");
+char *s = N_("Spam");
char *s = N_("Specific header");
char *s = N_("Status");
char *s = N_("Stop Processing");
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 0d9a101462..417ee0be24 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -109,6 +109,10 @@ libevolution_mail_la_SOURCES = \
em-sync-stream.h \
em-icon-stream.c \
em-icon-stream.h \
+ em-junk-filter.c \
+ em-junk-filter.h \
+ em-junk-plugin.c \
+ em-junk-plugin.h \
em-html-stream.c \
em-html-stream.h \
folder-browser-factory.c \
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index 7dcdc1d9e8..e6274abe37 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -144,7 +144,8 @@ enum {
FOLDER_ICON_NORMAL,
FOLDER_ICON_INBOX,
FOLDER_ICON_OUTBOX,
- FOLDER_ICON_TRASH
+ FOLDER_ICON_TRASH,
+ FOLDER_ICON_JUNK
};
static GdkPixbuf *folder_icons[4];
@@ -163,6 +164,7 @@ render_pixbuf (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
folder_icons[1] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/inbox-mini.png");
folder_icons[2] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/outbox-mini.png");
folder_icons[3] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/evolution-trash-mini.png");
+ folder_icons[4] = gdk_pixbuf_load_from_file (EVOLUTION_ICONSDIR "/evolution-junk-mini.png");
initialised = TRUE;
}
@@ -176,6 +178,8 @@ render_pixbuf (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
pixbuf = folder_icons[FOLDER_ICON_OUTBOX];
else if (!strcasecmp (name, "/Trash"))
pixbuf = folder_icons[FOLDER_ICON_TRASH];
+ else if (!strcasecmp (name, "/Junk"))
+ pixbuf = folder_icons[FOLDER_ICON_JUNK];
else
pixbuf = folder_icons[FOLDER_ICON_NORMAL];
}
diff --git a/mail/em-folder-view.c b/mail/em-folder-view.c
index 0c52a49fe1..45fe46dbbb 100644
--- a/mail/em-folder-view.c
+++ b/mail/em-folder-view.c
@@ -524,6 +524,18 @@ emfv_popup_mark_unimportant(GtkWidget *w, EMFolderView *emfv)
}
static void
+emfv_popup_mark_junk (GtkWidget *w, EMFolderView *emfv)
+{
+ mail_mark_junk (emfv->folder, emfv->list, TRUE);
+}
+
+static void
+emfv_popup_mark_nojunk (GtkWidget *w, EMFolderView *emfv)
+{
+ mail_mark_junk (emfv->folder, emfv->list, FALSE);
+}
+
+static void
emfv_popup_delete(GtkWidget *w, EMFolderView *emfv)
{
GPtrArray *uids;
@@ -676,6 +688,8 @@ static EMPopupItem emfv_popup_menu[] = {
{ EM_POPUP_ITEM, "30.emfv.01", N_("Mark as _Unread"), G_CALLBACK(emfv_popup_mark_unread), NULL, "mail-new.xpm", EM_POPUP_SELECT_MARK_UNREAD },
{ EM_POPUP_ITEM, "30.emfv.02", N_("Mark as _Important"), G_CALLBACK(emfv_popup_mark_important), NULL, "priority-high.xpm", EM_POPUP_SELECT_MARK_IMPORTANT },
{ EM_POPUP_ITEM, "30.emfv.03", N_("_Mark as Unimportant"), G_CALLBACK(emfv_popup_mark_unimportant), NULL, NULL, EM_POPUP_SELECT_MARK_UNIMPORTANT },
+ { EM_POPUP_ITEM, "30.emfv.04", N_("Mark as _Junk"), G_CALLBACK(emfv_popup_mark_junk), NULL, NULL, EM_POPUP_SELECT_MARK_JUNK },
+ { EM_POPUP_ITEM, "30.emfv.05", N_("Mark as _Not Junk"), G_CALLBACK(emfv_popup_mark_nojunk), NULL, NULL, EM_POPUP_SELECT_MARK_NOJUNK },
{ EM_POPUP_BAR, "40.emfv" },
{ EM_POPUP_ITEM, "40.emfv.00", N_("_Delete"), G_CALLBACK(emfv_popup_delete), NULL, "evolution-trash-mini.png", EM_POPUP_SELECT_DELETE },
@@ -821,6 +835,8 @@ EMFV_MAP_CALLBACK(emfv_message_mark_read, emfv_popup_mark_read)
EMFV_MAP_CALLBACK(emfv_message_mark_unread, emfv_popup_mark_unread)
EMFV_MAP_CALLBACK(emfv_message_mark_important, emfv_popup_mark_important)
EMFV_MAP_CALLBACK(emfv_message_mark_unimportant, emfv_popup_mark_unimportant)
+EMFV_MAP_CALLBACK(emfv_message_mark_junk, emfv_popup_mark_junk)
+EMFV_MAP_CALLBACK(emfv_message_mark_nojunk, emfv_popup_mark_nojunk)
EMFV_MAP_CALLBACK(emfv_message_delete, emfv_popup_delete)
EMFV_MAP_CALLBACK(emfv_message_undelete, emfv_popup_undelete)
EMFV_MAP_CALLBACK(emfv_message_followup_flag, emfv_popup_flag_followup)
@@ -1246,6 +1262,8 @@ static BonoboUIVerb emfv_message_verbs[] = {
BONOBO_UI_UNSAFE_VERB ("MessageMarkAsUnRead", emfv_message_mark_unread),
BONOBO_UI_UNSAFE_VERB ("MessageMarkAsImportant", emfv_message_mark_important),
BONOBO_UI_UNSAFE_VERB ("MessageMarkAsUnimportant", emfv_message_mark_unimportant),
+ BONOBO_UI_UNSAFE_VERB ("MessageMarkAsJunk", emfv_message_mark_junk),
+ BONOBO_UI_UNSAFE_VERB ("MessageMarkAsNojunk", emfv_message_mark_nojunk),
BONOBO_UI_UNSAFE_VERB ("MessageFollowUpFlag", emfv_message_followup_flag),
BONOBO_UI_UNSAFE_VERB ("MessageMove", emfv_message_move),
BONOBO_UI_UNSAFE_VERB ("MessageOpen", emfv_message_open),
@@ -1348,6 +1366,8 @@ static const EMFolderViewEnable emfv_enable_map[] = {
{ "MessageMarkAsUnRead", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNREAD },
{ "MessageMarkAsImportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_IMPORTANT },
{ "MessageMarkAsUnimportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNIMPORTANT },
+ { "MessageMarkAsJunk", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_JUNK },
+ { "MessageMarkAsNojunk", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_NOJUNK },
{ "MessageFollowUpFlag", EM_POPUP_SELECT_MANY },
{ "MessageMove", EM_POPUP_SELECT_MANY },
{ "MessageOpen", EM_POPUP_SELECT_MANY },
diff --git a/mail/em-junk-filter.c b/mail/em-junk-filter.c
new file mode 100644
index 0000000000..04bbadc2ba
--- /dev/null
+++ b/mail/em-junk-filter.c
@@ -0,0 +1,327 @@
+/* -*- 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
+ */
+
+#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 <camel/camel-data-wrapper.h>
+#include <camel/camel-stream-fs.h>
+
+#include "em-junk-filter.h"
+
+#define LOCK(x) pthread_mutex_lock(&x)
+#define UNLOCK(x) pthread_mutex_unlock(&x)
+
+static pthread_mutex_t em_junk_sa_test_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static const char * em_junk_sa_get_name (void);
+static gboolean em_junk_sa_check_junk (CamelMimeMessage *msg);
+static void em_junk_sa_report_junk (CamelMimeMessage *msg);
+static void em_junk_sa_report_notjunk (CamelMimeMessage *msg);
+static void em_junk_sa_commit_reports (void);
+
+static EMJunkPlugin spam_assassin_plugin =
+{
+ {
+ em_junk_sa_get_name,
+ 1,
+ em_junk_sa_check_junk,
+ em_junk_sa_report_junk,
+ em_junk_sa_report_notjunk,
+ em_junk_sa_commit_reports,
+ },
+ NULL,
+ NULL
+};
+
+static gboolean em_junk_sa_spamd_tested = FALSE;
+static gboolean em_junk_sa_use_spamc = FALSE;
+static gint em_junk_sa_spamd_port = -1;
+
+#define d(x) x
+
+static const char *
+em_junk_sa_get_name (void)
+{
+ return _("Spamassassin (built-in)");
+}
+
+static int
+pipe_to_sa (CamelMimeMessage *msg, gchar *in, int argc, gchar **argv)
+{
+ CamelStream *stream;
+ int result, status;
+ int in_fds[2];
+ pid_t pid;
+
+ if (argc < 1 || argv[0] == '\0')
+ return 0;
+
+ if (pipe (in_fds) == -1) {
+ /* camel_exception_setv (fms->ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to create pipe to '%s': %s"),
+ argv[0]->value.string, g_strerror (errno)); */
+ return -1;
+ }
+
+ if (!(pid = fork ())) {
+ /* child process */
+ int maxfd, fd;
+
+ fd = open ("/dev/null", O_WRONLY);
+
+ if (dup2 (in_fds[0], STDIN_FILENO) < 0 ||
+ dup2 (fd, STDOUT_FILENO) < 0 ||
+ dup2 (fd, STDERR_FILENO) < 0)
+ _exit (255);
+
+ setsid ();
+
+ maxfd = sysconf (_SC_OPEN_MAX);
+ if (maxfd > 0) {
+ for (fd = 0; fd < maxfd; fd++) {
+ if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
+ close (fd);
+ }
+ }
+
+ execvp (argv [0], argv);
+
+ d(printf ("Could not execute %s: %s\n", argv [0], g_strerror (errno)));
+ _exit (255);
+ } else if (pid < 0) {
+ /* camel_exception_setv (fms->ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to create create child process '%s': %s"),
+ argv[0]->value.string, g_strerror (errno)); */
+ return -1;
+ }
+
+ /* parent process */
+ close (in_fds[0]);
+ fcntl (in_fds[1], F_SETFL, O_NONBLOCK);
+
+ if (msg) {
+ stream = camel_stream_fs_new_with_fd (in_fds[1]);
+
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (msg), stream);
+ camel_stream_flush (stream);
+ camel_object_unref (CAMEL_OBJECT (stream));
+ } else if (in) {
+ write (in_fds [1], in, strlen (in));
+ close (in_fds [1]);
+ }
+
+ result = waitpid (pid, &status, 0);
+
+ 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 -1;
+}
+
+
+#define NPORTS 1
+
+static int
+em_junk_sa_test_spamd_running (gint port)
+{
+ static gchar *sac_args [3] = {
+ "/bin/sh",
+ "-c",
+ NULL
+ };
+ int retval;
+
+ d(fprintf (stderr, "test if spamd is running (port %d)\n", port);)
+ sac_args [2] = port > 0 ? g_strdup_printf ("spamc -x -p %d", port) : g_strdup_printf ("spamc -x");
+
+ retval = pipe_to_sa (NULL, "From test@127.0.0.1", 3, sac_args) == 0;
+ g_free (sac_args [2]);
+
+ return retval;
+}
+
+static void
+em_junk_sa_test_spamd ()
+{
+ gint i, port = 7830;
+
+ em_junk_sa_use_spamc = FALSE;
+
+ /* if (em_junk_sa_test_spamd_running (-1)) {
+ em_junk_sa_use_spamc = TRUE;
+ em_junk_sa_spamd_port = -1;
+ } else { */
+ for (i = 0; i < NPORTS; i ++) {
+ if (em_junk_sa_test_spamd_running (port)) {
+ em_junk_sa_use_spamc = TRUE;
+ em_junk_sa_spamd_port = port;
+ break;
+ }
+ port ++;
+ }
+ /* } */
+
+ if (!em_junk_sa_use_spamc) {
+ static gchar *sad_args [3] = {
+ "/bin/sh",
+ "-c",
+ NULL
+ };
+ gint i, port = 7830;
+
+ d(fprintf (stderr, "looks like spamd is not running\n");)
+
+ for (i = 0; i < NPORTS; i ++) {
+ d(fprintf (stderr, "trying to run spamd at port %d\n", port));
+
+ sad_args [2] = g_strdup_printf ("spamd --port %d --local --daemonize", port);
+ if (!pipe_to_sa (NULL, NULL, 3, sad_args)) {
+ g_free (sad_args [2]);
+ em_junk_sa_use_spamc = TRUE;
+ em_junk_sa_spamd_port = port;
+ d(fprintf (stderr, "success at port %d\n", port));
+ break;
+ }
+ g_free (sad_args [2]);
+ port ++;
+ }
+ }
+
+ d(fprintf (stderr, "use spamd %d at port %d\n", em_junk_sa_use_spamc, em_junk_sa_spamd_port);)
+
+ em_junk_sa_spamd_tested = TRUE;
+}
+
+static gboolean
+em_junk_sa_check_junk (CamelMimeMessage *msg)
+{
+ static gchar *args [3] = {
+ "/bin/sh",
+ "-c",
+ NULL
+ };
+ gint retval;
+
+ d(fprintf (stderr, "em_junk_sa_check_junk\n"));
+
+ LOCK (em_junk_sa_test_lock);
+ if (!em_junk_sa_spamd_tested)
+ em_junk_sa_test_spamd ();
+ UNLOCK (em_junk_sa_test_lock);
+
+ args [2] = em_junk_sa_use_spamc
+ ? (em_junk_sa_spamd_port == -1
+ ? g_strdup ("spamc -c") /* Exit with a non-zero exit code if the
+ tested message was junk */
+ : g_strdup_printf ("spamc"
+ " -c" /* Exit with a non-zero exit code if the
+ tested message was junk */
+ " -p %d", em_junk_sa_spamd_port))
+ : g_strdup ("spamassassin"
+ " --exit-code" /* Exit with a non-zero exit code if the
+ tested message was junk */
+ " --local"); /* Local tests only (no online tests) */
+
+ retval = pipe_to_sa (msg, NULL, 3, args);
+
+ g_free (args [2]);
+
+ return retval;
+}
+
+static void
+em_junk_sa_report_junk (CamelMimeMessage *msg)
+{
+ static gchar *args [3] = {
+ "/bin/sh",
+ "-c",
+ "sa-learn"
+ " --no-rebuild" /* do not rebuild db */
+ " --spam" /* report junk */
+ " --single" /* single message */
+ " --local" /* local only */
+ };
+
+ d(fprintf (stderr, "em_junk_sa_report_junk\n");)
+
+ pipe_to_sa (msg, NULL, 3, args) > 0;
+}
+
+static void
+em_junk_sa_report_notjunk (CamelMimeMessage *msg)
+{
+ static gchar *args [3] = {
+ "/bin/sh",
+ "-c",
+ "sa-learn"
+ " --no-rebuild" /* do not rebuild db */
+ " --ham" /* report notjunk */
+ " --single" /* single message */
+ " --local" /* local only */
+ };
+
+ d(fprintf (stderr, "em_junk_sa_report_notjunk\n");)
+
+ pipe_to_sa (msg, NULL, 3, args) > 0;
+}
+
+static void
+em_junk_sa_commit_reports (void)
+{
+ static gchar *args [3] = {
+ "/bin/sh",
+ "-c",
+ "sa-learn"
+ " --rebuild" /* do not rebuild db */
+ " --local" /* local only */
+ };
+
+ d(fprintf (stderr, "em_junk_sa_commit_reports\n");)
+
+ pipe_to_sa (NULL, NULL, 3, args) > 0;
+}
+
+const EMJunkPlugin *
+em_junk_filter_get_plugin (void)
+{
+ return &spam_assassin_plugin;
+}
diff --git a/mail/em-junk-filter.h b/mail/em-junk-filter.h
new file mode 100644
index 0000000000..f62ca7bfad
--- /dev/null
+++ b/mail/em-junk-filter.h
@@ -0,0 +1,30 @@
+/* -*- 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
+ */
+
+#ifndef _EM_JUNK_FILTER_H
+#define _EM_JUNK_FILTER_H
+
+#include "em-junk-plugin.h"
+
+const EMJunkPlugin * em_junk_filter_get_plugin (void);
+
+#endif
diff --git a/mail/em-junk-plugin.c b/mail/em-junk-plugin.c
new file mode 100644
index 0000000000..5ea2a40119
--- /dev/null
+++ b/mail/em-junk-plugin.c
@@ -0,0 +1,24 @@
+/* -*- 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
+ */
+
+#include "em-junk-plugin.h"
+
diff --git a/mail/em-junk-plugin.h b/mail/em-junk-plugin.h
new file mode 100644
index 0000000000..0c7eacd165
--- /dev/null
+++ b/mail/em-junk-plugin.h
@@ -0,0 +1,47 @@
+/* -*- 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
+ */
+
+#ifndef _EM_JUNK_PLUGIN_H
+#define _EM_JUNK_PLUGIN_H
+
+#include <camel/camel-junk-plugin.h>
+#include <gtk/gtkwidget.h>
+
+#define EM_JUNK_PLUGIN(x) ((EMJunkPlugin *) x)
+
+typedef struct _EMJunkPlugin EMJunkPlugin;
+
+struct _EMJunkPlugin
+{
+ CamelJunkPlugin csp;
+
+ /* when called, it should insert own GUI configuration into supplied.
+ container. returns data pointer which is later passed to apply,
+ plugin has to call (*changed_cb) (); whenever configuration
+ is changed to notify settings dialog about a change.
+ if setup_config_ui is NULL, it means there are no options */
+
+ gpointer (*setup_config_ui) (GtkWidget *container, void (*changed_cb) ());
+ void (*apply) (gpointer data);
+};
+
+#endif
diff --git a/mail/em-popup.c b/mail/em-popup.c
index 63159848bf..760aed48d5 100644
--- a/mail/em-popup.c
+++ b/mail/em-popup.c
@@ -459,6 +459,11 @@ em_popup_target_new_select(struct _CamelFolder *folder, const char *folder_uri,
mask &= ~EM_POPUP_SELECT_MARK_UNIMPORTANT;
else
mask &= ~EM_POPUP_SELECT_MARK_IMPORTANT;
+
+ if (info->flags & CAMEL_MESSAGE_JUNK)
+ mask &= ~EM_POPUP_SELECT_MARK_NOJUNK;
+ else
+ mask &= ~EM_POPUP_SELECT_MARK_JUNK;
tmp = camel_tag_get (&info->user_tags, "follow-up");
if (tmp && *tmp) {
diff --git a/mail/em-popup.h b/mail/em-popup.h
index 0ad1d0015c..831d586efe 100644
--- a/mail/em-popup.h
+++ b/mail/em-popup.h
@@ -88,7 +88,9 @@ enum {
EM_POPUP_SELECT_FLAG_COMPLETED = 1<<12,
EM_POPUP_SELECT_FLAG_CLEAR = 1<<13,
EM_POPUP_SELECT_ADD_SENDER = 1<<14,
- EM_POPUP_SELECT_LAST = 1<<16 /* reserve 2 slots */
+ EM_POPUP_SELECT_MARK_JUNK = 1<<15,
+ EM_POPUP_SELECT_MARK_NOJUNK = 1<<16,
+ EM_POPUP_SELECT_LAST = 1<<18 /* reserve 2 slots */
};
/* Flags that describe a TARGET_URI */
diff --git a/mail/mail-component.c b/mail/mail-component.c
index f22cb656b3..ea20dae624 100644
--- a/mail/mail-component.c
+++ b/mail/mail-component.c
@@ -269,6 +269,12 @@ type_is_vtrash (const char *type)
return !strcmp (type, "vtrash");
}
+static inline gboolean
+type_is_vjunk (const char *type)
+{
+ return !strcmp (type, "vjunk");
+}
+
static void
storage_go_online (gpointer key, gpointer value, gpointer data)
{
@@ -410,6 +416,11 @@ create_view_callback (EStorageBrowser *browser,
control = folder_browser_factory_new_control ("vtrash:file:/");
else
control = folder_browser_factory_new_control (physical_uri);
+ } else if (type_is_vjunk (folder_type)) {
+ if (!strncasecmp (physical_uri, "file:", 5))
+ control = folder_browser_factory_new_control ("vjunk:file:/");
+ else
+ control = folder_browser_factory_new_control (physical_uri);
} else
return NULL;
diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c
index 3d4eb96d53..a75ed046e9 100644
--- a/mail/mail-folder-cache.c
+++ b/mail/mail-folder-cache.c
@@ -240,9 +240,17 @@ real_flush_updates(void *o, void *event_data, void *data)
g_warning ("No folder at %s ?!", up->path);
}
} else if (storage != NULL) {
- char *type = (strncmp(up->uri, "vtrash:", 7)==0)?"vtrash":"mail";
- EFolder *new_folder = e_folder_new (up->name, type, NULL);
+ char *type;
+ EFolder *new_folder;
+ if (strncmp(up->uri, "vtrash:", 7)==0) {
+ type = "vtrash";
+ } else if (strncmp(up->uri, "vjunk:", 6)==0) {
+ type = "vjunk";
+ } else
+ type = "mail";
+
+ new_folder = e_folder_new (up->name, type, NULL);
d(printf("Adding new folder: %s\n", up->path));
e_folder_set_physical_uri (new_folder, up->uri);
@@ -461,7 +469,7 @@ folder_changed (CamelObject *o, gpointer event_data, gpointer user_data)
if (mfi->folder != folder)
return;
- if (!CAMEL_IS_VTRASH_FOLDER (folder) && folder != outbox_folder && folder != sent_folder && changes && changes->uid_added)
+ if (!CAMEL_IS_VTRASH_FOLDER (folder) && !CAMEL_IS_VJUNK_FOLDER (folder) && folder != outbox_folder && folder != sent_folder && changes && changes->uid_added)
new = changes->uid_added->len;
LOCK(info_lock);
diff --git a/mail/mail-ops.c b/mail/mail-ops.c
index 8d3711ff4e..b7aad2e55b 100644
--- a/mail/mail-ops.c
+++ b/mail/mail-ops.c
@@ -1063,9 +1063,9 @@ get_folderinfo_desc (struct _mail_msg *mm, int done)
}
static void
-add_vtrash_info (CamelStore *store, CamelFolderInfo *info)
+add_vtrash_or_vjunk_info (CamelStore *store, CamelFolderInfo *info, gchar *name, gchar *full_name, gchar *url_base, gboolean unread_count)
{
- CamelFolderInfo *fi, *vtrash, *parent;
+ CamelFolderInfo *fi, *vinfo, *parent;
char *uri, *path;
CamelURL *url;
@@ -1073,14 +1073,14 @@ add_vtrash_info (CamelStore *store, CamelFolderInfo *info)
parent = NULL;
for (fi = info; fi; fi = fi->sibling) {
- if (!strcmp (fi->name, CAMEL_VTRASH_NAME))
+ if (!strcmp (fi->name, name))
break;
parent = fi;
}
- /* create our vTrash URL */
+ /* create our vTrash/vJunk URL */
url = camel_url_new (info->url, NULL);
- path = g_strdup_printf ("/%s", CAMEL_VTRASH_NAME);
+ path = g_strdup_printf ("/%s", name);
if (url->fragment)
camel_url_set_fragment (url, path);
else
@@ -1090,32 +1090,45 @@ add_vtrash_info (CamelStore *store, CamelFolderInfo *info)
camel_url_free (url);
if (fi) {
- /* We're going to replace the physical Trash folder with our vTrash folder */
- vtrash = fi;
- g_free (vtrash->full_name);
- g_free (vtrash->name);
- g_free (vtrash->url);
+ /* We're going to replace the physical Trash/Junk folder with our vTrash/vJunk folder */
+ vinfo = fi;
+ g_free (vinfo->full_name);
+ g_free (vinfo->name);
+ g_free (vinfo->url);
} else {
- /* There wasn't a Trash folder so create a new folder entry */
- vtrash = g_new0 (CamelFolderInfo, 1);
+ /* There wasn't a Trash/Junk folder so create a new folder entry */
+ vinfo = g_new0 (CamelFolderInfo, 1);
g_assert(parent != NULL);
/* link it into the right spot */
- vtrash->sibling = parent->sibling;
- parent->sibling = vtrash;
+ vinfo->sibling = parent->sibling;
+ parent->sibling = vinfo;
}
/* Fill in the new fields */
- vtrash->full_name = g_strdup (_("Trash"));
- vtrash->name = g_strdup(vtrash->full_name);
- vtrash->url = g_strdup_printf ("vtrash:%s", uri);
- vtrash->unread_message_count = -1;
- vtrash->path = g_strdup_printf("/%s", vtrash->name);
+ vinfo->full_name = g_strdup (full_name);
+ vinfo->name = g_strdup(vinfo->full_name);
+ vinfo->url = g_strdup_printf ("%s:%s", url_base, uri);
+ if (!unread_count)
+ vinfo->unread_message_count = -1;
+ vinfo->path = g_strdup_printf("/%s", vinfo->name);
g_free (uri);
}
static void
+add_vtrash_info (CamelStore *store, CamelFolderInfo *info)
+{
+ add_vtrash_or_vjunk_info (store, info, CAMEL_VTRASH_NAME, _("Trash"), "vtrash", FALSE);
+}
+
+static void
+add_vjunk_info (CamelStore *store, CamelFolderInfo *info)
+{
+ add_vtrash_or_vjunk_info (store, info, CAMEL_VJUNK_NAME, _("Junk"), "vjunk", TRUE);
+}
+
+static void
add_unmatched_info(CamelFolderInfo *fi)
{
for (; fi; fi = fi->sibling) {
@@ -1142,6 +1155,8 @@ get_folderinfo_get (struct _mail_msg *mm)
if (m->info) {
if (m->info->url && (m->store->flags & CAMEL_STORE_VTRASH))
add_vtrash_info(m->store, m->info);
+ if (m->info->url && (m->store->flags & CAMEL_STORE_VJUNK))
+ add_vjunk_info(m->store, m->info);
if (CAMEL_IS_VEE_STORE(m->store))
add_unmatched_info(m->info);
}
@@ -2329,3 +2344,101 @@ mail_execute_shell_command (CamelFilterDriver *driver, int argc, char **argv, vo
gnome_execute_async_fds (NULL, argc, argv, TRUE);
}
+
+/* [Un]mark junk flag */
+
+struct _mark_junk_mail_msg {
+ struct _mail_msg msg;
+
+ CamelFolder *folder;
+ MessageList *list;
+ gboolean junk;
+};
+
+static char *
+mark_junk_describe (struct _mail_msg *mm, int complete)
+{
+ return g_strdup (_("Changing junk status"));
+}
+
+/* filter a folder, or a subset thereof, uses source_folder/source_uids */
+/* this is shared with fetch_mail */
+static void
+mark_junk_mark (struct _mail_msg *mm)
+{
+ struct _mark_junk_mail_msg *m = (struct _mark_junk_mail_msg *) mm;
+ CamelJunkPlugin *csp = NULL;
+ GPtrArray *uids;
+ gboolean commit_reports = FALSE;
+ int i;
+
+ if (m->folder == NULL)
+ return;
+
+ uids = message_list_get_selected (m->list);
+ camel_folder_freeze (m->folder);
+
+ for (i=0; i<uids->len; i++) {
+ guint32 flags;
+
+ flags = camel_folder_get_message_flags (m->folder, uids->pdata[i]);
+ if (((flags & CAMEL_MESSAGE_JUNK) == CAMEL_MESSAGE_JUNK) != m->junk) {
+ CamelMimeMessage *msg = camel_folder_get_message (m->folder, uids->pdata[i], NULL);
+
+ if (msg) {
+ csp = CAMEL_SERVICE (m->folder->parent_store)->session->junk_plugin;
+ if (m->junk)
+ camel_junk_plugin_report_junk (csp, msg);
+ else
+ camel_junk_plugin_report_notjunk (csp, msg);
+
+ commit_reports = TRUE;
+ camel_object_unref (msg);
+ }
+ }
+ camel_folder_set_message_flags(m->folder, uids->pdata[i],
+ CAMEL_MESSAGE_JUNK | (m->junk ? CAMEL_MESSAGE_DELETED : 0),
+ m->junk ? CAMEL_MESSAGE_JUNK : 0);
+ }
+
+ if (commit_reports)
+ camel_junk_plugin_commit_reports (csp);
+
+ message_list_free_uids(m->list, uids);
+ camel_folder_thaw(m->folder);
+}
+
+static void
+mark_junk_marked (struct _mail_msg *mm)
+{
+}
+
+static void
+mark_junk_free (struct _mail_msg *mm)
+{
+ struct _mark_junk_mail_msg *m = (struct _mark_junk_mail_msg *)mm;
+
+ if (m->folder)
+ camel_object_unref (m->folder);
+}
+
+static struct _mail_msg_op mark_junk_op = {
+ mark_junk_describe,
+ mark_junk_mark,
+ mark_junk_marked,
+ mark_junk_free,
+};
+
+void
+mail_mark_junk (CamelFolder *folder, MessageList *list, gboolean junk)
+{
+ struct _mark_junk_mail_msg *m;
+
+ m = mail_msg_new (&mark_junk_op, NULL, sizeof (*m));
+ m->folder = folder;
+ camel_object_ref (folder);
+ m->list = list;
+ m->junk = junk;
+
+ e_thread_put (mail_thread_new, (EMsg *) m);
+}
diff --git a/mail/mail-ops.h b/mail/mail-ops.h
index e15d7729c2..081e1a1425 100644
--- a/mail/mail-ops.h
+++ b/mail/mail-ops.h
@@ -36,6 +36,8 @@ extern "C" {
#include "camel/camel-mime-message.h"
#include "camel/camel-operation.h"
+#include "message-list.h"
+
#include "evolution-storage.h" /*EvolutionStorage */
#include "e-util/e-msgport.h"
#include "e-util/e-account.h"
@@ -164,6 +166,8 @@ int mail_store_set_offline(CamelStore *store, gboolean offline,
/* filter driver execute shell command async callback */
void mail_execute_shell_command (CamelFilterDriver *driver, int argc, char **argv, void *data);
+void mail_mark_junk (CamelFolder *folder, MessageList *list, gboolean junk);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/mail/mail-session.c b/mail/mail-session.c
index 58773513c4..0db6f38ba8 100644
--- a/mail/mail-session.c
+++ b/mail/mail-session.c
@@ -48,6 +48,7 @@
#include "mail-ops.h"
#include "e-util/e-passwords.h"
#include "e-util/e-msgport.h"
+#include "em-junk-filter.h"
#define d(x)
@@ -626,6 +627,9 @@ main_get_filter_driver (CamelSession *session, const char *type, CamelException
fsearch = g_string_new ("");
faction = g_string_new ("");
+
+ /* implicit junk check as 1st rule */
+ camel_filter_driver_add_rule (driver, "Junk check", "(junk-test)", "(begin (set-system-flag \"junk\"))");
/* add the user-defined rules next */
while ((rule = rule_context_next_rule (fc, rule, type))) {
@@ -634,7 +638,6 @@ main_get_filter_driver (CamelSession *session, const char *type, CamelException
filter_rule_build_code (rule, fsearch);
filter_filter_build_action ((FilterFilter *) rule, faction);
-
camel_filter_driver_add_rule (driver, rule->name, fsearch->str, faction->str);
}
@@ -755,6 +758,8 @@ mail_session_init (const char *base_directory)
camel_dir = g_strdup_printf ("%s/mail", base_directory);
camel_session_construct (session, camel_dir);
+
+ session->junk_plugin = CAMEL_JUNK_PLUGIN (em_junk_filter_get_plugin ());
/* The shell will tell us to go online. */
camel_session_set_online ((CamelSession *) session, FALSE);
diff --git a/mail/mail-tools.c b/mail/mail-tools.c
index b85a18c12f..0538efd354 100644
--- a/mail/mail-tools.c
+++ b/mail/mail-tools.c
@@ -312,6 +312,8 @@ mail_tool_uri_to_folder (const char *uri, guint32 flags, CamelException *ex)
/* This hack is still needed for file:/ since it's its own EvolutionStorage type */
if (!strncmp (uri, "vtrash:", 7))
offset = 7;
+ else if (!strncmp (uri, "vjunk:", 6))
+ offset = 6;
url = camel_url_new (uri + offset, ex);
if (!url) {
@@ -333,9 +335,14 @@ mail_tool_uri_to_folder (const char *uri, guint32 flags, CamelException *ex)
name = "";
}
- if (offset)
- folder = camel_store_get_trash (store, ex);
- else
+ if (offset) {
+ if (offset == 7)
+ folder = camel_store_get_trash (store, ex);
+ else if (offset == 6)
+ folder = camel_store_get_junk (store, ex);
+ else
+ g_assert (FALSE);
+ } else
folder = camel_store_get_folder (store, name, flags, ex);
camel_object_unref (store);
}
diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c
index f47fe4c660..2bb08a587e 100644
--- a/mail/mail-vfolder.c
+++ b/mail/mail-vfolder.c
@@ -345,7 +345,7 @@ mail_vfolder_add_uri(CamelStore *store, const char *uri, int remove)
GCompareFunc uri_cmp = CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name;
int is_ignore;
- if (CAMEL_IS_VEE_STORE(store) || !strncmp(uri, "vtrash:", 7) || context == NULL)
+ if (CAMEL_IS_VEE_STORE(store) || !strncmp(uri, "vtrash:", 7) || !strncmp(uri, "vjunk:", 6) || context == NULL)
return;
g_assert(pthread_self() == mail_gui_thread);
@@ -426,7 +426,7 @@ mail_vfolder_delete_uri(CamelStore *store, const char *uri)
CamelVeeFolder *vf;
GString *changed;
- if (context == NULL || !strncmp(uri, "vtrash:", 7))
+ if (context == NULL || !strncmp(uri, "vtrash:", 7) || !strncmp(uri, "vjunk:", 6))
return;
d(printf ("Deleting uri to check: %s\n", uri));
@@ -492,7 +492,7 @@ mail_vfolder_rename_uri(CamelStore *store, const char *from, const char *to)
d(printf("vfolder rename uri: %s to %s\n", from, to));
- if (context == NULL || !strncmp(from, "vtrash:", 7) || !strncmp(to, "vtrash:", 7))
+ if (context == NULL || !strncmp(from, "vtrash:", 7) || !strncmp(to, "vtrash:", 7) || !strncmp(from, "vjunk:", 6) || !strncmp(to, "vjunk:", 6))
return;
g_assert(pthread_self() == mail_gui_thread);
diff --git a/mail/message-list.c b/mail/message-list.c
index a16c40f265..430d2f4896 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -188,6 +188,9 @@ static struct {
{ NULL, NULL }
};
+/* FIXME: junk prefs */
+static gboolean junk_folder = TRUE;
+
#ifdef SMART_ADDRESS_COMPARE
static EMailAddress *
e_mail_address_new (const char *address)
@@ -2377,11 +2380,44 @@ build_flat_diff(MessageList *ml, CamelFolderChangeInfo *changes)
static void
+mail_folder_hide_by_flag (CamelFolder *folder, MessageList *ml, CamelFolderChangeInfo **changes, int flag)
+{
+ CamelFolderChangeInfo *newchanges, *oldchanges = *changes;
+ CamelMessageInfo *info;
+ int i;
+
+ newchanges = camel_folder_change_info_new ();
+
+ for (i = 0; i < oldchanges->uid_changed->len; i++) {
+ ETreePath node = g_hash_table_lookup (ml->uid_nodemap, oldchanges->uid_changed->pdata[i]);
+
+ info = camel_folder_get_message_info (folder, oldchanges->uid_changed->pdata[i]);
+ if (node != NULL && info != NULL && (info->flags & flag) != 0)
+ camel_folder_change_info_remove_uid (newchanges, oldchanges->uid_changed->pdata[i]);
+ else if (node == NULL && info != NULL && (info->flags & flag) == 0)
+ camel_folder_change_info_add_uid (newchanges, oldchanges->uid_changed->pdata[i]);
+ else
+ camel_folder_change_info_change_uid (newchanges, oldchanges->uid_changed->pdata[i]);
+ camel_folder_free_message_info (folder, info);
+ }
+
+ if (newchanges->uid_added->len > 0 || newchanges->uid_removed->len > 0) {
+ for (i = 0; i < oldchanges->uid_added->len; i++)
+ camel_folder_change_info_add_uid (newchanges, oldchanges->uid_added->pdata[i]);
+ for (i = 0; i < oldchanges->uid_removed->len; i++)
+ camel_folder_change_info_remove_uid (newchanges, oldchanges->uid_removed->pdata[i]);
+ camel_folder_change_info_free (oldchanges);
+ *changes = newchanges;
+ } else {
+ camel_folder_change_info_free (newchanges);
+ }
+}
+
+static void
main_folder_changed (CamelObject *o, gpointer event_data, gpointer user_data)
{
MessageList *ml = MESSAGE_LIST (user_data);
- CamelFolderChangeInfo *changes = (CamelFolderChangeInfo *)event_data, *newchanges;
- CamelMessageInfo *info;
+ CamelFolderChangeInfo *changes = (CamelFolderChangeInfo *)event_data;
CamelFolder *folder = (CamelFolder *)o;
int i;
@@ -2402,35 +2438,9 @@ main_folder_changed (CamelObject *o, gpointer event_data, gpointer user_data)
}
/* check if the hidden state has changed, if so modify accordingly, then regenerate */
- if (ml->hidedeleted) {
- newchanges = camel_folder_change_info_new ();
-
- for (i = 0; i < changes->uid_changed->len; i++) {
- ETreePath node = g_hash_table_lookup (ml->uid_nodemap, changes->uid_changed->pdata[i]);
-
- info = camel_folder_get_message_info (folder, changes->uid_changed->pdata[i]);
- if (node != NULL && info != NULL && (info->flags & CAMEL_MESSAGE_DELETED) != 0) {
- camel_folder_change_info_remove_uid (newchanges, changes->uid_changed->pdata[i]);
- } else if (node == NULL && info != NULL && (info->flags & CAMEL_MESSAGE_DELETED) == 0) {
- camel_folder_change_info_add_uid (newchanges, changes->uid_changed->pdata[i]);
- } else {
- camel_folder_change_info_change_uid (newchanges, changes->uid_changed->pdata[i]);
- }
- camel_folder_free_message_info (folder, info);
- }
-
- if (newchanges->uid_added->len > 0 || newchanges->uid_removed->len > 0) {
- for (i = 0; i < changes->uid_added->len; i++)
- camel_folder_change_info_add_uid (newchanges, changes->uid_added->pdata[i]);
- for (i = 0; i < changes->uid_removed->len; i++)
- camel_folder_change_info_remove_uid (newchanges, changes->uid_removed->pdata[i]);
- camel_folder_change_info_free (changes);
- changes = newchanges;
- } else {
- camel_folder_change_info_free (newchanges);
- }
- }
-
+ if (ml->hidejunk || ml->hidedeleted)
+ mail_folder_hide_by_flag (folder, ml, &changes, (ml->hidejunk ? CAMEL_MESSAGE_JUNK : 0) | (ml->hidedeleted ? CAMEL_MESSAGE_DELETED : 0));
+
if (changes->uid_added->len == 0 && changes->uid_removed->len == 0 && changes->uid_changed->len < 100) {
for (i = 0; i < changes->uid_changed->len; i++) {
ETreePath node = g_hash_table_lookup (ml->uid_nodemap, changes->uid_changed->pdata[i]);
@@ -2579,6 +2589,7 @@ message_list_set_folder (MessageList *message_list, CamelFolder *folder, const c
gconf = mail_config_get_gconf_client ();
hide_deleted = !gconf_client_get_bool (gconf, "/apps/evolution/mail/display/show_deleted", NULL);
message_list->hidedeleted = hide_deleted && !(folder->folder_flags & CAMEL_FOLDER_IS_TRASH);
+ message_list->hidejunk = junk_folder && !(folder->folder_flags & CAMEL_FOLDER_IS_JUNK) && !(folder->folder_flags & CAMEL_FOLDER_IS_TRASH);
hide_load_state (message_list);
mail_regen_list (message_list, message_list->search, NULL, NULL);
@@ -3038,6 +3049,7 @@ struct _regen_list_msg {
CamelFolderChangeInfo *changes;
gboolean dotree; /* we are building a tree */
gboolean hidedel; /* we want to/dont want to show deleted messages */
+ gboolean hidejunk; /* we want to/dont want to show junk messages */
gboolean thread_subject;
CamelFolderThread *tree;
@@ -3076,17 +3088,36 @@ regen_list_regen (struct _mail_msg *mm)
} else if (m->hidedel) {
char *expr;
- if (m->search) {
- expr = alloca(strlen(m->search) + 64);
- sprintf(expr, "(and (match-all (not (system-flag \"deleted\")))\n %s)", m->search);
- } else
- expr = "(match-all (not (system-flag \"deleted\")))";
+ if (m->hidejunk) {
+ if (m->search) {
+ expr = alloca(strlen(m->search) + 92);
+ sprintf(expr, "(and (match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\"))))\n %s)", m->search);
+ } else
+ expr = "(match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\"))))";
+ } else {
+ if (m->search) {
+ expr = alloca(strlen(m->search) + 64);
+ sprintf(expr, "(and (match-all (not (system-flag \"deleted\")))\n %s)", m->search);
+ } else
+ expr = "(match-all (not (system-flag \"deleted\")))";
+ }
searchuids = uids = camel_folder_search_by_expression (m->folder, expr, &mm->ex);
} else {
- if (m->search)
- searchuids = uids = camel_folder_search_by_expression (m->folder, m->search, &mm->ex);
- else
- uids = camel_folder_get_uids (m->folder);
+ char *expr;
+
+ if (m->hidejunk) {
+ if (m->search) {
+ expr = alloca(strlen(m->search) + 64);
+ sprintf(expr, "(and (match-all (not (system-flag \"junk\")))\n %s)", m->search);
+ } else
+ expr = "(match-all (not (system-flag \"junk\")))";
+ searchuids = uids = camel_folder_search_by_expression (m->folder, expr, &mm->ex);
+ } else {
+ if (m->search)
+ searchuids = uids = camel_folder_search_by_expression (m->folder, m->search, &mm->ex);
+ else
+ uids = camel_folder_get_uids (m->folder);
+ }
}
if (camel_exception_is_set (&mm->ex))
@@ -3318,6 +3349,7 @@ mail_regen_list (MessageList *ml, const char *search, const char *hideexpr, Came
m->changes = changes;
m->dotree = ml->threaded;
m->hidedel = ml->hidedeleted;
+ m->hidejunk = ml->hidejunk;
m->thread_subject = gconf_client_get_bool (gconf, "/apps/evolution/mail/display/thread_subject", NULL);
g_object_ref(ml);
m->folder = ml->folder;
diff --git a/mail/message-list.h b/mail/message-list.h
index a5c88cf308..8052ed791b 100644
--- a/mail/message-list.h
+++ b/mail/message-list.h
@@ -113,6 +113,9 @@ struct _MessageList {
/* do we automatically hide deleted messages? */
guint hidedeleted : 1;
+
+ /* do we automatically hide junk messages? */
+ guint hidejunk : 1;
/* is the message-list object in a destroyed state? */
guint destroyed : 1;
diff --git a/shell/e-local-storage.c b/shell/e-local-storage.c
index 8ce9f87189..01009cb805 100644
--- a/shell/e-local-storage.c
+++ b/shell/e-local-storage.c
@@ -182,6 +182,7 @@ setup_stock_folders (ELocalStorage *local_storage)
setup_folder_as_stock (local_storage, "/Sent", _("Sent"), NULL);
setup_folder_as_stock (local_storage, "/Tasks", _("Tasks"), NULL);
setup_folder_as_stock (local_storage, "/Trash", _("Trash"), NULL);
+ setup_folder_as_stock (local_storage, "/Spam", _("Spam"), NULL);
}
static gboolean
diff --git a/shell/e-shortcuts.c b/shell/e-shortcuts.c
index 697f50fe90..2672dc251d 100644
--- a/shell/e-shortcuts.c
+++ b/shell/e-shortcuts.c
@@ -27,6 +27,7 @@
<group title="Evolution shortcuts">
<item name="Inbox" type="mail">evolution:/local/Inbox</item>
<item name="Trash" type="vtrash">evolution:/local/Trash</item>
+ <item name="Spam" type="vspam">evolution:/local/Spam</item>
<item name="Calendar" type="calendar">evolution:/local/Calendar</item>
</group>
diff --git a/ui/evolution-mail-message.xml b/ui/evolution-mail-message.xml
index 7992c36be2..1d0af52295 100644
--- a/ui/evolution-mail-message.xml
+++ b/ui/evolution-mail-message.xml
@@ -97,6 +97,13 @@
<cmd name="MessageMarkAsUnimportant"
_tip="Mark the selected message(s) as unimportant"/>
+ <cmd name="MessageMarkAsJunk"
+ _tip="Mark the selected message(s) as junk"
+ pixtype="pixbuf"/>
+
+ <cmd name="MessageMarkAsNoJunk"
+ _tip="Mark the selected message(s) as not being junk"/>
+
<cmd name="MessageMove"
_tip="Move selected message(s) to another folder"
accel="*Control**Shift*v"
@@ -268,6 +275,8 @@
<menuitem name="MessageMarkAsUnRead" verb="" _label="Mark as U_nread"/>
<menuitem name="MessageMarkAsImportant" verb="" _label="Mark as I_mportant"/>
<menuitem name="MessageMarkAsUnimportant" verb="" _label="Mark as Unimp_ortant"/>
+ <menuitem name="MessageMarkAsJunk" verb="" _label="Mark as _Junk"/>
+ <menuitem name="MessageMarkAsNojunk" verb="" _label="Mark as _Not Junk"/>
</placeholder>
</submenu>
</placeholder>