about summary refs log tree commit diff
path: root/mmime.c
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2017-03-28 01:03:40 +0200
committerLeah Neukirchen <leah@vuxu.org>2017-03-28 01:03:40 +0200
commit2d612ce1667b45112cfd09729c58170270d721ec (patch)
tree9cb18f8bb8b704b9e5635dcc376f853d31419b1d /mmime.c
parent6d492539d61b40137c6c863e21e3fa95c2bd2150 (diff)
downloadmblaze-2d612ce1667b45112cfd09729c58170270d721ec.tar.gz
mblaze-2d612ce1667b45112cfd09729c58170270d721ec.tar.xz
mblaze-2d612ce1667b45112cfd09729c58170270d721ec.zip
mmime: print_header: refactor
Simplifies the code considerably.  QP-header-wrapping now happens inside
gen_qp.  We wrap the line in advance when this will save QP-encoding, or
splitting a QP-word into two.

Fixes #20.
Diffstat (limited to 'mmime.c')
-rw-r--r--mmime.c81
1 files changed, 39 insertions, 42 deletions
diff --git a/mmime.c b/mmime.c
index 78bd757..cf08bd6 100644
--- a/mmime.c
+++ b/mmime.c
@@ -56,10 +56,10 @@ int gen_b64(uint8_t *s, off_t size)
 	return 0;
 }
 
-int gen_qp(uint8_t *s, off_t size, int maxlinelen, int header)
+int gen_qp(uint8_t *s, off_t size, int maxlinelen, int linelen)
 {
 	off_t i;
-	int linelen = 0;
+	int header = linelen > 0;
 	char prev = 0;
 
 	for (i = 0; i < size; i++) {
@@ -90,10 +90,15 @@ int gen_qp(uint8_t *s, off_t size, int maxlinelen, int header)
 			prev = s[i];
 		}
 		
-		if (linelen >= maxlinelen-3) {
+		if (linelen >= maxlinelen-3-!!header) {
 			linelen = 0;
 			prev = '\n';
-			puts("=");
+			if (header) {
+				printf("?=\n =?UTF-8?Q?");
+				linelen += 11;
+			} else {
+				puts("=");
+			}
 		}
 	}
 	if (linelen > 0 && !header)
@@ -192,7 +197,7 @@ print_header(char *line) {
 			putc_unlocked(*s++, stdout);
 	}
 
-	int prevq = 0;
+	int prevq = 0;  // was the previous word encoded as qp?
 
 	int linelen = s - line;
 
@@ -205,51 +210,43 @@ print_header(char *line) {
 			if ((uint8_t) *e >= 127)
 				highbit++;
 		}
-		// use qp for lines with high bit, for long lines, or
-		// for more than two spaces
-		if (highbit ||
-		    e-s > 78-linelen ||
-		    (prevq && s[0] == ' ' && s[1] == ' ')) {
-			if (!prevq && s[0] == ' ')
-				s++;
 
-			// 13 = strlen(" =?UTF-8?Q??=")
-			int w;
-			while (s < e && (w = (78-linelen-13) / (highbit?3:1)) < e-s && w>0) {
-				printf(" =?UTF-8?Q?");
-				gen_qp((uint8_t *)s, w>e-s?e-s:w, 999, 1);
-				printf("?=\n");
-				s += w;
+		if (!highbit) {
+			if (e-s >= 78)
+				goto force_qp;
+			if (e-s >= 78 - linelen) {
+				// wrap in advance before long word
+				printf("\n");
 				linelen = 0;
-				prevq = 1;
 			}
-			if (s < e) {
-				if (linelen + (e-s)+13 > 78) {
-					printf("\n ");
-					linelen = 1;
-				}
-				if (highbit || s[0] == ' ') {
-					printf(" =?UTF-8?Q?");
-					linelen += 14;
-					linelen += gen_qp((uint8_t *)s, e-s, 999, 1);
-					printf("?=");
-					prevq = 1;
-				} else {
-					fwrite(s, 1, e-s, stdout);
-					linelen += e-s;
-					prevq = 0;
-				}
+			if (linelen <= 1 && s[0] == ' ' && s[1] == ' ') {
+				// space at beginning of line
+				goto force_qp;
 			}
-		} else {
-			if (linelen + (e-s) > 78) {
-				printf("\n");
-				if (*s != ' ')
-					printf(" ");
-				linelen = 0;
+			if (*s != ' ') {
+				printf(" ");
+				linelen++;
 			}
 			fwrite(s, 1, e-s, stdout);
 			linelen += e-s;
 			prevq = 0;
+		} else {
+force_qp:
+			if (!prevq && *s == ' ')
+				s++;
+			if (linelen >= 78 - 13 - 4 ||
+			    (e-s < (78 - 13)/3 &&
+			     e-s >= (78 - linelen - 13)/3)) {
+				// wrap in advance
+				printf("\n");
+				linelen = 0;
+			}
+			printf(" =?UTF-8?Q?");
+			linelen += 11;
+			linelen = gen_qp((uint8_t *)s, e-s, 78, linelen);
+			printf("?=");
+			linelen += 2;
+			prevq = 1;
 		}
 		s = e;
 	}