| 1 | From: A <author@example.com> |
| 2 | Subject: [PATCH] mailinfo: support format=flowed |
| 3 | Message-ID: <aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa@example.com> |
| 4 | Date: Sat, 25 Aug 2018 22:04:50 +0200 |
| 5 | User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 |
| 6 | Thunderbird/60.0 |
| 7 | MIME-Version: 1.0 |
| 8 | Content-Type: text/plain; charset=utf-8; format=flowed |
| 9 | Content-Language: en-US |
| 10 | Content-Transfer-Encoding: 7bit |
| 11 | |
| 12 | --- |
| 13 | mailinfo.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
| 14 | 1 file changed, 62 insertions(+), 2 deletions(-) |
| 15 | |
| 16 | diff --git a/mailinfo.c b/mailinfo.c |
| 17 | index 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 |
| 26 | char *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, |
| 46 | struct 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, |
| 100 | struct 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, |
| 110 | struct 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 | -- |
| 129 | 2.18.0 |