[evolution-patches] New hook for junk plugin
- From: Vivek Jain <jvivek novell com>
- To: "evolution-patches lists ximian com" <evolution-patches lists ximian com>
- Subject: [evolution-patches] New hook for junk plugin
- Date: Thu, 23 Jun 2005 21:10:50 +0530
hi,
I have created a hook that wraps up camelJunkPlugin and allows its
methods to be exposed to the plugins. Using this hook one can write a
plugin to use its own method for spam handling. As an example I have
moved the spamassasin junk mail handling to a plugin which used this new
hook.
I have added two files em-format-hook.c em-format-hook.h in the /mail
and removed em-junk-filter.[ch] from here. I have moved em-junk-filter.c
to the newly written sa-junk-plugin.
I am attaching the following:
1. Patch for mail/
2. two new files
3. sa-junk-plugin
Thanks,
Vivek Jain
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/mail/ChangeLog,v
retrieving revision 1.3647
diff -u -p -r1.3647 ChangeLog
--- ChangeLog 21 Jun 2005 05:33:47 -0000 1.3647
+++ ChangeLog 23 Jun 2005 15:27:39 -0000
@@ -1,3 +1,15 @@
+2005-06-23 Vivek Jain <jvivek novell com>
+
+ * em-junk-filter.c : moved to a sa-junk-plugin
+ * em-junk-filter.h :removed
+ * em-junk.plugin.[ch]: removed
+ * em-junk-hook.[ch] : added new files to have a new hook
+ * mail-session.c: (mail_session_init): use
+ em_junk_get_plugin to get the junk plugin
+ * mail-component-factory.c : (make_factory)
+ register em junk hook
+ * Makefile.am :updated to removed/add these files.
+
2005-06-21 Brian Mury <b mury ieee org>
** See bug #301466.
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution/mail/Makefile.am,v
retrieving revision 1.263
diff -u -p -r1.263 Makefile.am
--- Makefile.am 2 Jun 2005 04:30:16 -0000 1.263
+++ Makefile.am 23 Jun 2005 15:27:39 -0000
@@ -80,6 +80,7 @@ mailinclude_HEADERS = \
em-folder-utils.h \
em-folder-view.h \
em-format-hook.h \
+ em-junk-hook.h \
em-format-html-display.h \
em-format-html-print.h \
em-format-html.h \
@@ -147,6 +148,7 @@ libevolution_mail_la_SOURCES = \
em-folder-utils.c \
em-folder-view.c \
em-format-hook.c \
+ em-junk-hook.c \
em-format-html-display.c \
em-format-html-print.c \
em-format-html.c \
@@ -155,10 +157,6 @@ libevolution_mail_la_SOURCES = \
em-html-stream.c \
em-icon-stream.c \
em-inline-filter.c \
- em-junk-filter.c \
- em-junk-filter.h \
- em-junk-plugin.c \
- em-junk-plugin.h \
em-mailer-prefs.c \
em-mailer-prefs.h \
em-menu.c \
Index: mail-session.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-session.c,v
retrieving revision 1.104
diff -u -p -r1.104 mail-session.c
--- mail-session.c 16 May 2005 06:15:38 -0000 1.104
+++ mail-session.c 23 Jun 2005 15:27:39 -0000
@@ -54,7 +54,6 @@
#include "mail-ops.h"
#include <libedataserverui/e-passwords.h>
#include "libedataserver/e-msgport.h"
-#include "em-junk-filter.h"
#include "e-util/e-error.h"
#define d(x)
@@ -645,7 +644,7 @@ mail_session_init (const char *base_dire
session_check_junk_notify_id = gconf_client_notify_add (gconf, "/apps/evolution/mail/junk",
(GConfClientNotifyFunc) mail_session_check_junk_notify,
session, NULL, NULL);
- session->junk_plugin = CAMEL_JUNK_PLUGIN (em_junk_filter_get_plugin ());
+ session->junk_plugin = CAMEL_JUNK_PLUGIN (em_junk_get_plugin ());
if (session->junk_plugin)
camel_junk_plugin_init (session->junk_plugin);
Index: mail-component-factory.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-component-factory.c,v
retrieving revision 1.15
diff -u -p -r1.15 mail-component-factory.c
--- mail-component-factory.c 8 Dec 2004 01:58:48 -0000 1.15
+++ mail-component-factory.c 23 Jun 2005 15:27:39 -0000
@@ -40,6 +40,7 @@
#include "em-event.h"
#include "em-config.h"
#include "em-format-hook.h"
+#include "em-junk-hook.h"
#include "em-format-html-display.h"
#include "importers/mail-importer.h"
@@ -96,12 +97,12 @@ make_factory (PortableServer_POA poa, co
e_plugin_hook_register_type(em_popup_hook_get_type());
e_plugin_hook_register_type(em_menu_hook_get_type());
e_plugin_hook_register_type(em_config_hook_get_type());
-
em_format_hook_register_type(em_format_get_type());
+ em_junk_hook_register_type(emj_get_type());
em_format_hook_register_type(em_format_html_get_type());
em_format_hook_register_type(em_format_html_display_get_type());
e_plugin_hook_register_type(em_format_hook_get_type());
-
+ e_plugin_hook_register_type(em_junk_hook_get_type());
e_plugin_hook_register_type(em_event_hook_get_type());
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors: Vivek Jain <jvivek novell com>
*
* Copyright 2004 Novell, Inc. (www.novell.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include "em-junk-hook.h"
#include <e-util/e-icon-factory.h>
#include <camel/camel-junk-plugin.h>
#include <glib/gi18n.h>
static GHashTable *emjh_types;
static GObjectClass *parent_class = NULL;
static void *emjh_parent_class;
static GObjectClass *emj_parent;
#define emjh ((EMJunkHook *)eph)
#define d(x)
static void em_junk_get_name();
static gboolean em_junk_check_junk(CamelMimeMessage *m);
static void em_junk_report_junk(CamelMimeMessage *m);
static void em_junk_report_non_junk(CamelMimeMessage *m);
static void em_junk_commit_reports();
static void em_junk_init();
static const EPluginHookTargetKey emjh_flag_map[] = {
{ 0 }
};
static EMJunk junk_plugin = {
{
em_junk_get_name,
1,
em_junk_check_junk,
em_junk_report_junk,
em_junk_report_non_junk,
em_junk_commit_reports,
em_junk_init,
}
};
static struct _EMJunkHookItem *item = NULL;
EMJunk *
em_junk_get_plugin()
{
return &junk_plugin;
}
static void
em_junk_init()
{
}
static void
em_junk_get_name()
{
}
static gboolean
em_junk_check_junk(CamelMimeMessage *m)
{
if (item->hook->hook.plugin->enabled) {
EMJunkHookTarget target = {
item, m
};
e_plugin_invoke(item->hook->hook.plugin, item->check_junk, &target);
}
}
static void
em_junk_report_junk(CamelMimeMessage *m)
{
if (item->hook->hook.plugin->enabled) {
EMJunkHookTarget target = {
item, m
};
e_plugin_invoke(item->hook->hook.plugin, item->report_junk, &target);
}
}
static void
em_junk_report_non_junk(CamelMimeMessage *m)
{
if (item->hook->hook.plugin->enabled) {
EMJunkHookTarget target = {
item, m
};
e_plugin_invoke(item->hook->hook.plugin, item->report_non_junk, &target);
}
}
static void
em_junk_commit_reports()
{
if (item->hook->hook.plugin->enabled) {
EMJunkHookTarget target = {
item, NULL
};
e_plugin_invoke(item->hook->hook.plugin, item->commit_reports, &target);
}
}
static void
emj_dispose (GObject *object)
{
if (parent_class->dispose)
(* parent_class->dispose) (object);
}
static void
emj_finalize (GObject *object)
{
if (parent_class->finalize)
(* parent_class->finalize) (object);
}
static void
emjh_free_item(struct _EMFormatHookItem *item)
{
g_free(item);
}
static void
emjh_free_group(struct _EMJunkHookGroup *group)
{
g_slist_foreach(group->items, (GFunc)emjh_free_item, NULL);
g_slist_free(group->items);
g_free(group->id);
g_free(group);
}
static struct _EMJunkHookItem *
emjh_construct_item(EPluginHook *eph, EMJunkHookGroup *group, xmlNodePtr root)
{
d(printf(" loading group item\n"));
item = g_malloc0(sizeof(*item));
item->check_junk = e_plugin_xml_prop(root, "check_junk");
item->report_junk = e_plugin_xml_prop(root, "report_junk");
item->report_non_junk = e_plugin_xml_prop(root, "report_non_junk");
item->commit_reports = e_plugin_xml_prop(root, "commit_reports");
item->hook = emjh;
return item;
}
static struct _EMJunkHookGroup *
emjh_construct_group(EPluginHook *eph, xmlNodePtr root)
{
struct _EMJunkHookGroup *group;
xmlNodePtr node;
d(printf(" loading group\n"));
group = g_malloc0(sizeof(*group));
group->id = e_plugin_xml_prop(root, "id");
if (group->id == NULL)
goto error;
node = root->children;
while (node) {
if (0 == strcmp(node->name, "item")) {
struct _EMJunkHookItem *item;
item = emjh_construct_item(eph, group, node);
if (item)
group->items = g_slist_append(group->items, item);
}
node = node->next;
}
return group;
error:
emjh_free_group(group);
return NULL;
}
static int
emjh_construct(EPluginHook *eph, EPlugin *ep, xmlNodePtr root)
{
xmlNodePtr node;
d(printf("loading junk hook\n"));
if (((EPluginHookClass *)emjh_parent_class)->construct(eph, ep, root) == -1)
return -1;
node = root->children;
while (node) {
if (strcmp(node->name, "group") == 0) {
struct _EMJunkHookGroup *group;
group = emjh_construct_group(eph, node);
if (group) {
emjh->groups = g_slist_append(emjh->groups, group);
}
}
node = node->next;
}
eph->plugin = ep;
return 0;
}
/*XXX: do i need this?*/
static void
emjh_enable(EPluginHook *eph, int state)
{
GSList *g, *l;
EMJunk *klass;
g = emjh->groups;
if (emjh_types == NULL)
return;
}
static void
emjh_finalise(GObject *o)
{
EPluginHook *eph = (EPluginHook *)o;
g_slist_foreach(emjh->groups, (GFunc)emjh_free_group, NULL);
g_slist_free(emjh->groups);
((GObjectClass *)emjh_parent_class)->finalize(o);
}
static void
emjh_class_init(EPluginHookClass *klass)
{
((GObjectClass *)klass)->finalize = emjh_finalise;
klass->construct = emjh_construct;
klass->enable = emjh_enable;
klass->id = "org.gnome.evolution.mail.junk:1.0";
}
GType
em_junk_hook_get_type(void)
{
static GType type = 0;
if (!type) {
static const GTypeInfo info = {
sizeof(EMJunkHookClass), NULL, NULL, (GClassInitFunc) emjh_class_init, NULL, NULL,
sizeof(EMJunkHook), 0, (GInstanceInitFunc) NULL,
};
emjh_parent_class = g_type_class_ref(e_plugin_hook_get_type());
type = g_type_register_static(e_plugin_hook_get_type(), "EMJunkHook", &info, 0);
}
return type;
}
static void
emj_class_init (EMJunkClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->dispose = emj_dispose;
object_class->finalize = emj_finalize;
}
GType
emj_get_type(void)
{
static GType type = 0;
if (!type) {
static const GTypeInfo info = {
sizeof(EMJunkClass), NULL, NULL, (GClassInitFunc) emj_class_init, NULL, NULL,
sizeof(EMJunk), 0, (GInstanceInitFunc) NULL,
};
emj_parent = g_type_class_ref(G_TYPE_OBJECT);
type = g_type_register_static(G_TYPE_OBJECT, "EMJunk", &info, 0);
}
return type;
}
void em_junk_hook_register_type(GType type)
{
EMJunk *klass;
if (emjh_types == NULL)
emjh_types = g_hash_table_new(g_str_hash, g_str_equal);
printf("registering junk plugin type '%s'\n", g_type_name(type));
klass = g_type_class_ref(type);
g_hash_table_insert(emjh_types, (void *)g_type_name(type), klass);
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Authors: Vivek Jain <jvivek novell com>
*
* Copyright 2004 Novell, Inc. (www.novell.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __EM_FORMAT_HOOK_H__
#define __EM_FORMAT_HOOK_H__
#include <glib-object.h>
#include "libedataserver/e-msgport.h"
#include "e-util/e-plugin.h"
#include <camel/camel-junk-plugin.h>
#include <camel/camel-mime-message.h>
#ifdef __cplusplus
extern "C" {
#pragma }
#endif /* __cplusplus */
typedef struct _EMJunkHookItem EMJunkHookItem;
typedef struct _EMJunkHookGroup EMJunkHookGroup;
typedef struct _EMJunkHook EMJunkHook;
typedef struct _EMJunkHookClass EMJunkHookClass;
typedef struct _EMJunk EMJunk;
typedef struct _EMJunkClass EMJunkClass;
typedef struct _EMJunkHookTarget EMJunkHookTarget;
typedef void (*EMJunkHookFunc)(struct _EPlugin *plugin, EMJunkHookTarget *data);
struct _EMJunkHookTarget {
struct _EMJunkHookItem *item;
CamelMimeMessage *m;
};
struct _EMJunkHookItem {
struct _EMJunkHook *hook; /* parent pointer */
char *check_junk;
char *report_junk;
char *report_non_junk;
char *commit_reports;
};
struct _EMJunkHookGroup {
struct _EMJunkHook *hook; /* parent pointer */
char *id; /* target id */
GSList *items; /* items to consider */
};
struct _EMJunkHook {
EPluginHook hook;
GSList *groups;
};
struct _EMJunkHookClass {
EPluginHookClass hook_class;
/* which class to add matching items to */
GHashTable *junk_classes;
};
GType em_junk_hook_get_type(void);
void em_junk_hook_register_type(GType type);
struct _EMJunk {
CamelJunkPlugin csp;
};
struct _EMJunkClass {
GObjectClass parent_class;
/* which class to add matching items to */
GHashTable *junk_classes;
};
GType emj_get_type(void);
void em_junk_hook_register_type(GType type);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __EM_JUNK_HOOK_H__ */
<?xml version="1.0"?>
<e-plugin-list>
<e-plugin id="org.gnome.evolution.sa_junk_plugin"
type="shlib" _name="Sa junk-plugin"
location="@PLUGINDIR@/liborg-gnome-junk-plugin SOEXT@">
<_description>learns junk messages using spam assasin.</_description>
<author name="Vivek Jain" email="jvivek novell com"/>
<hook class="org.gnome.evolution.mail.junk:1.0">
<group id="EMJunk">
<item
check_junk="em_junk_sa_check_name"
report_junk="em_junk_sa_report_junk"
report_non_junk="em_junk_sa_report_non_junk"
commit_reports="em_junk_sa_commit_reports"/>
</group>
</hook>
</e-plugin>
</e-plugin-list>
/* -*- 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
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#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 <signal.h>
#include <time.h>
#include <camel/camel-debug.h>
#include <camel/camel-file-utils.h>
#include <camel/camel-data-wrapper.h>
#include <camel/camel-stream-fs.h>
#include <camel/camel-stream-mem.h>
#include <camel/camel-i18n.h>
#include <mail/em-junk-hook.h>
#include <mail/em-utils.h>
#include <e-util/e-mktemp.h>
#include <gconf/gconf-client.h>
#define d(x) (camel_debug("junk")?(x):0)
static pthread_mutex_t em_junk_sa_init_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t em_junk_sa_report_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t em_junk_sa_preferred_socket_path_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t em_junk_sa_spamd_restart_lock = PTHREAD_MUTEX_INITIALIZER;
static const char *em_junk_sa_get_name (void);
gboolean em_junk_sa_check_junk (EPlugin *ep, EMJunkHookTarget *target);
void em_junk_sa_report_junk (EPlugin *ep, EMJunkHookTarget *target);
void em_junk_sa_report_notjunk (EPlugin *ep, EMJunkHookTarget *target);
void em_junk_sa_commit_reports (EPlugin *ep, EMJunkHookTarget *target);
static void em_junk_sa_init (void);
static void em_junk_sa_finalize (void);
static void em_junk_sa_kill_spamd (void);
static gboolean em_junk_sa_tested = FALSE;
static gboolean em_junk_sa_spamd_tested = FALSE;
static gboolean em_junk_sa_use_spamc = FALSE;
static gboolean em_junk_sa_available = FALSE;
static gboolean em_junk_sa_system_spamd_available = FALSE;
static gboolean em_junk_sa_new_daemon_started = FALSE;
static char *em_junk_sa_socket_path = NULL;
static char *em_junk_sa_spamd_pidfile = NULL;
static char *em_junk_sa_spamc_binary = NULL;
static GConfClient *em_junk_sa_gconf = NULL;
/* volatile so not cached between threads */
static volatile gboolean em_junk_sa_local_only;
static volatile gboolean em_junk_sa_use_daemon;
static char * em_junk_sa_preferred_socket_path;
static char *em_junk_sa_spamc_binaries [3] = {"spamc", "/usr/sbin/spamc", NULL};
static char *em_junk_sa_spamd_binaries [3] = {"spamd", "/usr/sbin/spamd", NULL};
#define SPAMD_RESTARTS_SIZE 8
static time_t em_junk_sa_spamd_restarts [SPAMD_RESTARTS_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0};
static int em_junk_sa_spamd_restarts_count = 0;
char *em_junk_sa_spamc_gconf_binary = NULL;
char *em_junk_sa_spamd_gconf_binary = NULL;
static const char *
em_junk_sa_get_name (void)
{
return _("Spamassassin (built-in)");
}
static int
pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err, int wait_for_termination, GByteArray *output_buffer)
{
int result, status, errnosav, fds[2], out_fds[2];
CamelStream *stream;
char *program;
pid_t pid;
if (camel_debug_start ("junk")) {
int i;
printf ("pipe_to_sa ");
for (i = 0; argv[i]; i++)
printf ("%s ", argv[i]);
printf ("\n");
camel_debug_end ();
}
program = g_find_program_in_path (argv [0]);
if (program == NULL) {
d(printf ("program not found, returning %d\n", rv_err));
return rv_err;
}
g_free (program);
if (pipe (fds) == -1) {
errnosav = errno;
d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno)));
errno = errnosav;
return rv_err;
}
if (output_buffer && pipe (out_fds) == -1) {
errnosav = errno;
d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno)));
errno = errnosav;
return rv_err;
}
if (!(pid = fork ())) {
/* child process */
int maxfd, fd, nullfd;
nullfd = open ("/dev/null", O_WRONLY);
if (dup2 (fds[0], STDIN_FILENO) == -1 ||
dup2 (nullfd, STDERR_FILENO) == -1 ||
(output_buffer == NULL && dup2 (nullfd, STDOUT_FILENO) == -1) ||
(output_buffer != NULL && dup2 (out_fds[1], STDOUT_FILENO) == -1))
_exit (rv_err & 0377);
close (fds [0]);
if (output_buffer)
close (out_fds [1]);
setsid ();
maxfd = sysconf (_SC_OPEN_MAX);
for (fd = 3; fd < maxfd; fd++)
fcntl (fd, F_SETFD, FD_CLOEXEC);
execvp (argv[0], argv);
_exit (rv_err & 0377);
} else if (pid < 0) {
errnosav = errno;
close (fds[0]);
close (fds[1]);
errno = errnosav;
return rv_err;
}
/* parent process */
close (fds[0]);
if (output_buffer)
close (out_fds [1]);
if (msg) {
stream = camel_stream_fs_new_with_fd (fds[1]);
camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (msg), stream);
camel_stream_flush (stream);
camel_stream_close (stream);
camel_object_unref (stream);
} else if (in) {
camel_write (fds[1], in, strlen (in));
close (fds[1]);
}
if (output_buffer) {
CamelStreamMem *memstream;
stream = camel_stream_fs_new_with_fd (out_fds[0]);
memstream = (CamelStreamMem *) camel_stream_mem_new ();
camel_stream_mem_set_byte_array (memstream, output_buffer);
camel_stream_write_to_stream (stream, (CamelStream *) memstream);
camel_object_unref (stream);
g_byte_array_append (output_buffer, "", 1);
d(printf ("child process output: %s len: %d\n", output_buffer->data, output_buffer->len));
}
if (wait_for_termination) {
d(printf ("wait for child %d termination\n", pid));
result = waitpid (pid, &status, 0);
d(printf ("child %d terminated with result %d status %d exited %d exitstatus %d\n", pid, result, status, WIFEXITED (status), WEXITSTATUS (status)));
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 rv_err;
} else
return 0;
}
static int
pipe_to_sa (CamelMimeMessage *msg, const char *in, char **argv)
{
return pipe_to_sa_full (msg, in, argv, -1, 1, NULL);
}
static char *
em_junk_sa_get_socket_path ()
{
if (em_junk_sa_preferred_socket_path)
return em_junk_sa_preferred_socket_path;
else
return em_junk_sa_socket_path;
}
static gboolean
em_junk_sa_test_spamd_running (char *binary, gboolean system)
{
char *argv[5];
int i = 0;
gboolean rv;
pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
d(fprintf (stderr, "test if spamd is running (system %d) or using socket path %s\n", system, em_junk_sa_get_socket_path ()));
argv[i++] = binary;
argv[i++] = "-x";
if (!system) {
argv[i++] = "-U";
argv[i++] = em_junk_sa_get_socket_path ();
}
argv[i] = NULL;
rv = pipe_to_sa (NULL, "From test 127 0 0 1", argv) == 0;
d(fprintf (stderr, "result: %d (%s)\n", rv, rv ? "success" : "failed"));
pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
return rv;
}
static void
em_junk_sa_test_spamassassin (void)
{
char *argv [3] = {
"spamassassin",
"--version",
NULL,
};
if (pipe_to_sa (NULL, NULL, argv) != 0)
em_junk_sa_available = FALSE;
else
em_junk_sa_available = TRUE;
em_junk_sa_tested = TRUE;
}
#define MAX_SPAMD_PORTS 1
static gboolean
em_junk_sa_run_spamd (char *binary)
{
char *argv[8];
int i;
gboolean rv = FALSE;
pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
d(fprintf (stderr, "looks like spamd is not running\n"));
i = 0;
argv[i++] = binary;
argv[i++] = "--socketpath";
argv[i++] = em_junk_sa_get_socket_path ();
if (em_junk_sa_local_only)
argv[i++] = "--local";
//argv[i++] = "--daemonize";
argv[i++] = "--pidfile";
argv[i++] = em_junk_sa_spamd_pidfile;
argv[i] = NULL;
d(fprintf (stderr, "trying to run %s with socket path %s\n", binary, em_junk_sa_get_socket_path ()));
if (!pipe_to_sa_full (NULL, NULL, argv, -1, 0, NULL)) {
int i;
struct timespec time_req;
struct stat stat_buf;
d(fprintf (stderr, "success\n"));
d(fprintf (stderr, "waiting for spamd to come up\n"));
time_req.tv_sec = 0;
time_req.tv_nsec = 50000000;
for (i = 0; i < 100; i ++) {
if (stat (em_junk_sa_get_socket_path (), &stat_buf) == 0) {
d(fprintf (stderr, "socket created\n"));
break;
}
nanosleep (&time_req, NULL);
}
d(fprintf (stderr, "waiting is over (after %dms)\n", 50*i));
rv = TRUE;
}
pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
return rv;
}
static void
em_junk_sa_start_own_daemon ()
{
int b;
em_junk_sa_new_daemon_started = FALSE;
em_junk_sa_socket_path = e_mktemp ("spamd-socket-path-XXXXXX");
em_junk_sa_spamd_pidfile = e_mktemp ("spamd-pid-file-XXXXXX");
for (b = 0; em_junk_sa_spamd_binaries [b]; b ++) {
em_junk_sa_use_spamc = em_junk_sa_run_spamd (em_junk_sa_spamd_binaries [b]);
if (em_junk_sa_use_spamc) {
em_junk_sa_new_daemon_started = TRUE;
break;
}
}
}
static void
em_junk_sa_find_spamc ()
{
if (em_junk_sa_use_spamc && em_junk_sa_new_daemon_started) {
int b;
em_junk_sa_use_spamc = FALSE;
for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, FALSE)) {
em_junk_sa_use_spamc = TRUE;
break;
}
}
}
}
static void
em_junk_sa_test_spamd (void)
{
char *argv[4];
int i, b;
gboolean try_system_spamd = TRUE;
if (em_junk_sa_spamc_gconf_binary) {
em_junk_sa_spamc_binaries [0] = em_junk_sa_spamc_gconf_binary;
em_junk_sa_spamc_binaries [1] = NULL;
}
if (em_junk_sa_spamd_gconf_binary) {
em_junk_sa_spamd_binaries [0] = em_junk_sa_spamd_gconf_binary;
em_junk_sa_spamd_binaries [1] = NULL;
try_system_spamd = FALSE;
}
em_junk_sa_use_spamc = FALSE;
if (em_junk_sa_local_only && try_system_spamd) {
i = 0;
argv [i++] = "/bin/sh";
argv [i++] = "-c";
argv [i++] = "ps ax|grep -v grep|grep -E 'spamd.*(\\-L|\\-\\-local)'|grep -E -v '\\ \\-p\\ |\\ \\-\\-port\\ '";
argv[i] = NULL;
if (pipe_to_sa (NULL, NULL, argv) != 0) {
try_system_spamd = FALSE;
d(fprintf (stderr, "there's no system spamd with -L/--local parameter running\n"));
}
}
/* try to use sytem spamd first */
if (try_system_spamd) {
for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, TRUE)) {
em_junk_sa_use_spamc = TRUE;
em_junk_sa_system_spamd_available = TRUE;
break;
}
}
}
/* if there's no system spamd running, try to use user one with user specified socket */
if (!em_junk_sa_use_spamc && em_junk_sa_preferred_socket_path) {
for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, FALSE)) {
em_junk_sa_use_spamc = TRUE;
em_junk_sa_system_spamd_available = FALSE;
break;
}
}
}
/* unsuccessful? try to run one ourselfs */
if (!em_junk_sa_use_spamc)
em_junk_sa_start_own_daemon ();
/* new daemon started => let find spamc binary */
em_junk_sa_find_spamc ();
d(fprintf (stderr, "use spamd: %s\n", em_junk_sa_use_spamc ? "yes" : "no"));
em_junk_sa_spamd_tested = TRUE;
}
static gboolean
em_junk_sa_is_available (void)
{
pthread_mutex_lock (&em_junk_sa_init_lock);
if (!em_junk_sa_tested)
em_junk_sa_test_spamassassin ();
if (em_junk_sa_available && !em_junk_sa_spamd_tested && em_junk_sa_use_daemon)
em_junk_sa_test_spamd ();
pthread_mutex_unlock (&em_junk_sa_init_lock);
return em_junk_sa_available;
}
static gboolean
em_junk_sa_check_respawn_too_fast ()
{
time_t time_now = time (NULL);
gboolean rv;
pthread_mutex_lock (&em_junk_sa_spamd_restart_lock);
if (em_junk_sa_spamd_restarts_count >= SPAMD_RESTARTS_SIZE) {
/* all restarts in last 5 minutes */
rv = (time_now - em_junk_sa_spamd_restarts [em_junk_sa_spamd_restarts_count % SPAMD_RESTARTS_SIZE] < 5*60);
} else
rv = FALSE;
em_junk_sa_spamd_restarts [em_junk_sa_spamd_restarts_count % SPAMD_RESTARTS_SIZE] = time_now;
em_junk_sa_spamd_restarts_count ++;
pthread_mutex_unlock (&em_junk_sa_spamd_restart_lock);
d(printf ("em_junk_sa_check_respawn_too_fast: %d\n", rv));
return rv;
}
static gboolean
em_junk_sa_respawn_spamd ()
{
d(printf ("em_junk_sa_respawn_spamd\n"));
if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, em_junk_sa_system_spamd_available)) {
/* false alert */
d(printf ("false alert, spamd still running\n"));
return FALSE;
}
d(printf ("going to kill old spamd and start new one\n"));
em_junk_sa_kill_spamd ();
if (em_junk_sa_check_respawn_too_fast ()) {
g_warning ("respawning of spamd too fast => fallback to use spamassassin directly");
em_junk_sa_use_spamc = em_junk_sa_use_daemon = FALSE;
return FALSE;
}
em_junk_sa_start_own_daemon ();
em_junk_sa_find_spamc ();
d(printf ("%s\n", em_junk_sa_use_spamc ? "success" : "failed"));
return em_junk_sa_use_spamc;
}
gboolean
em_junk_sa_check_junk(EPlugin *ep, EMJunkHookTarget *target)
{
GByteArray *out = NULL;
char *argv[7], *to_free = NULL;
int i = 0, socket_i;
gboolean rv;
CamelMimeMessage *msg = target->m;
d(fprintf (stderr, "em_junk_sa_check_junk\n"));
g_print ("checking for junk..?\n");
if (!em_junk_sa_is_available ())
return FALSE;
if (em_junk_sa_use_spamc && em_junk_sa_use_daemon) {
out = g_byte_array_new ();
argv[i++] = em_junk_sa_spamc_binary;
argv[i++] = "-c";
argv[i++] = "-t";
argv[i++] = "60";
if (!em_junk_sa_system_spamd_available) {
argv[i++] = "-U";
pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
socket_i = i;
argv[i++] = to_free = g_strdup (em_junk_sa_get_socket_path ());
pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
}
} else {
argv [i++] = "spamassassin";
argv [i++] = "--exit-code";
if (em_junk_sa_local_only)
argv [i++] = "--local";
}
argv[i] = NULL;
rv = pipe_to_sa_full (msg, NULL, argv, 0, 1, out) != 0;
if (!rv && out && !strcmp (out->data, "0/0\n")) {
/* an error occured */
if (em_junk_sa_respawn_spamd ()) {
g_byte_array_set_size (out, 0);
pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
g_free (to_free);
argv [socket_i] = to_free = g_strdup (em_junk_sa_get_socket_path ());
pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
rv = pipe_to_sa_full (msg, NULL, argv, 0, 1, out) != 0;
} else if (!em_junk_sa_use_spamc)
/* in case respawning were too fast we fallback to spamassassin */
rv = em_junk_sa_check_junk (ep, target);
}
g_free (to_free);
d(fprintf (stderr, "em_junk_sa_check_junk rv = %d\n", rv));
if (out)
g_byte_array_free (out, TRUE);
return rv;
}
void
em_junk_sa_report_junk (EPlugin *ep, EMJunkHookTarget *target)
{
char *argv[6] = {
"sa-learn",
"--no-rebuild",
"--spam",
"--single",
NULL,
NULL
};
gchar *sub = NULL;
CamelMimeMessage *msg = target->m;
sub = g_strdup (camel_mime_message_get_subject (msg));
g_print ("\nreport junk?? %s\n", sub);
d(fprintf (stderr, "em_junk_sa_report_junk\n"));
if (em_junk_sa_is_available ()) {
if (em_junk_sa_local_only)
argv[4] = "--local";
pthread_mutex_lock (&em_junk_sa_report_lock);
pipe_to_sa (msg, NULL, argv);
pthread_mutex_unlock (&em_junk_sa_report_lock);
}
}
void
em_junk_sa_report_non_junk (EPlugin *ep, EMJunkHookTarget *target)
{
char *argv[6] = {
"sa-learn",
"--no-rebuild",
"--ham",
"--single",
NULL,
NULL
};
CamelMimeMessage *msg = target->m;
d(fprintf (stderr, "em_junk_sa_report_notjunk\n"));
if (em_junk_sa_is_available ()) {
if (em_junk_sa_local_only)
argv[4] = "--local";
pthread_mutex_lock (&em_junk_sa_report_lock);
pipe_to_sa (msg, NULL, argv);
pthread_mutex_unlock (&em_junk_sa_report_lock);
}
}
void
em_junk_sa_commit_reports (EPlugin *ep, EMJunkHookTarget *target)
{
char *argv[4] = {
"sa-learn",
"--rebuild",
NULL,
NULL
};
d(fprintf (stderr, "em_junk_sa_commit_reports\n"));
if (em_junk_sa_is_available ()) {
if (em_junk_sa_local_only)
argv[2] = "--local";
pthread_mutex_lock (&em_junk_sa_report_lock);
pipe_to_sa (NULL, NULL, argv);
pthread_mutex_unlock (&em_junk_sa_report_lock);
}
}
static void
em_junk_sa_setting_notify(GConfClient *gconf, guint cnxn_id, GConfEntry *entry, void *data)
{
GConfValue *value;
char *tkey;
g_return_if_fail (gconf_entry_get_key (entry) != NULL);
if (!(value = gconf_entry_get_value (entry)))
return;
tkey = strrchr(entry->key, '/');
g_return_if_fail (tkey != NULL);
if (!strcmp(tkey, "local_only"))
em_junk_sa_local_only = gconf_value_get_bool(value);
else if (!strcmp(tkey, "use_daemon"))
em_junk_sa_use_daemon = gconf_value_get_bool(value);
else if (!strcmp(tkey, "socket_path")) {
pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
g_free (em_junk_sa_preferred_socket_path);
em_junk_sa_preferred_socket_path = g_strdup (gconf_value_get_string(value));
pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
}
}
static void
em_junk_sa_init (void)
{
pthread_mutex_lock (&em_junk_sa_init_lock);
if (!em_junk_sa_gconf) {
em_junk_sa_gconf = gconf_client_get_default();
gconf_client_add_dir (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
em_junk_sa_local_only = gconf_client_get_bool (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/local_only", NULL);
em_junk_sa_use_daemon = gconf_client_get_bool (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/use_daemon", NULL);
pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
g_free (em_junk_sa_preferred_socket_path);
em_junk_sa_preferred_socket_path = g_strdup (gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/socket_path", NULL));
pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
gconf_client_notify_add(em_junk_sa_gconf, "/apps/evolution/mail/junk/sa",
(GConfClientNotifyFunc)em_junk_sa_setting_notify,
NULL, NULL, NULL);
em_junk_sa_spamc_gconf_binary = gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/spamc_binary", NULL);
em_junk_sa_spamd_gconf_binary = gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/spamd_binary", NULL);
}
pthread_mutex_unlock (&em_junk_sa_init_lock);
atexit (em_junk_sa_finalize);
}
static void
em_junk_sa_kill_spamd (void)
{
pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
g_free (em_junk_sa_preferred_socket_path);
em_junk_sa_preferred_socket_path = NULL;
pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
if (em_junk_sa_new_daemon_started) {
int fd = open (em_junk_sa_spamd_pidfile, O_RDONLY);
if (fd != -1) {
char pid_str [16];
int bytes;
bytes = read (fd, pid_str, 15);
if (bytes > 0) {
int pid;
pid_str [bytes] = 0;
pid = atoi (pid_str);
if (pid > 0) {
kill (pid, SIGTERM);
d(fprintf (stderr, "em_junk_sa_finalize send SIGTERM to daemon with pid %d\n", pid));
waitpid (pid, NULL, 0);
}
}
close (fd);
}
}
}
static void
em_junk_sa_finalize (void)
{
d(fprintf (stderr, "em_junk_sa_finalize\n"));
em_junk_sa_kill_spamd ();
}
INCLUDES = \
-I$(top_srcdir) \
$(EVOLUTION_MAIL_CFLAGS)
@EVO_PLUGIN_RULE@
plugin_DATA = org-gnome-sa-junk-plugin.eplug
plugin_LTLIBRARIES = liborg-gnome-sa-junk-plugin.la
liborg_gnome_sa_junk_plugin_la_SOURCES = em-junk-filter.c
liborg_gnome_sa_junk_plugin_la_LDFLAGS = -module -avoid-version
BUILT_SOURCES = $(plugin_DATA) $(error_DATA)
CLEANFILES = $(BUILT_SOURCES)
EXTRA_DIST = \
org-gnome-sa-junk-plugin.eplug.xml
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]