/* $Cambridge: hermes/src/prayer/cmd/cmd_download_xfer.c,v 1.5 2009/12/01 17:01:15 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"

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

/* unix_pseudo stolen from c-client */
extern unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);

static BOOL download(struct session *session, char *name)
{
    struct config *config = session->config;
    struct request *request = session->request;
    struct buffer *b = request->write_buffer;
    MAILSTREAM *tstream;
    unsigned long msgno, len;
    char *text, *s, c;
    char lastc = '\n';
    MESSAGECACHE *elt;
    ENVELOPE *env;
    ADDRESS *addr;
    int flag;
    char tmp[MAILTMPLEN];
    unsigned long uid;
    unsigned long total;

    session->xfer_stream
        = ml_open(session, session->xfer_stream,
                  session_mailbox(session, request->pool, name),
                  OP_READONLY);

    if (!session->xfer_stream) {
        session_alert(session, "Failed to open mail folder: %s",
                      utf8_from_imaputf7(request->pool, name));
        session_log(session,
                    "[cmd_transfer] Failed to open mail folder: %s", name);
        return (NIL);
    }

    tstream = session->xfer_stream;

    /* Fetch overview for all messages in folder */
    if (!ml_fetch_fast(session, tstream, "1:*", 0)) {
        session_alert(session, "Failed to fetch folder overview: %s",
                      utf8_from_imaputf7(request->pool, name));
        session_log(session,
                    "[cmd_transfer]] Failed to fetch overview: %s", name);
        return (NIL);
    }

    /* Test size of download */
    if (config->http_max_body_size > 0) {
        total = 0;

        for (msgno = 1; msgno <= tstream->nmsgs; msgno++) {
            if (!(elt = ml_elt(session, tstream, msgno)))
                return (NIL);
            total += elt->rfc822_size;
        }
        if (total > config->http_max_body_size) {
            struct template_vals *tvals = session->template_vals;

            template_vals_ulong(tvals, "size", total / (1024*1024));
            template_vals_ulong(tvals, "limit",
                                config->http_max_body_size / (1024*1024));

            session_seed_template(session, tvals);
            template_expand("download_xfer_error", tvals, b);
            response_html(request, 200);
            return(T);
        }
    }

    /* Fudge up unix pseudo message for Keywords etc */
    unix_pseudo(tstream, tmp);
    bputs(b, tmp);

    for (msgno = 1; msgno <= tstream->nmsgs; msgno++) {
        if (!((uid = ml_uid(session, tstream, msgno)) &&
              (elt = ml_elt(session, tstream, msgno)) &&
              (env = ml_fetch_structure(session, tstream, msgno, NIL, 0))))
            return (NIL);

        mail_cdate (tmp, elt);

        if ((addr = env->sender) && addr->mailbox && addr->host)
            bprintf(b, "From %s@%s %s", addr->mailbox, addr->host,
                    tmp);
        else
            bprintf(b, "From unknown@nowhere.com %s", tmp);


        if (!
            (text =
             ml_fetch_header(session, tstream, msgno, NIL, NIL, &len, 0)))
        {
            session_alert(session,
                          "Couldn't fetch header for message %lu",
                          msgno);
            session_log(session,
                        ("[cmd_transfer] Couldn't fetch header for message %lu"
                         "in folder: %s"), msgno, name);
            return (NIL);
        }

        /* Copy header replacing CRLF, CR or LF with LF */
        s = text;
        while ((c = *s)) {
            /* Chomp final CRLF sequence */
            if ((s[0] == '\015') && (s[1] == '\012') && (s[2] == '\0'))
                break;

            if (((s[0] == '\015') || (s[0] == '\012')) && (s[1] == '\0'))
                break;

            if ((c == '\015') || (c == '\012')) {
                /* Replace CRLF with single LF */
                s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1;
                bputc(b, '\n');

                /* Quote "From" on following line */
                if (!strncmp(s, "From ", strlen("From ")))
                    bputc(b, '>');

                continue;
            }
            bputc(b, c);
            s++;
        }

        bputs(b, "Status: ");
        if (elt->seen)     bputc(b, 'R');
        if (!elt->recent)  bputc(b, 'O');
        bputs(b, "\nX-Status: ");
        if (elt->deleted)  bputc(b, 'D');
        if (elt->flagged)  bputc(b, 'F');
        if (elt->answered) bputc(b, 'A');
        if (elt->draft)    bputc(b, 'T');
        bputs(b, "\nX-Keywords:");
        for (flag = 0 ; flag < NUSERFLAGS ; flag++) {
            if ((elt->user_flags & (1<<flag)) && tstream->user_flags[flag]) {
                bprintf(b, " %s", tstream->user_flags[flag]);
            }
        }
        bprintf(b, "\nX-UID: %lu\n\n", uid);

        if (!(text = ml_fetch_text(session, tstream, msgno, NIL, &len, 0))) {
            session_alert(session, "Couldn't fetch body for message %lu",
                          msgno);
            session_log(session,
                        ("[cmd_transfer] Couldn't fetch body for message %lu"
                         "in folder: %s"), msgno, name);
            return (NIL);
        }

        /* Copy body replacing CRLF, CR or LF with LF */
        s = text;
        while ((c = *s)) {
            if ((c == '\015') || (c == '\012')) {
                /* Replace CRLF with single LF */
                s += ((s[0] == '\015') && (s[1] == '\012')) ? 2 : 1;
                bputc(b, '\n');
                lastc = '\n';

                /* Quote "From" on following line */
                if (!strncmp(s, "From ", strlen("From ")))
                    bputc(b, '>');

                continue;
            }
            lastc = c;
            bputc(b, c);
            s++;
        }
        if (lastc != '\n')
            bputc(b, '\n');
        bputc(b, '\n');

        if (elt->rfc822_size > (1024*1024))      /* Large attachment */
            mail_gc(tstream, GC_ENV | GC_TEXTS); /* Discard cache */
    }
    mail_gc(tstream, GC_ENV | GC_TEXTS); /* Discard cache immediately */

    response_raw(request, name, "application/octet-stream", 200);
    return (T);
}

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

void cmd_download_xfer(struct session *session)
{
    struct request *request = session->request;

    if (request->argc < 2) {
        session_redirect(session, request, "error");
        return;
    }

    if (!download(session, string_canon_decode(request->argv[1])))
        session_redirect(session, request, "restart");
        return;
}
