8 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
9 static int b64_val
[256];
11 static void b64_init(void)
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
)
21 v
|= b64_val
[(unsigned char) s
[0]];
23 v
|= b64_val
[(unsigned char) s
[1]];
25 v
|= b64_val
[(unsigned char) s
[2]];
27 v
|= b64_val
[(unsigned char) s
[3]];
34 return 3 - (s
[1] == '=') - (s
[2] == '=') - (s
[3] == '=');
37 static void dec_b64(struct sbuf
*sb
, char *s
, char *e
)
42 while (s
< e
&& isspace((unsigned char) *s
))
46 int n
= b64_dec(dst
, s
);
53 static int hexval(int c
)
55 if (c
>= '0' && c
<= '9')
57 if (c
>= 'A' && c
<= 'F')
59 if (c
>= 'a' && c
<= 'f')
64 static void dec_qp(struct sbuf
*sb
, char *s
, char *e
)
67 if (*s
== '=' && s
[1] == '\n') {
69 } else if (*s
== '=' && s
+ 2 < e
) {
70 sbuf_chr(sb
, (hexval(s
[1]) << 4) | hexval(s
[2]));
73 sbuf_chr(sb
, *s
== '_' ? ' ' : (unsigned char) *s
);
79 static void msg_hdrdec2(struct sbuf
*sb
, char *hdr
, char *end
)
82 char *q1
= hdr
[0] == '=' && hdr
[1] == '?' ? hdr
+ 1 : NULL
;
83 char *q2
= q1
? memchr(q1
+ 1, '?', end
- q1
) : NULL
;
84 char *q3
= q2
? memchr(q2
+ 1, '?', end
- q2
) : NULL
;
85 char *q4
= q3
? memchr(q3
+ 1, '?', end
- q3
) : NULL
;
86 if (q1
&& q2
&& q3
&& q4
&& q4
[1] == '=') {
87 int c
= tolower((unsigned char) q2
[1]);
89 dec_b64(sb
, q3
+ 1, q4
);
91 dec_qp(sb
, q3
+ 1, q4
);
93 while (isspace((unsigned char) *hdr
) && hdr
+ 1 < end
)
96 sbuf_chr(sb
, (unsigned char) *hdr
++);
101 char *msg_hdrdec(char *hdr
)
105 msg_hdrdec2(sb
, hdr
, strchr(hdr
, '\0'));
106 return sbuf_done(sb
);
109 /* decoding mime messages */
111 #define MAXPARTS (1 << 3)
112 #define BOUNDLEN (1 << 7)
114 #define TYPE_TXT 0x01
115 #define TYPE_MPART 0x02
116 #define TYPE_ETC 0x04
124 char bound
[MAXPARTS
][BOUNDLEN
];
129 static void copy_till(struct mime
*m
, struct sbuf
*dst
, char *s
)
131 int len
= s
- m
->src
;
132 sbuf_mem(dst
, m
->src
, len
);
136 static void read_boundary(struct mime
*m
, char *s
, char *hdrend
)
138 char *bound
= m
->bound
[m
->depth
];
140 s
= memchr(s
, '=', hdrend
- s
);
146 e
= memchr(s
, '"', hdrend
- s
);
149 while (e
< hdrend
&& !isspace(*e
) && *e
!= ';')
156 memcpy(bound
+ 2, s
, e
- s
);
157 bound
[e
- s
+ 2] = '\0';
161 static char *hdr_nextfield(char *s
, char *e
)
163 while (s
&& s
< e
&& *s
!= ';')
165 if ((s
= memchr(s
, '"', e
- s
)))
167 return s
&& s
+ 2 < e
? s
+ 1 : NULL
;
170 static int read_hdrs(struct mime
*m
, struct sbuf
*dst
)
175 while (s
&& s
< e
&& *s
!= '\n') {
176 char *n
= memchr(s
, '\n', e
- s
);
177 while (n
&& n
+ 1 < e
&& n
[1] != '\n' && isspace(n
[1]))
178 n
= memchr(n
+ 1, '\n', e
- n
- 1);
181 if (startswith(s
, "Content-Type:")) {
182 char *key
= strchr(s
, ':') + 1;
183 char *hdrend
= s
+ hdrlen(s
, e
- s
);
185 while (key
< hdrend
&& isspace(*key
))
187 if (startswith(key
, "text"))
189 if (startswith(key
, "multipart"))
191 if (startswith(key
, "boundary"))
192 read_boundary(m
, key
, hdrend
);
193 key
= hdr_nextfield(key
, hdrend
);
196 if (startswith(s
, "Content-Transfer-Encoding:")) {
197 char *key
= strchr(s
, ':') + 1;
198 char *hdrend
= s
+ hdrlen(s
, e
- s
);
200 while (key
< hdrend
&& isspace(*key
))
202 if (startswith(key
, "quoted-printable"))
204 if (startswith(key
, "base64"))
206 key
= hdr_nextfield(key
, hdrend
);
209 msg_hdrdec2(dst
, s
, n
);
217 static int is_bound(struct mime
*m
, char *s
)
219 return startswith(s
, m
->bound
[m
->depth
- 1]);
222 static void read_bound(struct mime
*m
, struct sbuf
*dst
)
225 int len
= strlen(m
->bound
[m
->depth
- 1]);
226 if (s
[len
] == '-' && s
[len
+ 1] == '-')
228 s
= memchr(s
, '\n', m
->end
- s
);
229 s
= s
? s
+ 1 : m
->end
;
230 copy_till(m
, dst
, s
);
233 static char *find_bound(struct mime
*m
)
240 if (!(s
= memchr(s
, '\n', e
- s
)))
247 static void read_body(struct mime
*m
, struct sbuf
*dst
, int type
)
249 char *end
= m
->depth
? find_bound(m
) : m
->end
;
250 if (~type
& TYPE_TXT
) {
251 copy_till(m
, dst
, end
);
255 dec_qp(dst
, m
->src
, end
);
259 if (type
& ENC_B64
) {
260 dec_b64(dst
, m
->src
, end
);
265 copy_till(m
, dst
, end
);
268 int msg_demime(char *msg
, long msglen
, char **mod
, long *modlen
)
270 struct sbuf
*dst
= sbuf_make();
273 m
.end
= msg
+ msglen
;
275 while ((m
.depth
&& m
.src
< m
.end
) || m
.src
== msg
) {
276 int type
= read_hdrs(&m
, dst
);
277 read_body(&m
, dst
, type
);
282 *modlen
= sbuf_len(dst
) - 1;
283 *mod
= sbuf_done(dst
);