<<< Date Index >>>     <<< Thread Index >>>

patch-1.5.13.tlr.wrap_headers.1



Hello,

the attached patch teaches mutt a bit about being nice with writing
headers (such as subject) -- unless what I thought we do, we're not
actually wrapping subject headers when we write them.

While I was on it, messages are now also written a bit differently
when the editor's copy of a message is prepared (joy of joys, the
algorithm needs to be multibyte-aware), and when messages are
displayed.

Comments welcome; this is not yet in the CVS.  Might be buggy.

Cheers,
-- 
Thomas Roessler   <roessler@xxxxxxxxxxxxxxxxxx>
Index: copy.c
===================================================================
RCS file: /cvs/mutt/mutt/copy.c,v
retrieving revision 3.27
diff -u -r3.27 copy.c
--- copy.c      21 Oct 2005 04:35:37 -0000      3.27
+++ copy.c      16 Aug 2006 20:13:10 -0000
@@ -39,6 +39,7 @@
 
 /* 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 @@
       /* 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
       {      
Index: protos.h
===================================================================
RCS file: /cvs/mutt/mutt/protos.h,v
retrieving revision 3.45
diff -u -r3.45 protos.h
--- protos.h    11 Jul 2006 23:34:11 -0000      3.45
+++ protos.h    16 Aug 2006 20:13:10 -0000
@@ -356,6 +356,7 @@
 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 *);
Index: sendlib.c
===================================================================
RCS file: /cvs/mutt/mutt/sendlib.c,v
retrieving revision 3.40
diff -u -r3.40 sendlib.c
--- sendlib.c   17 Jul 2006 17:56:37 -0000      3.40
+++ sendlib.c   16 Aug 2006 20:13:11 -0000
@@ -1517,6 +1517,176 @@
   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; k < 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 @@
  *
  */
 
+
+
 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 @@
     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 @@
   {
     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 = ':';
     }
   }