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