NeoMutt  2023-03-22-27-g3cb248
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 <locale.h>
34#include <stdbool.h>
35#include <string.h>
36#include "mutt/lib.h"
37#include "address/lib.h"
38#include "config/lib.h"
39#include "email/lib.h"
40#include "core/lib.h"
41#include "gui/lib.h"
42#include "mutt.h"
43#include "copy.h"
44#include "index/lib.h"
45#include "ncrypt/lib.h"
46#include "send/lib.h"
47#include "format_flags.h"
48#include "globals.h" // IWYU pragma: keep
49#include "handler.h"
50#include "hdrline.h"
51#include "mx.h"
52#ifdef USE_NOTMUCH
53#include "notmuch/lib.h"
54#include "muttlib.h"
55#endif
56#ifdef ENABLE_NLS
57#include <libintl.h>
58#endif
59
60static int address_header_decode(char **h);
61static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out,
62 const char *quoted_date);
63
64ARRAY_HEAD(Headers, char *);
65
75static void add_one_header(struct Headers *headers, size_t pos, char *value)
76{
77 char **old = ARRAY_GET(headers, pos);
78 if (old && *old)
79 {
80 char *new_value = NULL;
81 mutt_str_asprintf(&new_value, "%s%s", *old, value);
82 FREE(old);
83 FREE(&value);
84 value = new_value;
85 }
86 ARRAY_SET(headers, pos, value);
87}
88
105int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end,
106 CopyHeaderFlags chflags, const char *prefix, int wraplen)
107{
108 bool from = false;
109 bool this_is_from = false;
110 bool ignore = false;
111 char buf[1024] = { 0 }; /* should be long enough to get most fields in one pass */
112 char *nl = NULL;
113 struct Headers headers = ARRAY_HEAD_INITIALIZER;
114 int hdr_count;
115 int x;
116 char *this_one = NULL;
117 size_t this_one_len = 0;
118
119 if (off_start < 0)
120 return -1;
121
122 if (ftello(fp_in) != off_start)
123 if (!mutt_file_seek(fp_in, off_start, SEEK_SET))
124 return -1;
125
126 buf[0] = '\n';
127 buf[1] = '\0';
128
129 if ((chflags & (CH_REORDER | CH_WEED | CH_MIME | CH_DECODE | CH_PREFIX | CH_WEED_DELIVERED)) == 0)
130 {
131 /* Without these flags to complicate things
132 * we can do a more efficient line to line copying */
133 while (ftello(fp_in) < off_end)
134 {
135 nl = strchr(buf, '\n');
136
137 if (!fgets(buf, sizeof(buf), fp_in))
138 break;
139
140 /* Is it the beginning of a header? */
141 if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
142 {
143 ignore = true;
144 if (!from && mutt_str_startswith(buf, "From "))
145 {
146 if ((chflags & CH_FROM) == 0)
147 continue;
148 from = true;
149 }
150 else if ((chflags & CH_NOQFROM) && mutt_istr_startswith(buf, ">From "))
151 continue;
152 else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
153 break; /* end of header */
154
155 if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
156 (mutt_istr_startswith(buf, "Status:") || mutt_istr_startswith(buf, "X-Status:")))
157 {
158 continue;
159 }
160 if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
161 (mutt_istr_startswith(buf, "Content-Length:") ||
162 mutt_istr_startswith(buf, "Lines:")))
163 {
164 continue;
165 }
166 if ((chflags & CH_UPDATE_REFS) && mutt_istr_startswith(buf, "References:"))
167 {
168 continue;
169 }
170 if ((chflags & CH_UPDATE_IRT) && 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) && mutt_istr_startswith(buf, "Subject:"))
177 {
178 continue;
179 }
180
181 ignore = false;
182 }
183
184 if (!ignore && (fputs(buf, fp_out) == EOF))
185 return -1;
186 }
187 return 0;
188 }
189
190 hdr_count = 1;
191 x = 0;
192
193 /* We are going to read and collect the headers in an array
194 * so we are able to do re-ordering.
195 * First count the number of entries in the array */
196 if (chflags & CH_REORDER)
197 {
198 struct ListNode *np = NULL;
199 STAILQ_FOREACH(np, &HeaderOrderList, entries)
200 {
201 mutt_debug(LL_DEBUG3, "Reorder list: %s\n", np->data);
202 hdr_count++;
203 }
204 }
205
206 mutt_debug(LL_DEBUG1, "WEED is %sset\n", (chflags & CH_WEED) ? "" : "not ");
207
208 ARRAY_RESERVE(&headers, hdr_count);
209
210 /* Read all the headers into the array */
211 while (ftello(fp_in) < off_end)
212 {
213 nl = strchr(buf, '\n');
214
215 /* Read a line */
216 if (!fgets(buf, sizeof(buf), fp_in))
217 break;
218
219 /* Is it the beginning of a header? */
220 if (nl && (buf[0] != ' ') && (buf[0] != '\t'))
221 {
222 /* Do we have anything pending? */
223 if (this_one)
224 {
225 if (chflags & CH_DECODE)
226 {
227 if (address_header_decode(&this_one) == 0)
228 rfc2047_decode(&this_one);
229 this_one_len = mutt_str_len(this_one);
230
231 /* Convert CRLF line endings to LF */
232 if ((this_one_len > 2) && (this_one[this_one_len - 2] == '\r') &&
233 (this_one[this_one_len - 1] == '\n'))
234 {
235 this_one[this_one_len - 2] = '\n';
236 this_one[this_one_len - 1] = '\0';
237 }
238 }
239
240 add_one_header(&headers, x, this_one);
241 this_one = NULL;
242 }
243
244 ignore = true;
245 this_is_from = false;
246 if (!from && mutt_str_startswith(buf, "From "))
247 {
248 if ((chflags & CH_FROM) == 0)
249 continue;
250 this_is_from = true;
251 from = true;
252 }
253 else if ((buf[0] == '\n') || ((buf[0] == '\r') && (buf[1] == '\n')))
254 break; /* end of header */
255
256 /* note: CH_FROM takes precedence over header weeding. */
257 if (!((chflags & CH_FROM) && (chflags & CH_FORCE_FROM) && this_is_from) &&
258 (chflags & CH_WEED) && mutt_matches_ignore(buf))
259 {
260 continue;
261 }
262 if ((chflags & CH_WEED_DELIVERED) && mutt_istr_startswith(buf, "Delivered-To:"))
263 {
264 continue;
265 }
266 if ((chflags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
267 (mutt_istr_startswith(buf, "Status:") || mutt_istr_startswith(buf, "X-Status:")))
268 {
269 continue;
270 }
271 if ((chflags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
272 (mutt_istr_startswith(buf, "Content-Length:") || mutt_istr_startswith(buf, "Lines:")))
273 {
274 continue;
275 }
276 if ((chflags & CH_MIME))
277 {
278 if (mutt_istr_startswith(buf, "mime-version:"))
279 {
280 continue;
281 }
282 size_t plen = mutt_istr_startswith(buf, "content-");
283 if ((plen != 0) && (mutt_istr_startswith(buf + plen, "transfer-encoding:") ||
284 mutt_istr_startswith(buf + plen, "type:")))
285 {
286 continue;
287 }
288 }
289 if ((chflags & CH_UPDATE_REFS) && mutt_istr_startswith(buf, "References:"))
290 {
291 continue;
292 }
293 if ((chflags & CH_UPDATE_IRT) && mutt_istr_startswith(buf, "In-Reply-To:"))
294 {
295 continue;
296 }
297 if ((chflags & CH_UPDATE_LABEL) && mutt_istr_startswith(buf, "X-Label:"))
298 continue;
299 if ((chflags & CH_UPDATE_SUBJECT) && mutt_istr_startswith(buf, "Subject:"))
300 {
301 continue;
302 }
303
304 /* Find x -- the array entry where this header is to be saved */
305 if (chflags & CH_REORDER)
306 {
307 struct ListNode *np = NULL;
308 x = 0;
309 int match = -1;
310 size_t match_len = 0;
311
312 STAILQ_FOREACH(np, &HeaderOrderList, entries)
313 {
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 x++;
325 }
326 if (match != -1)
327 x = match;
328 }
329
330 ignore = false;
331 } /* If beginning of header */
332
333 if (!ignore)
334 {
335 mutt_debug(LL_DEBUG2, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count);
336 if (this_one)
337 {
338 size_t blen = mutt_str_len(buf);
339
340 mutt_mem_realloc(&this_one, this_one_len + blen + sizeof(char));
341 strcat(this_one + this_one_len, buf);
342 this_one_len += blen;
343 }
344 else
345 {
346 this_one = mutt_str_dup(buf);
347 this_one_len = mutt_str_len(this_one);
348 }
349 }
350 } /* while (ftello (fp_in) < off_end) */
351
352 /* Do we have anything pending? -- XXX, same code as in above in the loop. */
353 if (this_one)
354 {
355 if (chflags & CH_DECODE)
356 {
357 if (address_header_decode(&this_one) == 0)
358 rfc2047_decode(&this_one);
359 this_one_len = mutt_str_len(this_one);
360 }
361
362 add_one_header(&headers, x, this_one);
363 this_one = NULL;
364 }
365
366 /* Now output the headers in order */
367 bool error = false;
368 char **hp = NULL;
369 ARRAY_FOREACH(hp, &headers)
370 {
371 if (!error && hp && *hp)
372 {
373 /* We couldn't do the prefixing when reading because RFC2047
374 * decoding may have concatenated lines. */
375 if (chflags & (CH_DECODE | CH_PREFIX))
376 {
377 const char *pre = (chflags & CH_PREFIX) ? prefix : NULL;
378 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
379 wraplen = mutt_window_wrap_cols(wraplen, c_wrap);
380
381 if (mutt_write_one_header(fp_out, 0, *hp, pre, wraplen, chflags, NeoMutt->sub) == -1)
382 {
383 error = true;
384 }
385 }
386 else
387 {
388 if (fputs(*hp, fp_out) == EOF)
389 {
390 error = true;
391 }
392 }
393 }
394
395 FREE(hp);
396 }
397 ARRAY_FREE(&headers);
398
399 if (error)
400 return -1;
401 return 0;
402}
403
415int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out,
416 CopyHeaderFlags chflags, const char *prefix, int wraplen)
417{
418 char *temp_hdr = NULL;
419
420 if (e->env)
421 {
422 chflags |= ((e->env->changed & MUTT_ENV_CHANGED_IRT) ? CH_UPDATE_IRT : 0) |
426 }
427
428 if (mutt_copy_hdr(fp_in, fp_out, e->offset, e->body->offset, chflags, prefix, wraplen) == -1)
429 return -1;
430
431 if (chflags & CH_TXTPLAIN)
432 {
433 char chsbuf[128] = { 0 };
434 char buf[128] = { 0 };
435 fputs("MIME-Version: 1.0\n", fp_out);
436 fputs("Content-Transfer-Encoding: 8bit\n", fp_out);
437 fputs("Content-Type: text/plain; charset=", fp_out);
438 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
439 mutt_ch_canonical_charset(chsbuf, sizeof(chsbuf), c_charset ? c_charset : "us-ascii");
440 mutt_addr_cat(buf, sizeof(buf), chsbuf, MimeSpecials);
441 fputs(buf, fp_out);
442 fputc('\n', fp_out);
443 }
444
445 if ((chflags & CH_UPDATE_IRT) && !STAILQ_EMPTY(&e->env->in_reply_to))
446 {
447 fputs("In-Reply-To:", fp_out);
448 struct ListNode *np = NULL;
449 STAILQ_FOREACH(np, &e->env->in_reply_to, entries)
450 {
451 fputc(' ', fp_out);
452 fputs(np->data, fp_out);
453 }
454 fputc('\n', fp_out);
455 }
456
457 if ((chflags & CH_UPDATE_REFS) && !STAILQ_EMPTY(&e->env->references))
458 {
459 fputs("References:", fp_out);
460 mutt_write_references(&e->env->references, fp_out, 0);
461 fputc('\n', fp_out);
462 }
463
464 if ((chflags & CH_UPDATE) && ((chflags & CH_NOSTATUS) == 0))
465 {
466 if (e->old || e->read)
467 {
468 fputs("Status: ", fp_out);
469 if (e->read)
470 fputs("RO", fp_out);
471 else if (e->old)
472 fputc('O', fp_out);
473 fputc('\n', fp_out);
474 }
475
476 if (e->flagged || e->replied)
477 {
478 fputs("X-Status: ", fp_out);
479 if (e->replied)
480 fputc('A', fp_out);
481 if (e->flagged)
482 fputc('F', fp_out);
483 fputc('\n', fp_out);
484 }
485 }
486
487 if (chflags & CH_UPDATE_LEN && ((chflags & CH_NOLEN) == 0))
488 {
489 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", e->body->length);
490 if ((e->lines != 0) || (e->body->length == 0))
491 fprintf(fp_out, "Lines: %d\n", e->lines);
492 }
493
494 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
495#ifdef USE_NOTMUCH
496 if (chflags & CH_VIRTUAL)
497 {
498 /* Add some fake headers based on notmuch data */
499 char *folder = nm_email_get_folder(e);
500 if (folder && !(c_weed && mutt_matches_ignore("folder")))
501 {
502 char buf[1024] = { 0 };
503 mutt_str_copy(buf, folder, sizeof(buf));
504 mutt_pretty_mailbox(buf, sizeof(buf));
505
506 fputs("Folder: ", fp_out);
507 fputs(buf, fp_out);
508 fputc('\n', fp_out);
509 }
510 }
511#endif
512 char *tags = driver_tags_get(&e->tags);
513 if (tags && !(c_weed && mutt_matches_ignore("tags")))
514 {
515 fputs("Tags: ", fp_out);
516 fputs(tags, fp_out);
517 fputc('\n', fp_out);
518 }
519 FREE(&tags);
520
521 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
522 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
523 if ((chflags & CH_UPDATE_LABEL) && e->env->x_label)
524 {
525 temp_hdr = e->env->x_label;
526 /* env->x_label isn't currently stored with direct references elsewhere.
527 * Mailbox->label_hash strdups the keys. But to be safe, encode a copy */
528 if (!(chflags & CH_DECODE))
529 {
530 temp_hdr = mutt_str_dup(temp_hdr);
531 rfc2047_encode(&temp_hdr, NULL, sizeof("X-Label:"), c_send_charset);
532 }
533 if (mutt_write_one_header(fp_out, "X-Label", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
534 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
535 NeoMutt->sub) == -1)
536 {
537 return -1;
538 }
539 if (!(chflags & CH_DECODE))
540 FREE(&temp_hdr);
541 }
542
543 if ((chflags & CH_UPDATE_SUBJECT) && e->env->subject)
544 {
545 temp_hdr = e->env->subject;
546 /* env->subject is directly referenced in Mailbox->subj_hash, so we
547 * have to be careful not to encode (and thus free) that memory. */
548 if (!(chflags & CH_DECODE))
549 {
550 temp_hdr = mutt_str_dup(temp_hdr);
551 rfc2047_encode(&temp_hdr, NULL, sizeof("Subject:"), c_send_charset);
552 }
553 if (mutt_write_one_header(fp_out, "Subject", temp_hdr, (chflags & CH_PREFIX) ? prefix : 0,
554 mutt_window_wrap_cols(wraplen, c_wrap), chflags,
555 NeoMutt->sub) == -1)
556 {
557 return -1;
558 }
559 if (!(chflags & CH_DECODE))
560 FREE(&temp_hdr);
561 }
562
563 if ((chflags & CH_NONEWLINE) == 0)
564 {
565 if (chflags & CH_PREFIX)
566 fputs(prefix, fp_out);
567 fputc('\n', fp_out); /* add header terminator */
568 }
569
570 if (ferror(fp_out) || feof(fp_out))
571 return -1;
572
573 return 0;
574}
575
587static int count_delete_lines(FILE *fp, struct Body *b, LOFF_T *length, size_t datelen)
588{
589 int dellines = 0;
590
591 if (b->deleted)
592 {
593 if (!mutt_file_seek(fp, b->offset, SEEK_SET))
594 {
595 return -1;
596 }
597 for (long l = b->length; l; l--)
598 {
599 const int ch = getc(fp);
600 if (ch == EOF)
601 break;
602 if (ch == '\n')
603 dellines++;
604 }
605 /* 3 and 89 come from the added header of three lines in
606 * copy_delete_attach(). 89 is the size of the header(including
607 * the newlines, tabs, and a single digit length), not including
608 * the date length. */
609 dellines -= 3;
610 *length -= b->length - (89 + datelen);
611 /* Count the number of digits exceeding the first one to write the size */
612 for (long l = 10; b->length >= l; l *= 10)
613 (*length)++;
614 }
615 else
616 {
617 for (b = b->parts; b; b = b->next)
618 {
619 const int del = count_delete_lines(fp, b, length, datelen);
620 if (del == -1)
621 {
622 return -1;
623 }
624 dellines += del;
625 }
626 }
627 return dellines;
628}
629
641int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e,
642 CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
643{
644 struct Body *body = e->body;
645 char prefix[128] = { 0 };
646 LOFF_T new_offset = -1;
647 int rc = 0;
648
649 if (cmflags & MUTT_CM_PREFIX)
650 {
651 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
652 if (c_text_flowed)
653 {
654 mutt_str_copy(prefix, ">", sizeof(prefix));
655 }
656 else
657 {
658 const char *const c_attribution_locale = cs_subset_string(NeoMutt->sub, "attribution_locale");
659 const char *const c_indent_string = cs_subset_string(NeoMutt->sub, "indent_string");
660 struct Mailbox *m_cur = get_current_mailbox();
661 setlocale(LC_TIME, NONULL(c_attribution_locale));
662 mutt_make_string(prefix, sizeof(prefix), wraplen, NONULL(c_indent_string),
663 m_cur, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
664 setlocale(LC_TIME, "");
665 }
666 }
667
668 if ((cmflags & MUTT_CM_NOHEADER) == 0)
669 {
670 if (cmflags & MUTT_CM_PREFIX)
671 {
672 chflags |= CH_PREFIX;
673 }
674 else if (e->attach_del && (chflags & CH_UPDATE_LEN))
675 {
676 int new_lines;
677 int rc_attach_del = -1;
678 LOFF_T new_length = body->length;
679 struct Buffer *quoted_date = NULL;
680
681 quoted_date = mutt_buffer_pool_get();
682 mutt_buffer_addch(quoted_date, '"');
683 mutt_date_make_date(quoted_date, cs_subset_bool(NeoMutt->sub, "local_date_header"));
684 mutt_buffer_addch(quoted_date, '"');
685
686 /* Count the number of lines and bytes to be deleted */
687 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
688 {
689 goto attach_del_cleanup;
690 }
691 const int del = count_delete_lines(fp_in, body, &new_length,
692 mutt_buffer_len(quoted_date));
693 if (del == -1)
694 {
695 goto attach_del_cleanup;
696 }
697 new_lines = e->lines - del;
698
699 /* Copy the headers */
700 if (mutt_copy_header(fp_in, e, fp_out, chflags | CH_NOLEN | CH_NONEWLINE, NULL, wraplen))
701 goto attach_del_cleanup;
702 fprintf(fp_out, "Content-Length: " OFF_T_FMT "\n", new_length);
703 if (new_lines <= 0)
704 new_lines = 0;
705 else
706 fprintf(fp_out, "Lines: %d\n", new_lines);
707
708 putc('\n', fp_out);
709 if (ferror(fp_out) || feof(fp_out))
710 goto attach_del_cleanup;
711 new_offset = ftello(fp_out);
712
713 /* Copy the body */
714 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
715 goto attach_del_cleanup;
716 if (copy_delete_attach(body, fp_in, fp_out, mutt_buffer_string(quoted_date)))
717 goto attach_del_cleanup;
718
719 mutt_buffer_pool_release(&quoted_date);
720
721 LOFF_T fail = ((ftello(fp_out) - new_offset) - new_length);
722 if (fail)
723 {
724 mutt_error(ngettext("The length calculation was wrong by %ld byte",
725 "The length calculation was wrong by %ld bytes", fail),
726 fail);
727 new_length += fail;
728 }
729
730 /* Update original message if we are sync'ing a mailfolder */
731 if (cmflags & MUTT_CM_UPDATE)
732 {
733 e->attach_del = false;
734 e->lines = new_lines;
735 body->offset = new_offset;
736
737 body->length = new_length;
738 mutt_body_free(&body->parts);
739 }
740
741 rc_attach_del = 0;
742
743 attach_del_cleanup:
744 mutt_buffer_pool_release(&quoted_date);
745 return rc_attach_del;
746 }
747
748 if (mutt_copy_header(fp_in, e, fp_out, chflags,
749 (chflags & CH_PREFIX) ? prefix : NULL, wraplen) == -1)
750 {
751 return -1;
752 }
753
754 new_offset = ftello(fp_out);
755 }
756
757 if (cmflags & MUTT_CM_DECODE)
758 {
759 /* now make a text/plain version of the message */
760 struct State state = { 0 };
761 state.fp_in = fp_in;
762 state.fp_out = fp_out;
763 if (cmflags & MUTT_CM_PREFIX)
764 state.prefix = prefix;
765 if (cmflags & MUTT_CM_DISPLAY)
766 {
767 state.flags |= STATE_DISPLAY;
768 state.wraplen = wraplen;
769 const char *const c_pager = cs_subset_string(NeoMutt->sub, "pager");
770 if (!c_pager || mutt_str_equal(c_pager, "builtin"))
771 state.flags |= STATE_PAGER;
772 }
773 if (cmflags & MUTT_CM_PRINTING)
774 state.flags |= STATE_PRINTING;
775 if (cmflags & MUTT_CM_WEED)
776 state.flags |= STATE_WEED;
777 if (cmflags & MUTT_CM_CHARCONV)
778 state.flags |= STATE_CHARCONV;
779 if (cmflags & MUTT_CM_REPLYING)
780 state.flags |= STATE_REPLYING;
781
782 if ((WithCrypto != 0) && cmflags & MUTT_CM_VERIFY)
783 state.flags |= STATE_VERIFY;
784
785 rc = mutt_body_handler(body, &state);
786 }
787 else if ((WithCrypto != 0) && (cmflags & MUTT_CM_DECODE_CRYPT) && (e->security & SEC_ENCRYPT))
788 {
789 struct Body *cur = NULL;
790 FILE *fp = NULL;
791
792 if (((WithCrypto & APPLICATION_PGP) != 0) && (cmflags & MUTT_CM_DECODE_PGP) &&
794 {
795 if (crypt_pgp_decrypt_mime(fp_in, &fp, e->body, &cur))
796 return -1;
797 fputs("MIME-Version: 1.0\n", fp_out);
798 }
799
800 if (((WithCrypto & APPLICATION_SMIME) != 0) && (cmflags & MUTT_CM_DECODE_SMIME) &&
802 {
803 if (crypt_smime_decrypt_mime(fp_in, &fp, e->body, &cur))
804 return -1;
805 }
806
807 if (!cur)
808 {
809 mutt_error(_("No decryption engine available for message"));
810 return -1;
811 }
812
813 mutt_write_mime_header(cur, fp_out, NeoMutt->sub);
814 fputc('\n', fp_out);
815
816 if (!mutt_file_seek(fp, cur->offset, SEEK_SET))
817 return -1;
818 if (mutt_file_copy_bytes(fp, fp_out, cur->length) == -1)
819 {
820 mutt_file_fclose(&fp);
821 mutt_body_free(&cur);
822 return -1;
823 }
824 mutt_body_free(&cur);
825 mutt_file_fclose(&fp);
826 }
827 else
828 {
829 if (!mutt_file_seek(fp_in, body->offset, SEEK_SET))
830 return -1;
831 if (cmflags & MUTT_CM_PREFIX)
832 {
833 int c;
834 size_t bytes = body->length;
835
836 fputs(prefix, fp_out);
837
838 while (((c = fgetc(fp_in)) != EOF) && bytes--)
839 {
840 fputc(c, fp_out);
841 if (c == '\n')
842 {
843 fputs(prefix, fp_out);
844 }
845 }
846 }
847 else if (mutt_file_copy_bytes(fp_in, fp_out, body->length) == -1)
848 return -1;
849 }
850
851 if ((cmflags & MUTT_CM_UPDATE) && ((cmflags & MUTT_CM_NOHEADER) == 0) &&
852 (new_offset != -1))
853 {
854 body->offset = new_offset;
855 mutt_body_free(&body->parts);
856 }
857
858 return rc;
859}
860
875int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg,
876 CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
877{
878 if (!msg || !e->body)
879 {
880 return -1;
881 }
882 if (fp_out == msg->fp)
883 {
884 mutt_debug(LL_DEBUG1, "trying to read/write from/to the same FILE*!\n");
885 return -1;
886 }
887
888 int rc = mutt_copy_message_fp(fp_out, msg->fp, e, cmflags, chflags, wraplen);
889 if ((rc == 0) && (ferror(fp_out) || feof(fp_out)))
890 {
891 mutt_debug(LL_DEBUG1, "failed to detect EOF!\n");
892 rc = -1;
893 }
894 return rc;
895}
896
908static int append_message(struct Mailbox *dest, FILE *fp_in, struct Mailbox *src,
909 struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
910{
911 char buf[256] = { 0 };
912 struct Message *msg = NULL;
913 int rc;
914
915 if (!mutt_file_seek(fp_in, e->offset, SEEK_SET))
916 return -1;
917 if (!fgets(buf, sizeof(buf), fp_in))
918 return -1;
919
920 msg = mx_msg_open_new(dest, e, is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
921 if (!msg)
922 return -1;
923 if ((dest->type == MUTT_MBOX) || (dest->type == MUTT_MMDF))
924 chflags |= CH_FROM | CH_FORCE_FROM;
925 chflags |= ((dest->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
926 rc = mutt_copy_message_fp(msg->fp, fp_in, e, cmflags, chflags, 0);
927 if (mx_msg_commit(dest, msg) != 0)
928 rc = -1;
929
930#ifdef USE_NOTMUCH
931 if (msg->committed_path && (dest->type == MUTT_MAILDIR) && (src->type == MUTT_NOTMUCH))
932 nm_update_filename(src, NULL, msg->committed_path, e);
933#endif
934
935 mx_msg_close(dest, &msg);
936 return rc;
937}
938
950int mutt_append_message(struct Mailbox *m_dst, struct Mailbox *m_src,
951 struct Email *e, struct Message *msg,
952 CopyMessageFlags cmflags, CopyHeaderFlags chflags)
953{
954 const bool own_msg = !msg;
955 if (own_msg && !(msg = mx_msg_open(m_src, e->msgno)))
956 {
957 return -1;
958 }
959
960 int rc = append_message(m_dst, msg->fp, m_src, e, cmflags, chflags);
961 if (own_msg)
962 {
963 mx_msg_close(m_src, &msg);
964 }
965 return rc;
966}
967
981static int copy_delete_attach(struct Body *b, FILE *fp_in, FILE *fp_out, const char *quoted_date)
982{
983 struct Body *part = NULL;
984
985 for (part = b->parts; part; part = part->next)
986 {
987 if (part->deleted || part->parts)
988 {
989 /* Copy till start of this part */
990 if (mutt_file_copy_bytes(fp_in, fp_out, part->hdr_offset - ftello(fp_in)))
991 {
992 return -1;
993 }
994
995 if (part->deleted)
996 {
997 /* If this is modified, count_delete_lines() needs to be changed too */
998 fprintf(fp_out,
999 "Content-Type: message/external-body; access-type=x-mutt-deleted;\n"
1000 "\texpiration=%s; length=" OFF_T_FMT "\n"
1001 "\n",
1002 quoted_date, part->length);
1003 if (ferror(fp_out))
1004 {
1005 return -1;
1006 }
1007
1008 /* Copy the original mime headers */
1009 if (mutt_file_copy_bytes(fp_in, fp_out, part->offset - ftello(fp_in)))
1010 {
1011 return -1;
1012 }
1013
1014 /* Skip the deleted body */
1015 if (!mutt_file_seek(fp_in, part->offset + part->length, SEEK_SET))
1016 {
1017 return -1;
1018 }
1019 }
1020 else
1021 {
1022 if (copy_delete_attach(part, fp_in, fp_out, quoted_date))
1023 {
1024 return -1;
1025 }
1026 }
1027 }
1028 }
1029
1030 /* Copy the last parts */
1031 if (mutt_file_copy_bytes(fp_in, fp_out, b->offset + b->length - ftello(fp_in)))
1032 return -1;
1033
1034 return 0;
1035}
1036
1043static int address_header_decode(char **h)
1044{
1045 char *s = *h;
1046 size_t l;
1047 bool rp = false;
1048
1049 switch (tolower((unsigned char) *s))
1050 {
1051 case 'b':
1052 {
1053 if (!(l = mutt_istr_startswith(s, "bcc:")))
1054 return 0;
1055 break;
1056 }
1057 case 'c':
1058 {
1059 if (!(l = mutt_istr_startswith(s, "cc:")))
1060 return 0;
1061 break;
1062 }
1063 case 'f':
1064 {
1065 if (!(l = mutt_istr_startswith(s, "from:")))
1066 return 0;
1067 break;
1068 }
1069 case 'm':
1070 {
1071 if (!(l = mutt_istr_startswith(s, "mail-followup-to:")))
1072 return 0;
1073 break;
1074 }
1075 case 'r':
1076 {
1077 if ((l = mutt_istr_startswith(s, "return-path:")))
1078 {
1079 rp = true;
1080 break;
1081 }
1082 else if ((l = mutt_istr_startswith(s, "reply-to:")))
1083 {
1084 break;
1085 }
1086 return 0;
1087 }
1088 case 's':
1089 {
1090 if (!(l = mutt_istr_startswith(s, "sender:")))
1091 return 0;
1092 break;
1093 }
1094 case 't':
1095 {
1096 if (!(l = mutt_istr_startswith(s, "to:")))
1097 return 0;
1098 break;
1099 }
1100 default:
1101 return 0;
1102 }
1103
1104 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
1105 mutt_addrlist_parse(&al, s + l);
1106 if (TAILQ_EMPTY(&al))
1107 return 0;
1108
1111 struct Address *a = NULL;
1112 TAILQ_FOREACH(a, &al, entries)
1113 {
1114 if (a->personal)
1115 {
1117 }
1118 }
1119
1120 /* angle brackets for return path are mandated by RFC5322,
1121 * so leave Return-Path as-is */
1122 if (rp)
1123 {
1124 *h = mutt_str_dup(s);
1125 }
1126 else
1127 {
1128 struct Buffer buf = { 0 };
1129 (*h)[l - 1] = '\0';
1130 mutt_addrlist_write_wrap(&al, &buf, *h);
1131 mutt_buffer_addch(&buf, '\n');
1132 *h = buf.data;
1133 }
1134
1136
1137 FREE(&s);
1138 return 1;
1139}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1443
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:687
size_t mutt_addrlist_write_wrap(const struct AddressList *al, struct Buffer *buf, const char *header)
Write an AddressList to a buffer, perform line wrapping.
Definition: address.c:1175
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1361
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:462
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:409
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:78
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:908
static int address_header_decode(char **h)
Parse an email's headers.
Definition: copy.c:1043
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:415
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:950
static void add_one_header(struct Headers *headers, size_t pos, char *value)
Add a header to a Headers array.
Definition: copy.c:75
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:105
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:875
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:587
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:641
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:981
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:384
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:469
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:229
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:708
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
struct ListHead HeaderOrderList
List of header fields in the order they should be displayed.
Definition: globals.c:50
Global variables.
#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 *state)
Handler for the Body of an email.
Definition: handler.c:1619
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:1443
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:750
void mutt_write_references(const struct ListHead *r, FILE *fp, size_t trim)
Add the message references to a list.
Definition: header.c:513
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
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_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:350
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
#define STATE_PAGER
Output will be displayed in the Pager.
Definition: state.h:41
#define STATE_WEED
Weed headers even when not in display mode.
Definition: state.h:35
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define STATE_REPLYING
Are we replying?
Definition: state.h:38
#define STATE_VERIFY
Perform signature verification.
Definition: state.h:33
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:36
#define STATE_PRINTING
Are we printing? - STATE_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
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
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.
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:366
Some miscellaneous functions.
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1200
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1154
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1062
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1179
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:1743
char * nm_email_get_folder(struct Email *e)
Get the folder for a Email.
Definition: notmuch.c:1456
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:315
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 STAILQ_EMPTY(head)
Definition: queue.h:348
#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:625
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:655
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:778
Convenience wrapper for the send headers.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
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
char * data
Pointer to data.
Definition: buffer.h:35
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:98
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:110
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:47
int wraplen
Width to wrap lines to (when flags & STATE_DISPLAY)
Definition: state.h:52
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:51
FILE * fp_out
File to write to.
Definition: state.h:49
char * prefix
String to add to the beginning of each output line.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:48
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:145