/* $Cambridge: hermes/src/prayer/cmd/cmd_spam.c,v 1.4 2008/09/17 17:20:25 dpc22 Exp $ */
/************************************************
 *    Prayer - a Webmail Interface              *
 ************************************************/

/* Copyright (c) University of Cambridge 2000 - 2008 */
/* See the file NOTICE for conditions of use and distribution. */

#include "prayer_session.h"

static void generate_form(struct session *session)
{
    struct template_vals *tvals = session->template_vals;
    struct request *request = session->request;
    struct account *account = session->account;
    struct buffer *b = request->write_buffer;
    unsigned long threshold =
        (account->spam_threshold_valid) ? account->spam_threshold : 10;

    template_vals_ulong(tvals, "spam_threshold", threshold);

    if (account->spam_enabled)
        template_vals_ulong(tvals, "spam_enabled", 1);


    if (session->sieved_server)
        template_vals_ulong(tvals, "using_sieve", 1);

    if (account->spam_purge_enabled)
        template_vals_ulong(tvals, "spam_purge_enabled", 1);

    template_vals_ulong(tvals, "spam_purge_timeout",
                        account->spam_purge_timeout);

    if (account->spam_whitelist && account->spam_whitelist[0])
        template_vals_string(tvals, "spam_whitelist", account->spam_whitelist);

    session_seed_template(session, tvals);
    template_expand("spam", tvals, b);
    response_html(request, 200);        /* Success */
}

static void generate_error(struct session *session)
{
    struct template_vals *tvals = session->template_vals;
    struct account *account = session->account;
    struct request *request = session->request;
    char *msg = account_fetch_message(account);
    struct buffer *b = request->write_buffer;

    if (!(msg && msg[0]))
        msg = "Unable to check mail processing status";

    template_vals_string(tvals, "msg", msg);
    session_seed_template(session, tvals);
    template_expand("spam_fail", tvals, b);
    response_html(request, 200);
}

/* Remove extraneous whitespace from each line in whitelist */

static char *
normalise_whitelist(char *list, struct pool *pool)
{
    struct buffer *b = buffer_create(pool, 64);
    char *tmp = pool_strdup(pool, list);         /* Scratch copy */
    char *s;

    while ((s=string_get_line(&tmp))) {
        if ((s=string_trim_whitespace(s)) && s[0]) {
            bputs(b, s);
            bputs(b, ""CRLF);
        }
    }
    return(buffer_fetch(b, 0, buffer_size(b), NIL));
}

/* Check that addresslist consists of one valid address per line
   (wildcard characters are allowed in addresses) */

static BOOL
validate_whitelist(struct session *session, char *list, struct pool *pool)
{
    char *tmp = pool_strdup(pool, list); /* Scratch copy */
    char *s;
    ADDRESS *addr;

    while ((s=string_get_line(&tmp))) {
        if ((s=string_trim_whitespace(s)) && s[0]) {
            addr = addr_parse(pool, s, "");

            if (!addr) {
                session_message(session, "Invalid address: %s", s);
                return(NIL);
            }
            if (addr->next) {
                session_message(session,
                                "Single address on each line please: %s", s);
                mail_free_address(&addr);
                return(NIL);
            }
            mail_free_address(&addr);
        }
    }
    return(T);
}

void cmd_spam(struct session *session)
{
    struct config *config = session->config;
    struct request *request = session->request;
    struct assoc *h = NIL;
    struct account *account = session->account;
    char *s, *t;

    if (request->method != POST) {
        if (!account_mail_check(account, request->pool))
            generate_error(session);
        else
            generate_form(session);
        return;
    }

    /* Form post */
    request_decode_form(request);
    h = request->form;

    if (assoc_lookup(h, "sub_cancel")) {
        session_redirect(session, request, "manage");
        return;
    }

    s = assoc_lookup(h, "spam_threshold");

    if (!(s && string_isnumber(s) && (atoi(s) > 0))) {
        session_message(session,
                        "Threshold must be a number greater than zero");
        generate_form(session);
        return;
    }

    account->spam_enabled = assoc_lookup(h, "sub_enable") ? T : NIL;
    account->spam_threshold = atoi(s);
    account->spam_threshold_valid = T;

    /* Spam whitelist and purge currently only available to sieve users */
    if (session->sieved_server) {
        if ((t = assoc_lookup(h, "spam_whitelist"))) {
            string_strdup(&account->spam_whitelist,
                          normalise_whitelist(t, request->pool));

            if (!validate_whitelist(session, account->spam_whitelist,
                                    request->pool)) {
                generate_form(session);
                return;
            }
        } else
            string_strdup(&account->spam_whitelist, "");

        t = assoc_lookup(h, "spam_purge_timeout");
        if (!(t && string_isnumber(t) && (atoi(t) >= 0))) {
            session_message(session,
                            "Purge time must be a non-negative integer");
            generate_form(session);
            return;
        }

        account->spam_purge_timeout = atoi(t);
        account->spam_purge_enabled = assoc_lookup(h, "spam_purge") ? T : NIL;

        if (account->spam_purge_enabled) {
            session_log(session, "[cmd_spam] spam_purge enabled: %d days", 
                        account->spam_purge_timeout);
        } else {
            session_log(session, "[cmd_spam] spam_purge disabled");
        }
    }

    if (!account_mail_update(account, request->pool)) {
        char *msg = account_fetch_message(account);

        session_alert(session, "Failed to update spam filter: %s", msg);
        session_log(session,
                    "[cmd_spam] Failed to update spam filter: %s", msg);
        generate_form(session);
        return;
    }

    if (account->spam_enabled &&
        !folderlist_lookup(session->folderlist, "spam")) {
        if (ml_create(session, session->stream,
                      session_mailbox(session, request->pool, "spam"))) {
            if (config->dualuse)
                folderlist_add(session->folderlist, "spam", NIL, NIL);
            else
                folderlist_add(session->folderlist, "spam", NIL, T);
        } else
            session_alert(session, "Failed to create spam folder");
    }

    session_message(session, "Updated junk email filtering");
    session_redirect(session, request, "manage");
}
