send: read reply-to header
[mailx.git] / mime.c
blob575405130296da0d295bcb6fc929c67584f71b7f
1 #include <ctype.h>
2 #include <string.h>
3 #include "mbox.h"
4 #include "mime.h"
5 #include "str.h"
7 static char *b64_ch =
8 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
9 static int b64_val[256];
11 static void b64_init(void)
13 int i;
14 for (i = 0; i < 64; i++)
15 b64_val[(unsigned char) b64_ch[i]] = i;
18 static int b64_dec(char *d, char *s)
20 unsigned v = 0;
21 v |= b64_val[(unsigned char) s[0]];
22 v <<= 6;
23 v |= b64_val[(unsigned char) s[1]];
24 v <<= 6;
25 v |= b64_val[(unsigned char) s[2]];
26 v <<= 6;
27 v |= b64_val[(unsigned char) s[3]];
29 d[2] = v & 0xff;
30 v >>= 8;
31 d[1] = v & 0xff;
32 v >>= 8;
33 d[0] = v & 0xff;
34 return 3 - (s[1] == '=') - (s[2] == '=') - (s[3] == '=');
37 static char *dec_b64(char *dst, char *src, int len)
39 char *end = src + len;
40 if (!b64_val['B'])
41 b64_init();
42 while (src + 4 <= end) {
43 while (src < end && isspace(*src))
44 src++;
45 if (src < end) {
46 dst += b64_dec(dst, src);
47 src += 4;
50 return dst;
53 static int hexval(int c)
55 if (c >= '0' && c <= '9')
56 return c - '0';
57 if (c >= 'A' && c <= 'F')
58 return 10 + c - 'A';
59 if (c >= 'a' && c <= 'f')
60 return 10 + c - 'a';
61 return 0;
64 static char *dec_qp(char *d, char *s, int len)
66 static char t[1 << 10];
67 char *end = s + len;
68 int i;
69 s--;
70 while (++s < end) {
71 if (*s != '=') {
72 *d++ = *s;
73 continue;
75 if (s[1] == '\n') {
76 s++;
77 continue;
79 if (s[1] == '?') {
80 char *enc_qu = memchr(s + 2, '?', end - s - 4);
81 if (enc_qu) {
82 int b64 = tolower(enc_qu[1]) == 'b';
83 char *b = enc_qu + 3;
84 char *e = memchr(b, '?', end - b);
85 if (e && sizeof(t) > e - b) {
86 for (i = 0; i < e - b; i++)
87 t[i] = b[i] == '_' ? ' ' : b[i];
88 d = (b64 ? dec_b64 : dec_qp)(d, t, e - b);
89 s = e + 1;
90 continue;
94 *d++ = hexval(s[1]) << 4 | hexval(s[2]);
95 s += 2;
97 return d;
100 #define MAXPARTS (1 << 3)
101 #define BOUNDLEN (1 << 7)
103 #define TYPE_TXT 0x00
104 #define TYPE_MPART 0x01
105 #define TYPE_ETC 0x02
106 #define ENC_B8 0x00
107 #define ENC_QP 0x10
108 #define ENC_B64 0x20
110 struct mime {
111 int depth;
112 int part[MAXPARTS];
113 char bound[MAXPARTS][BOUNDLEN];
114 char *src;
115 char *dst;
116 char *end;
119 static void copy_till(struct mime *m, char *s)
121 int len = s - m->src;
122 memcpy(m->dst, m->src, len);
123 m->dst += len;
124 m->src += len;
127 static void read_boundary(struct mime *m, char *s, char *hdrend)
129 char *bound = m->bound[m->depth];
130 char *e;
131 s = memchr(s, '=', hdrend - s);
132 if (!s)
133 return;
134 s++;
135 if (*s == '"') {
136 s++;
137 e = memchr(s, '"', hdrend - s);
138 } else {
139 e = s;
140 while (e < hdrend && !isspace(*e) && *e != ';')
141 e++;
143 if (!e)
144 return;
145 bound[0] = '-';
146 bound[1] = '-';
147 memcpy(bound + 2, s, e - s);
148 bound[e - s + 2] = '\0';
149 m->depth++;
152 static char *hdr_nextfield(char *s, char *e)
154 while (s && s < e && *s != ';')
155 if (*s++ == '"')
156 if ((s = memchr(s, '"', e - s)))
157 s++;
158 return s && s + 2 < e ? s + 1 : NULL;
161 static int read_hdrs(struct mime *m)
163 char *s = m->src;
164 char *e = m->end;
165 int type = 0;
166 while (s && s < e && *s != '\n') {
167 char *n = memchr(s, '\n', e - s);
168 while (n && n + 1 < e && n[1] != '\n' && isspace(n[1]))
169 n = memchr(n + 1, '\n', e - n - 1);
170 if (!n)
171 break;
172 n++;
173 copy_till(m, s);
174 if (startswith(s, "Subject:") || startswith(s, "From:") ||
175 startswith(s, "To:") || startswith(s, "Cc:")) {
176 m->dst = dec_qp(m->dst, m->src, n - s);
177 m->src = n;
179 if (startswith(s, "Content-Type:")) {
180 char *key = strchr(s, ':') + 1;
181 char *hdrend = s + hdr_len(s);
182 while (key) {
183 while (key < hdrend && isspace(*key))
184 key++;
185 if (startswith(key, "text"))
186 type |= TYPE_TXT;
187 if (startswith(key, "multipart"))
188 type |= TYPE_MPART;
189 if (startswith(key, "boundary"))
190 read_boundary(m, key, hdrend);
191 key = hdr_nextfield(key, hdrend);
194 if (startswith(s, "Content-Transfer-Encoding:")) {
195 char *key = strchr(s, ':') + 1;
196 char *hdrend = s + hdr_len(s);
197 while (key) {
198 while (key < hdrend && isspace(*key))
199 key++;
200 if (startswith(key, "quoted-printable"))
201 type |= ENC_QP;
202 if (startswith(key, "base64"))
203 type |= ENC_B64;
204 key = hdr_nextfield(key, hdrend);
208 s = n;
210 copy_till(m, s ? s + 1 : e);
211 return type;
214 static int is_bound(struct mime *m, char *s)
216 return startswith(s, m->bound[m->depth - 1]);
219 static void read_bound(struct mime *m)
221 char *s = m->src;
222 int len = strlen(m->bound[m->depth - 1]);
223 if (s[len] == '-' && s[len + 1] == '-')
224 m->depth--;
225 s = memchr(s, '\n', m->end - s);
226 s = s ? s + 1 : m->end;
227 copy_till(m, s);
230 static char *find_bound(struct mime *m)
232 char *s = m->src;
233 char *e = m->end;
234 while (s < e) {
235 if (is_bound(m, s))
236 return s;
237 if (!(s = memchr(s, '\n', e - s)))
238 break;
239 s++;
241 return e;
244 static void read_body(struct mime *m, int type)
246 char *end = m->depth ? find_bound(m) : m->end;
247 if (~type & TYPE_TXT) {
248 copy_till(m, end);
249 return;
251 if (type & ENC_QP) {
252 m->dst = dec_qp(m->dst, m->src, end - m->src);
253 m->src = end;
254 return;
256 if (type & ENC_B64) {
257 m->dst = dec_b64(m->dst, m->src, end - m->src);
258 m->src = end;
259 return;
261 copy_till(m, end);
264 int mime_decode(char *dst, char *src, int len)
266 struct mime m;
267 memset(&m, 0, sizeof(m));
268 m.src = src;
269 m.dst = dst;
270 m.end = src + len;
271 while ((m.depth && m.src < m.end) || m.src == src) {
272 int type = read_hdrs(&m);
273 read_body(&m, type);
274 if (m.depth)
275 read_bound(&m);
277 *m.dst = '\0';
278 return m.dst - dst;