From f83e1927a6225699522918bbdf581c2b73efbe71 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Fri, 17 Apr 2020 16:35:52 -0400 Subject: Write attachment files All this path stuff needs cleaning up. I think it's time to use the template renderer for paths. --- export.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 10 deletions(-) (limited to 'export.c') diff --git a/export.c b/export.c index 21f5662..9aa3126 100644 --- a/export.c +++ b/export.c @@ -15,11 +15,14 @@ */ #include +#include #include +#include #include #include #include #include +#include #include #include @@ -115,8 +118,58 @@ static void exportAtom( if (error) err(EX_IOERR, "%s", path); } +static struct Attachment exportAttachment( + const struct Envelope *envelope, struct List section, + const struct BodyPart *part, struct Data body +) { + struct Attachment attach = { "", "", "" }; + strlcpy( + attach.path[0], pathSafe(envelope->messageID), sizeof(attach.path[0]) + ); + for (size_t i = 0; i < section.len; ++i) { + uint32_t num = dataCheck(section.ptr[i], Number).number; + char buf[32]; + snprintf(buf, sizeof(buf), "%s%" PRIu32, (i ? "." : ""), num); + strlcat(attach.path[1], buf, sizeof(attach.path[1])); + } + struct List params = part->disposition.params; + for (size_t i = 0; i + 1 < params.len; i += 2) { + const char *key = dataCheck(params.ptr[i], String).string; + if (strcasecmp(key, "filename")) continue; + const char *value = dataCheck(params.ptr[i + 1], String).string; + strlcpy(attach.path[2], pathSafe(value), sizeof(attach.path[2])); + } + if (!attach.path[2][0]) { + const char *disposition = part->disposition.type; + if (!disposition) disposition = "INLINE"; + strlcat(attach.path[2], pathSafe(disposition), sizeof(attach.path[2])); + strlcat(attach.path[2], ".", sizeof(attach.path[2])); + strlcat(attach.path[2], pathSafe(part->subtype), sizeof(attach.path[2])); + } + + char path[PATH_MAX + 1] = "attachment"; + for (int i = 0; i < 2; ++i) { + strlcat(path, "/", sizeof(path)); + strlcat(path, attach.path[i], sizeof(path)); + int error = mkdir(path, 0775); + if (error && errno != EEXIST) err(EX_CANTCREAT, "%s", path); + } + strlcat(path, "/", sizeof(path)); + strlcat(path, attach.path[2], sizeof(path)); + + FILE *file = fopen(path, "w"); + if (!file) err(EX_CANTCREAT, "%s", path); + + int error = 0 + || decodeToFile(file, part, dataCheck(body, String).string) + || fclose(file); + if (error) err(EX_IOERR, "%s", path); + + return attach; +} + static int exportHTMLBody( - FILE *file, struct List *section, + FILE *file, const struct Envelope *envelope, struct List *section, const struct BodyPart *part, struct Data body ) { int error = 0; @@ -124,36 +177,46 @@ static int exportHTMLBody( for (size_t i = part->parts.len - 1; i < part->parts.len; --i) { if (!isInline(&part->parts.ptr[i])) continue; return exportHTMLBody( - file, section, &part->parts.ptr[i], - dataCheck(body, List).list.ptr[i] + file, envelope, section, + &part->parts.ptr[i], dataCheck(body, List).list.ptr[i] ); } return exportHTMLBody( - file, section, &part->parts.ptr[part->parts.len - 1], + file, envelope, section, + &part->parts.ptr[part->parts.len - 1], dataCheck(body, List).list.ptr[part->parts.len - 1] ); + } else if (part->multipart) { for (size_t i = 0; i < part->parts.len; ++i) { struct Data num = { .type = Number, .number = 1 + i }; listPush(section, num); error = exportHTMLBody( - file, section, &part->parts.ptr[i], - dataCheck(body, List).list.ptr[i] + file, envelope, section, + &part->parts.ptr[i], dataCheck(body, List).list.ptr[i] ); if (error) return error; section->len--; } - } else if (part->message.envelope) { + + } else if (part->message.structure) { + const struct BodyPart *structure = part->message.structure; error = 0 || htmlMessageOpen(file, part->message.envelope) - || exportHTMLBody(file, section, part->message.structure, body) + || exportHTMLBody(file, envelope, section, structure, body) || htmlMessageClose(file); + } else if (isInline(part)) { char *content = decodeToString(part, dataCheck(body, String).string); error = htmlInline(file, part, content); free(content); + } else { - // TODO: Write out attachment. + // TODO: Open and close attachment lists. + struct Attachment attach = exportAttachment( + envelope, *section, part, body + ); + error = htmlAttachment(file, part, &attach); } return error; } @@ -170,7 +233,7 @@ static void exportHTML( if (error) err(EX_IOERR, "%s", path); struct List section = {0}; - error = exportHTMLBody(file, §ion, structure, body); + error = exportHTMLBody(file, envelope, §ion, structure, body); if (error) err(EX_IOERR, "%s", path); listFree(section); -- cgit 1.4.1 /tr> 2022-04-03Publish "Care"June McEnroe 2022-03-31Publish "Compassion"June McEnroe 2022-03-24Skip matches with ident chars on either sideJune McEnroe This fixes, for example, where the link gets placed on static regex_t regex(const char *pattern, int flags) in title.c. 2022-03-24Add The Invisible Life of Addie LaRueJune McEnroe So good, but so long. Reminded me of The Ten Thousand Doors of January at the beginning, and more of that N. K. Jemisin series about gods later. I like this interacting with gods and becoming something like one sort of thing. God, it took me a whole month (more?) to read and this is only my third book of the year :( I need some more novellas to read, but the other books I have from the library currently are also thick. 2022-03-22Source ~/.profile.local if it existsJune McEnroe 2022-03-18Publish "Addendum 2021"June McEnroe 2022-03-16Remove wcwidth portJune McEnroe DYLD_FORCE_FLAT_NAMESPACE no longer exists in macOS 12 so this approach doesn't work anymore. Moved to <https://git.causal.agency/jorts/tree/wcwidth> and compiled into <https://git.causal.agency/jorts/tree/ncurses>. 2022-03-16Remove -j4 from ./PlanJune McEnroe Plan learned to set this automatically! 2022-03-15Rewrite Linux install.sh for DebianJune McEnroe 2022-03-15Remove dashJune McEnroe