diff options
Diffstat (limited to '')
-rw-r--r-- | parse.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/parse.c b/parse.c index d3c907f..33acd5b 100644 --- a/parse.c +++ b/parse.c @@ -102,3 +102,125 @@ void parseEnvelope(struct Envelope *envelope, struct List list) { } envelope->messageID = parseID(dataCheck(list.ptr[MessageID], String).string); } + +static void parseDisposition(struct BodyPart *part, struct List list) { + if (list.len < 2) errx(EX_PROTOCOL, "missing disposition fields"); + part->disposition.type = dataCheck(list.ptr[0], String).string; + if (list.ptr[1].type == List) { + part->disposition.params = list.ptr[1].list; + } +} + +static void parseNonMultipart(struct BodyPart *part, struct List list) { + enum { Type, Subtype, Params, ID, Description, Encoding, Size, BasicLen }; + if (list.len < BasicLen) errx(EX_PROTOCOL, "missing body part fields"); + + part->multipart = false; + part->type = dataCheck(list.ptr[Type], String).string; + part->subtype = dataCheck(list.ptr[Subtype], String).string; + if (list.ptr[Params].type == List) { + part->params = list.ptr[Params].list; + } + if (list.ptr[ID].type == String) { + part->id = list.ptr[ID].string; + } + if (list.ptr[Description].type == String) { + part->description = list.ptr[Description].string; + } + part->encoding = dataCheck(list.ptr[Encoding], String).string; + part->size = dataCheck(list.ptr[Size], Number).number; + + list.len -= BasicLen; + list.ptr += BasicLen; + + if (!strcmp(part->type, "MESSAGE") && !strcmp(part->subtype, "RFC822")) { + enum { Envelope, BodyStructure, Lines, MessageLen }; + if (list.len < MessageLen) { + errx(EX_PROTOCOL, "missing body part message fields"); + } + part->message.envelope = calloc(1, sizeof(*part->message.envelope)); + part->message.structure = calloc(1, sizeof(*part->message.structure)); + if (!part->message.envelope || !part->message.structure) { + err(EX_OSERR, "calloc"); + } + + parseEnvelope( + part->message.envelope, + dataCheck(list.ptr[Envelope], List).list + ); + parseBodyPart( + part->message.structure, + dataCheck(list.ptr[BodyStructure], List).list + ); + part->message.lines = dataCheck(list.ptr[Lines], Number).number; + + list.len -= MessageLen; + list.ptr += MessageLen; + } + + if (!strcmp(part->type, "TEXT")) { + if (!list.len) errx(EX_PROTOCOL, "missing body part text lines"); + part->text.lines = dataCheck(list.ptr[0], Number).number; + list.len--; + list.ptr++; + } + + enum { MD5, Disposition, Language, Location }; + if (MD5 < list.len && list.ptr[MD5].type == String) { + part->md5 = list.ptr[MD5].string; + } + if (Disposition < list.len && list.ptr[Disposition].type == List) { + parseDisposition(part, list.ptr[Disposition].list); + } + if (Language < list.len && list.ptr[Language].type == List) { + part->language = list.ptr[Language].list; + } + if (Location < list.len && list.ptr[Location].type == List) { + part->location = list.ptr[Location].list; + } +} + +static void parseMultipart(struct BodyPart *part, struct List list) { + part->multipart = true; + for ( + part->parts.len = 0; + part->parts.len < list.len && list.ptr[part->parts.len].type == List; + part->parts.len++ + ); + part->parts.ptr = calloc(part->parts.len, sizeof(*part->parts.ptr)); + if (!part->parts.ptr) err(EX_OSERR, "calloc"); + + for (size_t i = 0; i < part->parts.len; ++i) { + parseBodyPart(&part->parts.ptr[i], list.ptr[i].list); + } + list.len -= part->parts.len; + list.ptr += part->parts.len; + + if (!list.len) errx(EX_PROTOCOL, "missing multipart subtype"); + part->subtype = dataCheck(list.ptr[0], String).string; + list.len--; + list.ptr++; + + enum { Params, Disposition, Language, Location }; + if (Params < list.len && list.ptr[Params].type == List) { + part->params = list.ptr[Params].list; + } + if (Disposition < list.len && list.ptr[Disposition].type == List) { + parseDisposition(part, list.ptr[Disposition].list); + } + if (Language < list.len && list.ptr[Language].type == List) { + part->language = list.ptr[Language].list; + } + if (Location < list.len && list.ptr[Location].type == List) { + part->location = list.ptr[Location].list; + } +} + +void parseBodyPart(struct BodyPart *part, struct List list) { + if (!list.len) errx(EX_PROTOCOL, "empty body part"); + if (list.ptr[0].type != List) { + parseNonMultipart(part, list); + } else { + parseMultipart(part, list); + } +} |