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