]> granicus.if.org Git - mutt/commitdiff
Re-enable and cleanup format-flowed space stuffing.
authorKevin McCarthy <kevin@8t8.us>
Sat, 31 Aug 2019 20:37:16 +0000 (13:37 -0700)
committerKevin McCarthy <kevin@8t8.us>
Sat, 31 Aug 2019 20:59:10 +0000 (13:59 -0700)
Commit 04cb5bde tried to fix re-stuffing a postponed message more than
once, but unfortunately broke the normal case of composing a new
message.  So actually, space-stuffing has been turned off the past 7
years.

Move format=flowed parameter setting below the standard message
pre-processing block.  It shouldn't be performed for draft-files even
with $resume_draft_files set.  Moving out of the block makes that
clearer.

Create mutt_rfc3676_space_(un)stuff() functions, which check the
content type and stuff/unstuff apprpropriately.  Note that the
stuff/unstuff does not depend on $text_flowed, which is only in charge
of setting the format=flowed parameter.  This parameter can also come
from resumed/resent/draft messages and should still be respected.

Add unstuffing to mutt_prepare_template().  This is called by
postponed, resent, and draft files.  This will prevent double-stuffing
in those cases.

Unstuff/restuff around editing the message in the compose menu, to
keep everything transparent to the user.  I originally put the
stuffing *after* the compose menu, but previewing the messages in the
compose menu did not work properly in that case.  It's cleaner this
way too.

Change the stuff/unstuff functions to preserve the original
hdr->content->filename.  The "hack" previously used would interact
poorly with editable body files (mutt -i -E).  Fortunately space
stuffing was pretty much disabled except in unusual cases before.

compose.c
doc/manual.xml.head
init.h
postpone.c
rfc3676.c
rfc3676.h
send.c

index f4c7519d28ebfe4ac128d9031f02b34cf0497342..48765352999013cd506dd4edd273f00ab1115519 100644 (file)
--- a/compose.c
+++ b/compose.c
@@ -34,6 +34,7 @@
 #include "mailbox.h"
 #include "sort.h"
 #include "charset.h"
+#include "rfc3676.h"
 
 #ifdef MIXMASTER
 #include "remailer.h"
@@ -949,7 +950,9 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
       case OP_COMPOSE_EDIT_MESSAGE:
        if (Editor && (mutt_strcmp ("builtin", Editor) != 0) && !option (OPTEDITHDRS))
        {
+          mutt_rfc3676_space_unstuff (msg);
          mutt_edit_file (Editor, msg->content->filename);
+          mutt_rfc3676_space_stuff (msg);
          mutt_update_encoding (msg->content);
          menu->redraw = REDRAW_FULL;
          mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
@@ -957,6 +960,8 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
        }
        /* fall through */
       case OP_COMPOSE_EDIT_HEADERS:
+        mutt_rfc3676_space_unstuff (msg);
+
        if (mutt_strcmp ("builtin", Editor) != 0 &&
            (op == OP_COMPOSE_EDIT_HEADERS ||
              (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS))))
@@ -980,6 +985,8 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
             code below to regenerate the index array */
          mutt_builtin_editor (msg->content->filename, msg, cur);
        }
+
+        mutt_rfc3676_space_stuff (msg);
        mutt_update_encoding (msg->content);
 
        /* attachments may have been added */
index d1f7a0575385028f628b142c7e55ec663a596612..4da62a2594ee7ef397f7f6ab820d506d0b0a0487 100644 (file)
@@ -1660,8 +1660,7 @@ it does not add the trailing spaces.
 </para>
 
 <para>
-After editing the initial message text and before entering the compose
-menu, Mutt properly space-stuffs the message.
+After editing, Mutt properly space-stuffs the message.
 <emphasis>Space-stuffing</emphasis> is required by RfC3676 defining
 <literal>format=flowed</literal> and means to prepend a space to:
 </para>
@@ -1703,12 +1702,6 @@ 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
diff --git a/init.h b/init.h
index 52f75938ebd6fe82d1d53812ac060bdc7ed6b11e..2f450a43cee94546d881c5be54a6d38e17ce8368 100644 (file)
--- a/init.h
+++ b/init.h
@@ -4024,6 +4024,10 @@ struct option_t MuttVars[] = {
   ** just looks like ordinary text.  To actually make use of this format's
   ** features, you'll need support in your editor.
   ** .pp
+  ** The option only controls newly composed messages.  Postponed messages,
+  ** resent messages, and draft messages (via -H on the command line) will
+  ** use the content-type of the source message.
+  ** .pp
   ** Note that $$indent_string is ignored when this option is \fIset\fP.
   */
   { "thorough_search", DT_BOOL, R_NONE, {.l=OPTTHOROUGHSRC}, {.l=1} },
index 0b8f658df18618c7af1e718fa5340ba2034140af..0ce25d30b8ab1e0d7a704387b02a6e9d3546afd4 100644 (file)
@@ -31,6 +31,7 @@
 #include "imap.h"
 #endif
 #include "mutt_crypt.h"
+#include "rfc3676.h"
 
 #include <ctype.h>
 #include <unistd.h>
@@ -806,6 +807,8 @@ int mutt_prepare_template (FILE *fp, CONTEXT *ctx, HEADER *newhdr, HEADER *hdr,
       newhdr->security &= ~APPLICATION_SMIME;
   }
 
+  mutt_rfc3676_space_unstuff (newhdr);
+
   rv = 0;
 
 bail:
index faa57b4be2277c54f79be8c1d859c4a22afcd9e5..ab3665060af824decce7a58e7b1070b8c52ac4e3 100644 (file)
--- a/rfc3676.c
+++ b/rfc3676.c
@@ -37,6 +37,7 @@
 #include "mutt_curses.h"
 #include "ascii.h"
 #include "lib.h"
+#include "mime.h"
 
 #define FLOWED_MAX 72
 
@@ -327,64 +328,145 @@ int rfc3676_handler (BODY * a, STATE * s)
  * 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
+ * Care is taken to preserve the hdr->content->filename, as
+ * mutt -i -E can directly edit a passed in filename.
  */
-void rfc3676_space_stuff (HEADER* hdr)
+static 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];
+  char *buf = NULL;
+  size_t blen = 0;
+  BUFFER *tmpfile = NULL;
 
-  if (!hdr || !hdr->content || !hdr->content->filename)
-    return;
-
-  dprint (2, (debugfile, "f=f: postprocess %s\n", hdr->content->filename));
+  tmpfile = mutt_buffer_pool_get ();
 
   if ((in = safe_fopen (hdr->content->filename, "r")) == NULL)
-    return;
+    goto bail;
 
-  mutt_mktemp (tmpfile, sizeof (tmpfile));
-  if ((out = safe_fopen (tmpfile, "w+")) == NULL)
-  {
-    safe_fclose (&in);
-    return;
-  }
+  mutt_buffer_mktemp (tmpfile);
+  if ((out = safe_fopen (mutt_b2s (tmpfile), "w+")) == NULL)
+    goto bail;
 
-  while (fgets (buf, sizeof (buf), in))
+  while ((buf = mutt_read_line (buf, &blen, in, NULL, 0)) != NULL)
   {
     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);
+    fputc ('\n', out);
+  }
+  FREE (&buf);
+  safe_fclose (&in);
+  safe_fclose (&out);
+  mutt_set_mtime (hdr->content->filename, mutt_b2s (tmpfile));
+
+  if ((in = safe_fopen (mutt_b2s (tmpfile), "r")) == NULL)
+    goto bail;
+
+  if ((truncate (hdr->content->filename, 0) == -1) ||
+      ((out = safe_fopen (hdr->content->filename, "a")) == NULL))
+  {
+    goto bail;
+  }
+
+  mutt_copy_stream (in, out);
+  safe_fclose (&in);
+  safe_fclose (&out);
+  mutt_set_mtime (mutt_b2s (tmpfile), hdr->content->filename);
+  unlink (mutt_b2s (tmpfile));
+  mutt_buffer_pool_release (&tmpfile);
+  return;
+
+bail:
+  safe_fclose (&in);
+  safe_fclose (&out);
+  mutt_buffer_pool_release (&tmpfile);
+}
+
+static void rfc3676_space_unstuff (HEADER* hdr)
+{
+  FILE *in = NULL, *out = NULL;
+  char *buf = NULL;
+  size_t blen = 0;
+  BUFFER *tmpfile = NULL;
+
+  tmpfile = mutt_buffer_pool_get ();
+
+  if ((in = safe_fopen (hdr->content->filename, "r")) == NULL)
+    goto bail;
+
+  mutt_buffer_mktemp (tmpfile);
+  if ((out = safe_fopen (mutt_b2s (tmpfile), "w+")) == NULL)
+    goto bail;
+
+  while ((buf = mutt_read_line (buf, &blen, in, NULL, 0)) != NULL)
+  {
+    if (buf[0] == ' ')
+      fputs (buf + 1, out);
+    else
+      fputs (buf, out);
+    fputc ('\n', out);
   }
+  FREE (&buf);
   safe_fclose (&in);
   safe_fclose (&out);
-  mutt_set_mtime (hdr->content->filename, tmpfile);
-  unlink (hdr->content->filename);
-  mutt_str_replace (&hdr->content->filename, tmpfile);
+  mutt_set_mtime (hdr->content->filename, mutt_b2s (tmpfile));
+
+  if ((in = safe_fopen (mutt_b2s (tmpfile), "r")) == NULL)
+    goto bail;
+
+  if ((truncate (hdr->content->filename, 0) == -1) ||
+      ((out = safe_fopen (hdr->content->filename, "a")) == NULL))
+  {
+    goto bail;
+  }
+
+  mutt_copy_stream (in, out);
+  safe_fclose (&in);
+  safe_fclose (&out);
+  mutt_set_mtime (mutt_b2s (tmpfile), hdr->content->filename);
+  unlink (mutt_b2s (tmpfile));
+  mutt_buffer_pool_release (&tmpfile);
+  return;
+
+bail:
+  safe_fclose (&in);
+  safe_fclose (&out);
+  mutt_buffer_pool_release (&tmpfile);
+}
+
+/* Note: we don't check the option OPTTEXTFLOWED because we want to
+ * stuff based the actual content type.  The option only decides
+ * whether to *set* format=flowed on new messages.
+ */
+void mutt_rfc3676_space_stuff (HEADER *hdr)
+{
+  const char *format;
+
+  if (!hdr || !hdr->content || !hdr->content->filename)
+    return;
+
+  if (hdr->content->type == TYPETEXT &&
+      !ascii_strcasecmp ("plain", hdr->content->subtype))
+  {
+    format = mutt_get_parameter ("format", hdr->content->parameter);
+    if (!ascii_strcasecmp ("flowed", format))
+      rfc3676_space_stuff (hdr);
+  }
+}
+
+void mutt_rfc3676_space_unstuff (HEADER *hdr)
+{
+  const char *format;
+
+  if (!hdr || !hdr->content || !hdr->content->filename)
+    return;
+
+  if (hdr->content->type == TYPETEXT &&
+      !ascii_strcasecmp ("plain", hdr->content->subtype))
+  {
+    format = mutt_get_parameter ("format", hdr->content->parameter);
+    if (!ascii_strcasecmp ("flowed", format))
+      rfc3676_space_unstuff (hdr);
+  }
 }
index 2e6ed7ca3995a832c4fd89715640bb59fe11898d..d239c8b17276643690a889f883b60c52b3105983 100644 (file)
--- a/rfc3676.h
+++ b/rfc3676.h
@@ -29,7 +29,7 @@
 /* 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);
+void mutt_rfc3676_space_stuff (HEADER *hdr);
+void mutt_rfc3676_space_unstuff (HEADER *hdr);
 
 #endif /* !_MUTT_RFC3676_H */
diff --git a/send.c b/send.c
index baab77588f803251a06a8b4d841e9ede445366eb..08c89afd875dad5da0b50979b51a22991462f4d6 100644 (file)
--- a/send.c
+++ b/send.c
@@ -1758,12 +1758,6 @@ ci_send_message (int flags,              /* send mode */
      */
     msg->replied = 0;
 
-    if (! (flags & SENDKEY))
-    {
-      if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT && !ascii_strcasecmp (msg->content->subtype, "plain"))
-        mutt_set_parameter ("format", "flowed", &msg->content->parameter);
-    }
-
     /* $use_from and/or $from might have changed in a send-hook */
     if (killfrom)
     {
@@ -1793,6 +1787,19 @@ ci_send_message (int flags,              /* send mode */
       append_signature (tempfp);
   }
 
+  /* Only set format=flowed for new messages.  Postponed/resent/draftfiles
+   * should respect the original email.
+   *
+   * This is set here so that send-hook can be used to turn the option on.
+   */
+  if (!(flags & (SENDKEY | SENDPOSTPONED | SENDRESEND | SENDDRAFTFILE)))
+  {
+    if (option (OPTTEXTFLOWED) &&
+        msg->content->type == TYPETEXT &&
+        !ascii_strcasecmp (msg->content->subtype, "plain"))
+      mutt_set_parameter ("format", "flowed", &msg->content->parameter);
+  }
+
   /*
    * This hook is even called for postponed messages, and can, e.g., be
    * used for setting the editor, the sendmail path, or the
@@ -1862,18 +1869,6 @@ ci_send_message (int flags,              /* send mode */
          mutt_perror (msg->content->filename);
       }
 
-      /* If using format=flowed, perform space stuffing.  Avoid stuffing when
-       * recalling a postponed message where the stuffing was already
-       * performed.  If it has already been performed, the format=flowed
-       * parameter will be present.
-       */
-      if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT && !ascii_strcasecmp("plain", msg->content->subtype))
-      {
-       char *p = mutt_get_parameter("format", msg->content->parameter);
-       if (ascii_strcasecmp("flowed", NONULL(p)))
-         rfc3676_space_stuff (msg);
-      }
-
       mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
     }
 
@@ -2029,6 +2024,8 @@ ci_send_message (int flags,               /* send mode */
   }
 
 
+  mutt_rfc3676_space_stuff (msg);
+
   mutt_update_encoding (msg->content);
 
   if (! (flags & (SENDMAILX | SENDBATCH)))