1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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);
}
|