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