Sixth batch for 2.20
[gitweb.git] / mailinfo.c
index a89db22ab0c8ef50ae31d5811de5fc48d09224a2..b395adbdf2a405567bc40c254125265f30b12bbd 100644 (file)
@@ -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]) {
@@ -716,7 +727,7 @@ static void flush_inbody_header_accum(struct mailinfo *mi)
        if (!mi->inbody_header_accum.len)
                return;
        if (!check_header(mi, &mi->inbody_header_accum, mi->s_hdr_data, 0))
-               die("BUG: inbody_header_accum, if not empty, must always contain a valid in-body header");
+               BUG("inbody_header_accum, if not empty, must always contain a valid in-body header");
        strbuf_reset(&mi->inbody_header_accum);
 }
 
@@ -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:
@@ -1167,11 +1227,13 @@ void clear_mailinfo(struct mailinfo *mi)
        strbuf_release(&mi->inbody_header_accum);
        free(mi->message_id);
 
-       for (i = 0; mi->p_hdr_data[i]; i++)
-               strbuf_release(mi->p_hdr_data[i]);
+       if (mi->p_hdr_data)
+               for (i = 0; mi->p_hdr_data[i]; i++)
+                       strbuf_release(mi->p_hdr_data[i]);
        free(mi->p_hdr_data);
-       for (i = 0; mi->s_hdr_data[i]; i++)
-               strbuf_release(mi->s_hdr_data[i]);
+       if (mi->s_hdr_data)
+               for (i = 0; mi->s_hdr_data[i]; i++)
+                       strbuf_release(mi->s_hdr_data[i]);
        free(mi->s_hdr_data);
 
        while (mi->content < mi->content_top) {