1
2
3
4
5
6
7
8
9
10#include "libbb.h"
11#include "mail.h"
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
103int makemime_main(int argc UNUSED_PARAM, char **argv)
104{
105 llist_t *opt_headers = NULL, *l;
106 const char *opt_output;
107#define boundary opt_output
108
109 enum {
110 OPT_c = 1 << 0,
111 OPT_e = 1 << 1,
112 OPT_o = 1 << 2,
113 OPT_C = 1 << 3,
114 OPT_N = 1 << 4,
115 OPT_a = 1 << 5,
116 OPT_m = 1 << 6,
117 OPT_j = 1 << 7,
118 };
119
120 INIT_G();
121
122
123 opt_complementary = "a::";
124 opts = getopt32(argv,
125 "c:e:o:C:N:a:m:j:",
126 &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers, NULL, NULL
127 );
128
129 argv += optind;
130
131
132 if (opts & OPT_o)
133 freopen(opt_output, "w", stdout);
134
135
136 if (!*argv)
137 *--argv = (char *)"-";
138
139
140 for (l = opt_headers; l; l = l->link)
141 puts(l->data);
142
143
144 srand(monotonic_us());
145 boundary = xasprintf("%u-%u-%u",
146 (unsigned)rand(), (unsigned)rand(), (unsigned)rand());
147
148
149 printf(
150 "Mime-Version: 1.0\n"
151 "Content-Type: multipart/mixed; boundary=\"%s\"\n"
152 , boundary
153 );
154
155
156 while (*argv) {
157 printf(
158 "\n--%s\n"
159 "Content-Type: %s; charset=%s\n"
160 "Content-Disposition: inline; filename=\"%s\"\n"
161 "Content-Transfer-Encoding: base64\n"
162 , boundary
163 , G.content_type
164 , G.opt_charset
165 , bb_get_last_path_component_strip(*argv)
166 );
167 encode_base64(*argv++, (const char *)stdin, "");
168 }
169
170
171 printf("\n--%s--\n" "\n", boundary);
172
173 return EXIT_SUCCESS;
174#undef boundary
175}
176
177static const char *find_token(const char *const string_array[], const char *key, const char *defvalue)
178{
179 const char *r = NULL;
180 int i;
181 for (i = 0; string_array[i] != NULL; i++) {
182 if (strcasecmp(string_array[i], key) == 0) {
183 r = (char *)string_array[i+1];
184 break;
185 }
186 }
187 return (r) ? r : defvalue;
188}
189
190static const char *xfind_token(const char *const string_array[], const char *key)
191{
192 const char *r = find_token(string_array, key, NULL);
193 if (r)
194 return r;
195 bb_error_msg_and_die("header: %s", key);
196}
197
198enum {
199 OPT_x = 1 << 0,
200 OPT_X = 1 << 1,
201#if ENABLE_FEATURE_REFORMIME_COMPAT
202 OPT_d = 1 << 2,
203 OPT_e = 1 << 3,
204 OPT_i = 1 << 4,
205 OPT_s = 1 << 5,
206 OPT_r = 1 << 6,
207 OPT_c = 1 << 7,
208 OPT_m = 1 << 8,
209 OPT_h = 1 << 9,
210 OPT_o = 1 << 10,
211 OPT_O = 1 << 11,
212#endif
213};
214
215static int parse(const char *boundary, char **argv)
216{
217 char *line, *s, *p;
218 const char *type;
219 int boundary_len = strlen(boundary);
220 const char *delims = " ;\"\t\r\n";
221 const char *uniq;
222 int ntokens;
223 const char *tokens[32];
224
225
226 uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname());
227
228
229
230 while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) {
231
232
233
234 p = NULL;
235 s = line;
236 while ((s = strcasestr(s, "Content-Type:")) != NULL)
237 p = s++;
238 if (!p)
239 goto next;
240
241
242
243
244 ntokens = 0;
245 tokens[ntokens] = NULL;
246 for (s = strtok(p, delims); s; s = strtok(NULL, delims)) {
247 tokens[ntokens] = s;
248 if (ntokens < ARRAY_SIZE(tokens) - 1)
249 ntokens++;
250
251 }
252 tokens[ntokens] = NULL;
253
254
255
256 type = find_token(tokens, "Content-Type:", "text/plain");
257
258 if (0 == strncasecmp(type, "multipart/", 10)) {
259 if (0 == strcasecmp(type+10, "mixed")) {
260 parse(xfind_token(tokens, "boundary="), argv);
261 } else
262 bb_error_msg_and_die("no support of content type '%s'", type);
263 } else {
264 pid_t pid = pid;
265 int rc;
266 FILE *fp;
267
268 const char *charset = find_token(tokens, "charset=", CONFIG_FEATURE_MIME_CHARSET);
269
270 const char *encoding = find_token(tokens, "Content-Transfer-Encoding:", "7bit");
271
272 char *filename = (char *)find_token(tokens, "filename=", NULL);
273 if (!filename)
274 filename = xasprintf(uniq, monotonic_us());
275 else
276 filename = bb_get_last_path_component_strip(xstrdup(filename));
277
278
279 if (opts & OPT_X) {
280 int fd[2];
281 xpipe(fd);
282 pid = vfork();
283 if (0 == pid) {
284
285 close(fd[1]);
286 xmove_fd(fd[0], STDIN_FILENO);
287 xsetenv("CONTENT_TYPE", type);
288 xsetenv("CHARSET", charset);
289 xsetenv("ENCODING", encoding);
290 xsetenv("FILENAME", filename);
291 BB_EXECVP_or_die(argv);
292 }
293
294 close(fd[0]);
295 fp = xfdopen_for_write(fd[1]);
296 signal(SIGPIPE, SIG_IGN);
297
298 } else {
299 char *fname = xasprintf("%s%s", *argv, filename);
300 fp = xfopen_for_write(fname);
301 free(fname);
302 }
303
304
305 free(filename);
306
307
308 if (0 == strcasecmp(encoding, "base64")) {
309 decode_base64(stdin, fp);
310 } else if (0 != strcasecmp(encoding, "7bit")
311 && 0 != strcasecmp(encoding, "8bit")
312 ) {
313
314 bb_error_msg_and_die("no support of encoding '%s'", encoding);
315 } else {
316
317
318
319
320
321
322
323
324
325 p = xmalloc_fgets_str(stdin, "\r\n");
326 while (p) {
327 s = xmalloc_fgets_str(stdin, "\r\n");
328 if (s == NULL)
329 break;
330 if ('-' == s[0]
331 && '-' == s[1]
332 && 0 == strncmp(s+2, boundary, boundary_len)
333 ) {
334 break;
335 }
336 fputs(p, fp);
337 p = s;
338 }
339
340
341
342
343
344
345
346
347
348
349
350
351
352 }
353 fclose(fp);
354
355
356 if (opts & OPT_X) {
357 signal(SIGPIPE, SIG_DFL);
358
359 rc = (wait4pid(pid) & 0xff);
360 if (rc)
361 return rc+20;
362 }
363
364
365 if (s && '-' == s[2+boundary_len] && '-' == s[2+boundary_len+1]) {
366 free(line);
367 break;
368 }
369 }
370 next:
371 free(line);
372 }
373
374
375
376 return EXIT_SUCCESS;
377}
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397int reformime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
398int reformime_main(int argc UNUSED_PARAM, char **argv)
399{
400 const char *opt_prefix = "";
401
402 INIT_G();
403
404
405
406 opt_complementary = "x--X:X--x" IF_FEATURE_REFORMIME_COMPAT(":m::");
407 opts = getopt32(argv,
408 "x:X" IF_FEATURE_REFORMIME_COMPAT("deis:r:c:m:h:o:O:"),
409 &opt_prefix
410 IF_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL)
411 );
412
413 argv += optind;
414
415 return parse("", (opts & OPT_X) ? argv : (char **)&opt_prefix);
416}
417