File: Wrap-long-lines.patch

package info (click to toggle)
cron 3.0pl1-197
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 3,816 kB
  • sloc: ansic: 54,879; xml: 1,600; perl: 733; sh: 463; makefile: 446; python: 43
file content (133 lines) | stat: -rw-r--r-- 4,130 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
From: Georges Khaznadar <georgesk@debian.org>
Date: Wed, 22 Nov 2023 17:10:27 +0100
Subject: Wrap long lines

To avoid loosing cronjob mails with a "line too long" error
(exim4, for example) cron will wrap very long lines. The default encoding is
set to QUOTED-PRINTABLE

A new test is provided for autopkgtests

Contributed by Frank Heckenbach <f.heckenbach@fh-soft.de>

Bug-Debian: https://bugs.debian.org/777584
Forwarded: no
Last-Update: 2023-11-22
---
 config.h     | 17 +++++++++++++++++
 do_command.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/config.h b/config.h
index b7f4340..dd1a495 100644
--- a/config.h
+++ b/config.h
@@ -70,6 +70,23 @@
 			 * generate the Date: header.
 			 */
 
+			/* Content-Transfer-Encoding used in mail sent
+			 * if CONTENT_TRANSFER_ENCODING is not set.
+			 *
+			 * "8bit", the previous default, does not do
+			 * any encoding and will fail with long lines
+			 * (> 998 characters according to RFC 5322).
+			 *
+			 * "auto" means some suitable encoding (currently
+			 * quoted-printable) which cron will do internally.
+			 *
+			 * In contrast, setting this define or
+			 * CONTENT_TRANSFER_ENCODING to quoted-printable means
+			 * the command output must be encoded already.
+			 */
+/*#define DEFAULT_CONTENT_TRANSFER_ENCODING "8bit"			/*-*/
+#define DEFAULT_CONTENT_TRANSFER_ENCODING "auto"			/*-*/
+
 			/* if ALLOW_FILE and DENY_FILE are not defined or are
 			 * defined but neither exists, should crontab(1) be
 			 * usable only by root?
diff --git a/do_command.c b/do_command.c
index 43054ee..eb70b8a 100644
--- a/do_command.c
+++ b/do_command.c
@@ -543,6 +543,7 @@ child_process(e, u)
 	auto char	hostname[MAXHOSTNAMELEN];
 	char		*content_type = env_get("CONTENT_TYPE",jobenv),
 			*content_transfer_encoding = env_get("CONTENT_TRANSFER_ENCODING",jobenv);
+	int encoding_auto = 0;
 
 	(void) gethostname(hostname, MAXHOSTNAMELEN);
 	(void) snprintf(mailcmd, sizeof(mailcmd),
@@ -590,12 +591,13 @@ child_process(e, u)
 				(nl < (content_transfer_encoding+ctlen))) {
 			*nl = ' ';
 		}
-
-		fprintf(mail,"Content-Transfer-Encoding: %s\n",
-				content_transfer_encoding);
 	} else {
-		fprintf(mail,"Content-Transfer-Encoding: 8bit\n");
+		content_transfer_encoding = DEFAULT_CONTENT_TRANSFER_ENCODING;
 	}
+	encoding_auto = strcmp (content_transfer_encoding,"auto") == 0;
+	fprintf(mail,"Content-Transfer-Encoding: %s\n",
+			encoding_auto ? "quoted-printable"
+				: content_transfer_encoding);
 
 	for (env = e->envp;  *env;  env++)
 		fprintf(mail, "X-Cron-Env: <%s>\n",
@@ -606,12 +608,53 @@ child_process(e, u)
 
 	char buf[4096];
 	int ret, remain;
+	/* A QP character results in 3 characters. Inserted soft line breaks
+	 * may need a bit more. 4 is more than enough over the whole buffer.
+	 */
+	char buf_encoded[4 * sizeof(buf)];
+	char *buf_out = buf;
+	int qp_line_length = 0;
 
 	while(1) {
 		if ((ret = fread(buf, 1, sizeof(buf), tmpout)) == 0)
 			break;
+		
+		if (encoding_auto) {
+			// Quoted-printable encoding according to RFC 2045, 6.7
+			char *in, *out = buf_encoded;
+			for (in = buf; in < buf + ret; in++) {
+				// maximum output line width is 76 characters
+				if (qp_line_length > 72) {
+					*out++ = '=';
+					*out++ = '\n';
+					qp_line_length = 0;
+				}
+				if (*in == '\n') {
+					// encoded lines may not end with SPACE or TAB
+					if (out > buf_encoded
+						&& (out[-1] == ' ' || out[-1] == '\t')) {
+						*out++ = '=';
+						*out++ = '\n';
+					}
+					*out++ = *in;
+					qp_line_length = 0;
+				} else if ((*in >= 33 && *in <= 126 && *in != '=')
+					|| ((*in == ' ' || *in == '\t')
+						&& in + 1 < buf + ret)) {
+					*out++ = *in;
+					qp_line_length++;
+				} else {
+					int r = sprintf(out, "=%02X", (unsigned char)*in);
+					out += r;
+					qp_line_length += r;
+				}
+			}
+			buf_out = buf_encoded;
+			ret = out - buf_encoded;
+		}
+		
 		for (remain = ret; remain != 0; ) {
-			ret = fwrite(buf, 1, remain, mail);
+			ret = fwrite(buf_out, 1, remain, mail);
 			if (ret > 0) {
 				remain -= ret;
 				bytes += ret;