NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
copy.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <ctype.h>
32 #include <inttypes.h> // IWYU pragma: keep
33 #include <stdbool.h>
34 #include <string.h>
35 #include "mutt/lib.h"
36 #include "address/lib.h"
37 #include "config/lib.h"
38 #include "email/lib.h"
39 #include "core/lib.h"
40 #include "gui/lib.h"
41 #include "mutt.h"
42 #include "copy.h"
43 #include "ncrypt/lib.h"
44 #include "send/lib.h"
45 #include "context.h"
46 #include "format_flags.h"
47 #include "handler.h"
48 #include "hdrline.h"
49 #include "mutt_globals.h"
50 #include "mx.h"
51 #ifdef USE_NOTMUCH
52 #include "notmuch/lib.h"
53 #include "muttlib.h"
54 #endif
55 #ifdef ENABLE_NLS
56 #include <libintl.h>
57 #endif
58 
59 static int address_header_decode(char **h);
60 static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out,
61  const char *quoted_date);
62 
63 ARRAY_HEAD(Headers, char *);
64 
74 static void add_one_header(struct Headers *headers, size_t pos, char *value)
75 {
76  char **old = ARRAY_GET(headers, pos);
77  if (old && *old)
78  {
79  char *new_value = NULL;
80  mutt_str_asprintf(&new_value, "%s%s", *old, value);
81  FREE(old);
82  FREE(&value);
83  value = new_value;
84  }
85  ARRAY_SET(headers, pos, value);
86 }
87 
104 int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end,
105  CopyHeaderFlags chflags, const char *prefix, int wraplen)
106 {
107  bool from = false;
108  bool this_is_from = false;
109  bool ignore = false;
110  char buf[1024]; /* should be long enough to get most fields in one pass */
111  char *nl = NULL;
112  struct Headers headers = ARRAY_HEAD_INITIALIZER;
113  int hdr_count;
114  int x;
115  char *this_one = NULL;
116  size_t this_one_len = 0;
117 
118  if (off_start < 0)
119  return -1;
120 
121  if (ftello(fp_in) != off_start)
122  if (fseeko(fp_in, off_start, SEEK_SET) < 0)
123  return -1;
124 
125  buf[0] = '\n';
126  buf[1] = '\0';
127 
128  if ((chflags & (CH_REORDER | CH_WEED | CH_MIME | CH_DECODE | CH_PREFIX | CH_WEED_DELIVERED)) == 0)
129  {
130  /* Without these flags to complicate things
131  * we can do a more efficient line to line copying */
132  while (ftello(fp_in) < off_end)
133  {
134  nl = strchr(buf, '\n');
135 
136  if (!fgets(buf, sizeof(buf), fp_in))
137  break;
138 
139  /* Is it the beginning of a header? */
140  if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
141  {
142  ignore = true;
143  if (!from && mutt_str_startswith(buf, "From "))
144  {
145  if ((chflags & CH_FROM) == 0)
146  continue;
147  from = true;
148  }
149  else if ((chflags & CH_NOQFROM) && mutt_istr_startswith(buf, ">From "))
150  continue;
151  else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
152  break; /* end of header */
153 
154  if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
155  (mutt_istr_startswith(buf, "Status:") || mutt_istr_startswith(buf, "X-Status:")))
156  {
157  continue;
158  }
159  if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
160  (mutt_istr_startswith(buf, "Content-Length:") ||
161  mutt_istr_startswith(buf, "Lines:")))
162  {
163  continue;
164  }
165  if ((chflags & CH_UPDATE_REFS) &&
166  mutt_istr_startswith(buf, "References:"))
167  {
168  continue;
169  }
170  if ((chflags & CH_UPDATE_IRT) &&
171  mutt_istr_startswith(buf, "In-Reply-To:"))
172  {
173  continue;
174  }
175  if (chflags & CH_UPDATE_LABEL && mutt_istr_startswith(buf, "X-Label:"))
176  continue;
177  if ((chflags & CH_UPDATE_SUBJECT) &&
178  mutt_istr_startswith(buf, "Subject:"))
179  {
180  continue;
181  }
182 
183  ignore = false;
184  }
185 
186  if (!ignore && (fputs(buf, fp_out) == EOF))
187  return -1;
188  }
189  return 0;
190  }
191 
192  hdr_count = 1;
193  x = 0;
194 
195  /* We are going to read and collect the headers in an array
196  * so we are able to do re-ordering.
197  * First count the number of entries in the array */
198  if (chflags & CH_REORDER)
199  {
200  struct ListNode *np = NULL;
201  STAILQ_FOREACH(np, &HeaderOrderList, entries)
202  {
203  mutt_debug(LL_DEBUG3, "Reorder list: %s\n", np->data);
204  hdr_count++;
205  }
206  }
207 
208  mutt_debug(LL_DEBUG1, "WEED is %sset\n", (chflags & CH_WEED) ? "" : "not ");
209 
210  ARRAY_RESERVE(&headers, hdr_count);
211 
212  /* Read all the headers into the array */
213  while (ftello(fp_in) < off_end)
214  {
215  nl = strchr(buf, '\n');
216 
217  /* Read a line */
218  if (!fgets(buf, sizeof(buf), fp_in))
219  break;
220 
221  /* Is it the beginning of a header? */
222  if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
223  {
224  /* Do we have anything pending? */
225  if (this_one)
226  {
227  if (chflags & CH_DECODE)
228  {
229  if (address_header_decode(&this_one) == 0)
230  rfc2047_decode(&this_one);
231  this_one_len = mutt_str_len(this_one);
232 
233  /* Convert CRLF line endings to LF */
234  if ((this_one_len > 2) && (this_one[this_one_len - 2] == '\r') &&
235  (this_one[this_one_len - 1] == '\n'))
236  {
237  this_one[this_one_len - 2] = '\n';
238  this_one[this_one_len - 1] = '\0';
239  }
240  }
241 
242  add_one_header(&headers, x, this_one);
243  this_one = NULL;
244  }
245 
246  ignore = true;
247  this_is_from = false;
248  if (!from && mutt_str_startswith(buf, "From "))
249  {
250  if ((chflags & CH_FROM) == 0)
251  continue;
252  this_is_from = true;
253  from = true;
254  }
255  else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
256  break; /* end of header */
257 
258  /* note: CH_FROM takes precedence over header weeding. */
259  if (!((chflags & CH_FROM) && (chflags & CH_FORCE_FROM) && this_is_from) &&
260  (chflags & CH_WEED) && mutt_matches_ignore(buf))
261  {
262  continue;
263  }
264  if ((chflags & CH_WEED_DELIVERED) &&
265  mutt_istr_startswith(buf, "Delivered-To:"))
266  {
267  continue;
268  }
269  if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
270  (mutt_istr_startswith(buf, "Status:") ||
271  mutt_istr_startswith(buf, "X-Status:")))
272  {
273  continue;
274  }
275  if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
276  (mutt_istr_startswith(buf, "Content-Length:") || mutt_istr_startswith(buf, "Lines:")))
277  {
278  continue;
279  }
280  if ((chflags & CH_MIME))
281  {
282  if (mutt_istr_startswith(buf, "mime-version:"))
283  {
284  continue;
285  }
286  size_t plen = mutt_istr_startswith(buf, "content-");
287  if ((plen != 0) &&
288  (mutt_istr_startswith(buf + plen, "transfer-encoding:") ||
289  mutt_istr_startswith(buf + plen, "type:")))
290  {
291  continue;
292  }
293  }
294  if ((chflags & CH_UPDATE_REFS) &&
295  mutt_istr_startswith(buf, "References:"))
296  {
297  continue;
298  }
299  if ((chflags & CH_UPDATE_IRT) &&
300  mutt_istr_startswith(buf, "In-Reply-To:"))
301  {
302  continue;
303  }
304  if ((chflags & CH_UPDATE_LABEL) && mutt_istr_startswith(buf, "X-Label:"))
305  continue;
306  if ((chflags & CH_UPDATE_SUBJECT) &&
307  mutt_istr_startswith(buf, "Subject:"))
308  {
309  continue;
310  }
311 
312  /* Find x -- the array entry where this header is to be saved */
313  if (chflags & CH_REORDER)
314  {
315  struct ListNode *np = NULL;
316  x = 0;
317  STAILQ_FOREACH(np, &HeaderOrderList, entries)
318  {
319  ++x;
320  if (mutt_istr_startswith(buf, np->data))
321  {
322  mutt_debug(LL_DEBUG2, "Reorder: %s matches %s", np->data, buf);
323  break;
324  }
325  }
326  }
327 
328  ignore = false;
329  } /* If beginning of header */
330 
331  if (!ignore)
332  {
333  mutt_debug(LL_DEBUG2, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count);
334  if (this_one)
335  {
336  size_t blen = mutt_str_len(buf);
337 
338  mutt_mem_realloc(&this_one, this_one_len + blen + sizeof(char));
339  strcat(this_one + this_one_len, buf);
340  this_one_len += blen;
341  }
342  else
343  {
344  this_one = mutt_str_dup(buf);
345  this_one_len = mutt_str_len(this_one);
346  }
347  }
348  } /* while (ftello (fp_in) < off_end) */
349 
350  /* Do we have anything pending? -- XXX, same code as in above in the loop. */
351  if (this_one)
352  {
353  if (chflags & CH_DECODE)
354  {
355  if (address_header_decode(&this_one) == 0)
356  rfc2047_decode(&this_one);
357  this_one_len = mutt_str_len(this_one);
358  }
359 
360  add_one_header(&headers, x, this_one);
361  this_one = NULL;
362  }
363 
364  /* Now output the headers in order */
365  bool error = false;
366  char **hp = NULL;
367  ARRAY_FOREACH(hp, &headers)
368  {
369  if (!error && hp && *hp)
370  {
371  /* We couldn't do the prefixing when reading because RFC2047
372  * decoding may have concatenated lines. */
373  if (chflags & (CH_DECODE | CH_PREFIX))
374  {
375  const char *pre = (chflags & CH_PREFIX) ? prefix : NULL;
376  const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
377  wraplen = mutt_window_wrap_cols(wraplen, c_wrap);
378 
379  if (mutt_write_one_header(fp_out, 0, *hp, pre, wraplen, chflags, NeoMutt->sub) == -1)
380  {
381  error = true;
382  }
383  }
384  else
385  {
386  if (fputs(*hp, fp_out) == EOF)
387  {
388  error = true;
389  }
390  }
391  }
392 
393  FREE(hp);
394  }
395  ARRAY_FREE(&headers);
396 
397  if (error)
398  return -1;
399  return 0;
400 }
401 
413 int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out,
414  CopyHeaderFlags chflags, const char *prefix, int wraplen)
415 {
416  char *temp_hdr = NULL;
417 
418  if (e->env)
419  {
420  chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
424  }
425 
426  if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
427  return -1;
428 
429  if (chflags & CH_TXTPLAIN)
430  {
431  char chsbuf[128];
432  char buf[128];
433  fputs("MIME-Version: 1.0\n", fp_out);
434  fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
435  fputs("Content-Type: text/plain; charset=", fp_out);
436  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
437  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
438  mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
439  fputs(buf, fp_out);
440  fputc('\n', fp_out);
441  }
442 
443  if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
444  {
445  fputs("In-Reply-To:", fp_out);
446  struct ListNode *np = NULL;
447  STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
448  {
449  fputc(' ', fp_out);
450  fputs(np->data, fp_out);
451  }
452  fputc('\n', fp_out);
453  }
454 
455  if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
456  {
457  fputs("References:", fp_out);
458  mutt_write_references(&e->env->references, fp_out, 0, NeoMutt->sub);
459  fputc('\n', fp_out);
460  }
461 
462  if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
463  {
464  if (e->old || e->read)
465  {
466  fputs("Status: ", fp_out);
467  if (e->read)
468  fputs("RO", fp_out);
469  else if (e->old)
470  fputc('O', fp_out);
471  fputc('\n', fp_out);
472  }
473 
474  if (e->flagged || e->replied)
475  {
476  fputs("X-Status: ", fp_out);
477  if (e->replied)
478  fputc('A', fp_out);
479  if (e->flagged)
480  fputc('F', fp_out);
481  fputc('\n', fp_out);
482  }
483  }
484 
485  if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
486  {
487  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
488  if ((e->lines != 0) || (e->body->length == 0))
489  fprintf(fp_out, "Lines: %d\n", e->lines);
490  }
491 
492  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
493 #ifdef USE_NOTMUCH
494  if (chflags & CH_VIRTUAL)
495  {
496  /* Add some fake headers based on notmuch data */
497  char *folder = nm_email_get_folder(e);
498  if (folder && !(c_weed && mutt_matches_ignore("folder")))
499  {
500  char buf[1024];
501  mutt_str_copy(buf, folder, sizeof(buf));
502  mutt_pretty_mailbox(buf, sizeof(buf));
503 
504  fputs("Folder: ", fp_out);
505  fputs(buf, fp_out);
506  fputc('\n', fp_out);
507  }
508  }
509 #endif
510  char *tags = driver_tags_get(&e->tags);
511  if (tags && !(c_weed && mutt_matches_ignore("tags")))
512  {
513  fputs("Tags: ", fp_out);
514  fputs(tags, fp_out);
515  fputc('\n', fp_out);
516  }
517  FREE(&tags);
518 
519  const char *const c_send_charset =
520  cs_subset_string(NeoMutt->sub, "send_charset");
521  const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
522  if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
523  {
524  temp_hdr = e->env->x_label;
525  /* env->x_label isn't currently stored with direct references elsewhere.
526  * Context->label_hash strdups the keys. But to be safe, encode a copy */
527  if (!(chflags & CH_DECODE))
528  {
529  temp_hdr = mutt_str_dup(temp_hdr);
530  rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
531  }
533  fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
534  mutt_window_wrap_cols(wraplen, c_wrap), chflags, NeoMutt->sub) == -1)
535  {
536  return -1;
537  }
538  if (!(chflags & CH_DECODE))
539  FREE(&temp_hdr);
540  }
541 
542  if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
543  {
544  temp_hdr = e->env->subject;
545  /* env->subject is directly referenced in Context->subj_hash, so we
546  * have to be careful not to encode (and thus free) that memory. */
547  if (!(chflags & CH_DECODE))
548  {
549  temp_hdr = mutt_str_dup(temp_hdr);
550  rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
551  }
553  fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
554  mutt_window_wrap_cols(wraplen, c_wrap), chflags, NeoMutt->sub) == -1)
555  {
556  return -1;
557  }
558  if (!(chflags & CH_DECODE))
559  FREE(&temp_hdr);
560  }
561 
562  if ((chflags & CH_NONEWLINE) == 0)
563  {
564  if (chflags & CH_PREFIX)
565  fputs(prefix, fp_out);
566  fputc('\n', fp_out); /* add header terminator */
567  }
568 
569  if (ferror(fp_out) || feof(fp_out))
570  return -1;
571 
572  return 0;
573 }
574 
585 static int count_delete_lines(FILE *fp, struct Body *b, LOFF_T *length, size_t datelen)
586 {
587  int dellines = 0;
588 
589  if (b->deleted)
590  {
591  fseeko(fp, b->offset, SEEK_SET);
592  for (long l = b->length; l; l--)
593  {
594  const int ch = getc(fp);
595  if (ch == EOF)
596  break;
597  if (ch == '\n')
598  dellines++;
599  }
600  /* 3 and 89 come from the added header of three lines in
601  * copy_delete_attach(). 89 is the size of the header(including
602  * the newlines, tabs, and a single digit length), not including
603  * the date length. */
604  dellines -= 3;
605  *length -= b->length - (89 + datelen);
606  /* Count the number of digits exceeding the first one to write the size */
607  for (long l = 10; b->length >= l; l *= 10)
608  (*length)++;
609  }
610  else
611  {
612  for (b = b->parts; b; b = b->next)
613  dellines += count_delete_lines(fp, b, length, datelen);
614  }
615  return dellines;
616 }
617 
629 int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e,
630  CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
631 {
632  struct Body *body = e->body;
633  char prefix[128];
634  LOFF_T new_offset = -1;
635  int rc = 0;
636 
637  if (cmflags & MUTT_CM_PREFIX)
638  {
639  const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
640  if (c_text_flowed)
641  mutt_str_copy(prefix, ">", sizeof(prefix));
642  else
643  {
644  const char *const c_indent_string =
645  cs_subset_string(NeoMutt->sub, "indent_string");
646  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(c_indent_string),
647  Context->mailbox, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
648  }
649  }
650 
651  if ((cmflags & MUTT_CM_NOHEADER) == 0)
652  {
653  if (cmflags & MUTT_CM_PREFIX)
654  chflags |= CH_PREFIX;
655  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
656  {
657  int new_lines;
658  int rc_attach_del = -1;
659  LOFF_T new_length = body->length;
660  struct Buffer *quoted_date = NULL;
661 
662  quoted_date = mutt_buffer_pool_get();
663  mutt_buffer_addch(quoted_date, '"');
664  mutt_date_make_date(quoted_date,
665  cs_subset_bool(NeoMutt->sub, "local_date_header"));
666  mutt_buffer_addch(quoted_date, '"');
667 
668  /* Count the number of lines and bytes to be deleted */
669  fseeko(fp_in, body->offset, SEEK_SET);
670  new_lines = e->lines - count_delete_lines(fp_in, body, &new_length,
671  mutt_buffer_len(quoted_date));
672 
673  /* Copy the headers */
674  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
675  goto attach_del_cleanup;
676  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
677  if (new_lines <= 0)
678  new_lines = 0;
679  else
680  fprintf(fp_out, "Lines: %d\n", new_lines);
681 
682  putc('\n', fp_out);
683  if (ferror(fp_out) || feof(fp_out))
684  goto attach_del_cleanup;
685  new_offset = ftello(fp_out);
686 
687  /* Copy the body */
688  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
689  goto attach_del_cleanup;
690  if (copy_delete_attach(body, fp_in, fp_out, mutt_buffer_string(quoted_date)))
691  goto attach_del_cleanup;
692 
693  mutt_buffer_pool_release(&quoted_date);
694 
695  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
696  if (fail)
697  {
698  mutt_error(ngettext("The length calculation was wrong by %ld byte",
699  "The length calculation was wrong by %ld bytes", fail),
700  fail);
701  new_length += fail;
702  }
703 
704  /* Update original message if we are sync'ing a mailfolder */
705  if (cmflags & MUTT_CM_UPDATE)
706  {
707  e->attach_del = false;
708  e->lines = new_lines;
709  body->offset = new_offset;
710 
711  /* update the total size of the mailbox to reflect this deletion */
712  Context->mailbox->size -= body->length - new_length;
713  /* if the message is visible, update the visible size of the mailbox as well. */
714  if (Context->mailbox->v2r[e->msgno] != -1)
715  Context->vsize -= body->length - new_length;
716 
717  body->length = new_length;
718  mutt_body_free(&body->parts);
719  }
720 
721  rc_attach_del = 0;
722 
723  attach_del_cleanup:
724  mutt_buffer_pool_release(&quoted_date);
725  return rc_attach_del;
726  }
727 
728  if (mutt_copy_header(fp_in, e, fp_out, chflags,
729  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
730  {
731  return -1;
732  }
733 
734  new_offset = ftello(fp_out);
735  }
736 
737  if (cmflags & MUTT_CM_DECODE)
738  {
739  /* now make a text/plain version of the message */
740  struct State s = { 0 };
741  s.fp_in = fp_in;
742  s.fp_out = fp_out;
743  if (cmflags & MUTT_CM_PREFIX)
744  s.prefix = prefix;
745  if (cmflags & MUTT_CM_DISPLAY)
746  {
747  s.flags |= MUTT_DISPLAY;
748  s.wraplen = wraplen;
749  }
750  if (cmflags & MUTT_CM_PRINTING)
751  s.flags |= MUTT_PRINTING;
752  if (cmflags & MUTT_CM_WEED)
753  s.flags |= MUTT_WEED;
754  if (cmflags & MUTT_CM_CHARCONV)
755  s.flags |= MUTT_CHARCONV;
756  if (cmflags & MUTT_CM_REPLYING)
757  s.flags |= MUTT_REPLYING;
758 
759  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
760  s.flags |= MUTT_VERIFY;
761 
762  rc = mutt_body_handler(body, &s);
763  }
764  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
765  {
766  struct Body *cur = NULL;
767  FILE *fp = NULL;
768 
769  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
770  (e->security & APPLICATION_PGP) && (e->body->type == TYPE_MULTIPART))
771  {
772  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
773  return -1;
774  fputs("MIME-Version: 1.0\n", fp_out);
775  }
776 
777  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
778  (e->security & APPLICATION_SMIME) && (e->body->type == TYPE_APPLICATION))
779  {
780  if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
781  return -1;
782  }
783 
784  if (!cur)
785  {
786  mutt_error(_("No decryption engine available for message"));
787  return -1;
788  }
789 
790  mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
791  fputc('\n', fp_out);
792 
793  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
794  return -1;
795  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
796  {
797  mutt_file_fclose(&fp);
798  mutt_body_free(&cur);
799  return -1;
800  }
801  mutt_body_free(&cur);
802  mutt_file_fclose(&fp);
803  }
804  else
805  {
806  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
807  return -1;
808  if (cmflags & MUTT_CM_PREFIX)
809  {
810  int c;
811  size_t bytes = body->length;
812 
813  fputs(prefix, fp_out);
814 
815  while (((c = fgetc(fp_in)) != EOF) && bytes--)
816  {
817  fputc(c, fp_out);
818  if (c == '\n')
819  {
820  fputs(prefix, fp_out);
821  }
822  }
823  }
824  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
825  return -1;
826  }
827 
828  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
829  (new_offset != -1))
830  {
831  body->offset = new_offset;
832  mutt_body_free(&body->parts);
833  }
834 
835  return rc;
836 }
837 
853 int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e,
854  struct Message *msg, CopyMessageFlags cmflags,
855  CopyHeaderFlags chflags, int wraplen)
856 {
857  if (!msg || !e->body)
858  {
859  return -1;
860  }
861  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
862  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
863  {
864  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
865  rc = -1;
866  }
867  return rc;
868 }
869 
881 static int append_message(struct Mailbox *dest, FILE *fp_in, struct Mailbox *src,
882  struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
883 {
884  char buf[256];
885  struct Message *msg = NULL;
886  int rc;
887 
888  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
889  return -1;
890  if (!fgets(buf, sizeof(buf), fp_in))
891  return -1;
892 
893  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
894  if (!msg)
895  return -1;
896  if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
897  chflags |= CH_FROM | CH_FORCE_FROM;
898  chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
899  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
900  if (mx_msg_commit(dest, msg) != 0)
901  rc = -1;
902 
903 #ifdef USE_NOTMUCH
904  if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
905  nm_update_filename(src, NULL, msg->committed_path, e);
906 #endif
907 
908  mx_msg_close(dest, &msg);
909  return rc;
910 }
911 
923 int mutt_append_message(struct Mailbox *m_dst, struct Mailbox *m_src,
924  struct Email *e, struct Message *msg,
925  CopyMessageFlags cmflags, CopyHeaderFlags chflags)
926 {
927  const bool own_msg = !msg;
928  if (own_msg && !(msg = mx_msg_open(m_src, e->msgno)))
929  {
930  return -1;
931  }
932 
933  int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
934  if (own_msg)
935  {
936  mx_msg_close(m_src, &msg);
937  }
938  return rc;
939 }
940 
954 static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
955 {
956  struct Body *part = NULL;
957 
958  for (part = b->parts; part; part = part->next)
959  {
960  if (part->deleted || part->parts)
961  {
962  /* Copy till start of this part */
963  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
964  return -1;
965 
966  if (part->deleted)
967  {
968  /* If this is modified, count_delete_lines() needs to be changed too */
969  fprintf(
970  fp_out,
971  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
972  "\texpiration=%s; length=" OFF_T_FMT "\n"
973  "\n",
974  quoted_date, part->length);
975  if (ferror(fp_out))
976  return -1;
977 
978  /* Copy the original mime headers */
979  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
980  return -1;
981 
982  /* Skip the deleted body */
983  fseeko(fp_in, part->offset + part->length, SEEK_SET);
984  }
985  else
986  {
987  if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
988  return -1;
989  }
990  }
991  }
992 
993  /* Copy the last parts */
994  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
995  return -1;
996 
997  return 0;
998 }
999 
1011 static void format_address_header(char **h, struct AddressList *al)
1012 {
1013  char buf[8192];
1014  char cbuf[256];
1015  char c2buf[256];
1016  char *p = NULL;
1017  size_t linelen, buflen, plen;
1018 
1019  linelen = mutt_str_len(*h);
1020  plen = linelen;
1021  buflen = linelen + 3;
1022 
1023  mutt_mem_realloc(h, buflen);
1024  struct Address *first = TAILQ_FIRST(al);
1025  struct Address *a = NULL;
1026  TAILQ_FOREACH(a, al, entries)
1027  {
1028  *buf = '\0';
1029  *cbuf = '\0';
1030  *c2buf = '\0';
1031  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
1032 
1033  if (a != first && (linelen + l > 74))
1034  {
1035  strcpy(cbuf, "\n\t");
1036  linelen = l + 8;
1037  }
1038  else
1039  {
1040  if (a->mailbox)
1041  {
1042  strcpy(cbuf, " ");
1043  linelen++;
1044  }
1045  linelen += l;
1046  }
1047  if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
1048  {
1049  linelen++;
1050  buflen++;
1051  strcpy(c2buf, ",");
1052  }
1053 
1054  const size_t cbuflen = mutt_str_len(cbuf);
1055  const size_t c2buflen = mutt_str_len(c2buf);
1056  buflen += l + cbuflen + c2buflen;
1057  mutt_mem_realloc(h, buflen);
1058  p = *h;
1059  strcat(p + plen, cbuf);
1060  plen += cbuflen;
1061  strcat(p + plen, buf);
1062  plen += l;
1063  strcat(p + plen, c2buf);
1064  plen += c2buflen;
1065  }
1066 
1067  /* Space for this was allocated in the beginning of this function. */
1068  strcat(p + plen, "\n");
1069 }
1070 
1077 static int address_header_decode(char **h)
1078 {
1079  char *s = *h;
1080  size_t l;
1081  bool rp = false;
1082 
1083  switch (tolower((unsigned char) *s))
1084  {
1085  case 'b':
1086  {
1087  if (!(l = mutt_istr_startswith(s, "bcc:")))
1088  return 0;
1089  break;
1090  }
1091  case 'c':
1092  {
1093  if (!(l = mutt_istr_startswith(s, "cc:")))
1094  return 0;
1095  break;
1096  }
1097  case 'f':
1098  {
1099  if (!(l = mutt_istr_startswith(s, "from:")))
1100  return 0;
1101  break;
1102  }
1103  case 'm':
1104  {
1105  if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1106  return 0;
1107  break;
1108  }
1109  case 'r':
1110  {
1111  if ((l = mutt_istr_startswith(s, "return-path:")))
1112  {
1113  rp = true;
1114  break;
1115  }
1116  else if ((l = mutt_istr_startswith(s, "reply-to:")))
1117  {
1118  break;
1119  }
1120  return 0;
1121  }
1122  case 's':
1123  {
1124  if (!(l = mutt_istr_startswith(s, "sender:")))
1125  return 0;
1126  break;
1127  }
1128  case 't':
1129  {
1130  if (!(l = mutt_istr_startswith(s, "to:")))
1131  return 0;
1132  break;
1133  }
1134  default:
1135  return 0;
1136  }
1137 
1138  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1139  mutt_addrlist_parse(&al, s + l);
1140  if (TAILQ_EMPTY(&al))
1141  return 0;
1142 
1145  struct Address *a = NULL;
1146  TAILQ_FOREACH(a, &al, entries)
1147  {
1148  if (a->personal)
1149  {
1151  }
1152  }
1153 
1154  /* angle brackets for return path are mandated by RFC5322,
1155  * so leave Return-Path as-is */
1156  if (rp)
1157  *h = mutt_str_dup(s);
1158  else
1159  {
1160  *h = mutt_mem_calloc(1, l + 2);
1161  mutt_str_copy(*h, s, l + 1);
1162  format_address_header(h, &al);
1163  }
1164 
1165  mutt_addrlist_clear(&al);
1166 
1167  FREE(&s);
1168  return 1;
1169 }
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:48
Convenience wrapper for the gui headers.
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:41
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:316
The "current" mailbox.
Definition: context.h:37
#define ARRAY_RESERVE(head, num)
Reserve memory for the array.
Definition: array.h:185
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:526
int lines
How many lines in the body of this message?
Definition: email.h:85
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
off_t size
Size of the Mailbox.
Definition: mailbox.h:87
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define WithCrypto
Definition: lib.h:113
The envelope/body of an email.
Definition: email.h:37
static void format_address_header(char **h, struct AddressList *al)
Write address headers to a buffer.
Definition: copy.c:1011
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define TAILQ_FIRST(head)
Definition: queue.h:723
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:764
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
struct Body * body
List of MIME parts.
Definition: email.h:91
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
Structs that make up an email.
String processing routines to generate the mail index.
#define mutt_error(...)
Definition: logging.h:88
The "currently-open" mailbox.
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
Convenience wrapper for the send headers.
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1388
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:198
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:206
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
int mutt_append_message(struct Mailbox *m_dst, struct Mailbox *m_src, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Append a message.
Definition: copy.c:923
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:105
void mutt_str_dequote_comment(char *str)
Un-escape characters in an email address comment.
Definition: string.c:872
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:41
String manipulation buffer.
Definition: buffer.h:33
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:378
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
#define _(a)
Definition: message.h:28
static int count_delete_lines(FILE *fp, struct Body *b, LOFF_T *length, size_t datelen)
Count lines to be deleted in this email body.
Definition: copy.c:585
struct Body * next
next attachment in the list
Definition: body.h:53
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:58
An email address.
Definition: address.h:35
FILE * fp_out
File to write to.
Definition: state.h:47
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
char * mailbox
Mailbox and host address.
Definition: address.h:38
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:32
#define CH_UPDATE_REFS
Update References:
Definition: copy.h:69
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim, struct ConfigSubset *sub)
Add the message references to a list.
Definition: header.c:515
Flags to control mutt_expando_format()
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:43
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
Container for Accounts, Notifications.
Definition: neomutt.h:36
FILE * fp_in
File to read from.
Definition: state.h:46
#define MUTT_ENV_CHANGED_SUBJECT
Protected header update.
Definition: envelope.h:35
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:44
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
The body of an email.
Definition: body.h:34
Convenience wrapper for the config headers.
Email Address Handling.
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Some miscellaneous functions.
int nm_update_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Change the filename.
Definition: notmuch.c:1747
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:65
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
bool read
Email is read.
Definition: email.h:51
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
static int append_message(struct Mailbox *dest, FILE *fp_in, struct Mailbox *src, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
appends a copy of the given message to a mailbox
Definition: copy.c:881
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1054
struct Mailbox * mailbox
Definition: context.h:49
#define MUTT_CM_DISPLAY
Output is displayed to the user.
Definition: copy.h:39
Many unsorted constants and some structs.
Log at debug level 2.
Definition: logging.h:41
API for mailboxes.
bool old
Email is seen, but unread.
Definition: email.h:50
static int address_header_decode(char **h)
Parse an email&#39;s headers.
Definition: copy.c:1077
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:641
#define CH_WEED
Weed the headers?
Definition: copy.h:53
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1409
struct Envelope * env
Envelope information.
Definition: email.h:90
Convenience wrapper for the core headers.
#define CH_VIRTUAL
Write virtual header lines too.
Definition: copy.h:73
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:54
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:764
int wraplen
Width to wrap lines to (when flags & MUTT_DISPLAY)
Definition: state.h:50
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1025
struct TagList tags
For drivers that support server tagging.
Definition: email.h:109
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define CH_FORCE_FROM
Give CH_FROM precedence over CH_WEED?
Definition: copy.h:66
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
off_t vsize
Size (in bytes) of the messages shown.
Definition: context.h:39
#define CH_UPDATE_LABEL
Update X-Label: from email->env->x_label?
Definition: copy.h:71
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:37
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:34
Notmuch virtual mailbox type.
static void add_one_header(struct Headers *headers, size_t pos, char *value)
Add a header to a Headers array.
Definition: copy.c:74
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
A local copy of an email.
Definition: mxapi.h:41
#define CH_UPDATE_IRT
Update In-Reply-To:
Definition: copy.h:68
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
A mailbox.
Definition: mailbox.h:81
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:145
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:59
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
Copy a message, deleting marked attachments.
Definition: copy.c:954
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:55
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
ARRAY_HEAD(Headers, char *)
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
#define MUTT_WEED
Weed headers even when not in display mode.
Definition: state.h:35
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1458
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
API for encryption/signing of emails.
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:386
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:439
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
int 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
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
#define MUTT_CM_VERIFY
Do signature verification.
Definition: copy.h:47
#define CH_NOLEN
Don&#39;t write Content-Length: and Lines:
Definition: copy.h:64
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define CH_UPDATE_SUBJECT
Update Subject: protected header update.
Definition: copy.h:72
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:616
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:84
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition: array.h:119
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:45
char * personal
Real name of address.
Definition: address.h:37
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:46
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:67
bool deleted
Attachment marked for deletion.
Definition: body.h:71
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:212
char * data
String.
Definition: list.h:36
char * subject
Email&#39;s subject.
Definition: envelope.h:66
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Duplicate the structure of an entire email.
Log at debug level 1.
Definition: logging.h:40
bool group
Group mailbox?
Definition: address.h:39
bool flagged
Marked important?
Definition: email.h:43
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition: copy.c:413
bool replied
Email has been replied to.
Definition: email.h:54
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1165
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:104
FILE * fp
pointer to the message data
Definition: mxapi.h:43
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:853
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#define FREE(x)
Definition: memory.h:40
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
Keep track when processing files.
Definition: state.h:44
#define STAILQ_EMPTY(head)
Definition: queue.h:348
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1604
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:48
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:33
Hundreds of global variables to back the user variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
#define MUTT_ENV_CHANGED_IRT
In-Reply-To changed to link/break threads.
Definition: envelope.h:32
#define TAILQ_EMPTY(head)
Definition: queue.h:721
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1128
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
make a copy of a message from a FILE pointer
Definition: copy.c:629
#define MUTT_CM_NOHEADER
Don&#39;t copy the message header.
Definition: copy.h:36
Convenience wrapper for the library headers.
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:34
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:42
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
Decide how to display email content.
char * x_label
X-Label.
Definition: envelope.h:72
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:57
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:354
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition: address.c:681
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1140
Type: &#39;application/*&#39;.
Definition: mime.h:33
Log at debug level 3.
Definition: logging.h:42
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags, struct ConfigSubset *sub)
Write one header line to a file.
Definition: header.c:420
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:60
int msgno
Number displayed to the user.
Definition: email.h:87