From d894d447b97133ede1263aa186ca75f013bde579 Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Wed, 16 Aug 2006 20:32:23 +0000 Subject: [PATCH] Do intelligent things with long header lines. --- copy.c | 34 +++------- protos.h | 1 + sendlib.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 199 insertions(+), 33 deletions(-) diff --git a/copy.c b/copy.c index 16af8e8f..68cfcae1 100644 --- a/copy.c +++ b/copy.c @@ -39,6 +39,7 @@ static int copy_delete_attach (BODY *b, FILE *fpin, FILE *fpout, char *date); /* Ok, the only reason for not merging this with mutt_copy_header() * below is to avoid creating a HEADER structure in message_handler(). + * Also, this one will wrap headers much more aggressively than the other one. */ int mutt_copy_hdr (FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags, @@ -275,34 +276,15 @@ mutt_copy_hdr (FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags, /* We couldn't do the prefixing when reading because RFC 2047 * decoding may have concatenated lines. */ - if (flags & CH_PREFIX) + + if (flags & (CH_DECODE|CH_PREFIX)) { - char *ch = headers[x]; - int print_prefix = 1; - - while (*ch) - { - if (print_prefix) - { - if (fputs (prefix, out) == EOF) - { - error = TRUE; - break; - } - print_prefix = 0; - } - - if (*ch == '\n' && ch[1]) - print_prefix = 1; - - if (putc (*ch++, out) == EOF) - { - error = TRUE; - break; - } - } - if (error) + if (mutt_write_one_header (out, 0, headers[x], + flags & CH_PREFIX ? prefix : 0) == -1) + { + error = TRUE; break; + } } else { diff --git a/protos.h b/protos.h index 857e115b..451753c8 100644 --- a/protos.h +++ b/protos.h @@ -356,6 +356,7 @@ int mutt_which_case (const char *); int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int, char *); int mutt_write_mime_body (BODY *, FILE *); int mutt_write_mime_header (BODY *, FILE *); +int mutt_write_one_header (FILE *fp, const char *tag, const char *value, const char *pfx); int mutt_write_rfc822_header (FILE *, ENVELOPE *, BODY *, int, int); int mutt_yesorno (const char *, int); void mutt_set_header_color(CONTEXT *, HEADER *); diff --git a/sendlib.c b/sendlib.c index c629f685..1543a6bf 100644 --- a/sendlib.c +++ b/sendlib.c @@ -1517,6 +1517,176 @@ static void write_references (LIST *r, FILE *f) FREE (&ref); } + +#define WRAPLEN 76 + +static void foldingstrfcpy (char *d, const char *s, int n) +{ + while (--n >= 0 && *s) + { + *d = *s++; + if (*d == '\t') + *d = ' '; + if (!(d[0] == '\n' && (*s == '\t' || *s == ' '))) + d++; + } + *d = '\0'; +} + +int mutt_write_one_header (FILE *fp, const char *tag, const char *value, const char *pfx) +{ + int col = 0; + int i, k, n; + const char *cp; + char buf [HUGE_STRING]; + wchar_t w; + int l = 0; + int first = 1; + int wrapped = 0; + int in_encoded_word = 0; + + if (tag) + { + if (fprintf (fp, "%s%s: ", NONULL (pfx), tag) < 0) + return -1; + + col = mutt_strlen (tag) + 2 + mutt_strlen (pfx); + } + else + col = 0; + + *buf = '\0'; + cp = value; + + while (cp && *cp) + { + if (!col) + { + if (fputs (NONULL (pfx), fp) == EOF) + return -1; + col = mutt_strlen (pfx); + + /* Space padding, but only if necessary */ + if (!first && *cp != '\t' && *cp != ' ') + { + if (fputc ('\t', fp) == EOF) + return -1; + col += 8 - (col % 8); + } + } + + if (first) + wrapped = 0; + + first = 0; + + /* + * i is our running pointer, and always points to the *beginning* of an mb character. + * k is the pointer to the beginning of the last white-space character we have seen. + * n is the pointer to the beginning of the first character after white-space. + * + * yuck + */ + + for (i = 0, k = 0, l = 0, n = 0; i < sizeof (buf) && cp[i] != '\0' && + ((col < (WRAPLEN + (k ? 0 : WRAPLEN)) || in_encoded_word)); + i += l) + { + + /* If there is a line break in the header, honor it. */ + if (cp[i] == '\n') + { + in_encoded_word = 0; + + if (cp[i+1] != ' ' && cp[i+1] != '\t') + first = 1; + + if (first || !wrapped) + { + k = i; + n = k + 1; + l = 1; + break; + } + } + + /* Eat the current character; cannot be '\0' */ + + if ((l = mbtowc (&w, &cp[i], MB_CUR_MAX)) <= 0) + { + dprint (1, (debugfile, "mutt_write_one_header: encoutered bad multi-byte character at %d.\n", i)); + l = 1; /* if bad, move on by one character */ + } + else + { + if (wcwidth (w) >= 0) + col += wcwidth (w); + + if (iswspace (w)) + { + if (strncmp (&cp[i+l], "=?", 2) == 0) + in_encoded_word = 1; + else + in_encoded_word = 0; + } + + if (iswspace (w) && + (!k || col <= WRAPLEN)) + { + if (!k || i != n) + k = i; + n = i + l; + } + } + + /* + * As long as we haven't seen whitespace, we advance at least by one character. + */ + if (!k) + n = i + l; + } + + /* If no whitespace was found, copy as much as we can */ + if (!k) + k = n; + + /* If we're done, we're done. */ + if (!cp[i]) + k = n = i; + + if (k < i) /* we had to go back to an earlier wrapping point */ + wrapped = 1; + + buf[0] = *cp; + foldingstrfcpy (buf + 1, cp + 1, k - 1); + + if (fprintf (fp, "%s\n", buf) < 0) + return -1; + col = 0; + + cp = &cp[n]; + + while (*cp) + { + if ((l = mbtowc (&w, cp, MB_CUR_MAX)) > 0 && iswspace (w)) + cp += l; + else + break; + } + } + + if (col) + { + if (fputc ('\n', fp) == EOF) + return -1; + col = 0; + } + + return 0; +} + +#undef WRAPLEN + /* Note: all RFC2047 encoding should be done outside of this routine, except * for the "real name." This will allow this routine to be used more than * once, if necessary. @@ -1533,11 +1703,13 @@ static void write_references (LIST *r, FILE *f) * */ + + int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, int mode, int privacy) { char buffer[LONG_STRING]; - char *p; + char *p, *q; LIST *tmp = env->userhdrs; int has_agent = 0; /* user defined user-agent header field exists */ @@ -1582,13 +1754,13 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, fputs ("Bcc: \n", fp); if (env->subject) - fprintf (fp, "Subject: %s\n", env->subject); + mutt_write_one_header (fp, "Subject", env->subject, NULL); else if (mode == 1) fputs ("Subject: \n", fp); /* save message id if the user has set it */ if (env->message_id && !privacy) - fprintf (fp, "Message-ID: %s\n", env->message_id); + mutt_write_one_header (fp, "Message-ID", env->message_id, NULL); if (env->reply_to) { @@ -1630,19 +1802,30 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach, { if ((p = strchr (tmp->data, ':'))) { + q = p; + + *p = '\0'; + p++; SKIPWS (p); - if (!*p) continue; /* don't emit empty fields. */ + if (!*p) + { + *q = ':'; + continue; /* don't emit empty fields. */ + } /* check to see if the user has overridden the user-agent field */ if (!ascii_strncasecmp ("user-agent", tmp->data, 10)) { has_agent = 1; if (privacy) + { + *q = ':'; continue; + } } - - fputs (tmp->data, fp); - fputc ('\n', fp); + + mutt_write_one_header (fp, tmp->data, p, NULL); + *q = ':'; } } -- 2.40.0