]> granicus.if.org Git - neomutt/commitdiff
New format=flowed handler.
authorRocco Rutte <pdmef@gmx.net>
Tue, 6 Mar 2007 17:49:48 +0000 (09:49 -0800)
committerRocco Rutte <pdmef@gmx.net>
Tue, 6 Mar 2007 17:49:48 +0000 (09:49 -0800)
Makefile.am
PATCHES
doc/manual.xml.head
handler.c
muttlib.c
protos.h
rfc3676.c [new file with mode: 0644]
rfc3676.h [new file with mode: 0644]
send.c

index 23912e4d8d1d3ae780c0545cb6ee0810a1748404..d299d028f092fdc8e26dfe46a05013a643bd4b11 100644 (file)
@@ -25,7 +25,7 @@ mutt_SOURCES = $(BUILT_SOURCES) \
        handler.c hash.c hdrline.c headers.c help.c hook.c keymap.c \
        main.c mbox.c menu.c mh.c mx.c pager.c parse.c pattern.c \
        postpone.c query.c recvattach.c recvcmd.c \
-       rfc822.c rfc1524.c rfc2047.c rfc2231.c \
+       rfc822.c rfc1524.c rfc2047.c rfc2231.c rfc3676.c \
        score.c send.c sendlib.c signal.c sort.c \
        status.c system.c thread.c charset.c history.c lib.c \
        muttlib.c editmsg.c mbyte.c \
@@ -72,7 +72,7 @@ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO UPDATING \
        mailbox.h mapping.h md5.h mime.h mutt.h mutt_curses.h mutt_menu.h \
        mutt_regex.h mutt_sasl.h mutt_socket.h mutt_ssl.h mutt_tunnel.h \
        mx.h pager.h pgp.h pop.h protos.h rfc1524.h rfc2047.h \
-       rfc2231.h rfc822.h sha1.h sort.h mime.types VERSION prepare \
+       rfc2231.h rfc822.h rfc3676.h sha1.h sort.h mime.types VERSION prepare \
        _regex.h OPS.MIX README.SECURITY remailer.c remailer.h browser.h \
        mbyte.h lib.h extlib.c pgpewrap.c smime_keys.pl pgplib.h Muttrc.head Muttrc \
        makedoc.c stamp-doc-rc README.SSL smime.h\
diff --git a/PATCHES b/PATCHES
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d9386c44d6828526a6eb73168357a27747b753c6 100644 (file)
--- a/PATCHES
+++ b/PATCHES
@@ -0,0 +1 @@
+patch-1.5.14hg.muttng.ff.6
index e4d0e117f027472e7345ab5f2c59b4a19a55723f..cba32e48361cc62eb705ea736069522191a3c2f2 100644 (file)
@@ -1204,6 +1204,80 @@ have a look at the mixmaster documentation.
 
 </sect2>
 
+<sect2>
+<title>Sending format=flowed messages</title>
+
+<sect3>
+<title>Concept</title>
+
+<para>
+<literal>format=flowed</literal>-style messages (or <literal>f=f</literal>
+for short) are plain ASCII messages that consist of paragraphs which a receiver's
+mail client may reformat to its own needs which mostly means to
+customize line lengths regardless of what the sender sent. Technically this is
+achieved by letting lines of a ``flowable'' paragraph end in spaces.
+</para>
+
+<para>
+While for text-mode clients like mutt it's the best way to assume only a
+standard 80x25 character cell terminal, it may be desired to let the
+receiver decide completely how to view a message.
+</para>
+
+</sect3>
+
+<sect3>
+<title>Mutt support</title>
+
+<para>
+Mutt only supports setting the required <literal>format=flowed</literal>
+MIME parameter on outgoing messages if the <link linkend="text-flowed"
+>&dollar;text&lowbar;flowed</link> variable is set. It does not add the
+trailing spaces nor does it provide any other feature related to
+composing <literal>f=f</literal> messages (like reformatting
+non-<literal>f=f</literal> parts of a reply to <literal>f=f</literal>
+before calling the editor).
+</para>
+
+<para>
+After editing the initial message text and before entering
+the compose menu, mutt properly space-stuffes the message.
+<emphasis>Space-stuffing</emphasis> is required by RfC3676 defining
+<literal>format=flowed</literal> and means to prepend a space to all
+lines starting with a space and lines starting with the word
+<literal>From</literal> (followed by space). All leading spaces are to
+be removed by receiving clients to restore the original message.
+</para>
+
+</sect3>
+
+<sect3>
+<title>Editor considerations</title>
+
+<para>
+As mutt provides no additional features to compose <literal>f=f</literal>
+messages, it's completely up to the user and his editor to produce
+proper messages. Please consider your editor's documentation if you
+intend to send <literal>f=f</literal> messages.
+</para>
+
+<para>
+Please note that when editing messages from the compose menu several
+times before really sending a mail, it's up to the user to ensure that
+the message is properly space-stuffed.
+</para>
+
+<para>
+For example, <emphasis>vim</emphasis> provides the <literal>w</literal>
+flag for its <literal>formatoptions</literal> setting to assist in
+creating <literal>f=f</literal> messages, see <literal>:help
+fo-table</literal> for details.
+</para>
+
+</sect3>
+
+</sect2>
+
 </sect1>
 
 <sect1 id="forwarding-mail">
index 6d7048b5e9c2ac6d675f83a49c3c8f6eec6fd144..8a53e7353b8a7193a253ea906b952a56570f8e63 100644 (file)
--- a/handler.c
+++ b/handler.c
@@ -35,7 +35,7 @@
 #include "copy.h"
 #include "charset.h"
 #include "mutt_crypt.h"
-
+#include "rfc3676.h"
 
 #define BUFI_SIZE 1000
 #define BUFO_SIZE 2000
@@ -892,307 +892,6 @@ int text_enriched_handler (BODY *a, STATE *s)
   return 0;
 }                                                                              
 
-/*
- * An implementation of RFC 2646.
- *
- * NOTE: This still has to be made UTF-8 aware.
- *
- */
-
-#define FLOWED_MAX 77
-
-static void flowed_quote (STATE *s, int level)
-{
-  int i;
-  
-  if (s->prefix)
-  {
-    if (option (OPTTEXTFLOWED))
-      level++;
-    else
-      state_puts (s->prefix, s);
-  }
-  
-  for (i = 0; i < level; i++)
-    state_putc ('>', s);
-}
-
-static int flowed_maybe_quoted (char *cont)
-{
-  return regexec ((regex_t *) QuoteRegexp.rx, cont, 0, NULL, 0) == 0;
-}
-
-static void flowed_stuff (STATE *s, char *cont, int level)
-{
-  if (!option (OPTTEXTFLOWED) && !(s->flags & M_DISPLAY))
-    return;
-
-  if (s->flags & M_DISPLAY)
-  {
-    /* 
-     * Hack: If we are in the beginning of the line and there is 
-     * some text on the line which looks like it's quoted, turn off 
-     * ANSI colors, so quote coloring doesn't affect this line. 
-     */
-    if (*cont && !level && !mutt_strcmp (Pager, "builtin") && flowed_maybe_quoted (cont))
-      state_puts ("\033[0m",s);
-  }
-  else if ((!(s->flags & M_PRINTING)) && 
-          ((*cont == ' ') || (*cont == '>') || (!level && !mutt_strncmp (cont, "From ", 5))))
-    state_putc (' ', s);
-}
-
-static char *flowed_skip_indent (char *prefix, char *cont)
-{
-  for (; *cont == ' ' || *cont == '\t'; cont++)
-    *prefix++ = *cont;
-  *prefix = '\0';
-  return cont;
-}
-
-static int flowed_visual_strlen (char *l, int i)
-{
-  int j;
-  for (j = 0; *l; l++)
-  {
-    if (*l == '\t')
-      j += 8 - ((i + j) % 8);
-    else
-      j++;
-  }
-  
-  return j;
-}
-
-static int text_plain_flowed_handler (BODY *a, STATE *s)
-{
-  char line[LONG_STRING];
-  char indent[LONG_STRING];
-
-  int  quoted = -1;
-  int  last_quoted;
-  int  full = 1;
-  int  last_full;
-  int  col = 0, tmpcol;
-
-  int  i_add = 0;
-  int  add = 0;
-  int  soft = 0;
-  int  l, rl;
-  
-  int  flowed_max;
-  int  bytes = a->length;
-  int  actually_wrap = 0;
-  
-  char *cont = NULL;
-  char *tail = NULL;
-  char *lc = NULL;
-  char *t;
-  
-  *indent = '\0';
-  
-  if (s->prefix)
-    add = 1;
-  
-  if ((flowed_max = FLOWED_MAX) > mutt_term_width (0) - 3)
-    flowed_max = mutt_term_width (0) - 3;
-  if (flowed_max > mutt_term_width (Wrap))
-    flowed_max = mutt_term_width (Wrap);
-    
-
-  while (bytes > 0 && fgets (line, sizeof (line), s->fpin))
-  {
-    bytes        -= strlen (line);
-    tail          = NULL;
-
-    last_full     = full;
-    
-    /* 
-     * If the last line wasn't fully read, this is the
-     * tail of some line. 
-     */
-    actually_wrap = !last_full; 
-    
-    if ((t = strrchr (line, '\r')) || (t = strrchr (line, '\n')))
-    {
-      *t   = '\0';
-      full = 1;
-    }
-    else if ((t = strrchr (line, ' ')) || (t = strrchr (line, '\t')))
-    {
-      /* 
-       * Bad: We have a line of more than LONG_STRING characters.
-       * (Which SHOULD NOT happen, since lines SHOULD be <= 79
-       * characters long.)
-       * 
-       * Try to simulate a soft line break at a word boundary.
-       * Handle the rest of the line next time.
-       * 
-       * Give up when we have a single word which is longer than
-       * LONG_STRING characters.  It will just be split into parts,
-       * with a hard line break in between. 
-       */
-
-      full = 0;
-      l    = strlen (t + 1);
-      t[0] = ' ';
-      t[1] = '\0';
-
-      if (l)
-      {
-       fseek (s->fpin, -l, SEEK_CUR);
-       bytes += l;
-      }
-    }
-    else
-      full = 0;
-
-    last_quoted = quoted;
-
-    if (last_full)
-    {
-      /* 
-       * We are in the beginning of a new line. Determine quote level
-       * and indentation prefix 
-       */
-      for (quoted = 0; line[quoted] == '>'; quoted++)
-       ;
-      
-      cont = line + quoted;
-      
-      /* undo space stuffing */
-      if (*cont == ' ')
-       cont++;
-
-      /* If there is an indentation, record it. */
-      cont  = flowed_skip_indent (indent, cont);
-      i_add = flowed_visual_strlen (indent, quoted + add);
-    }
-    else
-    {
-      /* 
-       * This is just the tail of some over-long line. Keep
-       * indentation and quote levels.  Don't unstuff.
-       */
-      cont = line;
-    }
-
-    /* If we have a change in quoting depth, wrap. */
-
-    if (col && last_quoted != quoted && last_quoted >= 0)
-    {
-      state_putc ('\n', s);
-      col = 0;
-    }
-    
-    do 
-    {
-      if (tail)
-       cont = tail;
-
-      SKIPWS (cont);
-      
-      tail = NULL;
-      soft = 0;
-      
-      /* try to find a point for word wrapping */
-
-    retry_wrap:
-      l  = flowed_visual_strlen (cont, quoted + i_add + add + col);
-      rl = mutt_strlen (cont);
-      if (quoted + i_add + add + col + l > flowed_max)
-      {
-       actually_wrap = 1;
-
-       for (tmpcol = quoted + i_add + add + col, t = cont;
-            *t && tmpcol < flowed_max; t++)
-       {
-         if (*t == ' ' || *t == '\t')
-           tail = t;
-         if (*t == '\t')
-           tmpcol = (tmpcol & ~7) + 8;
-         else
-           tmpcol++;
-       }
-       
-       if (tail)
-       {
-         *tail++ = '\0';
-         soft = 2;
-       }
-      }
-
-      /* We seem to be desperate.  Get me a new line, and retry. */
-      if (!tail && (quoted + add + col + i_add + l > flowed_max) && col)
-      {
-       state_putc ('\n', s);
-       col = 0;
-       goto retry_wrap;
-      }
-
-      /* Detect soft line breaks. */
-      if (!soft && ascii_strcmp (cont, "-- "))
-      {
-       lc = strrchr (cont, ' ');
-       if (lc && lc[1] == '\0')
-         soft = 1;
-      }
-
-      /* 
-       * If we are in the beginning of an output line, do quoting
-       * and stuffing. 
-       * 
-       * We have to temporarily assemble the line since display
-       * stuffing (i.e., turning off quote coloring) may depend on
-       * the line's actual content.  You never know what people put
-       * into their regular expressions. 
-       */
-      if (!col)
-      {
-       char tmp[LONG_STRING];
-       snprintf (tmp, sizeof (tmp), "%s%s", indent, cont);
-
-       flowed_quote (s, quoted);
-       flowed_stuff (s, tmp, quoted + add);
-
-       state_puts (indent, s);
-      }
-
-      /* output the text */
-      state_puts (cont, s);
-      col += flowed_visual_strlen (cont, quoted + i_add + add + col);
-      
-      /* possibly indicate a soft line break */
-      if (soft == 2)
-      {
-       state_putc (' ', s);
-       col++;
-      }
-      
-      /* 
-       * Wrap if this display line corresponds to a 
-       * text line. Don't wrap if we changed the line.
-       */
-      if (!soft || (!actually_wrap && full))
-      {
-       state_putc ('\n', s);
-       col = 0;
-      }
-    }
-    while (tail);
-  }
-
-  if (col)
-    state_putc ('\n', s);
-
-  return 0;
-}
-
-
-
-
-
-
 #define TXTHTML     1
 #define TXTPLAIN    2
 #define TXTENRICHED 3
@@ -1811,7 +1510,7 @@ int mutt_body_handler (BODY *b, STATE *s)
       if ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b))
        handler = crypt_pgp_application_pgp_handler;
       else if (ascii_strcasecmp ("flowed", mutt_get_parameter ("format", b->parameter)) == 0)
-       handler = text_plain_flowed_handler;
+       handler = rfc3676_handler;
       else
        plaintext = 1;
     }
index babe55adbf1f1a4873dbd10a5af703fec8b33904..8b061116ddd3311e8ad3e389585678df33341064 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -1519,6 +1519,20 @@ time_t mutt_decrease_mtime (const char *f, struct stat *st)
   return mtime;
 }
 
+/* sets mtime of 'to' to mtime of 'from' */
+void mutt_set_mtime (const char* from, const char* to)
+{
+  struct utimbuf utim;
+  struct stat st;
+
+  if (stat (from, &st) != -1)
+  {
+    utim.actime = st.st_mtime;
+    utim.modtime = st.st_mtime;
+    utime (to, &utim);
+  }
+}
+
 const char *mutt_make_version (void)
 {
   static char vstring[STRING];
index b74041ba1d3460bb727f5b41c3c422518ed477b3..20d313dd68d459c94c97e938091848fa11481ba2 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -109,6 +109,7 @@ char *mutt_read_rfc822_line (FILE *, char *, size_t *);
 ENVELOPE *mutt_read_rfc822_header (FILE *, HEADER *, short, short);
 HEADER *mutt_dup_header (HEADER *);
 
+void mutt_set_mtime (const char *from, const char *to);
 time_t mutt_decrease_mtime (const char *, struct stat *);
 time_t mutt_local_tz (time_t);
 time_t mutt_mktime (struct tm *, int);
diff --git a/rfc3676.c b/rfc3676.c
new file mode 100644 (file)
index 0000000..6a6a7da
--- /dev/null
+++ b/rfc3676.c
@@ -0,0 +1,324 @@
+/*
+ * 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>
+ * 
+ *     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
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */ 
+
+/* This file was originally part of mutt-ng */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include "mutt.h"
+#include "mutt_curses.h"
+#include "ascii.h"
+#include "lib.h"
+
+#define FLOWED_MAX 77
+
+static int get_quote_level (const char *line)
+{
+  int quoted = 0;
+  char *p = (char *) line;
+
+  while (p && *p == '>')
+  {
+    quoted++;
+    p++;
+  }
+
+  return quoted;
+}
+
+static void print_empty_line (int ql, STATE *s)
+{
+  int i;
+
+  if (!(s->flags & M_REPLYING))
+  {
+    if (s->prefix)
+      state_puts (s->prefix, s);
+    for (i = 0; i < ql; i++)
+      state_putc ('>', s);
+    if (!(s->flags & M_REPLYING))
+      state_putc (' ', s);
+  }
+  state_putc ('\n', s);
+}
+
+static void print_flowed_line (const char *line, STATE *s, int ql)
+{
+  int width;
+  char *pos, *oldpos;
+  int len = mutt_strlen (line);
+  int i;
+
+  width = (Wrap ? mutt_term_width (Wrap) : FLOWED_MAX) - ql - 1;
+
+  if (!(s->flags & M_REPLYING))
+    --width;
+  if (width < 0)
+    width = COLS;
+
+  if (len == 0)
+  {
+    print_empty_line (ql, s);
+    return;
+  }
+
+  pos = (char *) line + width;
+  oldpos = (char *) line;
+
+  for (; oldpos < line + len; pos += width)
+  {
+    /* only search for a new position when we're not over the end */
+    if (pos < line + len)
+    {
+      if (*pos == ' ')
+      {
+        dprint (4, (debugfile, "f=f: found space directly at width\n"));
+        *pos = '\0';
+        ++pos;
+      }
+      else
+      {
+        char *save = pos;
+        dprint (4, (debugfile, "f=f: need to search for space\n"));
+
+        while (pos >= oldpos && *pos != ' ')
+          --pos;
+
+        if (pos < oldpos)
+        {
+          dprint (4, (debugfile, "f=f: no space found while searching "
+                           "to left; going right\n"));
+          pos = save;
+          while (pos < line + len && *pos && *pos != ' ')
+            ++pos;
+          dprint (4, (debugfile, "f=f: found space at pos %d\n", pos-line));
+        }
+        else
+        {
+          dprint (4, (debugfile, "f=f: found space while searching to left\n"));
+        }
+
+        *pos = '\0';
+        ++pos;
+      }
+    }
+    else
+    {
+      dprint (4, (debugfile, "f=f: line completely fits on screen\n"));
+    }
+
+    if (s->prefix)
+      state_puts (s->prefix, s);
+
+    for (i = 0; i < ql; ++i)
+      state_putc ('>', s);
+    if (!(s->flags & M_REPLYING) && (ql > 0 || s->prefix))
+      state_putc (' ', s);
+    state_puts (oldpos, s);
+
+    if (pos < line + len)
+      state_putc (' ', s);
+    state_putc ('\n', s);
+    oldpos = pos;
+  }
+}
+
+int rfc3676_handler (BODY * a, STATE * s)
+{
+  int bytes = a->length;
+  char buf[LONG_STRING];
+  char *curline = safe_malloc (STRING);
+  char *t = NULL;
+  unsigned int curline_len = 1, quotelevel = 0, newql = 0, sigsep = 0;
+  int buf_off, buf_len;
+  int delsp = 0, fixed = 0;
+
+  *curline = '\0';
+
+  /* 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;
+  }
+
+  dprint (2, (debugfile, "f=f: DelSp: %s\n", delsp ? "yes" : "no"));
+
+  while (bytes > 0 && fgets (buf, sizeof (buf), s->fpin))
+  {
+
+    buf_len = mutt_strlen (buf);
+    bytes -= buf_len;
+
+    newql = get_quote_level (buf);
+
+    /* a change of quoting level in a paragraph - shouldn't happen, 
+     * but has to be handled - see RFC 3676, sec. 4.5.
+     */
+    if (newql != quotelevel && curline && *curline)
+    {
+      print_flowed_line (curline, s, quotelevel);
+      *curline = '\0';
+      curline_len = 1;
+    }
+    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 */
+    if (buf[buf_off] == ' ')
+      buf_off++;
+
+    /* test for signature separator */
+    sigsep = ascii_strcmp (buf + buf_off, "-- ") == 0;
+
+    /* a fixed line either has no trailing space or is the
+     * signature separator */
+    fixed = buf_len == 0 || buf[buf_len - 1] != ' ' || sigsep;
+
+    /* for DelSp=yes, we need to strip one SP prior to CRLF;
+     * in case of the signature separator, leave the space */
+    if (delsp && !sigsep && buf_len >= 1 && buf[buf_len-1] == ' ')
+      buf[--buf_len] = '\0';
+
+    /* we're here when last space removed because of DelSp was
+     * the last space and there isn't more -> done */
+    if ((buf_len - buf_off) < 0)
+    {
+      print_flowed_line (curline, s, quotelevel);
+      *curline = '\0';
+      curline_len = 1;
+      continue;
+    }
+
+    /* signature separator also flushes the previous paragraph */
+    if (sigsep && curline && *curline)
+    {
+      print_flowed_line (curline, s, quotelevel);
+      *curline = '\0';
+      curline_len = 1;
+    }
+
+    /* append remaining contents without quotes, space-stuffed
+     * spaces and with 1 trailing space (0 or 1 for DelSp=yes) */
+    safe_realloc (&curline, curline_len + buf_len - buf_off);
+    strcpy (curline + curline_len - 1, buf + buf_off);         /* __STRCPY_CHECKED__ */
+    curline_len += buf_len - buf_off;
+
+    /* if this was a fixed line, the paragraph is finished */
+    if (fixed)
+    {
+      print_flowed_line (curline, s, quotelevel);
+      *curline = '\0';
+      curline_len = 1;
+    }
+
+  }
+  FREE(&curline);
+  return (0);
+}
+
+/*
+ * This routine does RfC3676 space stuffing since it's a MUST.
+ * Space stuffing means that we have to add leading spaces to
+ * certain lines:
+ *   - lines starting with a space
+ *   - lines starting with 'From '
+ * This routine is only called once right after editing the
+ * initial message so it's up to the user to take care of stuffing
+ * when editing the message several times before actually sending it
+ *
+ * This is more or less a hack as it replaces the message's content with
+ * a freshly created copy in a tempfile and modifies the file's mtime
+ * so we don't trigger code paths watching for mtime changes
+ */
+void rfc3676_space_stuff (HEADER* hdr)
+{
+#if DEBUG
+  int lc = 0;
+  size_t len = 0;
+  unsigned char c = '\0';
+#endif
+  FILE *in = NULL, *out = NULL;
+  char buf[LONG_STRING];
+  char tmpfile[_POSIX_PATH_MAX];
+
+  if (!hdr || !hdr->content || !hdr->content->filename)
+    return;
+
+  dprint (2, (debugfile, "f=f: postprocess %s\n", hdr->content->filename));
+
+  if ((in = safe_fopen (hdr->content->filename, "r")) == NULL)
+    return;
+
+  mutt_mktemp (tmpfile);
+  if ((out = safe_fopen (tmpfile, "w+")) == NULL)
+  {
+    fclose (in);
+    return;
+  }
+
+  while (fgets (buf, sizeof (buf), in))
+  {
+    if (ascii_strncmp ("From ", buf, 5) == 0 || buf[0] == ' ') {
+      fputc (' ', out);
+#if DEBUG
+      lc++;
+      len = mutt_strlen (buf);
+      if (len > 0)
+      {
+        c = buf[len-1];
+        buf[len-1] = '\0';
+      }
+      dprint (4, (debugfile, "f=f: line %d needs space-stuffing: '%s'\n",
+                  lc, buf));
+      if (len > 0)
+        buf[len-1] = c;
+#endif
+    }
+    fputs (buf, out);
+  }
+  fclose (in);
+  fclose (out);
+  mutt_set_mtime (hdr->content->filename, tmpfile);
+  unlink (hdr->content->filename);
+  mutt_str_replace (&hdr->content->filename, tmpfile);
+}
diff --git a/rfc3676.h b/rfc3676.h
new file mode 100644 (file)
index 0000000..0cd50e4
--- /dev/null
+++ b/rfc3676.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005 Andreas Krennmair <ak@synflood.at>
+ * Copyright (C) 2005 Peter J. Holzer <hjp@hjp.net>
+ * Copyright (C) 2005 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
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */ 
+
+/* This file was originally part of mutt-ng */
+
+#ifndef _MUTT_RFC3676_H
+#define _MUTT_RFC3676_H
+
+#include "mutt.h"
+
+/* body handler implementing RfC 3676 for format=flowed */
+int rfc3676_handler (BODY *a, STATE *s);
+
+/* this does the space-stuffing for RfC3676 style messages */
+void rfc3676_space_stuff (HEADER *hdr);
+
+#endif /* !_MUTT_RFC3676_H */
diff --git a/send.c b/send.c
index 0b4b8eb95980adfecd876aafb7b2ac562bb1efe7..8690a86fdcbca2dff64f14a67b20dc1f5fb0f560 100644 (file)
--- a/send.c
+++ b/send.c
@@ -31,6 +31,7 @@
 #include "mutt_crypt.h"
 #include "mutt_idna.h"
 #include "url.h"
+#include "rfc3676.h"
 
 #include <ctype.h>
 #include <stdlib.h>
@@ -1438,6 +1439,9 @@ ci_send_message (int flags,               /* send mode */
          mutt_perror (msg->content->filename);
       }
       
+      if (option (OPTTEXTFLOWED))
+       rfc3676_space_stuff (msg);
+
       mutt_message_hook (NULL, msg, M_SEND2HOOK);
     }