NeoMutt  2024-11-14-34-g5aaf0d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
external.c
Go to the documentation of this file.
1
32#include "config.h"
33#include <limits.h>
34#include <stdbool.h>
35#include <stdio.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38#include "mutt/lib.h"
39#include "address/lib.h"
40#include "config/lib.h"
41#include "email/lib.h"
42#include "core/lib.h"
43#include "alias/lib.h"
44#include "gui/lib.h"
45#include "mutt.h"
46#include "external.h"
47#include "attach/lib.h"
48#include "browser/lib.h"
49#include "complete/lib.h"
50#include "editor/lib.h"
51#include "history/lib.h"
52#include "imap/lib.h"
53#include "ncrypt/lib.h"
54#include "parse/lib.h"
55#include "progress/lib.h"
56#include "question/lib.h"
57#include "send/lib.h"
58#include "copy.h"
59#include "globals.h"
60#include "hook.h"
61#include "mutt_logging.h"
62#include "mutt_mailbox.h"
63#include "mutt_thread.h"
64#include "muttlib.h"
65#include "mx.h"
66#include "protos.h"
67#ifdef USE_NOTMUCH
68#include "notmuch/lib.h"
69#endif
70#ifdef ENABLE_NLS
71#include <libintl.h>
72#endif
73
75static struct Buffer LastSaveFolder = { 0 };
76
81{
83}
84
90void index_bounce_message(struct Mailbox *m, struct EmailArray *ea)
91{
92 if (!m || !ea || ARRAY_EMPTY(ea))
93 return;
94
95 struct Buffer *buf = buf_pool_get();
96 struct Buffer *prompt = buf_pool_get();
97 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
98 char *err = NULL;
99 int rc;
100 int msg_count = 0;
101
102 struct Email **ep = NULL;
103 ARRAY_FOREACH(ep, ea)
104 {
105 struct Email *e = *ep;
106 /* RFC5322 mandates a From: header,
107 * so warn before bouncing messages without one */
108 if (TAILQ_EMPTY(&e->env->from))
109 mutt_error(_("Warning: message contains no From: header"));
110
111 msg_count++;
112 }
113
114 if (msg_count == 1)
115 buf_strcpy(prompt, _("Bounce message to: "));
116 else
117 buf_strcpy(prompt, _("Bounce tagged messages to: "));
118
120 &CompleteAliasOps, NULL);
121 if ((rc != 0) || buf_is_empty(buf))
122 goto done;
123
125 if (TAILQ_EMPTY(&al))
126 {
127 mutt_error(_("Error parsing address"));
128 goto done;
129 }
130
132
133 if (mutt_addrlist_to_intl(&al, &err) < 0)
134 {
135 mutt_error(_("Bad IDN: '%s'"), err);
136 FREE(&err);
137 goto done;
138 }
139
140 buf_reset(buf);
141 mutt_addrlist_write(&al, buf, true);
142
143 buf_printf(prompt, ngettext("Bounce message to %s?", "Bounce messages to %s?", msg_count),
144 buf_string(buf));
145
146 if (query_quadoption(buf_string(prompt), NeoMutt->sub, "bounce") != MUTT_YES)
147 {
148 msgwin_clear_text(NULL);
149 mutt_message(ngettext("Message not bounced", "Messages not bounced", msg_count));
150 goto done;
151 }
152
153 msgwin_clear_text(NULL);
154
155 struct Message *msg = NULL;
156 ARRAY_FOREACH(ep, ea)
157 {
158 struct Email *e = *ep;
159 msg = mx_msg_open(m, e);
160 if (!msg)
161 {
162 rc = -1;
163 break;
164 }
165
166 rc = mutt_bounce_message(msg->fp, m, e, &al, NeoMutt->sub);
167 mx_msg_close(m, &msg);
168
169 if (rc < 0)
170 break;
171 }
172
173 /* If no error, or background, display message. */
174 if ((rc == 0) || (rc == S_BKG))
175 mutt_message(ngettext("Message bounced", "Messages bounced", msg_count));
176
177done:
179 buf_pool_release(&buf);
180 buf_pool_release(&prompt);
181}
182
190static void pipe_set_flags(bool decode, bool print, CopyMessageFlags *cmflags,
191 CopyHeaderFlags *chflags)
192{
193 if (decode)
194 {
195 *chflags |= CH_DECODE | CH_REORDER;
196 *cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
197
198 const bool c_print_decode_weed = cs_subset_bool(NeoMutt->sub, "print_decode_weed");
199 const bool c_pipe_decode_weed = cs_subset_bool(NeoMutt->sub, "pipe_decode_weed");
200 if (print ? c_print_decode_weed : c_pipe_decode_weed)
201 {
202 *chflags |= CH_WEED;
203 *cmflags |= MUTT_CM_WEED;
204 }
205
206 /* Just as with copy-decode, we need to update the mime fields to avoid
207 * confusing programs that may process the email. However, we don't want
208 * to force those fields to appear in printouts. */
209 if (!print)
210 *chflags |= CH_MIME | CH_TXTPLAIN;
211 }
212
213 if (print)
214 *cmflags |= MUTT_CM_PRINTING;
215}
216
226static void pipe_msg(struct Mailbox *m, struct Email *e, struct Message *msg,
227 FILE *fp, bool decode, bool print)
228{
230 CopyHeaderFlags chflags = CH_FROM;
231
232 pipe_set_flags(decode, print, &cmflags, &chflags);
233
234 if ((WithCrypto != 0) && decode && e->security & SEC_ENCRYPT)
235 {
237 return;
238 mutt_endwin();
239 }
240
241 const bool own_msg = !msg;
242 if (own_msg)
243 {
244 msg = mx_msg_open(m, e);
245 if (!msg)
246 {
247 return;
248 }
249 }
250
251 if (decode)
252 {
254 }
255
256 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
257
258 if (own_msg)
259 {
260 mx_msg_close(m, &msg);
261 }
262}
263
278static int pipe_message(struct Mailbox *m, struct EmailArray *ea, const char *cmd,
279 bool decode, bool print, bool split, const char *sep)
280{
281 if (!m || !ea || ARRAY_EMPTY(ea))
282 return 1;
283
284 int rc = 0;
285 pid_t pid;
286 FILE *fp_out = NULL;
287
288 if (ARRAY_SIZE(ea) == 1)
289 {
290 struct Email *e = *ARRAY_GET(ea, 0);
291 /* handle a single message */
293
294 struct Message *msg = mx_msg_open(m, e);
295 if (msg && (WithCrypto != 0) && decode)
296 {
299 {
300 mx_msg_close(m, &msg);
301 return 1;
302 }
303 }
304 mutt_endwin();
305
306 pid = filter_create(cmd, &fp_out, NULL, NULL, EnvList);
307 if (pid < 0)
308 {
309 mutt_perror(_("Can't create filter process"));
310 mx_msg_close(m, &msg);
311 return 1;
312 }
313
314 OptKeepQuiet = true;
315 pipe_msg(m, e, msg, fp_out, decode, print);
316 mx_msg_close(m, &msg);
317 mutt_file_fclose(&fp_out);
318 rc = filter_wait(pid);
319 OptKeepQuiet = false;
320 }
321 else
322 {
323 /* handle tagged messages */
324 if ((WithCrypto != 0) && decode)
325 {
326 struct Email **ep = NULL;
327 ARRAY_FOREACH(ep, ea)
328 {
329 struct Email *e = *ep;
330 struct Message *msg = mx_msg_open(m, e);
331 if (msg)
332 {
335 mx_msg_close(m, &msg);
336 }
338 {
339 return 1;
340 }
341 }
342 }
343
344 if (split)
345 {
346 struct Email **ep = NULL;
347 ARRAY_FOREACH(ep, ea)
348 {
349 struct Email *e = *ep;
351 mutt_endwin();
352 pid = filter_create(cmd, &fp_out, NULL, NULL, EnvList);
353 if (pid < 0)
354 {
355 mutt_perror(_("Can't create filter process"));
356 return 1;
357 }
358 OptKeepQuiet = true;
359 pipe_msg(m, e, NULL, fp_out, decode, print);
360 /* add the message separator */
361 if (sep)
362 fputs(sep, fp_out);
363 mutt_file_fclose(&fp_out);
364 if (filter_wait(pid) != 0)
365 rc = 1;
366 OptKeepQuiet = false;
367 }
368 }
369 else
370 {
371 mutt_endwin();
372 pid = filter_create(cmd, &fp_out, NULL, NULL, EnvList);
373 if (pid < 0)
374 {
375 mutt_perror(_("Can't create filter process"));
376 return 1;
377 }
378 OptKeepQuiet = true;
379 struct Email **ep = NULL;
380 ARRAY_FOREACH(ep, ea)
381 {
382 struct Email *e = *ep;
384 pipe_msg(m, e, NULL, fp_out, decode, print);
385 /* add the message separator */
386 if (sep)
387 fputs(sep, fp_out);
388 }
389 mutt_file_fclose(&fp_out);
390 if (filter_wait(pid) != 0)
391 rc = 1;
392 OptKeepQuiet = false;
393 }
394 }
395
396 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
397 if ((rc != 0) || c_wait_key)
399 return rc;
400}
401
407void mutt_pipe_message(struct Mailbox *m, struct EmailArray *ea)
408{
409 if (!m || !ea)
410 return;
411
412 struct Buffer *buf = buf_pool_get();
413
414 if (mw_get_field(_("Pipe to command: "), buf, MUTT_COMP_NO_FLAGS,
415 HC_EXT_COMMAND, &CompleteFileOps, NULL) != 0)
416 {
417 goto cleanup;
418 }
419
420 if (buf_is_empty(buf))
421 goto cleanup;
422
423 buf_expand_path(buf);
424 const bool c_pipe_decode = cs_subset_bool(NeoMutt->sub, "pipe_decode");
425 const bool c_pipe_split = cs_subset_bool(NeoMutt->sub, "pipe_split");
426 const char *const c_pipe_sep = cs_subset_string(NeoMutt->sub, "pipe_sep");
427 pipe_message(m, ea, buf_string(buf), c_pipe_decode, false, c_pipe_split, c_pipe_sep);
428
429cleanup:
430 buf_pool_release(&buf);
431}
432
438void mutt_print_message(struct Mailbox *m, struct EmailArray *ea)
439{
440 if (!m || !ea)
441 return;
442
443 const enum QuadOption c_print = cs_subset_quad(NeoMutt->sub, "print");
444 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
445 if (c_print && !c_print_command)
446 {
447 mutt_message(_("No printing command has been defined"));
448 return;
449 }
450
451 int msg_count = ARRAY_SIZE(ea);
452 const char *msg = ngettext("Print message?", "Print tagged messages?", msg_count);
453 if (query_quadoption(msg, NeoMutt->sub, "print") != MUTT_YES)
454 {
455 return;
456 }
457
458 const bool c_print_decode = cs_subset_bool(NeoMutt->sub, "print_decode");
459 const bool c_print_split = cs_subset_bool(NeoMutt->sub, "print_split");
460 if (pipe_message(m, ea, c_print_command, c_print_decode, true, c_print_split, "\f") == 0)
461 {
462 mutt_message(ngettext("Message printed", "Messages printed", msg_count));
463 }
464 else
465 {
466 mutt_message(ngettext("Message could not be printed",
467 "Messages could not be printed", msg_count));
468 }
469}
470
476bool mutt_select_sort(bool reverse)
477{
478 enum SortType sort = SORT_DATE;
479
480 switch (mw_multi_choice(reverse ?
481 /* L10N: The highlighted letters must match the "Sort" options */
482 _("Rev-Sort (d)ate,(f)rm,(r)ecv,(s)ubj,t(o),(t)hread,(u)nsort,si(z)e,s(c)ore,s(p)am,(l)abel?") :
483 /* L10N: The highlighted letters must match the "Rev-Sort" options */
484 _("Sort (d)ate,(f)rm,(r)ecv,(s)ubj,t(o),(t)hread,(u)nsort,si(z)e,s(c)ore,s(p)am,(l)abel?"),
485 /* L10N: These must match the highlighted letters from "Sort" and "Rev-Sort" */
486 _("dfrsotuzcpl")))
487 {
488 case -1: /* abort - don't resort */
489 return false;
490
491 case 1: /* (d)ate */
492 sort = SORT_DATE;
493 break;
494
495 case 2: /* (f)rm */
496 sort = SORT_FROM;
497 break;
498
499 case 3: /* (r)ecv */
500 sort = SORT_RECEIVED;
501 break;
502
503 case 4: /* (s)ubj */
504 sort = SORT_SUBJECT;
505 break;
506
507 case 5: /* t(o) */
508 sort = SORT_TO;
509 break;
510
511 case 6: /* (t)hread */
512 sort = SORT_THREADS;
513 break;
514
515 case 7: /* (u)nsort */
516 sort = SORT_ORDER;
517 break;
518
519 case 8: /* si(z)e */
520 sort = SORT_SIZE;
521 break;
522
523 case 9: /* s(c)ore */
524 sort = SORT_SCORE;
525 break;
526
527 case 10: /* s(p)am */
528 sort = SORT_SPAM;
529 break;
530
531 case 11: /* (l)abel */
532 sort = SORT_LABEL;
533 break;
534 }
535
536 const unsigned char c_use_threads = cs_subset_enum(NeoMutt->sub, "use_threads");
537 const enum SortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
538 int rc = CSR_ERR_CODE;
539 if ((sort != SORT_THREADS) || (c_use_threads == UT_UNSET))
540 {
541 if ((sort != SORT_THREADS) && (c_sort & SORT_LAST))
542 sort |= SORT_LAST;
543 if (reverse)
544 sort |= SORT_REVERSE;
545
546 rc = cs_subset_str_native_set(NeoMutt->sub, "sort", sort, NULL);
547 }
548 else
549 {
550 ASSERT((c_sort & SORT_MASK) != SORT_THREADS); /* See index_config_observer() */
551 /* Preserve the value of $sort, and toggle whether we are threaded. */
552 switch (c_use_threads)
553 {
554 case UT_FLAT:
555 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
556 reverse ? UT_REVERSE : UT_THREADS, NULL);
557 break;
558 case UT_THREADS:
559 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
560 reverse ? UT_REVERSE : UT_FLAT, NULL);
561 break;
562 case UT_REVERSE:
563 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
564 reverse ? UT_FLAT : UT_THREADS, NULL);
565 break;
566 default:
567 ASSERT(false);
568 }
569 }
570
571 return ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE));
572}
573
580{
581 bool rc = false;
582 struct Buffer *buf = buf_pool_get();
583
584 if (mw_get_field(_("Shell command: "), buf, MUTT_COMP_NO_FLAGS,
585 HC_EXT_COMMAND, &CompleteFileOps, NULL) != 0)
586 {
587 goto done;
588 }
589
590 if (buf_is_empty(buf))
591 {
592 const char *const c_shell = cs_subset_string(NeoMutt->sub, "shell");
593 buf_strcpy(buf, c_shell);
594 }
595
596 if (buf_is_empty(buf))
597 {
598 goto done;
599 }
600
601 msgwin_clear_text(NULL);
602 mutt_endwin();
603 fflush(stdout);
604 int rc2 = mutt_system(buf_string(buf));
605 if (rc2 == -1)
606 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", buf_string(buf));
607
608 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
609 if ((rc2 != 0) || c_wait_key)
611
612 rc = true;
613done:
614 buf_pool_release(&buf);
615 return rc;
616}
617
622{
623 struct Buffer *buf = buf_pool_get();
624 struct Buffer *err = buf_pool_get();
625
626 window_redraw(NULL);
627 /* if enter is pressed after : with no command, just return */
629 &CompleteCommandOps, NULL) != 0) ||
630 buf_is_empty(buf))
631 {
632 goto done;
633 }
634
635 enum CommandResult rc = parse_rc_line(buf_string(buf), err);
636 if (!buf_is_empty(err))
637 {
638 if (rc == MUTT_CMD_SUCCESS) /* command succeeded with message */
639 mutt_message("%s", buf_string(err));
640 else if (rc == MUTT_CMD_ERROR)
641 mutt_error("%s", buf_string(err));
642 else if (rc == MUTT_CMD_WARNING)
643 mutt_warning("%s", buf_string(err));
644 }
645
646 if (NeoMutt)
647 {
648 // Running commands could cause anything to change, so let others know
650 }
651
652done:
653 buf_pool_release(&buf);
654 buf_pool_release(&err);
655}
656
662{
663 const char *pfx = NULL;
664
665 struct AddressList *al = mutt_get_address(env, &pfx);
666 if (!al)
667 return;
668
669 /* Note: We don't convert IDNA to local representation this time.
670 * That is intentional, so the user has an opportunity to copy &
671 * paste the on-the-wire form of the address to other, IDN-unable
672 * software. */
673 struct Buffer *buf = buf_pool_get();
674 mutt_addrlist_write(al, buf, false);
675 mutt_message("%s: %s", pfx, buf_string(buf));
676 buf_pool_release(&buf);
677}
678
686static void set_copy_flags(struct Email *e, enum MessageTransformOpt transform_opt,
687 CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
688{
689 *cmflags = MUTT_CM_NO_FLAGS;
690 *chflags = CH_UPDATE_LEN;
691
692 const bool need_decrypt = (transform_opt == TRANSFORM_DECRYPT) &&
693 (e->security & SEC_ENCRYPT);
694 const bool want_pgp = (WithCrypto & APPLICATION_PGP);
695 const bool want_smime = (WithCrypto & APPLICATION_SMIME);
696 const bool is_pgp = mutt_is_application_pgp(e->body) & SEC_ENCRYPT;
697 const bool is_smime = mutt_is_application_smime(e->body) & SEC_ENCRYPT;
698
699 if (need_decrypt && want_pgp && mutt_is_multipart_encrypted(e->body))
700 {
701 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
702 *cmflags = MUTT_CM_DECODE_PGP;
703 }
704 else if (need_decrypt && want_pgp && is_pgp)
705 {
706 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN;
707 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
708 }
709 else if (need_decrypt && want_smime && is_smime)
710 {
711 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
712 *cmflags = MUTT_CM_DECODE_SMIME;
713 }
714 else if (transform_opt == TRANSFORM_DECODE)
715 {
716 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN | CH_DECODE; // then decode RFC2047
717 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
718 const bool c_copy_decode_weed = cs_subset_bool(NeoMutt->sub, "copy_decode_weed");
719 if (c_copy_decode_weed)
720 {
721 *chflags |= CH_WEED; // and respect $weed
722 *cmflags |= MUTT_CM_WEED;
723 }
724 }
725}
726
737int mutt_save_message_mbox(struct Mailbox *m_src, struct Email *e, enum MessageSaveOpt save_opt,
738 enum MessageTransformOpt transform_opt, struct Mailbox *m_dst)
739{
742 int rc;
743
744 set_copy_flags(e, transform_opt, &cmflags, &chflags);
745
746 struct Message *msg = mx_msg_open(m_src, e);
747 if (msg && transform_opt != TRANSFORM_NONE)
748 {
750 }
751
752 rc = mutt_append_message(m_dst, m_src, e, msg, cmflags, chflags);
753 mx_msg_close(m_src, &msg);
754 if (rc != 0)
755 return rc;
756
757 if (save_opt == SAVE_MOVE)
758 {
759 mutt_set_flag(m_src, e, MUTT_DELETE, true, true);
760 mutt_set_flag(m_src, e, MUTT_PURGE, true, true);
761 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
762 if (c_delete_untag)
763 mutt_set_flag(m_src, e, MUTT_TAG, false, true);
764 }
765
766 return 0;
767}
768
778int mutt_save_message(struct Mailbox *m, struct EmailArray *ea,
779 enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
780{
781 if (!ea || ARRAY_EMPTY(ea))
782 return -1;
783
784 int rc = -1;
785 int tagged_progress_count = 0;
786 unsigned int msg_count = ARRAY_SIZE(ea);
787 struct Mailbox *m_save = NULL;
788
789 struct Buffer *buf = buf_pool_get();
790 struct stat st = { 0 };
791 struct Email *e_cur = *ARRAY_GET(ea, 0);
792
793 const SecurityFlags security_flags = WithCrypto ? e_cur->security : SEC_NO_FLAGS;
794 const bool is_passphrase_needed = security_flags & SEC_ENCRYPT;
795
796 const char *prompt = NULL;
797 const char *progress_msg = NULL;
798
799 // Set prompt and progress_msg
800 switch (save_opt)
801 {
802 case SAVE_COPY:
803 // L10N: Progress meter message when copying tagged messages
804 progress_msg = (msg_count > 1) ? _("Copying tagged messages...") : NULL;
805 switch (transform_opt)
806 {
807 case TRANSFORM_NONE:
808 prompt = (msg_count > 1) ? _("Copy tagged to mailbox") : _("Copy to mailbox");
809 break;
811 prompt = (msg_count > 1) ? _("Decrypt-copy tagged to mailbox") :
812 _("Decrypt-copy to mailbox");
813 break;
814 case TRANSFORM_DECODE:
815 prompt = (msg_count > 1) ? _("Decode-copy tagged to mailbox") :
816 _("Decode-copy to mailbox");
817 break;
818 }
819 break;
820
821 case SAVE_MOVE:
822 // L10N: Progress meter message when saving tagged messages
823 progress_msg = (msg_count > 1) ? _("Saving tagged messages...") : NULL;
824 switch (transform_opt)
825 {
826 case TRANSFORM_NONE:
827 prompt = (msg_count > 1) ? _("Save tagged to mailbox") : _("Save to mailbox");
828 break;
830 prompt = (msg_count > 1) ? _("Decrypt-save tagged to mailbox") :
831 _("Decrypt-save to mailbox");
832 break;
833 case TRANSFORM_DECODE:
834 prompt = (msg_count > 1) ? _("Decode-save tagged to mailbox") :
835 _("Decode-save to mailbox");
836 break;
837 }
838 break;
839 }
840
842 mutt_default_save(buf, e_cur);
844
845 if (mw_enter_fname(prompt, buf, false, NULL, false, NULL, NULL, MUTT_SEL_NO_FLAGS) == -1)
846 {
847 goto cleanup;
848 }
849
850 size_t pathlen = buf_len(buf);
851 if (pathlen == 0)
852 goto cleanup;
853
854 mutt_path_tidy(buf, true);
855
856 /* This is an undocumented feature of ELM pointed out to me by Felix von
857 * Leitner <leitner@prz.fu-berlin.de> */
860 if (mutt_str_equal(buf_string(buf), "."))
862 else
864
865 buf_expand_path(buf);
866
867 /* check to make sure that this file is really the one the user wants */
868 if (mutt_save_confirm(buf_string(buf), &st) != 0)
869 goto cleanup;
870
871 if (is_passphrase_needed && (transform_opt != TRANSFORM_NONE) &&
872 !crypt_valid_passphrase(security_flags))
873 {
874 rc = -1;
875 goto errcleanup;
876 }
877
878 mutt_message(_("Copying to %s..."), buf_string(buf));
879
880 enum MailboxType mailbox_type = imap_path_probe(buf_string(buf), NULL);
881 if ((m->type == MUTT_IMAP) && (transform_opt == TRANSFORM_NONE) && (mailbox_type == MUTT_IMAP))
882 {
883 rc = imap_copy_messages(m, ea, buf_string(buf), save_opt);
884 switch (rc)
885 {
886 /* success */
887 case 0:
889 rc = 0;
890 if (save_opt == SAVE_MOVE)
891 {
892 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
893 if (c_delete_untag)
894 {
895 struct Email **ep = NULL;
896 ARRAY_FOREACH(ep, ea)
897 {
898 mutt_set_flag(m, *ep, MUTT_TAG, false, true);
899 }
900 }
901 }
902 goto cleanup;
903 /* non-fatal error: continue to fetch/append */
904 case 1:
905 break;
906 /* fatal error, abort */
907 case -1:
908 goto errcleanup;
909 }
910 }
911
913 m_save = mx_path_resolve(buf_string(buf));
914 bool old_append = m_save->append;
915 OpenMailboxFlags mbox_flags = MUTT_NEWFOLDER;
916 /* Display a tagged message progress counter, rather than (for
917 * IMAP) a per-message progress counter */
918 if (msg_count > 1)
919 mbox_flags |= MUTT_QUIET;
920 if (!mx_mbox_open(m_save, mbox_flags))
921 {
922 rc = -1;
923 mailbox_free(&m_save);
924 goto errcleanup;
925 }
926 m_save->append = true;
927
928 /* If we're saving to a compressed mailbox, the stats won't be updated
929 * until the next open. Until then, improvise. */
930 struct Mailbox *m_comp = NULL;
931 if (m_save->compress_info)
932 {
933 m_comp = mailbox_find(m_save->realpath);
934 }
935 /* We probably haven't been opened yet */
936 if (m_comp && (m_comp->msg_count == 0))
937 m_comp = NULL;
938
939 if (msg_count == 1)
940 {
941 rc = mutt_save_message_mbox(m, e_cur, save_opt, transform_opt, m_save);
942 if (rc != 0)
943 {
944 mx_mbox_close(m_save);
945 m_save->append = old_append;
946 goto errcleanup;
947 }
948
949 if (m_comp)
950 {
951 m_comp->msg_count++;
952 if (!e_cur->read)
953 {
954 m_comp->msg_unread++;
955 if (!e_cur->old)
956 m_comp->msg_new++;
957 }
958 if (e_cur->flagged)
959 m_comp->msg_flagged++;
960 }
961 }
962 else
963 {
964 rc = 0;
965
966#ifdef USE_NOTMUCH
967 if (m->type == MUTT_NOTMUCH)
968 nm_db_longrun_init(m, true);
969#endif
970 struct Progress *progress = progress_new(MUTT_PROGRESS_WRITE, msg_count);
971 progress_set_message(progress, "%s", progress_msg);
972 struct Email **ep = NULL;
973 ARRAY_FOREACH(ep, ea)
974 {
975 struct Email *e = *ep;
976 progress_update(progress, ++tagged_progress_count, -1);
978 rc = mutt_save_message_mbox(m, e, save_opt, transform_opt, m_save);
979 if (rc != 0)
980 break;
981
982 if (m_comp)
983 {
984 struct Email *e2 = e;
985 m_comp->msg_count++;
986 if (!e2->read)
987 {
988 m_comp->msg_unread++;
989 if (!e2->old)
990 m_comp->msg_new++;
991 }
992 if (e2->flagged)
993 m_comp->msg_flagged++;
994 }
995 }
996 progress_free(&progress);
997
998#ifdef USE_NOTMUCH
999 if (m->type == MUTT_NOTMUCH)
1001#endif
1002 if (rc != 0)
1003 {
1004 mx_mbox_close(m_save);
1005 m_save->append = old_append;
1006 goto errcleanup;
1007 }
1008 }
1009
1010 const bool need_mailbox_cleanup = ((m_save->type == MUTT_MBOX) ||
1011 (m_save->type == MUTT_MMDF));
1012
1013 mx_mbox_close(m_save);
1014 m_save->append = old_append;
1015
1016 if (need_mailbox_cleanup)
1018
1020 rc = 0;
1021
1022errcleanup:
1023 if (rc != 0)
1024 {
1025 switch (save_opt)
1026 {
1027 case SAVE_MOVE:
1028 if (msg_count > 1)
1029 {
1030 // L10N: Message when an index tagged save operation fails for some reason
1031 mutt_error(_("Error saving tagged messages"));
1032 }
1033 else
1034 {
1035 // L10N: Message when an index/pager save operation fails for some reason
1036 mutt_error(_("Error saving message"));
1037 }
1038 break;
1039 case SAVE_COPY:
1040 if (msg_count > 1)
1041 {
1042 // L10N: Message when an index tagged copy operation fails for some reason
1043 mutt_error(_("Error copying tagged messages"));
1044 }
1045 else
1046 {
1047 // L10N: Message when an index/pager copy operation fails for some reason
1048 mutt_error(_("Error copying message"));
1049 }
1050 break;
1051 }
1052 }
1053
1054 mailbox_free(&m_save);
1055
1056cleanup:
1057 buf_pool_release(&buf);
1058 return rc;
1059}
1060
1070bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
1071{
1072 struct Buffer *buf = buf_pool_get();
1073 struct Buffer *charset = buf_pool_get();
1074 struct Buffer *obuf = buf_pool_get();
1075 struct Buffer *tmp = buf_pool_get();
1076
1077 bool rc = false;
1078 bool charset_changed = false;
1079 bool type_changed = false;
1080 bool structure_changed = false;
1081
1082 char *cp = mutt_param_get(&b->parameter, "charset");
1083 buf_strcpy(charset, cp);
1084
1085 buf_printf(buf, "%s/%s", TYPE(b), b->subtype);
1086 buf_copy(obuf, buf);
1087 if (!TAILQ_EMPTY(&b->parameter))
1088 {
1089 struct Parameter *np = NULL;
1090 TAILQ_FOREACH(np, &b->parameter, entries)
1091 {
1092 mutt_addr_cat(tmp->data, tmp->dsize, np->value, MimeSpecials);
1093 buf_add_printf(buf, "; %s=%s", np->attribute, buf_string(tmp));
1094 }
1095 }
1096
1097 if ((mw_get_field("Content-Type: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
1098 buf_is_empty(buf))
1099 {
1100 goto done;
1101 }
1102
1103 /* clean up previous junk */
1105 FREE(&b->subtype);
1106
1108
1109 buf_printf(tmp, "%s/%s", TYPE(b), NONULL(b->subtype));
1110 type_changed = !mutt_istr_equal(buf_string(tmp), buf_string(obuf));
1111 charset_changed = !mutt_istr_equal(buf_string(charset),
1112 mutt_param_get(&b->parameter, "charset"));
1113
1114 /* if in send mode, check for conversion - current setting is default. */
1115
1116 if (!e && (b->type == TYPE_TEXT) && charset_changed)
1117 {
1118 buf_printf(tmp, _("Convert to %s upon sending?"),
1119 mutt_param_get(&b->parameter, "charset"));
1120 enum QuadOption ans = query_yesorno(buf_string(tmp), b->noconv ? MUTT_NO : MUTT_YES);
1121 if (ans != MUTT_ABORT)
1122 b->noconv = (ans == MUTT_NO);
1123 }
1124
1125 /* inform the user */
1126
1127 buf_printf(tmp, "%s/%s", TYPE(b), NONULL(b->subtype));
1128 if (type_changed)
1129 mutt_message(_("Content-Type changed to %s"), buf_string(tmp));
1130 if ((b->type == TYPE_TEXT) && charset_changed)
1131 {
1132 if (type_changed)
1133 mutt_sleep(1);
1134 mutt_message(b->noconv ? _("Character set changed to %s; not converting") :
1135 _("Character set changed to %s; converting"),
1136 mutt_param_get(&b->parameter, "charset"));
1137 }
1138
1139 b->force_charset |= charset_changed;
1140
1141 if (!is_multipart(b) && b->parts)
1142 {
1143 structure_changed = true;
1144 mutt_body_free(&b->parts);
1145 }
1146 if (!mutt_is_message_type(b->type, b->subtype) && b->email)
1147 {
1148 structure_changed = true;
1149 b->email->body = NULL;
1150 email_free(&b->email);
1151 }
1152
1153 if (fp && !b->parts && (is_multipart(b) || mutt_is_message_type(b->type, b->subtype)))
1154 {
1155 structure_changed = true;
1156 mutt_parse_part(fp, b);
1157 }
1158
1159 if ((WithCrypto != 0) && e)
1160 {
1161 if (e->body == b)
1163
1164 e->security |= crypt_query(b);
1165 }
1166
1167 rc = structure_changed | type_changed;
1168
1169done:
1170 buf_pool_release(&buf);
1171 buf_pool_release(&charset);
1172 buf_pool_release(&obuf);
1173 buf_pool_release(&tmp);
1174 return rc;
1175}
1176
1183static bool check_traditional_pgp(struct Mailbox *m, struct Email *e)
1184{
1185 bool rc = false;
1186
1188
1189 struct Message *msg = mx_msg_open(m, e);
1190 if (msg)
1191 {
1192 mutt_parse_mime_message(e, msg->fp);
1193 if (crypt_pgp_check_traditional(msg->fp, e->body, false))
1194 {
1195 e->security = crypt_query(e->body);
1196 rc = true;
1197 }
1198
1200 mx_msg_close(m, &msg);
1201 }
1202 return rc;
1203}
1204
1211bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailArray *ea)
1212{
1213 bool rc = false;
1214
1215 struct Email **ep = NULL;
1216 ARRAY_FOREACH(ep, ea)
1217 {
1218 struct Email *e = *ep;
1220 rc = check_traditional_pgp(m, e) || rc;
1221 }
1222
1223 return rc;
1224}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
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:708
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1206
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:644
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1293
Email Address Handling.
const struct CompleteOps CompleteAliasOps
Auto-Completion of Aliases.
Definition: complete.c:108
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:295
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:327
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:87
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:109
GUI display the mailboxes in a side panel.
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:596
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
Select a Mailbox from a list.
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:56
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:204
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:377
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:337
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
CommandResult
Error codes for command_t parse functions.
Definition: command.h:36
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:39
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:37
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition: command.h:38
const struct CompleteOps CompleteCommandOps
Auto-Completion of Commands.
Definition: helpers.c:477
Auto-completion.
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:192
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:71
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:266
Convenience wrapper for the config headers.
#define CSR_SUC_NO_CHANGE
The value hasn't changed.
Definition: set.h:44
#define CSR_ERR_CODE
Problem with the code.
Definition: set.h:36
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
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:982
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:907
Duplicate the structure of an entire email.
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:56
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:43
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:57
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:58
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:47
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:40
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:62
#define CH_WEED
Weed the headers?
Definition: copy.h:55
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition: copy.h:61
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:44
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:48
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:63
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:52
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:64
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:45
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:37
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:65
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:36
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:53
Convenience wrapper for the core headers.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:89
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:150
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:609
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:132
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:443
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition: crypt.c:548
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition: crypt.c:687
bool crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional()
Definition: cryptglue.c:282
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:173
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:151
Edit a string.
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:46
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1822
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition: parse.c:463
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1498
void mutt_print_message(struct Mailbox *m, struct EmailArray *ea)
Print a message.
Definition: external.c:438
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: external.c:476
void mutt_pipe_message(struct Mailbox *m, struct EmailArray *ea)
Pipe a message.
Definition: external.c:407
bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailArray *ea)
Check if a message has inline PGP content.
Definition: external.c:1211
static bool check_traditional_pgp(struct Mailbox *m, struct Email *e)
Check for an inline PGP content.
Definition: external.c:1183
static void pipe_set_flags(bool decode, bool print, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
Generate flags for copy header/message.
Definition: external.c:190
int mutt_save_message_mbox(struct Mailbox *m_src, struct Email *e, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt, struct Mailbox *m_dst)
Save a message to a given mailbox.
Definition: external.c:737
void index_bounce_message(struct Mailbox *m, struct EmailArray *ea)
Bounce an email.
Definition: external.c:90
void mutt_enter_command(void)
Enter a neomutt command.
Definition: external.c:621
int mutt_save_message(struct Mailbox *m, struct EmailArray *ea, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
Save an email.
Definition: external.c:778
static struct Buffer LastSaveFolder
The folder the user last saved to. Used by ci_save_message()
Definition: external.c:75
bool mutt_shell_escape(void)
Invoke a command in a subshell.
Definition: external.c:579
void external_cleanup(void)
Clean up commands globals.
Definition: external.c:80
static void set_copy_flags(struct Email *e, enum MessageTransformOpt transform_opt, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
Set the flags for a message copy.
Definition: external.c:686
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1070
static int pipe_message(struct Mailbox *m, struct EmailArray *ea, const char *cmd, bool decode, bool print, bool split, const char *sep)
Pipe message to a command.
Definition: external.c:278
static void pipe_msg(struct Mailbox *m, struct Email *e, struct Message *msg, FILE *fp, bool decode, bool print)
Pipe a message.
Definition: external.c:226
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: external.c:661
Manage where the email is piped to external commands.
MessageTransformOpt
Message transformation option.
Definition: external.h:41
@ TRANSFORM_NONE
No transformation.
Definition: external.h:42
@ TRANSFORM_DECODE
Decode message.
Definition: external.h:44
@ TRANSFORM_DECRYPT
Decrypt message.
Definition: external.h:43
MessageSaveOpt
Message save option.
Definition: external.h:51
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:53
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition: external.h:52
void mutt_file_resolve_symlink(struct Buffer *buf)
Resolve a symlink in place.
Definition: file.c:1659
#define mutt_file_fclose(FP)
Definition: file.h:138
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition: flags.c:57
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: globals.c:63
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:75
Global variables.
int mw_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file -.
Definition: curs_lib.c:236
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:274
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:63
#define mutt_warning(...)
Definition: logging2.h:90
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2345
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
@ HC_EXT_COMMAND
External commands.
Definition: lib.h:54
@ HC_ALIAS
Aliases.
Definition: lib.h:55
@ HC_NEO_COMMAND
NeoMutt commands.
Definition: lib.h:56
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:59
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition: hook.c:778
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:700
Parse and execute user-defined hooks.
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:44
IMAP network mailbox.
int imap_copy_messages(struct Mailbox *m, struct EmailArray *ea, const char *dest, enum MessageSaveOpt save_opt)
Server COPY messages to another folder.
Definition: message.c:1687
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define FREE(x)
Definition: memory.h:55
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
#define TYPE(body)
Definition: mime.h:89
#define is_multipart(body)
Definition: mime.h:82
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:519
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition: filter.c:209
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:173
bool mutt_path_tidy(struct Buffer *path, bool is_dir)
Remove unnecessary parts of a path.
Definition: path.c:169
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:672
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:77
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:80
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:75
#define PATH_MAX
Definition: mutt.h:42
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
void mailbox_restore_timestamp(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:407
Mailbox helper functions.
Create/manipulate threading in emails.
@ UT_FLAT
Unthreaded.
Definition: mutt_thread.h:99
@ UT_UNSET
Not yet set by user, stick to legacy semantics.
Definition: mutt_thread.h:98
@ UT_THREADS
Normal threading (root above subthreads)
Definition: mutt_thread.h:100
@ UT_REVERSE
Reverse threading (subthreads above root)
Definition: mutt_thread.h:101
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:633
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:843
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:519
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:746
Some miscellaneous functions.
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1180
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:288
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1636
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:598
API for mailboxes.
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:39
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND, but uses mutt_file_fopen() with mode "w" for mbox-style fo...
Definition: mxapi.h:45
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:44
API for encryption/signing of emails.
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:92
#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_NO_FLAGS
No flags are set.
Definition: lib.h:77
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
@ NT_GLOBAL_COMMAND
A NeoMutt command.
Definition: neomutt.h:63
@ NT_GLOBAL
Not object-related, NotifyGlobal.
Definition: notify_type.h:46
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:379
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:364
Notmuch virtual mailbox type.
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:85
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:62
Text parsing functions.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
Progress Bar.
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:83
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:80
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:52
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:379
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
enum CommandResult parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: rc.c:104
Convenience wrapper for the send headers.
int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:917
#define ASSERT(COND)
Definition: signal2.h:58
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:70
#define SORT_LAST
Sort thread by last-X, e.g. received date.
Definition: sort2.h:72
SortType
Methods for sorting.
Definition: sort2.h:34
@ SORT_SUBJECT
Sort by the email's subject.
Definition: sort2.h:38
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:40
@ SORT_THREADS
Sort by email threads.
Definition: sort2.h:41
@ SORT_SPAM
Sort by the email's spam score.
Definition: sort2.h:49
@ SORT_LABEL
Sort by the emails label.
Definition: sort2.h:54
@ SORT_FROM
Sort by the email's From field.
Definition: sort2.h:39
@ SORT_SIZE
Sort by the size of the email.
Definition: sort2.h:36
@ SORT_RECEIVED
Sort by when the message were delivered locally.
Definition: sort2.h:42
@ SORT_TO
Sort by the email's To field.
Definition: sort2.h:43
@ SORT_DATE
Sort by the date the email was sent.
Definition: sort2.h:35
@ SORT_SCORE
Sort by the email's score.
Definition: sort2.h:44
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:71
#define NONULL(x)
Definition: string2.h:37
#define S_BKG
Definition: string2.h:41
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:73
bool noconv
Don't do character set conversion.
Definition: body.h:46
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:63
struct Email * email
header information for message/rfc822
Definition: body.h:74
bool force_charset
Send mode: don't adjust the character set when in send-mode.
Definition: body.h:44
char * subtype
content-type subtype
Definition: body.h:61
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
String manipulation buffer.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
The envelope/body of an email.
Definition: email.h:39
bool read
Email is read.
Definition: email.h:50
struct Envelope * env
Envelope information.
Definition: email.h:68
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct Body * body
List of MIME parts.
Definition: email.h:69
bool old
Email is seen, but unread.
Definition: email.h:49
bool flagged
Marked important?
Definition: email.h:47
The header of an Email.
Definition: envelope.h:57
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
A mailbox.
Definition: mailbox.h:79
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:109
int msg_new
Number of new messages.
Definition: mailbox.h:92
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:90
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:121
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
A local copy of an email.
Definition: message.h:34
FILE * fp
pointer to the message data
Definition: message.h:35
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct Notify * notify
Notifications handler.
Definition: neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
Attribute associated with a MIME part.
Definition: parameter.h:33
char * attribute
Parameter name.
Definition: parameter.h:34
char * value
Parameter value.
Definition: parameter.h:35
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:297