From 4d35c86401b4a947689eac375ec4ba29b3c99d6d Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Sun, 19 Apr 2020 11:27:26 -0400 Subject: Use template system for paths and URLs This probably still needs a lot of cleaning up. --- export.c | 124 ++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 68 insertions(+), 56 deletions(-) (limited to 'export.c') diff --git a/export.c b/export.c index 9aa3126..873870c 100644 --- a/export.c +++ b/export.c @@ -29,15 +29,28 @@ #include "archive.h" #include "imap.h" +static const char *exportPath(uint32_t uid, const char *type) { + char str[32]; + snprintf(str, sizeof(str), "%" PRIu32, uid); + struct Variable vars[] = { + { "uid", str }, + { "type", type }, + {0}, + }; + static char buf[PATH_MAX + 1]; + templateBuffer(buf, sizeof(buf), PATH_UID, vars, escapePath); + return buf; +} + bool exportFetch(FILE *imap, enum Atom tag, struct List threads) { struct List uids = {0}; listFlatten(&uids, threads); for (size_t i = uids.len - 1; i < uids.len; --i) { uint32_t uid = dataCheck(uids.ptr[i], Number).number; int error = 0 - || access(pathUID(uid, "atom"), F_OK) - || access(pathUID(uid, "html"), F_OK) - || access(pathUID(uid, "mbox"), F_OK); + || access(exportPath(uid, "atom"), F_OK) + || access(exportPath(uid, "html"), F_OK) + || access(exportPath(uid, "mbox"), F_OK); if (!error) uids.ptr[i] = uids.ptr[--uids.len]; } if (!uids.len) { @@ -61,7 +74,7 @@ static void exportMbox( uint32_t uid, const struct Envelope *envelope, const char *header, const char *body ) { - const char *path = pathUID(uid, "mbox"); + const char *path = exportPath(uid, "mbox"); FILE *file = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); int error = 0 @@ -71,10 +84,17 @@ static void exportMbox( || fclose(file); if (error) err(EX_IOERR, "%s", path); - const char *msg = pathMessage(envelope->messageID, "mbox"); - unlink(msg); - error = link(path, msg); - if (error) err(EX_CANTCREAT, "%s", msg); + char buf[PATH_MAX + 1]; + struct Variable vars[] = { + { "messageID", envelope->messageID }, + { "type", "mbox" }, + {0}, + }; + templateBuffer(buf, sizeof(buf), PATH_MESSAGE, vars, escapePath); + + unlink(buf); + error = link(path, buf); + if (error) err(EX_CANTCREAT, "%s", buf); } static bool isInline(const struct BodyPart *part) { @@ -87,7 +107,7 @@ static void exportAtom( uint32_t uid, const struct Envelope *envelope, const struct BodyPart *structure, struct Data body ) { - const char *path = pathUID(uid, "atom"); + const char *path = exportPath(uid, "atom"); FILE *file = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); @@ -118,61 +138,55 @@ static void exportAtom( if (error) err(EX_IOERR, "%s", path); } -static struct Attachment exportAttachment( - const struct Envelope *envelope, struct List section, +static int exportHTMLAttachment( + FILE *file, 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 buf[256] = ""; + for (size_t i = 0; i < section->len; ++i) { + snprintf( + &buf[strlen(buf)], sizeof(buf) - strlen(buf), "%s%" PRIu32, + (i ? "." : ""), dataCheck(section->ptr[i], Number).number + ); } - - char path[PATH_MAX + 1] = "attachment"; - for (int i = 0; i < 2; ++i) { - strlcat(path, "/", sizeof(path)); - strlcat(path, attach.path[i], sizeof(path)); + const char *name = paramGet(part->disposition.params, "filename"); + const char *disposition = part->disposition.type; + if (!disposition) disposition = "INLINE"; + + char path[PATH_MAX + 1]; + struct Variable vars[] = { + { "messageID", envelope->messageID }, + { "section", buf }, + { "name", (name ? name : "") }, + { "disposition", (name ? "" : disposition) }, + { ".", (name ? "" : ".") }, + { "subtype", (name ? "" : part->subtype) }, + {0}, + }; + templateBuffer(path, sizeof(path), PATH_ATTACHMENT, vars, escapePath); + + for (char *ch = path; (ch = strchr(ch, '/')); ++ch) { + *ch = '\0'; int error = mkdir(path, 0775); if (error && errno != EEXIST) err(EX_CANTCREAT, "%s", path); + *ch = '/'; } - strlcat(path, "/", sizeof(path)); - strlcat(path, attach.path[2], sizeof(path)); - FILE *file = fopen(path, "w"); + FILE *attachment = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); int error = 0 - || decodeToFile(file, part, dataCheck(body, String).string) - || fclose(file); + || decodeToFile(attachment, part, dataCheck(body, String).string) + || fclose(attachment); if (error) err(EX_IOERR, "%s", path); - return attach; + return htmlAttachment(file, part, vars); } static int exportHTMLBody( FILE *file, const struct Envelope *envelope, struct List *section, const struct BodyPart *part, struct Data body ) { - int error = 0; if (bodyPartType(part, "multipart", "alternative")) { for (size_t i = part->parts.len - 1; i < part->parts.len; --i) { if (!isInline(&part->parts.ptr[i])) continue; @@ -191,41 +205,39 @@ static int exportHTMLBody( for (size_t i = 0; i < part->parts.len; ++i) { struct Data num = { .type = Number, .number = 1 + i }; listPush(section, num); - error = exportHTMLBody( + int error = exportHTMLBody( file, envelope, section, &part->parts.ptr[i], dataCheck(body, List).list.ptr[i] ); if (error) return error; section->len--; } + return 0; } else if (part->message.structure) { const struct BodyPart *structure = part->message.structure; - error = 0 + int error = 0 || htmlMessageOpen(file, part->message.envelope) || exportHTMLBody(file, envelope, section, structure, body) || htmlMessageClose(file); + return error; } else if (isInline(part)) { char *content = decodeToString(part, dataCheck(body, String).string); - error = htmlInline(file, part, content); + int error = htmlInline(file, part, content); free(content); + return error; } else { - // TODO: Open and close attachment lists. - struct Attachment attach = exportAttachment( - envelope, *section, part, body - ); - error = htmlAttachment(file, part, &attach); + return exportHTMLAttachment(file, envelope, section, part, body); } - return error; } static void exportHTML( uint32_t uid, const struct Envelope *envelope, const struct BodyPart *structure, struct Data body ) { - const char *path = pathUID(uid, "html"); + const char *path = exportPath(uid, "html"); FILE *file = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); -- cgit 1.4.1