git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 2/2] mailinfo: unescape quoted-pair in header fields

From
Kevin Daudt <me@ikke.info>
Date
Sep 25, 2016, 21:08 UTC
Message-ID
<20160925210808.26424-2-me@ikke.info>
In-Reply-To
<20160925210808.26424-1-me@ikke.info>

rfc2822 has provisions for quoted strings and comments in structured header fields, but also allows for escaping these with so-called quoted-pairs.

The only thing git currently does is removing exterior quotes, but quotes within are left alone.

Remove exterior quotes and remove escape characters so that they don't show up in the author field.

Signed-off-by: Kevin Daudt <me@ikke.info>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Changes since v2:
 - handle comments inside comments recursively
 - renamed the main function to unquote_quoted_pairs because it also
   handles quoted pairs in comments
 mailinfo.c                   | 82 ++++++++++++++++++++++++++++++++++++++++++++
 t/t5100-mailinfo.sh          | 14 ++++++++
 t/t5100/comment.expect       |  5 +++
 t/t5100/comment.in           |  9 +++++
 t/t5100/quoted-string.expect |  5 +++
 t/t5100/quoted-string.in     |  9 +++++
 6 files changed, 124 insertions(+)
 create mode 100644 t/t5100/comment.expect
 create mode 100644 t/t5100/comment.in
 create mode 100644 t/t5100/quoted-string.expect
 create mode 100644 t/t5100/quoted-string.in
diff --git a/mailinfo.c b/mailinfo.c
index e19abe3..b4118a0 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -54,6 +54,86 @@ static void parse_bogus_from(struct mailinfo *mi, const struct strbuf *line)
 	get_sane_name(&mi->name, &mi->name, &mi->email);
 }
 
+static const char *unquote_comment(struct strbuf *outbuf, const char *in)
+{
+	int c;
+	int take_next_litterally = 0;
+
+	strbuf_addch(outbuf, '(');
+
+	while ((c = *in++) != 0) {
+		if (take_next_litterally == 1) {
+			take_next_litterally = 0;
+		} else {
+			switch (c) {
+			case '\\':
+				take_next_litterally = 1;
+				continue;
+			case '(':
+				in = unquote_comment(outbuf, in);
+				continue;
+			case ')':
+				strbuf_addch(outbuf, ')');
+				return in;
+			}
+		}
+
+		strbuf_addch(outbuf, c);
+	}
+
+	return in;
+}
+
+static const char *unquote_quoted_string(struct strbuf *outbuf, const char *in)
+{
+	int c;
+	int take_next_litterally = 0;
+
+	while ((c = *in++) != 0) {
+		if (take_next_litterally == 1) {
+			take_next_litterally = 0;
+		} else {
+			switch (c) {
+			case '\\':
+				take_next_litterally = 1;
+				continue;
+			case '"':
+				return in;
+			}
+		}
+
+		strbuf_addch(outbuf, c);
+	}
+
+	return in;
+}
+
+static void unquote_quoted_pair(struct strbuf *line)
+{
+	struct strbuf outbuf;
+	const char *in = line->buf;
+	int c;
+
+	strbuf_init(&outbuf, line->len);
+
+	while ((c = *in++) != 0) {
+		switch (c) {
+		case '"':
+			in = unquote_quoted_string(&outbuf, in);
+			continue;
+		case '(':
+			in = unquote_comment(&outbuf, in);
+			continue;
+		}
+
+		strbuf_addch(&outbuf, c);
+	}
+
+	strbuf_swap(&outbuf, line);
+	strbuf_release(&outbuf);
+
+}
+
 static void handle_from(struct mailinfo *mi, const struct strbuf *from)
 {
 	char *at;
@@ -63,6 +143,8 @@ static void handle_from(struct mailinfo *mi, const struct strbuf *from)
 	strbuf_init(&f, from->len);
 	strbuf_addbuf(&f, from);
 
+	unquote_quoted_pair(&f);
+
 	at = strchr(f.buf, '@');
 	if (!at) {
 		parse_bogus_from(mi, from);
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index c4ed0f4..3e983c0 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -144,4 +144,18 @@ test_expect_success 'mailinfo unescapes with --mboxrd' '
 	test_cmp expect mboxrd/msg
 '
 
+test_expect_success 'mailinfo handles rfc2822 quoted-string' '
+	mkdir quoted-string &&
+	git mailinfo /dev/null /dev/null <"$DATA"/quoted-string.in \
+		>quoted-string/info &&
+	test_cmp "$DATA"/quoted-string.expect quoted-string/info
+'
+
+test_expect_success 'mailinfo handles rfc2822 comment' '
+	mkdir comment &&
+	git mailinfo /dev/null /dev/null <"$DATA"/comment.in \
+		>comment/info &&
+	test_cmp "$DATA"/comment.expect comment/info
+'
+
 test_done
diff --git a/t/t5100/comment.expect b/t/t5100/comment.expect
new file mode 100644
index 0000000..7228177
--- /dev/null
+++ b/t/t5100/comment.expect
@@ -0,0 +1,5 @@
+Author: A U Thor (this is (really) a comment (honestly))
+Email: somebody@example.com
+Subject: testing comments
+Date: Sun, 25 May 2008 00:38:18 -0700
+
diff --git a/t/t5100/comment.in b/t/t5100/comment.in
new file mode 100644
index 0000000..c53a192
--- /dev/null
+++ b/t/t5100/comment.in
@@ -0,0 +1,9 @@
+From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001
+From: "A U Thor" <somebody@example.com> (this is \(really\) a comment (honestly))
+Date: Sun, 25 May 2008 00:38:18 -0700
+Subject: [PATCH] testing comments
+
+
+
+---
+patch
diff --git a/t/t5100/quoted-string.expect b/t/t5100/quoted-string.expect
new file mode 100644
index 0000000..cab1bce
--- /dev/null
+++ b/t/t5100/quoted-string.expect
@@ -0,0 +1,5 @@
+Author: Author "The Author" Name
+Email: somebody@example.com
+Subject: testing quoted-pair
+Date: Sun, 25 May 2008 00:38:18 -0700
+
diff --git a/t/t5100/quoted-string.in b/t/t5100/quoted-string.in
new file mode 100644
index 0000000..e2e627a
--- /dev/null
+++ b/t/t5100/quoted-string.in
@@ -0,0 +1,9 @@
+From 1234567890123456789012345678901234567890 Mon Sep 17 00:00:00 2001
+From: "Author \"The Author\" Name" <somebody@example.com>
+Date: Sun, 25 May 2008 00:38:18 -0700
+Subject: [PATCH] testing quoted-pair
+
+
+
+---
+patch
-- 
2.10.0.89.ge802c3a.dirty
Previous: Kevin DaudtNext: Junio C Hamano
Message 21 of 32 in “mailinfo: unescape quoted-pair in header fields”
  1. mailinfo: unescape quoted-pair in header fieldsKevin Daudt, Sep 16, 2016
  2. Jeff KingSep 16, 2016
  3. Kevin DaudtSep 19, 2016
  4. Jeff KingSep 20, 2016
  5. Junio C HamanoSep 21, 2016
  6. 0/2 Handle escape characters in From field.Kevin Daudt, Sep 19, 2016
  7. 2/2 mailinfo: unescape quoted-pair in header fieldsKevin Daudt, Sep 19, 2016
  8. Junio C HamanoSep 19, 2016
  9. Junio C HamanoSep 19, 2016
  10. Jeff KingSep 20, 2016
  11. Jeff KingSep 21, 2016
  12. Junio C HamanoSep 22, 2016
  13. Jeff KingSep 23, 2016
  14. Kevin DaudtSep 25, 2016
  15. Jakub NarębskiSep 25, 2016
  16. Kevin DaudtSep 26, 2016
  17. 1/2 t5100-mailinfo: replace common path prefix with variableKevin Daudt, Sep 19, 2016
  18. Junio C HamanoSep 19, 2016
  19. Jeff KingSep 20, 2016
  20. 1/2 t5100-mailinfo: replace common path prefix with variableKevin Daudt, Sep 25, 2016
  21. 2/2 mailinfo: unescape quoted-pair in header fieldsKevin Daudt, Sep 25, 2016
  22. Junio C HamanoSep 26, 2016
  23. Junio C HamanoSep 26, 2016
  24. Kevin DaudtSep 26, 2016
  25. Junio C HamanoSep 26, 2016
  26. Kevin DaudtSep 27, 2016
  27. Junio C HamanoSep 26, 2016
  28. 0/2 Handle RFC2822 quoted-pairs in From headerKevin Daudt, Sep 28, 2016
  29. 1/2 t5100-mailinfo: replace common path prefix with variableKevin Daudt, Sep 28, 2016
  30. Junio C HamanoSep 28, 2016
  31. Kevin DaudtSep 28, 2016
  32. 2/2 mailinfo: unescape quoted-pair in header fieldsKevin Daudt, Sep 28, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.