1From: A <author@example.com>
2Subject: [PATCH] mailinfo: support format=flowed
3Message-ID: <aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa@example.com>
4Date: Sat, 25 Aug 2018 22:04:50 +0200
5User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101
6 Thunderbird/60.0
7MIME-Version: 1.0
8Content-Type: text/plain; charset=utf-8; format=flowed
9Content-Language: en-US
10Content-Transfer-Encoding: 7bit
11
12---
13 mailinfo.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
14 1 file changed, 62 insertions(+), 2 deletions(-)
15
16diff --git a/mailinfo.c b/mailinfo.c
17index 3281a37d51..b395adbdf2 100644
18--- a/mailinfo.c
19+++ b/mailinfo.c
20@@ -237,11 +237,22 @@ static int slurp_attr(const char *line, const char
21*name, struct strbuf *attr)
22 return 1;
23 }
24
25+static int has_attr_value(const char *line, const char *name, const
26char *value)
27+{
28+ struct strbuf sb = STRBUF_INIT;
29+ int rc = slurp_attr(line, name, &sb) && !strcasecmp(sb.buf, value);
30+ strbuf_release(&sb);
31+ return rc;
32+}
33+
34 static void handle_content_type(struct mailinfo *mi, struct strbuf *line)
35 {
36 struct strbuf *boundary = xmalloc(sizeof(struct strbuf));
37 strbuf_init(boundary, line->len);
38
39+ mi->format_flowed = has_attr_value(line->buf, "format=", "flowed");
40+ mi->delsp = has_attr_value(line->buf, "delsp=", "yes");
41+
42 if (slurp_attr(line->buf, "boundary=", boundary)) {
43 strbuf_insert(boundary, 0, "--", 2);
44 if (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) {
45@@ -964,6 +975,52 @@ static int handle_boundary(struct mailinfo *mi,
46struct strbuf *line)
47 return 1;
48 }
49
50+static void handle_filter_flowed(struct mailinfo *mi, struct strbuf *line,
51+ struct strbuf *prev)
52+{
53+ size_t len = line->len;
54+ const char *rest;
55+
56+ if (!mi->format_flowed) {
57+ handle_filter(mi, line);
58+ return;
59+ }
60+
61+ if (line->buf[len - 1] == '\n') {
62+ len--;
63+ if (len && line->buf[len - 1] == '\r')
64+ len--;
65+ }
66+
67+ /* Keep signature separator as-is. */
68+ if (skip_prefix(line->buf, "-- ", &rest) && rest - line->buf == len) {
69+ if (prev->len) {
70+ handle_filter(mi, prev);
71+ strbuf_reset(prev);
72+ }
73+ handle_filter(mi, line);
74+ return;
75+ }
76+
77+ /* Unstuff space-stuffed line. */
78+ if (len && line->buf[0] == ' ') {
79+ strbuf_remove(line, 0, 1);
80+ len--;
81+ }
82+
83+ /* Save flowed line for later, but without the soft line break. */
84+ if (len && line->buf[len - 1] == ' ') {
85+ strbuf_add(prev, line->buf, len - !!mi->delsp);
86+ return;
87+ }
88+
89+ /* Prepend any previous partial lines */
90+ strbuf_insert(line, 0, prev->buf, prev->len);
91+ strbuf_reset(prev);
92+
93+ handle_filter(mi, line);
94+}
95+
96 static void handle_body(struct mailinfo *mi, struct strbuf *line)
97 {
98 struct strbuf prev = STRBUF_INIT;
99@@ -1012,7 +1069,7 @@ static void handle_body(struct mailinfo *mi,
100struct strbuf *line)
101 strbuf_addbuf(&prev, sb);
102 break;
103 }
104- handle_filter(mi, sb);
105+ handle_filter_flowed(mi, sb, &prev);
106 }
107 /*
108 * The partial chunk is saved in "prev" and will be
109@@ -1022,13 +1079,16 @@ static void handle_body(struct mailinfo *mi,
110struct strbuf *line)
111 break;
112 }
113 default:
114- handle_filter(mi, line);
115+ handle_filter_flowed(mi, line, &prev);
116 }
117
118 if (mi->input_error)
119 break;
120 } while (!strbuf_getwholeline(line, mi->input, '\n'));
121
122+ if (prev.len)
123+ handle_filter(mi, &prev);
124+
125 flush_inbody_header_accum(mi);
126
127 handle_body_out:
128--
1292.18.0