aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-02-26 21:13:17 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-02-26 21:13:17 +0000
commit17db1a9ac1064a4847fd6a381260c68ab3449951 (patch)
tree84f8ec43cc7f5b468d617f689a730479e57c6ede
parent7be1030dcce0956d8bf12166c7a6fedbb1209169 (diff)
downloadbusybox-w32-17db1a9ac1064a4847fd6a381260c68ab3449951.tar.gz
busybox-w32-17db1a9ac1064a4847fd6a381260c68ab3449951.tar.bz2
busybox-w32-17db1a9ac1064a4847fd6a381260c68ab3449951.zip
sendmail: update from maintainer
-rw-r--r--include/usage.h16
-rw-r--r--networking/sendmail.c356
2 files changed, 215 insertions, 157 deletions
diff --git a/include/usage.h b/include/usage.h
index 6b54a1266..e9770cea9 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -1026,17 +1026,19 @@ USE_FEATURE_BRCTL_FANCY("\n" \
1026 " -v Give fdisk version" 1026 " -v Give fdisk version"
1027 1027
1028#define fetchmail_trivial_usage \ 1028#define fetchmail_trivial_usage \
1029 "[-C dir] [-w timeout] [-U user] -P password [-X] [-t] [-z] server[:port]" 1029 "[-w timeout] [-U user] -P password [-X] [-t] [-z] server[:port] maildir [prog]"
1030#define fetchmail_full_usage \ 1030#define fetchmail_full_usage \
1031 "Fetch content of remote mailbox to local Maildir." \ 1031 "Fetch content of remote mailbox to local Maildir." \
1032 "\n\nOptions:\n" \ 1032 "\n\nOptions:\n" \
1033 " -C dir Set Maildir location\n" \
1034 " -w timeout Set timeout on network operations\n" \ 1033 " -w timeout Set timeout on network operations\n" \
1035 " -U username Authenticate with specified username\n" \ 1034 " -U username Authenticate with specified username\n" \
1036 " -P password Authenticate with specified password\n" \ 1035 " -P password Authenticate with specified password\n" \
1037 " -X Use openssl connection helper for secured servers\n" \ 1036 " -X Use openssl connection helper for secured servers\n" \
1038 " -t Get only headers\n" \ 1037 " -t Get only headers\n" \
1039 " -z Delete messages on server" 1038 " -z Delete messages on server" \
1039USE_FEATURE_FETCHMAIL_FILTER("\n" \
1040 " prog Run prog <message file> on message delivery" \
1041)
1040 1042
1041#define findfs_trivial_usage \ 1043#define findfs_trivial_usage \
1042 "LABEL=label or UUID=uuid" 1044 "LABEL=label or UUID=uuid"
@@ -3258,18 +3260,16 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when
3258#define selinuxenabled_full_usage 3260#define selinuxenabled_full_usage
3259 3261
3260#define sendmail_trivial_usage \ 3262#define sendmail_trivial_usage \
3261 "[-C dir] [-w timeout] [-U user] [-P password] [-X]\n" \ 3263 "[-w timeout] [-U user] [-P password] [-X]\n" \
3262 "-t to [-t to] -f from [-n] [-s subject] [-c charset] server[:port] [body] [attachment ...]" 3264 "-t to [-t to]... [-n] [-s subject] [-c charset] server[:port] from [body] [attachment ...]"
3263#define sendmail_full_usage \ 3265#define sendmail_full_usage \
3264 "Send an email with optional attachments." \ 3266 "Send an email with optional attachments." \
3265 "\n\nOptions:\n" \ 3267 "\n\nOptions:\n" \
3266 " -C dir Change current directory to dir\n" \
3267 " -w timeout Set timeout on network operations\n" \ 3268 " -w timeout Set timeout on network operations\n" \
3268 " -U username Authenticate with specified username\n" \ 3269 " -U username Authenticate with specified username\n" \
3269 " -P password Authenticate with specified password\n" \ 3270 " -P password Authenticate with specified password\n" \
3271 " -t address Recipient(s). May be multiple\n" \
3270 " -X Use openssl connection helper for secured servers\n" \ 3272 " -X Use openssl connection helper for secured servers\n" \
3271 " -t to Recipient email. May be multiple\n" \
3272 " -f from Sender address\n" \
3273 " -n Request delivery notification to sender\n" \ 3273 " -n Request delivery notification to sender\n" \
3274 " -s subject Subject\n" \ 3274 " -s subject Subject\n" \
3275 " -c charset Assumed charset for body and subject [utf-8]" 3275 " -c charset Assumed charset for body and subject [utf-8]"
diff --git a/networking/sendmail.c b/networking/sendmail.c
index b2fbc5a7a..adc6c7626 100644
--- a/networking/sendmail.c
+++ b/networking/sendmail.c
@@ -27,9 +27,13 @@ static void uuencode(char *fname, const char *text)
27 if (NOT_LONE_DASH(fname)) 27 if (NOT_LONE_DASH(fname))
28 fd = xopen(fname, O_RDONLY); 28 fd = xopen(fname, O_RDONLY);
29 src_buf = bb_common_bufsiz1; 29 src_buf = bb_common_bufsiz1;
30 } else { 30 // N.B. strlen(NULL) segfaults!
31 } else if (text) {
32 // though we do not call uuencode(NULL, NULL) explicitly
33 // still we do not want to break things suddenly
31 len = strlen(text); 34 len = strlen(text);
32 } 35 } else
36 return;
33 37
34 fflush(stdout); // sync stdio and unistd output 38 fflush(stdout); // sync stdio and unistd output
35 while (1) { 39 while (1) {
@@ -59,7 +63,38 @@ static void uuencode(char *fname, const char *text)
59 close(fd); 63 close(fd);
60} 64}
61 65
62static pid_t helper_pid; 66static const char *const init_xargs[9] = {
67 "openssl", "s_client", "-quiet", "-connect",
68 NULL, "-tls1", "-starttls", "smtp"
69};
70
71struct globals {
72 pid_t helper_pid;
73 unsigned timeout;
74 // arguments for SSL connection helper
75 const char *xargs[9];
76#if ENABLE_FEATURE_FETCHMAIL_FILTER
77 // arguments for postprocess helper
78 const char *fargs[3];
79#endif
80};
81#define G (*ptr_to_globals)
82#define helper_pid (G.helper_pid)
83#define timeout (G.timeout )
84#define xargs (G.xargs )
85#define fargs (G.fargs )
86#define INIT_G() do { \
87 PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
88 memcpy(xargs, init_xargs, sizeof(init_xargs)); \
89 fargs[0] = "utf-8"; \
90} while (0)
91
92#define opt_connect (xargs[4])
93#define opt_after_connect (xargs[5])
94#if ENABLE_FEATURE_FETCHMAIL_FILTER
95#define opt_charset (fargs[0])
96#define opt_subject (fargs[1])
97#endif
63 98
64static void kill_helper(void) 99static void kill_helper(void)
65{ 100{
@@ -71,7 +106,7 @@ static void kill_helper(void)
71// generic signal handler 106// generic signal handler
72static void signal_handler(int signo) 107static void signal_handler(int signo)
73{ 108{
74 int err; 109#define err signo
75 110
76 if (SIGALRM == signo) { 111 if (SIGALRM == signo) {
77 kill_helper(); 112 kill_helper();
@@ -107,20 +142,19 @@ static void launch_helper(const char **argv)
107 close(pipes[i]); 142 close(pipes[i]);
108 if (!helper_pid) { 143 if (!helper_pid) {
109 // child - try to execute connection helper 144 // child - try to execute connection helper
110 BB_EXECVP(argv[0], (char **)argv); 145// close(STDERR_FILENO);
146 BB_EXECVP(*argv, (char **)argv);
111 _exit(127); 147 _exit(127);
112 } 148 }
113 // parent - check whether child is alive 149 // parent - check whether child is alive
114 bb_signals_recursive(0 150 bb_signals(0
115 + (1 << SIGCHLD) 151 + (1 << SIGCHLD)
116 + (1 << SIGALRM) 152 + (1 << SIGALRM)
117 , signal_handler); 153 , signal_handler);
118 signal_handler(SIGCHLD); 154 signal_handler(SIGCHLD);
119 // child seems OK -> parent goes on 155 // child seems OK -> parent goes on
120} 156}
121 157
122static unsigned timeout;
123
124static char *command(const char *fmt, const char *param) 158static char *command(const char *fmt, const char *param)
125{ 159{
126 char *msg = (char *)fmt; 160 char *msg = (char *)fmt;
@@ -145,7 +179,9 @@ static int smtp_checkp(const char *fmt, const char *param, int code)
145 // if code != -1 then checks whether the number equals the code 179 // if code != -1 then checks whether the number equals the code
146 // if not equal -> die saying msg 180 // if not equal -> die saying msg
147#if ENABLE_FEATURE_SENDMAIL_EHLO 181#if ENABLE_FEATURE_SENDMAIL_EHLO
148 while ((answer = xmalloc_getline(stdin)) && '-' == answer[3]) ; 182 while ((answer = xmalloc_getline(stdin)) != NULL)
183 if (strlen(answer) <= 3 || '-' != answer[3])
184 break;
149#else 185#else
150 answer = xmalloc_getline(stdin); 186 answer = xmalloc_getline(stdin);
151#endif 187#endif
@@ -169,15 +205,31 @@ static int smtp_check(const char *fmt, int code)
169 return smtp_checkp(fmt, NULL, code); 205 return smtp_checkp(fmt, NULL, code);
170} 206}
171 207
208// strip argument of bad chars
209static char *sane(char *str)
210{
211 char *s = str;
212 char *p = s;
213 while (*s) {
214 if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) {
215 *p++ = *s;
216 }
217 s++;
218 }
219 *p = '\0';
220 return str;
221}
222
223#if ENABLE_FETCHMAIL
172static void pop3_checkr(const char *fmt, const char *param, char **ret) 224static void pop3_checkr(const char *fmt, const char *param, char **ret)
173{ 225{
174 char *msg = command(fmt, param); 226 char *msg = command(fmt, param);
175 char *answer = xmalloc_getline(stdin); 227 char *answer = xmalloc_getline(stdin);
176 if (answer && '+' == answer[0]) { 228 if (answer && '+' == *answer) {
177 alarm(0); 229 alarm(0);
178 if (ret) 230 if (ret)
179 *ret = answer; 231 *ret = answer+4; // skip "+OK "
180 else 232 else if (ENABLE_FEATURE_CLEAN_UP)
181 free(answer); 233 free(answer);
182 return; 234 return;
183 } 235 }
@@ -190,28 +242,16 @@ static void pop3_check(const char *fmt, const char *param)
190 pop3_checkr(fmt, param, NULL); 242 pop3_checkr(fmt, param, NULL);
191} 243}
192 244
193// strip argument of bad chars 245static void pop3_message(const char *filename)
194static char *sane(char *str)
195{
196 char *s = str;
197 char *p = s;
198 while (*s) {
199 if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) {
200 *p++ = *s;
201 }
202 s++;
203 }
204 *p = '\0';
205 return str;
206}
207
208static void pop3_message(int fd)
209{ 246{
247 int fd;
210 char *answer; 248 char *answer;
211 // read stdin, copy to file fd 249 // create and open file filename
250 // read stdin, copy to created file
251 fd = xopen(filename, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL);
212 while ((answer = xmalloc_fgets_str(stdin, "\r\n"))) { 252 while ((answer = xmalloc_fgets_str(stdin, "\r\n"))) {
213 char *s = answer; 253 char *s = answer;
214 if ('.' == answer[0]) { 254 if ('.' == *answer) {
215 if ('.' == answer[1]) 255 if ('.' == answer[1])
216 s++; 256 s++;
217 else if ('\r' == answer[1] && '\n' == answer[2] && '\0' == answer[3]) 257 else if ('\r' == answer[1] && '\n' == answer[2] && '\0' == answer[3])
@@ -222,64 +262,56 @@ static void pop3_message(int fd)
222 } 262 }
223 close(fd); 263 close(fd);
224} 264}
225 265#endif
226static const char *args[] = {
227 "openssl", "s_client", "-quiet", "-connect", NULL, "-tls1", "-starttls", "smtp", NULL
228};
229#define opt_connect args[4]
230#define opt_after_connect args[5]
231 266
232int sendgetmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 267int sendgetmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
233int sendgetmail_main(int argc, char **argv) 268int sendgetmail_main(int argc, char **argv)
234{ 269{
235 llist_t *recipients = NULL; 270 llist_t *opt_recipients = NULL;
236 char *from; 271#if !ENABLE_FEATURE_FETCHMAIL_FILTER
237 const char *subject; 272 char *opt_subject;
238 char *charset = (char *)"utf-8"; 273 char *opt_charset = (char *)"utf-8";
274#endif
239 275
240 const char *opt_user; 276 const char *opt_user;
241 const char *opt_pass; 277 const char *opt_pass;
242 const char *opt_timeout;
243 const char *opt_chdir;
244 278
245 enum { 279 enum {
246 OPT_C = 1 << 0, // chdir 280 OPT_w = 1 << 0, // network timeout
247 OPT_w = 1 << 1, // network timeout 281 OPT_U = 1 << 1, // user
248 OPT_U = 1 << 2, // user 282 OPT_P = 1 << 2, // password
249 OPT_P = 1 << 3, // password 283 OPT_X = 1 << 3, // connect using openssl s_client helper
250 OPT_X = 1 << 4, // use openssl connection helper
251 284
252 OPTS_t = 1 << 5, // sendmail "to" 285 OPTS_n = 1 << 4, // sendmail: request notification
253 OPTF_t = 1 << 5, // fetchmail "TOP" 286 OPTF_t = 1 << 4, // fetchmail: use "TOP" not "RETR"
254 287
255 OPTS_f = 1 << 6, // sendmail "from" 288 OPTS_s = 1 << 5, // sendmail: subject
256 OPTF_z = 1 << 6, // fetchmail "delete" 289 OPTF_z = 1 << 5, // fetchmail: delete from server
257 290
258 OPTS_n = 1 << 7, // notification 291 OPTS_c = 1 << 6, // sendmail: assumed charset
259 OPTS_s = 1 << 8, // subject given 292 OPTS_t = 1 << 7, // sendmail: recipient(s)
260 OPTS_c = 1 << 9, // charset for subject and body
261 }; 293 };
262 294
263 const char *options; 295 const char *options;
264 unsigned opts; 296 unsigned opts;
265 297
266 // SENDMAIL 298 INIT_G();
267 if ('s' == applet_name[0]) { 299
268 // save initial stdin 300 if (!ENABLE_FETCHMAIL || 's' == applet_name[0]) {
301 // SENDMAIL
302 // save initial stdin (body or attachements can be piped!)
269 xdup2(STDIN_FILENO, INITIAL_STDIN_FILENO); 303 xdup2(STDIN_FILENO, INITIAL_STDIN_FILENO);
270 // -f must be specified 304 opt_complementary = "-2:w+:t:t::"; // count(-t) > 0
271 // -t may be multiple 305 options = "w:U:P:X" "ns:c:t:";
272 opt_complementary = "-1:f:t::";
273 options = "C:w:U:P:X" "t:f:ns:c:";
274 // FETCHMAIL
275 } else { 306 } else {
307 // FETCHMAIL
276 opt_after_connect = NULL; 308 opt_after_connect = NULL;
277 opt_complementary = "=1:P"; 309 opt_complementary = "-2:w+:P";
278 options = "C:w:U:P:X" "tz"; 310 options = "w:U:P:X" "tz";
279 } 311 }
280 opts = getopt32(argv, options, 312 opts = getopt32(argv, options,
281 &opt_chdir, &opt_timeout, &opt_user, &opt_pass, 313 &timeout, &opt_user, &opt_pass,
282 &recipients, &from, &subject, &charset 314 &opt_subject, &opt_charset, &opt_recipients
283 ); 315 );
284 316
285 //argc -= optind; 317 //argc -= optind;
@@ -288,16 +320,9 @@ int sendgetmail_main(int argc, char **argv)
288 // first argument is remote server[:port] 320 // first argument is remote server[:port]
289 opt_connect = *argv++; 321 opt_connect = *argv++;
290 322
291 if (opts & OPT_w)
292 timeout = xatou(opt_timeout);
293
294 // chdir
295 if (opts & OPT_C)
296 xchdir(opt_chdir);
297
298 // connect to server 323 // connect to server
299 if (opts & OPT_X) { 324 if (opts & OPT_X) {
300 launch_helper(args); 325 launch_helper(xargs);
301 } else { 326 } else {
302 // no connection helper provided -> make plain connect 327 // no connection helper provided -> make plain connect
303 int fd = create_and_connect_stream_or_die(opt_connect, 0); 328 int fd = create_and_connect_stream_or_die(opt_connect, 0);
@@ -305,24 +330,30 @@ int sendgetmail_main(int argc, char **argv)
305 xdup2(STDIN_FILENO, STDOUT_FILENO); 330 xdup2(STDIN_FILENO, STDOUT_FILENO);
306 } 331 }
307 332
308 // randomize 333#if ENABLE_FETCHMAIL
309 srand(time(NULL)); 334 if (opt_after_connect)
310 335#endif
311 // SENDMAIL 336 {
312 if (recipients) { 337 // SENDMAIL
338 char *opt_from;
313 int code; 339 int code;
314 char *boundary; 340 char *boundary;
341 const char *fmt;
342 const char *p;
343 char *q;
315 344
316 // wait for initial OK on plain connect 345 // wait for initial OK on plain connect
317 if (!(opts & OPT_X)) 346 if (!(opts & OPT_X))
318 smtp_check(NULL, 220); 347 smtp_check(NULL, 220);
319 348
320 sane(from); 349 // get specified sender
350 opt_from = sane(*argv++);
351
321 // introduce to server 352 // introduce to server
322 // should we respect modern (but useless here) EHLO? 353 // should we respect modern (but useless here) EHLO?
323 // or should they respect we wanna be tiny?! 354 // or should they respect we wanna be tiny?!
324 if (!ENABLE_FEATURE_SENDMAIL_EHLO || 250 != smtp_checkp("EHLO %s", from, -1)) { 355 if (!ENABLE_FEATURE_SENDMAIL_EHLO || 250 != smtp_checkp("EHLO %s", opt_from, -1)) {
325 smtp_checkp("HELO %s", from, 250); 356 smtp_checkp("HELO %s", opt_from, 250);
326 } 357 }
327 358
328 // set sender 359 // set sender
@@ -330,13 +361,13 @@ int sendgetmail_main(int argc, char **argv)
330 // no authentication is possible 361 // no authentication is possible
331 code = (opts & OPT_P) ? -1 : 250; 362 code = (opts & OPT_P) ? -1 : 250;
332 // first try softly without authentication 363 // first try softly without authentication
333 while (250 != smtp_checkp("MAIL FROM:<%s>", from, code)) { 364 while (250 != smtp_checkp("MAIL FROM:<%s>", opt_from, code)) {
334 // MAIL FROM failed -> authentication needed 365 // MAIL FROM failed -> authentication needed
335 // do we have username? 366 // do we have username?
336 if (!(opts & OPT_U)) { 367 if (!(opts & OPT_U)) {
337 // no! fetch it from "from" option 368 // no! fetch it from "from" option
338 //opts |= OPT_U; 369 //opts |= OPT_U;
339 opt_user = xstrdup(from); 370 opt_user = xstrdup(opt_from);
340 *strchrnul(opt_user, '@') = '\0'; 371 *strchrnul(opt_user, '@') = '\0';
341 } 372 }
342 // now it seems we have username 373 // now it seems we have username
@@ -351,30 +382,35 @@ int sendgetmail_main(int argc, char **argv)
351 // but now die on failure 382 // but now die on failure
352 code = 250; 383 code = 250;
353 } 384 }
385
354 // set recipients 386 // set recipients
355 for (llist_t *to = recipients; to; to = to->link) { 387 for (llist_t *to = opt_recipients; to; to = to->link) {
356 smtp_checkp("RCPT TO:<%s>", sane(to->data), 250); 388 smtp_checkp("RCPT TO:<%s>", sane(to->data), 250);
357 } 389 }
358 390
359 // now put message 391 // now put message
360 smtp_check("DATA", 354); 392 smtp_check("DATA", 354);
361 // put address headers 393 // put address headers
362 printf("From: %s\r\n", from); 394 printf("From: %s\r\n", opt_from);
363 for (llist_t *to = recipients; to; to = to->link) { 395 for (llist_t *to = opt_recipients; to; to = to->link) {
364 printf("To: %s\r\n", to->data); 396 printf("To: %s\r\n", to->data);
365 } 397 }
366 // put encoded subject 398 // put encoded subject
367 if (opts & OPTS_c) 399 if (opts & OPTS_c)
368 sane(charset); 400 sane((char *)opt_charset);
369 if (opts & OPTS_s) { 401 if (opts & OPTS_s) {
370 printf("Subject: =?%s?B?", charset); 402 printf("Subject: =?%s?B?", opt_charset);
371 uuencode(NULL, subject); 403 uuencode(NULL, opt_subject);
372 printf("?=\r\n"); 404 printf("?=\r\n");
373 } 405 }
374 // put notification 406 // put notification
375 if (opts & OPTS_n) 407 if (opts & OPTS_n)
376 printf("Disposition-Notification-To: %s\r\n", from); 408 printf("Disposition-Notification-To: %s\r\n", opt_from);
377 // put common headers and body start 409 // put common headers and body start
410 // randomize
411#if ENABLE_FEATURE_SENDMAIL_BLOATY
412 srand(time(NULL));
413#endif
378 boundary = xasprintf("%d-%d-%d", rand(), rand(), rand()); 414 boundary = xasprintf("%d-%d-%d", rand(), rand(), rand());
379 printf( 415 printf(
380 USE_FEATURE_SENDMAIL_BLOATY("X-Mailer: busybox " BB_VER " sendmail\r\n") 416 USE_FEATURE_SENDMAIL_BLOATY("X-Mailer: busybox " BB_VER " sendmail\r\n")
@@ -386,16 +422,16 @@ int sendgetmail_main(int argc, char **argv)
386 , boundary 422 , boundary
387 ); 423 );
388 // put body + attachment(s) 424 // put body + attachment(s)
389 { 425
390 const char *fmt = 426 fmt =
391 "\r\n--%s\r\n" 427 "\r\n--%s\r\n"
392 "%stext/plain; charset=%s\r\n" 428 "%stext/plain; charset=%s\r\n"
393 "%s%s\r\n" 429 "%s%s\r\n"
394 "%s" 430 "%s"
395 ; 431 ;
396 const char *p = charset; 432 p = opt_charset;
397 char *q = (char *)""; 433 q = (char *)"";
398 while (argv[0]) { 434 while (*argv) {
399 printf( 435 printf(
400 fmt 436 fmt
401 , boundary 437 , boundary
@@ -414,9 +450,9 @@ int sendgetmail_main(int argc, char **argv)
414 ; 450 ;
415 uuencode(*argv, NULL); 451 uuencode(*argv, NULL);
416 if (*(++argv)) 452 if (*(++argv))
417 q = bb_get_last_path_component_strip(argv[0]); 453 q = bb_get_last_path_component_strip(*argv);
418 } 454 }
419 } 455
420 // put terminator 456 // put terminator
421 printf("\r\n--%s--\r\n" "\r\n", boundary); 457 printf("\r\n--%s--\r\n" "\r\n", boundary);
422 if (ENABLE_FEATURE_CLEAN_UP) 458 if (ENABLE_FEATURE_CLEAN_UP)
@@ -426,11 +462,25 @@ int sendgetmail_main(int argc, char **argv)
426 smtp_check(".", 250); 462 smtp_check(".", 250);
427 smtp_check("QUIT", 221); 463 smtp_check("QUIT", 221);
428 464
429 // FETCHMAIL 465#if ENABLE_FETCHMAIL
430 } else { 466 } else {
431 // authenticate 467 // FETCHMAIL
432 char *buf; 468 char *buf;
433 unsigned nmsg; 469 unsigned nmsg;
470 char *hostname;
471 pid_t pid;
472 // cache fetch command
473 const char *retr = (opts & OPTF_t) ? "TOP %u 0" : "RETR %u";
474
475 // goto maildir
476 xchdir(*argv++);
477
478#if ENABLE_FEATURE_FETCHMAIL_FILTER
479 // cache postprocess program
480 *fargs = *argv;
481#endif
482
483 // authenticate
434 if (!(opts & OPT_U)) { 484 if (!(opts & OPT_U)) {
435 //opts |= OPT_U; 485 //opts |= OPT_U;
436 opt_user = getenv("USER"); 486 opt_user = getenv("USER");
@@ -438,25 +488,29 @@ int sendgetmail_main(int argc, char **argv)
438#if ENABLE_FEATURE_FETCHMAIL_APOP 488#if ENABLE_FEATURE_FETCHMAIL_APOP
439 pop3_checkr(NULL, NULL, &buf); 489 pop3_checkr(NULL, NULL, &buf);
440 // server supports APOP? 490 // server supports APOP?
441 if ('<' == buf[4]) { 491 if ('<' == *buf) {
442 md5_ctx_t md5; 492 md5_ctx_t md5;
443 uint8_t hex[16*2 + 1];
444 // yes. compose <stamp><password> 493 // yes. compose <stamp><password>
445 char *s = strchr(buf, '>'); 494 char *s = strchr(buf, '>');
446 if (s) 495 if (s)
447 strcpy(s+1, opt_pass); 496 strcpy(s+1, opt_pass);
448 s = buf+4; 497 s = buf;
449 // get md5 sum of <stamp><password> 498 // get md5 sum of <stamp><password>
450 md5_begin(&md5); 499 md5_begin(&md5);
451 md5_hash(s, strlen(s), &md5); 500 md5_hash(s, strlen(s), &md5);
452 md5_end(s, &md5); 501 md5_end(s, &md5);
453 bin2hex(hex, s, 16); 502 // NOTE: md5 struct contains enough space
503 // so we reuse md5 space instead of xzalloc(16*2+1)
504#define md5_hex ((uint8_t *)&md5)
505// uint8_t *md5_hex = (uint8_t *)&md5;
506 *bin2hex(md5_hex, s, 16) = '\0';
454 // APOP 507 // APOP
455 s = xasprintf("%s %s", opt_user, hex); 508 s = xasprintf("%s %s", opt_user, md5_hex);
509#undef md5_hex
456 pop3_check("APOP %s", s); 510 pop3_check("APOP %s", s);
457 if (ENABLE_FEATURE_CLEAN_UP) { 511 if (ENABLE_FEATURE_CLEAN_UP) {
458 free(s); 512 free(s);
459 free(buf); 513 free(buf-4); // buf is "+OK " away from malloc'ed string
460 } 514 }
461 } else { 515 } else {
462#else 516#else
@@ -472,60 +526,64 @@ int sendgetmail_main(int argc, char **argv)
472 // get statistics 526 // get statistics
473 pop3_checkr("STAT", NULL, &buf); 527 pop3_checkr("STAT", NULL, &buf);
474 528
529 // prepare message filename suffix
530 hostname = xzalloc(MAXHOSTNAMELEN+1);
531 gethostname(hostname, MAXHOSTNAMELEN);
532 pid = getpid();
533
475 // get number of messages 534 // get number of messages
476 nmsg = atoi(buf+4); 535 // NOTE: we don't use xatou(buf) since buf is "nmsg nbytes"
536 // we only need nmsg and atoi is just exactly what we need
537 // if atoi fails to convert buf into number it returns 0
538 // in this case the following loop simply will not be executed
539 nmsg = atoi(buf);
477 if (ENABLE_FEATURE_CLEAN_UP) 540 if (ENABLE_FEATURE_CLEAN_UP)
478 free(buf); 541 free(buf-4); // buf is "+OK " away from malloc'ed string
479
480 // lock maildir
481 ////USE_FEATURE_CLEAN_UP(close)(xopen(".lock", O_CREAT | O_WRONLY | O_TRUNC | O_EXCL));
482
483 // make tempnam(dir, salt) respect dir argument
484 unsetenv("TMPDIR");
485
486 // TODO: piping through external filter argv... if *argv
487 542
488 // cache fetch command
489 {
490 const char *retr = (opts & OPTF_t) ? "TOP %u 0" : "RETR %u";
491 // loop through messages 543 // loop through messages
492 for (; nmsg; nmsg--) { 544 for (; nmsg; nmsg--) {
493 int fd; 545 char *filename = xasprintf("tmp/%llu.%u.%s", monotonic_us(), pid, hostname);
494 char tmp_name[sizeof("tmp/XXXXXX")]; 546 char *target;
495 char new_name[sizeof("new/XXXXXX")]; 547#if ENABLE_FEATURE_FETCHMAIL_FILTER
496 548 int rc;
549#endif
497 // retrieve message in ./tmp 550 // retrieve message in ./tmp
498 strcpy(tmp_name, "tmp/XXXXXX");
499 fd = mkstemp(tmp_name);
500 if (fd < 0)
501 bb_perror_msg_and_die("cannot create unique file");
502 pop3_check(retr, (const char *)nmsg); 551 pop3_check(retr, (const char *)nmsg);
503 pop3_message(fd); // NB: closes fd 552 pop3_message(filename);
504
505 // move file to ./new atomically
506 strncpy(new_name, "new", 3);
507 strcpy(new_name + 3, tmp_name + 3);
508 if (rename(tmp_name, new_name) < 0) {
509 // rats! such file exists! try to make unique name
510 strcpy(new_name + 3, "tmp/XXXXXX" + 3);
511 fd = mkstemp(new_name);
512 if (fd < 0)
513 bb_perror_msg_and_die("cannot create unique file");
514 close(fd);
515 xrename(tmp_name, new_name);
516 }
517
518 // delete message from server 553 // delete message from server
519 if (opts & OPTF_z) 554 if (opts & OPTF_z)
520 pop3_check("DELE %u", (const char*)nmsg); 555 pop3_check("DELE %u", (const char*)nmsg);
556
557#if ENABLE_FEATURE_FETCHMAIL_FILTER
558 // run postprocessing program
559 if (*fargs) {
560 fargs[1] = filename;
561 rc = wait4pid(spawn((char **)fargs));
562 if (99 == rc)
563 break;
564 if (1 == rc)
565 goto skip;
566 }
567#endif
568 // atomically move message to ./new
569 target = xstrdup(filename);
570 strncpy(target, "new", 3);
571 // ... or just stop receiving on error
572 if (rename_or_warn(filename, target))
573 break;
574 free(target);
575#if ENABLE_FEATURE_FETCHMAIL_FILTER
576 skip:
577#endif
578 free(filename);
521 } 579 }
522 } 580
581 if (ENABLE_FEATURE_CLEAN_UP)
582 free(hostname);
523 583
524 // Bye 584 // Bye
525 pop3_check("QUIT", NULL); 585 pop3_check("QUIT", NULL);
526 586#endif // ENABLE_FETCHMAIL
527 // unlock maildir
528 ////unlink(".lock");
529 } 587 }
530 588
531 return 0; 589 return 0;