6 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7 static int b64_val
[256];
9 static void b64_init(void)
12 for (i
= 0; i
< 64; i
++)
13 b64_val
[b64_ch
[i
]] = i
;
16 static int b64_dec(char *d
, char *s
)
32 return 3 - (s
[1] == '=') - (s
[2] == '=') - (s
[3] == '=');
35 static char *dec_b64(char *dst
, char *src
, int len
)
37 char *end
= src
+ len
;
40 while (src
+ 4 <= end
) {
41 while (src
< end
&& isspace(*src
))
44 dst
+= b64_dec(dst
, src
);
51 static int hexval(int c
)
53 if (c
>= '0' && c
<= '9')
55 if (c
>= 'A' && c
<= 'F')
57 if (c
>= 'a' && c
<= 'f')
62 static char *dec_qp(char *d
, char *s
, int len
)
64 static char t
[1 << 10];
78 char *enc_qu
= memchr(s
+ 2, '?', end
- s
- 4);
80 int b64
= tolower(enc_qu
[1]) == 'b';
82 char *e
= memchr(b
, '?', end
- b
);
83 if (e
&& sizeof(t
) > e
- b
) {
84 for (i
= 0; i
< e
- b
; i
++)
85 t
[i
] = b
[i
] == '_' ? ' ' : b
[i
];
86 d
= (b64
? dec_b64
: dec_qp
)(d
, t
, e
- b
);
92 *d
++ = hexval(s
[1]) << 4 | hexval(s
[2]);
98 #define MAXPARTS (1 << 3)
99 #define BOUNDLEN (1 << 7)
101 #define TYPE_TXT 0x00
102 #define TYPE_MPART 0x01
103 #define TYPE_ETC 0x02
111 char bound
[MAXPARTS
][BOUNDLEN
];
117 static void copy_till(struct mime
*m
, char *s
)
119 int len
= s
- m
->src
;
120 memcpy(m
->dst
, m
->src
, len
);
125 static int starts(char *r
, char *s
)
128 if (tolower(*s
++) != tolower(*r
++))
133 static void read_boundary(struct mime
*m
, char *s
)
135 char *bound
= m
->bound
[m
->depth
];
137 s
= memchr(s
, '=', m
->end
- s
);
143 e
= memchr(s
, '"', m
->end
- s
);
146 while (e
< m
->end
&& !isspace(*e
))
153 memcpy(bound
+ 2, s
, e
- s
);
154 bound
[e
- s
+ 2] = '\0';
158 static int read_hdrs(struct mime
*m
)
163 while (s
&& s
< e
&& *s
!= '\n') {
164 char *n
= memchr(s
, '\n', e
- s
);
165 while (n
&& n
+ 1 < e
&& n
[1] != '\n' && isspace(n
[1]))
166 n
= memchr(n
+ 1, '\n', e
- n
- 1);
171 if (starts(s
, "Subject:") || starts(s
, "From:")) {
172 m
->dst
= dec_qp(m
->dst
, m
->src
, n
- s
);
175 if (starts(s
, "Content-Type:")) {
176 char *t
= strchr(s
, ':') + 1;
177 while (isspace(*t
) && t
< e
)
179 if (starts(t
, "text"))
181 if (starts(t
, "multipart")) {
186 if (starts(s
, "Content-Transfer-Encoding:")) {
187 char *t
= strchr(s
, ':') + 1;
188 while (isspace(*t
) && t
< e
)
190 if (starts(t
, "quoted-printable"))
192 if (starts(t
, "base64"))
198 copy_till(m
, s
? s
+ 1 : e
);
202 static int is_bound(struct mime
*m
, char *s
)
204 return starts(s
, m
->bound
[m
->depth
- 1]);
207 static void read_bound(struct mime
*m
)
210 int len
= strlen(m
->bound
[m
->depth
- 1]);
211 if (s
[len
] == '-' && s
[len
+ 1] == '-')
213 s
= memchr(s
, '\n', m
->end
- s
);
214 s
= s
? s
+ 1 : m
->end
;
218 static char *find_bound(struct mime
*m
)
225 if (!(s
= memchr(s
, '\n', e
- s
)))
232 static void read_body(struct mime
*m
, int type
)
234 char *end
= m
->depth
? find_bound(m
) : m
->end
;
235 if (~type
& TYPE_TXT
) {
240 m
->dst
= dec_qp(m
->dst
, m
->src
, end
- m
->src
);
244 if (type
& ENC_B64
) {
245 m
->dst
= dec_b64(m
->dst
, m
->src
, end
- m
->src
);
252 int mime_decode(char *dst
, char *src
, int len
)
255 memset(&m
, 0, sizeof(m
));
259 while ((m
.depth
&& m
.src
< m
.end
) || m
.src
== src
) {
260 int type
= read_hdrs(&m
);