/* $Cambridge: hermes/src/prayer/cmd/cmd_upload_xfer.c,v 1.5 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"

typedef struct append_package {
    struct pool *pool;          /* Scratch pool for this interation */
    MAILSTREAM *src;            /* Source stream */
    unsigned long last;         /* Last message appended (0 => none) */
} APPENDPACKAGE;


/* Append all marked messages to target stream */

static long
upload_append_next(MAILSTREAM * target, void *data, char **flags,
                   char **date, STRING ** message)
{
    APPENDPACKAGE *ap = (APPENDPACKAGE *) data;
    MAILSTREAM *src = ap->src;
    MESSAGECACHE *elt;
    unsigned long msgno;
    struct buffer *b, *f;
    char *text, *s;
    unsigned long len;
    static STRING msg;
    int flag;

    if (ap->pool)
        pool_free(ap->pool);
    /* Generate new pool */

    if (ap->last == src->nmsgs) {
        *message = NIL;
        return (LONGT);
    }
    msgno = ++ap->last;

    /* Generate scratch space for this interation */
    ap->pool = pool_create(0);
    b = buffer_create(ap->pool, 4096);
    f = buffer_create(ap->pool, 1024);

    /* Generate message flags. */
    if ((elt = mail_elt(src, msgno)) != NIL) {
        if (elt->seen)     bputs(f, "\\Seen ");
        if (elt->deleted)  bputs(f, "\\Deleted ");
        if (elt->flagged)  bputs(f, "\\Flagged ");
        if (elt->answered) bputs(f, "\\Answered ");
        if (elt->draft)    bputs(f, "\\Draft ");
        for (flag = 0 ; flag < NUSERFLAGS ; flag++) {
            if ((elt->user_flags & (1<<flag)) && src->user_flags[flag]) {
                bprintf(f, "%s ", src->user_flags[flag]);
            }
        }
    }

    /* Generate copy of full message in string */
    text = mail_fetch_header(src, msgno, NIL, NIL, &len, FT_PEEK);
    for (s = text; *s; s++)
        bputc(b, *s);

    text = mail_fetch_text(src, msgno, NIL, &len, FT_PEEK);
    for (s = text; *s; s++)
        bputc(b, *s);

    /* Initialise msg STRING */
    s = buffer_fetch(b, 0, len = buffer_size(b), NIL);
    INIT(&msg, mail_string, (void *) s, len);

    if (buffer_size(f) > 0)
        *flags = buffer_fetch(f, 0, buffer_size(f)-1, NIL);
    else
        *flags = NIL;

    *date = NIL;
    *message = &msg;

    return LONGT;               /* always return success */
}

/* ====================================================================== */

static BOOL upload(struct session *session, char *name, BOOL append)
{
    struct request *request = session->request;
    MAILSTREAM *tin;
    MAILSTREAM *tout;
    APPENDPACKAGE ap;

    /* Calculate remote folder name */
    name = session_mailbox(session, request->pool, name);

    if (!(tin = ml_open(session, NIL, session->upload_file, OP_READONLY))) {
        session_alert(session, "Failed to open temporary mail folder");
        session_log(session,
                    "[cmd_upload_xfer] Failed to open temporary mail folder");
        return (NIL);
    }

    tout = session->inbox_stream;

    if (!append && !ml_create(session, tout, name)) {
        session_alert(session,
                      "Failed to create target folder: %s", ml_errmsg());
        session_log(session,
                    "[cmd_upload_xfer] Failed to create target folder: %s",
                    ml_errmsg());
        return (NIL);
    }

    /* Transfer all messages from tin to tout using multiappend system */

    /* Prime append package */
    ap.pool = NIL;
    ap.last = 0;
    ap.src = tin;

    if (!ml_append_multiple(session, tout, name,
                            upload_append_next, (void *) &ap)) {
        session_alert(session,
                      "Failed to append message to target folder: %s",
                      ml_errmsg());
        session_log(session,
                    ("[cmd_upload_xfer] Failed to append message"
                     " to target folder (%s): %s"), name, ml_errmsg());
    }

    ml_close(session, tin);

    unlink(session->upload_file);
    string_free((void **) &session->upload_file);

    return (T);
}

/* ====================================================================== */

void cmd_upload_xfer(struct session *session)
{
    struct config *config = session->config;
    struct request *request = session->request;
    struct assoc *h = NIL;
    char *name = NIL;
    char *parent = NIL;
    BOOL append;

    if (!session->upload_file) {
        session_alert(session,
                      "Transit File missing (playing with browser history?)");
        session_redirect(session, request, "transfer");
        return;
    }

    if (request->argc < 2) {
        request_decode_form(request);
        h = request->form;

        if (assoc_lookup(h, "cancel")) {
            session_redirect(session, request, "upload_exit");
            return;
        }

        if (!(name = assoc_lookup(h, "name"))) {
            response_error(request, 404);
            return;
        }
        parent = assoc_lookup(h, "parent");
        append = (assoc_lookup(h, "append")) ? T : NIL;
    } else {
        name = request->argv[1];
        string_canon_decode(name);
        append = T;
    }

    if (parent && parent[0]) {
        string_canon_decode(parent);
        name = pool_strcat3(request->pool, parent, 
                            session->hiersep, name);
    }

    string_strdup(&session->upload_name, name);

    if (upload(session, name, append) && !append) {
        if (config->dualuse)
            folderlist_add(session->folderlist, name, NIL, NIL);
        else
            folderlist_add(session->folderlist, name, NIL, T);
    }
    string_free((void **) &session->upload_name);

    session_message(session, "Folder Upload Complete");
    session_redirect(session, request, "transfer");
}
