imap.preformattedHTML to tell Thunderbird to send non-flowed text

Many e-mail based development communities require non-flowed text to carry
patches to prevent whitespaces from getting mangled, but there is no easy
way to tell Thunderbird MUA not to use format=flowed, unless you configure
it to do so unconditionally for all outgoing mails.

A workaround for users who use git-imap-send is to wrap the patch in "pre"
element in the draft folder as an HTML message, and tell Thunderbird to
send "text only".  Thunderbird turns such a message into a non-flowed
plain text when sending it out, which is what we want for patch e-mails.

Signed-off-by: Jeremy White <jwhite@codeweavers.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 1685f04..024084b 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -64,6 +64,13 @@
 	used by the SSL/TLS connection. Default is `true`. Ignored when
 	imap.tunnel is set.
 
+imap.preformattedHTML::
+	A boolean to enable/disable the use of html encoding when sending
+	a patch.  An html encoded patch will be bracketed with <pre>
+	and have a content type of text/html.  Ironically, enabling this
+	option causes Thunderbird to send the patch as a plain/text,
+	format=fixed email.  Default is `false`.
+
 Examples
 ~~~~~~~~
 
diff --git a/imap-send.c b/imap-send.c
index f91293c..cb518eb 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -135,6 +135,7 @@
 	char *pass;
 	int use_ssl;
 	int ssl_verify;
+	int use_html;
 };
 
 struct imap_store_conf {
@@ -1263,6 +1264,53 @@
 	return DRV_OK;
 }
 
+static void encode_html_chars(struct strbuf *p)
+{
+	int i;
+	for (i = 0; i < p->len; i++) {
+		if (p->buf[i] == '&')
+			strbuf_splice(p, i, 1, "&amp;", 5);
+		if (p->buf[i] == '<')
+			strbuf_splice(p, i, 1, "&lt;", 4);
+		if (p->buf[i] == '>')
+			strbuf_splice(p, i, 1, "&gt;", 4);
+		if (p->buf[i] == '"')
+			strbuf_splice(p, i, 1, "&quot;", 6);
+	}
+}
+static void wrap_in_html(struct msg_data *msg)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf **lines;
+	struct strbuf **p;
+	static char *content_type = "Content-Type: text/html;\n";
+	static char *pre_open = "<pre>\n";
+	static char *pre_close = "</pre>\n";
+	int added_header = 0;
+
+	strbuf_attach(&buf, msg->data, msg->len, msg->len);
+	lines = strbuf_split(&buf, '\n');
+	strbuf_release(&buf);
+	for (p = lines; *p; p++) {
+		if (! added_header) {
+			if ((*p)->len == 1 && *((*p)->buf) == '\n') {
+				strbuf_addstr(&buf, content_type);
+				strbuf_addbuf(&buf, *p);
+				strbuf_addstr(&buf, pre_open);
+				added_header = 1;
+				continue;
+			}
+		}
+		else
+			encode_html_chars(*p);
+		strbuf_addbuf(&buf, *p);
+	}
+	strbuf_addstr(&buf, pre_close);
+	strbuf_list_free(lines);
+	msg->len  = buf.len;
+	msg->data = strbuf_detach(&buf, NULL);
+}
+
 #define CHUNKSIZE 0x1000
 
 static int read_message(FILE *f, struct msg_data *msg)
@@ -1339,6 +1387,7 @@
 	NULL,	/* pass */
 	0,   	/* use_ssl */
 	1,   	/* ssl_verify */
+	0,   	/* use_html */
 };
 
 static char *imap_folder;
@@ -1377,6 +1426,8 @@
 		server.tunnel = xstrdup(val);
 	else if (!strcmp("sslverify", key))
 		server.ssl_verify = git_config_bool(key, val);
+	else if (!strcmp("preformattedHTML", key))
+		server.use_html = git_config_bool(key, val);
 	return 0;
 }
 
@@ -1439,6 +1490,8 @@
 		fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
 		if (!split_msg(&all_msgs, &msg, &ofs))
 			break;
+		if (server.use_html)
+			wrap_in_html(&msg);
 		r = imap_store_msg(ctx, &msg, &uid);
 		if (r != DRV_OK)
 			break;