/* $Cambridge: hermes/src/prayer/cmd/cmd_reply2.c,v 1.2 2008/05/19 15:55:54 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 BOOL string_check_sigdash(char *sig)
{
    char *s;

    /* Check whether signature already contains sigdash line */
    for (s = sig; *s; s++) {
        if ((s[0] == '-') && (s[1] == '-') && (s[2] == ' ') &&
            ((s[3] == '\015') || (s[3] == '\012'))) {
            return (NIL);
        }
    }

    return (T);
}

static char *string_decode_mime(struct pool *tpool, char *s)
{
    unsigned long len = strlen(s) + 20;
    char *buffer = pool_alloc(tpool, len);
    char *d;

    d = (char *) rfc1522_decode((unsigned char *) buffer, len, s, NIL);

    return (d);
}

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

/* Extract text from relevant message (go fishing around inside multipart
 * messages) and put in into the specified buffer as quoted (and possibly
 * line wrapped) text */

static BOOL
add_text(struct session *session, struct buffer *b, struct pool *pool,
         MAILSTREAM *stream, unsigned long msgno)

{
    struct prefs *prefs = session->options->prefs;
    BODY *body = NIL;
    char *section = NIL;
    char *init_msg, *decode_msg, *type;
    unsigned long len;
    char *text, *s;
    PARAMETER *parameter;
    char *charset = "ISO-8859-1";

    if ((body = ml_body(session, stream, msgno, "1")) == NIL)
        return(NIL);

    if (body->type == TYPEMULTIPART) {
        PART *part = body->nested.part;
        int   i = 1, body_plain = 0, body_html = 0, subsection;

        for (i = 1; part != NIL; part = part->next, i++) {
            if (!(body = &part->body))
                continue;

            if ((body->type != TYPETEXT) || !body->subtype)
                continue;

            if (!strcasecmp(body->subtype, "plain")) {
                if (!body_plain) body_plain = i;
            } else if (!strcasecmp(body->subtype, "html")) {
                if (!body_html) body_html = i;
            }
        }

        subsection = (body_plain) ? body_plain : body_html;

        if (subsection) {
            section = pool_printf(pool, "1.%lu", subsection);
            if ((body = ml_body(session, stream, msgno, section)) == NIL)
                return (NIL);
        } else
            section = NIL;
    } else if (body->type == TYPETEXT) {
        section = "1";
    } else
        section = NIL;

    if (!section) {
        bputs(b, "> (Message body was not text: suppressed)" CRLF);
        return(T);
    }

    for (parameter = body->parameter; parameter; parameter = parameter->next) {
        if (strcasecmp(parameter->attribute, "charset") == 0) {
            charset = parameter->value;
            break;
        }
    }

    /* Got a valid text section to display */
    if (!(init_msg=ml_fetchbody(session, stream, msgno, section, &len)))
        return(NIL);

    /* Strip off encoding */
    switch (body->encoding) {
    case ENCBASE64:
        if (!(decode_msg =
              (char *) rfc822_base64((unsigned char *) init_msg,
                                     body->size.bytes, &len))) {
            /* Decode failed */
            decode_msg = init_msg;
            len = body->size.bytes;
        }
        break;
    case ENCQUOTEDPRINTABLE:
        if (!(decode_msg =
              (char *) rfc822_qprint((unsigned char *) init_msg,
                                     body->size.bytes, &len))) {
            /* Decode failed */
            decode_msg = init_msg;
            len = body->size.bytes;
        }
        break;
    case ENC7BIT:
    case ENC8BIT:
    case ENCBINARY:
    case ENCOTHER:
    default:
        decode_msg = init_msg;
        len = body->size.bytes;
    }

    type = pool_strcat3(pool, body_types[body->type], "/", body->subtype);
    string_lcase(type);

    if ((!strcasecmp(type, "text/html") && prefs->html_inline) ||
        (!strncasecmp(decode_msg, "<html>", strlen("<html>")) &&
         prefs->html_inline_auto)) {
        struct buffer *b = buffer_create(pool, 8192);
        if (decode_msg == init_msg)
            decode_msg = strdup(init_msg);
        html_secure_strip_all(b, utf8_from_string(pool, charset, decode_msg, len));
        
        text = buffer_fetch(b, 0, buffer_size(b), NIL);
    } else
        text = utf8_from_string(pool, charset, decode_msg, len);

    bputs(b, ">");
    for (s = text; *s;) {
        if ((s[0] == '\015') || (s[0] == '\012')) {
            if ((s[0] == '\015') && (s[1] == '\012'))
                s += 2;     /* CRLF */
            else
                s++;        /* CR or LF */
            bputs(b, CRLF ">");

            /* Check for sigdash at start of line */
            if ((s[0] == '-') && (s[1] == '-') && (s[2] == ' ')  &&
                ((s[3] == '\015') || (s[3] == '\012')))
                break;
        } else
            bputc(b, *s++);
    }

    if (decode_msg != init_msg)
        fs_give((void **) &decode_msg);

    return(T);
}

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

void cmd_reply2(struct session *session)
{
    struct request *request = session->request;
    struct draft *draft = session->draft;
    struct options *options = session->options;
    struct prefs *prefs = options->prefs;
    unsigned long msgno;
    unsigned long msgno_uid;
    char *s, *opt_cc;
    MAILSTREAM *stream = session->stream;
    MESSAGECACHE *elt;
    ENVELOPE *env;
    ADDRESS *sender;
    struct buffer *b = request->write_buffer;
    char *postponed_text = "";

    request_decode_form(request);
    if ((s = assoc_lookup(request->form, "role")))
        draft_role_set(draft, role_find(options->role_list, s));

    msgno = session->current;
    msgno_uid = ml_uid(session, stream, msgno);

    if (!(msgno = stream_check_uid(session, stream, msgno, msgno_uid))) {
        session_redirect(session, request, "list");
        return;
    }

    if (!((elt = ml_elt(session, stream, msgno)) &&
          (env = ml_fetch_structure(session, stream, msgno, NIL, 0)))) {
        session_redirect(session, request, "restart");
        return;
    }

    sender = (env->reply_to) ? (env->reply_to) : (env->from);

    /* Calculate possible Cc value from message recipients */
    if (env->to) {
        opt_cc = pool_strdup(request->pool,
                             addr_text_exclude(session, request->pool,
                                               env->to, sender));
        if (env->cc) {
            s = addr_text_exclude(session, request->pool, env->cc, sender);
            if (s && s[0]) {
                if (opt_cc && opt_cc[0])
                    opt_cc = pool_strcat3(request->pool, opt_cc, ", ", s);
                else
                    opt_cc = pool_strdup(request->pool, s);
            }
        }
    } else if (env->cc) {
        opt_cc = pool_strdup(request->pool,
                             addr_text_exclude(session, request->pool,
                                               env->cc, sender));
    } else
        opt_cc = NIL;

    /* Write out exiting draft */
    if (draft->have_draft) {
        if (!draft_write(draft)) {
            session_message_clear(session);
            session_message(session,
                            "Failed to postpone existing draft before reply");
            session_log(session,
                        "[cmd_reply2] Failed to postponed draft message: %s",
                        ml_errmsg());
            session_redirect(session, session->request, "compose");
            return;
        }
        draft_free(draft);
        postponed_text = " Postponed existing draft.";
    }

    draft_init(draft);
    draft_init_rich_headers(draft);

    /* Record message that we are responding to here */
    draft_set_reply(draft, stream, session->foldername, msgno);

    /* Set To address */
    if (sender && sender->mailbox && sender->host) {
        char *s = string_decode_mime(request->pool,
                                     addr_text(request->pool, sender));

        draft->to = pool_strdup(draft->pool, s);
    }

    /* Set Cc address */
    if (opt_cc && opt_cc[0] && (session->reply_all)) {
        char *s = string_decode_mime(request->pool, opt_cc);

        draft->cc = pool_strdup(draft->pool, s);
    }

    /* Create temporary scratch buffer */
    b = buffer_create(draft->pool, 0);

    if ((sender = env->from)) {
        if (prefs->use_full_date)
            bprintf(b, "On %s, ",
                    string_date_to_string_long(elt->month, elt->day,
                                               elt->year + BASEYEAR));
        else
            bprintf(b, "On %s, ",
                    string_date_to_string_short(elt->month, elt->day));

        /* XXX Factor out rfc1522_decode calls */
        if (sender->personal) {
            unsigned long len = strlen(sender->personal) + 20;
            char *buffer = pool_alloc(b->pool, len);    /* Decoded form smaller */
            char *d =
                (char *) rfc1522_decode((unsigned char *) buffer, len,
                                        sender->personal, NIL);
            bprintf(b, "%s wrote:" CRLF "" CRLF, d);
        } else if (sender->mailbox && sender->host)
            bprintf(b, "%s@%s wrote:" CRLF "" CRLF, sender->mailbox,
                    sender->host);
    }

    if (!add_text(session, b, request->pool, stream, msgno)) {
        session_redirect(session, request, "restart");
        return;
    }

    if (draft->role && draft->role->signature && draft->role->signature[0]) {
        bputs(b, "" CRLF "" CRLF);
        if (string_check_sigdash(draft->role->signature))
            bputs(b, "-- " CRLF);
        bprintf(b, "%s" CRLF, draft->role->signature);
    } else if (prefs->signature && prefs->signature[0]) {
        bputs(b, "" CRLF "" CRLF);
        if (string_check_sigdash(prefs->signature))
            bputs(b, "-- " CRLF);
        bprintf(b, "%s" CRLF, prefs->signature);
    }

    /* Get full copy of buffer */
    draft->body = buffer_fetch(b, 0, buffer_size(b), NIL);

    if (prefs->line_wrap_on_reply)
        draft_line_wrap_body(draft);

    if (!(env = ml_fetch_structure(session, stream, msgno, NIL, 0))) {
        session_redirect(session, request, "restart");
        return;
    }

    if (env->subject && env->subject) {
        char *s = string_decode_mime(request->pool, env->subject);

        if (!strncasecmp(s, "Re: ", strlen("Re: ")))
            draft->subject = pool_strdup(draft->pool, s);
        else
            draft->subject = pool_strcat(draft->pool, "Re: ", s);
    }

    session_message(session, "Replying to message %d.%s", msgno,
                    postponed_text);
    session_redirect(session, request, "compose");
}
