NeoMutt  2024-11-14-138-ge5ca67
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
128#define GNULIB_defined_setlocale
129
130#include "config.h"
131#include <errno.h>
132#include <limits.h>
133#include <locale.h>
134#include <pwd.h>
135#include <stdbool.h>
136#include <stdint.h>
137#include <stdio.h>
138#include <stdlib.h>
139#include <string.h>
140#include <sys/stat.h>
141#include <time.h>
142#include <unistd.h>
143#include "mutt/lib.h"
144#include "address/lib.h"
145#include "config/lib.h"
146#include "email/lib.h"
147#include "core/lib.h"
148#include "alias/lib.h"
149#include "conn/lib.h"
150#include "gui/lib.h"
151#include "mutt.h"
152#include "attach/lib.h"
153#include "browser/lib.h"
154#include "color/lib.h"
155#include "history/lib.h"
156#include "imap/lib.h"
157#include "index/lib.h"
158#include "key/lib.h"
159#include "menu/lib.h"
160#include "ncrypt/lib.h"
161#include "nntp/lib.h"
162#include "pop/lib.h"
163#include "postpone/lib.h"
164#include "question/lib.h"
165#include "send/lib.h"
166#include "alternates.h"
167#include "external.h"
168#include "globals.h"
169#include "hook.h"
170#include "init.h"
171#include "mutt_logging.h"
172#include "mutt_mailbox.h"
173#include "muttlib.h"
174#include "mx.h"
175#include "nntp/adata.h" // IWYU pragma: keep
176#include "protos.h"
177#include "subjectrx.h"
178#include "version.h"
179#ifdef ENABLE_NLS
180#include <libintl.h>
181#endif
182#ifdef USE_AUTOCRYPT
183#include "autocrypt/lib.h"
184#endif
185#if defined(USE_DEBUG_NOTIFY) || defined(USE_DEBUG_BACKTRACE)
186#include "debug/lib.h"
187#endif
188
189bool StartupComplete = false;
190
191// clang-format off
192typedef uint8_t CliFlags;
193#define MUTT_CLI_NO_FLAGS 0
194#define MUTT_CLI_IGNORE (1 << 0)
195#define MUTT_CLI_MAILBOX (1 << 1)
196#define MUTT_CLI_NOSYSRC (1 << 2)
197#define MUTT_CLI_RO (1 << 3)
198#define MUTT_CLI_SELECT (1 << 4)
199#define MUTT_CLI_NEWS (1 << 5)
200// clang-format on
201
206static void reset_tilde(struct ConfigSet *cs)
207{
208 static const char *names[] = { "folder", "mbox", "postponed", "record" };
209
210 struct Buffer *value = buf_pool_get();
211 for (size_t i = 0; i < mutt_array_size(names); i++)
212 {
213 struct HashElem *he = cs_get_elem(cs, names[i]);
214 if (!he)
215 continue;
216 buf_reset(value);
217 cs_he_initial_get(cs, he, value);
218 buf_expand_path_regex(value, false);
219 cs_he_initial_set(cs, he, value->data, NULL);
220 cs_he_reset(cs, he, NULL);
221 }
222 buf_pool_release(&value);
223}
224
225#ifdef ENABLE_NLS
230static void localise_config(struct ConfigSet *cs)
231{
232 static const char *names[] = {
233 "attribution_intro",
234 "compose_format",
235 "forward_attribution_intro",
236 "forward_attribution_trailer",
237 "reply_regex",
238 "status_format",
239 "ts_icon_format",
240 "ts_status_format",
241 };
242
243 struct Buffer *value = buf_pool_get();
244 for (size_t i = 0; i < mutt_array_size(names); i++)
245 {
246 struct HashElem *he = cs_get_elem(cs, names[i]);
247 if (!he)
248 continue;
249 buf_reset(value);
250 cs_he_initial_get(cs, he, value);
251
252 // Lookup the translation
253 const char *l10n = gettext(buf_string(value));
254
255 cs_he_initial_set(cs, he, l10n, NULL);
256 cs_he_reset(cs, he, NULL);
257 }
258 buf_pool_release(&value);
259}
260#endif
261
266void mutt_exit(int code)
267{
268 mutt_endwin();
269#ifdef USE_DEBUG_BACKTRACE
270 if (code != 0)
272#endif
273 exit(code);
274}
275
280static bool usage(void)
281{
282 puts(mutt_make_version());
283
284 // clang-format off
285 /* L10N: Try to limit to 80 columns */
286 puts(_("usage:"));
287 puts(_(" neomutt [-CEn] [-e <command>] [-F <config>] [-H <draft>] [-i <include>]\n"
288 " [-b <address>] [-c <address>] [-s <subject>] [-a <file> [...] --]\n"
289 " <address> [...]"));
290 puts(_(" neomutt [-Cn] [-e <command>] [-F <config>] [-b <address>] [-c <address>]\n"
291 " [-s <subject>] [-a <file> [...] --] <address> [...] < message"));
292 puts(_(" neomutt [-nRy] [-e <command>] [-F <config>] [-f <mailbox>] [-m <type>]"));
293 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -A <alias>"));
294 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -B"));
295 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -D [-S] [-O]"));
296 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -d <level> -l <file>"));
297 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -G"));
298 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -g <server>"));
299 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -p"));
300 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -Q <variable> [-O]"));
301 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -Z"));
302 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -z [-f <mailbox>]"));
303 puts(_(" neomutt -v[v]\n"));
304
305 /* L10N: Try to limit to 80 columns. If more space is needed add an indented line */
306 puts(_("options:"));
307 puts(_(" -- Special argument forces NeoMutt to stop option parsing and treat\n"
308 " remaining arguments as addresses even if they start with a dash"));
309 puts(_(" -A <alias> Print an expanded version of the given alias to stdout and exit"));
310 puts(_(" -a <file> Attach one or more files to a message (must be the last option)\n"
311 " Add any addresses after the '--' argument"));
312 puts(_(" -B Run in batch mode (do not start the ncurses UI)"));
313 puts(_(" -b <address> Specify a blind carbon copy (Bcc) recipient"));
314 puts(_(" -c <address> Specify a carbon copy (Cc) recipient"));
315 puts(_(" -C Enable Command-line Crypto (signing/encryption)"));
316 puts(_(" -D Dump all config variables as 'name=value' pairs to stdout"));
317 puts(_(" -D -O Like -D, but show one-liner documentation"));
318 puts(_(" -D -S Like -D, but hide the value of sensitive variables"));
319 puts(_(" -d <level> Log debugging output to a file (default is \"~/.neomuttdebug0\")\n"
320 " The level can range from 1-5 and affects verbosity"));
321 puts(_(" -E Edit draft (-H) or include (-i) file during message composition"));
322 puts(_(" -e <command> Specify a command to be run after reading the config files"));
323 puts(_(" -F <config> Specify an alternative initialization file to read"));
324 puts(_(" -f <mailbox> Specify a mailbox (as defined with 'mailboxes' command) to load"));
325 puts(_(" -G Start NeoMutt with a listing of subscribed newsgroups"));
326 puts(_(" -g <server> Like -G, but start at specified news server"));
327 puts(_(" -H <draft> Specify a draft file with header and body for message composing"));
328 puts(_(" -h Print this help message and exit"));
329 puts(_(" -i <include> Specify an include file to be embedded in the body of a message"));
330 puts(_(" -l <file> Specify a file for debugging output (default \"~/.neomuttdebug0\")"));
331 puts(_(" -m <type> Specify a default mailbox format type for newly created folders\n"
332 " The type is either MH, MMDF, Maildir or mbox (case-insensitive)"));
333 puts(_(" -n Do not read the system-wide configuration file"));
334 puts(_(" -p Resume a prior postponed message, if any"));
335 puts(_(" -Q <variable> Query a configuration variable and print its value to stdout\n"
336 " (after the config has been read and any commands executed)\n"
337 " Add -O for one-liner documentation"));
338 puts(_(" -R Open mailbox in read-only mode"));
339 puts(_(" -s <subject> Specify a subject (must be enclosed in quotes if it has spaces)"));
340 puts(_(" -v Print the NeoMutt version and compile-time definitions and exit"));
341 puts(_(" -vv Print the NeoMutt license and copyright information and exit"));
342 puts(_(" -y Start NeoMutt with a listing of all defined mailboxes"));
343 puts(_(" -Z Open the first mailbox with new message or exit immediately with\n"
344 " exit code 1 if none is found in all defined mailboxes"));
345 puts(_(" -z Open the first or specified (-f) mailbox if it holds any message\n"
346 " or exit immediately with exit code 1 otherwise"));
347 // clang-format on
348
349 fflush(stdout);
350 return !ferror(stdout);
351}
352
358static int start_curses(void)
359{
360 km_init(); /* must come before mutt_init */
361
362 /* should come before initscr() so that ncurses 4.2 doesn't try to install
363 * its own SIGWINCH handler */
365
366 if (!initscr())
367 {
368 mutt_error(_("Error initializing terminal"));
369 return 1;
370 }
371
373 keypad(stdscr, true);
374 cbreak();
375 noecho();
376 nonl();
377 typeahead(-1); /* simulate smooth scrolling */
378 meta(stdscr, true);
380 /* Now that curses is set up, we drop back to normal screen mode.
381 * This simplifies displaying error messages to the user.
382 * The first call to refresh() will swap us back to curses screen mode. */
383 endwin();
384 return 0;
385}
386
390static void init_locale(void)
391{
392 setlocale(LC_ALL, "");
393
394#ifdef ENABLE_NLS
395 const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
396 if (domdir)
397 bindtextdomain(PACKAGE, domdir);
398 else
399 bindtextdomain(PACKAGE, MUTTLOCALEDIR);
400 textdomain(PACKAGE);
401#endif
402#ifndef LOCALES_HACK
403 /* Do we have a locale definition? */
404 if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
405 {
406 OptLocales = true;
407 }
408#endif
409}
410
418static bool get_user_info(struct ConfigSet *cs)
419{
420 const char *shell = mutt_str_getenv("SHELL");
421 if (shell)
422 cs_str_initial_set(cs, "shell", shell, NULL);
423
424 /* Get some information about the user */
425 struct passwd *pw = getpwuid(getuid());
426 if (pw)
427 {
428 if (!Username)
429 Username = mutt_str_dup(pw->pw_name);
430 if (!HomeDir)
431 HomeDir = mutt_str_dup(pw->pw_dir);
432 if (!shell)
433 cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
434 }
435
436 if (!Username)
437 {
438 mutt_error(_("unable to determine username"));
439 return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
440 }
441
442 if (!HomeDir)
443 {
444 mutt_error(_("unable to determine home directory"));
445 return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
446 }
447
448 cs_str_reset(cs, "shell", NULL);
449 return true;
450}
451
459static void log_translation(void)
460{
461 const char *header = ""; // Do not merge these two lines
462 header = _(header); // otherwise the .po files will end up badly ordered
463 const char *label = "Language:"; // the start of the lookup/needle
464 const char *lang = mutt_istr_find(header, label);
465 int len = 64;
466 if (lang)
467 {
468 lang += strlen(label); // skip label
469 SKIPWS(lang);
470 char *nl = strchr(lang, '\n');
471 if (nl)
472 len = (nl - lang);
473 }
474 else
475 {
476 lang = "NONE";
477 }
478
479 mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
480}
481
485static void log_gui(void)
486{
487 const char *term = mutt_str_getenv("TERM");
488 const char *color_term = mutt_str_getenv("COLORTERM");
489 bool true_color = false;
490#ifdef NEOMUTT_DIRECT_COLORS
491 true_color = true;
492#endif
493
494 mutt_debug(LL_DEBUG1, "GUI:\n");
495 mutt_debug(LL_DEBUG1, " Curses: %s\n", curses_version());
496 mutt_debug(LL_DEBUG1, " COLORS=%d\n", COLORS);
497 mutt_debug(LL_DEBUG1, " COLOR_PAIRS=%d\n", COLOR_PAIRS);
498 mutt_debug(LL_DEBUG1, " TERM=%s\n", NONULL(term));
499 mutt_debug(LL_DEBUG1, " COLORTERM=%s\n", NONULL(color_term));
500 mutt_debug(LL_DEBUG1, " True color support: %s\n", true_color ? "YES" : "NO");
501 mutt_debug(LL_DEBUG1, " Screen: %dx%d\n", RootWindow->state.cols,
503}
504
509{
510 static time_t last_run = 0;
511
512 if (nc->event_type != NT_TIMEOUT)
513 return 0;
514
515 const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
516 if (c_timeout <= 0)
517 goto done;
518
519 time_t now = mutt_date_now();
520 if (now < (last_run + c_timeout))
521 goto done;
522
523 // Limit hook to running under the Index or Pager
525 struct MuttWindow *dlg = dialog_find(focus);
526 if (!dlg || (dlg->type != WT_DLG_INDEX))
527 goto done;
528
529 last_run = now;
531
532done:
533 mutt_debug(LL_DEBUG5, "timeout done\n");
534 return 0;
535}
536
545int
546#ifdef ENABLE_FUZZ_TESTS
547disabled_main
548#else
550#endif
551(int argc, char *argv[], char *envp[])
552{
553 char *subject = NULL;
554 char *include_file = NULL;
555 char *draft_file = NULL;
556 char *new_type = NULL;
557 char *dlevel = NULL;
558 char *dfile = NULL;
559 const char *cli_nntp = NULL;
560 struct Email *e = NULL;
561 struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
562 struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
563 struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
564 struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
565 struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
566 struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
567 SendFlags sendflags = SEND_NO_FLAGS;
569 int version = 0;
570 int i;
571 bool explicit_folder = false;
572 bool dump_variables = false;
573 bool one_liner = false;
574 bool hide_sensitive = false;
575 bool batch_mode = false;
576 bool edit_infile = false;
577 int double_dash = argc, nargc = 1;
578 int rc = 1;
579 bool repeat_error = false;
580 struct Buffer *folder = buf_pool_get();
581 struct Buffer *expanded_infile = buf_pool_get();
582 struct Buffer *tempfile = buf_pool_get();
583 struct ConfigSet *cs = NULL;
584
586
587 /* sanity check against stupid administrators */
588 if (getegid() != getgid())
589 {
590 mutt_error("%s: I don't want to run with privileges!", (argc != 0) ? argv[0] : "neomutt");
591 goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
592 }
593
594 init_locale();
595
596 EnvList = envlist_init(envp);
597 for (optind = 1; optind < double_dash;)
598 {
599 /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
600 * encounters a non-option. That could be a file to attach
601 * (all non-options between -a and --) or it could be an address
602 * (which gets collapsed to the front of argv). */
603 for (; optind < argc; optind++)
604 {
605 if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
606 {
607 if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
608 double_dash = optind; /* quit outer loop after getopt */
609 break; /* drop through to getopt */
610 }
611
612 /* non-option, either an attachment or address */
613 if (!STAILQ_EMPTY(&attach))
614 mutt_list_insert_tail(&attach, mutt_str_dup(argv[optind]));
615 else
616 argv[nargc++] = argv[optind];
617 }
618
619 i = getopt(argc, argv, "+A:a:Bb:F:f:Cc:Dd:l:Ee:g:GH:i:hm:nOpQ:RSs:TvyzZ");
620 if (i != EOF)
621 {
622 switch (i)
623 {
624 case 'A':
625 mutt_list_insert_tail(&alias_queries, mutt_str_dup(optarg));
626 break;
627 case 'a':
628 mutt_list_insert_tail(&attach, mutt_str_dup(optarg));
629 break;
630 case 'B':
631 batch_mode = true;
632 break;
633 case 'b':
634 mutt_list_insert_tail(&bcc_list, mutt_str_dup(optarg));
635 break;
636 case 'C':
637 sendflags |= SEND_CLI_CRYPTO;
638 break;
639 case 'c':
640 mutt_list_insert_tail(&cc_list, mutt_str_dup(optarg));
641 break;
642 case 'D':
643 dump_variables = true;
644 break;
645 case 'd':
646 dlevel = optarg;
647 break;
648 case 'E':
649 edit_infile = true;
650 break;
651 case 'e':
652 mutt_list_insert_tail(&commands, mutt_str_dup(optarg));
653 break;
654 case 'F':
656 break;
657 case 'f':
658 buf_strcpy(folder, optarg);
659 explicit_folder = true;
660 break;
661 case 'g': /* Specify a news server */
662 cli_nntp = optarg;
664
665 case 'G': /* List of newsgroups */
667 break;
668 case 'H':
669 draft_file = optarg;
670 break;
671 case 'i':
672 include_file = optarg;
673 break;
674 case 'l':
675 dfile = optarg;
676 break;
677 case 'm':
678 new_type = optarg;
679 break;
680 case 'n':
681 flags |= MUTT_CLI_NOSYSRC;
682 break;
683 case 'O':
684 one_liner = true;
685 break;
686 case 'p':
687 sendflags |= SEND_POSTPONED;
688 break;
689 case 'Q':
690 mutt_list_insert_tail(&queries, mutt_str_dup(optarg));
691 break;
692 case 'R':
693 flags |= MUTT_CLI_RO; /* read-only mode */
694 break;
695 case 'S':
696 hide_sensitive = true;
697 break;
698 case 's':
699 subject = optarg;
700 break;
701 case 'v':
702 version++;
703 break;
704 case 'y': /* My special hack mode */
705 flags |= MUTT_CLI_SELECT;
706 break;
707 case 'Z':
709 break;
710 case 'z':
711 flags |= MUTT_CLI_IGNORE;
712 break;
713 default:
714 OptNoCurses = true;
715 if (usage())
716 goto main_ok; // TEST03: neomutt -9
717 else
718 goto main_curses;
719 }
720 }
721 }
722
723 /* collapse remaining argv */
724 while (optind < argc)
725 argv[nargc++] = argv[optind++];
726 optind = 1;
727 argc = nargc;
728
729 if (version > 0)
730 {
732 bool done;
733 if (version == 1)
734 done = print_version(stdout);
735 else
736 done = print_copyright();
737 OptNoCurses = true;
738 if (done)
739 goto main_ok; // TEST04: neomutt -v
740 else
741 goto main_curses;
742 }
743
746
747 cs = cs_new(500);
748 if (!cs)
749 goto main_curses;
750
751 NeoMutt = neomutt_new(cs);
752 init_config(cs);
753
754 // Change the current umask, and save the original one
755 NeoMutt->user_default_umask = umask(077);
756 subjrx_init();
757 attach_init();
759
760#ifdef USE_DEBUG_NOTIFY
762#endif
763
764 if (!get_user_info(cs))
765 goto main_exit;
766
767 reset_tilde(cs);
768#ifdef ENABLE_NLS
769 localise_config(cs);
770#endif
771
772 if (dfile)
773 {
774 cs_str_initial_set(cs, "debug_file", dfile, NULL);
775 cs_str_reset(cs, "debug_file", NULL);
776 }
777
778 if (dlevel)
779 {
780 short num = 0;
781 if (!mutt_str_atos_full(dlevel, &num) || (num < LL_MESSAGE) || (num >= LL_MAX))
782 {
783 mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
784 goto main_exit; // TEST07: neomutt -d xyz
785 }
786 cs_str_initial_set(cs, "debug_level", dlevel, NULL);
787 cs_str_reset(cs, "debug_level", NULL);
788 }
789
793 mutt_debug(LL_DEBUG1, "user's umask %03o\n", NeoMutt->user_default_umask);
794 mutt_debug(LL_DEBUG3, "umask set to 077\n");
795
796 if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
797 {
798 e = email_new();
799 e->env = mutt_env_new();
800
801 struct ListNode *np = NULL;
802 STAILQ_FOREACH(np, &bcc_list, entries)
803 {
804 mutt_addrlist_parse(&e->env->bcc, np->data);
805 }
806
807 STAILQ_FOREACH(np, &cc_list, entries)
808 {
809 mutt_addrlist_parse(&e->env->cc, np->data);
810 }
811
812 mutt_list_free(&bcc_list);
813 mutt_list_free(&cc_list);
814 }
815
816 /* Check for a batch send. */
817 if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
818 dump_variables || batch_mode)
819 {
820 OptNoCurses = true;
821 sendflags |= SEND_BATCH;
824 }
825
826 /* Check to make sure stdout is available in curses mode. */
827 if (!OptNoCurses && !isatty(1))
828 goto main_curses;
829
830 /* This must come before mutt_init() because curses needs to be started
831 * before calling the init_pair() function to set the color scheme. */
832 if (!OptNoCurses)
833 {
834 int crc = start_curses();
835 if (crc != 0)
836 goto main_curses; // TEST08: can't test -- fake term?
837 }
838
839 /* Always create the mutt_windows because batch mode has some shared code
840 * paths that end up referencing them. */
841 rootwin_new();
842
843 if (!OptNoCurses)
844 {
845 /* check whether terminal status is supported (must follow curses init) */
848 log_gui();
849 }
850
851 /* set defaults and read init files */
852 int rc2 = mutt_init(cs, dlevel, dfile, flags & MUTT_CLI_NOSYSRC, &commands);
853 if (rc2 != 0)
854 goto main_curses;
855
857
858 /* "$news_server" precedence: command line, config file, environment, system file */
859 if (!cli_nntp)
860 cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
861
862 if (!cli_nntp)
863 cli_nntp = mutt_str_getenv("NNTPSERVER");
864
865 if (!cli_nntp)
866 {
867 char buf[1024] = { 0 };
868 cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
869 }
870
871 if (cli_nntp)
872 {
873 cs_str_initial_set(cs, "news_server", cli_nntp, NULL);
874 cs_str_reset(cs, "news_server", NULL);
875 }
876
877 /* Initialize crypto backends. */
878 crypt_init();
879
880 if (new_type)
881 {
882 struct Buffer *err = buf_pool_get();
883 int r = cs_str_initial_set(cs, "mbox_type", new_type, err);
884 if (CSR_RESULT(r) != CSR_SUCCESS)
885 {
886 mutt_error("%s", buf_string(err));
887 buf_pool_release(&err);
888 goto main_curses;
889 }
890 cs_str_reset(cs, "mbox_type", NULL);
891 }
892
893 if (!STAILQ_EMPTY(&queries))
894 {
895 rc = mutt_query_variables(&queries, one_liner);
896 goto main_curses;
897 }
898
899 if (dump_variables)
900 {
902 if (hide_sensitive)
903 cdflags |= CS_DUMP_HIDE_SENSITIVE;
904 if (one_liner)
905 cdflags |= CS_DUMP_SHOW_DOCS;
906 dump_config(cs, cdflags, stdout);
907 goto main_ok; // TEST18: neomutt -D
908 }
909
910 if (!STAILQ_EMPTY(&alias_queries))
911 {
912 rc = 0;
913 for (; optind < argc; optind++)
914 mutt_list_insert_tail(&alias_queries, mutt_str_dup(argv[optind]));
915 struct ListNode *np = NULL;
916 STAILQ_FOREACH(np, &alias_queries, entries)
917 {
918 struct AddressList *al = alias_lookup(np->data);
919 if (al)
920 {
921 /* output in machine-readable form */
922 mutt_addrlist_to_intl(al, NULL);
923 struct Buffer *buf = buf_pool_get();
924 mutt_addrlist_write(al, buf, false);
925 printf("%s\n", buf_string(buf));
926 buf_pool_release(&buf);
927 }
928 else
929 {
930 rc = 1;
931 printf("%s\n", NONULL(np->data)); // TEST19: neomutt -A unknown
932 }
933 }
934 mutt_list_free(&alias_queries);
935 goto main_curses; // TEST20: neomutt -A alias
936 }
937
938 if (!OptNoCurses)
939 {
941 clear();
945 }
946
947#ifdef USE_AUTOCRYPT
948 /* Initialize autocrypt after curses messages are working,
949 * because of the initial account setup screens. */
950 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
951 if (c_autocrypt)
952 mutt_autocrypt_init(!(sendflags & SEND_BATCH));
953#endif
954
955 /* Create the `$folder` directory if it doesn't exist. */
956 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
957 if (!OptNoCurses && c_folder)
958 {
959 struct stat st = { 0 };
960 struct Buffer *fpath = buf_pool_get();
961
962 buf_strcpy(fpath, c_folder);
963 buf_expand_path(fpath);
964 bool skip = false;
965 /* we're not connected yet - skip mail folder creation */
966 skip |= (imap_path_probe(buf_string(fpath), NULL) == MUTT_IMAP);
967 skip |= (pop_path_probe(buf_string(fpath), NULL) == MUTT_POP);
968 skip |= (nntp_path_probe(buf_string(fpath), NULL) == MUTT_NNTP);
969 if (!skip && (stat(buf_string(fpath), &st) == -1) && (errno == ENOENT))
970 {
971 char msg2[256] = { 0 };
972 snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
973 if (query_yesorno(msg2, MUTT_YES) == MUTT_YES)
974 {
975 if ((mkdir(buf_string(fpath), 0700) == -1) && (errno != EEXIST))
976 mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
977 }
978 }
979 buf_pool_release(&fpath);
980 }
981
982 if (batch_mode)
983 {
984 goto main_ok; // TEST22: neomutt -B
985 }
986 StartupComplete = true;
987
992
993 if (sendflags & SEND_POSTPONED)
994 {
995 if (!OptNoCurses)
997 if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
998 rc = 0;
999 // TEST23: neomutt -p (postponed message, cancel)
1000 // TEST24: neomutt -p (no postponed message)
1002 repeat_error = true;
1003 goto main_curses;
1004 }
1005 else if (subject || e || draft_file || include_file ||
1006 !STAILQ_EMPTY(&attach) || (optind < argc))
1007 {
1008 FILE *fp_in = NULL;
1009 FILE *fp_out = NULL;
1010 char *infile = NULL;
1011 char *bodytext = NULL;
1012 const char *bodyfile = NULL;
1013 int rv = 0;
1014
1015 if (!OptNoCurses)
1016 mutt_flushinp();
1017
1018 if (!e)
1019 e = email_new();
1020 if (!e->env)
1021 e->env = mutt_env_new();
1022
1023 for (i = optind; i < argc; i++)
1024 {
1025 if (url_check_scheme(argv[i]) == U_MAILTO)
1026 {
1027 if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
1028 {
1029 mutt_error(_("Failed to parse mailto: link"));
1030 email_free(&e);
1031 goto main_curses; // TEST25: neomutt mailto:?
1032 }
1033 }
1034 else
1035 {
1036 mutt_addrlist_parse(&e->env->to, argv[i]);
1037 }
1038 }
1039
1040 const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
1041 if (!draft_file && c_auto_edit && TAILQ_EMPTY(&e->env->to) &&
1042 TAILQ_EMPTY(&e->env->cc))
1043 {
1044 mutt_error(_("No recipients specified"));
1045 email_free(&e);
1046 goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
1047 }
1048
1049 if (subject)
1050 {
1051 /* prevent header injection */
1053 mutt_env_set_subject(e->env, subject);
1054 }
1055
1056 if (draft_file)
1057 {
1058 infile = draft_file;
1059 include_file = NULL;
1060 }
1061 else if (include_file)
1062 {
1063 infile = include_file;
1064 }
1065 else
1066 {
1067 edit_infile = false;
1068 }
1069
1070 if (infile || bodytext)
1071 {
1072 /* Prepare fp_in and expanded_infile. */
1073 if (infile)
1074 {
1075 if (mutt_str_equal("-", infile))
1076 {
1077 if (edit_infile)
1078 {
1079 mutt_error(_("Can't use -E flag with stdin"));
1080 email_free(&e);
1081 goto main_curses; // TEST27: neomutt -E -H -
1082 }
1083 fp_in = stdin;
1084 }
1085 else
1086 {
1087 buf_strcpy(expanded_infile, infile);
1088 buf_expand_path(expanded_infile);
1089 fp_in = mutt_file_fopen(buf_string(expanded_infile), "r");
1090 if (!fp_in)
1091 {
1092 mutt_perror("%s", buf_string(expanded_infile));
1093 email_free(&e);
1094 goto main_curses; // TEST28: neomutt -E -H missing
1095 }
1096 }
1097 }
1098
1099 if (edit_infile)
1100 {
1101 /* If editing the infile, keep it around afterwards so
1102 * it doesn't get unlinked, and we can rebuild the draft_file */
1103 sendflags |= SEND_NO_FREE_HEADER;
1104 }
1105 else
1106 {
1107 /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1108 * Note: stdin is always copied to a tempfile, ensuring draft_file
1109 * can stat and get the correct st_size below. */
1110 buf_mktemp(tempfile);
1111
1112 fp_out = mutt_file_fopen(buf_string(tempfile), "w");
1113 if (!fp_out)
1114 {
1115 mutt_file_fclose(&fp_in);
1116 mutt_perror("%s", buf_string(tempfile));
1117 email_free(&e);
1118 goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1119 }
1120 if (fp_in)
1121 {
1122 mutt_file_copy_stream(fp_in, fp_out);
1123 if (fp_in == stdin)
1124 sendflags |= SEND_CONSUMED_STDIN;
1125 else
1126 mutt_file_fclose(&fp_in);
1127 }
1128 else if (bodytext)
1129 {
1130 fputs(bodytext, fp_out);
1131 }
1132 mutt_file_fclose(&fp_out);
1133
1134 fp_in = mutt_file_fopen(buf_string(tempfile), "r");
1135 if (!fp_in)
1136 {
1137 mutt_perror("%s", buf_string(tempfile));
1138 email_free(&e);
1139 goto main_curses; // TEST30: can't test
1140 }
1141 }
1142
1143 /* Parse the draft_file into the full Email/Body structure.
1144 * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1145 * our e->body. */
1146 if (draft_file)
1147 {
1148 struct Envelope *opts_env = e->env;
1149 struct stat st = { 0 };
1150
1151 sendflags |= SEND_DRAFT_FILE;
1152
1153 /* Set up a tmp Email with just enough information so that
1154 * mutt_prepare_template() can parse the message in fp_in. */
1155 struct Email *e_tmp = email_new();
1156 e_tmp->offset = 0;
1157 e_tmp->body = mutt_body_new();
1158 if (fstat(fileno(fp_in), &st) != 0)
1159 {
1160 mutt_perror("%s", draft_file);
1161 email_free(&e);
1162 email_free(&e_tmp);
1163 goto main_curses; // TEST31: can't test
1164 }
1165 e_tmp->body->length = st.st_size;
1166
1167 if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1168 {
1169 mutt_error(_("Can't parse message template: %s"), draft_file);
1170 email_free(&e);
1171 email_free(&e_tmp);
1172 goto main_curses;
1173 }
1174
1175 /* Scan for neomutt header to set `$resume_draft_files` */
1176 struct ListNode *np = NULL, *tmp = NULL;
1177 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1178 STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1179 {
1180 if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1181 {
1182 if (c_resume_edited_draft_files)
1183 cs_str_native_set(cs, "resume_draft_files", true, NULL);
1184
1185 STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1186 FREE(&np->data);
1187 FREE(&np);
1188 }
1189 }
1190
1191 mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1192 mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1193 mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1194 if (opts_env->subject)
1195 mutt_env_set_subject(e->env, opts_env->subject);
1196
1197 mutt_env_free(&opts_env);
1198 email_free(&e_tmp);
1199 }
1200 /* Editing the include_file: pass it directly in.
1201 * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1202 else if (edit_infile)
1203 bodyfile = buf_string(expanded_infile);
1204 // For bodytext and unedited include_file: use the tempfile.
1205 else
1206 bodyfile = buf_string(tempfile);
1207
1208 mutt_file_fclose(&fp_in);
1209 }
1210
1211 FREE(&bodytext);
1212
1213 if (!STAILQ_EMPTY(&attach))
1214 {
1215 struct Body *b = e->body;
1216
1217 while (b && b->next)
1218 b = b->next;
1219
1220 struct ListNode *np = NULL;
1221 STAILQ_FOREACH(np, &attach, entries)
1222 {
1223 if (b)
1224 {
1226 b = b->next;
1227 }
1228 else
1229 {
1231 e->body = b;
1232 }
1233 if (!b)
1234 {
1235 mutt_error(_("%s: unable to attach file"), np->data);
1236 mutt_list_free(&attach);
1237 email_free(&e);
1238 goto main_curses; // TEST32: neomutt john@example.com -a missing
1239 }
1240 }
1241 mutt_list_free(&attach);
1242 }
1243
1244 rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1245 /* We WANT the "Mail sent." and any possible, later error */
1247 if (ErrorBufMessage)
1248 mutt_message("%s", ErrorBuf);
1249
1250 if (edit_infile)
1251 {
1252 if (draft_file)
1253 {
1254 if (truncate(buf_string(expanded_infile), 0) == -1)
1255 {
1256 mutt_perror("%s", buf_string(expanded_infile));
1257 email_free(&e);
1258 goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1259 }
1260 fp_out = mutt_file_fopen(buf_string(expanded_infile), "a");
1261 if (!fp_out)
1262 {
1263 mutt_perror("%s", buf_string(expanded_infile));
1264 email_free(&e);
1265 goto main_curses; // TEST34: can't test
1266 }
1267
1268 /* If the message was sent or postponed, these will already
1269 * have been done. */
1270 if (rv < 0)
1271 {
1272 if (e->body->next)
1273 e->body = mutt_make_multipart(e->body);
1275 mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1276 mutt_env_to_intl(e->env, NULL, NULL);
1277 }
1278
1279 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1281 c_crypt_protected_headers_read &&
1283 NeoMutt->sub);
1284 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1285 if (c_resume_edited_draft_files)
1286 fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1287 fputc('\n', fp_out);
1288 if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1289 {
1290 mutt_file_fclose(&fp_out);
1291 email_free(&e);
1292 goto main_curses; // TEST35: can't test
1293 }
1294 mutt_file_fclose(&fp_out);
1295 }
1296
1297 email_free(&e);
1298 }
1299
1300 /* !edit_infile && draft_file will leave the tempfile around */
1301 if (!buf_is_empty(tempfile))
1302 unlink(buf_string(tempfile));
1303
1305
1306 if (rv != 0)
1307 goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1308 }
1309 else if (sendflags & SEND_BATCH)
1310 {
1311 /* This guards against invoking `neomutt < /dev/null` and accidentally
1312 * sending an email due to a my_hdr or other setting. */
1313 mutt_error(_("No recipients specified"));
1314 goto main_curses;
1315 }
1316 else
1317 {
1318 if (flags & MUTT_CLI_MAILBOX)
1319 {
1320 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1321 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1323 if (mutt_mailbox_check(NULL, csflags) == 0)
1324 {
1325 mutt_message(_("No mailbox with new mail"));
1326 goto main_curses; // TEST37: neomutt -Z (no new mail)
1327 }
1328 buf_reset(folder);
1329 mutt_mailbox_next(NULL, folder);
1330 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1331 }
1332 else if (flags & MUTT_CLI_SELECT)
1333 {
1334 if (flags & MUTT_CLI_NEWS)
1335 {
1336 const char *const c_news_server = cs_subset_string(NeoMutt->sub, "news_server");
1337 OptNews = true;
1338 CurrentNewsSrv = nntp_select_server(NULL, c_news_server, false);
1339 if (!CurrentNewsSrv)
1340 goto main_curses; // TEST38: neomutt -G (unset news_server)
1341 }
1342 else if (TAILQ_EMPTY(&NeoMutt->accounts))
1343 {
1344 mutt_error(_("No incoming mailboxes defined"));
1345 goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1346 }
1347 buf_reset(folder);
1348 dlg_browser(folder, MUTT_SEL_FOLDER | MUTT_SEL_MAILBOX, NULL, NULL, NULL);
1349 if (buf_is_empty(folder))
1350 {
1351 goto main_ok; // TEST40: neomutt -y (quit selection)
1352 }
1353 }
1354
1355 if (buf_is_empty(folder))
1356 {
1357 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1358 if (c_spool_file)
1359 {
1360 // Check if `$spool_file` corresponds a mailboxes' description.
1361 struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1362 if (m_desc)
1363 buf_strcpy(folder, m_desc->realpath);
1364 else
1365 buf_strcpy(folder, c_spool_file);
1366 }
1367 else if (c_folder)
1368 {
1369 buf_strcpy(folder, c_folder);
1370 }
1371 /* else no folder */
1372 }
1373
1374 if (OptNews)
1375 {
1376 OptNews = false;
1377 buf_alloc(folder, PATH_MAX);
1378 nntp_expand_path(folder->data, folder->dsize, &CurrentNewsSrv->conn->account);
1379 }
1380 else
1381 {
1382 buf_expand_path(folder);
1383 }
1384
1387
1388 if (flags & MUTT_CLI_IGNORE)
1389 {
1390 /* check to see if there are any messages in the folder */
1391 switch (mx_path_is_empty(folder))
1392 {
1393 case -1:
1394 mutt_perror("%s", buf_string(folder));
1395 goto main_curses; // TEST41: neomutt -z -f missing
1396 case 1:
1397 mutt_error(_("Mailbox is empty"));
1398 goto main_curses; // TEST42: neomutt -z -f /dev/null
1399 }
1400 }
1401
1402 struct Mailbox *m_cur = mailbox_find(buf_string(folder));
1403 mutt_folder_hook(buf_string(folder), m_cur ? m_cur->name : NULL);
1405 mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1407
1409 window_redraw(NULL);
1410
1411 repeat_error = true;
1412 struct Mailbox *m = mx_resolve(buf_string(folder));
1413 const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1414 if (!mx_mbox_open(m, ((flags & MUTT_CLI_RO) || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1415 {
1416 if (m->account)
1418
1419 mailbox_free(&m);
1420 mutt_error(_("Unable to open mailbox %s"), buf_string(folder));
1421 repeat_error = false;
1422 }
1423 if (m || !explicit_folder)
1424 {
1425 struct MuttWindow *dlg = index_pager_init();
1426 dialog_push(dlg);
1427
1429 m = dlg_index(dlg, m);
1431 mailbox_free(&m);
1432
1433 dialog_pop();
1434 mutt_window_free(&dlg);
1436 repeat_error = false;
1437 }
1439#ifdef USE_SASL_CYRUS
1441#endif
1442#ifdef USE_SASL_GNU
1444#endif
1445#ifdef USE_AUTOCRYPT
1447#endif
1448 // TEST43: neomutt (no change to mailbox)
1449 // TEST44: neomutt (change mailbox)
1450 }
1451
1452main_ok:
1453 rc = 0;
1454main_curses:
1455 mutt_endwin();
1457 /* Repeat the last message to the user */
1458 if (repeat_error && ErrorBufMessage)
1459 puts(ErrorBuf);
1460main_exit:
1461 if (NeoMutt && NeoMutt->sub)
1462 {
1467 }
1468 mutt_list_free(&commands);
1470 buf_pool_release(&folder);
1471 buf_pool_release(&expanded_infile);
1472 buf_pool_release(&tempfile);
1473 mutt_list_free(&queries);
1480 menu_cleanup();
1481 crypt_cleanup();
1491 cs_free(&cs);
1493 mutt_log_stop();
1494 return rc;
1495}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:765
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_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:480
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1293
Email Address Handling.
Email Aliases.
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:277
void alternates_cleanup(void)
Free the alternates lists.
Definition: alternates.c:49
void alternates_init(void)
Set up the alternates lists.
Definition: alternates.c:60
Alternate address handling.
GUI display the mailboxes in a side panel.
void attach_init(void)
Set up the attachments lists.
Definition: attachments.c:106
void attach_cleanup(void)
Free the attachments lists.
Definition: attachments.c:92
Autocrypt end-to-end encryption.
void mutt_autocrypt_cleanup(void)
Shutdown Autocrypt.
Definition: autocrypt.c:129
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:99
void show_backtrace(void)
Log the program's call stack.
Definition: backtrace.c:39
Select a Mailbox from a list.
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: lib.h:58
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: lib.h:60
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
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
Color and attribute parsing.
void mutt_colors_init(void)
Initialize colours.
Definition: color.c:74
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:59
bool dump_config(struct ConfigSet *cs, ConfigDumpFlags flags, FILE *fp)
Write all the config to a file.
Definition: dump.c:167
#define CS_DUMP_HIDE_SENSITIVE
Obscure sensitive information like passwords.
Definition: dump.h:37
uint16_t ConfigDumpFlags
Flags for dump_config(), e.g. CS_DUMP_ONLY_CHANGED.
Definition: dump.h:34
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
#define CS_DUMP_SHOW_DOCS
Show one-liner documentation for the config item.
Definition: dump.h:45
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:143
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: globals.c:37
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition: set.c:175
int cs_str_initial_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:503
void cs_free(struct ConfigSet **ptr)
Free a Config Set.
Definition: set.c:141
int cs_str_reset(const struct ConfigSet *cs, const char *name, struct Buffer *err)
Reset a config item to its initial value.
Definition: set.c:438
struct ConfigSet * cs_new(size_t size)
Create a new Config Set.
Definition: set.c:127
int cs_he_reset(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *err)
Reset a config item to its initial value.
Definition: set.c:391
int cs_str_native_set(const struct ConfigSet *cs, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: set.c:760
int cs_he_initial_set(const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:461
int cs_he_initial_get(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *result)
Get the initial, or parent, value of a config item.
Definition: set.c:529
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
void config_cache_cleanup(void)
Cleanup the cache of charset config variables.
Definition: config_cache.c:145
Connection Library.
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:98
Convenience wrapper for the core headers.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:89
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:187
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:150
@ MUTT_POP
'POP3' Mailbox type
Definition: mailbox.h:52
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1100
void crypto_module_cleanup(void)
Clean up the crypto modules.
Definition: crypt_mod.c:84
void crypt_cleanup(void)
Clean up backend.
Definition: cryptglue.c:141
void crypt_init(void)
Initialise the crypto backends.
Definition: cryptglue.c:93
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:151
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: get.c:58
Convenience wrapper for the debug headers.
int debug_all_observer(struct NotifyCallback *nc)
Definition: notify.c:205
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:109
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:142
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:89
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: dlg_browser.c:159
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1437
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:44
struct Email * email_new(void)
Create a new Email.
Definition: email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:46
Structs that make up an email.
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1754
void mutt_filter_commandline_header_value(char *header)
Sanitise characters in a header value.
Definition: parse.c:93
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope's Address fields to Punycode format.
Definition: envelope.c:355
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:126
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:46
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition: envelope.c:69
void envlist_free(char ***envp)
Free the private copy of the environment.
Definition: envlist.c:42
char ** envlist_init(char **envp)
Create a copy of the environment.
Definition: envlist.c:58
void external_cleanup(void)
Clean up commands globals.
Definition: external.c:80
Manage where the email is piped to external commands.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:287
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
Definition: file.c:1406
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:67
char * LastFolder
Previously selected mailbox.
Definition: globals.c:43
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: globals.c:69
char ErrorBuf[1024]
Copy of the last error message.
Definition: globals.c:35
bool ErrorBufMessage
true if the last message was an error
Definition: globals.c:34
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:42
struct ListHead Muttrc
List of config files to read.
Definition: globals.c:51
char * Username
User's login name.
Definition: globals.c:40
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:75
Global variables.
void dlg_browser(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file -.
Definition: dlg_browser.c:853
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition: dlg_index.c:1099
int log_disp_queue(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...)
Save a log line to an internal queue - Implements log_dispatcher_t -.
Definition: logging.c:398
int log_disp_terminal(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...)
Save a log line to the terminal - Implements log_dispatcher_t -.
Definition: logging.c:441
int log_disp_curses(time_t stamp, const char *file, int line, const char *function, enum LogLevel level, const char *format,...)
Display a log line in the message line - Implements log_dispatcher_t -.
Definition: mutt_logging.c:88
#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 nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe() -.
Definition: nntp.c:2786
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe() -.
Definition: pop.c:1156
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2344
int main_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: init.c:259
int main_hist_observer(struct NotifyCallback *nc)
Notification that a Config Variable has change - Implements observer_t -.
Definition: history.c:713
int main_timeout_observer(struct NotifyCallback *nc)
Notification that a timeout has occurred - Implements observer_t -.
Definition: main.c:508
int main_log_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: mutt_logging.c:285
void mutt_gsasl_cleanup(void)
Shutdown GNU SASL library.
Definition: gsasl.c:149
Convenience wrapper for the gui headers.
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *b, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:577
@ MUTT_WRITE_HEADER_POSTPONE
A postponed Email, just the envelope info.
Definition: header.h:42
Read/write command history from/to a file.
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:931
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:963
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:630
Parse and execute user-defined hooks.
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:54
IMAP network mailbox.
void imap_logout_all(void)
Close all open connections.
Definition: imap.c:553
GUI manage the main index (list of emails)
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:621
int mutt_init(struct ConfigSet *cs, const char *dlevel, const char *dfile, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:318
void mutt_opts_cleanup(void)
Clean up before quitting.
Definition: init.c:262
Config/command parsing.
void init_config(struct ConfigSet *cs)
Initialise the config system.
Definition: mutt_config.c:932
void km_init(void)
Initialise all the menu keybindings.
Definition: init.c:177
void mutt_keys_cleanup(void)
Free the key maps.
Definition: init.c:224
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: init.c:134
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: init.c:237
Manage keymappings.
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
int(*) log_dispatcher_ MuttLogger)
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_MESSAGE
Log informational message.
Definition: logging2.h:42
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
@ LL_MAX
Definition: logging2.h:50
#define MUTT_CLI_SELECT
-y Start with a list of all mailboxes
Definition: main.c:198
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition: main.c:390
static void localise_config(struct ConfigSet *cs)
Localise some config.
Definition: main.c:230
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:192
static void log_translation(void)
Log the translation being used.
Definition: main.c:459
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:195
static void log_gui(void)
Log info about the GUI.
Definition: main.c:485
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:266
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:206
static bool usage(void)
Display NeoMutt command line.
Definition: main.c:280
static int start_curses(void)
Start the Curses UI.
Definition: main.c:358
bool StartupComplete
When the config has been read.
Definition: main.c:189
static bool get_user_info(struct ConfigSet *cs)
Find the user's name, home and shell.
Definition: main.c:418
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:197
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:193
int main(int argc, char *argv[], char *envp[])
Start NeoMutt.
Definition: main.c:551
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:194
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:199
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:196
bool OptLocales
(pseudo) set if user has valid locale definition
Definition: mbyte.c:44
#define FREE(x)
Definition: memory.h:55
#define mutt_array_size(x)
Definition: memory.h:38
GUI present the user with a selectable list.
void menu_cleanup(void)
Free the saved Menu searches.
Definition: menu.c:70
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
void mutt_ch_cache_cleanup(void)
Clean up the cached iconv handles and charset strings.
Definition: charset.c:1175
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
Convenience wrapper for the library headers.
#define FALLTHROUGH
Definition: lib.h:111
void log_queue_empty(void)
Free the contents of the queue.
Definition: logging.c:324
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition: logging.c:312
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:346
#define _(a)
Definition: message.h:28
bool notify_observer_remove(struct Notify *notify, const observer_t callback, const void *global_data)
Remove an observer from an object.
Definition: notify.c:230
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:191
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
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:726
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:521
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:242
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
Many unsorted constants and some structs.
#define PATH_MAX
Definition: mutt.h:42
void mutt_temp_attachments_cleanup(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1309
enum MuttCursorState mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:94
const struct AttrColor * mutt_curses_set_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:79
void mutt_resize_screen(void)
Update NeoMutt's opinion about the window size.
Definition: resize.c:76
@ MUTT_CURSOR_INVISIBLE
Hide the cursor.
Definition: mutt_curses.h:65
@ MUTT_CURSOR_VISIBLE
Display a normal cursor.
Definition: mutt_curses.h:66
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:181
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:171
NeoMutt Logging.
int mutt_mailbox_check(struct Mailbox *m_cur, CheckStatsFlags flags)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:169
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
Definition: mutt_mailbox.c:361
Mailbox helper functions.
void mutt_signal_init(void)
Initialise the signal handling.
Definition: mutt_signal.c:130
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:634
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:202
struct MuttWindow * window_get_focus(void)
Get the currently focused Window.
Definition: mutt_window.c:668
@ WT_DLG_INDEX
Index Dialog, dlg_index()
Definition: mutt_window.h:87
void buf_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:122
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:858
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
Some miscellaneous functions.
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:288
struct Mailbox * mx_resolve(const char *path_or_name)
Get a Mailbox from either a path or name.
Definition: mx.c:1705
int mx_path_is_empty(struct Buffer *path)
Is the mailbox empty.
Definition: mx.c:1252
API for mailboxes.
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:43
#define MUTT_MAILBOX_CHECK_IMMEDIATE
Don't postpone the actual checking.
Definition: mxapi.h:56
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:40
uint8_t CheckStatsFlags
Flags for mutt_mailbox_check.
Definition: mxapi.h:52
API for encryption/signing of emails.
struct NeoMutt * neomutt_new(struct ConfigSet *cs)
Create the main NeoMutt object.
Definition: neomutt.c:50
void neomutt_free(struct NeoMutt **ptr)
Free a NeoMutt.
Definition: neomutt.c:86
@ NT_GLOBAL_STARTUP
NeoMutt is initialised.
Definition: neomutt.h:61
Nntp-specific Account data.
Usenet network mailbox type; talk to an NNTP server.
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:556
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:945
@ NT_TIMEOUT
Timeout has occurred.
Definition: notify_type.h:56
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:43
@ NT_ALL
Register for all notifications.
Definition: notify_type.h:35
@ NT_GLOBAL
Not object-related, NotifyGlobal.
Definition: notify_type.h:46
@ NT_RESIZE
Window has been resized.
Definition: notify_type.h:52
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
void buf_pool_cleanup(void)
Release the Buffer pool.
Definition: pool.c:68
POP network mailbox.
Postponed Emails.
int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new, struct Email *e, bool resend)
Prepare a message template.
Definition: postpone.c:483
void mutt_prex_cleanup(void)
Cleanup heap memory allocated by compiled regexes.
Definition: prex.c:339
Prototypes for many functions.
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
#define TAILQ_EMPTY(head)
Definition: queue.h:739
void rootwin_cleanup(void)
Free all the default Windows.
Definition: rootwin.c:202
struct MuttWindow * RootWindow
Parent of all Windows.
Definition: rootwin.c:106
void rootwin_new(void)
Create the default Windows.
Definition: rootwin.c:214
void mutt_sasl_cleanup(void)
Invoke when processing is complete.
Definition: sasl.c:786
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:300
Convenience wrapper for the send headers.
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
RFC2047 encode the content-descriptions.
Definition: send.c:1488
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2033
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:47
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:51
#define SEND_DRAFT_FILE
Used by the -H flag.
Definition: send.h:52
uint32_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:40
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:46
#define SEND_CONSUMED_STDIN
stdin has been read; don't read it twice
Definition: send.h:57
#define SEND_CLI_CRYPTO
Enable message security in modes that by default don't enable it.
Definition: send.h:58
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:41
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:607
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:780
int endwin(void)
#define NONULL(x)
Definition: string2.h:37
#define SKIPWS(ch)
Definition: string2.h:45
The body of an email.
Definition: body.h:36
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct Body * next
next attachment in the list
Definition: body.h:72
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
Container for lots of config items.
Definition: set.h:252
struct Notify * notify
Notifications: NotifyConfig, EventConfig.
Definition: subset.h:52
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:49
The envelope/body of an email.
Definition: email.h:39
struct Envelope * env
Envelope information.
Definition: email.h:68
struct Body * body
List of MIME parts.
Definition: email.h:69
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:71
The header of an Email.
Definition: envelope.h:57
struct ListHead userhdrs
user defined headers
Definition: envelope.h:85
char *const subject
Email's subject.
Definition: envelope.h:70
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
The item stored in a Hash Table.
Definition: hash.h:43
A List node for strings.
Definition: list.h:37
char * data
String.
Definition: list.h:38
A mailbox.
Definition: mailbox.h:79
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:127
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
struct MuttWindow * focus
Focused Window.
Definition: mutt_window.h:140
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:144
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct Notify * notify_resize
Window resize notifications handler.
Definition: neomutt.h:44
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:47
mode_t user_default_umask
User's default file writing permissions (inferred from umask)
Definition: neomutt.h:49
struct Notify * notify
Notifications handler.
Definition: neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:62
Data passed to a notification function.
Definition: observer.h:34
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:36
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:62
void subjrx_init(void)
Create new Subject Regex List.
Definition: subjectrx.c:55
void subjrx_cleanup(void)
Free the Subject Regex List.
Definition: subjectrx.c:46
Subject Regex handling.
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
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:42
bool mutt_ts_capability(void)
Check terminal capabilities.
Definition: terminal.c:72
#define buf_mktemp(buf)
Definition: tmp.h:33
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:226
@ U_MAILTO
Url is mailto://.
Definition: url.h:45
bool print_copyright(void)
Print copyright message.
Definition: version.c:517
bool print_version(FILE *fp)
Print system and compile info to a file.
Definition: version.c:388
Display version and copyright about NeoMutt.