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