NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
sendlib.c
Go to the documentation of this file.
1 
31 #include "config.h"
32 #include <errno.h>
33 #include <iconv.h>
34 #include <inttypes.h> // IWYU pragma: keep
35 #include <limits.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <sys/stat.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include "mutt/lib.h"
43 #include "address/lib.h"
44 #include "config/lib.h"
45 #include "email/lib.h"
46 #include "core/lib.h"
47 #include "mutt.h"
48 #include "sendlib.h"
49 #include "lib.h"
50 #include "ncrypt/lib.h"
51 #include "attachments.h"
52 #include "copy.h"
53 #include "handler.h"
54 #include "mutt_globals.h"
55 #include "mutt_mailbox.h"
56 #include "muttlib.h"
57 #include "mx.h"
58 #include "options.h"
59 
64 {
65  bool from;
67  bool dot;
68  int linelen;
69  bool was_cr;
70 };
71 
79 static void update_content_info(struct Content *info, struct ContentState *s,
80  char *buf, size_t buflen)
81 {
82  bool from = s->from;
83  int whitespace = s->whitespace;
84  bool dot = s->dot;
85  int linelen = s->linelen;
86  bool was_cr = s->was_cr;
87 
88  if (!buf) /* This signals EOF */
89  {
90  if (was_cr)
91  info->binary = true;
92  if (linelen > info->linemax)
93  info->linemax = linelen;
94 
95  return;
96  }
97 
98  for (; buflen; buf++, buflen--)
99  {
100  char ch = *buf;
101 
102  if (was_cr)
103  {
104  was_cr = false;
105  if (ch == '\n')
106  {
107  if (whitespace)
108  info->space = true;
109  if (dot)
110  info->dot = true;
111  if (linelen > info->linemax)
112  info->linemax = linelen;
113  whitespace = 0;
114  dot = false;
115  linelen = 0;
116  continue;
117  }
118 
119  info->binary = true;
120  }
121 
122  linelen++;
123  if (ch == '\n')
124  {
125  info->crlf++;
126  if (whitespace)
127  info->space = true;
128  if (dot)
129  info->dot = true;
130  if (linelen > info->linemax)
131  info->linemax = linelen;
132  whitespace = 0;
133  linelen = 0;
134  dot = false;
135  }
136  else if (ch == '\r')
137  {
138  info->crlf++;
139  info->cr = true;
140  was_cr = true;
141  continue;
142  }
143  else if (ch & 0x80)
144  info->hibin++;
145  else if ((ch == '\t') || (ch == '\f'))
146  {
147  info->ascii++;
148  whitespace++;
149  }
150  else if (ch == 0)
151  {
152  info->nulbin++;
153  info->lobin++;
154  }
155  else if ((ch < 32) || (ch == 127))
156  info->lobin++;
157  else
158  {
159  if (linelen == 1)
160  {
161  if ((ch == 'F') || (ch == 'f'))
162  from = true;
163  else
164  from = false;
165  if (ch == '.')
166  dot = true;
167  else
168  dot = false;
169  }
170  else if (from)
171  {
172  if ((linelen == 2) && (ch != 'r'))
173  from = false;
174  else if ((linelen == 3) && (ch != 'o'))
175  from = false;
176  else if (linelen == 4)
177  {
178  if (ch == 'm')
179  info->from = true;
180  from = false;
181  }
182  }
183  if (ch == ' ')
184  whitespace++;
185  info->ascii++;
186  }
187 
188  if (linelen > 1)
189  dot = false;
190  if ((ch != ' ') && (ch != '\t'))
191  whitespace = 0;
192  }
193 
194  s->from = from;
195  s->whitespace = whitespace;
196  s->dot = dot;
197  s->linelen = linelen;
198  s->was_cr = was_cr;
199 }
200 
226 static size_t convert_file_to(FILE *fp, const char *fromcode, int ncodes,
227  char const *const *tocodes, int *tocode, struct Content *info)
228 {
229  char bufi[256], bufu[512], bufo[4 * sizeof(bufi)];
230  size_t ret;
231 
232  const iconv_t cd1 = mutt_ch_iconv_open("utf-8", fromcode, MUTT_ICONV_NO_FLAGS);
233  if (cd1 == (iconv_t) (-1))
234  return -1;
235 
236  iconv_t *cd = mutt_mem_calloc(ncodes, sizeof(iconv_t));
237  size_t *score = mutt_mem_calloc(ncodes, sizeof(size_t));
238  struct ContentState *states = mutt_mem_calloc(ncodes, sizeof(struct ContentState));
239  struct Content *infos = mutt_mem_calloc(ncodes, sizeof(struct Content));
240 
241  for (int i = 0; i < ncodes; i++)
242  {
243  if (!mutt_istr_equal(tocodes[i], "utf-8"))
244  cd[i] = mutt_ch_iconv_open(tocodes[i], "utf-8", MUTT_ICONV_NO_FLAGS);
245  else
246  {
247  /* Special case for conversion to UTF-8 */
248  cd[i] = (iconv_t) (-1);
249  score[i] = (size_t) (-1);
250  }
251  }
252 
253  rewind(fp);
254  size_t ibl = 0;
255  while (true)
256  {
257  /* Try to fill input buffer */
258  size_t n = fread(bufi + ibl, 1, sizeof(bufi) - ibl, fp);
259  ibl += n;
260 
261  /* Convert to UTF-8 */
262  const char *ib = bufi;
263  char *ob = bufu;
264  size_t obl = sizeof(bufu);
265  n = iconv(cd1, (ICONV_CONST char **) ((ibl != 0) ? &ib : 0), &ibl, &ob, &obl);
266  /* assert(n == (size_t)(-1) || !n); */
267  if ((n == (size_t) (-1)) && (((errno != EINVAL) && (errno != E2BIG)) || (ib == bufi)))
268  {
269  /* assert(errno == EILSEQ || (errno == EINVAL && ib == bufi && ibl < sizeof(bufi))); */
270  ret = (size_t) (-1);
271  break;
272  }
273  const size_t ubl1 = ob - bufu;
274 
275  /* Convert from UTF-8 */
276  for (int i = 0; i < ncodes; i++)
277  {
278  if ((cd[i] != (iconv_t) (-1)) && (score[i] != (size_t) (-1)))
279  {
280  const char *ub = bufu;
281  size_t ubl = ubl1;
282  ob = bufo;
283  obl = sizeof(bufo);
284  n = iconv(cd[i], (ICONV_CONST char **) ((ibl || ubl) ? &ub : 0), &ubl, &ob, &obl);
285  if (n == (size_t) (-1))
286  {
287  /* assert(errno == E2BIG || (BUGGY_ICONV && (errno == EILSEQ || errno == ENOENT))); */
288  score[i] = (size_t) (-1);
289  }
290  else
291  {
292  score[i] += n;
293  update_content_info(&infos[i], &states[i], bufo, ob - bufo);
294  }
295  }
296  else if ((cd[i] == (iconv_t) (-1)) && (score[i] == (size_t) (-1)))
297  {
298  /* Special case for conversion to UTF-8 */
299  update_content_info(&infos[i], &states[i], bufu, ubl1);
300  }
301  }
302 
303  if (ibl)
304  {
305  /* Save unused input */
306  memmove(bufi, ib, ibl);
307  }
308  else if (!ubl1 && (ib < bufi + sizeof(bufi)))
309  {
310  ret = 0;
311  break;
312  }
313  }
314 
315  if (ret == 0)
316  {
317  /* Find best score */
318  ret = (size_t) (-1);
319  for (int i = 0; i < ncodes; i++)
320  {
321  if ((cd[i] == (iconv_t) (-1)) && (score[i] == (size_t) (-1)))
322  {
323  /* Special case for conversion to UTF-8 */
324  *tocode = i;
325  ret = 0;
326  break;
327  }
328  else if ((cd[i] == (iconv_t) (-1)) || (score[i] == (size_t) (-1)))
329  continue;
330  else if ((ret == (size_t) (-1)) || (score[i] < ret))
331  {
332  *tocode = i;
333  ret = score[i];
334  if (ret == 0)
335  break;
336  }
337  }
338  if (ret != (size_t) (-1))
339  {
340  memcpy(info, &infos[*tocode], sizeof(struct Content));
341  update_content_info(info, &states[*tocode], 0, 0); /* EOF */
342  }
343  }
344 
345  for (int i = 0; i < ncodes; i++)
346  if (cd[i] != (iconv_t) (-1))
347  iconv_close(cd[i]);
348 
349  iconv_close(cd1);
350  FREE(&cd);
351  FREE(&infos);
352  FREE(&score);
353  FREE(&states);
354 
355  return ret;
356 }
357 
379 static size_t convert_file_from_to(FILE *fp, const char *fromcodes, const char *tocodes,
380  char **fromcode, char **tocode, struct Content *info)
381 {
382  char *fcode = NULL;
383  char **tcode = NULL;
384  const char *c = NULL, *c1 = NULL;
385  size_t ret;
386  int ncodes, i, cn;
387 
388  /* Count the tocodes */
389  ncodes = 0;
390  for (c = tocodes; c; c = c1 ? c1 + 1 : 0)
391  {
392  c1 = strchr(c, ':');
393  if (c1 == c)
394  continue;
395  ncodes++;
396  }
397 
398  /* Copy them */
399  tcode = mutt_mem_malloc(ncodes * sizeof(char *));
400  for (c = tocodes, i = 0; c; c = c1 ? c1 + 1 : 0, i++)
401  {
402  c1 = strchr(c, ':');
403  if (c1 == c)
404  continue;
405  if (c1)
406  tcode[i] = mutt_strn_dup(c, c1 - c);
407  else
408  tcode[i] = mutt_str_dup(c);
409  }
410 
411  ret = (size_t) (-1);
412  if (fromcode)
413  {
414  /* Try each fromcode in turn */
415  for (c = fromcodes; c; c = c1 ? c1 + 1 : 0)
416  {
417  c1 = strchr(c, ':');
418  if (c1 == c)
419  continue;
420  if (c1)
421  fcode = mutt_strn_dup(c, c1 - c);
422  else
423  fcode = mutt_str_dup(c);
424 
425  ret = convert_file_to(fp, fcode, ncodes, (char const *const *) tcode, &cn, info);
426  if (ret != (size_t) (-1))
427  {
428  *fromcode = fcode;
429  *tocode = tcode[cn];
430  tcode[cn] = 0;
431  break;
432  }
433  FREE(&fcode);
434  }
435  }
436  else
437  {
438  /* There is only one fromcode */
439  ret = convert_file_to(fp, fromcodes, ncodes, (char const *const *) tcode, &cn, info);
440  if (ret != (size_t) (-1))
441  {
442  *tocode = tcode[cn];
443  tcode[cn] = 0;
444  }
445  }
446 
447  /* Free memory */
448  for (i = 0; i < ncodes; i++)
449  FREE(&tcode[i]);
450 
451  FREE(&tcode);
452 
453  return ret;
454 }
455 
465 struct Content *mutt_get_content_info(const char *fname, struct Body *b,
466  struct ConfigSubset *sub)
467 {
468  struct Content *info = NULL;
469  struct ContentState state = { 0 };
470  FILE *fp = NULL;
471  char *fromcode = NULL;
472  char *tocode = NULL;
473  char buf[100];
474  size_t r;
475 
476  struct stat sb;
477 
478  if (b && !fname)
479  fname = b->filename;
480  if (!fname)
481  return NULL;
482 
483  if (stat(fname, &sb) == -1)
484  {
485  mutt_error(_("Can't stat %s: %s"), fname, strerror(errno));
486  return NULL;
487  }
488 
489  if (!S_ISREG(sb.st_mode))
490  {
491  mutt_error(_("%s isn't a regular file"), fname);
492  return NULL;
493  }
494 
495  fp = fopen(fname, "r");
496  if (!fp)
497  {
498  mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", fname, strerror(errno), errno);
499  return NULL;
500  }
501 
502  info = mutt_mem_calloc(1, sizeof(struct Content));
503 
504  const char *const c_charset = cs_subset_string(sub, "charset");
505 
506  if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
507  {
508  const char *const c_attach_charset =
509  cs_subset_string(sub, "attach_charset");
510  const char *const c_send_charset = cs_subset_string(sub, "send_charset");
511 
512  char *chs = mutt_param_get(&b->parameter, "charset");
513  const char *fchs =
514  b->use_disp ? (c_attach_charset ? c_attach_charset : c_charset) : c_charset;
515  if (c_charset && (chs || c_send_charset) &&
516  (convert_file_from_to(fp, fchs, chs ? chs : c_send_charset, &fromcode,
517  &tocode, info) != (size_t) (-1)))
518  {
519  if (!chs)
520  {
521  char chsbuf[256];
522  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), tocode);
523  mutt_param_set(&b->parameter, "charset", chsbuf);
524  }
525  FREE(&b->charset);
526  b->charset = fromcode;
527  FREE(&tocode);
528  mutt_file_fclose(&fp);
529  return info;
530  }
531  }
532 
533  rewind(fp);
534  while ((r = fread(buf, 1, sizeof(buf), fp)))
535  update_content_info(info, &state, buf, r);
536  update_content_info(info, &state, 0, 0);
537 
538  mutt_file_fclose(&fp);
539 
540  if (b && (b->type == TYPE_TEXT) && (!b->noconv && !b->force_charset))
541  {
542  mutt_param_set(&b->parameter, "charset",
543  (!info->hibin ? "us-ascii" :
544  c_charset && !mutt_ch_is_us_ascii(c_charset) ?
545  c_charset :
546  "unknown-8bit"));
547  }
548 
549  return info;
550 }
551 
564 enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
565 {
566  FILE *fp = NULL;
567  char *p = NULL, *q = NULL, *ct = NULL;
568  char buf[PATH_MAX];
569  char subtype[256] = { 0 };
570  char xtype[256] = { 0 };
571  int sze, cur_sze = 0;
572  bool found_mimetypes = false;
573  enum ContentType type = TYPE_OTHER;
574 
575  int szf = mutt_str_len(path);
576 
577  for (int count = 0; count < 4; count++)
578  {
579  /* can't use strtok() because we use it in an inner loop below, so use
580  * a switch statement here instead. */
581  switch (count)
582  {
583  /* last file with last entry to match wins type/xtype */
584  case 0:
585  /* check default unix mimetypes location first */
586  mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
587  break;
588  case 1:
589  mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
590  break;
591  case 2:
592  mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
593  break;
594  case 3:
595  snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
596  break;
597  default:
598  mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
599  goto bye; /* shouldn't happen */
600  }
601 
602  fp = fopen(buf, "r");
603  if (fp)
604  {
605  found_mimetypes = true;
606 
607  while (fgets(buf, sizeof(buf) - 1, fp))
608  {
609  /* weed out any comments */
610  p = strchr(buf, '#');
611  if (p)
612  *p = '\0';
613 
614  /* remove any leading space. */
615  ct = buf;
616  SKIPWS(ct);
617 
618  /* position on the next field in this line */
619  p = strpbrk(ct, " \t");
620  if (!p)
621  continue;
622  *p++ = 0;
623  SKIPWS(p);
624 
625  /* cycle through the file extensions */
626  while ((p = strtok(p, " \t\n")))
627  {
628  sze = mutt_str_len(p);
629  if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
630  ((szf == sze) || (path[szf - sze - 1] == '.')))
631  {
632  /* get the content-type */
633 
634  p = strchr(ct, '/');
635  if (!p)
636  {
637  /* malformed line, just skip it. */
638  break;
639  }
640  *p++ = 0;
641 
642  for (q = p; *q && !IS_SPACE(*q); q++)
643  ; // do nothing
644 
645  mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
646 
647  type = mutt_check_mime_type(ct);
648  if (type == TYPE_OTHER)
649  mutt_str_copy(xtype, ct, sizeof(xtype));
650 
651  cur_sze = sze;
652  }
653  p = NULL;
654  }
655  }
656  mutt_file_fclose(&fp);
657  }
658  }
659 
660 bye:
661 
662  /* no mime.types file found */
663  if (!found_mimetypes)
664  {
665  mutt_error(_("Could not find any mime.types file"));
666  }
667 
668  if ((type != TYPE_OTHER) || (*xtype != '\0'))
669  {
670  att->type = type;
671  mutt_str_replace(&att->subtype, subtype);
672  mutt_str_replace(&att->xtype, xtype);
673  }
674 
675  return type;
676 }
677 
684 static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
685 {
686  struct Buffer *buf = NULL;
687  struct State s = { 0 };
688  struct stat sb;
689 
690  for (; a; a = a->next)
691  {
692  if (a->type == TYPE_MULTIPART)
693  {
694  a->encoding = ENC_7BIT;
695  transform_to_7bit(a->parts, fp_in, sub);
696  }
697  else if (mutt_is_message_type(a->type, a->subtype))
698  {
699  mutt_message_to_7bit(a, fp_in, sub);
700  }
701  else
702  {
703  a->noconv = true;
704  a->force_charset = true;
705 
706  /* Because of the potential recursion in message types, we
707  * restrict the lifetime of the buffer tightly */
708  buf = mutt_buffer_pool_get();
709  mutt_buffer_mktemp(buf);
711  if (!s.fp_out)
712  {
713  mutt_perror("fopen");
715  return;
716  }
717  s.fp_in = fp_in;
718  mutt_decode_attachment(a, &s);
720  FREE(&a->d_filename);
721  a->d_filename = a->filename;
722  a->filename = mutt_buffer_strdup(buf);
724  a->unlink = true;
725  if (stat(a->filename, &sb) == -1)
726  {
727  mutt_perror("stat");
728  return;
729  }
730  a->length = sb.st_size;
731 
732  mutt_update_encoding(a, sub);
733  if (a->encoding == ENC_8BIT)
735  else if (a->encoding == ENC_BINARY)
736  a->encoding = ENC_BASE64;
737  }
738  }
739 }
740 
747 void mutt_message_to_7bit(struct Body *a, FILE *fp, struct ConfigSubset *sub)
748 {
749  struct Buffer temp = mutt_buffer_make(0);
750  FILE *fp_in = NULL;
751  FILE *fp_out = NULL;
752  struct stat sb;
753 
754  if (!a->filename && fp)
755  fp_in = fp;
756  else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
757  {
758  mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
759  return;
760  }
761  else
762  {
763  a->offset = 0;
764  if (stat(a->filename, &sb) == -1)
765  {
766  mutt_perror("stat");
767  mutt_file_fclose(&fp_in);
768  goto cleanup;
769  }
770  a->length = sb.st_size;
771  }
772 
773  /* Avoid buffer pool due to recursion */
774  mutt_buffer_mktemp(&temp);
775  fp_out = mutt_file_fopen(mutt_buffer_string(&temp), "w+");
776  if (!fp_out)
777  {
778  mutt_perror("fopen");
779  goto cleanup;
780  }
781 
782  fseeko(fp_in, a->offset, SEEK_SET);
783  a->parts = mutt_rfc822_parse_message(fp_in, a);
784 
785  transform_to_7bit(a->parts, fp_in, sub);
786 
787  mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
788  CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
789 
790  fputs("MIME-Version: 1.0\n", fp_out);
791  mutt_write_mime_header(a->parts, fp_out, sub);
792  fputc('\n', fp_out);
793  mutt_write_mime_body(a->parts, fp_out, sub);
794 
795  if (fp_in != fp)
796  mutt_file_fclose(&fp_in);
797  mutt_file_fclose(&fp_out);
798 
799  a->encoding = ENC_7BIT;
800  FREE(&a->d_filename);
801  a->d_filename = a->filename;
802  if (a->filename && a->unlink)
803  unlink(a->filename);
804  a->filename = mutt_buffer_strdup(&temp);
805  a->unlink = true;
806  if (stat(a->filename, &sb) == -1)
807  {
808  mutt_perror("stat");
809  goto cleanup;
810  }
811  a->length = sb.st_size;
812  mutt_body_free(&a->parts);
813  a->email->body = NULL;
814 
815 cleanup:
816  if (fp_in && (fp_in != fp))
817  mutt_file_fclose(&fp_in);
818 
819  if (fp_out)
820  {
821  mutt_file_fclose(&fp_out);
823  }
824 
825  mutt_buffer_dealloc(&temp);
826 }
827 
834 static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
835 {
836  const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
837  if (b->type == TYPE_TEXT)
838  {
839  const bool c_encode_from = cs_subset_bool(sub, "encode_from");
840  char send_charset[128];
841  char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
842  if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
843  (info->linemax > 990) || (info->from && c_encode_from))
844  {
846  }
847  else if (info->hibin)
848  {
849  b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
850  }
851  else
852  {
853  b->encoding = ENC_7BIT;
854  }
855  }
856  else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
857  {
858  if (info->lobin || info->hibin)
859  {
860  if (c_allow_8bit && !info->lobin)
861  b->encoding = ENC_8BIT;
862  else
863  mutt_message_to_7bit(b, NULL, sub);
864  }
865  else
866  b->encoding = ENC_7BIT;
867  }
868  else if ((b->type == TYPE_APPLICATION) &&
869  mutt_istr_equal(b->subtype, "pgp-keys"))
870  {
871  b->encoding = ENC_7BIT;
872  }
873  else
874  {
875  /* Determine which encoding is smaller */
876  if (1.33 * (float) (info->lobin + info->hibin + info->ascii) <
877  3.0 * (float) (info->lobin + info->hibin) + (float) info->ascii)
878  {
879  b->encoding = ENC_BASE64;
880  }
881  else
882  {
884  }
885  }
886 }
887 
893 {
894  a->stamp = mutt_date_epoch();
895 }
896 
904 void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
905 {
906  struct Content *info = NULL;
907  char chsbuf[256];
908 
909  /* override noconv when it's us-ascii */
910  if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
911  a->noconv = false;
912 
913  if (!a->force_charset && !a->noconv)
914  mutt_param_delete(&a->parameter, "charset");
915 
916  info = mutt_get_content_info(a->filename, a, sub);
917  if (!info)
918  return;
919 
920  set_encoding(a, info, sub);
922 
923  FREE(&a->content);
924  a->content = info;
925 }
926 
936 struct Body *mutt_make_message_attach(struct Mailbox *m, struct Email *e,
937  bool attach_msg, struct ConfigSubset *sub)
938 {
939  struct Body *body = NULL;
940  FILE *fp = NULL;
941  CopyMessageFlags cmflags;
943 
944  const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
945  const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
946  if (WithCrypto)
947  {
948  if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
949  {
951  return NULL;
952  }
953  }
954 
955  struct Buffer *buf = mutt_buffer_pool_get();
956  mutt_buffer_mktemp(buf);
957  fp = mutt_file_fopen(mutt_buffer_string(buf), "w+");
958  if (!fp)
959  {
961  return NULL;
962  }
963 
964  body = mutt_body_new();
965  body->type = TYPE_MESSAGE;
966  body->subtype = mutt_str_dup("rfc822");
968  body->unlink = true;
969  body->use_disp = false;
970  body->disposition = DISP_INLINE;
971  body->noconv = true;
972 
974 
975  struct Message *msg = mx_msg_open(m, e->msgno);
976  if (!msg)
977  {
978  return NULL;
979  }
980  mutt_parse_mime_message(m, e, msg->fp);
981 
982  CopyHeaderFlags chflags = CH_XMIT;
983  cmflags = MUTT_CM_NO_FLAGS;
984 
985  /* If we are attaching a message, ignore `$mime_forward_decode` */
986  if (!attach_msg && c_mime_forward_decode)
987  {
988  chflags |= CH_MIME | CH_TXTPLAIN;
989  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
991  pgp &= ~PGP_ENCRYPT;
993  pgp &= ~SMIME_ENCRYPT;
994  }
995  else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
996  {
998  {
999  chflags |= CH_MIME | CH_NONEWLINE;
1000  cmflags = MUTT_CM_DECODE_PGP;
1001  pgp &= ~PGP_ENCRYPT;
1002  }
1003  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
1005  {
1006  chflags |= CH_MIME | CH_TXTPLAIN;
1007  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1008  pgp &= ~PGP_ENCRYPT;
1009  }
1010  else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1012  {
1013  chflags |= CH_MIME | CH_TXTPLAIN;
1014  cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
1015  pgp &= ~SMIME_ENCRYPT;
1016  }
1017  }
1018 
1019  mutt_copy_message(fp, m, e, msg, cmflags, chflags, 0);
1020  mx_msg_close(m, &msg);
1021 
1022  fflush(fp);
1023  rewind(fp);
1024 
1025  body->email = email_new();
1026  body->email->offset = 0;
1027  /* we don't need the user headers here */
1028  body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
1029  if (WithCrypto)
1030  body->email->security = pgp;
1031  mutt_update_encoding(body, sub);
1032  body->parts = body->email->body;
1033 
1034  mutt_file_fclose(&fp);
1035 
1036  return body;
1037 }
1038 
1046 static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
1047 {
1048  FILE *fp = NULL, *fp_err = NULL;
1049  char *buf = NULL;
1050  size_t buflen;
1051  pid_t pid;
1052  struct Buffer *cmd = mutt_buffer_pool_get();
1053 
1054  const char *const c_mime_type_query_command =
1055  cs_subset_string(sub, "mime_type_query_command");
1056 
1057  mutt_buffer_file_expand_fmt_quote(cmd, c_mime_type_query_command, att->filename);
1058 
1059  pid = filter_create(mutt_buffer_string(cmd), NULL, &fp, &fp_err);
1060  if (pid < 0)
1061  {
1062  mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
1064  return;
1065  }
1067 
1068  buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
1069  if (buf)
1070  {
1071  if (strchr(buf, '/'))
1072  mutt_parse_content_type(buf, att);
1073  FREE(&buf);
1074  }
1075 
1076  mutt_file_fclose(&fp);
1077  mutt_file_fclose(&fp_err);
1078  filter_wait(pid);
1079 }
1080 
1088 struct Body *mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
1089 {
1090  struct Body *att = mutt_body_new();
1091  att->filename = mutt_str_dup(path);
1092 
1093  const char *const c_mime_type_query_command =
1094  cs_subset_string(sub, "mime_type_query_command");
1095  const bool c_mime_type_query_first =
1096  cs_subset_bool(sub, "mime_type_query_first");
1097 
1098  if (c_mime_type_query_command && c_mime_type_query_first)
1099  run_mime_type_query(att, sub);
1100 
1101  /* Attempt to determine the appropriate content-type based on the filename
1102  * suffix. */
1103  if (!att->subtype)
1104  mutt_lookup_mime_type(att, path);
1105 
1106  if (!att->subtype && c_mime_type_query_command && !c_mime_type_query_first)
1107  {
1108  run_mime_type_query(att, sub);
1109  }
1110 
1111  struct Content *info = mutt_get_content_info(path, att, sub);
1112  if (!info)
1113  {
1114  mutt_body_free(&att);
1115  return NULL;
1116  }
1117 
1118  if (!att->subtype)
1119  {
1120  if ((info->nulbin == 0) &&
1121  ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
1122  {
1123  /* Statistically speaking, there should be more than 10% "lobin"
1124  * chars if this is really a binary file... */
1125  att->type = TYPE_TEXT;
1126  att->subtype = mutt_str_dup("plain");
1127  }
1128  else
1129  {
1130  att->type = TYPE_APPLICATION;
1131  att->subtype = mutt_str_dup("octet-stream");
1132  }
1133  }
1134 
1135  FREE(&info);
1136  mutt_update_encoding(att, sub);
1137  return att;
1138 }
1139 
1147 static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
1148 {
1149  char *tmp = NULL;
1150  char *p = NULL;
1151  int i;
1152 
1153  const char *const c_send_charset = cs_subset_string(sub, "send_charset");
1154 
1155  struct ListNode *np = NULL;
1156  STAILQ_FOREACH(np, h, entries)
1157  {
1158  p = strchr(np->data, ':');
1159  if (!p)
1160  continue;
1161 
1162  i = p - np->data;
1163  p = mutt_str_skip_email_wsp(p + 1);
1164  tmp = mutt_str_dup(p);
1165 
1166  if (!tmp)
1167  continue;
1168 
1169  rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
1170  mutt_mem_realloc(&np->data, i + 2 + mutt_str_len(tmp) + 1);
1171 
1172  sprintf(np->data + i + 2, "%s", tmp);
1173 
1174  FREE(&tmp);
1175  }
1176 }
1177 
1187 const char *mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
1188 {
1189  const char *const c_hostname = cs_subset_string(sub, "hostname");
1190  if (!c_hostname || (c_hostname[0] == '@'))
1191  return NULL;
1192 
1193  const char *p = c_hostname;
1194 
1195  const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
1196  if (may_hide_host && c_hidden_host)
1197  {
1198  p = strchr(c_hostname, '.');
1199  if (p)
1200  p++;
1201 
1202  // sanity check: don't hide the host if the fqdn is something like example.com
1203  if (!p || !strchr(p, '.'))
1204  p = c_hostname;
1205  }
1206 
1207  return p;
1208 }
1209 
1216 static char *gen_msgid(struct ConfigSubset *sub)
1217 {
1218  char buf[128];
1219  char rndid[MUTT_RANDTAG_LEN + 1];
1220 
1221  mutt_rand_base32(rndid, sizeof(rndid) - 1);
1222  rndid[MUTT_RANDTAG_LEN] = 0;
1223  const char *fqdn = mutt_fqdn(false, sub);
1224  if (!fqdn)
1225  fqdn = NONULL(ShortHostname);
1226 
1227  struct tm tm = mutt_date_gmtime(MUTT_DATE_NOW);
1228  snprintf(buf, sizeof(buf), "<%d%02d%02d%02d%02d%02d.%s@%s>", tm.tm_year + 1900,
1229  tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, rndid, fqdn);
1230  return mutt_str_dup(buf);
1231 }
1232 
1243 void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
1244 {
1245  if (final)
1246  {
1247  if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
1248  {
1249  /* some MTA's will put an Apparently-To: header field showing the Bcc:
1250  * recipients if there is no To: or Cc: field, so attempt to suppress
1251  * it by using an empty To: field. */
1252  struct Address *to = mutt_addr_new();
1253  to->group = true;
1254  mutt_addrlist_append(&env->to, to);
1256 
1257  char buf[1024];
1258  buf[0] = '\0';
1259  mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
1260 
1261  to->mailbox = mutt_str_dup(buf);
1262  }
1263 
1264  mutt_set_followup_to(env, sub);
1265 
1266  if (!env->message_id)
1267  env->message_id = gen_msgid(sub);
1268  }
1269 
1270  /* Take care of 8-bit => 7-bit conversion. */
1272  encode_headers(&env->userhdrs, sub);
1273 }
1274 
1283 {
1284  struct ListNode *item = NULL;
1285  STAILQ_FOREACH(item, &env->userhdrs, entries)
1286  {
1287  rfc2047_decode(&item->data);
1288  }
1289 
1291 
1292  /* back conversions */
1294 }
1295 
1308 static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
1309  struct AddressList *to, const char *resent_from,
1310  struct AddressList *env_from, struct ConfigSubset *sub)
1311 {
1312  if (!e)
1313  return -1;
1314 
1315  int rc = 0;
1316 
1317  struct Buffer *tempfile = mutt_buffer_pool_get();
1318  mutt_buffer_mktemp(tempfile);
1319  FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w");
1320  if (fp_tmp)
1321  {
1323 
1324  const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
1325  if (!c_bounce_delivered)
1326  chflags |= CH_WEED_DELIVERED;
1327 
1328  fseeko(fp, e->offset, SEEK_SET);
1329  fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
1330 
1331  struct Buffer *date = mutt_buffer_pool_get();
1332  mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
1333  fprintf(fp_tmp, "Resent-Date: %s\n", mutt_buffer_string(date));
1334  mutt_buffer_pool_release(&date);
1335 
1336  char *msgid_str = gen_msgid(sub);
1337  fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
1338  FREE(&msgid_str);
1339  fputs("Resent-To: ", fp_tmp);
1340  mutt_addrlist_write_file(to, fp_tmp, 11, false);
1341  mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
1342  fputc('\n', fp_tmp);
1343  mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
1344  if (mutt_file_fclose(&fp_tmp) != 0)
1345  {
1346  mutt_perror(mutt_buffer_string(tempfile));
1347  unlink(mutt_buffer_string(tempfile));
1348  return -1;
1349  }
1350 #ifdef USE_SMTP
1351  const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
1352  if (c_smtp_url)
1353  {
1354  rc = mutt_smtp_send(env_from, to, NULL, NULL, mutt_buffer_string(tempfile),
1355  (e->body->encoding == ENC_8BIT), sub);
1356  }
1357  else
1358 #endif
1359  {
1360  rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, mutt_buffer_string(tempfile),
1361  (e->body->encoding == ENC_8BIT), sub);
1362  }
1363  }
1364 
1365  mutt_buffer_pool_release(&tempfile);
1366  return rc;
1367 }
1368 
1379 int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
1380  struct AddressList *to, struct ConfigSubset *sub)
1381 {
1382  if (!fp || !e || !to || TAILQ_EMPTY(to))
1383  return -1;
1384 
1385  const char *fqdn = mutt_fqdn(true, sub);
1386  char resent_from[256];
1387  char *err = NULL;
1388 
1389  resent_from[0] = '\0';
1390  struct Address *from = mutt_default_from(sub);
1391  struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
1392  mutt_addrlist_append(&from_list, from);
1393 
1394  /* mutt_default_from() does not use $real_name if the real name is not set
1395  * in $from, so we add it here. The reason it is not added in
1396  * mutt_default_from() is that during normal sending, we execute
1397  * send-hooks and set the real_name last so that it can be changed based
1398  * upon message criteria. */
1399  if (!from->personal)
1400  {
1401  const char *const c_real_name = cs_subset_string(sub, "real_name");
1402  from->personal = mutt_str_dup(c_real_name);
1403  }
1404 
1405  mutt_addrlist_qualify(&from_list, fqdn);
1406 
1407  rfc2047_encode_addrlist(&from_list, "Resent-From");
1408  if (mutt_addrlist_to_intl(&from_list, &err))
1409  {
1410  mutt_error(_("Bad IDN %s while preparing resent-from"), err);
1411  FREE(&err);
1412  mutt_addrlist_clear(&from_list);
1413  return -1;
1414  }
1415  mutt_addrlist_write(&from_list, resent_from, sizeof(resent_from), false);
1416 
1417 #ifdef USE_NNTP
1418  OptNewsSend = false;
1419 #endif
1420 
1421  /* prepare recipient list. idna conversion appears to happen before this
1422  * function is called, since the user receives confirmation of the address
1423  * list being bounced to. */
1424  struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
1425  mutt_addrlist_copy(&resent_to, to, false);
1426  rfc2047_encode_addrlist(&resent_to, "Resent-To");
1427  int rc = bounce_message(fp, m, e, &resent_to, resent_from, &from_list, sub);
1428  mutt_addrlist_clear(&resent_to);
1429  mutt_addrlist_clear(&from_list);
1430 
1431  return rc;
1432 }
1433 
1439 static void set_noconv_flags(struct Body *b, bool flag)
1440 {
1441  for (; b; b = b->next)
1442  {
1443  if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
1444  set_noconv_flags(b->parts, flag);
1445  else if ((b->type == TYPE_TEXT) && b->noconv)
1446  {
1447  if (flag)
1448  mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
1449  else
1450  mutt_param_delete(&b->parameter, "x-mutt-noconv");
1451  }
1452  }
1453 }
1454 
1467 int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1468  char *fcc, char **finalpath, struct ConfigSubset *sub)
1469 {
1470  char fcc_tok[PATH_MAX];
1471  char fcc_expanded[PATH_MAX];
1472 
1473  mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
1474 
1475  char *tok = strtok(fcc_tok, ",");
1476  if (!tok)
1477  return -1;
1478 
1479  mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
1480  /* mutt_expand_path already called above for the first token */
1481  int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
1482  if (status != 0)
1483  return status;
1484 
1485  while ((tok = strtok(NULL, ",")))
1486  {
1487  if (*tok == '\0')
1488  continue;
1489 
1490  /* Only call mutt_expand_path if tok has some data */
1491  mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1492  mutt_str_copy(fcc_expanded, tok, sizeof(fcc_expanded));
1493  mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
1494  mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n", fcc_expanded);
1495  status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath, sub);
1496  if (status != 0)
1497  return status;
1498  }
1499 
1500  return 0;
1501 }
1502 
1515 int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1516  const char *fcc, char **finalpath, struct ConfigSubset *sub)
1517 {
1518  struct Message *msg = NULL;
1519  struct Buffer *tempfile = NULL;
1520  FILE *fp_tmp = NULL;
1521  int rc = -1;
1522  bool need_mailbox_cleanup = false;
1523  struct stat st;
1524  MsgOpenFlags onm_flags;
1525 
1526  if (post)
1527  set_noconv_flags(e->body, true);
1528 
1529 #ifdef RECORD_FOLDER_HOOK
1530  mutt_folder_hook(path, NULL);
1531 #endif
1532  struct Mailbox *m_fcc = mx_path_resolve(path);
1533  bool old_append = m_fcc->append;
1534  if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1535  {
1536  mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1537  mailbox_free(&m_fcc);
1538  goto done;
1539  }
1540 
1541  /* We need to add a Content-Length field to avoid problems where a line in
1542  * the message body begins with "From " */
1543  if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1544  {
1545  tempfile = mutt_buffer_pool_get();
1546  mutt_buffer_mktemp(tempfile);
1547  fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
1548  if (!fp_tmp)
1549  {
1550  mutt_perror(mutt_buffer_string(tempfile));
1551  mx_mbox_close(m_fcc);
1552  goto done;
1553  }
1554  /* remember new mail status before appending message */
1555  need_mailbox_cleanup = true;
1556  stat(path, &st);
1557  }
1558 
1559  e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1560  onm_flags = MUTT_ADD_FROM;
1561  if (post)
1562  onm_flags |= MUTT_SET_DRAFT;
1563  msg = mx_msg_open_new(m_fcc, e, onm_flags);
1564  if (!msg)
1565  {
1566  mutt_file_fclose(&fp_tmp);
1567  mx_mbox_close(m_fcc);
1568  goto done;
1569  }
1570 
1571  const bool c_crypt_protected_headers_read =
1572  cs_subset_bool(sub, "crypt_protected_headers_read");
1573 
1574  /* post == 1 => postpone message.
1575  * post == 0 => Normal mode. */
1577  msg->fp, e->env, e->body,
1579  c_crypt_protected_headers_read && mutt_should_hide_protected_subject(e), sub);
1580 
1581  /* (postponement) if this was a reply of some sort, <msgid> contains the
1582  * Message-ID: of message replied to. Save it using a special X-Mutt-
1583  * header so it can be picked up if the message is recalled at a later
1584  * point in time. This will allow the message to be marked as replied if
1585  * the same mailbox is still open. */
1586  if (post && msgid)
1587  fprintf(msg->fp, "X-Mutt-References: %s\n", msgid);
1588 
1589  /* (postponement) save the Fcc: using a special X-Mutt- header so that
1590  * it can be picked up when the message is recalled */
1591  if (post && fcc)
1592  fprintf(msg->fp, "X-Mutt-Fcc: %s\n", fcc);
1593 
1594  if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1595  fprintf(msg->fp, "Status: RO\n");
1596 
1597  /* (postponement) if the mail is to be signed or encrypted, save this info */
1598  if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1599  {
1600  fputs("X-Mutt-PGP: ", msg->fp);
1601  if (e->security & SEC_ENCRYPT)
1602  fputc('E', msg->fp);
1603  if (e->security & SEC_OPPENCRYPT)
1604  fputc('O', msg->fp);
1605  if (e->security & SEC_SIGN)
1606  {
1607  fputc('S', msg->fp);
1608 
1609  const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1610  if (c_pgp_sign_as)
1611  fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1612  }
1613  if (e->security & SEC_INLINE)
1614  fputc('I', msg->fp);
1615 #ifdef USE_AUTOCRYPT
1616  if (e->security & SEC_AUTOCRYPT)
1617  fputc('A', msg->fp);
1619  fputc('Z', msg->fp);
1620 #endif
1621  fputc('\n', msg->fp);
1622  }
1623 
1624  /* (postponement) if the mail is to be signed or encrypted, save this info */
1625  if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1626  {
1627  fputs("X-Mutt-SMIME: ", msg->fp);
1628  if (e->security & SEC_ENCRYPT)
1629  {
1630  fputc('E', msg->fp);
1631 
1632  const char *const c_smime_encrypt_with =
1633  cs_subset_string(sub, "smime_encrypt_with");
1634  if (c_smime_encrypt_with)
1635  fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1636  }
1637  if (e->security & SEC_OPPENCRYPT)
1638  fputc('O', msg->fp);
1639  if (e->security & SEC_SIGN)
1640  {
1641  fputc('S', msg->fp);
1642 
1643  const char *const c_smime_sign_as =
1644  cs_subset_string(sub, "smime_sign_as");
1645  if (c_smime_sign_as)
1646  fprintf(msg->fp, "<%s>", c_smime_sign_as);
1647  }
1648  if (e->security & SEC_INLINE)
1649  fputc('I', msg->fp);
1650  fputc('\n', msg->fp);
1651  }
1652 
1653 #ifdef MIXMASTER
1654  /* (postponement) if the mail is to be sent through a mixmaster
1655  * chain, save that information */
1656 
1657  if (post && !STAILQ_EMPTY(&e->chain))
1658  {
1659  fputs("X-Mutt-Mix:", msg->fp);
1660  struct ListNode *p = NULL;
1661  STAILQ_FOREACH(p, &e->chain, entries)
1662  {
1663  fprintf(msg->fp, " %s", (char *) p->data);
1664  }
1665 
1666  fputc('\n', msg->fp);
1667  }
1668 #endif
1669 
1670  if (fp_tmp)
1671  {
1672  mutt_write_mime_body(e->body, fp_tmp, sub);
1673 
1674  /* make sure the last line ends with a newline. Emacs doesn't ensure this
1675  * will happen, and it can cause problems parsing the mailbox later. */
1676  fseek(fp_tmp, -1, SEEK_END);
1677  if (fgetc(fp_tmp) != '\n')
1678  {
1679  fseek(fp_tmp, 0, SEEK_END);
1680  fputc('\n', fp_tmp);
1681  }
1682 
1683  fflush(fp_tmp);
1684  if (ferror(fp_tmp))
1685  {
1686  mutt_debug(LL_DEBUG1, "%s: write failed\n", mutt_buffer_string(tempfile));
1687  mutt_file_fclose(&fp_tmp);
1688  unlink(mutt_buffer_string(tempfile));
1689  mx_msg_commit(m_fcc, msg); /* XXX really? */
1690  mx_msg_close(m_fcc, &msg);
1691  mx_mbox_close(m_fcc);
1692  goto done;
1693  }
1694 
1695  /* count the number of lines */
1696  int lines = 0;
1697  char line_buf[1024];
1698  rewind(fp_tmp);
1699  while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1700  lines++;
1701  fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1702  fprintf(msg->fp, "Lines: %d\n\n", lines);
1703 
1704  /* copy the body and clean up */
1705  rewind(fp_tmp);
1706  rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1707  if (mutt_file_fclose(&fp_tmp) != 0)
1708  rc = -1;
1709  /* if there was an error, leave the temp version */
1710  if (rc >= 0)
1711  {
1712  unlink(mutt_buffer_string(tempfile));
1713  rc = 0;
1714  }
1715  }
1716  else
1717  {
1718  fputc('\n', msg->fp); /* finish off the header */
1719  rc = mutt_write_mime_body(e->body, msg->fp, sub);
1720  }
1721 
1722  if (mx_msg_commit(m_fcc, msg) != 0)
1723  rc = -1;
1724  else if (finalpath)
1725  *finalpath = mutt_str_dup(msg->committed_path);
1726  mx_msg_close(m_fcc, &msg);
1727  mx_mbox_close(m_fcc);
1728 
1729  if (!post && need_mailbox_cleanup)
1730  mutt_mailbox_cleanup(path, &st);
1731 
1732  if (post)
1733  set_noconv_flags(e->body, false);
1734 
1735 done:
1736  if (m_fcc)
1737  m_fcc->append = old_append;
1738 #ifdef RECORD_FOLDER_HOOK
1739  /* We ran a folder hook for the destination mailbox,
1740  * now we run it for the user's current mailbox */
1741  const struct Mailbox *m = ctx_mailbox(Context);
1742  if (m)
1743  mutt_folder_hook(m->path, m->desc);
1744 #endif
1745 
1746  if (fp_tmp)
1747  {
1748  mutt_file_fclose(&fp_tmp);
1749  unlink(mutt_buffer_string(tempfile));
1750  }
1751  mutt_buffer_pool_release(&tempfile);
1752 
1753  return rc;
1754 }
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:591
Info about the body of an email.
Definition: sendlib.c:63
struct Content * mutt_get_content_info(const char *fname, struct Body *b, struct ConfigSubset *sub)
Analyze file to determine MIME encoding to use.
Definition: sendlib.c:465
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
static void update_content_info(struct Content *info, struct ContentState *s, char *buf, size_t buflen)
Cache some info about an email.
Definition: sendlib.c:79
The "current" mailbox.
Definition: context.h:37
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:807
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1861
int whitespace
Definition: sendlib.c:66
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:892
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
Unknown Content-Type.
Definition: mime.h:31
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define WithCrypto
Definition: lib.h:113
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1385
The envelope/body of an email.
Definition: email.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:51
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:904
A postponed Email, just the envelope info.
Definition: header.h:42
bool dot
Has a line consisting of a single dot?
Definition: content.h:44
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
long linemax
Length of the longest line in the file.
Definition: content.h:40
struct Body * body
List of MIME parts.
Definition: email.h:91
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:444
Structs that make up an email.
#define mutt_error(...)
Definition: logging.h:88
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:74
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:360
7-bit text
Definition: mime.h:49
void mutt_message_to_7bit(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Convert an email&#39;s MIME parts to 7-bit.
Definition: sendlib.c:747
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
#define SMIME_ENCRYPT
Definition: lib.h:99
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1108
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
Write email to FCC mailbox.
Definition: sendlib.c:1515
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:1147
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:623
#define PGP_ENCRYPT
Definition: lib.h:93
String manipulation buffer.
Definition: buffer.h:33
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:378
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
#define _(a)
Definition: message.h:28
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
struct Body * next
next attachment in the list
Definition: body.h:53
An email address.
Definition: address.h:35
8-bit text
Definition: mime.h:50
#define MUTT_DATE_NOW
Constant representing the &#39;current time&#39;, see: mutt_date_gmtime(), mutt_date_localtime() ...
Definition: date.h:39
FILE * fp_out
File to write to.
Definition: state.h:47
char * mailbox
Mailbox and host address.
Definition: address.h:38
bool dot
Definition: sendlib.c:67
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:62
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:84
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:71
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:32
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:787
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:667
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone. ...
Definition: date.c:672
long hibin
8-bit characters
Definition: content.h:35
bool was_cr
Definition: sendlib.c:69
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:610
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define mutt_perror(...)
Definition: logging.h:89
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:742
FILE * fp_in
File to read from.
Definition: state.h:46
The body of an email.
Definition: body.h:34
iconv_t mutt_ch_iconv_open(const char *tocode, const char *fromcode, uint8_t flags)
Set up iconv for conversions.
Definition: charset.c:569
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
Convenience wrapper for the config headers.
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:43
#define MUTT_RANDTAG_LEN
Definition: sendlib.h:35
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:45
Email Address Handling.
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:82
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Some miscellaneous functions.
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:65
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:529
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:122
fcc mode, like normal mode but for Bcc header
Definition: header.h:41
bool read
Email is read.
Definition: email.h:51
char * message_id
Message ID.
Definition: envelope.h:69
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
parse a Message/RFC822 body
Definition: parse.c:1693
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1054
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:1243
int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:1379
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:460
Many unsorted constants and some structs.
API for mailboxes.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:641
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:326
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, int start_col, bool display)
Wrapper for mutt_write_address()
Definition: address.c:1231
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:548
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
bool force_charset
Send mode: don&#39;t adjust the character set when in send-mode.
Definition: body.h:75
struct Envelope * env
Envelope information.
Definition: email.h:90
Convenience wrapper for the core headers.
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:1088
static char * gen_msgid(struct ConfigSubset *sub)
Generate a unique Message ID.
Definition: sendlib.c:1216
#define SKIPWS(ch)
Definition: string2.h:46
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:764
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: body.c:131
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
static char * chs
Definition: gnupgparse.c:73
static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, const char *resent_from, struct AddressList *env_from, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:1308
char * mutt_strn_copy(char *dest, const char *src, size_t len, size_t dsize)
Copy a sub-string into a buffer.
Definition: string.c:528
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
char * subtype
content-type subtype
Definition: body.h:37
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
Info about an attachment.
Definition: content.h:33
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath, struct ConfigSubset *sub)
Handle FCC with multiple, comma separated entries.
Definition: sendlib.c:1467
struct ListHead chain
Mixmaster chain.
Definition: email.h:102
A set of inherited config items.
Definition: subset.h:46
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:1282
bool from
Definition: sendlib.c:65
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
A local copy of an email.
Definition: mxapi.h:41
bool binary
Long lines, or CR not in CRLF pair.
Definition: content.h:42
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:40
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default &#39;from&#39; Address.
Definition: send.c:1454
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1329
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
int mutt_invoke_sendmail(struct Mailbox *m, struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, bool eightbit, struct ConfigSubset *sub)
Run sendmail.
Definition: sendmail.c:287
long ascii
Number of ascii chars.
Definition: content.h:39
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
Create a message attachment.
Definition: sendlib.c:936
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:85
Type: &#39;text/*&#39;.
Definition: mime.h:38
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:46
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
char * xtype
content-type if x-unknown
Definition: body.h:36
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:55
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
char * charset
Send mode: charset of attached file as stored on disk.
Definition: body.h:49
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
API for encryption/signing of emails.
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:113
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:64
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
int linelen
Definition: sendlib.c:68
static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:684
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:241
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit, struct ConfigSubset *sub)
Send a message using SMTP.
Definition: smtp.c:882
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:40
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:83
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:616
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:84
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
bool from
Has a line beginning with "From "?
Definition: content.h:43
Type: &#39;message/*&#39;.
Definition: mime.h:35
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:96
#define SEC_SIGN
Email is signed.
Definition: lib.h:76
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:45
#define IS_SPACE(ch)
Definition: string2.h:38
char * personal
Real name of address.
Definition: address.h:37
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:67
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:427
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1187
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:36
char * data
String.
Definition: list.h:36
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Duplicate the structure of an entire email.
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
Log at debug level 1.
Definition: logging.h:40
bool group
Group mailbox?
Definition: address.h:39
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:564
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition: copy.c:413
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:565
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1165
void mutt_rand_base32(char *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: random.c:103
Binary.
Definition: mime.h:53
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:104
Quoted-printable text.
Definition: mime.h:51
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1435
FILE * fp
pointer to the message data
Definition: mxapi.h:43
long crlf
\r and \n characters
Definition: content.h:38
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:853
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#define FREE(x)
Definition: memory.h:40
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1668
bool space
Whitespace at the end of lines?
Definition: content.h:41
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:1439
Keep track when processing files.
Definition: state.h:44
#define STAILQ_EMPTY(head)
Definition: queue.h:348
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
static size_t convert_file_to(FILE *fp, const char *fromcode, int ncodes, char const *const *tocodes, int *tocode, struct Content *info)
Change the encoding of a file.
Definition: sendlib.c:226
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
Miscellaneous functions for sending an email.
#define TAILQ_EMPTY(head)
Definition: queue.h:721
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:45
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
A List node for strings.
Definition: list.h:34
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
Miscellaneous email parsing routines.
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
Decide how to display email content.
Content is inline.
Definition: mime.h:62
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1124
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
struct Email * email
header information for message/rfc822
Definition: body.h:55
long nulbin
Null characters (0x0)
Definition: content.h:37
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:354
bool cr
Has CR, even when in a CRLF pair.
Definition: content.h:45
Mailbox helper functions.
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition: address.c:681
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1140
Type: &#39;application/*&#39;.
Definition: mime.h:33
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:574
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
static size_t convert_file_from_to(FILE *fp, const char *fromcodes, const char *tocodes, char **fromcode, char **tocode, struct Content *info)
Convert a file between encodings.
Definition: sendlib.c:379
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:60
The header of an Email.
Definition: envelope.h:54
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
determine which Content-Transfer-Encoding to use
Definition: sendlib.c:834
int msgno
Number displayed to the user.
Definition: email.h:87
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
ContentType
Content-Type.
Definition: mime.h:29
static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition: sendlib.c:1046