diff options
Diffstat (limited to '')
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | archive.h | 2 | ||||
-rw-r--r-- | export.c | 86 | ||||
-rw-r--r-- | parse.c | 104 |
4 files changed, 108 insertions, 85 deletions
diff --git a/Makefile b/Makefile index bdb5986..8e63376 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ OBJS += export.o OBJS += html.o OBJS += imap.o OBJS += mbox.o +OBJS += parse.o OBJS += template.o dev: tags all diff --git a/archive.h b/archive.h index 83f2e76..b43fe87 100644 --- a/archive.h +++ b/archive.h @@ -64,6 +64,8 @@ static inline void envelopeFree(struct Envelope envelope) { free(envelope.bcc.addrs); } +void parseEnvelope(struct Envelope *envelope, struct List list); + bool exportFetch(FILE *imap, enum Atom tag, struct List threads); void exportData(struct List items); diff --git a/export.c b/export.c index 6e3554c..c563c3f 100644 --- a/export.c +++ b/export.c @@ -78,90 +78,6 @@ bool exportFetch(FILE *imap, enum Atom tag, struct List threads) { return true; } -static struct Address parseAddress(struct List list) { - if (list.len < 4) { - errx(EX_PROTOCOL, "missing address structure fields"); - } - struct Address addr = {0}; - if (list.ptr[0].type == String) { - // TODO: Decode UTF-8 in name. - addr.name = strdup(list.ptr[0].string); - if (!addr.name) err(EX_OSERR, "strdup"); - } - if (list.ptr[2].type == String) addr.mailbox = list.ptr[2].string; - if (list.ptr[3].type == String) addr.host = list.ptr[3].string; - return addr; -} - -static struct AddressList parseAddressList(struct List list) { - struct Address *addrs = calloc(list.len, sizeof(*addrs)); - if (!addrs) err(EX_OSERR, "calloc"); - for (size_t i = 0; i < list.len; ++i) { - addrs[i] = parseAddress(dataCheck(list.ptr[i], List).list); - } - return (struct AddressList) { list.len, addrs }; -} - -static char *parseID(char *id) { - size_t len = strlen(id); - if (id[0] != '<' || !len || id[len - 1] != '>') { - errx(EX_PROTOCOL, "invalid message ID"); - } - id[len - 1] = '\0'; - return &id[1]; -} - -static struct Envelope parseEnvelope(struct List list) { - enum { - Date, Subject, From, Sender, ReplyTo, - To, Cc, Bcc, InReplyTo, MessageID, - EnvelopeLen, - }; - if (list.len < EnvelopeLen) { - errx(EX_PROTOCOL, "missing envelope structure fields"); - } - struct Envelope envelope = {0}; - - const char *date = dataCheck(list.ptr[Date], String).string; - date = strptime(date, "%a, %e %b %Y %H:%M:%S %z", &envelope.date); - if (!date) errx(EX_PROTOCOL, "invalid envelope date format"); - - envelope.date.tm_isdst = -1; - envelope.utc = mktime(&envelope.date); - - // TODO: Decode UTF-8 in subject. - envelope.subject = strdup(dataCheck(list.ptr[Subject], String).string); - if (!envelope.subject) err(EX_OSERR, "strdup"); - - for (size_t i = From; i <= Bcc; ++i) { - if (list.ptr[i].type == List) continue; - if (list.ptr[i].type == Atom && list.ptr[i].atom == AtomNil) { - list.ptr[i].type = List; - list.ptr[i].list = (struct List) {0}; - continue; - } - errx(EX_PROTOCOL, "invalid envelope address field"); - } - for (size_t i = From; i <= ReplyTo; ++i) { - if (!list.ptr[i].list.len || list.ptr[i].list.ptr[0].type != List) { - errx(EX_PROTOCOL, "invalid envelope address field"); - } - } - envelope.from = parseAddress(list.ptr[From].list.ptr[0].list); - envelope.sender = parseAddress(list.ptr[Sender].list.ptr[0].list); - envelope.replyTo = parseAddress(list.ptr[ReplyTo].list.ptr[0].list); - envelope.to = parseAddressList(list.ptr[To].list); - envelope.cc = parseAddressList(list.ptr[Cc].list); - envelope.bcc = parseAddressList(list.ptr[Bcc].list); - - if (list.ptr[InReplyTo].type == String) { - envelope.inReplyTo = parseID(list.ptr[InReplyTo].string); - } - envelope.messageID = parseID(dataCheck(list.ptr[MessageID], String).string); - - return envelope; -} - void exportData(struct List items) { uint32_t uid = 0; struct Envelope envelope = {0}; @@ -188,7 +104,7 @@ void exportData(struct List items) { } else if (name == AtomUID) { uid = dataCheck(items.ptr[i + 1], Number).number; } else if (name == AtomEnvelope) { - envelope = parseEnvelope(dataCheck(items.ptr[i + 1], List).list); + parseEnvelope(&envelope, dataCheck(items.ptr[i + 1], List).list); } else if (name == AtomHeaderFields) { header = dataCheck(items.ptr[i + 1], String).string; } else if (name == AtomText) { diff --git a/parse.c b/parse.c new file mode 100644 index 0000000..d3c907f --- /dev/null +++ b/parse.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2020 C. McEnroe <june@causal.agency> + * + * 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 <https://www.gnu.org/licenses/>. + */ + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <sysexits.h> + +#include "archive.h" +#include "imap.h" + +static struct Address parseAddress(struct List list) { + if (list.len < 4) { + errx(EX_PROTOCOL, "missing address structure fields"); + } + struct Address addr = {0}; + if (list.ptr[0].type == String) { + // TODO: Decode UTF-8 in name. + addr.name = strdup(list.ptr[0].string); + if (!addr.name) err(EX_OSERR, "strdup"); + } + if (list.ptr[2].type == String) addr.mailbox = list.ptr[2].string; + if (list.ptr[3].type == String) addr.host = list.ptr[3].string; + return addr; +} + +static struct AddressList parseAddressList(struct List list) { + struct Address *addrs = calloc(list.len, sizeof(*addrs)); + if (!addrs) err(EX_OSERR, "calloc"); + for (size_t i = 0; i < list.len; ++i) { + addrs[i] = parseAddress(dataCheck(list.ptr[i], List).list); + } + return (struct AddressList) { list.len, addrs }; +} + +static char *parseID(char *id) { + size_t len = strlen(id); + if (id[0] != '<' || !len || id[len - 1] != '>') { + errx(EX_PROTOCOL, "invalid message ID"); + } + id[len - 1] = '\0'; + return &id[1]; +} + +void parseEnvelope(struct Envelope *envelope, struct List list) { + enum { + Date, Subject, From, Sender, ReplyTo, + To, Cc, Bcc, InReplyTo, MessageID, + EnvelopeLen, + }; + if (list.len < EnvelopeLen) { + errx(EX_PROTOCOL, "missing envelope structure fields"); + } + + const char *date = dataCheck(list.ptr[Date], String).string; + date = strptime(date, "%a, %e %b %Y %H:%M:%S %z", &envelope->date); + if (!date) errx(EX_PROTOCOL, "invalid envelope date format"); + + envelope->date.tm_isdst = -1; + envelope->utc = mktime(&envelope->date); + + // TODO: Decode UTF-8 in subject. + envelope->subject = strdup(dataCheck(list.ptr[Subject], String).string); + if (!envelope->subject) err(EX_OSERR, "strdup"); + + for (size_t i = From; i <= Bcc; ++i) { + if (list.ptr[i].type == List) continue; + if (list.ptr[i].type == Atom && list.ptr[i].atom == AtomNil) { + list.ptr[i].type = List; + list.ptr[i].list = (struct List) {0}; + continue; + } + errx(EX_PROTOCOL, "invalid envelope address field"); + } + for (size_t i = From; i <= ReplyTo; ++i) { + if (!list.ptr[i].list.len || list.ptr[i].list.ptr[0].type != List) { + errx(EX_PROTOCOL, "invalid envelope address field"); + } + } + envelope->from = parseAddress(list.ptr[From].list.ptr[0].list); + envelope->sender = parseAddress(list.ptr[Sender].list.ptr[0].list); + envelope->replyTo = parseAddress(list.ptr[ReplyTo].list.ptr[0].list); + envelope->to = parseAddressList(list.ptr[To].list); + envelope->cc = parseAddressList(list.ptr[Cc].list); + envelope->bcc = parseAddressList(list.ptr[Bcc].list); + + if (list.ptr[InReplyTo].type == String) { + envelope->inReplyTo = parseID(list.ptr[InReplyTo].string); + } + envelope->messageID = parseID(dataCheck(list.ptr[MessageID], String).string); +} |