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
];
130 static void copy_till(struct mime
*m
, struct sbuf
*dst
, char *s
)
132 int len
= s
- m
->src
;
133 sbuf_mem(dst
, m
->src
, len
);
137 static void read_boundary(struct mime
*m
, char *s
, char *hdrend
)
139 char *bound
= m
->bound
[m
->depth
];
141 s
= memchr(s
, '=', hdrend
- s
);
147 e
= memchr(s
, '"', hdrend
- s
);
150 while (e
< hdrend
&& !isspace(*e
) && *e
!= ';')
157 memcpy(bound
+ 2, s
, e
- s
);
158 bound
[e
- s
+ 2] = '\0';
162 static char *hdr_nextfield(char *s
, char *e
)
164 while (s
&& s
< e
&& *s
!= ';')
166 if ((s
= memchr(s
, '"', e
- s
)))
168 return s
&& s
+ 2 < e
? s
+ 1 : NULL
;
171 static int read_hdrs(struct mime
*m
, struct sbuf
*dst
)
176 while (s
&& s
< e
&& *s
!= '\n') {
177 char *n
= memchr(s
, '\n', e
- s
);
178 while (n
&& n
+ 1 < e
&& n
[1] != '\n' && isspace(n
[1]))
179 n
= memchr(n
+ 1, '\n', e
- n
- 1);
182 if (startswith(s
, "Content-Type:")) {
183 char *key
= strchr(s
, ':') + 1;
184 char *hdrend
= s
+ hdrlen(s
, e
- s
);
186 while (key
< hdrend
&& isspace(*key
))
188 if (startswith(key
, "text"))
190 if (startswith(key
, "multipart"))
192 if (startswith(key
, "boundary"))
193 read_boundary(m
, key
, hdrend
);
194 key
= hdr_nextfield(key
, hdrend
);
197 if (startswith(s
, "Content-Transfer-Encoding:")) {
198 char *key
= strchr(s
, ':') + 1;
199 char *hdrend
= s
+ hdrlen(s
, e
- s
);
201 while (key
< hdrend
&& isspace(*key
))
203 if (startswith(key
, "quoted-printable"))
205 if (startswith(key
, "base64"))
207 key
= hdr_nextfield(key
, hdrend
);
210 msg_hdrdec2(dst
, s
, n
);
218 static int is_bound(struct mime
*m
, char *s
)
220 return startswith(s
, m
->bound
[m
->depth
- 1]);
223 static void read_bound(struct mime
*m
, struct sbuf
*dst
)
226 int len
= strlen(m
->bound
[m
->depth
- 1]);
227 if (s
[len
] == '-' && s
[len
+ 1] == '-')
229 s
= memchr(s
, '\n', m
->end
- s
);
230 s
= s
? s
+ 1 : m
->end
;
231 copy_till(m
, dst
, s
);
234 static char *find_bound(struct mime
*m
)
241 if (!(s
= memchr(s
, '\n', e
- s
)))
248 static void read_body(struct mime
*m
, struct sbuf
*dst
, int type
)
250 char *end
= m
->depth
? find_bound(m
) : m
->end
;
251 if (~type
& TYPE_TXT
) {
252 copy_till(m
, dst
, end
);
256 dec_qp(dst
, m
->src
, end
);
260 if (type
& ENC_B64
) {
261 dec_b64(dst
, m
->src
, end
);
266 copy_till(m
, dst
, end
);
269 int msg_demime(char *msg
, long msglen
, char **mod
, long *modlen
)
271 struct sbuf
*dst
= sbuf_make();
274 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
);