The problem is that i dont have it working for the new antispam but here
is your old script with the recipient fixed
This is 100% your code so you should be able to understand what i have done
You have changed 1000 things in your antispam plugin so it relly hard
for me to patch it
atleast take a look at it, if its possible to do the same thing with the
new plugin, please
I think that more people then me would like this feature, if the to is
wrong then its wrong but it would be great if this feature existed
= me happy ;-)
Look att the attached lib_dspam.c
/J3nkl3r
Johannes Berg wrote:
On Thu, 2008-08-21 at 16:15 +0200, Mikael Jenkler wrote:
The problem is that my %u is a user not the mail address and i train on
the mail address from master.cf
I modded your old script to support (for dovecot 1.0.x) it but when
1.1.x came it didnot work anymore
i have a diffrent username for auth then for resiveing mail so it
impossible to train on that
You could have a option called train on resiptient or something
i got the recipient address in the script then added this:
execl(DSPAM, "--source=error", "--stdout", "--user", recipient,
class_arg, sign_arg, NULL);
So how did you get the recipient? What if the To: header isn't right?
Did you use the envelope recipient? How did you get it?
I'd rather not open that can of worms. If you can send me a clean patch,
I might integrate it, but I'm surely not going to work on it.
johannes
/*
To use this plugin, you need to configure dspam to
* deliver spam into the SPAM folder for each user
* add a X-DSPAM-Signature header line with the signature. Body or
attachment signatures do not work, as dovecot is programmed to
extract the signature. It should be trivial to change this,
but it seemed cleaner this way. If you want (or already have)
a different header line name, then just change
the #define on top of the file.
To compile:
make "plugins" directory right beside "src" in the dovecot source tree,
copy this into there and run
cc -fPIC -shared -Wall -I../src/ -I../src/lib -I.. -I../src/lib-storage \
-I../src/lib-mail -I../src/lib-imap -I../src/imap/ -DHAVE_CONFIG_H \
lib_dspam.c -o lib30_dspam.so
Add -DDEBUG_DSPAM for debug
Install the plugin in the usual dovecot module location.
copy the plugin to /usr/lib/dovecot/imap folder
If you need to ignore a trash folder, define a trash folder
name as follows, or alternatively give -DIGNORE_TRASH_NAME=\"Trash\" on
the cc command line.
*/
#include "common.h"
#include "str.h"
#include "strfuncs.h"
#include "commands.h"
#include "imap-search.h"
#include "lib-storage/mail-storage.h"
#include "lib/mempool.h"
#include "mail-storage.h"
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#ifdef DEBUG_DSPAM
#include <syslog.h>
#endif
#define IGNORE_TRASH_NAME "INBOX.Trash"
#define MAXSIGLEN 100
#define RECIPIENT "Delivered-To"
#define SIGHEADERLINE "X-DSPAM-Signature"
#ifndef DSPAM
#define DSPAM "/usr/bin/dspam"
#endif /* DSPAM */
static int
call_dspam(const char* signature, int is_spam, const char* recipient)
{
pid_t pid;
int s;
char class_arg[16+2];
char sign_arg[MAXSIGLEN+2];
int pipes[2];
s = snprintf(sign_arg, 101, "--signature=%s", signature);
if ( s > MAXSIGLEN || s <= 0) return -1;
snprintf(class_arg, 17, "--class=%s", is_spam ? "spam" : "innocent");
pipe(pipes); /* for dspam stderr */
pid = fork();
if (pid < 0) return -1;
if (pid) {
int status;
/* well. dspam doesn't report an error if it has an error,
but instead only prints stuff to stderr. Usually, it
won't print anything, so we treat it having output as
an error condition */
char buf[1024];
int readsize;
close(pipes[1]);
do {
readsize = read(pipes[0], buf, 1024);
if (readsize < 0) {
readsize = -1;
if (errno == EINTR) readsize = -2;
}
} while (readsize == -2);
if (readsize != 0) {
close(pipes[0]);
return -1;
}
waitpid (pid, &status, 0);
if (!WIFEXITED(status)) {
close(pipes[0]);
return -1;
}
readsize = read(pipes[0], buf, 1024);
if (readsize != 0) {
close(pipes[0]);
return -1;
}
close(pipes[0]);
return WEXITSTATUS(status);
} else {
int fd = open("/dev/null", O_RDONLY);
close(0); close(1); close(2);
/* see above */
close(pipes[0]);
if (dup2(pipes[1], 2) != 2) {
exit(1);
}
if (dup2(pipes[1], 1) != 1) {
exit(1);
}
close(pipes[1]);
if (dup2(fd, 0) != 0) {
exit(1);
}
close(fd);
#ifdef DEBUG_DSPAM
syslog(LOG_MAIL, DSPAM " --source=error --stdout --user %s %s %s", recipient, class_arg, sign_arg);
#endif
execl(DSPAM, "--source=error", "--stdout", "--user", recipient, class_arg, sign_arg, NULL);
exit(127); /* fall through if dspam can't be found */
return -1; /* never executed */
}
}
struct dspam_signature_list {
struct dspam_signature_list * next;
char * sig;
};
typedef struct dspam_signature_list * siglist_t;
static siglist_t list_append(pool_t pool, siglist_t * list) {
siglist_t l = *list;
siglist_t p = NULL;
siglist_t n;
while (l != NULL) {
p = l;
l = l->next;
}
n = p_malloc (pool, sizeof(struct dspam_signature_list));
n->next = NULL;
n->sig = NULL;
if (p == NULL) {
*list = n;
} else {
p->next = n;
}
return n;
}
static int
fetch_and_copy_reclassified (struct mailbox_transaction_context *t,
struct mailbox *srcbox,
struct mail_search_arg *search_args,
int is_spam,
int *enh_error)
{
struct mail_search_context *search_ctx;
struct mailbox_transaction_context *src_trans;
struct mail_keywords *keywords;
const char *const *keywords_list;
struct mail *mail;
int ret;
char* recipient;
const char* signature;
struct dspam_signature_list * siglist = NULL;
pool_t listpool = pool_alloconly_create("dspam-siglist-pool", 1024);
*enh_error = 0;
src_trans = mailbox_transaction_begin(srcbox, 0);
search_ctx = mailbox_search_init(src_trans, NULL, search_args, NULL);
mail = mail_alloc(src_trans, MAIL_FETCH_STREAM_HEADER |
MAIL_FETCH_STREAM_BODY, NULL);
ret = 1;
while (mailbox_search_next(search_ctx, mail) > 0 && ret > 0) {
if (mail->expunged) {
ret = 0;
break;
}
recipient = strdup(mail_get_first_header(mail, RECIPIENT));
signature = mail_get_first_header(mail, SIGHEADERLINE);
if (is_empty_str(signature) || is_empty_str(recipient)) {
ret = -1;
*enh_error = -2;
break;
}
list_append(listpool, &siglist)->sig = p_strdup(listpool, signature);
keywords_list = mail_get_keywords(mail);
keywords = strarray_length(keywords_list) == 0 ? NULL :
mailbox_keywords_create(t, keywords_list);
if (mailbox_copy(t, mail, mail_get_flags(mail),
keywords, NULL) < 0)
ret = -1;
mailbox_keywords_free(t, &keywords);
}
mail_free(&mail);
if (mailbox_search_deinit(&search_ctx) < 0)
ret = -1;
/* got all signatures now, walk them passing to dspam */
while (siglist) {
if ((*enh_error = call_dspam(siglist->sig, is_spam, recipient))) {
ret = -1;
break;
}
siglist = siglist->next;
}
pool_unref (listpool);
if (*enh_error) {
mailbox_transaction_rollback(&src_trans);
} else {
if (mailbox_transaction_commit(&src_trans, 0) < 0)
ret = -1;
}
return ret;
}
static bool cmd_append_spam_plugin(struct client_command_context *cmd)
{
const char *mailbox;
struct mail_storage *storage;
struct mailbox *box;
/* <mailbox> */
if (!client_read_string_args(cmd, 1, &mailbox))
return FALSE;
storage = client_find_storage(cmd, &mailbox);
if (storage == NULL)
return FALSE;
/* TODO: is this really the best way to handle this? maybe more logic could be provided */
box = mailbox_open(storage, mailbox, NULL, MAILBOX_OPEN_FAST | MAILBOX_OPEN_KEEP_RECENT);
if (box != NULL)
{
if (mailbox_equals(box, storage, "Spam"))
{
mailbox_close(&box);
return cmd_sync (cmd, 0, 0, "NO Cannot APPEND to Spam box, sorry.");
}
mailbox_close(&box);
}
return cmd_append (cmd);
}
static bool cmd_copy_spam_plugin(struct client_command_context *cmd)
{
struct client *client = cmd->client;
struct mail_storage *storage;
struct mailbox *destbox;
struct mailbox_transaction_context *t;
struct mail_search_arg *search_arg;
const char *messageset, *mailbox;
enum mailbox_sync_flags sync_flags = 0;
int ret;
int spam_folder = 0;
int enh_error = 0, is_spam;
#ifdef IGNORE_TRASH_NAME
int is_trash;
int trash_folder = 0;
#endif
struct mailbox *box;
/* <message set> <mailbox> */
if (!client_read_string_args(cmd, 2, &messageset, &mailbox))
return FALSE;
if (!client_verify_open_mailbox(cmd))
return TRUE;
storage = client_find_storage(cmd, &mailbox);
if (storage == NULL)
return FALSE;
box = mailbox_open(storage, mailbox, NULL, MAILBOX_OPEN_FAST | MAILBOX_OPEN_KEEP_RECENT);
if (!box) {
client_send_storage_error(cmd, storage);
return TRUE;
}
is_spam = mailbox_equals(box, storage, "Spam");
spam_folder = is_spam || mailbox_equals(cmd->client->mailbox, storage, "Spam");
#ifdef IGNORE_TRASH_NAME
is_trash = mailbox_equals(box, storage, IGNORE_TRASH_NAME);
trash_folder = is_trash || mailbox_equals(cmd->client->mailbox, storage, IGNORE_TRASH_NAME);
#endif
mailbox_close(&box);
/* only act on spam */
if (!spam_folder)
return cmd_copy(cmd);
#ifdef IGNORE_TRASH_NAME
/* ignore any mail going into or out of trash
* This means users can circumvent re-classification
* by moving into trash and then out again...
* All in all, it may be a better idea to not use
* a Trash folder at all :) */
if (trash_folder)
return cmd_copy(cmd);
#endif
/* otherwise, do (almost) everything the copy would have done */
/* open the destination mailbox */
if (!client_verify_mailbox_name(cmd, mailbox, TRUE, FALSE))
return TRUE;
search_arg = imap_search_get_arg(cmd, messageset, cmd->uid);
if (search_arg == NULL)
return TRUE;
storage = client_find_storage(cmd, &mailbox);
if (storage == NULL)
return TRUE;
if (mailbox_equals(client->mailbox, storage, mailbox))
destbox = client->mailbox;
else {
destbox = mailbox_open(storage, mailbox, NULL,
MAILBOX_OPEN_FAST |
MAILBOX_OPEN_KEEP_RECENT);
if (destbox == NULL) {
client_send_storage_error(cmd, storage);
return TRUE;
}
}
t = mailbox_transaction_begin(destbox,
MAILBOX_TRANSACTION_FLAG_EXTERNAL);
ret = fetch_and_copy_reclassified(t, client->mailbox, search_arg, is_spam, &enh_error);
if (ret <= 0)
mailbox_transaction_rollback(&t);
else {
if (mailbox_transaction_commit(&t, 0) < 0)
ret = -1;
}
if (destbox != client->mailbox) {
sync_flags |= MAILBOX_SYNC_FLAG_FAST;
mailbox_close(&destbox);
}
if (ret > 0)
return cmd_sync(cmd, sync_flags, 0, "OK Copy completed.");
else if (ret == 0) {
/* some messages were expunged, sync them */
return cmd_sync(cmd, 0, 0,
"NO Some of the requested messages no longer exist.");
} else {
switch (enh_error) {
case -2:
return cmd_sync(cmd, 0, 0, "NO Some messages did not have " SIGHEADERLINE " header line");
break;
case -3:
return cmd_sync(cmd, 0, 0, "NO Failed to call dspam");
break;
case 0:
client_send_storage_error(cmd, storage);
return TRUE;
break;
default:
return cmd_sync(cmd, 0, 0, "NO dspam failed");
break;
}
}
return TRUE;
}
void dspam_init(void)
{
command_unregister("COPY");
command_unregister("APPEND");
command_unregister("UID COPY");
/* i_strdup() here is a kludge to avoid crashing in commands_deinit()
* since modules are unloaded before it's called, this "COPY" string
* would otherwise point to nonexisting memory. */
command_register(i_strdup("COPY"), cmd_copy_spam_plugin);
command_register(i_strdup("UID COPY"), cmd_copy_spam_plugin);
command_register(i_strdup("APPEND"), cmd_append_spam_plugin);
}
void dspam_deinit(void)
{
}