NeoMutt  2020-06-26-89-g172cd3
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 "email/lib.h"
38 #include "core/lib.h"
39 #include "gui/lib.h"
40 #include "mutt.h"
41 #include "copy.h"
42 #include "context.h"
43 #include "handler.h"
44 #include "hdrline.h"
45 #include "mutt_globals.h"
46 #include "mx.h"
47 #include "state.h"
48 #include "ncrypt/lib.h"
49 #include "send/lib.h"
50 #ifdef USE_NOTMUCH
51 #include "muttlib.h"
52 #include "notmuch/lib.h"
53 #endif
54 #ifdef ENABLE_NLS
55 #include <libintl.h>
56 #endif
57 
58 static int address_header_decode(char **h);
59 static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, char *date);
60 
77 int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end,
78  CopyHeaderFlags chflags, const char *prefix, int wraplen)
79 {
80  bool from = false;
81  bool this_is_from = false;
82  bool ignore = false;
83  char buf[1024]; /* should be long enough to get most fields in one pass */
84  char *nl = NULL;
85  char **headers = NULL;
86  int hdr_count;
87  int x;
88  char *this_one = NULL;
89  size_t this_one_len = 0;
90  int error;
91 
92  if (off_start < 0)
93  return -1;
94 
95  if (ftello(fp_in) != off_start)
96  if (fseeko(fp_in, off_start, SEEK_SET) < 0)
97  return -1;
98 
99  buf[0] = '\n';
100  buf[1] = '\0';
101 
102  if ((chflags & (CH_REORDER | CH_WEED | CH_MIME | CH_DECODE | CH_PREFIX | CH_WEED_DELIVERED)) == 0)
103  {
104  /* Without these flags to complicate things
105  * we can do a more efficient line to line copying */
106  while (ftello(fp_in) < off_end)
107  {
108  nl = strchr(buf, '\n');
109 
110  if (!fgets(buf, sizeof(buf), fp_in))
111  break;
112 
113  /* Is it the beginning of a header? */
114  if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
115  {
116  ignore = true;
117  if (!from && mutt_str_startswith(buf, "From "))
118  {
119  if ((chflags & CH_FROM) == 0)
120  continue;
121  from = true;
122  }
123  else if ((chflags & CH_NOQFROM) && mutt_istr_startswith(buf, ">From "))
124  continue;
125  else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
126  break; /* end of header */
127 
128  if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
129  (mutt_istr_startswith(buf, "Status:") || mutt_istr_startswith(buf, "X-Status:")))
130  {
131  continue;
132  }
133  if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
134  (mutt_istr_startswith(buf, "Content-Length:") ||
135  mutt_istr_startswith(buf, "Lines:")))
136  {
137  continue;
138  }
139  if ((chflags & CH_UPDATE_REFS) &&
140  mutt_istr_startswith(buf, "References:"))
141  continue;
142  if ((chflags & CH_UPDATE_IRT) &&
143  mutt_istr_startswith(buf, "In-Reply-To:"))
144  continue;
145  if (chflags & CH_UPDATE_LABEL && mutt_istr_startswith(buf, "X-Label:"))
146  continue;
147  if ((chflags & CH_UPDATE_SUBJECT) &&
148  mutt_istr_startswith(buf, "Subject:"))
149  continue;
150 
151  ignore = false;
152  }
153 
154  if (!ignore && (fputs(buf, fp_out) == EOF))
155  return -1;
156  }
157  return 0;
158  }
159 
160  hdr_count = 1;
161  x = 0;
162  error = false;
163 
164  /* We are going to read and collect the headers in an array
165  * so we are able to do re-ordering.
166  * First count the number of entries in the array */
167  if (chflags & CH_REORDER)
168  {
169  struct ListNode *np = NULL;
170  STAILQ_FOREACH(np, &HeaderOrderList, entries)
171  {
172  mutt_debug(LL_DEBUG3, "Reorder list: %s\n", np->data);
173  hdr_count++;
174  }
175  }
176 
177  mutt_debug(LL_DEBUG1, "WEED is %sset\n", (chflags & CH_WEED) ? "" : "not ");
178 
179  headers = mutt_mem_calloc(hdr_count, sizeof(char *));
180 
181  /* Read all the headers into the array */
182  while (ftello(fp_in) < off_end)
183  {
184  nl = strchr(buf, '\n');
185 
186  /* Read a line */
187  if (!fgets(buf, sizeof(buf), fp_in))
188  break;
189 
190  /* Is it the beginning of a header? */
191  if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
192  {
193  /* Do we have anything pending? */
194  if (this_one)
195  {
196  if (chflags & CH_DECODE)
197  {
198  if (address_header_decode(&this_one) == 0)
199  rfc2047_decode(&this_one);
200  this_one_len = mutt_str_len(this_one);
201 
202  /* Convert CRLF line endings to LF */
203  if ((this_one_len > 2) && (this_one[this_one_len - 2] == '\r') &&
204  (this_one[this_one_len - 1] == '\n'))
205  {
206  this_one[this_one_len - 2] = '\n';
207  this_one[this_one_len - 1] = '\0';
208  }
209  }
210 
211  if (!headers[x])
212  headers[x] = this_one;
213  else
214  {
215  int hlen = mutt_str_len(headers[x]);
216 
217  mutt_mem_realloc(&headers[x], hlen + this_one_len + sizeof(char));
218  strcat(headers[x] + hlen, this_one);
219  FREE(&this_one);
220  }
221 
222  this_one = NULL;
223  }
224 
225  ignore = true;
226  this_is_from = false;
227  if (!from && mutt_str_startswith(buf, "From "))
228  {
229  if ((chflags & CH_FROM) == 0)
230  continue;
231  this_is_from = true;
232  from = true;
233  }
234  else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
235  break; /* end of header */
236 
237  /* note: CH_FROM takes precedence over header weeding. */
238  if (!((chflags & CH_FROM) && (chflags & CH_FORCE_FROM) && this_is_from) &&
239  (chflags & CH_WEED) && mutt_matches_ignore(buf))
240  {
241  continue;
242  }
243  if ((chflags & CH_WEED_DELIVERED) &&
244  mutt_istr_startswith(buf, "Delivered-To:"))
245  {
246  continue;
247  }
248  if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
249  (mutt_istr_startswith(buf, "Status:") ||
250  mutt_istr_startswith(buf, "X-Status:")))
251  {
252  continue;
253  }
254  if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
255  (mutt_istr_startswith(buf, "Content-Length:") || mutt_istr_startswith(buf, "Lines:")))
256  {
257  continue;
258  }
259  if ((chflags & CH_MIME))
260  {
261  if (mutt_istr_startswith(buf, "mime-version:"))
262  {
263  continue;
264  }
265  size_t plen = mutt_istr_startswith(buf, "content-");
266  if ((plen != 0) &&
267  (mutt_istr_startswith(buf + plen, "transfer-encoding:") ||
268  mutt_istr_startswith(buf + plen, "type:")))
269  {
270  continue;
271  }
272  }
273  if ((chflags & CH_UPDATE_REFS) &&
274  mutt_istr_startswith(buf, "References:"))
275  continue;
276  if ((chflags & CH_UPDATE_IRT) &&
277  mutt_istr_startswith(buf, "In-Reply-To:"))
278  continue;
279  if ((chflags & CH_UPDATE_LABEL) && mutt_istr_startswith(buf, "X-Label:"))
280  continue;
281  if ((chflags & CH_UPDATE_SUBJECT) &&
282  mutt_istr_startswith(buf, "Subject:"))
283  continue;
284 
285  /* Find x -- the array entry where this header is to be saved */
286  if (chflags & CH_REORDER)
287  {
288  struct ListNode *np = NULL;
289  x = 0;
290  STAILQ_FOREACH(np, &HeaderOrderList, entries)
291  {
292  ++x;
293  if (mutt_istr_startswith(buf, np->data))
294  {
295  mutt_debug(LL_DEBUG2, "Reorder: %s matches %s", np->data, buf);
296  break;
297  }
298  }
299  }
300 
301  ignore = false;
302  } /* If beginning of header */
303 
304  if (!ignore)
305  {
306  mutt_debug(LL_DEBUG2, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count);
307  if (this_one)
308  {
309  size_t blen = mutt_str_len(buf);
310 
311  mutt_mem_realloc(&this_one, this_one_len + blen + sizeof(char));
312  strcat(this_one + this_one_len, buf);
313  this_one_len += blen;
314  }
315  else
316  {
317  this_one = mutt_str_dup(buf);
318  this_one_len = mutt_str_len(this_one);
319  }
320  }
321  } /* while (ftello (fp_in) < off_end) */
322 
323  /* Do we have anything pending? -- XXX, same code as in above in the loop. */
324  if (this_one)
325  {
326  if (chflags & CH_DECODE)
327  {
328  if (address_header_decode(&this_one) == 0)
329  rfc2047_decode(&this_one);
330  this_one_len = mutt_str_len(this_one);
331  }
332 
333  if (!headers[x])
334  headers[x] = this_one;
335  else
336  {
337  int hlen = mutt_str_len(headers[x]);
338 
339  mutt_mem_realloc(&headers[x], hlen + this_one_len + sizeof(char));
340  strcat(headers[x] + hlen, this_one);
341  FREE(&this_one);
342  }
343 
344  this_one = NULL;
345  }
346 
347  /* Now output the headers in order */
348  for (x = 0; x < hdr_count; x++)
349  {
350  if (headers[x])
351  {
352  /* We couldn't do the prefixing when reading because RFC2047
353  * decoding may have concatenated lines. */
354  if (chflags & (CH_DECODE | CH_PREFIX))
355  {
356  const char *pre = (chflags & CH_PREFIX) ? prefix : NULL;
357  wraplen = mutt_window_wrap_cols(wraplen, C_Wrap);
358 
359  if (mutt_write_one_header(fp_out, 0, headers[x], pre, wraplen, chflags,
360  NeoMutt->sub) == -1)
361  {
362  error = true;
363  break;
364  }
365  }
366  else
367  {
368  if (fputs(headers[x], fp_out) == EOF)
369  {
370  error = true;
371  break;
372  }
373  }
374  }
375  }
376 
377  /* Free in a separate loop to be sure that all headers are freed
378  * in case of error. */
379  for (x = 0; x < hdr_count; x++)
380  FREE(&headers[x]);
381  FREE(&headers);
382 
383  if (error)
384  return -1;
385  return 0;
386 }
387 
399 int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out,
400  CopyHeaderFlags chflags, const char *prefix, int wraplen)
401 {
402  char *temp_hdr = NULL;
403 
404  if (e->env)
405  {
406  chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
410  }
411 
412  if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->content->offset, chflags,
413  prefix, wraplen) == -1)
414  return -1;
415 
416  if (chflags & CH_TXTPLAIN)
417  {
418  char chsbuf[128];
419  char buf[128];
420  fputs("MIME-Version: 1.0\n", fp_out);
421  fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
422  fputs("Content-Type: text/plain; charset=", fp_out);
423  mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), C_Charset ? C_Charset : "us-ascii");
424  mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
425  fputs(buf, fp_out);
426  fputc('\n', fp_out);
427  }
428 
429  if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
430  {
431  fputs("In-Reply-To:", fp_out);
432  struct ListNode *np = NULL;
433  STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
434  {
435  fputc(' ', fp_out);
436  fputs(np->data, fp_out);
437  }
438  fputc('\n', fp_out);
439  }
440 
441  if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
442  {
443  fputs("References:", fp_out);
444  mutt_write_references(&e->env->references, fp_out, 0, NeoMutt->sub);
445  fputc('\n', fp_out);
446  }
447 
448  if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
449  {
450  if (e->old || e->read)
451  {
452  fputs("Status: ", fp_out);
453  if (e->read)
454  fputs("RO", fp_out);
455  else if (e->old)
456  fputc('O', fp_out);
457  fputc('\n', fp_out);
458  }
459 
460  if (e->flagged || e->replied)
461  {
462  fputs("X-Status: ", fp_out);
463  if (e->replied)
464  fputc('A', fp_out);
465  if (e->flagged)
466  fputc('F', fp_out);
467  fputc('\n', fp_out);
468  }
469  }
470 
471  if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
472  {
473  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->content->length);
474  if ((e->lines != 0) || (e->content->length == 0))
475  fprintf(fp_out, "Lines: %d\n", e->lines);
476  }
477 
478 #ifdef USE_NOTMUCH
479  if (chflags & CH_VIRTUAL)
480  {
481  /* Add some fake headers based on notmuch data */
482  char *folder = nm_email_get_folder(e);
483  if (folder && !(C_Weed && mutt_matches_ignore("folder")))
484  {
485  char buf[1024];
486  mutt_str_copy(buf, folder, sizeof(buf));
487  mutt_pretty_mailbox(buf, sizeof(buf));
488 
489  fputs("Folder: ", fp_out);
490  fputs(buf, fp_out);
491  fputc('\n', fp_out);
492  }
493  }
494 #endif
495  char *tags = driver_tags_get(&e->tags);
496  if (tags && !(C_Weed && mutt_matches_ignore("tags")))
497  {
498  fputs("Tags: ", fp_out);
499  fputs(tags, fp_out);
500  fputc('\n', fp_out);
501  }
502  FREE(&tags);
503 
504  if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
505  {
506  temp_hdr = e->env->x_label;
507  /* env->x_label isn't currently stored with direct references elsewhere.
508  * Context->label_hash strdups the keys. But to be safe, encode a copy */
509  if (!(chflags & CH_DECODE))
510  {
511  temp_hdr = mutt_str_dup(temp_hdr);
512  rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), C_SendCharset);
513  }
515  fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
516  mutt_window_wrap_cols(wraplen, C_Wrap), chflags, NeoMutt->sub) == -1)
517  {
518  return -1;
519  }
520  if (!(chflags & CH_DECODE))
521  FREE(&temp_hdr);
522  }
523 
524  if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
525  {
526  temp_hdr = e->env->subject;
527  /* env->subject is directly referenced in Context->subj_hash, so we
528  * have to be careful not to encode (and thus free) that memory. */
529  if (!(chflags & CH_DECODE))
530  {
531  temp_hdr = mutt_str_dup(temp_hdr);
532  rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), C_SendCharset);
533  }
535  fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
536  mutt_window_wrap_cols(wraplen, C_Wrap), chflags, NeoMutt->sub) == -1)
537  {
538  return -1;
539  }
540  if (!(chflags & CH_DECODE))
541  FREE(&temp_hdr);
542  }
543 
544  if ((chflags & CH_NONEWLINE) == 0)
545  {
546  if (chflags & CH_PREFIX)
547  fputs(prefix, fp_out);
548  fputc('\n', fp_out); /* add header terminator */
549  }
550 
551  if (ferror(fp_out) || feof(fp_out))
552  return -1;
553 
554  return 0;
555 }
556 
567 static int count_delete_lines(FILE *fp, struct Body *b, LOFF_T *length, size_t datelen)
568 {
569  int dellines = 0;
570 
571  if (b->deleted)
572  {
573  fseeko(fp, b->offset, SEEK_SET);
574  for (long l = b->length; l; l--)
575  {
576  const int ch = getc(fp);
577  if (ch == EOF)
578  break;
579  if (ch == '\n')
580  dellines++;
581  }
582  dellines -= 3;
583  *length -= b->length - (84 + datelen);
584  /* Count the number of digits exceeding the first one to write the size */
585  for (long l = 10; b->length >= l; l *= 10)
586  (*length)++;
587  }
588  else
589  {
590  for (b = b->parts; b; b = b->next)
591  dellines += count_delete_lines(fp, b, length, datelen);
592  }
593  return dellines;
594 }
595 
607 int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e,
608  CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
609 {
610  struct Body *body = e->content;
611  char prefix[128];
612  LOFF_T new_offset = -1;
613  int rc = 0;
614 
615  if (cmflags & MUTT_CM_PREFIX)
616  {
617  if (C_TextFlowed)
618  mutt_str_copy(prefix, ">", sizeof(prefix));
619  else
620  {
621  mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(C_IndentString),
622  Context, Context->mailbox, e);
623  }
624  }
625 
626  if ((cmflags & MUTT_CM_NOHEADER) == 0)
627  {
628  if (cmflags & MUTT_CM_PREFIX)
629  chflags |= CH_PREFIX;
630  else if (e->attach_del && (chflags & CH_UPDATE_LEN))
631  {
632  int new_lines;
633  LOFF_T new_length = body->length;
634  char date[128];
635 
636  mutt_date_make_date(date, sizeof(date));
637  int dlen = mutt_str_len(date);
638  if (dlen == 0)
639  return -1;
640 
641  date[5] = '\"';
642  date[dlen - 1] = '\"';
643 
644  /* Count the number of lines and bytes to be deleted */
645  fseeko(fp_in, body->offset, SEEK_SET);
646  new_lines = e->lines - count_delete_lines(fp_in, body, &new_length, dlen);
647 
648  /* Copy the headers */
649  if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
650  return -1;
651  fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
652  if (new_lines <= 0)
653  new_lines = 0;
654  else
655  fprintf(fp_out, "Lines: %d\n", new_lines);
656 
657  putc('\n', fp_out);
658  if (ferror(fp_out) || feof(fp_out))
659  return -1;
660  new_offset = ftello(fp_out);
661 
662  /* Copy the body */
663  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
664  return -1;
665  if (copy_delete_attach(body, fp_in, fp_out, date))
666  return -1;
667 
668  LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
669  if (fail)
670  {
671  mutt_error(ngettext("The length calculation was wrong by %ld byte",
672  "The length calculation was wrong by %ld bytes", fail),
673  fail);
674  new_length += fail;
675  }
676 
677  /* Update original message if we are sync'ing a mailfolder */
678  if (cmflags & MUTT_CM_UPDATE)
679  {
680  e->attach_del = false;
681  e->lines = new_lines;
682  body->offset = new_offset;
683 
684  /* update the total size of the mailbox to reflect this deletion */
685  Context->mailbox->size -= body->length - new_length;
686  /* if the message is visible, update the visible size of the mailbox as well. */
687  if (Context->mailbox->v2r[e->msgno] != -1)
688  Context->vsize -= body->length - new_length;
689 
690  body->length = new_length;
691  mutt_body_free(&body->parts);
692  }
693 
694  return 0;
695  }
696 
697  if (mutt_copy_header(fp_in, e, fp_out, chflags,
698  (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
699  {
700  return -1;
701  }
702 
703  new_offset = ftello(fp_out);
704  }
705 
706  if (cmflags & MUTT_CM_DECODE)
707  {
708  /* now make a text/plain version of the message */
709  struct State s = { 0 };
710  s.fp_in = fp_in;
711  s.fp_out = fp_out;
712  if (cmflags & MUTT_CM_PREFIX)
713  s.prefix = prefix;
714  if (cmflags & MUTT_CM_DISPLAY)
715  {
716  s.flags |= MUTT_DISPLAY;
717  s.wraplen = wraplen;
718  }
719  if (cmflags & MUTT_CM_PRINTING)
720  s.flags |= MUTT_PRINTING;
721  if (cmflags & MUTT_CM_WEED)
722  s.flags |= MUTT_WEED;
723  if (cmflags & MUTT_CM_CHARCONV)
724  s.flags |= MUTT_CHARCONV;
725  if (cmflags & MUTT_CM_REPLYING)
726  s.flags |= MUTT_REPLYING;
727 
728  if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
729  s.flags |= MUTT_VERIFY;
730 
731  rc = mutt_body_handler(body, &s);
732  }
733  else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
734  {
735  struct Body *cur = NULL;
736  FILE *fp = NULL;
737 
738  if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
739  (e->security & APPLICATION_PGP) && (e->content->type == TYPE_MULTIPART))
740  {
741  if (crypt_pgp_decrypt_mime(fp_in, &fp, e->content, &cur))
742  return -1;
743  fputs("MIME-Version: 1.0\n", fp_out);
744  }
745 
746  if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
747  (e->security & APPLICATION_SMIME) && (e->content->type == TYPE_APPLICATION))
748  {
749  if (crypt_smime_decrypt_mime(fp_in, &fp, e->content, &cur))
750  return -1;
751  }
752 
753  if (!cur)
754  {
755  mutt_error(_("No decryption engine available for message"));
756  return -1;
757  }
758 
759  mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
760  fputc('\n', fp_out);
761 
762  if (fseeko(fp, cur->offset, SEEK_SET) < 0)
763  return -1;
764  if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
765  {
766  mutt_file_fclose(&fp);
767  mutt_body_free(&cur);
768  return -1;
769  }
770  mutt_body_free(&cur);
771  mutt_file_fclose(&fp);
772  }
773  else
774  {
775  if (fseeko(fp_in, body->offset, SEEK_SET) < 0)
776  return -1;
777  if (cmflags & MUTT_CM_PREFIX)
778  {
779  int c;
780  size_t bytes = body->length;
781 
782  fputs(prefix, fp_out);
783 
784  while (((c = fgetc(fp_in)) != EOF) && bytes--)
785  {
786  fputc(c, fp_out);
787  if (c == '\n')
788  {
789  fputs(prefix, fp_out);
790  }
791  }
792  }
793  else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
794  return -1;
795  }
796 
797  if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
798  (new_offset != -1))
799  {
800  body->offset = new_offset;
801  mutt_body_free(&body->parts);
802  }
803 
804  return rc;
805 }
806 
821 int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e,
822  CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
823 {
824  struct Message *msg = mx_msg_open(m, e->msgno);
825  if (!msg)
826  return -1;
827  if (!e->content)
828  return -1;
829  int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
830  if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
831  {
832  mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
833  rc = -1;
834  }
835  mx_msg_close(m, &msg);
836  return rc;
837 }
838 
850 static int append_message(struct Mailbox *dest, FILE *fp_in, struct Mailbox *src,
851  struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
852 {
853  char buf[256];
854  struct Message *msg = NULL;
855  int rc;
856 
857  if (fseeko(fp_in, e->offset, SEEK_SET) < 0)
858  return -1;
859  if (!fgets(buf, sizeof(buf), fp_in))
860  return -1;
861 
862  msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
863  if (!msg)
864  return -1;
865  if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
866  chflags |= CH_FROM | CH_FORCE_FROM;
867  chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
868  rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
869  if (mx_msg_commit(dest, msg) != 0)
870  rc = -1;
871 
872 #ifdef USE_NOTMUCH
873  if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
874  nm_update_filename(src, NULL, msg->committed_path, e);
875 #endif
876 
877  mx_msg_close(dest, &msg);
878  return rc;
879 }
880 
891 int mutt_append_message(struct Mailbox *dest, struct Mailbox *src, struct Email *e,
892  CopyMessageFlags cmflags, CopyHeaderFlags chflags)
893 {
894  struct Message *msg = mx_msg_open(src, e->msgno);
895  if (!msg)
896  return -1;
897  int rc = append_message(dest, msg->fp, src, e, cmflags, chflags);
898  mx_msg_close(src, &msg);
899  return rc;
900 }
901 
915 static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, char *date)
916 {
917  struct Body *part = NULL;
918 
919  for (part = b->parts; part; part = part->next)
920  {
921  if (part->deleted || part->parts)
922  {
923  /* Copy till start of this part */
924  if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
925  return -1;
926 
927  if (part->deleted)
928  {
929  fprintf(
930  fp_out,
931  "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
932  "\texpiration=%s; length=" OFF_T_FMT "\n"
933  "\n",
934  date + 5, part->length);
935  if (ferror(fp_out))
936  return -1;
937 
938  /* Copy the original mime headers */
939  if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
940  return -1;
941 
942  /* Skip the deleted body */
943  fseeko(fp_in, part->offset + part->length, SEEK_SET);
944  }
945  else
946  {
947  if (copy_delete_attach(part, fp_in, fp_out, date))
948  return -1;
949  }
950  }
951  }
952 
953  /* Copy the last parts */
954  if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
955  return -1;
956 
957  return 0;
958 }
959 
971 static void format_address_header(char **h, struct AddressList *al)
972 {
973  char buf[8192];
974  char cbuf[256];
975  char c2buf[256];
976  char *p = NULL;
977  size_t linelen, buflen, plen;
978 
979  linelen = mutt_str_len(*h);
980  plen = linelen;
981  buflen = linelen + 3;
982 
983  mutt_mem_realloc(h, buflen);
984  struct Address *first = TAILQ_FIRST(al);
985  struct Address *a = NULL;
986  TAILQ_FOREACH(a, al, entries)
987  {
988  *buf = '\0';
989  *cbuf = '\0';
990  *c2buf = '\0';
991  const size_t l = mutt_addr_write(buf, sizeof(buf), a, false);
992 
993  if (a != first && (linelen + l > 74))
994  {
995  strcpy(cbuf, "\n\t");
996  linelen = l + 8;
997  }
998  else
999  {
1000  if (a->mailbox)
1001  {
1002  strcpy(cbuf, " ");
1003  linelen++;
1004  }
1005  linelen += l;
1006  }
1007  if (!a->group && TAILQ_NEXT(a, entries) && TAILQ_NEXT(a, entries)->mailbox)
1008  {
1009  linelen++;
1010  buflen++;
1011  strcpy(c2buf, ",");
1012  }
1013 
1014  const size_t cbuflen = mutt_str_len(cbuf);
1015  const size_t c2buflen = mutt_str_len(c2buf);
1016  buflen += l + cbuflen + c2buflen;
1017  mutt_mem_realloc(h, buflen);
1018  p = *h;
1019  strcat(p + plen, cbuf);
1020  plen += cbuflen;
1021  strcat(p + plen, buf);
1022  plen += l;
1023  strcat(p + plen, c2buf);
1024  plen += c2buflen;
1025  }
1026 
1027  /* Space for this was allocated in the beginning of this function. */
1028  strcat(p + plen, "\n");
1029 }
1030 
1037 static int address_header_decode(char **h)
1038 {
1039  char *s = *h;
1040  size_t l;
1041  bool rp = false;
1042 
1043  switch (tolower((unsigned char) *s))
1044  {
1045  case 'b':
1046  {
1047  if (!(l = mutt_istr_startswith(s, "bcc:")))
1048  return 0;
1049  break;
1050  }
1051  case 'c':
1052  {
1053  if (!(l = mutt_istr_startswith(s, "cc:")))
1054  return 0;
1055  break;
1056  }
1057  case 'f':
1058  {
1059  if (!(l = mutt_istr_startswith(s, "from:")))
1060  return 0;
1061  break;
1062  }
1063  case 'm':
1064  {
1065  if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1066  return 0;
1067  break;
1068  }
1069  case 'r':
1070  {
1071  if ((l = mutt_istr_startswith(s, "return-path:")))
1072  {
1073  rp = true;
1074  break;
1075  }
1076  else if ((l = mutt_istr_startswith(s, "reply-to:")))
1077  {
1078  break;
1079  }
1080  return 0;
1081  }
1082  case 's':
1083  {
1084  if (!(l = mutt_istr_startswith(s, "sender:")))
1085  return 0;
1086  break;
1087  }
1088  case 't':
1089  {
1090  if (!(l = mutt_istr_startswith(s, "to:")))
1091  return 0;
1092  break;
1093  }
1094  default:
1095  return 0;
1096  }
1097 
1098  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1099  mutt_addrlist_parse(&al, s + l);
1100  if (TAILQ_EMPTY(&al))
1101  return 0;
1102 
1105  struct Address *a = NULL;
1106  TAILQ_FOREACH(a, &al, entries)
1107  {
1108  if (a->personal)
1109  {
1111  }
1112  }
1113 
1114  /* angle brackets for return path are mandated by RFC5322,
1115  * so leave Return-Path as-is */
1116  if (rp)
1117  *h = mutt_str_dup(s);
1118  else
1119  {
1120  *h = mutt_mem_calloc(1, l + 2);
1121  mutt_str_copy(*h, s, l + 1);
1122  format_address_header(h, &al);
1123  }
1124 
1125  mutt_addrlist_clear(&al);
1126 
1127  FREE(&s);
1128  return 1;
1129 }
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:47
Convenience wrapper for the gui headers.
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:65
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:309
The "current" mailbox.
Definition: context.h:37
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:60
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
int lines
How many lines in the body of this message?
Definition: email.h:84
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
#define WithCrypto
Definition: lib.h:118
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:971
#define TAILQ_FIRST(head)
Definition: queue.h:716
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:758
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, char *date)
Copy a message, deleting marked attachments.
Definition: copy.c:915
#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.
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:1379
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:39
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
#define mutt_make_string(BUF, BUFLEN, COLS, S, CTX, M, E)
Definition: hdrline.h:59
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
struct Body * content
List of MIME parts.
Definition: email.h:90
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:40
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:375
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:821
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
#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:567
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:57
An email address.
Definition: address.h:34
FILE * fp_out
File to write to.
Definition: state.h:47
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:51
char * mailbox
Mailbox and host address.
Definition: address.h:37
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:31
#define CH_UPDATE_REFS
Update References:
Definition: copy.h:68
#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:514
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:42
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:43
char * mutt_date_make_date(char *buf, size_t buflen)
Write a date in RFC822 format to a buffer.
Definition: date.c:375
The body of an email.
Definition: body.h:34
Email Address Handling.
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
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:1882
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:64
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:1180
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:850
struct Mailbox * mailbox
Definition: context.h:50
#define MUTT_CM_DISPLAY
Output is displayed to the user.
Definition: copy.h:38
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:1037
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:639
#define CH_WEED
Weed the headers?
Definition: copy.h:52
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:89
Convenience wrapper for the core headers.
void mutt_ch_canonical_charset(char *buf, size_t buflen, const char *name)
Canonicalise the charset of a string.
Definition: charset.c:352
#define CH_VIRTUAL
Write virtual header lines too.
Definition: copy.h:72
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:755
int wraplen
Width to wrap lines to (when flags & MUTT_DISPLAY)
Definition: state.h:50
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1046
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:102
&#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:65
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:62
off_t vsize
Definition: context.h:39
#define CH_UPDATE_LABEL
Update X-Label: from email->env->x_label?
Definition: copy.h:70
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:93
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:34
Notmuch virtual mailbox type.
WHERE short C_Wrap
Config: Width to wrap text in the pager.
Definition: mutt_globals.h:119
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:92
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
A local copy of an email.
Definition: mx.h:83
#define CH_UPDATE_IRT
Update In-Reply-To:
Definition: copy.h:67
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:81
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:37
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:142
#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:58
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:41
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:53
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:54
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
#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:1621
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:473
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:431
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
void mutt_str_dequote_comment(char *s)
Un-escape characters in an email address comment.
Definition: string.c:844
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:522
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:349
#define MUTT_CM_VERIFY
Do signature verification.
Definition: copy.h:46
#define CH_NOLEN
Don&#39;t write Content-Length: and Lines:
Definition: copy.h:63
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:71
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:615
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
char * committed_path
the final path generated by mx_msg_commit()
Definition: mx.h:87
char * personal
Real name of address.
Definition: address.h:36
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:45
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
Keep track when processing files.
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:66
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:636
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:207
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:38
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:721
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
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:399
#define mutt_error(...)
Definition: logging.h:84
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:1159
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:77
int mutt_append_message(struct Mailbox *dest, struct Mailbox *src, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Append a message.
Definition: copy.c:891
FILE * fp
pointer to the message data
Definition: mx.h:85
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:44
#define FREE(x)
Definition: memory.h:40
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
bool C_Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: globals.c:40
Keep track when processing files.
Definition: state.h:44
#define STAILQ_EMPTY(head)
Definition: queue.h:345
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:53
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1585
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:825
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: globals.c:38
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:33
Hundreds of global variables to back the user variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
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:714
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:607
#define MUTT_CM_NOHEADER
Don&#39;t copy the message header.
Definition: copy.h:35
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:66
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
Decide how to display email content.
char * x_label
X-Label.
Definition: envelope.h:72
#define CH_PREFIX
Quote header using C_IndentString string?
Definition: copy.h:56
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:1132
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:419
#define CH_NONEWLINE
Don&#39;t output terminating newline after the header.
Definition: copy.h:59
int msgno
Number displayed to the user.
Definition: email.h:86
WHERE char * C_IndentString
Config: String used to indent &#39;reply&#39; text.
Definition: mutt_globals.h:105
WHERE bool C_TextFlowed
Config: Generate &#39;format=flowed&#39; messages.
Definition: mutt_globals.h:168