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)
{
}

Reply via email to