Commit 4959e8d4 authored by Kevin J. McCarthy's avatar Kevin J. McCarthy

Re-enable and cleanup format-flowed space stuffing.

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.
parent af47e694
Pipeline #79579198 passed with stages
in 3 minutes and 4 seconds
......@@ -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 */
......
......@@ -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
......
......@@ -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} },
......
......@@ -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:
......
......@@ -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);
}
}
......@@ -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 */
......@@ -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)))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment