From 2b2d97705701f8a0c8a46313bad429582d906d81 Mon Sep 17 00:00:00 2001
From: Denis Vlasenko <vda.linux@googlemail.com>
Date: Sun, 28 Sep 2008 13:50:57 +0000
Subject: sendmail: update by Vladimir

---
 include/applets.h     |   5 +-
 include/usage.h       |   8 +-
 networking/Config.in  |   7 +
 networking/sendmail.c | 639 +++++++++++++++++++-------------------------------
 4 files changed, 251 insertions(+), 408 deletions(-)

diff --git a/include/applets.h b/include/applets.h
index 90b941766..35649d3df 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -149,7 +149,7 @@ USE_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_NEVER))
 USE_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_NEVER, fdflush))
 USE_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 USE_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_FETCHMAIL(APPLET_ODDNAME(fetchmail, sendgetmail, _BB_DIR_USR_BIN, _BB_SUID_NEVER, fetchmail))
+//USE_FETCHMAIL(APPLET(fetchmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
 USE_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, fgrep))
 USE_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_NEVER, find))
 USE_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE))
@@ -235,6 +235,7 @@ USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER))
 USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
 USE_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
 USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat))
+USE_FEATURE_SENDMAIL_MAILX(APPLET_ODDNAME(mail, sendmail, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sendmail))
 USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER))
 USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER))
 USE_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
@@ -313,7 +314,7 @@ USE_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 USE_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 USE_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER))
 USE_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SENDMAIL(APPLET_ODDNAME(sendmail, sendgetmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER, sendmail))
+USE_SENDMAIL(APPLET(sendmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
 USE_SEQ(APPLET_NOFORK(seq, seq, _BB_DIR_USR_BIN, _BB_SUID_NEVER, seq))
 USE_SESTATUS(APPLET(sestatus, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
 USE_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_NEVER))
diff --git a/include/usage.h b/include/usage.h
index a5234e053..fa7ac3bf7 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3468,7 +3468,7 @@
 #define sendmail_trivial_usage \
        "[-w timeout] [-H [user:pass@]server[:port]] [-S]\n" \
        "[-N type] [-f sender] [-F fullname] " \
-       USE_FEATURE_SENDMAIL_MAILX("[-s subject] [-c charset] [-a attach]... ") "[-t] [rcpt]..."
+       USE_FEATURE_SENDMAIL_MAILX("[-s subject] [-c cc-rcpt]... [-j charset] [-a attach]... [-e err-rcpt] ") "[-t] [rcpt]..."
 #define sendmail_full_usage "\n\n" \
        "Send an email\n" \
      "\nOptions:" \
@@ -3480,9 +3480,11 @@
      "\n	-F fullname	Sender full name. Overrides $NAME" \
 	USE_FEATURE_SENDMAIL_MAILX( \
      "\n	-s subject	Subject" \
-     "\n	-c charset	Assume charset for body and subject (" CONFIG_FEATURE_SENDMAIL_CHARSET ")" \
+     "\n	-c rcpt		Cc: recipient. May be multiple" \
+     "\n	-j charset	Assume charset for body and subject (" CONFIG_FEATURE_SENDMAIL_CHARSET ")" \
      "\n	-a file		File to attach. May be multiple" \
-	)
+     "\n	-e rcpt		Errors-To: recipient" \
+     	)
      "\n	-t		Read recipients and subject from body" \
      "\n" \
      "\nOther options are silently ignored; -oi is implied" \
diff --git a/networking/Config.in b/networking/Config.in
index 1984297a6..9aa14220f 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -694,6 +694,13 @@ config FEATURE_SENDMAIL_MAILX
 	help
 	  Allow to specify subject, attachments and their charset.
 
+config FEATURE_SENDMAIL_MAILXX
+	bool "Allow to specify Cc: addresses and some additional headers"
+	default n
+	depends on FEATURE_SENDMAIL_MAILX
+	help
+	  Allow to specify Cc: addresses and some additional headers: Errors-To:.
+
 config FEATURE_SENDMAIL_SSL
 	bool "Allow to communicate via SSL/TLS"
 	default y
diff --git a/networking/sendmail.c b/networking/sendmail.c
index 6d00026e2..ef6e03be6 100644
--- a/networking/sendmail.c
+++ b/networking/sendmail.c
@@ -1,6 +1,6 @@
 /* vi: set sw=4 ts=4: */
 /*
- * bare bones sendmail/fetchmail
+ * bare bones sendmail
  *
  * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
  *
@@ -14,15 +14,12 @@ struct globals {
 	FILE *fp0; // initial stdin
 	// arguments for SSL connection helper
 	const char *xargs[9];
-	// arguments for postprocess helper
-	const char *fargs[3];
 };
 #define G (*ptr_to_globals)
 #define helper_pid      (G.helper_pid)
 #define timeout         (G.timeout   )
 #define fp0             (G.fp0       )
 #define xargs           (G.xargs     )
-#define fargs           (G.fargs     )
 #define INIT_G() do { \
 	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 	xargs[0] = "openssl"; \
@@ -33,13 +30,9 @@ struct globals {
 	xargs[5] = "-tls1"; \
 	xargs[6] = "-starttls"; \
 	xargs[7] = "smtp"; \
-	fargs[0] = CONFIG_FEATURE_SENDMAIL_CHARSET; \
 } while (0)
 
-#define opt_connect       (xargs[4])
-#define opt_after_connect (xargs[5])
-#define opt_charset       (fargs[0])
-#define opt_subject       (fargs[1])
+#define opt_connect (xargs[4])
 
 static void uuencode(char *fname, const char *text)
 {
@@ -112,8 +105,12 @@ static void signal_handler(int signo)
 
 	// SIGCHLD. reap zombies
 	if (wait_any_nohang(&err) > 0)
-		if (WIFEXITED(err) && WEXITSTATUS(err))
-			bb_error_msg_and_die("child exited (%d)", WEXITSTATUS(err));
+		if (WIFEXITED(err)) {
+//			if (WEXITSTATUS(err))
+				bb_error_msg_and_die("child exited (%d)", WEXITSTATUS(err));
+//			else
+//				kill(0, SIGCONT);
+		}
 #undef err
 }
 
@@ -178,10 +175,8 @@ static int smtp_checkp(const char *fmt, const char *param, int code)
 	while ((answer = xmalloc_fgetline(stdin)) != NULL)
 		if (strlen(answer) <= 3 || '-' != answer[3])
 			break;
-//bb_error_msg("FMT[%s]ANS[%s]", fmt, answer);
 	if (answer) {
 		int n = atoi(answer);
-//bb_error_msg("FMT[%s]COD[%d][%d]", fmt, n, code);
 		alarm(0);
 		free(answer);
 		if (-1 == code || n == code)
@@ -211,50 +206,6 @@ static char *sane(char *str)
 	return str;
 }
 
-#if ENABLE_FETCHMAIL
-static void pop3_checkr(const char *fmt, const char *param, char **ret)
-{
-	const char *msg = command(fmt, param);
-	char *answer = xmalloc_fgetline(stdin);
-	if (answer && '+' == *answer) {
-		alarm(0);
-		if (ret)
-			*ret = answer+4; // skip "+OK "
-		else if (ENABLE_FEATURE_CLEAN_UP)
-			free(answer);
-		return;
-	}
-	kill_helper();
-	bb_error_msg_and_die("%s failed", msg);
-}
-
-static inline void pop3_check(const char *fmt, const char *param)
-{
-	pop3_checkr(fmt, param, NULL);
-}
-
-static void pop3_message(const char *filename)
-{
-	int fd;
-	char *answer;
-	// create and open file filename
-	// read stdin, copy to created file
-	fd = xopen(filename, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL);
-	while ((answer = xmalloc_fgets_str(stdin, "\r\n")) != NULL) {
-		char *s = answer;
-		if ('.' == *answer) {
-			if ('.' == answer[1])
-				s++;
-			else if ('\r' == answer[1] && '\n' == answer[2] && '\0' == answer[3])
-				break;
-		}
-		xwrite(fd, s, strlen(s));
-		free(answer);
-	}
-	close(fd);
-}
-#endif
-
 // NB: parse_url can modify url[] (despite const), but only if '@' is there
 static const char *parse_url(const char *url, const char **user, const char **pass)
 {
@@ -280,64 +231,61 @@ static void rcptto(const char *s)
 	smtp_checkp("RCPT TO:<%s>", s, 250);
 }
 
-int sendgetmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int sendgetmail_main(int argc UNUSED_PARAM, char **argv)
+int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sendmail_main(int argc UNUSED_PARAM, char **argv)
 {
 #if ENABLE_FEATURE_SENDMAIL_MAILX
 	llist_t *opt_attachments = NULL;
+	const char *opt_subject;
+	const char *opt_charset = CONFIG_FEATURE_SENDMAIL_CHARSET;
+#if ENABLE_FEATURE_SENDMAIL_MAILXX
+	llist_t *opt_carboncopies = NULL;
+	char *opt_errors_to;
+#endif
 #endif
 	char *opt_from, *opt_fullname;
 	const char *opt_user;
 	const char *opt_pass;
+	int code;
+	char *boundary;
+	llist_t *l;
+	llist_t *headers = NULL;
+	char *domain = sane(safe_getdomainname());
+	unsigned opts;
 
 	enum {
 		OPT_w = 1 << 0,         // network timeout
-
 		OPT_H = 1 << 1,         // [user:password@]server[:port]
 		OPT_S = 1 << 2,         // connect using openssl s_client helper
-
-		OPTS_t = 1 << 3,        // sendmail: read message for recipients
-		OPTF_t = 1 << 3,        // fetchmail: use "TOP" not "RETR"
-
-		OPTS_N = 1 << 4,        // sendmail: request notification
-		OPTF_z = 1 << 4,        // fetchmail: delete from server
-
-		OPTS_f = 1 << 5,        // sendmail: sender address
-		OPTS_F = 1 << 6,        // sendmail: sender name, overrides $NAME
-
-		OPTS_s = 1 << 7,        // sendmail: subject
-		OPTS_c = 1 << 8,        // sendmail: assumed charset
-		OPTS_a = 1 << 9,        // sendmail: attachment(s)
+		OPT_t = 1 << 3,         // read message for recipients
+		OPT_N = 1 << 4,         // request notification
+		OPT_f = 1 << 5,         // sender address
+		OPT_F = 1 << 6,         // sender name, overrides $NAME
+		OPT_s = 1 << 7,         // subject
+		OPT_j = 1 << 8,         // assumed charset
+		OPT_a = 1 << 9,         // attachment(s)
+		OPT_c = 1 << 10,        // carbon copy
+		OPT_e = 1 << 11,        // errors-to address
 	};
-	const char *options;
-	unsigned opts;
 
 	// init global variables
 	INIT_G();
 
-	// parse options, different option sets for sendmail and fetchmail
-	// N.B. opt_after_connect hereafter is NULL if we are called as fetchmail
-	// and is NOT NULL if we are called as sendmail
-	if (!ENABLE_FETCHMAIL || 's' == applet_name[0]) {
-		// SENDMAIL
-		// save initial stdin since body is piped!
-		xdup2(STDIN_FILENO, 3);
-		fp0 = fdopen(3, "r");
-		opt_complementary = "w+:a::";
-		options = "w:H:St" "N:f:F:" USE_FEATURE_SENDMAIL_MAILX("s:c:a:")
-		"X:V:vq:R:O:o:nmL:Iih:GC:B:b:A:"; // postfix compat only, ignored
-	} else {
-		// FETCHMAIL
-		opt_after_connect = NULL;
-		opt_complementary = "-1:w+";
-		options = "w:H:St" "z";
-	}
-	opts = getopt32(argv, options,
+	// save initial stdin since body is piped!
+	xdup2(STDIN_FILENO, 3);
+	fp0 = fdopen(3, "r");
+
+	// parse options
+	opt_complementary = "w+:a::" USE_FEATURE_SENDMAIL_MAILXX("c::");
+	opts = getopt32(argv,
+		"w:H:St" "N:f:F:" USE_FEATURE_SENDMAIL_MAILX("s:j:a:") USE_FEATURE_SENDMAIL_MAILXX("c:e:")
+		"X:V:vq:R:O:o:nmL:Iih:GC:B:b:A:" // postfix compat only, ignored
+		// r:Q:p:M:Dd are candidates from another man page. TODO?
+		"46E", // ssmtp introduces another quirks. TODO?: -a[upm] (user, pass, method) to be supported
 		&timeout /* -w */, &opt_connect /* -H */,
 		NULL, &opt_from, &opt_fullname,
-#if ENABLE_FEATURE_SENDMAIL_MAILX
-		&opt_subject, &opt_charset, &opt_attachments,
-#endif
+		USE_FEATURE_SENDMAIL_MAILX(&opt_subject, &opt_charset, &opt_attachments,)
+		USE_FEATURE_SENDMAIL_MAILXX(&opt_carboncopies, &opt_errors_to,)
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 	);
 	//argc -= optind;
@@ -354,7 +302,6 @@ int sendgetmail_main(int argc UNUSED_PARAM, char **argv)
 	// NB: parse_url modifies opt_connect[] ONLY if '@' is there.
 	// Thus "127.0.0.1" won't be modified, an is ok that it is RO.
 	opt_connect = parse_url(opt_connect, &opt_user, &opt_pass);
-//	bb_error_msg("H[%s] U[%s] P[%s]", opt_connect, opt_user, opt_pass);
 
 	// username must be defined!
 	if (!opt_user) {
@@ -376,347 +323,233 @@ int sendgetmail_main(int argc UNUSED_PARAM, char **argv)
 		xdup2(STDIN_FILENO, STDOUT_FILENO);
 	}
 
-	// are we sendmail?
-	if (!ENABLE_FETCHMAIL || opt_after_connect)
-/***************************************************
- * SENDMAIL
- ***************************************************/
-	{
-		int code;
-		char *boundary;
-		llist_t *l;
-		llist_t *headers = NULL;
-		char *domain = sane(safe_getdomainname());
-
-		// got no sender address? -> use username as a resort
-		if (!(opts & OPTS_f)) {
-			opt_from = xasprintf("%s@%s", opt_user, domain);
-		}
+	// got no sender address? -> use username as a resort
+	if (!(opts & OPT_f)) {
+		opt_from = xasprintf("%s@%s", opt_user, domain);
+	}
 
-		// introduce to server
+	// introduce to server
 
-		// we didn't use SSL helper? ->
-		if (!(opts & OPT_S)) {
-			// ... wait for initial server OK
-			smtp_check(NULL, 220);
-		}
+	// we didn't use SSL helper? ->
+	if (!(opts & OPT_S)) {
+		// ... wait for initial server OK
+		smtp_check(NULL, 220);
+	}
 
-		// we should start with modern EHLO
-		if (250 != smtp_checkp("EHLO %s", domain, -1)) {
-			smtp_checkp("HELO %s", domain, 250);
+	// we should start with modern EHLO
+	if (250 != smtp_checkp("EHLO %s", domain, -1)) {
+		smtp_checkp("HELO %s", domain, 250);
+	}
+	if (ENABLE_FEATURE_CLEAN_UP)
+		free(domain);
+
+	// set sender
+	// NOTE: if password has not been specified
+	// then no authentication is possible
+	code = (opt_pass ? -1 : 250);
+	// first try softly without authentication
+	while (250 != smtp_checkp("MAIL FROM:<%s>", opt_from, code)) {
+		// MAIL FROM failed -> authentication needed
+		if (334 == smtp_check("AUTH LOGIN", -1)) {
+			uuencode(NULL, opt_user); // opt_user != NULL
+			smtp_check("", 334);
+			uuencode(NULL, opt_pass);
+			smtp_check("", 235);
 		}
-		if (ENABLE_FEATURE_CLEAN_UP)
-			free(domain);
-
-		// set sender
-		// NOTE: if password has not been specified
-		// then no authentication is possible
-		code = (opt_pass ? -1 : 250);
-		// first try softly without authentication
-		while (250 != smtp_checkp("MAIL FROM:<%s>", opt_from, code)) {
-			// MAIL FROM failed -> authentication needed
-			if (334 == smtp_check("AUTH LOGIN", -1)) {
-				uuencode(NULL, opt_user); // opt_user != NULL
-				smtp_check("", 334);
-				uuencode(NULL, opt_pass);
-				smtp_check("", 235);
-			}
-			// authenticated OK? -> retry to set sender
-			// but this time die on failure!
-			code = 250;
+		// authenticated OK? -> retry to set sender
+		// but this time die on failure!
+		code = 250;
+	}
+
+	// recipients specified as arguments
+	while (*argv) {
+		char *s = sane(*argv);
+		// loose test on email address validity
+		if (strchr(s, '@')) {
+			rcptto(s);
+			llist_add_to_end(&headers, xasprintf("To: %s", s));
 		}
+		argv++;
+	}
 
-		// recipients specified as arguments
-		while (*argv) {
-			// loose test on email address validity
-			if (strchr(sane(*argv), '@')) {
-				rcptto(sane(*argv));
-				llist_add_to_end(&headers, xasprintf("To: %s", *argv));
-			}
-			argv++;
+#if ENABLE_FEATURE_SENDMAIL_MAILXX
+	// carbon copies recipients specified as -c options
+	for (l = opt_carboncopies; l; l = l->link) {
+		char *s = sane(l->data);
+		// loose test on email address validity
+		if (strchr(s, '@')) {
+			rcptto(s);
+			// TODO: do we ever need to mangle the message?
+			//llist_add_to_end(&headers, xasprintf("Cc: %s", s));
 		}
+	}
+#endif
 
-		// if -t specified or no recipients specified -> read recipients from message
-		// i.e. scan stdin for To:, Cc:, Bcc: lines ...
-		// ... and then use the rest of stdin as message body
-		// N.B. subject read from body can be further overrided with one specified on command line.
-		// recipients are merged. Bcc: lines are deleted
-		// N.B. other headers are collected and will be dumped verbatim
-		if (opts & OPTS_t || !headers) {
-			// fetch recipients and (optionally) subject
-			char *s;
-			while ((s = xmalloc_fgetline(fp0)) != NULL) {
-				if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Cc: ", s, 4)) {
-					rcptto(sane(s+4));
-					llist_add_to_end(&headers, s);
-				} else if (0 == strncasecmp("Bcc: ", s, 5)) {
-					rcptto(sane(s+5));
-					free(s);
-					// N.B. Bcc vanishes from headers!
-				} else if (0 == strncmp("Subject: ", s, 9)) {
-					// we read subject -> use it verbatim unless it is specified
-					// on command line
-					if (!(opts & OPTS_s))
-						llist_add_to_end(&headers, s);
-					else
-						free(s);
-				} else if (s[0]) {
-					// misc header
+	// if -t specified or no recipients specified -> read recipients from message
+	// i.e. scan stdin for To:, Cc:, Bcc: lines ...
+	// ... and then use the rest of stdin as message body
+	// N.B. subject read from body can be further overrided with one specified on command line.
+	// recipients are merged. Bcc: lines are deleted
+	// N.B. other headers are collected and will be dumped verbatim
+	if (opts & OPT_t || !headers) {
+		// fetch recipients and (optionally) subject
+		char *s;
+		while ((s = xmalloc_fgetline(fp0)) != NULL) {
+			if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Cc: ", s, 4)) {
+				rcptto(sane(s+4));
+				llist_add_to_end(&headers, s);
+			} else if (0 == strncasecmp("Bcc: ", s, 5)) {
+				rcptto(sane(s+5));
+				free(s);
+				// N.B. Bcc vanishes from headers!
+			} else if (0 == strncmp("Subject: ", s, 9)) {
+				// we read subject -> use it verbatim unless it is specified
+				// on command line
+				if (!(opts & OPT_s))
 					llist_add_to_end(&headers, s);
-				} else {
+				else
 					free(s);
-					break; // stop on the first empty line
-				}
+			} else if (s[0]) {
+				// misc header
+				llist_add_to_end(&headers, s);
+			} else {
+				free(s);
+				break; // stop on the first empty line
 			}
 		}
+	}
 
-		// enter "put message" mode
-		smtp_check("DATA", 354);
+	// enter "put message" mode
+	smtp_check("DATA", 354);
 
-		// put headers we could have preread with -t
-		for (l = headers; l; l = l->link) {
-			printf("%s\r\n", l->data);
-			if (ENABLE_FEATURE_CLEAN_UP)
-				free(l->data);
-		}
+	// put headers we could have preread with -t
+	for (l = headers; l; l = l->link) {
+		printf("%s\r\n", l->data);
+		if (ENABLE_FEATURE_CLEAN_UP)
+			free(l->data);
+	}
 
-		// put (possibly encoded) subject
-		if (opts & OPTS_c)
-			sane((char *)opt_charset);
-		if (opts & OPTS_s) {
-			printf("Subject: ");
-			if (opts & OPTS_c) {
-				printf("=?%s?B?", opt_charset);
-				uuencode(NULL, opt_subject);
-				printf("?=");
-			} else {
-				printf("%s", opt_subject);
-			}
-			printf("\r\n");
+	// put (possibly encoded) subject
+	if (opts & OPT_j)
+		sane((char *)opt_charset);
+	if (opts & OPT_s) {
+		printf("Subject: ");
+		if (opts & OPT_j) {
+			printf("=?%s?B?", opt_charset);
+			uuencode(NULL, opt_subject);
+			printf("?=");
+		} else {
+			printf("%s", opt_subject);
 		}
+		printf("\r\n");
+	}
 
-		// put sender name, $NAME is the default
-		if (!(opts & OPTS_F))
-			opt_fullname = getenv("NAME");
-		if (opt_fullname)
-			printf("From: \"%s\" <%s>\r\n", opt_fullname, opt_from);
+	// put sender name, $NAME is the default
+	if (!(opts & OPT_F))
+		opt_fullname = getenv("NAME");
+	if (opt_fullname)
+		printf("From: \"%s\" <%s>\r\n", opt_fullname, opt_from);
 
-		// put notification
-		if (opts & OPTS_N)
-			printf("Disposition-Notification-To: %s\r\n", opt_from);
+	// put notification
+	if (opts & OPT_N)
+		printf("Disposition-Notification-To: %s\r\n", opt_from);
 
-		// make a random string -- it will delimit message parts
-		srand(monotonic_us());
-		boundary = xasprintf("%d-%d-%d", rand(), rand(), rand());
+#if ENABLE_FEATURE_SENDMAIL_MAILXX
+	// put errors recipient
+	if (opts & OPT_e)
+		printf("Errors-To: %s\r\n", opt_errors_to);
+#endif
 
-		// put common headers
-		// TODO: do we really need this?
-//		printf("Message-ID: <%s>\r\n", boundary);
+	// make a random string -- it will delimit message parts
+	srand(monotonic_us());
+	boundary = xasprintf("%d-%d-%d", rand(), rand(), rand());
 
-#if ENABLE_FEATURE_SENDMAIL_MAILX
-		// have attachments? -> compose multipart MIME
-		if (opt_attachments) {
-			const char *fmt;
-			const char *p;
-			char *q;
+	// put common headers
+	// TODO: do we really need this?
+//	printf("Message-ID: <%s>\r\n", boundary);
 
+#if ENABLE_FEATURE_SENDMAIL_MAILX
+	// have attachments? -> compose multipart MIME
+	if (opt_attachments) {
+		const char *fmt;
+		const char *p;
+		char *q;
+
+		printf(
+			"Mime-Version: 1.0\r\n"
+			"%smultipart/mixed; boundary=\"%s\"\r\n"
+			, "Content-Type: "
+			, boundary
+		);
+
+		// body is pseudo attachment read from stdin in first turn
+		llist_add_to(&opt_attachments, (char *)"-");
+
+		// put body + attachment(s)
+		// N.B. all these weird things just to be tiny
+		// by reusing string patterns!
+		fmt =
+			"\r\n--%s\r\n"
+			"%stext/plain; charset=%s\r\n"
+			"%s%s\r\n"
+			"%s"
+		;
+		p = opt_charset;
+		q = (char *)"";
+		l = opt_attachments;
+		while (l) {
 			printf(
-				"Mime-Version: 1.0\r\n"
-				"%smultipart/mixed; boundary=\"%s\"\r\n"
-				, "Content-Type: "
+				fmt
 				, boundary
+				, "Content-Type: "
+				, p
+				, "Content-Disposition: inline"
+				, q
+				, "Content-Transfer-Encoding: base64\r\n"
 			);
-
-			// body is pseudo attachment read from stdin in first turn
-			llist_add_to(&opt_attachments, (char *)"-");
-
-			// put body + attachment(s)
-			// N.B. all these weird things just to be tiny
-			// by reusing string patterns!
+			p = "";
 			fmt =
 				"\r\n--%s\r\n"
-				"%stext/plain; charset=%s\r\n"
-				"%s%s\r\n"
+				"%sapplication/octet-stream%s\r\n"
+				"%s; filename=\"%s\"\r\n"
 				"%s"
 			;
-			p = opt_charset;
-			q = (char *)"";
-			l = opt_attachments;
-			while (l) {
-				printf(
-					fmt
-					, boundary
-					, "Content-Type: "
-					, p
-					, "Content-Disposition: inline"
-					, q
-					, "Content-Transfer-Encoding: base64\r\n"
-				);
-				p = "";
-				fmt =
-					"\r\n--%s\r\n"
-					"%sapplication/octet-stream%s\r\n"
-					"%s; filename=\"%s\"\r\n"
-					"%s"
-				;
-				uuencode(l->data, NULL);
-				l = l->link;
-				if (l)
-					q = bb_get_last_path_component_strip(l->data);
-			}
+			uuencode(l->data, NULL);
+			l = l->link;
+			if (l)
+				q = bb_get_last_path_component_strip(l->data);
+		}
 
-			// put message terminator
-			printf("\r\n--%s--\r\n" "\r\n", boundary);
+		// put message terminator
+		printf("\r\n--%s--\r\n" "\r\n", boundary);
 
-		// no attachments? -> just dump message
-		} else
+	// no attachments? -> just dump message
+	} else
 #endif
-		{
-			char *s;
-			// terminate headers
-			printf("\r\n");
-			// put plain text respecting leading dots
-			while ((s = xmalloc_fgetline(fp0)) != NULL) {
-				// escape leading dots
-				// N.B. this feature is implied even if no -i switch given
-				// N.B. we need to escape the leading dot regardless of
-				// whether it is single or not character on the line
-				if (/*(opts & OPTS_i) && */ '.' == s[0] /*&& '\0' == s[1] */)
-					printf(".");
-				// dump read line
-				printf("%s\r\n", s);
-			}
+	{
+		char *s;
+		// terminate headers
+		printf("\r\n");
+		// put plain text respecting leading dots
+		while ((s = xmalloc_fgetline(fp0)) != NULL) {
+			// escape leading dots
+			// N.B. this feature is implied even if no -i (-oi) switch given
+			// N.B. we need to escape the leading dot regardless of
+			// whether it is single or not character on the line
+			if ('.' == s[0] /*&& '\0' == s[1] */)
+				printf(".");
+			// dump read line
+			printf("%s\r\n", s);
 		}
-
-		// leave "put message" mode
-		smtp_check(".", 250);
-		// ... and say goodbye
-		smtp_check("QUIT", 221);
-		// cleanup
-		if (ENABLE_FEATURE_CLEAN_UP)
-			fclose(fp0);
 	}
-#if ENABLE_FETCHMAIL
-/***************************************************
- * FETCHMAIL
- ***************************************************/
-	else {
-		char *buf;
-		unsigned nmsg;
-		char *hostname;
-		pid_t pid;
-
-		// cache fetch command:
-		// TOP will return only the headers
-		// RETR will dump the whole message
-		const char *retr = (opts & OPTF_t) ? "TOP %u 0" : "RETR %u";
-
-		// goto maildir
-		xchdir(*argv++);
-
-		// cache postprocess program
-		*fargs = *argv;
-
-		// authenticate
-
-		// password is mandatory
-		if (!opt_pass) {
-			bb_error_msg_and_die("no password");
-		}
 
-		// get server greeting
-		pop3_checkr(NULL, NULL, &buf);
-
-		// server supports APOP?
-		if ('<' == *buf) {
-			md5_ctx_t md5;
-			// yes! compose <stamp><password>
-			char *s = strchr(buf, '>');
-			if (s)
-				strcpy(s+1, opt_pass);
-			s = buf;
-			// get md5 sum of <stamp><password>
-			md5_begin(&md5);
-			md5_hash(s, strlen(s), &md5);
-			md5_end(s, &md5);
-			// NOTE: md5 struct contains enough space
-			// so we reuse md5 space instead of xzalloc(16*2+1)
-#define md5_hex ((uint8_t *)&md5)
-//			uint8_t *md5_hex = (uint8_t *)&md5;
-			*bin2hex((char *)md5_hex, s, 16) = '\0';
-			// APOP
-			s = xasprintf("%s %s", opt_user, md5_hex);
-#undef md5_hex
-			pop3_check("APOP %s", s);
-			if (ENABLE_FEATURE_CLEAN_UP) {
-				free(s);
-				free(buf-4); // buf is "+OK " away from malloc'ed string
-			}
-		// server ignores APOP -> use simple text authentication
-		} else {
-			// USER
-			pop3_check("USER %s", opt_user);
-			// PASS
-			pop3_check("PASS %s", opt_pass);
-		}
-
-		// get mailbox statistics
-		pop3_checkr("STAT", NULL, &buf);
-
-		// prepare message filename suffix
-		hostname = safe_gethostname();
-		pid = getpid();
-
-		// get messages counter
-		// NOTE: we don't use xatou(buf) since buf is "nmsg nbytes"
-		// we only need nmsg and atoi is just exactly what we need
-		// if atoi fails to convert buf into number it returns 0
-		// in this case the following loop simply will not be executed
-		nmsg = atoi(buf);
-		if (ENABLE_FEATURE_CLEAN_UP)
-			free(buf-4); // buf is "+OK " away from malloc'ed string
-
-		// loop through messages
-		for (; nmsg; nmsg--) {
-
-			// generate unique filename
-			char *filename = xasprintf("tmp/%llu.%u.%s",
-					monotonic_us(), (unsigned)pid, hostname);
-			char *target;
-			int rc;
-
-			// retrieve message in ./tmp/
-			pop3_check(retr, (const char *)(ptrdiff_t)nmsg);
-			pop3_message(filename);
-			// delete message from server
-			if (opts & OPTF_z)
-				pop3_check("DELE %u", (const char*)(ptrdiff_t)nmsg);
-
-			// run postprocessing program
-			if (*fargs) {
-				fargs[1] = filename;
-				rc = wait4pid(spawn((char **)fargs));
-				if (99 == rc)
-					break;
-				if (1 == rc)
-					goto skip;
-			}
-
-			// atomically move message to ./new/
-			target = xstrdup(filename);
-			strncpy(target, "new", 3);
-			// ... or just stop receiving on error
-			if (rename_or_warn(filename, target))
-				break;
-			free(target);
- skip:
-			free(filename);
-		}
-
-		// Bye
-		pop3_check("QUIT", NULL);
-	}
-#endif // ENABLE_FETCHMAIL
+	// leave "put message" mode
+	smtp_check(".", 250);
+	// ... and say goodbye
+	smtp_check("QUIT", 221);
+	// cleanup
+	if (ENABLE_FEATURE_CLEAN_UP)
+		fclose(fp0);
 
 	return EXIT_SUCCESS;
 }
-- 
cgit v1.2.3