On Mon, Apr 06, 2026 at 02:38:34PM +0800, Kevin J. McCarthy wrote:
> Many thanks to Matthijs Kooijman for the bug report, complete with a
> detailed explanation, pointers to the code causing the problem, and an
> anaylsis of the RFC in question.  He all but wrote the simple patch
> himself.
> 
> I've added comments around the change, to hopefully make it clear why
> the change was made to long standing behavior in mutt.
> 
> I've also separated out the one place in the code where it wasn't
> immediately obvious a header was being tied off with an extra newline,
> inside mutt_write_fcc().
> ---
>  sendlib.c | 25 +++++++++++++++++++++++--
>  1 file changed, 23 insertions(+), 2 deletions(-)
> 
> diff --git a/sendlib.c b/sendlib.c
> index 3c8b0c7c..150bc72d 100644
> --- a/sendlib.c
> +++ b/sendlib.c
> @@ -310,6 +310,8 @@ static void encode_8bit(FGETCONV *fc, FILE *fout, int 
> istext)
>  }
>  
>  
> +/* The caller is responsible for terminating the headers with an
> + * additional '\n' before writing the body. */
>  int mutt_write_mime_header(BODY *a, FILE *f)
>  {
>    PARAMETER *p;
> @@ -474,12 +476,30 @@ int mutt_write_mime_body(BODY *a, FILE *f)
>  
>      for (t = a->parts; t ; t = t->next)
>      {
> -      fprintf(f, "\n--%s\n", boundary);
> +      fprintf(f, "--%s\n", boundary);
>        if (mutt_write_mime_header(t, f) == -1)
>          return -1;
>        fputc('\n', f);
>        if (mutt_write_mime_body(t, f) == -1)
>          return -1;
> +
> +      /* This '\n' is part of the following delimiter.  The very
> +       * first dash-boundary printed in this loop already has a '\n'
> +       * printed prior to calling this function (to separate the
> +       * headers from the body).
> +       *
> +       * Reading RFC 2046, it's possible to conclude the '\n'
> +       * separator between headers and body is different from the '\n'
> +       * part of the first delimiter.  This is probably why mutt
> +       * previously included a '\n' in front of every dash-boundary in
> +       * this loop.
> +       *
> +       * However common practice and the examples shown in the RFC do
> +       * not have a double '\n' separator between the message headers
> +       * and a multipart body.
> +       */
> +      if (t->next)
> +        fputc('\n', f);
>      }
>      fprintf(f, "\n--%s--\n", boundary);
>      return (ferror(f) ? -1 : 0);
> @@ -3305,7 +3325,8 @@ int mutt_write_fcc(const char *path, SEND_CONTEXT 
> *sctx, const char *msgid, int
>      while (fgets(sasha, sizeof(sasha), tempfp) != NULL)
>        lines++;
>      fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) 
> ftello(tempfp));
> -    fprintf(msg->fp, "Lines: %d\n\n", lines);
> +    fprintf(msg->fp, "Lines: %d\n", lines);
> +    fputc('\n', msg->fp); /* finish off the header */
>  
>      /* copy the body and clean up */
>      rewind(tempfp);
> -- 
> 2.53.0

Given only the patch and the contained comments the changes make sense
to me.

Don't know if it's right, but at least comments seem to match the
code. ;-)

Reply via email to