From: Christian Kastner <ckk@kvr.at>
Date: Sun, 10 Jan 2016 20:32:28 +0100
Subject: Enable setting content headers in email

Set the ContentType: header based on the system locale or cron's environment,
if available.

Implementation taken from Fedora Core's version of cron.

Bug-Debian: https://bugs.debian.org/338051
Bug-Debian: https://bugs.debian.org/309150
Bug-Debian: https://bugs.debian.org/600310
Forwarded: no
Last-Update: 2016-01-10
Index: cron/cron.c
===================================================================
--- cron.orig/cron.c
+++ cron/cron.c
@@ -30,6 +30,7 @@ static char rcsid[] = "$Id: cron.c,v 2.1
 #include <sys/types.h>
 #include <fcntl.h>
 #include <libgen.h>
+#include <strings.h>
 
 static	void	usage __P((void)),
 		run_reboot_jobs __P((cron_db *)),
@@ -66,6 +67,7 @@ main(argc, argv)
 	char	*argv[];
 {
 	cron_db	database;
+	char	*cs;
 
 	ProgramName = basename(argv[0]);
 
@@ -95,6 +97,20 @@ main(argc, argv)
 	setenv("PATH", _PATH_DEFPATH, 1);
 #endif
 
+	/* Get the default locale character set for the mail
+	* "Content-Type: ...; charset=" header
+	*/
+	setlocale(LC_ALL,""); /* set locale to system defaults or to
+				that specified by any  LC_* env vars */
+	setlocale(LC_COLLATE, "C"); /* Except for collation, since load_database() uses a-z */
+	/* Except that "US-ASCII" is preferred to "ANSI_x3.4-1968" in MIME,
+	* even though "ANSI_x3.4-1968" is the official charset name. */
+	if ((cs = nl_langinfo(CODESET)) != 0L &&
+			strcasecmp(cs, "ANSI_x3.4-1968") != 0)
+		strncpy(cron_default_mail_charset, cs, MAX_ENVSTR);
+	else
+		strcpy( cron_default_mail_charset, "US-ASCII");
+
 	/* if there are no debug flags turned on, fork as a daemon should.
 	 */
 # if DEBUGGING
Index: cron/cron.h
===================================================================
--- cron.orig/cron.h
+++ cron/cron.h
@@ -294,6 +294,8 @@ static long GMToff;
 
 int	lsbsysinit_mode;
 
+char	cron_default_mail_charset[MAX_ENVSTR] = "";
+
 # if DEBUGGING
 int	DebugFlags;
 char	*DebugFlagNames[] = {	/* sync with #defines */
@@ -312,6 +314,7 @@ extern	time_t	StartTime;
 extern  time_min timeRunning;
 extern  time_min virtualTime;
 extern  time_min clockTime;
+extern	char	cron_default_mail_charset[MAX_ENVSTR];
 # if DEBUGGING
 extern	int	DebugFlags;
 extern	char	*DebugFlagNames[];
Index: cron/externs.h
===================================================================
--- cron.orig/externs.h
+++ cron/externs.h
@@ -26,6 +26,11 @@
 # define WAIT_IS_INT 1
 extern char *tzname[2];
 # define TZONE(tm) tzname[(tm).tm_isdst]
+/* include locale stuff for mailer "Content-Type":
+ */
+#include <locale.h>
+#include <nl_types.h>
+#include <langinfo.h>
 #endif
 
 #if defined(UNIXPC)
Index: cron/do_command.c
===================================================================
--- cron.orig/do_command.c
+++ cron/do_command.c
@@ -470,8 +470,12 @@ child_process(e, u)
 
 			if (mailto) {
 				register char	**env;
+				char		**jobenv = build_env(e->envp);
 				auto char	mailcmd[MAX_COMMAND];
 				auto char	hostname[MAXHOSTNAMELEN];
+				char	*content_type = env_get("CONTENT_TYPE",jobenv),
+					*content_transfer_encoding = env_get("CONTENT_TRANSFER_ENCODING",jobenv);
+
 
 				(void) gethostname(hostname, MAXHOSTNAMELEN);
 				(void) snprintf(mailcmd, sizeof(mailcmd),
@@ -490,7 +494,40 @@ child_process(e, u)
 					arpadate(&StartTime));
 # endif /* MAIL_DATE */
 				fprintf(mail, "MIME-Version: 1.0\n");
-				fprintf(mail, "Content-Transfer-Encoding: 8bit\n");
+
+				if (content_type == 0L) {
+					fprintf(mail, "Content-Type: text/plain; charset=%s\n",
+						cron_default_mail_charset);
+				} else {
+					/* user specified Content-Type header.
+					 * disallow new-lines for security reasons
+					 * (else users could specify arbitrary mail headers!)
+					 */
+					char *nl=content_type;
+					size_t ctlen = strlen(content_type);
+
+					while ((*nl != '\0') &&
+							((nl=strchr(nl,'\n')) != 0L) &&
+							(nl < (content_type+ctlen))) {
+						*nl = ' ';
+					}
+				       fprintf(mail,"Content-Type: %s\n", content_type);
+				}
+
+				if (content_transfer_encoding != 0L) {
+					char *nl=content_transfer_encoding;
+					size_t ctlen = strlen(content_transfer_encoding);
+					while ((*nl != '\0') &&
+							((nl=strchr(nl,'\n')) != 0L) &&
+							(nl < (content_transfer_encoding+ctlen))) {
+						*nl = ' ';
+					}
+
+					fprintf(mail,"Content-Transfer-Encoding: %s\n",
+							content_transfer_encoding);
+				} else {
+					fprintf(mail,"Content-Transfer-Encoding: 8bit\n");
+				}
 
 				for (env = e->envp;  *env;  env++)
 					fprintf(mail, "X-Cron-Env: <%s>\n",
Index: cron/crontab.5
===================================================================
--- cron.orig/crontab.5
+++ cron/crontab.5
@@ -121,6 +121,20 @@ override the settings described above no
 .I crontab
 file itself.  Note in particular that if you want a PATH other than
 "/usr/bin:/bin", you will need to set it in the crontab file.
+.PP
+By default, cron will send mail using the mail "Content-Type:" header of
+"text/plain" with the "charset=" parameter set to the charmap / codeset of the
+locale in which
+.IR crond (8)
+is started up \(en i.e.\& either the default system locale,
+if no LC_* environment variables are set, or the locale specified by
+the LC_* environment variables
+( see
+.IR locale (7) ).
+You can use different character encodings for mailed cron job output by
+setting the CONTENT_TYPE and CONTENT_TRANSFER_ENCODING variables in crontabs,
+to the correct values of the mail headers of those names.
+.PP
 The format of a cron command is very much the V7 standard, with a number of
 upward-compatible extensions.  Each line has five time and date fields,
 followed by a command, followed by a newline character ('\en').
