]> git.llucax.com Git - software/mutt-debian.git/blobdiff - rfc3676.c
Standards-Version upgraded to 3.9.2.0, no changes required
[software/mutt-debian.git] / rfc3676.c
index 4de8ba7c09502c29e8441c2ada07cf8819fba905..aadda0f3093ee5d896e1574ca6cf1e1295e223e1 100644 (file)
--- a/rfc3676.c
+++ b/rfc3676.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2005 Andreas Krennmair <ak@synflood.at>
  * Copyright (C) 2005 Peter J. Holzer <hjp@hjp.net>
- * Copyright (C) 2005-7 Rocco Rutte <pdmef@gmx.net>
+ * Copyright (C) 2005-9 Rocco Rutte <pdmef@gmx.net>
  * 
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
 #include "ascii.h"
 #include "lib.h"
 
-#define FLOWED_MAX 77
+#define FLOWED_MAX 72
+
+typedef struct flowed_state
+{
+  size_t width;
+  size_t spaces;
+  int delsp;
+} flowed_state_t;
 
 static int get_quote_level (const char *line)
 {
@@ -56,23 +63,37 @@ static int get_quote_level (const char *line)
 static size_t print_indent (int ql, STATE *s, int sp)
 {
   int i;
+  size_t wid = 0;
 
   if (s->prefix)
-    ql++;
+  {
+    /* use given prefix only for format=fixed replies to format=flowed,
+     * for format=flowed replies to format=flowed, use '>' indentation
+     */
+    if (option (OPTTEXTFLOWED))
+      ql++;
+    else
+    {
+      state_puts (s->prefix, s);
+      wid = mutt_strwidth (s->prefix);
+      sp = 0;
+    }
+  }
   for (i = 0; i < ql; i++)
     state_putc ('>', s);
   if (sp)
     state_putc (' ', s);
-  return ql + sp;
+  return ql + sp + wid;
 }
 
-static void flush_par (STATE *s, size_t *sofar)
+static void flush_par (STATE *s, flowed_state_t *fst)
 {
-  if (*sofar > 0)
+  if (fst->width > 0)
   {
     state_putc ('\n', s);
-    *sofar = 0;
+    fst->width = 0;
   }
+  fst->spaces = 0;
 }
 
 static int quote_width (STATE *s, int ql)
@@ -85,120 +106,123 @@ static int quote_width (STATE *s, int ql)
   return width;
 }
 
-static void print_flowed_line (char *line, STATE *s, int ql, size_t *sofar, int term)
+static void print_flowed_line (char *line, STATE *s, int ql,
+                              flowed_state_t *fst, int term)
 {
-  size_t width, w, words;
+  size_t width, w, words = 0;
   char *p;
+  char last;
 
   if (!line || !*line)
   {
     /* flush current paragraph (if any) first */
-    flush_par (s, sofar);
+    flush_par (s, fst);
     print_indent (ql, s, 0);
     state_putc ('\n', s);
     return;
   }
 
   width = quote_width (s, ql);
+  last = line[mutt_strlen (line) - 1];
 
-  dprint (4, (debugfile, "f-f: line [%s], width = %ld\n", NONULL(line), (long)width));
+  dprint (4, (debugfile, "f=f: line [%s], width = %ld, spaces = %d\n",
+             NONULL(line), (long)width, fst->spaces));
 
   for (p = (char *)line, words = 0; (p = strsep (&line, " ")) != NULL ; )
   {
-    w = mutt_strwidth (NONULL(p));
-    dprint (4, (debugfile, "f-f: word [%s], width = %ld, line = %ld\n", NONULL(p), (long)w, (long)*sofar));
-    if (w + 1 + (*sofar) > width)
+    dprint(4,(debugfile,"f=f: word [%s], width: %d, remaining = [%s]\n",
+             p, fst->width, line));
+
+    /* remember number of spaces */
+    if (!*p)
     {
-      /* line would be too long, flush */
-      dprint (4, (debugfile, "f-f: width: %ld\n", (long)*sofar));
-      state_puts (" \n", s);
-      *sofar = 0;
+      dprint(4,(debugfile,"f=f: additional space\n"));
+      fst->spaces++;
+      continue;
     }
-    if (*sofar == 0)
+    /* there's exactly one space prior to every but the first word */
+    if (words)
+      fst->spaces++;
+
+    w = mutt_strwidth (p);
+    /* see if we need to break the line but make sure the first
+       word is put on the line regardless;
+       if for DelSp=yes only one trailing space is used, we probably
+       have a long word that we should break within (we leave that
+       up to the pager or user) */
+    if (!(!fst->spaces && fst->delsp && last != ' ') &&
+       w < width && w + fst->width + fst->spaces > width)
     {
-      /* indent empty lines */
-      *sofar = print_indent (ql, s, ql > 0 || s->prefix);
+      dprint(4,(debugfile,"f=f: break line at %d, %d spaces left\n",
+               fst->width, fst->spaces));
+      /* only honor trailing spaces for format=flowed replies */
+      if (option(OPTTEXTFLOWED))
+       for ( ; fst->spaces; fst->spaces--)
+         state_putc (' ', s);
+      state_putc ('\n', s);
+      fst->width = 0;
+      fst->spaces = 0;
       words = 0;
     }
-    if (words > 0)
-    {
-      /* put space before current word if we have words already */
+
+    if (!words && !fst->width)
+      fst->width = print_indent (ql, s, !(s->flags & M_REPLYING) &&
+                                (ql > 0 || s->prefix));
+    fst->width += w + fst->spaces;
+    for ( ; fst->spaces; fst->spaces--)
       state_putc (' ', s);
-      (*sofar)++;
-    }
-    state_puts (NONULL(p), s);
-    (*sofar) += w;
+    state_puts (p, s);
     words++;
   }
 
   if (term)
-    flush_par (s, sofar);
+    flush_par (s, fst);
 }
 
-static void print_fixed_line (const char *line, STATE *s, int ql, size_t *sofar)
+static void print_fixed_line (const char *line, STATE *s, int ql,
+                             flowed_state_t *fst)
 {
-  int len = mutt_strlen (line);
-
-  if (len == 0)
-  {
-    print_indent (ql, s, 0);
-    state_putc ('\n', s);
-    return;
-  }
-
-  print_indent (ql, s, ql > 0 || s->prefix);
-  state_puts (line, s);
+  print_indent (ql, s, !(s->flags & M_REPLYING) && (ql > 0 || s->prefix));
+  if (line && *line)
+    state_puts (line, s);
   state_putc ('\n', s);
 
-  *sofar = 0;
+  fst->width = 0;
+  fst->spaces = 0;
 }
 
 int rfc3676_handler (BODY * a, STATE * s)
 {
-  int bytes = a->length;
-  char buf[LONG_STRING];
-  char *t = NULL;
+  char *buf = NULL, *t = NULL;
   unsigned int quotelevel = 0, newql = 0, sigsep = 0;
-  int buf_off = 0, buf_len;
-  int delsp = 0, fixed = 0;
-  size_t width = 0;
+  int buf_off = 0, delsp = 0, fixed = 0;
+  size_t buf_len = 0, sz = 0;
+  flowed_state_t fst;
+
+  memset (&fst, 0, sizeof (fst));
 
   /* respect DelSp of RfC3676 only with f=f parts */
   if ((t = (char *) mutt_get_parameter ("delsp", a->parameter)))
   {
     delsp = mutt_strlen (t) == 3 && ascii_strncasecmp (t, "yes", 3) == 0;
     t = NULL;
+    fst.delsp = 1;
   }
 
   dprint (4, (debugfile, "f=f: DelSp: %s\n", delsp ? "yes" : "no"));
 
-  while (bytes > 0 && fgets (buf, sizeof (buf), s->fpin))
+  while ((buf = mutt_read_line (buf, &sz, s->fpin, NULL, 0)))
   {
-
     buf_len = mutt_strlen (buf);
-    bytes -= buf_len;
-
     newql = get_quote_level (buf);
 
     /* end flowed paragraph (if we're within one) if quoting level
      * changes (should not but can happen, see RFC 3676, sec. 4.5.)
      */
     if (newql != quotelevel)
-      flush_par (s, &width);
+      flush_par (s, &fst);
 
     quotelevel = newql;
-
-    /* XXX - If a line is longer than buf (shouldn't happen), it is split.
-     * This will almost always cause an unintended line break, and 
-     * possibly a change in quoting level. But that's better than not
-     * displaying it at all.
-     */
-    if ((t = strrchr (buf, '\r')) || (t = strrchr (buf, '\n')))
-    {
-      *t = '\0';
-      buf_len = t - buf;
-    }
-
     buf_off = newql;
 
     /* respect sender's space-stuffing by removing one leading space */
@@ -214,11 +238,11 @@ int rfc3676_handler (BODY * a, STATE * s)
 
     /* print fixed-and-standalone, fixed-and-empty and sigsep lines as
      * fixed lines */
-    if ((fixed && (!width || !buf_len)) || sigsep)
+    if ((fixed && (!fst.width || !buf_len)) || sigsep)
     {
       /* if we're within a flowed paragraph, terminate it */
-      flush_par (s, &width);
-      print_fixed_line (buf + buf_off, s, quotelevel, &width);
+      flush_par (s, &fst);
+      print_fixed_line (buf + buf_off, s, quotelevel, &fst);
       continue;
     }
 
@@ -226,11 +250,12 @@ int rfc3676_handler (BODY * a, STATE * s)
     if (delsp && !fixed)
       buf[--buf_len] = '\0';
 
-    print_flowed_line (buf + buf_off, s, quotelevel, &width, fixed);
+    print_flowed_line (buf + buf_off, s, quotelevel, &fst, fixed);
   }
 
-  flush_par (s, &width);
+  flush_par (s, &fst);
 
+  FREE (&buf);
   return (0);
 }
 
@@ -267,10 +292,10 @@ void rfc3676_space_stuff (HEADER* hdr)
   if ((in = safe_fopen (hdr->content->filename, "r")) == NULL)
     return;
 
-  mutt_mktemp (tmpfile);
+  mutt_mktemp (tmpfile, sizeof (tmpfile));
   if ((out = safe_fopen (tmpfile, "w+")) == NULL)
   {
-    fclose (in);
+    safe_fclose (&in);
     return;
   }
 
@@ -294,8 +319,8 @@ void rfc3676_space_stuff (HEADER* hdr)
     }
     fputs (buf, out);
   }
-  fclose (in);
-  fclose (out);
+  safe_fclose (&in);
+  safe_fclose (&out);
   mutt_set_mtime (hdr->content->filename, tmpfile);
   unlink (hdr->content->filename);
   mutt_str_replace (&hdr->content->filename, tmpfile);