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
+ 2 < e
) {
68 sbuf_chr(sb
, (hexval(s
[1]) << 4) | hexval(s
[2]));
71 sbuf_chr(sb
, *s
== '_' ? ' ' : (unsigned char) *s
);
77 static void msg_hdrdec2(struct sbuf
*sb
, char *hdr
, char *end
)
80 char *q1
= hdr
[0] == '=' && hdr
[1] == '?' ? hdr
+ 1 : NULL
;
81 char *q2
= q1
? memchr(q1
+ 1, '?', end
- q1
) : NULL
;
82 char *q3
= q2
? memchr(q2
+ 1, '?', end
- q2
) : NULL
;
83 char *q4
= q3
? memchr(q3
+ 1, '?', end
- q3
) : NULL
;
84 if (q1
&& q2
&& q3
&& q4
&& q4
[1] == '=') {
85 int c
= tolower((unsigned char) q2
[1]);
87 dec_b64(sb
, q3
+ 1, q4
);
89 dec_qp(sb
, q3
+ 1, q4
);
91 while (isspace((unsigned char) *hdr
) && hdr
+ 1 < end
)
94 sbuf_chr(sb
, (unsigned char) *hdr
++);
99 char *msg_hdrdec(char *hdr
)
103 msg_hdrdec2(sb
, hdr
, strchr(hdr
, '\0'));
104 return sbuf_done(sb
);
107 /* decoding mime messages */
109 #define MAXPARTS (1 << 3)
110 #define BOUNDLEN (1 << 7)
112 #define TYPE_TXT 0x01
113 #define TYPE_MPART 0x02
114 #define TYPE_ETC 0x04
122 char bound
[MAXPARTS
][BOUNDLEN
];
128 static void copy_till(struct mime
*m
, struct sbuf
*dst
, char *s
)
130 int len
= s
- m
->src
;
131 sbuf_mem(dst
, m
->src
, len
);
135 static void read_boundary(struct mime
*m
, char *s
, char *hdrend
)
137 char *bound
= m
->bound
[m
->depth
];
139 s
= memchr(s
, '=', hdrend
- s
);
145 e
= memchr(s
, '"', hdrend
- s
);
148 while (e
< hdrend
&& !isspace(*e
) && *e
!= ';')
155 memcpy(bound
+ 2, s
, e
- s
);
156 bound
[e
- s
+ 2] = '\0';
160 static char *hdr_nextfield(char *s
, char *e
)
162 while (s
&& s
< e
&& *s
!= ';')
164 if ((s
= memchr(s
, '"', e
- s
)))
166 return s
&& s
+ 2 < e
? s
+ 1 : NULL
;
169 static int read_hdrs(struct mime
*m
, struct sbuf
*dst
)
174 while (s
&& s
< e
&& *s
!= '\n') {
175 char *n
= memchr(s
, '\n', e
- s
);
176 while (n
&& n
+ 1 < e
&& n
[1] != '\n' && isspace(n
[1]))
177 n
= memchr(n
+ 1, '\n', e
- n
- 1);
180 if (startswith(s
, "Content-Type:")) {
181 char *key
= strchr(s
, ':') + 1;
182 char *hdrend
= s
+ hdrlen(s
, e
- s
);
184 while (key
< hdrend
&& isspace(*key
))
186 if (startswith(key
, "text"))
188 if (startswith(key
, "multipart"))
190 if (startswith(key
, "boundary"))
191 read_boundary(m
, key
, hdrend
);
192 key
= hdr_nextfield(key
, hdrend
);
195 if (startswith(s
, "Content-Transfer-Encoding:")) {
196 char *key
= strchr(s
, ':') + 1;
197 char *hdrend
= s
+ hdrlen(s
, e
- s
);
199 while (key
< hdrend
&& isspace(*key
))
201 if (startswith(key
, "quoted-printable"))
203 if (startswith(key
, "base64"))
205 key
= hdr_nextfield(key
, hdrend
);
208 msg_hdrdec2(dst
, s
, n
);
216 static int is_bound(struct mime
*m
, char *s
)
218 return startswith(s
, m
->bound
[m
->depth
- 1]);
221 static void read_bound(struct mime
*m
, struct sbuf
*dst
)
224 int len
= strlen(m
->bound
[m
->depth
- 1]);
225 if (s
[len
] == '-' && s
[len
+ 1] == '-')
227 s
= memchr(s
, '\n', m
->end
- s
);
228 s
= s
? s
+ 1 : m
->end
;
229 copy_till(m
, dst
, s
);
232 static char *find_bound(struct mime
*m
)
239 if (!(s
= memchr(s
, '\n', e
- s
)))
246 static void read_body(struct mime
*m
, struct sbuf
*dst
, int type
)
248 char *end
= m
->depth
? find_bound(m
) : m
->end
;
249 if (~type
& TYPE_TXT
) {
250 copy_till(m
, dst
, end
);
254 dec_qp(dst
, m
->src
, end
);
258 if (type
& ENC_B64
) {
259 dec_b64(dst
, m
->src
, end
);
263 copy_till(m
, dst
, end
);
266 int msg_demime(char *msg
, long msglen
, char **mod
, long *modlen
)
268 struct sbuf
*dst
= sbuf_make();
271 m
.end
= msg
+ msglen
;
272 while ((m
.depth
&& m
.src
< m
.end
) || m
.src
== msg
) {
273 int type
= read_hdrs(&m
, dst
);
274 read_body(&m
, dst
, type
);
279 *modlen
= sbuf_len(dst
) - 1;
280 *mod
= sbuf_done(dst
);