diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-06 23:41:38 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-06 23:41:38 +0000 |
commit | b9d572a2733fa20957a9a3287bd04d66176e3b6a (patch) | |
tree | 2b9ff7454709e84b02e644db4914ad9d4b739e68 | |
parent | f10bc3964f1d92fa83ec97a625fca33ce1592f26 (diff) | |
download | busybox-w32-b9d572a2733fa20957a9a3287bd04d66176e3b6a.tar.gz busybox-w32-b9d572a2733fa20957a9a3287bd04d66176e3b6a.tar.bz2 busybox-w32-b9d572a2733fa20957a9a3287bd04d66176e3b6a.zip |
total overhaul of mail applets. again. Vladimir as usual.
-rw-r--r-- | Config.in | 1 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | include/applets.h | 5 | ||||
-rw-r--r-- | include/usage.h | 74 | ||||
-rw-r--r-- | networking/Config.in | 41 | ||||
-rw-r--r-- | networking/Kbuild | 2 | ||||
-rw-r--r-- | networking/sendmail.c | 563 |
7 files changed, 61 insertions, 626 deletions
@@ -596,6 +596,7 @@ source util-linux/Config.in | |||
596 | source miscutils/Config.in | 596 | source miscutils/Config.in |
597 | source networking/Config.in | 597 | source networking/Config.in |
598 | source printutils/Config.in | 598 | source printutils/Config.in |
599 | source mailutils/Config.in | ||
599 | source procps/Config.in | 600 | source procps/Config.in |
600 | source runit/Config.in | 601 | source runit/Config.in |
601 | source selinux/Config.in | 602 | source selinux/Config.in |
@@ -456,6 +456,7 @@ libs-y := \ | |||
456 | libbb/ \ | 456 | libbb/ \ |
457 | libpwdgrp/ \ | 457 | libpwdgrp/ \ |
458 | loginutils/ \ | 458 | loginutils/ \ |
459 | mailutils/ \ | ||
459 | miscutils/ \ | 460 | miscutils/ \ |
460 | modutils/ \ | 461 | modutils/ \ |
461 | networking/ \ | 462 | networking/ \ |
diff --git a/include/applets.h b/include/applets.h index d52f9f034..0e4cbd5a3 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -151,7 +151,6 @@ USE_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_NEVER)) | |||
151 | USE_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_NEVER, fdflush)) | 151 | USE_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_NEVER, fdflush)) |
152 | USE_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 152 | USE_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
153 | USE_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 153 | USE_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
154 | //USE_FETCHMAIL(APPLET(fetchmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) | ||
155 | USE_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, fgrep)) | 154 | USE_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, fgrep)) |
156 | USE_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_NEVER, find)) | 155 | USE_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_NEVER, find)) |
157 | USE_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE)) | 156 | USE_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE)) |
@@ -237,8 +236,8 @@ USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER)) | |||
237 | USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 236 | USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
238 | USE_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe)) | 237 | USE_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe)) |
239 | USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat)) | 238 | USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat)) |
240 | USE_FEATURE_SENDMAIL_MAILX(APPLET_ODDNAME(mail, sendmail, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sendmail)) | ||
241 | USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 239 | USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
240 | USE_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_NEVER)) | ||
242 | USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 241 | USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
243 | USE_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) | 242 | USE_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) |
244 | USE_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum)) | 243 | USE_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum)) |
@@ -281,6 +280,7 @@ USE_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_NEVER)) | |||
281 | USE_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_NEVER)) | 280 | USE_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_NEVER)) |
282 | USE_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 281 | USE_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
283 | USE_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER, pkill)) | 282 | USE_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER, pkill)) |
283 | USE_POPMAILDIR(APPLET(popmaildir, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) | ||
284 | USE_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff)) | 284 | USE_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff)) |
285 | USE_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER)) | 285 | USE_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER)) |
286 | USE_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER, printf)) | 286 | USE_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER, printf)) |
@@ -295,6 +295,7 @@ USE_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | |||
295 | USE_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) | 295 | USE_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) |
296 | USE_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 296 | USE_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
297 | USE_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, reboot)) | 297 | USE_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, reboot)) |
298 | USE_REFORMIME(APPLET(reformime, _BB_DIR_BIN, _BB_SUID_NEVER)) | ||
298 | USE_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 299 | USE_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
299 | USE_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 300 | USE_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
300 | USE_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 301 | USE_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
diff --git a/include/usage.h b/include/usage.h index 4ee82059e..19af3486a 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -1095,18 +1095,6 @@ | |||
1095 | "\n -H HEADS\n" \ | 1095 | "\n -H HEADS\n" \ |
1096 | "\n -S SECTORS" \ | 1096 | "\n -S SECTORS" \ |
1097 | 1097 | ||
1098 | #define fetchmail_trivial_usage \ | ||
1099 | "[-w timeout] [-H [user:pass@]server[:port]] [-S] [-t] [-z] maildir [prog]" | ||
1100 | #define fetchmail_full_usage "\n\n" \ | ||
1101 | "Fetch content of remote mailbox to local maildir\n" \ | ||
1102 | "\nOptions:" \ | ||
1103 | "\n -w timeout Network timeout" \ | ||
1104 | "\n -H [user:pass@]server[:port] Server" \ | ||
1105 | "\n -S Use openssl connection helper for secure servers" \ | ||
1106 | "\n -t Get only headers" \ | ||
1107 | "\n -z Delete messages on server" \ | ||
1108 | "\n prog Run 'prog <message_file>' on message delivery" \ | ||
1109 | |||
1110 | #define blkid_trivial_usage \ | 1098 | #define blkid_trivial_usage \ |
1111 | "" | 1099 | "" |
1112 | #define blkid_full_usage "\n\n" \ | 1100 | #define blkid_full_usage "\n\n" \ |
@@ -2378,6 +2366,16 @@ | |||
2378 | "/dev/hda[0-15]\n" | 2366 | "/dev/hda[0-15]\n" |
2379 | #endif | 2367 | #endif |
2380 | 2368 | ||
2369 | #define makemime_trivial_usage \ | ||
2370 | "[OPTION]... [FILE]..." | ||
2371 | #define makemime_full_usage "\n\n" \ | ||
2372 | "Create MIME-encoded message\n" \ | ||
2373 | "\nOptions:" \ | ||
2374 | "\n -C Charset" \ | ||
2375 | "\n -e Tranfer encoding. Ignored. base64 is assumed" \ | ||
2376 | "\n" \ | ||
2377 | "\nOther options are silently ignored." \ | ||
2378 | |||
2381 | #define man_trivial_usage \ | 2379 | #define man_trivial_usage \ |
2382 | "[OPTION]... [MANPAGE]..." | 2380 | "[OPTION]... [MANPAGE]..." |
2383 | #define man_full_usage "\n\n" \ | 2381 | #define man_full_usage "\n\n" \ |
@@ -3095,6 +3093,33 @@ | |||
3095 | "\n -v Negate the matching" \ | 3093 | "\n -v Negate the matching" \ |
3096 | "\n -x Match whole name (not substring)" \ | 3094 | "\n -x Match whole name (not substring)" \ |
3097 | 3095 | ||
3096 | #define popmaildir_trivial_usage \ | ||
3097 | "[OPTIONS] Maildir [connection-helper ...]" | ||
3098 | #define popmaildir_full_usage "\n\n" \ | ||
3099 | "Fetch content of remote mailbox to local maildir\n" \ | ||
3100 | "\nOptions:" \ | ||
3101 | "\n -b Binary mode. Ignored" \ | ||
3102 | "\n -d Debug. Ignored" \ | ||
3103 | "\n -m Show used memory. Ignored" \ | ||
3104 | "\n -V Show version. Ignored" \ | ||
3105 | "\n -c Use tcpclient. Ignored" \ | ||
3106 | "\n -a Use APOP protocol. Implied. If server supports APOP -> use it" \ | ||
3107 | "\n -s Skip authorization" \ | ||
3108 | "\n -T Get messages with TOP instead with RETR" \ | ||
3109 | "\n -k Keep retrieved messages on the server" \ | ||
3110 | "\n -t timeout Set network timeout" \ | ||
3111 | USE_FEATURE_POPMAILDIR_DELIVERY( \ | ||
3112 | "\n -F \"program arg1 arg2 ...\" Filter by program. May be multiple" \ | ||
3113 | "\n -M \"program arg1 arg2 ...\" Deliver by program" \ | ||
3114 | ) \ | ||
3115 | "\n -R size Remove old messages on the server >= size (in bytes). Ignored" \ | ||
3116 | "\n -Z N1-N2 Remove messages from N1 to N2 (dangerous). Ignored" \ | ||
3117 | "\n -L size Do not retrieve new messages >= size (in bytes). Ignored" \ | ||
3118 | "\n -H lines Type specified number of lines of a message. Ignored" | ||
3119 | #define popmaildir_example_usage \ | ||
3120 | "$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [<password_file]\n" \ | ||
3121 | "$ popmaildir ~/Maildir -- openssl s_client -quiet -connect pop.gmail.com:995 [<password_file]\n" | ||
3122 | |||
3098 | #define poweroff_trivial_usage \ | 3123 | #define poweroff_trivial_usage \ |
3099 | "[-d delay] [-n] [-f]" | 3124 | "[-d delay] [-n] [-f]" |
3100 | #define poweroff_full_usage "\n\n" \ | 3125 | #define poweroff_full_usage "\n\n" \ |
@@ -3250,6 +3275,17 @@ | |||
3250 | "\n -n No call to sync()" \ | 3275 | "\n -n No call to sync()" \ |
3251 | "\n -f Force reboot (don't go through init)" \ | 3276 | "\n -f Force reboot (don't go through init)" \ |
3252 | 3277 | ||
3278 | #define reformime_trivial_usage \ | ||
3279 | "[OPTION]... [FILE]..." | ||
3280 | #define reformime_full_usage "\n\n" \ | ||
3281 | "Parse MIME-encoded message\n" \ | ||
3282 | "\nOptions:" \ | ||
3283 | "\n -x prefix Extract content of MIME sections to files" \ | ||
3284 | "\n -X prog [args] Filter content of MIME sections through prog." \ | ||
3285 | "\n Must be the last option" \ | ||
3286 | "\n" \ | ||
3287 | "\nOther options are silently ignored." \ | ||
3288 | |||
3253 | #define renice_trivial_usage \ | 3289 | #define renice_trivial_usage \ |
3254 | "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" | 3290 | "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" |
3255 | #define renice_full_usage "\n\n" \ | 3291 | #define renice_full_usage "\n\n" \ |
@@ -3484,9 +3520,7 @@ | |||
3484 | #define selinuxenabled_full_usage "" | 3520 | #define selinuxenabled_full_usage "" |
3485 | 3521 | ||
3486 | #define sendmail_trivial_usage \ | 3522 | #define sendmail_trivial_usage \ |
3487 | "[-w timeout] [-H [user:pass@]server[:port]] [-S]\n" \ | 3523 | "[OPTIONS] [rcpt]..." |
3488 | "[-N type] [-f sender] [-F fullname] " \ | ||
3489 | USE_FEATURE_SENDMAIL_MAILX("[-s subject] [-c cc-rcpt]... [-j charset] [-a attach]... [-e err-rcpt] ") "[-t] [rcpt]..." | ||
3490 | #define sendmail_full_usage "\n\n" \ | 3524 | #define sendmail_full_usage "\n\n" \ |
3491 | "Send an email\n" \ | 3525 | "Send an email\n" \ |
3492 | "\nOptions:" \ | 3526 | "\nOptions:" \ |
@@ -3498,11 +3532,15 @@ | |||
3498 | "\n -F fullname Sender full name. Overrides $NAME" \ | 3532 | "\n -F fullname Sender full name. Overrides $NAME" \ |
3499 | USE_FEATURE_SENDMAIL_MAILX( \ | 3533 | USE_FEATURE_SENDMAIL_MAILX( \ |
3500 | "\n -s subject Subject" \ | 3534 | "\n -s subject Subject" \ |
3501 | "\n -c rcpt Cc: recipient. May be multiple" \ | 3535 | "\n -j charset Assume charset for body and subject (" CONFIG_FEATURE_MIME_CHARSET ")" \ |
3502 | "\n -j charset Assume charset for body and subject (" CONFIG_FEATURE_SENDMAIL_CHARSET ")" \ | ||
3503 | "\n -a file File to attach. May be multiple" \ | 3536 | "\n -a file File to attach. May be multiple" \ |
3537 | "\n -H \"prog args...\" Use external connection helper. E.g. openssl for secure servers" \ | ||
3538 | "\n -S server[:port] Server" \ | ||
3539 | ) \ | ||
3540 | USE_FEATURE_SENDMAIL_MAILXX( \ | ||
3541 | "\n -c rcpt Cc: recipient. May be multiple" \ | ||
3504 | "\n -e rcpt Errors-To: recipient" \ | 3542 | "\n -e rcpt Errors-To: recipient" \ |
3505 | ) | 3543 | ) |
3506 | "\n -t Read recipients and subject from body" \ | 3544 | "\n -t Read recipients and subject from body" \ |
3507 | "\n" \ | 3545 | "\n" \ |
3508 | "\nOther options are silently ignored; -oi is implied" \ | 3546 | "\nOther options are silently ignored; -oi is implied" \ |
diff --git a/networking/Config.in b/networking/Config.in index 3ae77e119..95f894230 100644 --- a/networking/Config.in +++ b/networking/Config.in | |||
@@ -681,47 +681,6 @@ config ROUTE | |||
681 | help | 681 | help |
682 | Route displays or manipulates the kernel's IP routing tables. | 682 | Route displays or manipulates the kernel's IP routing tables. |
683 | 683 | ||
684 | config SENDMAIL | ||
685 | bool "sendmail" | ||
686 | default n | ||
687 | help | ||
688 | Barebones sendmail. | ||
689 | |||
690 | config FEATURE_SENDMAIL_MAILX | ||
691 | bool "Allow to specify subject, attachments and their charset" | ||
692 | default y | ||
693 | depends on SENDMAIL | ||
694 | help | ||
695 | Allow to specify subject, attachments and their charset. | ||
696 | |||
697 | config FEATURE_SENDMAIL_MAILXX | ||
698 | bool "Allow to specify Cc: addresses and some additional headers" | ||
699 | default n | ||
700 | depends on FEATURE_SENDMAIL_MAILX | ||
701 | help | ||
702 | Allow to specify Cc: addresses and some additional headers: | ||
703 | Errors-To: | ||
704 | |||
705 | config FEATURE_SENDMAIL_SSL | ||
706 | bool "Allow to communicate via SSL/TLS" | ||
707 | default y | ||
708 | depends on SENDMAIL | ||
709 | help | ||
710 | Allow to use secure connections provided by openssl. E.g. @gmail.com. | ||
711 | |||
712 | config FEATURE_SENDMAIL_CHARSET | ||
713 | string "Default charset" | ||
714 | default "utf-8" | ||
715 | depends on SENDMAIL | ||
716 | help | ||
717 | Default charset of the message. | ||
718 | |||
719 | config FETCHMAIL | ||
720 | bool "fetchmail" | ||
721 | default n | ||
722 | help | ||
723 | Barebones fetchmail. | ||
724 | |||
725 | config SLATTACH | 684 | config SLATTACH |
726 | bool "slattach" | 685 | bool "slattach" |
727 | default n | 686 | default n |
diff --git a/networking/Kbuild b/networking/Kbuild index 75cc20f58..63d0745f8 100644 --- a/networking/Kbuild +++ b/networking/Kbuild | |||
@@ -11,7 +11,6 @@ lib-$(CONFIG_BRCTL) += brctl.o | |||
11 | lib-$(CONFIG_DNSD) += dnsd.o | 11 | lib-$(CONFIG_DNSD) += dnsd.o |
12 | lib-$(CONFIG_ETHER_WAKE) += ether-wake.o | 12 | lib-$(CONFIG_ETHER_WAKE) += ether-wake.o |
13 | lib-$(CONFIG_FAKEIDENTD) += isrv_identd.o isrv.o | 13 | lib-$(CONFIG_FAKEIDENTD) += isrv_identd.o isrv.o |
14 | lib-$(CONFIG_FETCHMAIL) += sendmail.o | ||
15 | lib-$(CONFIG_FTPGET) += ftpgetput.o | 14 | lib-$(CONFIG_FTPGET) += ftpgetput.o |
16 | lib-$(CONFIG_FTPPUT) += ftpgetput.o | 15 | lib-$(CONFIG_FTPPUT) += ftpgetput.o |
17 | lib-$(CONFIG_HOSTNAME) += hostname.o | 16 | lib-$(CONFIG_HOSTNAME) += hostname.o |
@@ -30,7 +29,6 @@ lib-$(CONFIG_PING) += ping.o | |||
30 | lib-$(CONFIG_PING6) += ping.o | 29 | lib-$(CONFIG_PING6) += ping.o |
31 | lib-$(CONFIG_PSCAN) += pscan.o | 30 | lib-$(CONFIG_PSCAN) += pscan.o |
32 | lib-$(CONFIG_ROUTE) += route.o | 31 | lib-$(CONFIG_ROUTE) += route.o |
33 | lib-$(CONFIG_SENDMAIL) += sendmail.o | ||
34 | lib-$(CONFIG_SLATTACH) += slattach.o | 32 | lib-$(CONFIG_SLATTACH) += slattach.o |
35 | lib-$(CONFIG_TC) += tc.o | 33 | lib-$(CONFIG_TC) += tc.o |
36 | lib-$(CONFIG_TELNET) += telnet.o | 34 | lib-$(CONFIG_TELNET) += telnet.o |
diff --git a/networking/sendmail.c b/networking/sendmail.c deleted file mode 100644 index 9602b89ec..000000000 --- a/networking/sendmail.c +++ /dev/null | |||
@@ -1,563 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * bare bones sendmail | ||
4 | * | ||
5 | * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com> | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | #include "libbb.h" | ||
10 | |||
11 | struct globals { | ||
12 | pid_t helper_pid; | ||
13 | unsigned timeout; | ||
14 | FILE *fp0; // initial stdin | ||
15 | // arguments for SSL connection helper | ||
16 | const char *xargs[9]; | ||
17 | }; | ||
18 | #define G (*ptr_to_globals) | ||
19 | #define helper_pid (G.helper_pid) | ||
20 | #define timeout (G.timeout ) | ||
21 | #define fp0 (G.fp0 ) | ||
22 | #define xargs (G.xargs ) | ||
23 | #define INIT_G() do { \ | ||
24 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | ||
25 | xargs[0] = "openssl"; \ | ||
26 | xargs[1] = "s_client"; \ | ||
27 | xargs[2] = "-quiet"; \ | ||
28 | xargs[3] = "-connect"; \ | ||
29 | /*xargs[4] = "localhost";*/ \ | ||
30 | xargs[5] = "-tls1"; \ | ||
31 | xargs[6] = "-starttls"; \ | ||
32 | xargs[7] = "smtp"; \ | ||
33 | } while (0) | ||
34 | |||
35 | #define opt_connect (xargs[4]) | ||
36 | |||
37 | static void uuencode(char *fname, const char *text) | ||
38 | { | ||
39 | enum { | ||
40 | SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */ | ||
41 | DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), | ||
42 | }; | ||
43 | |||
44 | #define src_buf text | ||
45 | FILE *fp = fp; | ||
46 | ssize_t len = len; | ||
47 | char dst_buf[DST_BUF_SIZE + 1]; | ||
48 | |||
49 | if (fname) { | ||
50 | fp = (NOT_LONE_DASH(fname)) ? xfopen_for_read(fname) : fp0; | ||
51 | src_buf = bb_common_bufsiz1; | ||
52 | // N.B. strlen(NULL) segfaults! | ||
53 | } else if (text) { | ||
54 | // though we do not call uuencode(NULL, NULL) explicitly | ||
55 | // still we do not want to break things suddenly | ||
56 | len = strlen(text); | ||
57 | } else | ||
58 | return; | ||
59 | |||
60 | while (1) { | ||
61 | size_t size; | ||
62 | if (fname) { | ||
63 | size = fread((char *)src_buf, 1, SRC_BUF_SIZE, fp); | ||
64 | if ((ssize_t)size < 0) | ||
65 | bb_perror_msg_and_die(bb_msg_read_error); | ||
66 | } else { | ||
67 | size = len; | ||
68 | if (len > SRC_BUF_SIZE) | ||
69 | size = SRC_BUF_SIZE; | ||
70 | } | ||
71 | if (!size) | ||
72 | break; | ||
73 | // encode the buffer we just read in | ||
74 | bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64); | ||
75 | if (fname) { | ||
76 | printf("\r\n"); | ||
77 | } else { | ||
78 | src_buf += size; | ||
79 | len -= size; | ||
80 | } | ||
81 | fwrite(dst_buf, 1, 4 * ((size + 2) / 3), stdout); | ||
82 | } | ||
83 | if (fname) | ||
84 | fclose(fp); | ||
85 | #undef src_buf | ||
86 | } | ||
87 | |||
88 | |||
89 | #if ENABLE_FEATURE_SENDMAIL_SSL | ||
90 | static void kill_helper(void) | ||
91 | { | ||
92 | // TODO!!!: is there more elegant way to terminate child on program failure? | ||
93 | if (helper_pid > 0) | ||
94 | kill(helper_pid, SIGTERM); | ||
95 | } | ||
96 | |||
97 | // generic signal handler | ||
98 | static void signal_handler(int signo) | ||
99 | { | ||
100 | #define err signo | ||
101 | if (SIGALRM == signo) { | ||
102 | kill_helper(); | ||
103 | bb_error_msg_and_die("timed out"); | ||
104 | } | ||
105 | |||
106 | // SIGCHLD. reap zombies | ||
107 | if (wait_any_nohang(&err) > 0) | ||
108 | if (WIFEXITED(err)) { | ||
109 | // if (WEXITSTATUS(err)) | ||
110 | bb_error_msg_and_die("child exited (%d)", WEXITSTATUS(err)); | ||
111 | // else | ||
112 | // kill(0, SIGCONT); | ||
113 | } | ||
114 | #undef err | ||
115 | } | ||
116 | |||
117 | static void launch_helper(const char **argv) | ||
118 | { | ||
119 | // setup vanilla unidirectional pipes interchange | ||
120 | int idx; | ||
121 | int pipes[4]; | ||
122 | |||
123 | xpipe(pipes); | ||
124 | xpipe(pipes+2); | ||
125 | helper_pid = vfork(); | ||
126 | if (helper_pid < 0) | ||
127 | bb_perror_msg_and_die("vfork"); | ||
128 | idx = (!helper_pid) * 2; | ||
129 | xdup2(pipes[idx], STDIN_FILENO); | ||
130 | xdup2(pipes[3-idx], STDOUT_FILENO); | ||
131 | if (ENABLE_FEATURE_CLEAN_UP) | ||
132 | for (int i = 4; --i >= 0; ) | ||
133 | if (pipes[i] > STDOUT_FILENO) | ||
134 | close(pipes[i]); | ||
135 | if (!helper_pid) { | ||
136 | // child: try to execute connection helper | ||
137 | BB_EXECVP(*argv, (char **)argv); | ||
138 | _exit(127); | ||
139 | } | ||
140 | // parent: check whether child is alive | ||
141 | bb_signals(0 | ||
142 | + (1 << SIGCHLD) | ||
143 | + (1 << SIGALRM) | ||
144 | , signal_handler); | ||
145 | signal_handler(SIGCHLD); | ||
146 | // child seems OK -> parent goes on | ||
147 | } | ||
148 | #else | ||
149 | #define kill_helper() ((void)0) | ||
150 | #define launch_helper(x) bb_error_msg_and_die("no SSL support") | ||
151 | #endif | ||
152 | |||
153 | static const char *command(const char *fmt, const char *param) | ||
154 | { | ||
155 | const char *msg = fmt; | ||
156 | alarm(timeout); | ||
157 | if (msg) { | ||
158 | msg = xasprintf(fmt, param); | ||
159 | printf("%s\r\n", msg); | ||
160 | } | ||
161 | fflush(stdout); | ||
162 | return msg; | ||
163 | } | ||
164 | |||
165 | static int smtp_checkp(const char *fmt, const char *param, int code) | ||
166 | { | ||
167 | char *answer; | ||
168 | const char *msg = command(fmt, param); | ||
169 | // read stdin | ||
170 | // if the string has a form \d\d\d- -- read next string. E.g. EHLO response | ||
171 | // parse first bytes to a number | ||
172 | // if code = -1 then just return this number | ||
173 | // if code != -1 then checks whether the number equals the code | ||
174 | // if not equal -> die saying msg | ||
175 | while ((answer = xmalloc_fgetline(stdin)) != NULL) | ||
176 | if (strlen(answer) <= 3 || '-' != answer[3]) | ||
177 | break; | ||
178 | if (answer) { | ||
179 | int n = atoi(answer); | ||
180 | alarm(0); | ||
181 | free(answer); | ||
182 | if (-1 == code || n == code) | ||
183 | return n; | ||
184 | } | ||
185 | kill_helper(); | ||
186 | bb_error_msg_and_die("%s failed", msg); | ||
187 | } | ||
188 | |||
189 | static inline int smtp_check(const char *fmt, int code) | ||
190 | { | ||
191 | return smtp_checkp(fmt, NULL, code); | ||
192 | } | ||
193 | |||
194 | // strip argument of bad chars | ||
195 | static char *sane(char *str) | ||
196 | { | ||
197 | char *s = str; | ||
198 | char *p = s; | ||
199 | while (*s) { | ||
200 | if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { | ||
201 | *p++ = *s; | ||
202 | } | ||
203 | s++; | ||
204 | } | ||
205 | *p = '\0'; | ||
206 | return str; | ||
207 | } | ||
208 | |||
209 | // NB: parse_url can modify url[] (despite const), but only if '@' is there | ||
210 | static const char *parse_url(const char *url, const char **user, const char **pass) | ||
211 | { | ||
212 | // parse [user[:pass]@]host | ||
213 | // return host | ||
214 | char *s = strchr(url, '@'); | ||
215 | *user = *pass = NULL; | ||
216 | if (s) { | ||
217 | *s++ = '\0'; | ||
218 | *user = url; | ||
219 | url = s; | ||
220 | s = strchr(*user, ':'); | ||
221 | if (s) { | ||
222 | *s++ = '\0'; | ||
223 | *pass = s; | ||
224 | } | ||
225 | } | ||
226 | return url; | ||
227 | } | ||
228 | |||
229 | static void rcptto(const char *s) | ||
230 | { | ||
231 | smtp_checkp("RCPT TO:<%s>", s, 250); | ||
232 | } | ||
233 | |||
234 | int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
235 | int sendmail_main(int argc UNUSED_PARAM, char **argv) | ||
236 | { | ||
237 | #if ENABLE_FEATURE_SENDMAIL_MAILX | ||
238 | llist_t *opt_attachments = NULL; | ||
239 | const char *opt_subject; | ||
240 | const char *opt_charset = CONFIG_FEATURE_SENDMAIL_CHARSET; | ||
241 | #if ENABLE_FEATURE_SENDMAIL_MAILXX | ||
242 | llist_t *opt_carboncopies = NULL; | ||
243 | char *opt_errors_to; | ||
244 | #endif | ||
245 | #endif | ||
246 | char *opt_from, *opt_fullname; | ||
247 | const char *opt_user; | ||
248 | const char *opt_pass; | ||
249 | int code; | ||
250 | char *boundary; | ||
251 | llist_t *l; | ||
252 | llist_t *headers = NULL; | ||
253 | char *domain = sane(safe_getdomainname()); | ||
254 | unsigned opts; | ||
255 | |||
256 | enum { | ||
257 | OPT_w = 1 << 0, // network timeout | ||
258 | OPT_H = 1 << 1, // [user:password@]server[:port] | ||
259 | OPT_S = 1 << 2, // connect using openssl s_client helper | ||
260 | OPT_t = 1 << 3, // read message for recipients | ||
261 | OPT_N = 1 << 4, // request notification | ||
262 | OPT_f = 1 << 5, // sender address | ||
263 | OPT_F = 1 << 6, // sender name, overrides $NAME | ||
264 | #if ENABLE_FEATURE_SENDMAIL_MAILX | ||
265 | OPT_s = 1 << 7, // subject | ||
266 | OPT_j = 1 << 8, // assumed charset | ||
267 | OPT_a = 1 << 9, // attachment(s) | ||
268 | #if ENABLE_FEATURE_SENDMAIL_MAILXX | ||
269 | OPT_c = 1 << 10, // carbon copy | ||
270 | OPT_e = 1 << 11, // errors-to address | ||
271 | #endif | ||
272 | #endif | ||
273 | }; | ||
274 | |||
275 | // init global variables | ||
276 | INIT_G(); | ||
277 | |||
278 | // save initial stdin since body is piped! | ||
279 | xdup2(STDIN_FILENO, 3); | ||
280 | fp0 = fdopen(3, "r"); | ||
281 | |||
282 | // parse options | ||
283 | opt_complementary = "w+:a::" USE_FEATURE_SENDMAIL_MAILXX("c::"); | ||
284 | opts = getopt32(argv, | ||
285 | "w:H:St" "N:f:F:" USE_FEATURE_SENDMAIL_MAILX("s:j:a:") USE_FEATURE_SENDMAIL_MAILXX("c:e:") | ||
286 | "X:V:vq:R:O:o:nmL:Iih:GC:B:b:A:" // postfix compat only, ignored | ||
287 | // r:Q:p:M:Dd are candidates from another man page. TODO? | ||
288 | "46E", // ssmtp introduces another quirks. TODO?: -a[upm] (user, pass, method) to be supported | ||
289 | &timeout /* -w */, &opt_connect /* -H */, | ||
290 | NULL, &opt_from, &opt_fullname, | ||
291 | USE_FEATURE_SENDMAIL_MAILX(&opt_subject, &opt_charset, &opt_attachments,) | ||
292 | USE_FEATURE_SENDMAIL_MAILXX(&opt_carboncopies, &opt_errors_to,) | ||
293 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL | ||
294 | ); | ||
295 | //argc -= optind; | ||
296 | argv += optind; | ||
297 | |||
298 | // connect to server | ||
299 | // host[:port] not specified ? -> use $SMTPHOST. no $SMTPHOST ? -> use localhost | ||
300 | if (!(opts & OPT_H)) { | ||
301 | opt_connect = getenv("SMTPHOST"); | ||
302 | if (!opt_connect) | ||
303 | opt_connect = "127.0.0.1"; | ||
304 | } | ||
305 | // fetch username and password, if any | ||
306 | // NB: parse_url modifies opt_connect[] ONLY if '@' is there. | ||
307 | // Thus "127.0.0.1" won't be modified, an is ok that it is RO. | ||
308 | opt_connect = parse_url(opt_connect, &opt_user, &opt_pass); | ||
309 | |||
310 | // username must be defined! | ||
311 | if (!opt_user) { | ||
312 | // N.B. IMHO getenv("USER") can be way easily spoofed! | ||
313 | opt_user = bb_getpwuid(NULL, -1, getuid()); | ||
314 | } | ||
315 | |||
316 | // SSL ordered? -> | ||
317 | if (opts & OPT_S) { | ||
318 | // ... use openssl helper | ||
319 | launch_helper(xargs); | ||
320 | // no SSL ordered? -> | ||
321 | } else { | ||
322 | // ... make plain connect | ||
323 | int fd = create_and_connect_stream_or_die(opt_connect, 25); | ||
324 | // make ourselves a simple IO filter | ||
325 | // from now we know nothing about network :) | ||
326 | xmove_fd(fd, STDIN_FILENO); | ||
327 | xdup2(STDIN_FILENO, STDOUT_FILENO); | ||
328 | } | ||
329 | |||
330 | // got no sender address? -> use username as a resort | ||
331 | if (!(opts & OPT_f)) { | ||
332 | opt_from = xasprintf("%s@%s", opt_user, domain); | ||
333 | } | ||
334 | |||
335 | // introduce to server | ||
336 | |||
337 | // we didn't use SSL helper? -> | ||
338 | if (!(opts & OPT_S)) { | ||
339 | // ... wait for initial server OK | ||
340 | smtp_check(NULL, 220); | ||
341 | } | ||
342 | |||
343 | // we should start with modern EHLO | ||
344 | if (250 != smtp_checkp("EHLO %s", domain, -1)) { | ||
345 | smtp_checkp("HELO %s", domain, 250); | ||
346 | } | ||
347 | if (ENABLE_FEATURE_CLEAN_UP) | ||
348 | free(domain); | ||
349 | |||
350 | // set sender | ||
351 | // NOTE: if password has not been specified | ||
352 | // then no authentication is possible | ||
353 | code = (opt_pass ? -1 : 250); | ||
354 | // first try softly without authentication | ||
355 | while (250 != smtp_checkp("MAIL FROM:<%s>", opt_from, code)) { | ||
356 | // MAIL FROM failed -> authentication needed | ||
357 | if (334 == smtp_check("AUTH LOGIN", -1)) { | ||
358 | uuencode(NULL, opt_user); // opt_user != NULL | ||
359 | smtp_check("", 334); | ||
360 | uuencode(NULL, opt_pass); | ||
361 | smtp_check("", 235); | ||
362 | } | ||
363 | // authenticated OK? -> retry to set sender | ||
364 | // but this time die on failure! | ||
365 | code = 250; | ||
366 | } | ||
367 | |||
368 | // recipients specified as arguments | ||
369 | while (*argv) { | ||
370 | char *s = sane(*argv); | ||
371 | // loose test on email address validity | ||
372 | if (strchr(s, '@')) { | ||
373 | rcptto(s); | ||
374 | llist_add_to_end(&headers, xasprintf("To: %s", s)); | ||
375 | } | ||
376 | argv++; | ||
377 | } | ||
378 | |||
379 | #if ENABLE_FEATURE_SENDMAIL_MAILXX | ||
380 | // carbon copies recipients specified as -c options | ||
381 | for (l = opt_carboncopies; l; l = l->link) { | ||
382 | char *s = sane(l->data); | ||
383 | // loose test on email address validity | ||
384 | if (strchr(s, '@')) { | ||
385 | rcptto(s); | ||
386 | // TODO: do we ever need to mangle the message? | ||
387 | //llist_add_to_end(&headers, xasprintf("Cc: %s", s)); | ||
388 | } | ||
389 | } | ||
390 | #endif | ||
391 | |||
392 | // if -t specified or no recipients specified -> read recipients from message | ||
393 | // i.e. scan stdin for To:, Cc:, Bcc: lines ... | ||
394 | // ... and then use the rest of stdin as message body | ||
395 | // N.B. subject read from body can be further overrided with one specified on command line. | ||
396 | // recipients are merged. Bcc: lines are deleted | ||
397 | // N.B. other headers are collected and will be dumped verbatim | ||
398 | if (opts & OPT_t || !headers) { | ||
399 | // fetch recipients and (optionally) subject | ||
400 | char *s; | ||
401 | while ((s = xmalloc_fgetline(fp0)) != NULL) { | ||
402 | if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Cc: ", s, 4)) { | ||
403 | rcptto(sane(s+4)); | ||
404 | llist_add_to_end(&headers, s); | ||
405 | } else if (0 == strncasecmp("Bcc: ", s, 5)) { | ||
406 | rcptto(sane(s+5)); | ||
407 | free(s); | ||
408 | // N.B. Bcc vanishes from headers! | ||
409 | } else if (0 == strncmp("Subject: ", s, 9)) { | ||
410 | // we read subject -> use it verbatim unless it is specified | ||
411 | // on command line | ||
412 | #if ENABLE_FEATURE_SENDMAIL_MAILX | ||
413 | if (opts & OPT_s) | ||
414 | free(s); | ||
415 | else | ||
416 | #endif | ||
417 | llist_add_to_end(&headers, s); | ||
418 | } else if (s[0]) { | ||
419 | // misc header | ||
420 | llist_add_to_end(&headers, s); | ||
421 | } else { | ||
422 | free(s); | ||
423 | break; // stop on the first empty line | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | |||
428 | // enter "put message" mode | ||
429 | smtp_check("DATA", 354); | ||
430 | |||
431 | // put headers we could have preread with -t | ||
432 | for (l = headers; l; l = l->link) { | ||
433 | printf("%s\r\n", l->data); | ||
434 | if (ENABLE_FEATURE_CLEAN_UP) | ||
435 | free(l->data); | ||
436 | } | ||
437 | |||
438 | // put (possibly encoded) subject | ||
439 | #if ENABLE_FEATURE_SENDMAIL_MAILX | ||
440 | if (opts & OPT_j) | ||
441 | sane((char *)opt_charset); | ||
442 | if (opts & OPT_s) { | ||
443 | printf("Subject: "); | ||
444 | if (opts & OPT_j) { | ||
445 | printf("=?%s?B?", opt_charset); | ||
446 | uuencode(NULL, opt_subject); | ||
447 | printf("?="); | ||
448 | } else { | ||
449 | printf("%s", opt_subject); | ||
450 | } | ||
451 | printf("\r\n"); | ||
452 | } | ||
453 | #endif | ||
454 | |||
455 | // put sender name, $NAME is the default | ||
456 | if (!(opts & OPT_F)) | ||
457 | opt_fullname = getenv("NAME"); | ||
458 | if (opt_fullname) | ||
459 | printf("From: \"%s\" <%s>\r\n", opt_fullname, opt_from); | ||
460 | |||
461 | // put notification | ||
462 | if (opts & OPT_N) | ||
463 | printf("Disposition-Notification-To: %s\r\n", opt_from); | ||
464 | |||
465 | #if ENABLE_FEATURE_SENDMAIL_MAILXX | ||
466 | // put errors recipient | ||
467 | if (opts & OPT_e) | ||
468 | printf("Errors-To: %s\r\n", opt_errors_to); | ||
469 | #endif | ||
470 | |||
471 | // make a random string -- it will delimit message parts | ||
472 | srand(monotonic_us()); | ||
473 | boundary = xasprintf("%d-%d-%d", rand(), rand(), rand()); | ||
474 | |||
475 | // put common headers | ||
476 | // TODO: do we really need this? | ||
477 | // printf("Message-ID: <%s>\r\n", boundary); | ||
478 | |||
479 | #if ENABLE_FEATURE_SENDMAIL_MAILX | ||
480 | // have attachments? -> compose multipart MIME | ||
481 | if (opt_attachments) { | ||
482 | const char *fmt; | ||
483 | const char *p; | ||
484 | char *q; | ||
485 | |||
486 | printf( | ||
487 | "Mime-Version: 1.0\r\n" | ||
488 | "%smultipart/mixed; boundary=\"%s\"\r\n" | ||
489 | , "Content-Type: " | ||
490 | , boundary | ||
491 | ); | ||
492 | |||
493 | // body is pseudo attachment read from stdin in first turn | ||
494 | llist_add_to(&opt_attachments, (char *)"-"); | ||
495 | |||
496 | // put body + attachment(s) | ||
497 | // N.B. all these weird things just to be tiny | ||
498 | // by reusing string patterns! | ||
499 | fmt = | ||
500 | "\r\n--%s\r\n" | ||
501 | "%stext/plain; charset=%s\r\n" | ||
502 | "%s%s\r\n" | ||
503 | "%s" | ||
504 | ; | ||
505 | p = opt_charset; | ||
506 | q = (char *)""; | ||
507 | l = opt_attachments; | ||
508 | while (l) { | ||
509 | printf( | ||
510 | fmt | ||
511 | , boundary | ||
512 | , "Content-Type: " | ||
513 | , p | ||
514 | , "Content-Disposition: inline" | ||
515 | , q | ||
516 | , "Content-Transfer-Encoding: base64\r\n" | ||
517 | ); | ||
518 | p = ""; | ||
519 | fmt = | ||
520 | "\r\n--%s\r\n" | ||
521 | "%sapplication/octet-stream%s\r\n" | ||
522 | "%s; filename=\"%s\"\r\n" | ||
523 | "%s" | ||
524 | ; | ||
525 | uuencode(l->data, NULL); | ||
526 | l = l->link; | ||
527 | if (l) | ||
528 | q = bb_get_last_path_component_strip(l->data); | ||
529 | } | ||
530 | |||
531 | // put message terminator | ||
532 | printf("\r\n--%s--\r\n" "\r\n", boundary); | ||
533 | |||
534 | // no attachments? -> just dump message | ||
535 | } else | ||
536 | #endif | ||
537 | { | ||
538 | char *s; | ||
539 | // terminate headers | ||
540 | printf("\r\n"); | ||
541 | // put plain text respecting leading dots | ||
542 | while ((s = xmalloc_fgetline(fp0)) != NULL) { | ||
543 | // escape leading dots | ||
544 | // N.B. this feature is implied even if no -i (-oi) switch given | ||
545 | // N.B. we need to escape the leading dot regardless of | ||
546 | // whether it is single or not character on the line | ||
547 | if ('.' == s[0] /*&& '\0' == s[1] */) | ||
548 | printf("."); | ||
549 | // dump read line | ||
550 | printf("%s\r\n", s); | ||
551 | } | ||
552 | } | ||
553 | |||
554 | // leave "put message" mode | ||
555 | smtp_check(".", 250); | ||
556 | // ... and say goodbye | ||
557 | smtp_check("QUIT", 221); | ||
558 | // cleanup | ||
559 | if (ENABLE_FEATURE_CLEAN_UP) | ||
560 | fclose(fp0); | ||
561 | |||
562 | return EXIT_SUCCESS; | ||
563 | } | ||