NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
commands.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <assert.h>
33#include <limits.h>
34#include <stdbool.h>
35#include <stdio.h>
36#include <sys/stat.h>
37#include <unistd.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 "commands.h"
47#include "attach/lib.h"
48#include "browser/lib.h"
49#include "enter/lib.h"
50#include "ncrypt/lib.h"
51#include "progress/lib.h"
52#include "question/lib.h"
53#include "send/lib.h"
54#include "copy.h"
55#include "hook.h"
56#include "icommands.h"
57#include "init.h"
58#include "mutt_logging.h"
59#include "mutt_mailbox.h"
60#include "mutt_thread.h"
61#include "muttlib.h"
62#include "mx.h"
63#include "options.h"
64#include "protos.h"
65#ifdef USE_IMAP
66#include "imap/lib.h"
67#endif
68#ifdef USE_NOTMUCH
69#include "notmuch/lib.h"
70#endif
71#ifdef ENABLE_NLS
72#include <libintl.h>
73#endif
74
76static struct Buffer LastSaveFolder = { 0 };
77
82{
84}
85
91void ci_bounce_message(struct Mailbox *m, struct EmailList *el)
92{
93 if (!m || !el || STAILQ_EMPTY(el))
94 return;
95
96 struct Buffer *buf = mutt_buffer_pool_get();
97 struct Buffer *prompt = mutt_buffer_pool_get();
98 struct Buffer *scratch = NULL;
99
100 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
101 char *err = NULL;
102 int rc;
103 int msg_count = 0;
104
105 struct EmailNode *en = NULL;
106 STAILQ_FOREACH(en, el, entries)
107 {
108 /* RFC5322 mandates a From: header,
109 * so warn before bouncing messages without one */
110 if (TAILQ_EMPTY(&en->email->env->from))
111 mutt_error(_("Warning: message contains no From: header"));
112
113 msg_count++;
114 }
115
116 if (msg_count == 1)
117 mutt_buffer_strcpy(prompt, _("Bounce message to: "));
118 else
119 mutt_buffer_strcpy(prompt, _("Bounce tagged messages to: "));
120
122 false, NULL, NULL, NULL);
123 if ((rc != 0) || mutt_buffer_is_empty(buf))
124 goto done;
125
127 if (TAILQ_EMPTY(&al))
128 {
129 mutt_error(_("Error parsing address"));
130 goto done;
131 }
132
134
135 if (mutt_addrlist_to_intl(&al, &err) < 0)
136 {
137 mutt_error(_("Bad IDN: '%s'"), err);
138 FREE(&err);
139 goto done;
140 }
141
143 mutt_addrlist_write(&al, buf->data, buf->dsize, true);
144
145#define EXTRA_SPACE (15 + 7 + 2)
146 scratch = mutt_buffer_pool_get();
147 mutt_buffer_printf(scratch,
148 ngettext("Bounce message to %s?", "Bounce messages to %s?", msg_count),
149 mutt_buffer_string(buf));
150
151 const size_t width = msgwin_get_width();
152 if (mutt_strwidth(mutt_buffer_string(scratch)) > (width - EXTRA_SPACE))
153 {
154 mutt_simple_format(prompt->data, prompt->dsize, 0, width - EXTRA_SPACE,
155 JUSTIFY_LEFT, 0, scratch->data, scratch->dsize, false);
156 mutt_buffer_addstr(prompt, "...?");
157 }
158 else
159 mutt_buffer_copy(prompt, scratch);
160
161 const enum QuadOption c_bounce = cs_subset_quad(NeoMutt->sub, "bounce");
162 if (query_quadoption(c_bounce, mutt_buffer_string(prompt)) != MUTT_YES)
163 {
165 mutt_message(ngettext("Message not bounced", "Messages not bounced", msg_count));
166 goto done;
167 }
168
170
171 struct Message *msg = NULL;
172 STAILQ_FOREACH(en, el, entries)
173 {
174 msg = mx_msg_open(m, en->email->msgno);
175 if (!msg)
176 {
177 rc = -1;
178 break;
179 }
180
181 rc = mutt_bounce_message(msg->fp, m, en->email, &al, NeoMutt->sub);
182 mx_msg_close(m, &msg);
183
184 if (rc < 0)
185 break;
186 }
187
188 /* If no error, or background, display message. */
189 if ((rc == 0) || (rc == S_BKG))
190 mutt_message(ngettext("Message bounced", "Messages bounced", msg_count));
191
192done:
196 mutt_buffer_pool_release(&scratch);
197}
198
206static void pipe_set_flags(bool decode, bool print, CopyMessageFlags *cmflags,
207 CopyHeaderFlags *chflags)
208{
209 if (decode)
210 {
211 *chflags |= CH_DECODE | CH_REORDER;
212 *cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
213
214 const bool c_print_decode_weed = cs_subset_bool(NeoMutt->sub, "print_decode_weed");
215 const bool c_pipe_decode_weed = cs_subset_bool(NeoMutt->sub, "pipe_decode_weed");
216 if (print ? c_print_decode_weed : c_pipe_decode_weed)
217 {
218 *chflags |= CH_WEED;
219 *cmflags |= MUTT_CM_WEED;
220 }
221
222 /* Just as with copy-decode, we need to update the mime fields to avoid
223 * confusing programs that may process the email. However, we don't want
224 * to force those fields to appear in printouts. */
225 if (!print)
226 *chflags |= CH_MIME | CH_TXTPLAIN;
227 }
228
229 if (print)
230 *cmflags |= MUTT_CM_PRINTING;
231}
232
242static void pipe_msg(struct Mailbox *m, struct Email *e, struct Message *msg,
243 FILE *fp, bool decode, bool print)
244{
246 CopyHeaderFlags chflags = CH_FROM;
247
248 pipe_set_flags(decode, print, &cmflags, &chflags);
249
250 if ((WithCrypto != 0) && decode && e->security & SEC_ENCRYPT)
251 {
253 return;
254 endwin();
255 }
256
257 const bool own_msg = !msg;
258 if (own_msg)
259 {
260 msg = mx_msg_open(m, e->msgno);
261 if (!msg)
262 {
263 return;
264 }
265 }
266
267 if (decode)
268 {
270 }
271
272 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
273
274 if (own_msg)
275 {
276 mx_msg_close(m, &msg);
277 }
278}
279
294static int pipe_message(struct Mailbox *m, struct EmailList *el, const char *cmd,
295 bool decode, bool print, bool split, const char *sep)
296{
297 if (!m || !el)
298 return 1;
299
300 struct EmailNode *en = STAILQ_FIRST(el);
301 if (!en)
302 return 1;
303
304 int rc = 0;
305 pid_t pid;
306 FILE *fp_out = NULL;
307
308 if (!STAILQ_NEXT(en, entries))
309 {
310 /* handle a single message */
312
313 struct Message *msg = mx_msg_open(m, en->email->msgno);
314 if (msg && (WithCrypto != 0) && decode)
315 {
317 if ((en->email->security & SEC_ENCRYPT) &&
319 {
320 mx_msg_close(m, &msg);
321 return 1;
322 }
323 }
324 mutt_endwin();
325
326 pid = filter_create(cmd, &fp_out, NULL, NULL);
327 if (pid < 0)
328 {
329 mutt_perror(_("Can't create filter process"));
330 mx_msg_close(m, &msg);
331 return 1;
332 }
333
334 OptKeepQuiet = true;
335 pipe_msg(m, en->email, msg, fp_out, decode, print);
336 mx_msg_close(m, &msg);
337 mutt_file_fclose(&fp_out);
338 rc = filter_wait(pid);
339 OptKeepQuiet = false;
340 }
341 else
342 {
343 /* handle tagged messages */
344 if ((WithCrypto != 0) && decode)
345 {
346 STAILQ_FOREACH(en, el, entries)
347 {
348 struct Message *msg = mx_msg_open(m, en->email->msgno);
349 if (msg)
350 {
353 mx_msg_close(m, &msg);
354 }
355 if ((en->email->security & SEC_ENCRYPT) &&
357 {
358 return 1;
359 }
360 }
361 }
362
363 if (split)
364 {
365 STAILQ_FOREACH(en, el, entries)
366 {
368 mutt_endwin();
369 pid = filter_create(cmd, &fp_out, NULL, NULL);
370 if (pid < 0)
371 {
372 mutt_perror(_("Can't create filter process"));
373 return 1;
374 }
375 OptKeepQuiet = true;
376 pipe_msg(m, en->email, NULL, fp_out, decode, print);
377 /* add the message separator */
378 if (sep)
379 fputs(sep, fp_out);
380 mutt_file_fclose(&fp_out);
381 if (filter_wait(pid) != 0)
382 rc = 1;
383 OptKeepQuiet = false;
384 }
385 }
386 else
387 {
388 mutt_endwin();
389 pid = filter_create(cmd, &fp_out, NULL, NULL);
390 if (pid < 0)
391 {
392 mutt_perror(_("Can't create filter process"));
393 return 1;
394 }
395 OptKeepQuiet = true;
396 STAILQ_FOREACH(en, el, entries)
397 {
399 pipe_msg(m, en->email, NULL, fp_out, decode, print);
400 /* add the message separator */
401 if (sep)
402 fputs(sep, fp_out);
403 }
404 mutt_file_fclose(&fp_out);
405 if (filter_wait(pid) != 0)
406 rc = 1;
407 OptKeepQuiet = false;
408 }
409 }
410
411 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
412 if ((rc != 0) || c_wait_key)
414 return rc;
415}
416
422void mutt_pipe_message(struct Mailbox *m, struct EmailList *el)
423{
424 if (!m || !el)
425 return;
426
427 struct Buffer *buf = mutt_buffer_pool_get();
428
429 if (mutt_buffer_get_field(_("Pipe to command: "), buf, MUTT_COMP_FILE_SIMPLE,
430 false, NULL, NULL, NULL) != 0)
431 {
432 goto cleanup;
433 }
434
435 if (mutt_buffer_len(buf) == 0)
436 goto cleanup;
437
439 const bool c_pipe_decode = cs_subset_bool(NeoMutt->sub, "pipe_decode");
440 const bool c_pipe_split = cs_subset_bool(NeoMutt->sub, "pipe_split");
441 const char *const c_pipe_sep = cs_subset_string(NeoMutt->sub, "pipe_sep");
442 pipe_message(m, el, mutt_buffer_string(buf), c_pipe_decode, false, c_pipe_split, c_pipe_sep);
443
444cleanup:
446}
447
453void mutt_print_message(struct Mailbox *m, struct EmailList *el)
454{
455 if (!m || !el)
456 return;
457
458 const enum QuadOption c_print = cs_subset_quad(NeoMutt->sub, "print");
459 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
460 if (c_print && !c_print_command)
461 {
462 mutt_message(_("No printing command has been defined"));
463 return;
464 }
465
466 int msg_count = 0;
467 struct EmailNode *en = NULL;
468 STAILQ_FOREACH(en, el, entries)
469 {
470 msg_count++;
471 }
472
473 if (query_quadoption(c_print, (msg_count == 1) ? _("Print message?") :
474 _("Print tagged messages?")) != MUTT_YES)
475 {
476 return;
477 }
478
479 const bool c_print_decode = cs_subset_bool(NeoMutt->sub, "print_decode");
480 const bool c_print_split = cs_subset_bool(NeoMutt->sub, "print_split");
481 if (pipe_message(m, el, c_print_command, c_print_decode, true, c_print_split, "\f") == 0)
482 mutt_message(ngettext("Message printed", "Messages printed", msg_count));
483 else
484 {
485 mutt_message(ngettext("Message could not be printed",
486 "Messages could not be printed", msg_count));
487 }
488}
489
495bool mutt_select_sort(bool reverse)
496{
497 enum SortType sort = SORT_DATE;
498
499 switch (mutt_multi_choice(
500 reverse ?
501 /* L10N: The highlighted letters must match the "Sort" options */
502 _("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?") :
503 /* L10N: The highlighted letters must match the "Rev-Sort" options */
504 _("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?"),
505 /* L10N: These must match the highlighted letters from "Sort" and "Rev-Sort" */
506 _("dfrsotuzcpl")))
507 {
508 case -1: /* abort - don't resort */
509 return false;
510
511 case 1: /* (d)ate */
512 sort = SORT_DATE;
513 break;
514
515 case 2: /* (f)rm */
516 sort = SORT_FROM;
517 break;
518
519 case 3: /* (r)ecv */
520 sort = SORT_RECEIVED;
521 break;
522
523 case 4: /* (s)ubj */
524 sort = SORT_SUBJECT;
525 break;
526
527 case 5: /* t(o) */
528 sort = SORT_TO;
529 break;
530
531 case 6: /* (t)hread */
532 sort = SORT_THREADS;
533 break;
534
535 case 7: /* (u)nsort */
536 sort = SORT_ORDER;
537 break;
538
539 case 8: /* si(z)e */
540 sort = SORT_SIZE;
541 break;
542
543 case 9: /* s(c)ore */
544 sort = SORT_SCORE;
545 break;
546
547 case 10: /* s(p)am */
548 sort = SORT_SPAM;
549 break;
550
551 case 11: /* (l)abel */
552 sort = SORT_LABEL;
553 break;
554 }
555
556 const unsigned char c_use_threads = cs_subset_enum(NeoMutt->sub, "use_threads");
557 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
558 int rc = CSR_ERR_CODE;
559 if ((sort != SORT_THREADS) || (c_use_threads == UT_UNSET))
560 {
561 if ((sort != SORT_THREADS) && (c_sort & SORT_LAST))
562 sort |= SORT_LAST;
563 if (reverse)
564 sort |= SORT_REVERSE;
565
566 rc = cs_subset_str_native_set(NeoMutt->sub, "sort", sort, NULL);
567 }
568 else
569 {
570 assert((c_sort & SORT_MASK) != SORT_THREADS); /* See index_config_observer() */
571 /* Preserve the value of $sort, and toggle whether we are threaded. */
572 switch (c_use_threads)
573 {
574 case UT_FLAT:
575 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
576 reverse ? UT_REVERSE : UT_THREADS, NULL);
577 break;
578 case UT_THREADS:
579 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
580 reverse ? UT_REVERSE : UT_FLAT, NULL);
581 break;
582 case UT_REVERSE:
583 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
584 reverse ? UT_FLAT : UT_THREADS, NULL);
585 break;
586 default:
587 assert(false);
588 }
589 }
590
591 return ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE));
592}
593
600{
601 bool rc = false;
602 struct Buffer *buf = mutt_buffer_pool_get();
603
604 if (mutt_buffer_get_field(_("Shell command: "), buf, MUTT_COMP_FILE_SIMPLE,
605 false, NULL, NULL, NULL) != 0)
606 {
607 goto done;
608 }
609
610 if (mutt_buffer_is_empty(buf))
611 {
612 const char *const c_shell = cs_subset_string(NeoMutt->sub, "shell");
613 mutt_buffer_strcpy(buf, c_shell);
614 }
615
616 if (mutt_buffer_is_empty(buf))
617 {
618 goto done;
619 }
620
622 mutt_endwin();
623 fflush(stdout);
624 int rc2 = mutt_system(mutt_buffer_string(buf));
625 if (rc2 == -1)
626 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", mutt_buffer_string(buf));
627
628 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
629 if ((rc2 != 0) || c_wait_key)
631
632 rc = true;
633done:
635 return rc;
636}
637
642{
643 struct Buffer *buf = mutt_buffer_pool_get();
644 struct Buffer *err = mutt_buffer_pool_get();
645
646 window_redraw(NULL);
647 /* if enter is pressed after : with no command, just return */
648 if ((mutt_buffer_get_field(":", buf, MUTT_COMP_COMMAND, false, NULL, NULL, NULL) != 0) ||
650 {
651 goto done;
652 }
653
654 /* check if buf is a valid icommand, else fall back quietly to parse_rc_lines */
656 if (!mutt_buffer_is_empty(err))
657 {
658 /* since errbuf could potentially contain printf() sequences in it,
659 * we must call mutt_error() in this fashion so that vsprintf()
660 * doesn't expect more arguments that we passed */
661 if (rc == MUTT_CMD_ERROR)
662 mutt_error("%s", mutt_buffer_string(err));
663 else
665 }
666 else if (rc != MUTT_CMD_SUCCESS)
667 {
669 if (!mutt_buffer_is_empty(err))
670 {
671 if (rc == MUTT_CMD_SUCCESS) /* command succeeded with message */
673 else if (rc == MUTT_CMD_ERROR)
674 mutt_error("%s", mutt_buffer_string(err));
675 else if (rc == MUTT_CMD_WARNING)
677 }
678 }
679 /* else successful command */
680
681 if (NeoMutt)
682 {
683 // Running commands could cause anything to change, so let others know
685 }
686
687done:
690}
691
697{
698 const char *pfx = NULL;
699 char buf[128] = { 0 };
700
701 struct AddressList *al = mutt_get_address(env, &pfx);
702 if (!al)
703 return;
704
705 /* Note: We don't convert IDNA to local representation this time.
706 * That is intentional, so the user has an opportunity to copy &
707 * paste the on-the-wire form of the address to other, IDN-unable
708 * software. */
709 buf[0] = '\0';
710 mutt_addrlist_write(al, buf, sizeof(buf), false);
711 mutt_message("%s: %s", pfx, buf);
712}
713
721static void set_copy_flags(struct Email *e, enum MessageTransformOpt transform_opt,
722 CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
723{
724 *cmflags = MUTT_CM_NO_FLAGS;
725 *chflags = CH_UPDATE_LEN;
726
727 const bool need_decrypt = (transform_opt == TRANSFORM_DECRYPT) &&
728 (e->security & SEC_ENCRYPT);
729 const bool want_pgp = (WithCrypto & APPLICATION_PGP);
730 const bool want_smime = (WithCrypto & APPLICATION_SMIME);
731 const bool is_pgp = mutt_is_application_pgp(e->body) & SEC_ENCRYPT;
732 const bool is_smime = mutt_is_application_smime(e->body) & SEC_ENCRYPT;
733
734 if (need_decrypt && want_pgp && mutt_is_multipart_encrypted(e->body))
735 {
736 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
737 *cmflags = MUTT_CM_DECODE_PGP;
738 }
739 else if (need_decrypt && want_pgp && is_pgp)
740 {
741 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN;
742 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
743 }
744 else if (need_decrypt && want_smime && is_smime)
745 {
746 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
747 *cmflags = MUTT_CM_DECODE_SMIME;
748 }
749 else if (transform_opt == TRANSFORM_DECODE)
750 {
751 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN | CH_DECODE; // then decode RFC2047
752 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
753 const bool c_copy_decode_weed = cs_subset_bool(NeoMutt->sub, "copy_decode_weed");
754 if (c_copy_decode_weed)
755 {
756 *chflags |= CH_WEED; // and respect $weed
757 *cmflags |= MUTT_CM_WEED;
758 }
759 }
760}
761
772int mutt_save_message_ctx(struct Mailbox *m_src, struct Email *e, enum MessageSaveOpt save_opt,
773 enum MessageTransformOpt transform_opt, struct Mailbox *m_dst)
774{
777 int rc;
778
779 set_copy_flags(e, transform_opt, &cmflags, &chflags);
780
781 struct Message *msg = mx_msg_open(m_src, e->msgno);
782 if (msg && transform_opt != TRANSFORM_NONE)
783 {
785 }
786
787 rc = mutt_append_message(m_dst, m_src, e, msg, cmflags, chflags);
788 mx_msg_close(m_src, &msg);
789 if (rc != 0)
790 return rc;
791
792 if (save_opt == SAVE_MOVE)
793 {
794 mutt_set_flag(m_src, e, MUTT_DELETE, true);
795 mutt_set_flag(m_src, e, MUTT_PURGE, true);
796 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
797 if (c_delete_untag)
798 mutt_set_flag(m_src, e, MUTT_TAG, false);
799 }
800
801 return 0;
802}
803
813int mutt_save_message(struct Mailbox *m, struct EmailList *el,
814 enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
815{
816 if (!el || STAILQ_EMPTY(el))
817 return -1;
818
819 int rc = -1;
820 int tagged_progress_count = 0;
821 unsigned int msg_count = 0;
822 struct Mailbox *m_save = NULL;
823
824 struct Buffer *buf = mutt_buffer_pool_get();
825 struct stat st = { 0 };
826 struct EmailNode *en = NULL;
827
828 STAILQ_FOREACH(en, el, entries)
829 {
830 msg_count++;
831 }
832 en = STAILQ_FIRST(el);
833
834 const SecurityFlags security_flags = WithCrypto ? en->email->security : SEC_NO_FLAGS;
835 const bool is_passphrase_needed = security_flags & SEC_ENCRYPT;
836
837 const char *prompt = NULL;
838 const char *progress_msg = NULL;
839
840 // Set prompt and progress_msg
841 switch (save_opt)
842 {
843 case SAVE_COPY:
844 // L10N: Progress meter message when copying tagged messages
845 progress_msg = (msg_count > 1) ? _("Copying tagged messages...") : NULL;
846 switch (transform_opt)
847 {
848 case TRANSFORM_NONE:
849 prompt = (msg_count > 1) ? _("Copy tagged to mailbox") : _("Copy to mailbox");
850 break;
852 prompt = (msg_count > 1) ? _("Decrypt-copy tagged to mailbox") :
853 _("Decrypt-copy to mailbox");
854 break;
855 case TRANSFORM_DECODE:
856 prompt = (msg_count > 1) ? _("Decode-copy tagged to mailbox") :
857 _("Decode-copy to mailbox");
858 break;
859 }
860 break;
861
862 case SAVE_MOVE:
863 // L10N: Progress meter message when saving tagged messages
864 progress_msg = (msg_count > 1) ? _("Saving tagged messages...") : NULL;
865 switch (transform_opt)
866 {
867 case TRANSFORM_NONE:
868 prompt = (msg_count > 1) ? _("Save tagged to mailbox") : _("Save to mailbox");
869 break;
871 prompt = (msg_count > 1) ? _("Decrypt-save tagged to mailbox") :
872 _("Decrypt-save to mailbox");
873 break;
874 case TRANSFORM_DECODE:
875 prompt = (msg_count > 1) ? _("Decode-save tagged to mailbox") :
876 _("Decode-save to mailbox");
877 break;
878 }
879 break;
880 }
881
883 mutt_default_save(buf->data, buf->dsize, en->email);
886
887 if (mutt_buffer_enter_fname(prompt, buf, false, NULL, false, NULL, NULL,
888 MUTT_SEL_NO_FLAGS) == -1)
889 {
890 goto cleanup;
891 }
892
893 size_t pathlen = mutt_buffer_len(buf);
894 if (pathlen == 0)
895 goto cleanup;
896
897 /* Trim any trailing '/' */
898 if (buf->data[pathlen - 1] == '/')
899 buf->data[pathlen - 1] = '\0';
900
901 /* This is an undocumented feature of ELM pointed out to me by Felix von
902 * Leitner <leitner@prz.fu-berlin.de> */
905 if (mutt_str_equal(mutt_buffer_string(buf), "."))
907 else
909
911
912 /* check to make sure that this file is really the one the user wants */
913 if (mutt_save_confirm(mutt_buffer_string(buf), &st) != 0)
914 goto cleanup;
915
916 if (is_passphrase_needed && (transform_opt != TRANSFORM_NONE) &&
917 !crypt_valid_passphrase(security_flags))
918 {
919 rc = -1;
920 goto errcleanup;
921 }
922
923 mutt_message(_("Copying to %s..."), mutt_buffer_string(buf));
924
925#ifdef USE_IMAP
926 enum MailboxType mailbox_type = imap_path_probe(mutt_buffer_string(buf), NULL);
927 if ((m->type == MUTT_IMAP) && (transform_opt == TRANSFORM_NONE) && (mailbox_type == MUTT_IMAP))
928 {
929 rc = imap_copy_messages(m, el, mutt_buffer_string(buf), save_opt);
930 switch (rc)
931 {
932 /* success */
933 case 0:
935 rc = 0;
936 goto cleanup;
937 /* non-fatal error: continue to fetch/append */
938 case 1:
939 break;
940 /* fatal error, abort */
941 case -1:
942 goto errcleanup;
943 }
944 }
945#endif
946
948 m_save = mx_path_resolve(mutt_buffer_string(buf));
949 bool old_append = m_save->append;
950 OpenMailboxFlags mbox_flags = MUTT_NEWFOLDER;
951 /* Display a tagged message progress counter, rather than (for
952 * IMAP) a per-message progress counter */
953 if (msg_count > 1)
954 mbox_flags |= MUTT_QUIET;
955 if (!mx_mbox_open(m_save, mbox_flags))
956 {
957 rc = -1;
958 mailbox_free(&m_save);
959 goto errcleanup;
960 }
961 m_save->append = true;
962
963#ifdef USE_COMP_MBOX
964 /* If we're saving to a compressed mailbox, the stats won't be updated
965 * until the next open. Until then, improvise. */
966 struct Mailbox *m_comp = NULL;
967 if (m_save->compress_info)
968 {
969 m_comp = mailbox_find(m_save->realpath);
970 }
971 /* We probably haven't been opened yet */
972 if (m_comp && (m_comp->msg_count == 0))
973 m_comp = NULL;
974#endif
975 if (msg_count == 1)
976 {
977 rc = mutt_save_message_ctx(m, en->email, save_opt, transform_opt, m_save);
978 if (rc != 0)
979 {
980 mx_mbox_close(m_save);
981 m_save->append = old_append;
982 goto errcleanup;
983 }
984#ifdef USE_COMP_MBOX
985 if (m_comp)
986 {
987 m_comp->msg_count++;
988 if (!en->email->read)
989 {
990 m_comp->msg_unread++;
991 if (!en->email->old)
992 m_comp->msg_new++;
993 }
994 if (en->email->flagged)
995 m_comp->msg_flagged++;
996 }
997#endif
998 }
999 else
1000 {
1001 rc = 0;
1002
1003#ifdef USE_NOTMUCH
1004 if (m->type == MUTT_NOTMUCH)
1005 nm_db_longrun_init(m, true);
1006#endif
1007 struct Progress *progress = progress_new(progress_msg, MUTT_PROGRESS_WRITE, msg_count);
1008 STAILQ_FOREACH(en, el, entries)
1009 {
1010 progress_update(progress, ++tagged_progress_count, -1);
1012 rc = mutt_save_message_ctx(m, en->email, save_opt, transform_opt, m_save);
1013 if (rc != 0)
1014 break;
1015#ifdef USE_COMP_MBOX
1016 if (m_comp)
1017 {
1018 struct Email *e2 = en->email;
1019 m_comp->msg_count++;
1020 if (!e2->read)
1021 {
1022 m_comp->msg_unread++;
1023 if (!e2->old)
1024 m_comp->msg_new++;
1025 }
1026 if (e2->flagged)
1027 m_comp->msg_flagged++;
1028 }
1029#endif
1030 }
1031 progress_free(&progress);
1032
1033#ifdef USE_NOTMUCH
1034 if (m->type == MUTT_NOTMUCH)
1036#endif
1037 if (rc != 0)
1038 {
1039 mx_mbox_close(m_save);
1040 m_save->append = old_append;
1041 goto errcleanup;
1042 }
1043 }
1044
1045 const bool need_mailbox_cleanup = ((m_save->type == MUTT_MBOX) ||
1046 (m_save->type == MUTT_MMDF));
1047
1048 mx_mbox_close(m_save);
1049 m_save->append = old_append;
1050
1051 if (need_mailbox_cleanup)
1053
1055 rc = 0;
1056
1057errcleanup:
1058 if (rc != 0)
1059 {
1060 switch (save_opt)
1061 {
1062 case SAVE_MOVE:
1063 if (msg_count > 1)
1064 {
1065 // L10N: Message when an index tagged save operation fails for some reason
1066 mutt_error(_("Error saving tagged messages"));
1067 }
1068 else
1069 {
1070 // L10N: Message when an index/pager save operation fails for some reason
1071 mutt_error(_("Error saving message"));
1072 }
1073 break;
1074 case SAVE_COPY:
1075 if (msg_count > 1)
1076 {
1077 // L10N: Message when an index tagged copy operation fails for some reason
1078 mutt_error(_("Error copying tagged messages"));
1079 }
1080 else
1081 {
1082 // L10N: Message when an index/pager copy operation fails for some reason
1083 mutt_error(_("Error copying message"));
1084 }
1085 break;
1086 }
1087 }
1088
1089 mailbox_free(&m_save);
1090
1091cleanup:
1093 return rc;
1094}
1095
1105bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
1106{
1107 struct Buffer *buf = mutt_buffer_pool_get();
1108 struct Buffer *charset = mutt_buffer_pool_get();
1109 struct Buffer *obuf = mutt_buffer_pool_get();
1110 struct Buffer *tmp = mutt_buffer_pool_get();
1111
1112 bool rc = false;
1113 bool charset_changed = false;
1114 bool type_changed = false;
1115 bool structure_changed = false;
1116
1117 char *cp = mutt_param_get(&b->parameter, "charset");
1118 mutt_buffer_strcpy(charset, cp);
1119
1120 mutt_buffer_printf(buf, "%s/%s", TYPE(b), b->subtype);
1121 mutt_buffer_copy(obuf, buf);
1122 if (!TAILQ_EMPTY(&b->parameter))
1123 {
1124 struct Parameter *np = NULL;
1125 TAILQ_FOREACH(np, &b->parameter, entries)
1126 {
1127 mutt_addr_cat(tmp->data, tmp->dsize, np->value, MimeSpecials);
1128 mutt_buffer_add_printf(buf, "; %s=%s", np->attribute, mutt_buffer_string(tmp));
1129 }
1130 }
1131
1132 if ((mutt_buffer_get_field("Content-Type: ", buf, MUTT_COMP_NO_FLAGS, false,
1133 NULL, NULL, NULL) != 0) ||
1135 {
1136 goto done;
1137 }
1138
1139 /* clean up previous junk */
1141 FREE(&b->subtype);
1142
1144
1145 mutt_buffer_printf(tmp, "%s/%s", TYPE(b), NONULL(b->subtype));
1146 type_changed = !mutt_istr_equal(mutt_buffer_string(tmp), mutt_buffer_string(obuf));
1147 charset_changed = !mutt_istr_equal(mutt_buffer_string(charset),
1148 mutt_param_get(&b->parameter, "charset"));
1149
1150 /* if in send mode, check for conversion - current setting is default. */
1151
1152 if (!e && (b->type == TYPE_TEXT) && charset_changed)
1153 {
1154 mutt_buffer_printf(tmp, _("Convert to %s upon sending?"),
1155 mutt_param_get(&b->parameter, "charset"));
1157 if (ans != MUTT_ABORT)
1158 b->noconv = (ans == MUTT_NO);
1159 }
1160
1161 /* inform the user */
1162
1163 mutt_buffer_printf(tmp, "%s/%s", TYPE(b), NONULL(b->subtype));
1164 if (type_changed)
1165 mutt_message(_("Content-Type changed to %s"), mutt_buffer_string(tmp));
1166 if ((b->type == TYPE_TEXT) && charset_changed)
1167 {
1168 if (type_changed)
1169 mutt_sleep(1);
1170 mutt_message(b->noconv ? _("Character set changed to %s; not converting") :
1171 _("Character set changed to %s; converting"),
1172 mutt_param_get(&b->parameter, "charset"));
1173 }
1174
1175 b->force_charset |= charset_changed;
1176
1177 if (!is_multipart(b) && b->parts)
1178 {
1179 structure_changed = true;
1180 mutt_body_free(&b->parts);
1181 }
1182 if (!mutt_is_message_type(b->type, b->subtype) && b->email)
1183 {
1184 structure_changed = true;
1185 b->email->body = NULL;
1186 email_free(&b->email);
1187 }
1188
1189 if (fp && !b->parts && (is_multipart(b) || mutt_is_message_type(b->type, b->subtype)))
1190 {
1191 structure_changed = true;
1192 mutt_parse_part(fp, b);
1193 }
1194
1195 if ((WithCrypto != 0) && e)
1196 {
1197 if (e->body == b)
1199
1200 e->security |= crypt_query(b);
1201 }
1202
1203 rc = structure_changed | type_changed;
1204
1205done:
1207 mutt_buffer_pool_release(&charset);
1210 return rc;
1211}
1212
1219static bool check_traditional_pgp(struct Mailbox *m, struct Email *e)
1220{
1221 bool rc = false;
1222
1224
1225 struct Message *msg = mx_msg_open(m, e->msgno);
1226 if (msg)
1227 {
1228 mutt_parse_mime_message(e, msg->fp);
1229 if (crypt_pgp_check_traditional(msg->fp, e->body, false))
1230 {
1231 e->security = crypt_query(e->body);
1232 rc = true;
1233 }
1234
1236 mx_msg_close(m, &msg);
1237 }
1238 return rc;
1239}
1240
1247bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailList *el)
1248{
1249 bool rc = false;
1250 struct EmailNode *en = NULL;
1251 STAILQ_FOREACH(en, el, entries)
1252 {
1254 rc = check_traditional_pgp(m, en->email) || rc;
1255 }
1256
1257 return rc;
1258}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition: address.c:681
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:616
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:330
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:591
Select a Mailbox from a list.
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:55
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:275
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:189
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:211
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:462
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
CommandResult
Error codes for command_t parse functions.
Definition: command.h:34
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:37
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:35
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition: command.h:36
bool mutt_select_sort(bool reverse)
Ask the user for a sort method.
Definition: commands.c:495
void mutt_print_message(struct Mailbox *m, struct EmailList *el)
Print a message.
Definition: commands.c:453
void mutt_commands_cleanup(void)
Clean up commands globals.
Definition: commands.c:81
int mutt_save_message(struct Mailbox *m, struct EmailList *el, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
Save an email.
Definition: commands.c:813
void ci_bounce_message(struct Mailbox *m, struct EmailList *el)
Bounce an email.
Definition: commands.c:91
static bool check_traditional_pgp(struct Mailbox *m, struct Email *e)
Check for an inline PGP content.
Definition: commands.c:1219
static void pipe_set_flags(bool decode, bool print, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
Generate flags for copy header/message.
Definition: commands.c:206
void mutt_enter_command(void)
Enter a neomutt command.
Definition: commands.c:641
int mutt_save_message_ctx(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: commands.c:772
static struct Buffer LastSaveFolder
The folder the user last saved to.
Definition: commands.c:76
bool mutt_shell_escape(void)
Invoke a command in a subshell.
Definition: commands.c:599
static void set_copy_flags(struct Email *e, enum MessageTransformOpt transform_opt, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
Set the flags for a message copy.
Definition: commands.c:721
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1105
bool mutt_check_traditional_pgp(struct Mailbox *m, struct EmailList *el)
Check if a message has inline PGP content.
Definition: commands.c:1247
void mutt_pipe_message(struct Mailbox *m, struct EmailList *el)
Pipe a message.
Definition: commands.c:422
#define EXTRA_SPACE
static void pipe_msg(struct Mailbox *m, struct Email *e, struct Message *msg, FILE *fp, bool decode, bool print)
Pipe a message.
Definition: commands.c:242
static int pipe_message(struct Mailbox *m, struct EmailList *el, const char *cmd, bool decode, bool print, bool split, const char *sep)
Pipe message to a command.
Definition: commands.c:294
void mutt_display_address(struct Envelope *env)
Display the address of a message.
Definition: commands.c:696
Manage where the email is piped to external commands.
MessageTransformOpt
Message transformation option.
Definition: commands.h:39
@ TRANSFORM_NONE
No transformation.
Definition: commands.h:40
@ TRANSFORM_DECODE
Decode message.
Definition: commands.h:42
@ TRANSFORM_DECRYPT
Decrypt message.
Definition: commands.h:41
MessageSaveOpt
Message save option.
Definition: commands.h:49
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: commands.h:51
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition: commands.h:50
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:97
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
Convenience wrapper for the config headers.
int mutt_append_message(struct Mailbox *m_dst, struct Mailbox *m_src, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Append a message.
Definition: copy.c:939
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:864
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 CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:55
#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
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
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 MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:43
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#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_NO_FLAGS
No flags are set.
Definition: copy.h:51
Convenience wrapper for the core headers.
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:544
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:601
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:439
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition: crypt.c:675
bool crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional()
Definition: cryptglue.c:283
int mutt_buffer_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:445
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:639
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:387
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:354
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:907
@ JUSTIFY_LEFT
Left justify the text.
Definition: curs_lib.h:42
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
Structs that make up an email.
Enter a string.
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
void mutt_file_resolve_symlink(struct Buffer *buf)
Resolve a symlink in place.
Definition: file.c:1691
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define mutt_warning(...)
Definition: logging.h:85
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2400
Convenience wrapper for the gui headers.
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:737
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:658
Parse and execute user-defined hooks.
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:45
enum CommandResult mutt_parse_icommand(const char *line, struct Buffer *err)
Parse an informational command.
Definition: icommands.c:91
Information commands.
IMAP network mailbox.
int imap_copy_messages(struct Mailbox *m, struct EmailList *el, const char *dest, enum MessageSaveOpt save_opt)
Server COPY messages to another folder.
Definition: message.c:1683
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:894
Config/command parsing.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:139
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
#define FREE(x)
Definition: memory.h:43
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
size_t msgwin_get_width(void)
Get the width of the Message Window.
Definition: msgwin.c:269
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:249
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:171
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
Many unsorted constants and some structs.
#define MUTT_COMP_ALIAS
Alias completion (in alias dialog)
Definition: mutt.h:53
#define MUTT_COMP_COMMAND
Complete a NeoMutt command.
Definition: mutt.h:54
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:97
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:100
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:95
#define PATH_MAX
Definition: mutt.h:40
#define MUTT_COMP_FILE_SIMPLE
File completion (no browser)
Definition: mutt.h:57
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:424
Mailbox helper functions.
Create/manipulate threading in emails.
@ UT_FLAT
Unthreaded.
Definition: mutt_thread.h:85
@ UT_UNSET
Not yet set by user, stick to legacy semantics.
Definition: mutt_thread.h:84
@ UT_THREADS
Normal threading (root above subthreads)
Definition: mutt_thread.h:86
@ UT_REVERSE
Reverse threading (subthreads above root)
Definition: mutt_thread.h:87
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:604
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:599
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1455
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1356
Some miscellaneous functions.
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1147
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
API for mailboxes.
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:60
#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:66
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:65
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:55
@ 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:368
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:353
Notmuch virtual mailbox type.
Handling of global boolean variables.
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: options.h:44
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1737
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:424
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1442
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
Progress bar.
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:50
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
Prototypes for many functions.
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:63
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
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 mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define STAILQ_FIRST(head)
Definition: queue.h:350
#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
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
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:894
#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
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:78
#define SORT_LAST
Sort thread by last-X, e.g. received date.
Definition: sort2.h:80
SortType
Methods for sorting.
Definition: sort2.h:42
@ SORT_SUBJECT
Sort by the email's subject.
Definition: sort2.h:46
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:48
@ SORT_THREADS
Sort by email threads.
Definition: sort2.h:49
@ SORT_SPAM
Sort by the email's spam score.
Definition: sort2.h:57
@ SORT_LABEL
Sort by the emails label.
Definition: sort2.h:62
@ SORT_FROM
Sort by the email's From field.
Definition: sort2.h:47
@ SORT_SIZE
Sort by the size of the email.
Definition: sort2.h:44
@ SORT_RECEIVED
Sort by when the message were delivered locally.
Definition: sort2.h:50
@ SORT_TO
Sort by the email's To field.
Definition: sort2.h:51
@ SORT_DATE
Sort by the date the email was sent.
Definition: sort2.h:43
@ SORT_SCORE
Sort by the email's score.
Definition: sort2.h:52
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:79
#define NONULL(x)
Definition: string2.h:37
#define S_BKG
Definition: string2.h:42
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool noconv
Don't do character set conversion.
Definition: body.h:46
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
struct Email * email
header information for message/rfc822
Definition: body.h:73
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:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
List of Emails.
Definition: email.h:131
struct Email * email
Email in the list.
Definition: email.h:132
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
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
bool flagged
Marked important?
Definition: email.h:45
int msgno
Number displayed to the user.
Definition: email.h:111
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:120
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
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:305