]> granicus.if.org Git - neomutt/blob - sendlib.c
Rename mutt_addrlist_free_all into mutt_addrlist_clear, remove freeing functions
[neomutt] / sendlib.c
1 /**
2  * @file
3  * Miscellaneous functions for sending an email
4  *
5  * @authors
6  * Copyright (C) 1996-2002,2009-2012 Michael R. Elkins <me@mutt.org>
7  * Copyright (C) 2019 Pietro Cerutti <gahr@gahr.ch>
8  *
9  * @copyright
10  * This program is free software: you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free Software
12  * Foundation, either version 2 of the License, or (at your option) any later
13  * version.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License along with
21  * this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 /**
25  * @page sendlib Miscellaneous functions for sending an email
26  *
27  * Miscellaneous functions for sending an email
28  */
29
30 #include "config.h"
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <iconv.h>
34 #include <inttypes.h>
35 #include <limits.h>
36 #include <signal.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/stat.h>
42 #include <sys/wait.h>
43 #include <time.h>
44 #include <unistd.h>
45 #include "mutt/mutt.h"
46 #include "address/lib.h"
47 #include "config/lib.h"
48 #include "email/lib.h"
49 #include "mutt.h"
50 #include "sendlib.h"
51 #include "context.h"
52 #include "copy.h"
53 #include "curs_lib.h"
54 #include "filter.h"
55 #include "globals.h"
56 #include "handler.h"
57 #include "hook.h"
58 #include "mailbox.h"
59 #include "mutt_parse.h"
60 #include "mutt_window.h"
61 #include "muttlib.h"
62 #include "mx.h"
63 #include "ncrypt/ncrypt.h"
64 #include "options.h"
65 #include "send.h"
66 #include "smtp.h"
67 #include "state.h"
68 #ifdef USE_NNTP
69 #include "nntp/nntp.h"
70 #endif
71 #ifdef HAVE_SYSEXITS_H
72 #include <sysexits.h>
73 #else
74 #define EX_OK 0
75 #endif
76
77 /* These Config Variables are only used in sendlib.c */
78 bool C_Allow8bit; ///< Config: Allow 8-bit messages, don't use quoted-printable or base64
79 char *C_AttachCharset; ///< Config: When attaching files, use one of these character sets
80 bool C_BounceDelivered; ///< Config: Add 'Delivered-To' to bounced messages
81 bool C_EncodeFrom; ///< Config: Encode 'From ' as 'quote-printable' at the beginning of lines
82 bool C_ForwardDecrypt; ///< Config: Decrypt the message when forwarding it
83 bool C_HiddenHost; ///< Config: Don't use the hostname, just the domain, when generating the message id
84 char *C_Inews;     ///< Config: (nntp) External command to post news articles
85 bool C_MimeForwardDecode; ///< Config: Decode the forwarded message before attaching it
86 bool C_MimeSubject; ///< Config: (nntp) Encode the article subject in base64
87 char *C_MimeTypeQueryCommand; ///< Config: External command to determine the MIME type of an attachment
88 bool C_MimeTypeQueryFirst; ///< Config: Run the #C_MimeTypeQueryCommand before the mime.types lookup
89 char *C_Sendmail;     ///< Config: External command to send email
90 short C_SendmailWait; ///< Config: Time to wait for sendmail to finish
91 bool C_Use8bitmime;   ///< Config: Use 8-bit messages and ESMTP to send messages
92 bool C_UseEnvelopeFrom; ///< Config: Set the envelope sender of the message
93 bool C_UserAgent;       ///< Config: Add a 'User-Agent' head to outgoing mail
94 short C_WrapHeaders;    ///< Config: Width to wrap headers in outgoing messages
95
96 /**
97  * encode_quoted - Encode text as quoted printable
98  * @param fc     Cursor for converting a file's encoding
99  * @param fp_out File to store the result
100  * @param istext Is the input text?
101  */
102 static void encode_quoted(struct FgetConv *fc, FILE *fp_out, bool istext)
103 {
104   int c, linelen = 0;
105   char line[77], savechar;
106
107   while ((c = mutt_ch_fgetconv(fc)) != EOF)
108   {
109     /* Wrap the line if needed. */
110     if ((linelen == 76) && ((istext && (c != '\n')) || !istext))
111     {
112       /* If the last character is "quoted", then be sure to move all three
113        * characters to the next line.  Otherwise, just move the last
114        * character...  */
115       if (line[linelen - 3] == '=')
116       {
117         line[linelen - 3] = 0;
118         fputs(line, fp_out);
119         fputs("=\n", fp_out);
120         line[linelen] = 0;
121         line[0] = '=';
122         line[1] = line[linelen - 2];
123         line[2] = line[linelen - 1];
124         linelen = 3;
125       }
126       else
127       {
128         savechar = line[linelen - 1];
129         line[linelen - 1] = '=';
130         line[linelen] = 0;
131         fputs(line, fp_out);
132         fputc('\n', fp_out);
133         line[0] = savechar;
134         linelen = 1;
135       }
136     }
137
138     /* Escape lines that begin with/only contain "the message separator". */
139     if ((linelen == 4) && mutt_str_startswith(line, "From", CASE_MATCH))
140     {
141       mutt_str_strfcpy(line, "=46rom", sizeof(line));
142       linelen = 6;
143     }
144     else if ((linelen == 4) && mutt_str_startswith(line, "from", CASE_MATCH))
145     {
146       mutt_str_strfcpy(line, "=66rom", sizeof(line));
147       linelen = 6;
148     }
149     else if ((linelen == 1) && (line[0] == '.'))
150     {
151       mutt_str_strfcpy(line, "=2E", sizeof(line));
152       linelen = 3;
153     }
154
155     if ((c == '\n') && istext)
156     {
157       /* Check to make sure there is no trailing space on this line. */
158       if ((linelen > 0) && ((line[linelen - 1] == ' ') || (line[linelen - 1] == '\t')))
159       {
160         if (linelen < 74)
161         {
162           sprintf(line + linelen - 1, "=%2.2X", (unsigned char) line[linelen - 1]);
163           fputs(line, fp_out);
164         }
165         else
166         {
167           int savechar2 = line[linelen - 1];
168
169           line[linelen - 1] = '=';
170           line[linelen] = 0;
171           fputs(line, fp_out);
172           fprintf(fp_out, "\n=%2.2X", (unsigned char) savechar2);
173         }
174       }
175       else
176       {
177         line[linelen] = 0;
178         fputs(line, fp_out);
179       }
180       fputc('\n', fp_out);
181       linelen = 0;
182     }
183     else if ((c != 9) && ((c < 32) || (c > 126) || (c == '=')))
184     {
185       /* Check to make sure there is enough room for the quoted character.
186        * If not, wrap to the next line.  */
187       if (linelen > 73)
188       {
189         line[linelen++] = '=';
190         line[linelen] = 0;
191         fputs(line, fp_out);
192         fputc('\n', fp_out);
193         linelen = 0;
194       }
195       sprintf(line + linelen, "=%2.2X", (unsigned char) c);
196       linelen += 3;
197     }
198     else
199     {
200       /* Don't worry about wrapping the line here.  That will happen during
201        * the next iteration when I'll also know what the next character is.  */
202       line[linelen++] = c;
203     }
204   }
205
206   /* Take care of anything left in the buffer */
207   if (linelen > 0)
208   {
209     if ((line[linelen - 1] == ' ') || (line[linelen - 1] == '\t'))
210     {
211       /* take care of trailing whitespace */
212       if (linelen < 74)
213         sprintf(line + linelen - 1, "=%2.2X", (unsigned char) line[linelen - 1]);
214       else
215       {
216         savechar = line[linelen - 1];
217         line[linelen - 1] = '=';
218         line[linelen] = 0;
219         fputs(line, fp_out);
220         fputc('\n', fp_out);
221         sprintf(line, "=%2.2X", (unsigned char) savechar);
222       }
223     }
224     else
225       line[linelen] = 0;
226     fputs(line, fp_out);
227   }
228 }
229
230 /**
231  * struct B64Context - Cursor for the Base64 conversion
232  */
233 struct B64Context
234 {
235   char buffer[3];
236   short size;
237   short linelen;
238 };
239
240 /**
241  * b64_init - Set up the base64 conversion
242  * @param bctx Cursor for the base64 conversion
243  * @retval 0 Always
244  */
245 static int b64_init(struct B64Context *bctx)
246 {
247   memset(bctx->buffer, '\0', sizeof(bctx->buffer));
248   bctx->size = 0;
249   bctx->linelen = 0;
250
251   return 0;
252 }
253
254 /**
255  * b64_flush - Save the bytes to the file
256  * @param bctx   Cursor for the base64 conversion
257  * @param fp_out File to save the output
258  */
259 static void b64_flush(struct B64Context *bctx, FILE *fp_out)
260 {
261   /* for some reasons, mutt_b64_encode expects the
262    * output buffer to be larger than 10B */
263   char encoded[11];
264   size_t ret;
265
266   if (bctx->size == 0)
267     return;
268
269   if (bctx->linelen >= 72)
270   {
271     fputc('\n', fp_out);
272     bctx->linelen = 0;
273   }
274
275   /* ret should always be equal to 4 here, because bctx->size
276    * is a value between 1 and 3 (included), but let's not hardcode it
277    * and prefer the return value of the function */
278   ret = mutt_b64_encode(bctx->buffer, bctx->size, encoded, sizeof(encoded));
279   for (size_t i = 0; i < ret; i++)
280   {
281     fputc(encoded[i], fp_out);
282     bctx->linelen++;
283   }
284
285   bctx->size = 0;
286 }
287
288 /**
289  * b64_putc - Base64-encode one character
290  * @param bctx   Cursor for the base64 conversion
291  * @param c      Character to encode
292  * @param fp_out File to save the output
293  */
294 static void b64_putc(struct B64Context *bctx, char c, FILE *fp_out)
295 {
296   if (bctx->size == 3)
297     b64_flush(bctx, fp_out);
298
299   bctx->buffer[bctx->size++] = c;
300 }
301
302 /**
303  * encode_base64 - Base64-encode some data
304  * @param fc     Cursor for converting a file's encoding
305  * @param fp_out File to store the result
306  * @param istext Is the input text?
307  */
308 static void encode_base64(struct FgetConv *fc, FILE *fp_out, int istext)
309 {
310   struct B64Context bctx;
311   int ch, ch1 = EOF;
312
313   b64_init(&bctx);
314
315   while ((ch = mutt_ch_fgetconv(fc)) != EOF)
316   {
317     if (SigInt == 1)
318     {
319       SigInt = 0;
320       return;
321     }
322     if (istext && (ch == '\n') && (ch1 != '\r'))
323       b64_putc(&bctx, '\r', fp_out);
324     b64_putc(&bctx, ch, fp_out);
325     ch1 = ch;
326   }
327   b64_flush(&bctx, fp_out);
328   fputc('\n', fp_out);
329 }
330
331 /**
332  * encode_8bit - Write the data as raw 8-bit data
333  * @param fc     Cursor for converting a file's encoding
334  * @param fp_out File to store the result
335  */
336 static void encode_8bit(struct FgetConv *fc, FILE *fp_out)
337 {
338   int ch;
339
340   while ((ch = mutt_ch_fgetconv(fc)) != EOF)
341   {
342     if (SigInt == 1)
343     {
344       SigInt = 0;
345       return;
346     }
347     fputc(ch, fp_out);
348   }
349 }
350
351 /**
352  * mutt_write_mime_header - Create a MIME header
353  * @param a  Body part
354  * @param fp File to write to
355  * @retval  0 Success
356  * @retval -1 Failure
357  */
358 int mutt_write_mime_header(struct Body *a, FILE *fp)
359 {
360   int len;
361   int tmplen;
362   char buf[256] = { 0 };
363
364   fprintf(fp, "Content-Type: %s/%s", TYPE(a), a->subtype);
365
366   if (!TAILQ_EMPTY(&a->parameter))
367   {
368     len = 25 + mutt_str_strlen(a->subtype); /* approximate len. of content-type */
369
370     struct Parameter *np = NULL;
371     TAILQ_FOREACH(np, &a->parameter, entries)
372     {
373       if (!np->attribute || !np->value)
374         continue;
375
376       struct ParameterList param_conts = rfc2231_encode_string(np->attribute, np->value);
377       struct Parameter *cont = NULL;
378       TAILQ_FOREACH(cont, &param_conts, entries)
379       {
380         fputc(';', fp);
381
382         buf[0] = 0;
383         mutt_addr_cat(buf, sizeof(buf), cont->value, MimeSpecials);
384
385         /* Dirty hack to make messages readable by Outlook Express
386          * for the Mac: force quotes around the boundary parameter
387          * even when they aren't needed.
388          */
389         if (!mutt_str_strcasecmp(cont->attribute, "boundary") &&
390             !mutt_str_strcmp(buf, cont->value))
391           snprintf(buf, sizeof(buf), "\"%s\"", cont->value);
392
393         tmplen = mutt_str_strlen(buf) + mutt_str_strlen(cont->attribute) + 1;
394         if (len + tmplen + 2 > 76)
395         {
396           fputs("\n\t", fp);
397           len = tmplen + 1;
398         }
399         else
400         {
401           fputc(' ', fp);
402           len += tmplen + 1;
403         }
404
405         fprintf(fp, "%s=%s", cont->attribute, buf);
406       }
407
408       mutt_param_free(&param_conts);
409     }
410   }
411
412   fputc('\n', fp);
413
414   if (a->language)
415     fprintf(fp, "Content-Language: %s\n", a->language);
416
417   if (a->description)
418     fprintf(fp, "Content-Description: %s\n", a->description);
419
420   if (a->disposition != DISP_NONE)
421   {
422     const char *dispstr[] = { "inline", "attachment", "form-data" };
423
424     if (a->disposition < sizeof(dispstr) / sizeof(char *))
425     {
426       fprintf(fp, "Content-Disposition: %s", dispstr[a->disposition]);
427       len = 21 + mutt_str_strlen(dispstr[a->disposition]);
428
429       if (a->use_disp && (a->disposition != DISP_INLINE))
430       {
431         char *fn = a->d_filename;
432         if (!fn)
433           fn = a->filename;
434
435         if (fn)
436         {
437           /* Strip off the leading path... */
438           char *t = strrchr(fn, '/');
439           if (t)
440             t++;
441           else
442             t = fn;
443
444           struct ParameterList param_conts = rfc2231_encode_string("filename", t);
445           struct Parameter *cont = NULL;
446           TAILQ_FOREACH(cont, &param_conts, entries)
447           {
448             fputc(';', fp);
449             buf[0] = 0;
450             mutt_addr_cat(buf, sizeof(buf), cont->value, MimeSpecials);
451
452             tmplen = mutt_str_strlen(buf) + mutt_str_strlen(cont->attribute) + 1;
453             if (len + tmplen + 2 > 76)
454             {
455               fputs("\n\t", fp);
456               len = tmplen + 1;
457             }
458             else
459             {
460               fputc(' ', fp);
461               len += tmplen + 1;
462             }
463
464             fprintf(fp, "%s=%s", cont->attribute, buf);
465           }
466
467           mutt_param_free(&param_conts);
468         }
469       }
470
471       fputc('\n', fp);
472     }
473     else
474     {
475       mutt_debug(LL_DEBUG1, "ERROR: invalid content-disposition %d\n", a->disposition);
476     }
477   }
478
479   if (a->encoding != ENC_7BIT)
480     fprintf(fp, "Content-Transfer-Encoding: %s\n", ENCODING(a->encoding));
481
482   if (C_CryptProtectedHeadersWrite && a->mime_headers)
483     mutt_rfc822_write_header(fp, a->mime_headers, NULL, MUTT_WRITE_HEADER_MIME, false, false);
484
485   /* Do NOT add the terminator here!!! */
486   return ferror(fp) ? -1 : 0;
487 }
488
489 /**
490  * write_as_text_part - Should the Body be written as a text MIME part
491  * @param b Email to examine
492  * @retval true If the Body should be written as text
493  */
494 static bool write_as_text_part(struct Body *b)
495 {
496   return mutt_is_text_part(b) ||
497          (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_application_pgp(b));
498 }
499
500 /**
501  * mutt_write_mime_body - Write a MIME part
502  * @param a  Body to use
503  * @param fp File to write to
504  * @retval  0 Success
505  * @retval -1 Failure
506  */
507 int mutt_write_mime_body(struct Body *a, FILE *fp)
508 {
509   FILE *fp_in = NULL;
510   struct FgetConv *fc = NULL;
511
512   if (a->type == TYPE_MULTIPART)
513   {
514     /* First, find the boundary to use */
515     const char *p = mutt_param_get(&a->parameter, "boundary");
516     if (!p)
517     {
518       mutt_debug(LL_DEBUG1, "no boundary parameter found\n");
519       mutt_error(_("No boundary parameter found [report this error]"));
520       return -1;
521     }
522     char boundary[128];
523     mutt_str_strfcpy(boundary, p, sizeof(boundary));
524
525     for (struct Body *t = a->parts; t; t = t->next)
526     {
527       fprintf(fp, "\n--%s\n", boundary);
528       if (mutt_write_mime_header(t, fp) == -1)
529         return -1;
530       fputc('\n', fp);
531       if (mutt_write_mime_body(t, fp) == -1)
532         return -1;
533     }
534     fprintf(fp, "\n--%s--\n", boundary);
535     return ferror(fp) ? -1 : 0;
536   }
537
538   /* This is pretty gross, but it's the best solution for now... */
539   if (((WithCrypto & APPLICATION_PGP) != 0) && (a->type == TYPE_APPLICATION) &&
540       (mutt_str_strcmp(a->subtype, "pgp-encrypted") == 0))
541   {
542     fputs("Version: 1\n", fp);
543     return 0;
544   }
545
546   fp_in = fopen(a->filename, "r");
547   if (!fp_in)
548   {
549     mutt_debug(LL_DEBUG1, "%s no longer exists\n", a->filename);
550     mutt_error(_("%s no longer exists"), a->filename);
551     return -1;
552   }
553
554   if ((a->type == TYPE_TEXT) && (!a->noconv))
555   {
556     char send_charset[128];
557     fc = mutt_ch_fgetconv_open(
558         fp_in, a->charset,
559         mutt_body_get_charset(a, send_charset, sizeof(send_charset)), 0);
560   }
561   else
562     fc = mutt_ch_fgetconv_open(fp_in, 0, 0, 0);
563
564   mutt_sig_allow_interrupt(1);
565   if (a->encoding == ENC_QUOTED_PRINTABLE)
566     encode_quoted(fc, fp, write_as_text_part(a));
567   else if (a->encoding == ENC_BASE64)
568     encode_base64(fc, fp, write_as_text_part(a));
569   else if ((a->type == TYPE_TEXT) && (!a->noconv))
570     encode_8bit(fc, fp);
571   else
572     mutt_file_copy_stream(fp_in, fp);
573   mutt_sig_allow_interrupt(0);
574
575   mutt_ch_fgetconv_close(&fc);
576   mutt_file_fclose(&fp_in);
577
578   if (SigInt == 1)
579   {
580     SigInt = 0;
581     return -1;
582   }
583   return ferror(fp) ? -1 : 0;
584 }
585
586 /**
587  * mutt_generate_boundary - Create a unique boundary id for a MIME part
588  * @param parm MIME part
589  */
590 void mutt_generate_boundary(struct ParameterList *parm)
591 {
592   char rs[MUTT_RANDTAG_LEN + 1];
593
594   mutt_rand_base32(rs, sizeof(rs) - 1);
595   rs[MUTT_RANDTAG_LEN] = 0;
596   mutt_param_set(parm, "boundary", rs);
597 }
598
599 /**
600  * struct ContentState - Info about the body of an email
601  */
602 struct ContentState
603 {
604   bool from;
605   int whitespace;
606   bool dot;
607   int linelen;
608   bool was_cr;
609 };
610
611 /**
612  * update_content_info - Cache some info about an email
613  * @param info   Info about an Attachment
614  * @param s      Info about the Body of an email
615  * @param buf    Buffer for the result
616  * @param buflen Length of the buffer
617  */
618 static void update_content_info(struct Content *info, struct ContentState *s,
619                                 char *buf, size_t buflen)
620 {
621   bool from = s->from;
622   int whitespace = s->whitespace;
623   bool dot = s->dot;
624   int linelen = s->linelen;
625   bool was_cr = s->was_cr;
626
627   if (!buf) /* This signals EOF */
628   {
629     if (was_cr)
630       info->binary = true;
631     if (linelen > info->linemax)
632       info->linemax = linelen;
633
634     return;
635   }
636
637   for (; buflen; buf++, buflen--)
638   {
639     char ch = *buf;
640
641     if (was_cr)
642     {
643       was_cr = false;
644       if (ch != '\n')
645       {
646         info->binary = true;
647       }
648       else
649       {
650         if (whitespace)
651           info->space = true;
652         if (dot)
653           info->dot = true;
654         if (linelen > info->linemax)
655           info->linemax = linelen;
656         whitespace = 0;
657         dot = false;
658         linelen = 0;
659         continue;
660       }
661     }
662
663     linelen++;
664     if (ch == '\n')
665     {
666       info->crlf++;
667       if (whitespace)
668         info->space = true;
669       if (dot)
670         info->dot = true;
671       if (linelen > info->linemax)
672         info->linemax = linelen;
673       whitespace = 0;
674       linelen = 0;
675       dot = false;
676     }
677     else if (ch == '\r')
678     {
679       info->crlf++;
680       info->cr = true;
681       was_cr = true;
682       continue;
683     }
684     else if (ch & 0x80)
685       info->hibin++;
686     else if ((ch == '\t') || (ch == '\f'))
687     {
688       info->ascii++;
689       whitespace++;
690     }
691     else if (ch == 0)
692     {
693       info->nulbin++;
694       info->lobin++;
695     }
696     else if ((ch < 32) || (ch == 127))
697       info->lobin++;
698     else
699     {
700       if (linelen == 1)
701       {
702         if ((ch == 'F') || (ch == 'f'))
703           from = true;
704         else
705           from = false;
706         if (ch == '.')
707           dot = true;
708         else
709           dot = false;
710       }
711       else if (from)
712       {
713         if ((linelen == 2) && (ch != 'r'))
714           from = false;
715         else if ((linelen == 3) && (ch != 'o'))
716           from = false;
717         else if (linelen == 4)
718         {
719           if (ch == 'm')
720             info->from = true;
721           from = false;
722         }
723       }
724       if (ch == ' ')
725         whitespace++;
726       info->ascii++;
727     }
728
729     if (linelen > 1)
730       dot = false;
731     if ((ch != ' ') && (ch != '\t'))
732       whitespace = 0;
733   }
734
735   s->from = from;
736   s->whitespace = whitespace;
737   s->dot = dot;
738   s->linelen = linelen;
739   s->was_cr = was_cr;
740 }
741
742 /**
743  * convert_file_to - Change the encoding of a file
744  * @param[in]  fp         File to convert
745  * @param[in]  fromcode   Original encoding
746  * @param[in]  ncodes     Number of target encodings
747  * @param[in]  tocodes    List of target encodings
748  * @param[out] tocode     Chosen encoding
749  * @param[in]  info       Encoding information
750  * @retval -1 Error, no conversion was possible
751  * @retval >0 Success, number of bytes converted
752  *
753  * Find the best charset conversion of the file from fromcode into one
754  * of the tocodes. If successful, set *tocode and Content *info and
755  * return the number of characters converted inexactly.
756  *
757  * We convert via UTF-8 in order to avoid the condition -1(EINVAL),
758  * which would otherwise prevent us from knowing the number of inexact
759  * conversions. Where the candidate target charset is UTF-8 we avoid
760  * doing the second conversion because iconv_open("UTF-8", "UTF-8")
761  * fails with some libraries.
762  *
763  * We assume that the output from iconv is never more than 4 times as
764  * long as the input for any pair of charsets we might be interested
765  * in.
766  */
767 static size_t convert_file_to(FILE *fp, const char *fromcode, int ncodes,
768                               const char **tocodes, int *tocode, struct Content *info)
769 {
770   char bufi[256], bufu[512], bufo[4 * sizeof(bufi)];
771   size_t ret;
772
773   const iconv_t cd1 = mutt_ch_iconv_open("utf-8", fromcode, 0);
774   if (cd1 == (iconv_t)(-1))
775     return -1;
776
777   iconv_t *cd = mutt_mem_calloc(ncodes, sizeof(iconv_t));
778   size_t *score = mutt_mem_calloc(ncodes, sizeof(size_t));
779   struct ContentState *states = mutt_mem_calloc(ncodes, sizeof(struct ContentState));
780   struct Content *infos = mutt_mem_calloc(ncodes, sizeof(struct Content));
781
782   for (int i = 0; i < ncodes; i++)
783   {
784     if (mutt_str_strcasecmp(tocodes[i], "utf-8") != 0)
785       cd[i] = mutt_ch_iconv_open(tocodes[i], "utf-8", 0);
786     else
787     {
788       /* Special case for conversion to UTF-8 */
789       cd[i] = (iconv_t)(-1);
790       score[i] = (size_t)(-1);
791     }
792   }
793
794   rewind(fp);
795   size_t ibl = 0;
796   while (true)
797   {
798     /* Try to fill input buffer */
799     size_t n = fread(bufi + ibl, 1, sizeof(bufi) - ibl, fp);
800     ibl += n;
801
802     /* Convert to UTF-8 */
803     const char *ib = bufi;
804     char *ob = bufu;
805     size_t obl = sizeof(bufu);
806     n = iconv(cd1, (ICONV_CONST char **) ((ibl != 0) ? &ib : 0), &ibl, &ob, &obl);
807     /* assert(n == (size_t)(-1) || !n); */
808     if ((n == (size_t)(-1)) && (((errno != EINVAL) && (errno != E2BIG)) || (ib == bufi)))
809     {
810       /* assert(errno == EILSEQ || (errno == EINVAL && ib == bufi && ibl < sizeof(bufi))); */
811       ret = (size_t)(-1);
812       break;
813     }
814     const size_t ubl1 = ob - bufu;
815
816     /* Convert from UTF-8 */
817     for (int i = 0; i < ncodes; i++)
818     {
819       if ((cd[i] != (iconv_t)(-1)) && (score[i] != (size_t)(-1)))
820       {
821         const char *ub = bufu;
822         size_t ubl = ubl1;
823         ob = bufo;
824         obl = sizeof(bufo);
825         n = iconv(cd[i], (ICONV_CONST char **) ((ibl || ubl) ? &ub : 0), &ubl, &ob, &obl);
826         if (n == (size_t)(-1))
827         {
828           /* assert(errno == E2BIG || (BUGGY_ICONV && (errno == EILSEQ || errno == ENOENT))); */
829           score[i] = (size_t)(-1);
830         }
831         else
832         {
833           score[i] += n;
834           update_content_info(&infos[i], &states[i], bufo, ob - bufo);
835         }
836       }
837       else if ((cd[i] == (iconv_t)(-1)) && (score[i] == (size_t)(-1)))
838       {
839         /* Special case for conversion to UTF-8 */
840         update_content_info(&infos[i], &states[i], bufu, ubl1);
841       }
842     }
843
844     if (ibl)
845     {
846       /* Save unused input */
847       memmove(bufi, ib, ibl);
848     }
849     else if (!ubl1 && (ib < bufi + sizeof(bufi)))
850     {
851       ret = 0;
852       break;
853     }
854   }
855
856   if (ret == 0)
857   {
858     /* Find best score */
859     ret = (size_t)(-1);
860     for (int i = 0; i < ncodes; i++)
861     {
862       if ((cd[i] == (iconv_t)(-1)) && (score[i] == (size_t)(-1)))
863       {
864         /* Special case for conversion to UTF-8 */
865         *tocode = i;
866         ret = 0;
867         break;
868       }
869       else if ((cd[i] == (iconv_t)(-1)) || (score[i] == (size_t)(-1)))
870         continue;
871       else if ((ret == (size_t)(-1)) || (score[i] < ret))
872       {
873         *tocode = i;
874         ret = score[i];
875         if (ret == 0)
876           break;
877       }
878     }
879     if (ret != (size_t)(-1))
880     {
881       memcpy(info, &infos[*tocode], sizeof(struct Content));
882       update_content_info(info, &states[*tocode], 0, 0); /* EOF */
883     }
884   }
885
886   for (int i = 0; i < ncodes; i++)
887     if (cd[i] != (iconv_t)(-1))
888       iconv_close(cd[i]);
889
890   iconv_close(cd1);
891   FREE(&cd);
892   FREE(&infos);
893   FREE(&score);
894   FREE(&states);
895
896   return ret;
897 }
898
899 /**
900  * convert_file_from_to - Convert a file between encodings
901  * @param[in]  fp        File to read from
902  * @param[in]  fromcodes Charsets to try converting FROM
903  * @param[in]  tocodes   Charsets to try converting TO
904  * @param[out] fromcode  From charset selected
905  * @param[out] tocode    To charset selected
906  * @param[out] info      Info about the file
907  * @retval num Characters converted
908  * @retval -1  Error (as a size_t)
909  *
910  * Find the first of the fromcodes that gives a valid conversion and the best
911  * charset conversion of the file into one of the tocodes. If successful, set
912  * *fromcode and *tocode to dynamically allocated strings, set Content *info,
913  * and return the number of characters converted inexactly. If no conversion
914  * was possible, return -1.
915  *
916  * Both fromcodes and tocodes may be colon-separated lists of charsets.
917  * However, if fromcode is zero then fromcodes is assumed to be the name of a
918  * single charset even if it contains a colon.
919  */
920 static size_t convert_file_from_to(FILE *fp, const char *fromcodes, const char *tocodes,
921                                    char **fromcode, char **tocode, struct Content *info)
922 {
923   char *fcode = NULL;
924   char **tcode = NULL;
925   const char *c = NULL, *c1 = NULL;
926   size_t ret;
927   int ncodes, i, cn;
928
929   /* Count the tocodes */
930   ncodes = 0;
931   for (c = tocodes; c; c = c1 ? c1 + 1 : 0)
932   {
933     c1 = strchr(c, ':');
934     if (c1 == c)
935       continue;
936     ncodes++;
937   }
938
939   /* Copy them */
940   tcode = mutt_mem_malloc(ncodes * sizeof(char *));
941   for (c = tocodes, i = 0; c; c = c1 ? c1 + 1 : 0, i++)
942   {
943     c1 = strchr(c, ':');
944     if (c1 == c)
945       continue;
946     tcode[i] = mutt_str_substr_dup(c, c1);
947   }
948
949   ret = (size_t)(-1);
950   if (fromcode)
951   {
952     /* Try each fromcode in turn */
953     for (c = fromcodes; c; c = c1 ? c1 + 1 : 0)
954     {
955       c1 = strchr(c, ':');
956       if (c1 == c)
957         continue;
958       fcode = mutt_str_substr_dup(c, c1);
959
960       ret = convert_file_to(fp, fcode, ncodes, (const char **) tcode, &cn, info);
961       if (ret != (size_t)(-1))
962       {
963         *fromcode = fcode;
964         *tocode = tcode[cn];
965         tcode[cn] = 0;
966         break;
967       }
968       FREE(&fcode);
969     }
970   }
971   else
972   {
973     /* There is only one fromcode */
974     ret = convert_file_to(fp, fromcodes, ncodes, (const char **) tcode, &cn, info);
975     if (ret != (size_t)(-1))
976     {
977       *tocode = tcode[cn];
978       tcode[cn] = 0;
979     }
980   }
981
982   /* Free memory */
983   for (i = 0; i < ncodes; i++)
984     FREE(&tcode[i]);
985
986   FREE(&tcode);
987
988   return ret;
989 }
990
991 /**
992  * mutt_get_content_info - Analyze file to determine MIME encoding to use
993  * @param fname File to examine
994  * @param b     Body to update
995  * @retval ptr Newly allocated Content
996  *
997  * Also set the body charset, sometimes, or not.
998  */
999 struct Content *mutt_get_content_info(const char *fname, struct Body *b)
1000 {
1001   struct Content *info = NULL;
1002   struct ContentState state = { 0 };
1003   FILE *fp = NULL;
1004   char *fromcode = NULL;
1005   char *tocode = NULL;
1006   char buf[100];
1007   size_t r;
1008
1009   struct stat sb;
1010
1011   if (b && !fname)
1012     fname = b->filename;
1013
1014   if (stat(fname, &sb) == -1)
1015   {
1016     mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
1017     return NULL;
1018   }
1019
1020   if (!S_ISREG(sb.st_mode))
1021   {
1022     mutt_error(_("%s isn't a regular file"), fname);
1023     return NULL;
1024   }
1025
1026   fp = fopen(fname, "r");
1027   if (!fp)
1028   {
1029     mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", fname, strerror(errno), errno);
1030     return NULL;
1031   }
1032
1033   info = mutt_mem_calloc(1, sizeof(struct Content));
1034
1035   if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
1036   {
1037     char *chs = mutt_param_get(&b->parameter, "charset");
1038     char *fchs = b->use_disp ? (C_AttachCharset ? C_AttachCharset : C_Charset) : C_Charset;
1039     if (C_Charset && (chs || C_SendCharset) &&
1040         (convert_file_from_to(fp, fchs, chs ? chs : C_SendCharset, &fromcode,
1041                               &tocode, info) != (size_t)(-1)))
1042     {
1043       if (!chs)
1044       {
1045         char chsbuf[256];
1046         mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), tocode);
1047         mutt_param_set(&b->parameter, "charset", chsbuf);
1048       }
1049       FREE(&b->charset);
1050       b->charset = fromcode;
1051       FREE(&tocode);
1052       mutt_file_fclose(&fp);
1053       return info;
1054     }
1055   }
1056
1057   rewind(fp);
1058   while ((r = fread(buf, 1, sizeof(buf), fp)))
1059     update_content_info(info, &state, buf, r);
1060   update_content_info(info, &state, 0, 0);
1061
1062   mutt_file_fclose(&fp);
1063
1064   if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
1065   {
1066     mutt_param_set(&b->parameter, "charset",
1067                    (!info->hibin ?
1068                         "us-ascii" :
1069                         C_Charset && !mutt_ch_is_us_ascii(C_Charset) ? C_Charset : "unknown-8bit"));
1070   }
1071
1072   return info;
1073 }
1074
1075 /**
1076  * mutt_lookup_mime_type - Find the MIME type for an attachment
1077  * @param att  Email with attachment
1078  * @param path Path to attachment
1079  * @retval num MIME type, e.g. #TYPE_IMAGE
1080  *
1081  * Given a file at 'path', see if there is a registered MIME type.
1082  * Returns the major MIME type, and copies the subtype to "d".  First look
1083  * in a system mime.types if we can find one, then look for ~/.mime.types.
1084  * The longest match is used so that we can match 'ps.gz' when 'gz' also
1085  * exists.
1086  */
1087 int mutt_lookup_mime_type(struct Body *att, const char *path)
1088 {
1089   FILE *fp = NULL;
1090   char *p = NULL, *q = NULL, *ct = NULL;
1091   char buf[PATH_MAX];
1092   char subtype[256], xtype[256];
1093   int szf, sze, cur_sze;
1094   int type;
1095   bool found_mimetypes = false;
1096
1097   *subtype = '\0';
1098   *xtype = '\0';
1099   type = TYPE_OTHER;
1100   cur_sze = 0;
1101
1102   szf = mutt_str_strlen(path);
1103
1104   for (int count = 0; count < 4; count++)
1105   {
1106     /* can't use strtok() because we use it in an inner loop below, so use
1107      * a switch statement here instead.  */
1108     switch (count)
1109     {
1110       /* last file with last entry to match wins type/xtype */
1111       case 0:
1112         /* check default unix mimetypes location first */
1113         mutt_str_strfcpy(buf, "/etc/mime.types", sizeof(buf));
1114         break;
1115       case 1:
1116         mutt_str_strfcpy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
1117         break;
1118       case 2:
1119         mutt_str_strfcpy(buf, PKGDATADIR "/mime.types", sizeof(buf));
1120         break;
1121       case 3:
1122         snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
1123         break;
1124       default:
1125         mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
1126         goto bye; /* shouldn't happen */
1127     }
1128
1129     fp = fopen(buf, "r");
1130     if (fp)
1131     {
1132       found_mimetypes = true;
1133
1134       while (fgets(buf, sizeof(buf) - 1, fp))
1135       {
1136         /* weed out any comments */
1137         p = strchr(buf, '#');
1138         if (p)
1139           *p = '\0';
1140
1141         /* remove any leading space. */
1142         ct = buf;
1143         SKIPWS(ct);
1144
1145         /* position on the next field in this line */
1146         p = strpbrk(ct, " \t");
1147         if (!p)
1148           continue;
1149         *p++ = 0;
1150         SKIPWS(p);
1151
1152         /* cycle through the file extensions */
1153         while ((p = strtok(p, " \t\n")))
1154         {
1155           sze = mutt_str_strlen(p);
1156           if ((sze > cur_sze) && (szf >= sze) &&
1157               ((mutt_str_strcasecmp(path + szf - sze, p) == 0) ||
1158                (mutt_str_strcasecmp(path + szf - sze, p) == 0)) &&
1159               ((szf == sze) || (path[szf - sze - 1] == '.')))
1160           {
1161             /* get the content-type */
1162
1163             p = strchr(ct, '/');
1164             if (!p)
1165             {
1166               /* malformed line, just skip it. */
1167               break;
1168             }
1169             *p++ = 0;
1170
1171             for (q = p; *q && !IS_SPACE(*q); q++)
1172               ;
1173
1174             mutt_str_substr_cpy(subtype, p, q, sizeof(subtype));
1175
1176             type = mutt_check_mime_type(ct);
1177             if (type == TYPE_OTHER)
1178               mutt_str_strfcpy(xtype, ct, sizeof(xtype));
1179
1180             cur_sze = sze;
1181           }
1182           p = NULL;
1183         }
1184       }
1185       mutt_file_fclose(&fp);
1186     }
1187   }
1188
1189 bye:
1190
1191   /* no mime.types file found */
1192   if (!found_mimetypes)
1193   {
1194     mutt_error(_("Could not find any mime.types file."));
1195   }
1196
1197   if ((type != TYPE_OTHER) || (*xtype != '\0'))
1198   {
1199     att->type = type;
1200     mutt_str_replace(&att->subtype, subtype);
1201     mutt_str_replace(&att->xtype, xtype);
1202   }
1203
1204   return type;
1205 }
1206
1207 /**
1208  * transform_to_7bit - Convert MIME parts to 7-bit
1209  * @param a    Body of the email
1210  * @param fp_in File to read
1211  */
1212 static void transform_to_7bit(struct Body *a, FILE *fp_in)
1213 {
1214   char buf[PATH_MAX];
1215   struct State s = { 0 };
1216   struct stat sb;
1217
1218   for (; a; a = a->next)
1219   {
1220     if (a->type == TYPE_MULTIPART)
1221     {
1222       if (a->encoding != ENC_7BIT)
1223         a->encoding = ENC_7BIT;
1224
1225       transform_to_7bit(a->parts, fp_in);
1226     }
1227     else if (mutt_is_message_type(a->type, a->subtype))
1228     {
1229       mutt_message_to_7bit(a, fp_in);
1230     }
1231     else
1232     {
1233       a->noconv = true;
1234       a->force_charset = true;
1235
1236       mutt_mktemp(buf, sizeof(buf));
1237       s.fp_out = mutt_file_fopen(buf, "w");
1238       if (!s.fp_out)
1239       {
1240         mutt_perror("fopen");
1241         return;
1242       }
1243       s.fp_in = fp_in;
1244       mutt_decode_attachment(a, &s);
1245       mutt_file_fclose(&s.fp_out);
1246       FREE(&a->d_filename);
1247       a->d_filename = a->filename;
1248       a->filename = mutt_str_strdup(buf);
1249       a->unlink = true;
1250       if (stat(a->filename, &sb) == -1)
1251       {
1252         mutt_perror("stat");
1253         return;
1254       }
1255       a->length = sb.st_size;
1256
1257       mutt_update_encoding(a);
1258       if (a->encoding == ENC_8BIT)
1259         a->encoding = ENC_QUOTED_PRINTABLE;
1260       else if (a->encoding == ENC_BINARY)
1261         a->encoding = ENC_BASE64;
1262     }
1263   }
1264 }
1265
1266 /**
1267  * mutt_message_to_7bit - Convert an email's MIME parts to 7-bit
1268  * @param a  Body of the email
1269  * @param fp File to read (OPTIONAL)
1270  */
1271 void mutt_message_to_7bit(struct Body *a, FILE *fp)
1272 {
1273   char temp[PATH_MAX];
1274   char *line = NULL;
1275   FILE *fp_in = NULL;
1276   FILE *fp_out = NULL;
1277   struct stat sb;
1278
1279   if (!a->filename && fp)
1280     fp_in = fp;
1281   else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
1282   {
1283     mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
1284     return;
1285   }
1286   else
1287   {
1288     a->offset = 0;
1289     if (stat(a->filename, &sb) == -1)
1290     {
1291       mutt_perror("stat");
1292       mutt_file_fclose(&fp_in);
1293     }
1294     a->length = sb.st_size;
1295   }
1296
1297   mutt_mktemp(temp, sizeof(temp));
1298   fp_out = mutt_file_fopen(temp, "w+");
1299   if (!fp_out)
1300   {
1301     mutt_perror("fopen");
1302     goto cleanup;
1303   }
1304
1305   if (!fp_in)
1306     goto cleanup;
1307
1308   fseeko(fp_in, a->offset, SEEK_SET);
1309   a->parts = mutt_rfc822_parse_message(fp_in, a);
1310
1311   transform_to_7bit(a->parts, fp_in);
1312
1313   mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
1314                 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL);
1315
1316   fputs("MIME-Version: 1.0\n", fp_out);
1317   mutt_write_mime_header(a->parts, fp_out);
1318   fputc('\n', fp_out);
1319   mutt_write_mime_body(a->parts, fp_out);
1320
1321 cleanup:
1322   FREE(&line);
1323
1324   if (fp_in && (fp_in != fp))
1325     mutt_file_fclose(&fp_in);
1326   if (fp_out)
1327     mutt_file_fclose(&fp_out);
1328   else
1329     return;
1330
1331   a->encoding = ENC_7BIT;
1332   FREE(&a->d_filename);
1333   a->d_filename = a->filename;
1334   if (a->filename && a->unlink)
1335     unlink(a->filename);
1336   a->filename = mutt_str_strdup(temp);
1337   a->unlink = true;
1338   if (stat(a->filename, &sb) == -1)
1339   {
1340     mutt_perror("stat");
1341     return;
1342   }
1343   a->length = sb.st_size;
1344   mutt_body_free(&a->parts);
1345   a->email->content = NULL;
1346 }
1347
1348 /**
1349  * set_encoding - determine which Content-Transfer-Encoding to use
1350  * @param[in]  b    Body of email
1351  * @param[out] info Info about the email
1352  */
1353 static void set_encoding(struct Body *b, struct Content *info)
1354 {
1355   if (b->type == TYPE_TEXT)
1356   {
1357     char send_charset[128];
1358     char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
1359     if ((info->lobin && !mutt_str_startswith(chsname, "iso-2022", CASE_IGNORE)) ||
1360         (info->linemax > 990) || (info->from && C_EncodeFrom))
1361     {
1362       b->encoding = ENC_QUOTED_PRINTABLE;
1363     }
1364     else if (info->hibin)
1365     {
1366       b->encoding = C_Allow8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
1367     }
1368     else
1369     {
1370       b->encoding = ENC_7BIT;
1371     }
1372   }
1373   else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
1374   {
1375     if (info->lobin || info->hibin)
1376     {
1377       if (C_Allow8bit && !info->lobin)
1378         b->encoding = ENC_8BIT;
1379       else
1380         mutt_message_to_7bit(b, NULL);
1381     }
1382     else
1383       b->encoding = ENC_7BIT;
1384   }
1385   else if ((b->type == TYPE_APPLICATION) &&
1386            (mutt_str_strcasecmp(b->subtype, "pgp-keys") == 0))
1387   {
1388     b->encoding = ENC_7BIT;
1389   }
1390   else
1391   {
1392     /* Determine which encoding is smaller  */
1393     if (1.33 * (float) (info->lobin + info->hibin + info->ascii) <
1394         3.0 * (float) (info->lobin + info->hibin) + (float) info->ascii)
1395     {
1396       b->encoding = ENC_BASE64;
1397     }
1398     else
1399     {
1400       b->encoding = ENC_QUOTED_PRINTABLE;
1401     }
1402   }
1403 }
1404
1405 /**
1406  * mutt_stamp_attachment - Timestamp an Attachment
1407  * @param a Attachment
1408  */
1409 void mutt_stamp_attachment(struct Body *a)
1410 {
1411   a->stamp = time(NULL);
1412 }
1413
1414 /**
1415  * mutt_body_get_charset - Get a body's character set
1416  * @param b      Body to examine
1417  * @param buf    Buffer for the result
1418  * @param buflen Length of the buffer
1419  * @retval ptr  Buffer containing character set
1420  * @retval NULL On error, or if not a text type
1421  */
1422 char *mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
1423 {
1424   char *p = NULL;
1425
1426   if (b && (b->type != TYPE_TEXT))
1427     return NULL;
1428
1429   if (b)
1430     p = mutt_param_get(&b->parameter, "charset");
1431
1432   if (p)
1433     mutt_ch_canonical_charset(buf, buflen, p);
1434   else
1435     mutt_str_strfcpy(buf, "us-ascii", buflen);
1436
1437   return buf;
1438 }
1439
1440 /**
1441  * mutt_update_encoding - Update the encoding type
1442  * @param a Body to update
1443  *
1444  * Assumes called from send mode where Body->filename points to actual file
1445  */
1446 void mutt_update_encoding(struct Body *a)
1447 {
1448   struct Content *info = NULL;
1449   char chsbuf[256];
1450
1451   /* override noconv when it's us-ascii */
1452   if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
1453     a->noconv = false;
1454
1455   if (!a->force_charset && !a->noconv)
1456     mutt_param_delete(&a->parameter, "charset");
1457
1458   info = mutt_get_content_info(a->filename, a);
1459   if (!info)
1460     return;
1461
1462   set_encoding(a, info);
1463   mutt_stamp_attachment(a);
1464
1465   FREE(&a->content);
1466   a->content = info;
1467 }
1468
1469 /**
1470  * mutt_make_message_attach - Create a message attachment
1471  * @param m          Mailbox
1472  * @param e          Email
1473  * @param attach_msg true if attaching a message
1474  * @retval ptr  Newly allocated Body
1475  * @retval NULL Error
1476  */
1477 struct Body *mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg)
1478 {
1479   char buf[1024];
1480   struct Body *body = NULL;
1481   FILE *fp = NULL;
1482   CopyMessageFlags cmflags;
1483   SecurityFlags pgp = WithCrypto ? e->security : SEC_NO_FLAGS;
1484
1485   if (WithCrypto)
1486   {
1487     if ((C_MimeForwardDecode || C_ForwardDecrypt) && (e->security & SEC_ENCRYPT))
1488     {
1489       if (!crypt_valid_passphrase(e->security))
1490         return NULL;
1491     }
1492   }
1493
1494   mutt_mktemp(buf, sizeof(buf));
1495   fp = mutt_file_fopen(buf, "w+");
1496   if (!fp)
1497     return NULL;
1498
1499   body = mutt_body_new();
1500   body->type = TYPE_MESSAGE;
1501   body->subtype = mutt_str_strdup("rfc822");
1502   body->filename = mutt_str_strdup(buf);
1503   body->unlink = true;
1504   body->use_disp = false;
1505   body->disposition = DISP_INLINE;
1506   body->noconv = true;
1507
1508   mutt_parse_mime_message(m, e);
1509
1510   CopyHeaderFlags chflags = CH_XMIT;
1511   cmflags = MUTT_CM_NO_FLAGS;
1512
1513   /* If we are attaching a message, ignore C_MimeForwardDecode */
1514   if (!attach_msg && C_MimeForwardDecode)
1515   {
1516     chflags |= CH_MIME | CH_TXTPLAIN;
1517     cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1518     if (WithCrypto & APPLICATION_PGP)
1519       pgp &= ~PGP_ENCRYPT;
1520     if (WithCrypto & APPLICATION_SMIME)
1521       pgp &= ~SMIME_ENCRYPT;
1522   }
1523   else if ((WithCrypto != 0) && C_ForwardDecrypt && (e->security & SEC_ENCRYPT))
1524   {
1525     if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_is_multipart_encrypted(e->content))
1526     {
1527       chflags |= CH_MIME | CH_NONEWLINE;
1528       cmflags = MUTT_CM_DECODE_PGP;
1529       pgp &= ~PGP_ENCRYPT;
1530     }
1531     else if (((WithCrypto & APPLICATION_PGP) != 0) &&
1532              ((mutt_is_application_pgp(e->content) & PGP_ENCRYPT) == PGP_ENCRYPT))
1533     {
1534       chflags |= CH_MIME | CH_TXTPLAIN;
1535       cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1536       pgp &= ~PGP_ENCRYPT;
1537     }
1538     else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1539              ((mutt_is_application_smime(e->content) & SMIME_ENCRYPT) == SMIME_ENCRYPT))
1540     {
1541       chflags |= CH_MIME | CH_TXTPLAIN;
1542       cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1543       pgp &= ~SMIME_ENCRYPT;
1544     }
1545   }
1546
1547   mutt_copy_message_ctx(fp, m, e, cmflags, chflags);
1548
1549   fflush(fp);
1550   rewind(fp);
1551
1552   body->email = mutt_email_new();
1553   body->email->offset = 0;
1554   /* we don't need the user headers here */
1555   body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
1556   if (WithCrypto)
1557     body->email->security = pgp;
1558   mutt_update_encoding(body);
1559   body->parts = body->email->content;
1560
1561   mutt_file_fclose(&fp);
1562
1563   return body;
1564 }
1565
1566 /**
1567  * run_mime_type_query - Run an external command to determine the MIME type
1568  * @param att Attachment
1569  *
1570  * The command in $mime_type_query_command is run.
1571  */
1572 static void run_mime_type_query(struct Body *att)
1573 {
1574   FILE *fp = NULL, *fp_err = NULL;
1575   char *buf = NULL;
1576   size_t buflen;
1577   int dummy = 0;
1578   pid_t pid;
1579   struct Buffer *cmd = mutt_buffer_pool_get();
1580
1581   mutt_buffer_file_expand_fmt_quote(cmd, C_MimeTypeQueryCommand, att->filename);
1582
1583   pid = mutt_create_filter(mutt_b2s(cmd), NULL, &fp, &fp_err);
1584   if (pid < 0)
1585   {
1586     mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
1587     mutt_buffer_pool_release(&cmd);
1588     return;
1589   }
1590   mutt_buffer_pool_release(&cmd);
1591
1592   buf = mutt_file_read_line(buf, &buflen, fp, &dummy, 0);
1593   if (buf)
1594   {
1595     if (strchr(buf, '/'))
1596       mutt_parse_content_type(buf, att);
1597     FREE(&buf);
1598   }
1599
1600   mutt_file_fclose(&fp);
1601   mutt_file_fclose(&fp_err);
1602   mutt_wait_filter(pid);
1603 }
1604
1605 /**
1606  * mutt_make_file_attach - Create a file attachment
1607  * @param path File to attach
1608  * @retval ptr  Newly allocated Body
1609  * @retval NULL Error
1610  */
1611 struct Body *mutt_make_file_attach(const char *path)
1612 {
1613   struct Body *att = mutt_body_new();
1614   att->filename = mutt_str_strdup(path);
1615
1616   if (C_MimeTypeQueryCommand && C_MimeTypeQueryFirst)
1617     run_mime_type_query(att);
1618
1619   /* Attempt to determine the appropriate content-type based on the filename
1620    * suffix.  */
1621   if (!att->subtype)
1622     mutt_lookup_mime_type(att, path);
1623
1624   if (!att->subtype && C_MimeTypeQueryCommand && !C_MimeTypeQueryFirst)
1625   {
1626     run_mime_type_query(att);
1627   }
1628
1629   struct Content *info = mutt_get_content_info(path, att);
1630   if (!info)
1631   {
1632     mutt_body_free(&att);
1633     return NULL;
1634   }
1635
1636   if (!att->subtype)
1637   {
1638     if ((info->nulbin == 0) &&
1639         ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
1640     {
1641       /* Statistically speaking, there should be more than 10% "lobin"
1642        * chars if this is really a binary file...  */
1643       att->type = TYPE_TEXT;
1644       att->subtype = mutt_str_strdup("plain");
1645     }
1646     else
1647     {
1648       att->type = TYPE_APPLICATION;
1649       att->subtype = mutt_str_strdup("octet-stream");
1650     }
1651   }
1652
1653   FREE(&info);
1654   mutt_update_encoding(att);
1655   return att;
1656 }
1657
1658 /**
1659  * get_toplevel_encoding - Find the most restrictive encoding type
1660  * @param a Body to examine
1661  * @retval num Encoding type, e.g. #ENC_7BIT
1662  */
1663 static int get_toplevel_encoding(struct Body *a)
1664 {
1665   int e = ENC_7BIT;
1666
1667   for (; a; a = a->next)
1668   {
1669     if (a->encoding == ENC_BINARY)
1670       return ENC_BINARY;
1671     else if (a->encoding == ENC_8BIT)
1672       e = ENC_8BIT;
1673   }
1674
1675   return e;
1676 }
1677
1678 /**
1679  * check_boundary - check for duplicate boundary
1680  * @param boundary Boundary to look for
1681  * @param b        Body parts to check
1682  * @retval true if duplicate found
1683  */
1684 static bool check_boundary(const char *boundary, struct Body *b)
1685 {
1686   char *p = NULL;
1687
1688   if (b->parts && check_boundary(boundary, b->parts))
1689     return true;
1690
1691   if (b->next && check_boundary(boundary, b->next))
1692     return true;
1693
1694   p = mutt_param_get(&b->parameter, "boundary");
1695   if (p && (mutt_str_strcmp(p, boundary) == 0))
1696   {
1697     return true;
1698   }
1699   return false;
1700 }
1701
1702 /**
1703  * mutt_make_multipart - Create a multipart email
1704  * @param b Body of email to start
1705  * @retval ptr Newly allocated Body
1706  */
1707 struct Body *mutt_make_multipart(struct Body *b)
1708 {
1709   struct Body *new = mutt_body_new();
1710   new->type = TYPE_MULTIPART;
1711   new->subtype = mutt_str_strdup("mixed");
1712   new->encoding = get_toplevel_encoding(b);
1713   do
1714   {
1715     mutt_generate_boundary(&new->parameter);
1716     if (check_boundary(mutt_param_get(&new->parameter, "boundary"), b))
1717       mutt_param_delete(&new->parameter, "boundary");
1718   } while (!mutt_param_get(&new->parameter, "boundary"));
1719   new->use_disp = false;
1720   new->disposition = DISP_INLINE;
1721   new->parts = b;
1722
1723   return new;
1724 }
1725
1726 /**
1727  * mutt_remove_multipart - Extract the multipart body if it exists
1728  * @param b Body to alter
1729  * @retval ptr The parts of the Body
1730  *
1731  * @note The original Body is freed
1732  */
1733 struct Body *mutt_remove_multipart(struct Body *b)
1734 {
1735   struct Body *t = NULL;
1736
1737   if (b->parts)
1738   {
1739     t = b;
1740     b = b->parts;
1741     t->parts = NULL;
1742     mutt_body_free(&t);
1743   }
1744   return b;
1745 }
1746
1747 /**
1748  * mutt_write_addrlist - wrapper around mutt_write_address()
1749  * @param al      Address list
1750  * @param fp      File to write to
1751  * @param linelen Line length to use
1752  * @param display True if these addresses will be displayed to the user
1753  *
1754  * So we can handle very large recipient lists without needing a huge temporary
1755  * buffer in memory
1756  */
1757 void mutt_write_addrlist(struct AddressList *al, FILE *fp, int linelen, bool display)
1758 {
1759   char buf[1024];
1760   int count = 0;
1761
1762   struct Address *a = NULL;
1763   TAILQ_FOREACH(a, al, entries)
1764   {
1765     buf[0] = '\0';
1766     mutt_addr_write(buf, sizeof(buf), a, display);
1767     size_t len = mutt_str_strlen(buf);
1768     if (count && (linelen + len > 74))
1769     {
1770       fputs("\n\t", fp);
1771       linelen = len + 8; /* tab is usually about 8 spaces... */
1772     }
1773     else
1774     {
1775       if (count && a->mailbox)
1776       {
1777         fputc(' ', fp);
1778         linelen++;
1779       }
1780       linelen += len;
1781     }
1782     fputs(buf, fp);
1783     struct Address *next = TAILQ_NEXT(a, entries);
1784     if (!a->group && next && next->mailbox)
1785     {
1786       linelen++;
1787       fputc(',', fp);
1788     }
1789     count++;
1790   }
1791   fputc('\n', fp);
1792 }
1793
1794 /**
1795  * mutt_write_references - Add the message references to a list
1796  * @param r    String List of references
1797  * @param fp   File to write to
1798  * @param trim Trim the list to at most this many items
1799  *
1800  * Write the list in reverse because they are stored in reverse order when
1801  * parsed to speed up threading.
1802  */
1803 void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
1804 {
1805   struct ListNode *np = NULL;
1806   size_t length = 0;
1807
1808   STAILQ_FOREACH(np, r, entries)
1809   {
1810     if (++length == trim)
1811       break;
1812   }
1813
1814   struct ListNode **ref = mutt_mem_calloc(length, sizeof(struct ListNode *));
1815
1816   // store in reverse order
1817   size_t tmp = length;
1818   STAILQ_FOREACH(np, r, entries)
1819   {
1820     ref[--tmp] = np;
1821     if (tmp == 0)
1822       break;
1823   }
1824
1825   for (size_t i = 0; i < length; i++)
1826   {
1827     fputc(' ', fp);
1828     fputs(ref[i]->data, fp);
1829     if (i != length - 1)
1830       fputc('\n', fp);
1831   }
1832
1833   FREE(&ref);
1834 }
1835
1836 /**
1837  * print_val - Add pieces to an email header, wrapping where necessary
1838  * @param fp      File to write to
1839  * @param pfx     Prefix for headers
1840  * @param value   Text to be added
1841  * @param chflags Flags, see #CopyHeaderFlags
1842  * @param col     Column that this text starts at
1843  * @retval  0 Success
1844  * @retval -1 Failure
1845  */
1846 static int print_val(FILE *fp, const char *pfx, const char *value,
1847                      CopyHeaderFlags chflags, size_t col)
1848 {
1849   while (value && (value[0] != '\0'))
1850   {
1851     if (fputc(*value, fp) == EOF)
1852       return -1;
1853     /* corner-case: break words longer than 998 chars by force,
1854      * mandated by RFC5322 */
1855     if (!(chflags & CH_DISPLAY) && (++col >= 998))
1856     {
1857       if (fputs("\n ", fp) < 0)
1858         return -1;
1859       col = 1;
1860     }
1861     if (*value == '\n')
1862     {
1863       if ((value[1] != '\0') && pfx && (pfx[0] != '\0') && (fputs(pfx, fp) == EOF))
1864         return -1;
1865       /* for display, turn folding spaces into folding tabs */
1866       if ((chflags & CH_DISPLAY) && ((value[1] == ' ') || (value[1] == '\t')))
1867       {
1868         value++;
1869         while ((value[0] != '\0') && ((value[0] == ' ') || (value[0] == '\t')))
1870           value++;
1871         if (fputc('\t', fp) == EOF)
1872           return -1;
1873         continue;
1874       }
1875     }
1876     value++;
1877   }
1878   return 0;
1879 }
1880
1881 /**
1882  * fold_one_header - Fold one header line
1883  * @param fp      File to write to
1884  * @param tag     Header key, e.g. "From"
1885  * @param value   Header value
1886  * @param pfx     Prefix for header
1887  * @param wraplen Column to wrap at
1888  * @param chflags Flags, see #CopyHeaderFlags
1889  * @retval  0 Success
1890  * @retval -1 Failure
1891  */
1892 static int fold_one_header(FILE *fp, const char *tag, const char *value,
1893                            const char *pfx, int wraplen, CopyHeaderFlags chflags)
1894 {
1895   const char *p = value;
1896   char buf[8192] = { 0 };
1897   int first = 1, col = 0, l = 0;
1898   const bool display = (chflags & CH_DISPLAY);
1899
1900   mutt_debug(5, "pfx=[%s], tag=[%s], flags=%d value=[%s]\n", pfx, tag, chflags,
1901              NONULL(value));
1902
1903   if (tag && *tag && (fprintf(fp, "%s%s: ", NONULL(pfx), tag) < 0))
1904     return -1;
1905   col = mutt_str_strlen(tag) + ((tag && (tag[0] != '\0')) ? 2 : 0) + mutt_str_strlen(pfx);
1906
1907   while (p && (p[0] != '\0'))
1908   {
1909     int fold = 0;
1910
1911     /* find the next word and place it in 'buf'. it may start with
1912      * whitespace we can fold before */
1913     const char *next = mutt_str_find_word(p);
1914     l = MIN(sizeof(buf) - 1, next - p);
1915     memcpy(buf, p, l);
1916     buf[l] = '\0';
1917
1918     /* determine width: character cells for display, bytes for sending
1919      * (we get pure ascii only) */
1920     const int w = mutt_mb_width(buf, col, display);
1921     const int enc = mutt_str_startswith(buf, "=?", CASE_MATCH);
1922
1923     mutt_debug(5, "word=[%s], col=%d, w=%d, next=[0x0%x]\n", buf, col, w, *next);
1924
1925     /* insert a folding \n before the current word's lwsp except for
1926      * header name, first word on a line (word longer than wrap width)
1927      * and encoded words */
1928     if (!first && !enc && col && ((col + w) >= wraplen))
1929     {
1930       col = mutt_str_strlen(pfx);
1931       fold = 1;
1932       if (fprintf(fp, "\n%s", NONULL(pfx)) <= 0)
1933         return -1;
1934     }
1935
1936     /* print the actual word; for display, ignore leading ws for word
1937      * and fold with tab for readability */
1938     if (display && fold)
1939     {
1940       char *pc = buf;
1941       while ((pc[0] != '\0') && ((pc[0] == ' ') || (pc[0] == '\t')))
1942       {
1943         pc++;
1944         col--;
1945       }
1946       if (fputc('\t', fp) == EOF)
1947         return -1;
1948       if (print_val(fp, pfx, pc, chflags, col) < 0)
1949         return -1;
1950       col += 8;
1951     }
1952     else if (print_val(fp, pfx, buf, chflags, col) < 0)
1953       return -1;
1954     col += w;
1955
1956     /* if the current word ends in \n, ignore all its trailing spaces
1957      * and reset column; this prevents us from putting only spaces (or
1958      * even none) on a line if the trailing spaces are located at our
1959      * current line width
1960      * XXX this covers ASCII space only, for display we probably
1961      * want something like iswspace() here */
1962     const char *sp = next;
1963     while ((sp[0] != '\0') && ((sp[0] == ' ') || (sp[0] == '\t')))
1964       sp++;
1965     if (sp[0] == '\n')
1966     {
1967       next = sp;
1968       col = 0;
1969     }
1970
1971     p = next;
1972     first = 0;
1973   }
1974
1975   /* if we have printed something but didn't \n-terminate it, do it
1976    * except the last word we printed ended in \n already */
1977   if (col && ((l == 0) || (buf[l - 1] != '\n')))
1978     if (putc('\n', fp) == EOF)
1979       return -1;
1980
1981   return 0;
1982 }
1983
1984 /**
1985  * unfold_header - Unfold a wrapped email header
1986  * @param s String to process
1987  * @retval ptr Unfolded string
1988  *
1989  * @note The string is altered in-place
1990  */
1991 static char *unfold_header(char *s)
1992 {
1993   char *p = s;
1994   char *q = s;
1995
1996   while (p && (p[0] != '\0'))
1997   {
1998     /* remove CRLF prior to FWSP, turn \t into ' ' */
1999     if ((p[0] == '\r') && (p[1] != '\0') && (p[1] == '\n') && (p[2] != '\0') &&
2000         ((p[2] == ' ') || (p[2] == '\t')))
2001     {
2002       *q++ = ' ';
2003       p += 3;
2004       continue;
2005     }
2006     /* remove LF prior to FWSP, turn \t into ' ' */
2007     else if ((p[0] == '\n') && (p[1] != '\0') && ((p[1] == ' ') || (p[1] == '\t')))
2008     {
2009       *q++ = ' ';
2010       p += 2;
2011       continue;
2012     }
2013     *q++ = *p++;
2014   }
2015   if (q)
2016     q[0] = '\0';
2017
2018   return s;
2019 }
2020
2021 /**
2022  * write_one_header - Write out one header line
2023  * @param fp      File to write to
2024  * @param pfxw    Width of prefix string
2025  * @param max     Max width
2026  * @param wraplen Column to wrap at
2027  * @param pfx     Prefix for header
2028  * @param start   Start of header line
2029  * @param end     End of header line
2030  * @param chflags Flags, see #CopyHeaderFlags
2031  * @retval  0 Success
2032  * @retval -1 Failure
2033  */
2034 static int write_one_header(FILE *fp, int pfxw, int max, int wraplen, const char *pfx,
2035                             const char *start, const char *end, CopyHeaderFlags chflags)
2036 {
2037   char *tagbuf = NULL, *valbuf = NULL, *t = NULL;
2038   bool is_from = ((end - start) > 5) && mutt_str_startswith(start, "from ", CASE_IGNORE);
2039
2040   /* only pass through folding machinery if necessary for sending,
2041    * never wrap From_ headers on sending */
2042   if (!(chflags & CH_DISPLAY) && ((pfxw + max <= wraplen) || is_from))
2043   {
2044     valbuf = mutt_str_substr_dup(start, end);
2045     mutt_debug(5, "buf[%s%s] short enough, max width = %d <= %d\n", NONULL(pfx),
2046                valbuf, max, wraplen);
2047     if (pfx && *pfx)
2048     {
2049       if (fputs(pfx, fp) == EOF)
2050       {
2051         FREE(&valbuf);
2052         return -1;
2053       }
2054     }
2055
2056     t = strchr(valbuf, ':');
2057     if (!t)
2058     {
2059       mutt_debug(LL_DEBUG1, "#1 warning: header not in 'key: value' format!\n");
2060       FREE(&valbuf);
2061       return 0;
2062     }
2063     if (print_val(fp, pfx, valbuf, chflags, mutt_str_strlen(pfx)) < 0)
2064     {
2065       FREE(&valbuf);
2066       return -1;
2067     }
2068     FREE(&valbuf);
2069   }
2070   else
2071   {
2072     t = strchr(start, ':');
2073     if (!t || (t > end))
2074     {
2075       mutt_debug(LL_DEBUG1, "#2 warning: header not in 'key: value' format!\n");
2076       return 0;
2077     }
2078     if (is_from)
2079     {
2080       tagbuf = NULL;
2081       valbuf = mutt_str_substr_dup(start, end);
2082     }
2083     else
2084     {
2085       tagbuf = mutt_str_substr_dup(start, t);
2086       /* skip over the colon separating the header field name and value */
2087       t++;
2088
2089       /* skip over any leading whitespace (WSP, as defined in RFC5322)
2090        * NOTE: mutt_str_skip_email_wsp() does the wrong thing here.
2091        *       See tickets 3609 and 3716. */
2092       while ((*t == ' ') || (*t == '\t'))
2093         t++;
2094
2095       valbuf = mutt_str_substr_dup(t, end);
2096     }
2097     mutt_debug(LL_DEBUG2, "buf[%s%s] too long, max width = %d > %d\n",
2098                NONULL(pfx), NONULL(valbuf), max, wraplen);
2099     if (fold_one_header(fp, tagbuf, valbuf, pfx, wraplen, chflags) < 0)
2100     {
2101       FREE(&valbuf);
2102       FREE(&tagbuf);
2103       return -1;
2104     }
2105     FREE(&tagbuf);
2106     FREE(&valbuf);
2107   }
2108   return 0;
2109 }
2110
2111 /**
2112  * mutt_write_one_header - Write one header line to a file
2113  * @param fp      File to write to
2114  * @param tag     Header key, e.g. "From"
2115  * @param value   Header value
2116  * @param pfx     Prefix for header
2117  * @param wraplen Column to wrap at
2118  * @param chflags Flags, see #CopyHeaderFlags
2119  * @retval  0 Success
2120  * @retval -1 Failure
2121  *
2122  * split several headers into individual ones and call write_one_header
2123  * for each one
2124  */
2125 int mutt_write_one_header(FILE *fp, const char *tag, const char *value,
2126                           const char *pfx, int wraplen, CopyHeaderFlags chflags)
2127 {
2128   char *p = (char *) value;
2129   char *last = NULL, *line = NULL;
2130   int max = 0, w, rc = -1;
2131   int pfxw = mutt_strwidth(pfx);
2132   char *v = mutt_str_strdup(value);
2133   bool display = (chflags & CH_DISPLAY);
2134
2135   if (!display || C_Weed)
2136     v = unfold_header(v);
2137
2138   /* when not displaying, use sane wrap value */
2139   if (!display)
2140   {
2141     if ((C_WrapHeaders < 78) || (C_WrapHeaders > 998))
2142       wraplen = 78;
2143     else
2144       wraplen = C_WrapHeaders;
2145   }
2146   else if ((wraplen <= 0) || (wraplen > MuttIndexWindow->cols))
2147     wraplen = MuttIndexWindow->cols;
2148
2149   if (tag)
2150   {
2151     /* if header is short enough, simply print it */
2152     if (!display && (mutt_strwidth(tag) + 2 + pfxw + mutt_strwidth(v) <= wraplen))
2153     {
2154       mutt_debug(5, "buf[%s%s: %s] is short enough\n", NONULL(pfx), tag, v);
2155       if (fprintf(fp, "%s%s: %s\n", NONULL(pfx), tag, v) <= 0)
2156         goto out;
2157       rc = 0;
2158       goto out;
2159     }
2160     else
2161     {
2162       rc = fold_one_header(fp, tag, v, pfx, wraplen, chflags);
2163       goto out;
2164     }
2165   }
2166
2167   p = v;
2168   last = v;
2169   line = v;
2170   while (p && *p)
2171   {
2172     p = strchr(p, '\n');
2173
2174     /* find maximum line width in current header */
2175     if (p)
2176       *p = '\0';
2177     w = mutt_mb_width(line, 0, display);
2178     if (w > max)
2179       max = w;
2180     if (p)
2181       *p = '\n';
2182
2183     if (!p)
2184       break;
2185
2186     line = ++p;
2187     if ((*p != ' ') && (*p != '\t'))
2188     {
2189       if (write_one_header(fp, pfxw, max, wraplen, pfx, last, p, chflags) < 0)
2190         goto out;
2191       last = p;
2192       max = 0;
2193     }
2194   }
2195
2196   if (last && *last)
2197     if (write_one_header(fp, pfxw, max, wraplen, pfx, last, p, chflags) < 0)
2198       goto out;
2199
2200   rc = 0;
2201
2202 out:
2203   FREE(&v);
2204   return rc;
2205 }
2206
2207 /**
2208  * mutt_rfc822_write_header - Write out one RFC822 header line
2209  * @param fp      File to write to
2210  * @param env     Envelope of email
2211  * @param attach  Attachment
2212  * @param mode    Mode, see #MuttWriteHeaderMode
2213  * @param privacy If true, remove headers that might identify the user
2214  * @param hide_protected_subject If true, replace subject header
2215  * @retval  0 Success
2216  * @retval -1 Failure
2217  *
2218  * Note: all RFC2047 encoding should be done outside of this routine, except
2219  * for the "real name."  This will allow this routine to be used more than
2220  * once, if necessary.
2221  *
2222  * Likewise, all IDN processing should happen outside of this routine.
2223  *
2224  * privacy true => will omit any headers which may identify the user.
2225  *               Output generated is suitable for being sent through
2226  *               anonymous remailer chains.
2227  *
2228  * hide_protected_subject: replaces the Subject header with
2229  * $crypt_protected_headers_subject in NORMAL or POSTPONE mode.
2230  */
2231 int mutt_rfc822_write_header(FILE *fp, struct Envelope *env,
2232                              struct Body *attach, enum MuttWriteHeaderMode mode,
2233                              bool privacy, bool hide_protected_subject)
2234 {
2235   char buf[1024];
2236   char *p = NULL, *q = NULL;
2237   bool has_agent = false; /* user defined user-agent header field exists */
2238
2239   if ((mode == MUTT_WRITE_HEADER_NORMAL) && !privacy)
2240     fputs(mutt_date_make_date(buf, sizeof(buf)), fp);
2241
2242   /* UseFrom is not consulted here so that we can still write a From:
2243    * field if the user sets it with the 'my_hdr' command */
2244   if (!TAILQ_EMPTY(&env->from) && !privacy)
2245   {
2246     buf[0] = '\0';
2247     mutt_addrlist_write(buf, sizeof(buf), &env->from, false);
2248     fprintf(fp, "From: %s\n", buf);
2249   }
2250
2251   if (!TAILQ_EMPTY(&env->sender) && !privacy)
2252   {
2253     buf[0] = '\0';
2254     mutt_addrlist_write(buf, sizeof(buf), &env->sender, false);
2255     fprintf(fp, "Sender: %s\n", buf);
2256   }
2257
2258   if (!TAILQ_EMPTY(&env->to))
2259   {
2260     fputs("To: ", fp);
2261     mutt_write_addrlist(&env->to, fp, 4, 0);
2262   }
2263   else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2264 #ifdef USE_NNTP
2265     if (!OptNewsSend)
2266 #endif
2267       fputs("To:\n", fp);
2268
2269   if (!TAILQ_EMPTY(&env->cc))
2270   {
2271     fputs("Cc: ", fp);
2272     mutt_write_addrlist(&env->cc, fp, 4, 0);
2273   }
2274   else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2275 #ifdef USE_NNTP
2276     if (!OptNewsSend)
2277 #endif
2278       fputs("Cc:\n", fp);
2279
2280   if (!TAILQ_EMPTY(&env->bcc))
2281   {
2282     if ((mode == MUTT_WRITE_HEADER_POSTPONE) || (mode == MUTT_WRITE_HEADER_EDITHDRS) ||
2283         ((mode == MUTT_WRITE_HEADER_NORMAL) && C_WriteBcc))
2284     {
2285       fputs("Bcc: ", fp);
2286       mutt_write_addrlist(&env->bcc, fp, 5, 0);
2287     }
2288   }
2289   else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2290 #ifdef USE_NNTP
2291     if (!OptNewsSend)
2292 #endif
2293       fputs("Bcc:\n", fp);
2294
2295 #ifdef USE_NNTP
2296   if (env->newsgroups)
2297     fprintf(fp, "Newsgroups: %s\n", env->newsgroups);
2298   else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend)
2299     fputs("Newsgroups:\n", fp);
2300
2301   if (env->followup_to)
2302     fprintf(fp, "Followup-To: %s\n", env->followup_to);
2303   else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend)
2304     fputs("Followup-To:\n", fp);
2305
2306   if (env->x_comment_to)
2307     fprintf(fp, "X-Comment-To: %s\n", env->x_comment_to);
2308   else if ((mode == MUTT_WRITE_HEADER_EDITHDRS) && OptNewsSend && C_XCommentTo)
2309     fputs("X-Comment-To:\n", fp);
2310 #endif
2311
2312   if (env->subject)
2313   {
2314     if (hide_protected_subject &&
2315         ((mode == MUTT_WRITE_HEADER_NORMAL) || (mode == MUTT_WRITE_HEADER_POSTPONE)))
2316       mutt_write_one_header(fp, "Subject", C_CryptProtectedHeadersSubject, NULL, 0, CH_NO_FLAGS);
2317     else
2318       mutt_write_one_header(fp, "Subject", env->subject, NULL, 0, CH_NO_FLAGS);
2319   }
2320   else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2321     fputs("Subject:\n", fp);
2322
2323   /* save message id if the user has set it */
2324   if (env->message_id && !privacy)
2325     fprintf(fp, "Message-ID: %s\n", env->message_id);
2326
2327   if (!TAILQ_EMPTY(&env->reply_to))
2328   {
2329     fputs("Reply-To: ", fp);
2330     mutt_write_addrlist(&env->reply_to, fp, 10, 0);
2331   }
2332   else if (mode == MUTT_WRITE_HEADER_EDITHDRS)
2333     fputs("Reply-To:\n", fp);
2334
2335   if (!TAILQ_EMPTY(&env->mail_followup_to))
2336 #ifdef USE_NNTP
2337     if (!OptNewsSend)
2338 #endif
2339     {
2340       fputs("Mail-Followup-To: ", fp);
2341       mutt_write_addrlist(&env->mail_followup_to, fp, 18, 0);
2342     }
2343
2344   if ((mode == MUTT_WRITE_HEADER_NORMAL) || (mode == MUTT_WRITE_HEADER_POSTPONE))
2345   {
2346     if (!STAILQ_EMPTY(&env->references))
2347     {
2348       fputs("References:", fp);
2349       mutt_write_references(&env->references, fp, 10);
2350       fputc('\n', fp);
2351     }
2352
2353     /* Add the MIME headers */
2354     fputs("MIME-Version: 1.0\n", fp);
2355     mutt_write_mime_header(attach, fp);
2356   }
2357
2358   if (!STAILQ_EMPTY(&env->in_reply_to))
2359   {
2360     fputs("In-Reply-To:", fp);
2361     mutt_write_references(&env->in_reply_to, fp, 0);
2362     fputc('\n', fp);
2363   }
2364
2365   /* Add any user defined headers */
2366   struct ListNode *tmp = NULL;
2367   STAILQ_FOREACH(tmp, &env->userhdrs, entries)
2368   {
2369     p = strchr(tmp->data, ':');
2370     if (p)
2371     {
2372       q = p;
2373
2374       *p = '\0';
2375
2376       p = mutt_str_skip_email_wsp(p + 1);
2377       if (!*p)
2378       {
2379         *q = ':';
2380         continue; /* don't emit empty fields. */
2381       }
2382
2383       /* check to see if the user has overridden the user-agent field */
2384       if (mutt_str_startswith(tmp->data, "user-agent", CASE_IGNORE))
2385       {
2386         has_agent = true;
2387         if (privacy)
2388         {
2389           *q = ':';
2390           continue;
2391         }
2392       }
2393
2394       mutt_write_one_header(fp, tmp->data, p, NULL, 0, CH_NO_FLAGS);
2395       *q = ':';
2396     }
2397   }
2398
2399   if ((mode == MUTT_WRITE_HEADER_NORMAL) && !privacy && C_UserAgent && !has_agent)
2400   {
2401     /* Add a vanity header */
2402     fprintf(fp, "User-Agent: NeoMutt/%s%s\n", PACKAGE_VERSION, GitVer);
2403   }
2404
2405   return (ferror(fp) == 0) ? 0 : -1;
2406 }
2407
2408 /**
2409  * encode_headers - RFC2047-encode a list of headers
2410  * @param h String List of headers
2411  *
2412  * The strings are encoded in-place.
2413  */
2414 static void encode_headers(struct ListHead *h)
2415 {
2416   char *tmp = NULL;
2417   char *p = NULL;
2418   int i;
2419
2420   struct ListNode *np = NULL;
2421   STAILQ_FOREACH(np, h, entries)
2422   {
2423     p = strchr(np->data, ':');
2424     if (!p)
2425       continue;
2426
2427     i = p - np->data;
2428     p = mutt_str_skip_email_wsp(p + 1);
2429     tmp = mutt_str_strdup(p);
2430
2431     if (!tmp)
2432       continue;
2433
2434     rfc2047_encode(&tmp, NULL, i + 2, C_SendCharset);
2435     mutt_mem_realloc(&np->data, i + 2 + mutt_str_strlen(tmp) + 1);
2436
2437     sprintf(np->data + i + 2, "%s", tmp);
2438
2439     FREE(&tmp);
2440   }
2441 }
2442
2443 /**
2444  * mutt_fqdn - Get the Fully-Qualified Domain Name
2445  * @param may_hide_host If true, hide the hostname (leaving just the domain)
2446  * @retval ptr  string pointer into Hostname
2447  * @retval NULL Error, e.g no Hostname
2448  *
2449  * @warning Do not free the returned pointer
2450  */
2451 const char *mutt_fqdn(bool may_hide_host)
2452 {
2453   if (!C_Hostname || (C_Hostname[0] == '@'))
2454     return NULL;
2455
2456   char *p = C_Hostname;
2457
2458   if (may_hide_host && C_HiddenHost)
2459   {
2460     p = strchr(C_Hostname, '.');
2461     if (p)
2462       p++;
2463
2464     // sanity check: don't hide the host if the fqdn is something like example.com
2465     if (!p || !strchr(p, '.'))
2466       p = C_Hostname;
2467   }
2468
2469   return p;
2470 }
2471
2472 /**
2473  * gen_msgid - Generate a unique Message ID
2474  * @retval ptr Message ID
2475  *
2476  * @note The caller should free the string
2477  */
2478 static char *gen_msgid(void)
2479 {
2480   char buf[128];
2481   unsigned char rndid[MUTT_RANDTAG_LEN + 1];
2482
2483   mutt_rand_base32(rndid, sizeof(rndid) - 1);
2484   rndid[MUTT_RANDTAG_LEN] = 0;
2485   const char *fqdn = mutt_fqdn(false);
2486   if (!fqdn)
2487     fqdn = NONULL(ShortHostname);
2488
2489   struct tm tm = mutt_date_gmtime(MUTT_DATE_NOW);
2490   snprintf(buf, sizeof(buf), "<%d%02d%02d%02d%02d%02d.%s@%s>", tm.tm_year + 1900,
2491            tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, rndid, fqdn);
2492   return mutt_str_strdup(buf);
2493 }
2494
2495 /**
2496  * alarm_handler - Async notification of an alarm signal
2497  * @param sig Signal, (SIGALRM)
2498  */
2499 static void alarm_handler(int sig)
2500 {
2501   SigAlrm = 1;
2502 }
2503
2504 /**
2505  * send_msg - invoke sendmail in a subshell
2506  * @param[in]  path     Path to program to execute
2507  * @param[in]  args     Arguments to pass to program
2508  * @param[in]  msg      Temp file containing message to send
2509  * @param[out] tempfile If sendmail is put in the background, this points
2510  *                      to the temporary file containing the stdout of the
2511  *                      child process. If it is NULL, stderr and stdout
2512  *                      are not redirected.
2513  * @retval  0 Success
2514  * @retval >0 Failure, return code from sendmail
2515  */
2516 static int send_msg(const char *path, char **args, const char *msg, char **tempfile)
2517 {
2518   sigset_t set;
2519   int st;
2520
2521   mutt_sig_block_system();
2522
2523   sigemptyset(&set);
2524   /* we also don't want to be stopped right now */
2525   sigaddset(&set, SIGTSTP);
2526   sigprocmask(SIG_BLOCK, &set, NULL);
2527
2528   if ((C_SendmailWait >= 0) && tempfile)
2529   {
2530     char tmp[PATH_MAX];
2531
2532     mutt_mktemp(tmp, sizeof(tmp));
2533     *tempfile = mutt_str_strdup(tmp);
2534   }
2535
2536   pid_t pid = fork();
2537   if (pid == 0)
2538   {
2539     struct sigaction act, oldalrm;
2540
2541     /* save parent's ID before setsid() */
2542     pid_t ppid = getppid();
2543
2544     /* we want the delivery to continue even after the main process dies,
2545      * so we put ourselves into another session right away */
2546     setsid();
2547
2548     /* next we close all open files */
2549     close(0);
2550 #ifdef OPEN_MAX
2551     for (int fd = tempfile ? 1 : 3; fd < OPEN_MAX; fd++)
2552       close(fd);
2553 #elif defined(_POSIX_OPEN_MAX)
2554     for (int fd = tempfile ? 1 : 3; fd < _POSIX_OPEN_MAX; fd++)
2555       close(fd);
2556 #else
2557     if (tempfile)
2558     {
2559       close(1);
2560       close(2);
2561     }
2562 #endif
2563
2564     /* now the second fork() */
2565     pid = fork();
2566     if (pid == 0)
2567     {
2568       /* "msg" will be opened as stdin */
2569       if (open(msg, O_RDONLY, 0) < 0)
2570       {
2571         unlink(msg);
2572         _exit(S_ERR);
2573       }
2574       unlink(msg);
2575
2576       if ((C_SendmailWait >= 0) && tempfile && *tempfile)
2577       {
2578         /* *tempfile will be opened as stdout */
2579         if (open(*tempfile, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0600) < 0)
2580           _exit(S_ERR);
2581         /* redirect stderr to *tempfile too */
2582         if (dup(1) < 0)
2583           _exit(S_ERR);
2584       }
2585       else if (tempfile)
2586       {
2587         if (open("/dev/null", O_WRONLY | O_APPEND) < 0) /* stdout */
2588           _exit(S_ERR);
2589         if (open("/dev/null", O_RDWR | O_APPEND) < 0) /* stderr */
2590           _exit(S_ERR);
2591       }
2592
2593       /* execvpe is a glibc extension */
2594       /* execvpe (path, args, mutt_envlist_getlist()); */
2595       execvp(path, args);
2596       _exit(S_ERR);
2597     }
2598     else if (pid == -1)
2599     {
2600       unlink(msg);
2601       FREE(tempfile);
2602       _exit(S_ERR);
2603     }
2604
2605     /* C_SendmailWait > 0: interrupt waitpid() after C_SendmailWait seconds
2606      * C_SendmailWait = 0: wait forever
2607      * C_SendmailWait < 0: don't wait */
2608     if (C_SendmailWait > 0)
2609     {
2610       SigAlrm = 0;
2611       act.sa_handler = alarm_handler;
2612 #ifdef SA_INTERRUPT
2613       /* need to make sure waitpid() is interrupted on SIGALRM */
2614       act.sa_flags = SA_INTERRUPT;
2615 #else
2616       act.sa_flags = 0;
2617 #endif
2618       sigemptyset(&act.sa_mask);
2619       sigaction(SIGALRM, &act, &oldalrm);
2620       alarm(C_SendmailWait);
2621     }
2622     else if (C_SendmailWait < 0)
2623       _exit(0xff & EX_OK);
2624
2625     if (waitpid(pid, &st, 0) > 0)
2626     {
2627       st = WIFEXITED(st) ? WEXITSTATUS(st) : S_ERR;
2628       if (C_SendmailWait && (st == (0xff & EX_OK)) && tempfile && *tempfile)
2629       {
2630         unlink(*tempfile); /* no longer needed */
2631         FREE(tempfile);
2632       }
2633     }
2634     else
2635     {
2636       st = ((C_SendmailWait > 0) && (errno == EINTR) && SigAlrm) ? S_BKG : S_ERR;
2637       if ((C_SendmailWait > 0) && tempfile && *tempfile)
2638       {
2639         unlink(*tempfile);
2640         FREE(tempfile);
2641       }
2642     }
2643
2644     if (C_SendmailWait > 0)
2645     {
2646       /* reset alarm; not really needed, but... */
2647       alarm(0);
2648       sigaction(SIGALRM, &oldalrm, NULL);
2649     }
2650
2651     if ((kill(ppid, 0) == -1) && (errno == ESRCH) && tempfile && *tempfile)
2652     {
2653       /* the parent is already dead */
2654       unlink(*tempfile);
2655       FREE(tempfile);
2656     }
2657
2658     _exit(st);
2659   }
2660
2661   sigprocmask(SIG_UNBLOCK, &set, NULL);
2662
2663   if ((pid != -1) && (waitpid(pid, &st, 0) > 0))
2664     st = WIFEXITED(st) ? WEXITSTATUS(st) : S_ERR; /* return child status */
2665   else
2666     st = S_ERR; /* error */
2667
2668   mutt_sig_unblock_system(true);
2669
2670   return st;
2671 }
2672
2673 /**
2674  * add_args_one - Add an Address to a dynamic array
2675  * @param[out] args    Array to add to
2676  * @param[out] argslen Number of entries in array
2677  * @param[out] argsmax Allocated size of the array
2678  * @param[in]  addr    Address to add
2679  * @retval ptr Updated array
2680  */
2681 static char **add_args_one(char **args, size_t *argslen, size_t *argsmax, struct Address *addr)
2682 {
2683   /* weed out group mailboxes, since those are for display only */
2684   if (addr->mailbox && !addr->group)
2685   {
2686     if (*argslen == *argsmax)
2687       mutt_mem_realloc(&args, (*argsmax += 5) * sizeof(char *));
2688     args[(*argslen)++] = addr->mailbox;
2689   }
2690   return args;
2691 }
2692
2693 /**
2694  * add_args - Add a list of Addresses to a dynamic array
2695  * @param[out] args    Array to add to
2696  * @param[out] argslen Number of entries in array
2697  * @param[out] argsmax Allocated size of the array
2698  * @param[in]  al      Addresses to add
2699  * @retval ptr Updated array
2700  */
2701 static char **add_args(char **args, size_t *argslen, size_t *argsmax, struct AddressList *al)
2702 {
2703   struct Address *a = NULL;
2704   TAILQ_FOREACH(a, al, entries)
2705   {
2706     args = add_args_one(args, argslen, argsmax, a);
2707   }
2708   return args;
2709 }
2710
2711 /**
2712  * add_option - Add a string to a dynamic array
2713  * @param[out] args    Array to add to
2714  * @param[out] argslen Number of entries in array
2715  * @param[out] argsmax Allocated size of the array
2716  * @param[in]  s       string to add
2717  * @retval ptr Updated array
2718  *
2719  * @note The array may be realloc()'d
2720  */
2721 static char **add_option(char **args, size_t *argslen, size_t *argsmax, char *s)
2722 {
2723   if (*argslen == *argsmax)
2724     mutt_mem_realloc(&args, (*argsmax += 5) * sizeof(char *));
2725   args[(*argslen)++] = s;
2726   return args;
2727 }
2728
2729 /**
2730  * mutt_invoke_sendmail - Run sendmail
2731  * @param from     The sender
2732  * @param to       Recipients
2733  * @param cc       Recipients
2734  * @param bcc      Recipients
2735  * @param msg      File containing message
2736  * @param eightbit Message contains 8bit chars
2737  * @retval  0 Success
2738  * @retval -1 Failure
2739  */
2740 int mutt_invoke_sendmail(struct AddressList *from, struct AddressList *to,
2741                          struct AddressList *cc, struct AddressList *bcc,
2742                          const char *msg, int eightbit)
2743 {
2744   char *ps = NULL, *path = NULL, *s = NULL, *childout = NULL;
2745   char **args = NULL;
2746   size_t argslen = 0, argsmax = 0;
2747   char **extra_args = NULL;
2748   int i;
2749
2750 #ifdef USE_NNTP
2751   if (OptNewsSend)
2752   {
2753     char cmd[1024];
2754
2755     mutt_expando_format(cmd, sizeof(cmd), 0, MuttIndexWindow->cols,
2756                         NONULL(C_Inews), nntp_format_str, 0, MUTT_FORMAT_NO_FLAGS);
2757     if (!*cmd)
2758     {
2759       i = nntp_post(Context->mailbox, msg);
2760       unlink(msg);
2761       return i;
2762     }
2763
2764     s = mutt_str_strdup(cmd);
2765   }
2766   else
2767 #endif
2768     s = mutt_str_strdup(C_Sendmail);
2769
2770   /* ensure that $sendmail is set to avoid a crash. http://dev.mutt.org/trac/ticket/3548 */
2771   if (!s)
2772   {
2773     mutt_error(_("$sendmail must be set in order to send mail"));
2774     return -1;
2775   }
2776
2777   ps = s;
2778   i = 0;
2779   while ((ps = strtok(ps, " ")))
2780   {
2781     if (argslen == argsmax)
2782       mutt_mem_realloc(&args, sizeof(char *) * (argsmax += 5));
2783
2784     if (i)
2785     {
2786       if (mutt_str_strcmp(ps, "--") == 0)
2787         break;
2788       args[argslen++] = ps;
2789     }
2790     else
2791     {
2792       path = mutt_str_strdup(ps);
2793       ps = strrchr(ps, '/');
2794       if (ps)
2795         ps++;
2796       else
2797         ps = path;
2798       args[argslen++] = ps;
2799     }
2800     ps = NULL;
2801     i++;
2802   }
2803
2804 #ifdef USE_NNTP
2805   if (!OptNewsSend)
2806   {
2807 #endif
2808     size_t extra_argslen = 0;
2809     /* If C_Sendmail contained a "--", we save the recipients to append to
2810    * args after other possible options added below. */
2811     if (ps)
2812     {
2813       ps = NULL;
2814       size_t extra_argsmax = 0;
2815       while ((ps = strtok(ps, " ")))
2816       {
2817         if (extra_argslen == extra_argsmax)
2818           mutt_mem_realloc(&extra_args, sizeof(char *) * (extra_argsmax += 5));
2819
2820         extra_args[extra_argslen++] = ps;
2821         ps = NULL;
2822       }
2823     }
2824
2825     if (eightbit && C_Use8bitmime)
2826       args = add_option(args, &argslen, &argsmax, "-B8BITMIME");
2827
2828     if (C_UseEnvelopeFrom)
2829     {
2830       if (C_EnvelopeFromAddress)
2831       {
2832         args = add_option(args, &argslen, &argsmax, "-f");
2833         args = add_args_one(args, &argslen, &argsmax, C_EnvelopeFromAddress);
2834       }
2835       else if (!TAILQ_EMPTY(from) && !TAILQ_NEXT(TAILQ_FIRST(from), entries))
2836       {
2837         args = add_option(args, &argslen, &argsmax, "-f");
2838         args = add_args(args, &argslen, &argsmax, from);
2839       }
2840     }
2841
2842     if (C_DsnNotify)
2843     {
2844       args = add_option(args, &argslen, &argsmax, "-N");
2845       args = add_option(args, &argslen, &argsmax, C_DsnNotify);
2846     }
2847     if (C_DsnReturn)
2848     {
2849       args = add_option(args, &argslen, &argsmax, "-R");
2850       args = add_option(args, &argslen, &argsmax, C_DsnReturn);
2851     }
2852     args = add_option(args, &argslen, &argsmax, "--");
2853     for (i = 0; i < extra_argslen; i++)
2854       args = add_option(args, &argslen, &argsmax, extra_args[i]);
2855     args = add_args(args, &argslen, &argsmax, to);
2856     args = add_args(args, &argslen, &argsmax, cc);
2857     args = add_args(args, &argslen, &argsmax, bcc);
2858 #ifdef USE_NNTP
2859   }
2860 #endif
2861
2862   if (argslen == argsmax)
2863     mutt_mem_realloc(&args, sizeof(char *) * (++argsmax));
2864
2865   args[argslen++] = NULL;
2866
2867   /* Some user's $sendmail command uses gpg for password decryption,
2868    * and is set up to prompt using ncurses pinentry.  If we
2869    * mutt_endwin() it leaves other users staring at a blank screen.
2870    * So instead, just force a hard redraw on the next refresh. */
2871   if (!OptNoCurses)
2872     mutt_need_hard_redraw();
2873
2874   i = send_msg(path, args, msg, OptNoCurses ? NULL : &childout);
2875   if (i != (EX_OK & 0xff))
2876   {
2877     if (i != S_BKG)
2878     {
2879       const char *e = mutt_str_sysexit(i);
2880       mutt_error(_("Error sending message, child exited %d (%s)"), i, NONULL(e));
2881       if (childout)
2882       {
2883         struct stat st;
2884
2885         if ((stat(childout, &st) == 0) && (st.st_size > 0))
2886           mutt_do_pager(_("Output of the delivery process"), childout,
2887                         MUTT_PAGER_NO_FLAGS, NULL);
2888       }
2889     }
2890   }
2891   else if (childout)
2892     unlink(childout);
2893
2894   FREE(&childout);
2895   FREE(&path);
2896   FREE(&s);
2897   FREE(&args);
2898   FREE(&extra_args);
2899
2900   if (i == (EX_OK & 0xff))
2901     i = 0;
2902   else if (i == S_BKG)
2903     i = 1;
2904   else
2905     i = -1;
2906   return i;
2907 }
2908
2909 /**
2910  * mutt_prepare_envelope - Prepare an email header
2911  * @param env   Envelope to prepare
2912  * @param final true if this email is going to be sent (not postponed)
2913  *
2914  * Encode all the headers prior to sending the email.
2915  *
2916  * For postponing (!final) do the necessary encodings only
2917  */
2918 void mutt_prepare_envelope(struct Envelope *env, bool final)
2919 {
2920   if (final)
2921   {
2922     if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
2923     {
2924       /* some MTA's will put an Apparently-To: header field showing the Bcc:
2925        * recipients if there is no To: or Cc: field, so attempt to suppress
2926        * it by using an empty To: field.  */
2927       struct Address *to = mutt_addr_new();
2928       to->group = true;
2929       mutt_addrlist_append(&env->to, to);
2930       mutt_addrlist_append(&env->to, mutt_addr_new());
2931
2932       char buf[1024];
2933       buf[0] = '\0';
2934       mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
2935
2936       to->mailbox = mutt_str_strdup(buf);
2937     }
2938
2939     mutt_set_followup_to(env);
2940
2941     if (!env->message_id)
2942       env->message_id = gen_msgid();
2943   }
2944
2945   /* Take care of 8-bit => 7-bit conversion. */
2946   rfc2047_encode_envelope(env);
2947   encode_headers(&env->userhdrs);
2948 }
2949
2950 /**
2951  * mutt_unprepare_envelope - Undo the encodings of mutt_prepare_envelope()
2952  * @param env Envelope to unprepare
2953  *
2954  * Decode all the headers of an email, e.g. when the sending failed or was
2955  * aborted.
2956  */
2957 void mutt_unprepare_envelope(struct Envelope *env)
2958 {
2959   struct ListNode *item = NULL;
2960   STAILQ_FOREACH(item, &env->userhdrs, entries)
2961   {
2962     rfc2047_decode(&item->data);
2963   }
2964
2965   mutt_addrlist_clear(&env->mail_followup_to);
2966
2967   /* back conversions */
2968   rfc2047_decode_envelope(env);
2969 }
2970
2971 /**
2972  * bounce_message - Bounce an email message
2973  * @param fp          Handle of message
2974  * @param e           Email
2975  * @param to          Address to bounce to
2976  * @param resent_from Address of new sender
2977  * @param env_from    Envelope of original sender
2978  * @retval  0 Success
2979  * @retval -1 Failure
2980  */
2981 static int bounce_message(FILE *fp, struct Email *e, struct AddressList *to,
2982                           const char *resent_from, struct AddressList *env_from)
2983 {
2984   if (!e)
2985     return -1;
2986
2987   int rc = 0;
2988   char tempfile[PATH_MAX];
2989
2990   mutt_mktemp(tempfile, sizeof(tempfile));
2991   FILE *fp_tmp = mutt_file_fopen(tempfile, "w");
2992   if (fp_tmp)
2993   {
2994     char date[128];
2995     CopyHeaderFlags chflags = CH_XMIT | CH_NONEWLINE | CH_NOQFROM;
2996
2997     if (!C_BounceDelivered)
2998       chflags |= CH_WEED_DELIVERED;
2999
3000     fseeko(fp, e->offset, SEEK_SET);
3001     fprintf(fp_tmp, "Resent-From: %s", resent_from);
3002     fprintf(fp_tmp, "\nResent-%s", mutt_date_make_date(date, sizeof(date)));
3003     char *msgid_str = gen_msgid();
3004     fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
3005     FREE(&msgid_str);
3006     fputs("Resent-To: ", fp_tmp);
3007     mutt_write_addrlist(to, fp_tmp, 11, 0);
3008     mutt_copy_header(fp, e, fp_tmp, chflags, NULL);
3009     fputc('\n', fp_tmp);
3010     mutt_file_copy_bytes(fp, fp_tmp, e->content->length);
3011     if (mutt_file_fclose(&fp_tmp) != 0)
3012     {
3013       mutt_perror(tempfile);
3014       unlink(tempfile);
3015       return -1;
3016     }
3017 #ifdef USE_SMTP
3018     if (C_SmtpUrl)
3019       rc = mutt_smtp_send(env_from, to, NULL, NULL, tempfile, e->content->encoding == ENC_8BIT);
3020     else
3021 #endif
3022       rc = mutt_invoke_sendmail(env_from, to, NULL, NULL, tempfile,
3023                                 e->content->encoding == ENC_8BIT);
3024   }
3025
3026   return rc;
3027 }
3028
3029 /**
3030  * mutt_bounce_message - Bounce an email message
3031  * @param fp Handle of message
3032  * @param e  Email
3033  * @param to AddressList to bounce to
3034  * @retval  0 Success
3035  * @retval -1 Failure
3036  */
3037 int mutt_bounce_message(FILE *fp, struct Email *e, struct AddressList *to)
3038 {
3039   if (!fp || !e || !to || TAILQ_EMPTY(to))
3040     return -1;
3041
3042   const char *fqdn = mutt_fqdn(true);
3043   char resent_from[256];
3044   char *err = NULL;
3045
3046   resent_from[0] = '\0';
3047   struct Address *from = mutt_default_from();
3048   struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
3049   mutt_addrlist_append(&from_list, from);
3050
3051   /* mutt_default_from() does not use $realname if the real name is not set
3052    * in $from, so we add it here.  The reason it is not added in
3053    * mutt_default_from() is that during normal sending, we execute
3054    * send-hooks and set the realname last so that it can be changed based
3055    * upon message criteria.  */
3056   if (!from->personal)
3057     from->personal = mutt_str_strdup(C_Realname);
3058
3059   mutt_addrlist_qualify(&from_list, fqdn);
3060
3061   rfc2047_encode_addrlist(&from_list, "Resent-From");
3062   if (mutt_addrlist_to_intl(&from_list, &err))
3063   {
3064     mutt_error(_("Bad IDN %s while preparing resent-from"), err);
3065     FREE(&err);
3066     mutt_addrlist_clear(&from_list);
3067     return -1;
3068   }
3069   mutt_addrlist_write(resent_from, sizeof(resent_from), &from_list, false);
3070
3071 #ifdef USE_NNTP
3072   OptNewsSend = false;
3073 #endif
3074
3075   /* prepare recipient list. idna conversion appears to happen before this
3076    * function is called, since the user receives confirmation of the address
3077    * list being bounced to.  */
3078   struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
3079   mutt_addrlist_copy(&resent_to, to, false);
3080   rfc2047_encode_addrlist(&resent_to, "Resent-To");
3081   int rc = bounce_message(fp, e, &resent_to, resent_from, &from_list);
3082   mutt_addrlist_clear(&resent_to);
3083   mutt_addrlist_clear(&from_list);
3084
3085   return rc;
3086 }
3087
3088 /**
3089  * set_noconv_flags - Set/reset the "x-mutt-noconv" flag
3090  * @param b    Body of email
3091  * @param flag If true, set the flag, otherwise remove it
3092  */
3093 static void set_noconv_flags(struct Body *b, bool flag)
3094 {
3095   for (; b; b = b->next)
3096   {
3097     if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
3098       set_noconv_flags(b->parts, flag);
3099     else if ((b->type == TYPE_TEXT) && b->noconv)
3100     {
3101       if (flag)
3102         mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
3103       else
3104         mutt_param_delete(&b->parameter, "x-mutt-noconv");
3105     }
3106   }
3107 }
3108
3109 /**
3110  * mutt_write_multiple_fcc - Handle FCC with multiple, comma separated entries
3111  * @param[in]  path      Path to mailboxes (comma separated)
3112  * @param[in]  e       Email
3113  * @param[in]  msgid     Message id
3114  * @param[in]  post      If true, postpone message
3115  * @param[in]  fcc       fcc setting to save (postpone only)
3116  * @param[out] finalpath Final path of email
3117  * @retval  0 Success
3118  * @retval -1 Failure
3119  */
3120 int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid,
3121                             bool post, char *fcc, char **finalpath)
3122 {
3123   char fcc_tok[PATH_MAX];
3124   char fcc_expanded[PATH_MAX];
3125
3126   mutt_str_strfcpy(fcc_tok, path, sizeof(fcc_tok));
3127
3128   char *tok = strtok(fcc_tok, ",");
3129   if (!tok)
3130     return -1;
3131
3132   mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
3133   /* mutt_expand_path already called above for the first token */
3134   int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath);
3135   if (status != 0)
3136     return status;
3137
3138   while ((tok = strtok(NULL, ",")))
3139   {
3140     if (!*tok)
3141       continue;
3142
3143     /* Only call mutt_expand_path if tok has some data */
3144     mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
3145     mutt_str_strfcpy(fcc_expanded, tok, sizeof(fcc_expanded));
3146     mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
3147     mutt_debug(LL_DEBUG1, "     Additional mailbox expanded = '%s'\n", fcc_expanded);
3148     status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath);
3149     if (status != 0)
3150       return status;
3151   }
3152
3153   return 0;
3154 }
3155
3156 /**
3157  * mutt_write_fcc - Write email to FCC mailbox
3158  * @param[in]  path      Path to mailbox
3159  * @param[in]  e       Email
3160  * @param[in]  msgid     Message id
3161  * @param[in]  post      If true, postpone message
3162  * @param[in]  fcc       fcc setting to save (postpone only)
3163  * @param[out] finalpath Final path of email
3164  * @retval  0 Success
3165  * @retval -1 Failure
3166  */
3167 int mutt_write_fcc(const char *path, struct Email *e, const char *msgid,
3168                    bool post, char *fcc, char **finalpath)
3169 {
3170   struct Message *msg = NULL;
3171   char tempfile[PATH_MAX];
3172   FILE *fp_tmp = NULL;
3173   int rc = -1;
3174   bool need_mailbox_cleanup = false;
3175   struct stat st;
3176   char buf[128];
3177   MsgOpenFlags onm_flags;
3178
3179   if (post)
3180     set_noconv_flags(e->content, true);
3181
3182 #ifdef RECORD_FOLDER_HOOK
3183   mutt_folder_hook(path, NULL);
3184 #endif
3185   struct Mailbox *m_fcc = mx_path_resolve(path);
3186   bool old_append = m_fcc->append;
3187   struct Context *ctx_fcc = mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET);
3188   if (!ctx_fcc)
3189   {
3190     mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
3191     mailbox_free(&m_fcc);
3192     goto done;
3193   }
3194
3195   /* We need to add a Content-Length field to avoid problems where a line in
3196    * the message body begins with "From " */
3197   if ((ctx_fcc->mailbox->magic == MUTT_MMDF) || (ctx_fcc->mailbox->magic == MUTT_MBOX))
3198   {
3199     mutt_mktemp(tempfile, sizeof(tempfile));
3200     fp_tmp = mutt_file_fopen(tempfile, "w+");
3201     if (!fp_tmp)
3202     {
3203       mutt_perror(tempfile);
3204       mx_mbox_close(&ctx_fcc);
3205       goto done;
3206     }
3207     /* remember new mail status before appending message */
3208     need_mailbox_cleanup = true;
3209     stat(path, &st);
3210   }
3211
3212   e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
3213   onm_flags = MUTT_ADD_FROM;
3214   if (post)
3215     onm_flags |= MUTT_SET_DRAFT;
3216   msg = mx_msg_open_new(ctx_fcc->mailbox, e, onm_flags);
3217   if (!msg)
3218   {
3219     mutt_file_fclose(&fp_tmp);
3220     mx_mbox_close(&ctx_fcc);
3221     goto done;
3222   }
3223
3224   /* post == 1 => postpone message.
3225    * post == 0 => Normal mode.  */
3226   mutt_rfc822_write_header(
3227       msg->fp, e->env, e->content, post ? MUTT_WRITE_HEADER_POSTPONE : MUTT_WRITE_HEADER_NORMAL,
3228       false, C_CryptProtectedHeadersRead && mutt_should_hide_protected_subject(e));
3229
3230   /* (postponement) if this was a reply of some sort, <msgid> contains the
3231    * Message-ID: of message replied to.  Save it using a special X-Mutt-
3232    * header so it can be picked up if the message is recalled at a later
3233    * point in time.  This will allow the message to be marked as replied if
3234    * the same mailbox is still open.  */
3235   if (post && msgid)
3236     fprintf(msg->fp, "X-Mutt-References: %s\n", msgid);
3237
3238   /* (postponement) save the Fcc: using a special X-Mutt- header so that
3239    * it can be picked up when the message is recalled */
3240   if (post && fcc)
3241     fprintf(msg->fp, "X-Mutt-Fcc: %s\n", fcc);
3242
3243   if ((ctx_fcc->mailbox->magic == MUTT_MMDF) || (ctx_fcc->mailbox->magic == MUTT_MBOX))
3244     fprintf(msg->fp, "Status: RO\n");
3245
3246   /* mutt_rfc822_write_header() only writes out a Date: header with
3247    * mode == 0, i.e. _not_ postponement; so write out one ourself */
3248   if (post)
3249     fprintf(msg->fp, "%s", mutt_date_make_date(buf, sizeof(buf)));
3250
3251   /* (postponement) if the mail is to be signed or encrypted, save this info */
3252   if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
3253   {
3254     fputs("X-Mutt-PGP: ", msg->fp);
3255     if (e->security & SEC_ENCRYPT)
3256       fputc('E', msg->fp);
3257     if (e->security & SEC_OPPENCRYPT)
3258       fputc('O', msg->fp);
3259     if (e->security & SEC_SIGN)
3260     {
3261       fputc('S', msg->fp);
3262       if (C_PgpSignAs)
3263         fprintf(msg->fp, "<%s>", C_PgpSignAs);
3264     }
3265     if (e->security & SEC_INLINE)
3266       fputc('I', msg->fp);
3267     fputc('\n', msg->fp);
3268   }
3269
3270   /* (postponement) if the mail is to be signed or encrypted, save this info */
3271   if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
3272   {
3273     fputs("X-Mutt-SMIME: ", msg->fp);
3274     if (e->security & SEC_ENCRYPT)
3275     {
3276       fputc('E', msg->fp);
3277       if (C_SmimeEncryptWith)
3278         fprintf(msg->fp, "C<%s>", C_SmimeEncryptWith);
3279     }
3280     if (e->security & SEC_OPPENCRYPT)
3281       fputc('O', msg->fp);
3282     if (e->security & SEC_SIGN)
3283     {
3284       fputc('S', msg->fp);
3285       if (C_SmimeSignAs)
3286         fprintf(msg->fp, "<%s>", C_SmimeSignAs);
3287     }
3288     if (e->security & SEC_INLINE)
3289       fputc('I', msg->fp);
3290     fputc('\n', msg->fp);
3291   }
3292
3293 #ifdef MIXMASTER
3294   /* (postponement) if the mail is to be sent through a mixmaster
3295    * chain, save that information */
3296
3297   if (post && !STAILQ_EMPTY(&e->chain))
3298   {
3299     fputs("X-Mutt-Mix:", msg->fp);
3300     struct ListNode *p = NULL;
3301     STAILQ_FOREACH(p, &e->chain, entries)
3302     {
3303       fprintf(msg->fp, " %s", (char *) p->data);
3304     }
3305
3306     fputc('\n', msg->fp);
3307   }
3308 #endif
3309
3310   if (fp_tmp)
3311   {
3312     mutt_write_mime_body(e->content, fp_tmp);
3313
3314     /* make sure the last line ends with a newline.  Emacs doesn't ensure this
3315      * will happen, and it can cause problems parsing the mailbox later.  */
3316     fseek(fp_tmp, -1, SEEK_END);
3317     if (fgetc(fp_tmp) != '\n')
3318     {
3319       fseek(fp_tmp, 0, SEEK_END);
3320       fputc('\n', fp_tmp);
3321     }
3322
3323     fflush(fp_tmp);
3324     if (ferror(fp_tmp))
3325     {
3326       mutt_debug(LL_DEBUG1, "%s: write failed\n", tempfile);
3327       mutt_file_fclose(&fp_tmp);
3328       unlink(tempfile);
3329       mx_msg_commit(ctx_fcc->mailbox, msg); /* XXX really? */
3330       mx_msg_close(ctx_fcc->mailbox, &msg);
3331       mx_mbox_close(&ctx_fcc);
3332       goto done;
3333     }
3334
3335     /* count the number of lines */
3336     int lines = 0;
3337     char line_buf[1024];
3338     rewind(fp_tmp);
3339     while (fgets(line_buf, sizeof(line_buf), fp_tmp))
3340       lines++;
3341     fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
3342     fprintf(msg->fp, "Lines: %d\n\n", lines);
3343
3344     /* copy the body and clean up */
3345     rewind(fp_tmp);
3346     rc = mutt_file_copy_stream(fp_tmp, msg->fp);
3347     if (fclose(fp_tmp) != 0)
3348       rc = -1;
3349     /* if there was an error, leave the temp version */
3350     if (rc == 0)
3351       unlink(tempfile);
3352   }
3353   else
3354   {
3355     fputc('\n', msg->fp); /* finish off the header */
3356     rc = mutt_write_mime_body(e->content, msg->fp);
3357   }
3358
3359   if (mx_msg_commit(ctx_fcc->mailbox, msg) != 0)
3360     rc = -1;
3361   else if (finalpath)
3362     *finalpath = mutt_str_strdup(msg->committed_path);
3363   mx_msg_close(ctx_fcc->mailbox, &msg);
3364   mx_mbox_close(&ctx_fcc);
3365
3366   if (!post && need_mailbox_cleanup)
3367     mutt_mailbox_cleanup(path, &st);
3368
3369   if (post)
3370     set_noconv_flags(e->content, false);
3371
3372 done:
3373   m_fcc->append = old_append;
3374 #ifdef RECORD_FOLDER_HOOK
3375   /* We ran a folder hook for the destination mailbox,
3376    * now we run it for the user's current mailbox */
3377   if (Context && Context->mailbox->path)
3378     mutt_folder_hook(Context->mailbox->path, Context->mailbox->desc);
3379 #endif
3380
3381   return rc;
3382 }