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 char *dec_b64(char *dst
, char *src
, int len
)
39 char *end
= src
+ len
;
42 while (src
+ 4 <= end
) {
43 while (src
< end
&& isspace(*src
))
46 dst
+= b64_dec(dst
, src
);
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 char *dec_qp(char *d
, char *s
, int len
)
66 static char t
[1 << 10];
80 char *enc_qu
= memchr(s
+ 2, '?', end
- s
- 4);
82 int b64
= tolower(enc_qu
[1]) == 'b';
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
);
94 *d
++ = hexval(s
[1]) << 4 | hexval(s
[2]);
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
113 char bound
[MAXPARTS
][BOUNDLEN
];
119 static void copy_till(struct mime
*m
, char *s
)
121 int len
= s
- m
->src
;
122 memcpy(m
->dst
, m
->src
, len
);
127 static void read_boundary(struct mime
*m
, char *s
, char *hdrend
)
129 char *bound
= m
->bound
[m
->depth
];
131 s
= memchr(s
, '=', hdrend
- s
);
137 e
= memchr(s
, '"', hdrend
- s
);
140 while (e
< hdrend
&& !isspace(*e
) && *e
!= ';')
147 memcpy(bound
+ 2, s
, e
- s
);
148 bound
[e
- s
+ 2] = '\0';
152 static char *hdr_nextfield(char *s
, char *e
)
154 while (s
&& s
< e
&& *s
!= ';')
156 if ((s
= memchr(s
, '"', e
- s
)))
158 return s
&& s
+ 2 < e
? s
+ 1 : NULL
;
161 static int read_hdrs(struct mime
*m
)
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);
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
);
179 if (startswith(s
, "Content-Type:")) {
180 char *key
= strchr(s
, ':') + 1;
181 char *hdrend
= s
+ hdr_len(s
);
183 while (key
< hdrend
&& isspace(*key
))
185 if (startswith(key
, "text"))
187 if (startswith(key
, "multipart"))
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
);
198 while (key
< hdrend
&& isspace(*key
))
200 if (startswith(key
, "quoted-printable"))
202 if (startswith(key
, "base64"))
204 key
= hdr_nextfield(key
, hdrend
);
210 copy_till(m
, s
? s
+ 1 : e
);
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
)
222 int len
= strlen(m
->bound
[m
->depth
- 1]);
223 if (s
[len
] == '-' && s
[len
+ 1] == '-')
225 s
= memchr(s
, '\n', m
->end
- s
);
226 s
= s
? s
+ 1 : m
->end
;
230 static char *find_bound(struct mime
*m
)
237 if (!(s
= memchr(s
, '\n', e
- s
)))
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
) {
252 m
->dst
= dec_qp(m
->dst
, m
->src
, end
- m
->src
);
256 if (type
& ENC_B64
) {
257 m
->dst
= dec_b64(m
->dst
, m
->src
, end
- m
->src
);
264 int mime_decode(char *dst
, char *src
, int len
)
267 memset(&m
, 0, sizeof(m
));
271 while ((m
.depth
&& m
.src
< m
.end
) || m
.src
== src
) {
272 int type
= read_hdrs(&m
);