/* Copyright (C) 2020 C. McEnroe * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "archive.h" static int htmlAddress(FILE *file, const char *class, struct Address addr) { const char *template; if (addr.host) { template = TEMPLATE(
  • [name]
  • ); } else if (addr.mailbox) { template = TEMPLATE(
  • [mailbox]
      ); } else { template = TEMPLATE(
  • ); } struct Variable vars[] = { { "class", class }, { "name", addressName(addr) }, { "mailbox", addr.mailbox }, {0}, }; return templateRender(file, template, vars, escapeXML); } static int htmlAddressList(FILE *file, const char *class, struct AddressList list) { if (!list.len) return 0; const char *template = TEMPLATE(
      ); struct Variable vars[] = { { "class", class }, {0}, }; int error = templateRender(file, template, vars, escapeXML); if (error) return error; for (size_t i = 0; i < list.len; ++i) { error = htmlAddress(file, class, list.addrs[i]); if (error) return error; } return templateRender(file, TEMPLATE(
    ), NULL, NULL); } static char *htmlMailto(const struct Envelope *envelope) { const char *template = { "mailto:[mailbox]@[host]?subject=[re][subject]&In-Reply-To=[messageID]" }; struct Variable vars[] = { { "mailbox", envelope->from.mailbox }, { "host", envelope->from.host }, { "re", (strncmp(envelope->subject, "Re: ", 4) ? "Re: " : "") }, { "subject", envelope->subject }, { "messageID", envelope->messageID }, {0}, }; return templateURL(template, vars); } static char *htmlFragment(const struct Envelope *envelope) { struct Variable vars[] = { { "messageID", envelope->messageID }, {0}, }; return templateURL("#[messageID]", vars); } static char *htmlMbox(const struct Envelope *envelope) { struct Variable vars[] = { { "messageID", envelope->messageID }, { "type", "mbox" }, {0}, }; return templateURL("../" PATH_MESSAGE, vars); } int htmlMessageOpen(FILE *file, const struct Envelope *envelope) { // TODO: Conditionally include mailto: link. const char *template = TEMPLATE(

    [subject]

    [from]
    ); char *fragment = htmlFragment(envelope); char *mailto = htmlMailto(envelope); char *mbox = htmlMbox(envelope); char utc[sizeof("0000-00-00T00:00:00Z")]; strftime(utc, sizeof(utc), "%FT%TZ", gmtime(&envelope->time)); struct Variable vars[] = { { "messageID", envelope->messageID }, { "fragment", fragment }, { "subject", envelope->subject }, { "mailto", mailto }, { "from", addressName(envelope->from) }, { "utc", utc }, { "date", envelope->date }, { "mbox", mbox }, {0}, }; int error = 0 || templateRender(file, template, vars, escapeXML) || htmlAddressList(file, "to", envelope->to) || htmlAddressList(file, "cc", envelope->cc) || templateRender(file, TEMPLATE(
    ), NULL, NULL); free(mailto); free(fragment); free(mbox); return error; } int htmlInline(FILE *file, const struct BodyPart *part, const char *content) { // TODO: Include Content-Id as id? // TODO: format=flowed. // TODO: Process quoting. // TODO: Highlight patches. const char *template = TEMPLATE(
    [content]
    ); const char *lang = ""; // FIXME: part->language should be more structured. if (part->language.len && part->language.ptr[0].type == String) { lang = part->language.ptr[0].string; } struct Variable vars[] = { { "lang", lang }, { "content", content }, {0}, }; return templateRender(file, template, vars, escapeXML); } int htmlAttachment( FILE *file, const struct BodyPart *part, const struct Variable *path ) { const char *template = TEMPLATE( [name][type][/][subtype] ); char *url = templateURL("../" PATH_ATTACHMENT, path); const char *name = paramGet(part->disposition.params, "filename"); struct Variable vars[] = { { "url", url }, { "name", (name ? name : "") }, { "type", (name ? "" : part->type) }, { "/", (name ? "" : "/") }, { "subtype", (name ? "" : part->subtype) }, {0}, }; int error = templateRender(file, template, vars, escapeXML); free(url); return error; } int htmlMessageClose(FILE *file) { return templateRender(file, TEMPLATE(
    ), NULL, NULL); } const char *htmlTitle; static char *htmlThreadURL(const struct Envelope *envelope, const char *type) { struct Variable vars[] = { { "messageID", envelope->messageID }, { "type", type }, {0}, }; return templateURL("../" PATH_THREAD, vars); } int htmlThreadHead(FILE *file, const struct Envelope *envelope) { const char *template = TEMPLATE( [subject] · [title] ); char *atom = htmlThreadURL(envelope, "atom"); char *mbox = htmlThreadURL(envelope, "mbox"); struct Variable vars[] = { { "subject", envelope->subject }, { "title", htmlTitle }, { "atom", atom }, { "mbox", mbox }, {0}, }; int error = templateRender(file, template, vars, escapeXML); free(atom); free(mbox); return error; } int htmlThreadOpen(FILE *file, const struct Envelope *envelope) { const char *template = TEMPLATE(

    [subject]

    ); char *atom = htmlThreadURL(envelope, "atom"); char *mbox = htmlThreadURL(envelope, "mbox"); struct Variable vars[] = { { "subject", envelope->subject }, { "atom", atom }, { "mbox", mbox }, {0}, }; int error = templateRender(file, template, vars, escapeXML); free(atom); free(mbox); return error; } static size_t threadCount(struct List thread) { size_t count = 0; for (size_t i = 0; i < thread.len; ++i) { if (thread.ptr[i].type == List) { count += threadCount(thread.ptr[i].list); } else { count++; } } return count; } int htmlSubthreadOpen(FILE *file, struct List thread) { const char *template = TEMPLATE(
    [replies] repl[ies] ); size_t count = threadCount(thread); char replies[32]; snprintf(replies, sizeof(replies), "%zu", count); struct Variable vars[] = { { "replies", replies }, { "ies", (count > 1 ? "ies" : "y") }, {0}, }; return templateRender(file, template, vars, escapeXML); } int htmlSubthreadClose(FILE *file) { return templateRender(file, TEMPLATE(
    ), NULL, NULL); } int htmlThreadClose(FILE *file) { return templateRender(file, TEMPLATE(
    ), NULL, NULL); }