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