/* 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 #include "imap.h" struct Address { char *name; const char *mailbox; const char *host; }; static inline const char *addressName(struct Address addr) { return (addr.name ? addr.name : addr.mailbox); } struct AddressList { size_t len; struct Address *addrs; }; struct Envelope { time_t time; const char *date; char *subject; struct Address from, sender, replyTo; struct AddressList to, cc, bcc; const char *inReplyTo; const char *messageID; }; static inline void envelopeFree(struct Envelope envelope) { free(envelope.subject); free(envelope.from.name); free(envelope.sender.name); free(envelope.replyTo.name); for (size_t i = 0; i < envelope.to.len; ++i) { free(envelope.to.addrs[i].name); } for (size_t i = 0; i < envelope.cc.len; ++i) { free(envelope.cc.addrs[i].name); } for (size_t i = 0; i < envelope.bcc.len; ++i) { free(envelope.bcc.addrs[i].name); } free(envelope.to.addrs); free(envelope.cc.addrs); free(envelope.bcc.addrs); } struct BodyPart { bool multipart; union { const char *type; struct { size_t len; struct BodyPart *ptr; } parts; }; const char *subtype; struct List params; const char *id; const char *description; const char *encoding; uint32_t size; struct { struct Envelope *envelope; struct BodyPart *structure; uint32_t lines; } message; struct { uint32_t lines; } text; const char *md5; struct { const char *type; struct List params; } disposition; struct List language; struct List location; }; static inline void bodyPartFree(struct BodyPart part) { if (part.multipart) { for (size_t i = 0; i < part.parts.len; ++i) { bodyPartFree(part.parts.ptr[i]); } } if (part.message.envelope) { envelopeFree(*part.message.envelope); free(part.message.envelope); } if (part.message.structure) { bodyPartFree(*part.message.structure); free(part.message.structure); } } void parseEnvelope(struct Envelope *envelope, struct List list); void parseBodyPart(struct BodyPart *part, struct List list); bool exportFetch(FILE *imap, enum Atom tag, struct List threads); bool exportData(FILE *imap, enum Atom tag, struct List items); void concatFetch(FILE *imap, enum Atom tag, struct List threads); void concatData(struct List threads, struct List items); #define TEMPLATE(...) #__VA_ARGS__ struct Variable { const char *name; const char *value; }; typedef int EscapeFn(FILE *file, const char *str); int escapeURL(FILE *file, const char *str); int escapeXML(FILE *file, const char *str); int templateRender( FILE *file, const char *template, const struct Variable vars[], EscapeFn *escape ); char *templateURL(const char *template, const struct Variable vars[]); static inline const char *pathUID(uint32_t uid, const char *type) { static char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "UID/%" PRIu32 ".%s", uid, type); return buf; } static inline const char *pathMangle(const char *messageID) { if (!strchr(messageID, '/')) return messageID; static char buf[PATH_MAX]; strlcpy(buf, messageID, sizeof(buf)); for (char *ptr = buf; (ptr = strchr(ptr, '/')); ++ptr) { *ptr = ';'; } return buf; } static inline const char *pathMessage(const char *messageID, const char *type) { static char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "message/%s.%s", pathMangle(messageID), type); return buf; } static inline const char *pathThread(const char *messageID, const char *type) { static char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "thread/%s.%s", pathMangle(messageID), type); return buf; } #define MBOX_HEADERS \ "Date Subject From Sender Reply-To To Cc Bcc " \ "Message-Id In-Reply-To References " \ "MIME-Version Content-Type Content-Disposition Content-Transfer-Encoding" int mboxFrom(FILE *file); int mboxHeader(FILE *file, const char *header); int mboxBody(FILE *file, const char *body); int htmlMessageHead(FILE *file, const struct Envelope *envelope); int htmlMessageTail(FILE *file); int htmlThreadHead(FILE *file, const struct Envelope *envelope); int htmlThreadHeader(FILE *file, const struct Envelope *envelope); int htmlThreadOpen(FILE *file); int htmlThreadClose(FILE *file); int htmlThreadTail(FILE *file); int atomEntryOpen(FILE *file, const struct Envelope *envelope); int atomEntryClose(FILE *file); int atomFeedOpen(FILE *file, const struct Envelope *envelope); int atomFeedClose(FILE *file);