|  | From: A <author@example.com> | 
|  | Subject: [PATCH] mailinfo: support format=flowed | 
|  | Message-ID: <aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa@example.com> | 
|  | Date: Sat, 25 Aug 2018 22:04:50 +0200 | 
|  | User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 | 
|  | Thunderbird/60.0 | 
|  | MIME-Version: 1.0 | 
|  | Content-Type: text/plain; charset=utf-8; format=flowed | 
|  | Content-Language: en-US | 
|  | Content-Transfer-Encoding: 7bit | 
|  |  | 
|  | --- | 
|  | mailinfo.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- | 
|  | 1 file changed, 62 insertions(+), 2 deletions(-) | 
|  |  | 
|  | diff --git a/mailinfo.c b/mailinfo.c | 
|  | index 3281a37d51..b395adbdf2 100644 | 
|  | --- a/mailinfo.c | 
|  | +++ b/mailinfo.c | 
|  | @@ -237,11 +237,22 @@ static int slurp_attr(const char *line, const char | 
|  | *name, struct strbuf *attr) | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | +static int has_attr_value(const char *line, const char *name, const | 
|  | char *value) | 
|  | +{ | 
|  | +	struct strbuf sb = STRBUF_INIT; | 
|  | +	int rc = slurp_attr(line, name, &sb) && !strcasecmp(sb.buf, value); | 
|  | +	strbuf_release(&sb); | 
|  | +	return rc; | 
|  | +} | 
|  | + | 
|  | static void handle_content_type(struct mailinfo *mi, struct strbuf *line) | 
|  | { | 
|  | struct strbuf *boundary = xmalloc(sizeof(struct strbuf)); | 
|  | strbuf_init(boundary, line->len); | 
|  |  | 
|  | +	mi->format_flowed = has_attr_value(line->buf, "format=", "flowed"); | 
|  | +	mi->delsp = has_attr_value(line->buf, "delsp=", "yes"); | 
|  | + | 
|  | if (slurp_attr(line->buf, "boundary=", boundary)) { | 
|  | strbuf_insert(boundary, 0, "--", 2); | 
|  | if (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) { | 
|  | @@ -964,6 +975,52 @@ static int handle_boundary(struct mailinfo *mi, | 
|  | struct strbuf *line) | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | +static void handle_filter_flowed(struct mailinfo *mi, struct strbuf *line, | 
|  | +				 struct strbuf *prev) | 
|  | +{ | 
|  | +	size_t len = line->len; | 
|  | +	const char *rest; | 
|  | + | 
|  | +	if (!mi->format_flowed) { | 
|  | +		handle_filter(mi, line); | 
|  | +		return; | 
|  | +	} | 
|  | + | 
|  | +	if (line->buf[len - 1] == '\n') { | 
|  | +		len--; | 
|  | +		if (len && line->buf[len - 1] == '\r') | 
|  | +			len--; | 
|  | +	} | 
|  | + | 
|  | +	/* Keep signature separator as-is. */ | 
|  | +	if (skip_prefix(line->buf, "-- ", &rest) && rest - line->buf == len) { | 
|  | +		if (prev->len) { | 
|  | +			handle_filter(mi, prev); | 
|  | +			strbuf_reset(prev); | 
|  | +		} | 
|  | +		handle_filter(mi, line); | 
|  | +		return; | 
|  | +	} | 
|  | + | 
|  | +	/* Unstuff space-stuffed line. */ | 
|  | +	if (len && line->buf[0] == ' ') { | 
|  | +		strbuf_remove(line, 0, 1); | 
|  | +		len--; | 
|  | +	} | 
|  | + | 
|  | +	/* Save flowed line for later, but without the soft line break. */ | 
|  | +	if (len && line->buf[len - 1] == ' ') { | 
|  | +		strbuf_add(prev, line->buf, len - !!mi->delsp); | 
|  | +		return; | 
|  | +	} | 
|  | + | 
|  | +	/* Prepend any previous partial lines */ | 
|  | +	strbuf_insert(line, 0, prev->buf, prev->len); | 
|  | +	strbuf_reset(prev); | 
|  | + | 
|  | +	handle_filter(mi, line); | 
|  | +} | 
|  | + | 
|  | static void handle_body(struct mailinfo *mi, struct strbuf *line) | 
|  | { | 
|  | struct strbuf prev = STRBUF_INIT; | 
|  | @@ -1012,7 +1069,7 @@ static void handle_body(struct mailinfo *mi, | 
|  | struct strbuf *line) | 
|  | strbuf_addbuf(&prev, sb); | 
|  | break; | 
|  | } | 
|  | -				handle_filter(mi, sb); | 
|  | +				handle_filter_flowed(mi, sb, &prev); | 
|  | } | 
|  | /* | 
|  | * The partial chunk is saved in "prev" and will be | 
|  | @@ -1022,13 +1079,16 @@ static void handle_body(struct mailinfo *mi, | 
|  | struct strbuf *line) | 
|  | break; | 
|  | } | 
|  | default: | 
|  | -			handle_filter(mi, line); | 
|  | +			handle_filter_flowed(mi, line, &prev); | 
|  | } | 
|  |  | 
|  | if (mi->input_error) | 
|  | break; | 
|  | } while (!strbuf_getwholeline(line, mi->input, '\n')); | 
|  |  | 
|  | +	if (prev.len) | 
|  | +		handle_filter(mi, &prev); | 
|  | + | 
|  | flush_inbody_header_accum(mi); | 
|  |  | 
|  | handle_body_out: | 
|  | -- | 
|  | 2.18.0 |