NeoMutt  2025-09-05-43-g177ed6
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
29
121
127
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 <stdio.h>
137#include <string.h>
138#include <sys/stat.h>
139#include <sys/utsname.h>
140#include <time.h>
141#include <unistd.h>
142#include "mutt/lib.h"
143#include "address/lib.h"
144#include "config/lib.h"
145#include "email/lib.h"
146#include "core/lib.h"
147#include "alias/lib.h"
148#include "conn/lib.h"
149#include "gui/lib.h"
150#include "mutt.h"
151#include "attach/lib.h"
152#include "browser/lib.h"
153#include "cli/lib.h"
154#include "color/lib.h"
155#include "compmbox/lib.h"
156#include "history/lib.h"
157#include "imap/lib.h"
158#include "index/lib.h"
159#include "key/lib.h"
160#include "menu/lib.h"
161#include "ncrypt/lib.h"
162#include "nntp/lib.h"
163#include "notmuch/lib.h"
164#include "parse/lib.h"
165#include "pop/lib.h"
166#include "postpone/lib.h"
167#include "question/lib.h"
168#include "send/lib.h"
169#include "sidebar/lib.h"
170#include "alternates.h"
171#include "commands.h"
172#include "external.h"
173#include "globals.h"
174#include "hook.h"
175#include "mutt_logging.h"
176#include "mutt_mailbox.h"
177#include "muttlib.h"
178#include "mx.h"
179#include "nntp/adata.h" // IWYU pragma: keep
180#include "protos.h"
181#include "subjectrx.h"
182#include "version.h"
183#ifdef ENABLE_NLS
184#include <libintl.h>
185#endif
186#ifdef USE_AUTOCRYPT
187#include "autocrypt/lib.h"
188#endif
189#if defined(USE_DEBUG_NOTIFY) || defined(USE_DEBUG_BACKTRACE)
190#include "debug/lib.h"
191#endif
192#ifndef DOMAIN
193#include "conn/lib.h"
194#endif
195#ifdef USE_LUA
196#include "mutt_lua.h"
197#endif
198
199bool StartupComplete = false;
200
201void show_cli(enum HelpMode mode, bool use_color);
202
209static int execute_commands(struct StringArray *sa)
210{
211 int rc = 0;
212 struct Buffer *err = buf_pool_get();
213
214 const char **cp = NULL;
215 ARRAY_FOREACH(cp, sa)
216 {
217 enum CommandResult rc2 = parse_rc_line(*cp, err);
218 if (rc2 == MUTT_CMD_ERROR)
219 mutt_error(_("Error in command line: %s"), buf_string(err));
220 else if (rc2 == MUTT_CMD_WARNING)
221 mutt_warning(_("Warning in command line: %s"), buf_string(err));
222
223 if ((rc2 == MUTT_CMD_ERROR) || (rc2 == MUTT_CMD_WARNING))
224 {
225 buf_pool_release(&err);
226 return -1;
227 }
228 }
229 buf_pool_release(&err);
230
231 return rc;
232}
233
241static char *find_cfg(const char *home, const char *xdg_cfg_home)
242{
243 const char *names[] = {
244 "neomuttrc",
245 "muttrc",
246 NULL,
247 };
248
249 const char *locations[][2] = {
250 { xdg_cfg_home, "neomutt/" },
251 { xdg_cfg_home, "mutt/" },
252 { home, ".neomutt/" },
253 { home, ".mutt/" },
254 { home, "." },
255 { NULL, NULL },
256 };
257
258 struct Buffer *buf = buf_pool_get();
259 char *cfg = NULL;
260
261 for (int i = 0; locations[i][0] || locations[i][1]; i++)
262 {
263 if (!locations[i][0])
264 continue;
265
266 for (int j = 0; names[j]; j++)
267 {
268 buf_printf(buf, "%s/%s%s", locations[i][0], locations[i][1], names[j]);
269 if (access(buf_string(buf), F_OK) == 0)
270 {
271 cfg = buf_strdup(buf);
272 goto done;
273 }
274 }
275 }
276
277done:
278 buf_pool_release(&buf);
279 return cfg;
280}
281
282#ifndef DOMAIN
288static char *getmailname(void)
289{
290 char *mailname = NULL;
291 static const char *mn_files[] = { "/etc/mailname", "/etc/mail/mailname" };
292
293 for (size_t i = 0; i < countof(mn_files); i++)
294 {
295 FILE *fp = mutt_file_fopen(mn_files[i], "r");
296 if (!fp)
297 continue;
298
299 size_t len = 0;
300 mailname = mutt_file_read_line(NULL, &len, fp, NULL, MUTT_RL_NO_FLAGS);
301 mutt_file_fclose(&fp);
302 if (mailname && *mailname)
303 break;
304
305 FREE(&mailname);
306 }
307
308 return mailname;
309}
310#endif
311
321static bool get_hostname(struct ConfigSet *cs)
322{
323 const char *short_host = NULL;
324 struct utsname utsname = { 0 };
325
326 const char *const c_hostname = cs_subset_string(NeoMutt->sub, "hostname");
327 if (c_hostname)
328 {
329 short_host = c_hostname;
330 }
331 else
332 {
333 /* The call to uname() shouldn't fail, but if it does, the system is horribly
334 * broken, and the system's networking configuration is in an unreliable
335 * state. We should bail. */
336 if ((uname(&utsname)) == -1)
337 {
338 mutt_perror(_("unable to determine nodename via uname()"));
339 return false; // TEST09: can't test
340 }
341
342 short_host = utsname.nodename;
343 }
344
345 /* some systems report the FQDN instead of just the hostname */
346 char *dot = strchr(short_host, '.');
347 if (dot)
348 ShortHostname = mutt_strn_dup(short_host, dot - short_host);
349 else
350 ShortHostname = mutt_str_dup(short_host);
351
352 // All the code paths from here alloc memory for the fqdn
353 char *fqdn = mutt_str_dup(c_hostname);
354 if (!fqdn)
355 {
356 mutt_debug(LL_DEBUG1, "Setting $hostname\n");
357 /* now get FQDN. Use configured domain first, DNS next, then uname */
358#ifdef DOMAIN
359 /* we have a compile-time domain name, use that for `$hostname` */
360 mutt_str_asprintf(&fqdn, "%s.%s", NONULL(ShortHostname), DOMAIN);
361#else
362 fqdn = getmailname();
363 if (!fqdn)
364 {
365 struct Buffer *domain = buf_pool_get();
366 if (getdnsdomainname(domain) == 0)
367 {
368 mutt_str_asprintf(&fqdn, "%s.%s", NONULL(ShortHostname), buf_string(domain));
369 }
370 else
371 {
372 /* DNS failed, use the nodename. Whether or not the nodename had a '.'
373 * in it, we can use the nodename as the FQDN. On hosts where DNS is
374 * not being used, e.g. small network that relies on hosts files, a
375 * short host name is all that is required for SMTP to work correctly.
376 * It could be wrong, but we've done the best we can, at this point the
377 * onus is on the user to provide the correct hostname if the nodename
378 * won't work in their network. */
379 fqdn = mutt_str_dup(utsname.nodename);
380 }
381 buf_pool_release(&domain);
382 mutt_debug(LL_DEBUG1, "Hostname: %s\n", NONULL(fqdn));
383 }
384#endif
385 }
386
387 if (fqdn)
388 {
389 config_str_set_initial(cs, "hostname", fqdn);
390 FREE(&fqdn);
391 }
392
393 return true;
394}
395
407static int mutt_init(struct ConfigSet *cs, struct Buffer *dlevel,
408 struct Buffer *dfile, bool skip_sys_rc,
409 struct StringArray *user_files, struct StringArray *commands)
410{
411 bool need_pause = false;
412 int rc = 1;
413 struct Buffer *err = buf_pool_get();
414 struct Buffer *buf = buf_pool_get();
415 const char **cp = NULL;
416
417#ifdef NEOMUTT_DIRECT_COLORS
418 /* Test if we run in a terminal which supports direct colours.
419 *
420 * The user/terminal can indicate their capability independent of the
421 * terminfo file by setting the COLORTERM environment variable to "truecolor"
422 * or "24bit" (case sensitive).
423 *
424 * Note: This is to test is less about whether the terminal understands
425 * direct color commands but more about whether ncurses believes it can send
426 * them to the terminal, e.g. ncurses ignores COLORTERM.
427 */
428 if (COLORS == 16777216) // 2^24
429 {
430 /* Ncurses believes the Terminal supports it check the environment variable
431 * to respect the user's choice */
432 const char *env_colorterm = mutt_str_getenv("COLORTERM");
433 if (env_colorterm && (mutt_str_equal(env_colorterm, "truecolor") ||
434 mutt_str_equal(env_colorterm, "24bit")))
435 {
436 config_str_set_initial(cs, "color_directcolor", "yes");
437 }
438 }
439#endif
440
441 /* "$spool_file" precedence: config file, environment */
442 const char *p = mutt_str_getenv("MAIL");
443 if (!p)
444 p = mutt_str_getenv("MAILDIR");
445 if (!p)
446 {
447#ifdef HOMESPOOL
448 buf_concat_path(buf, NONULL(NeoMutt->home_dir), MAILPATH);
449#else
450 buf_concat_path(buf, MAILPATH, NONULL(NeoMutt->username));
451#endif
452 p = buf_string(buf);
453 }
454 config_str_set_initial(cs, "spool_file", p);
455
456 p = mutt_str_getenv("REPLYTO");
457 if (p)
458 {
459 struct Buffer *token = buf_pool_get();
460
461 buf_printf(buf, "Reply-To: %s", p);
462 buf_seek(buf, 0);
463 parse_my_hdr(token, buf, 0, err); /* adds to UserHeader */
464 buf_pool_release(&token);
465 }
466
467 p = mutt_str_getenv("EMAIL");
468 if (p)
469 config_str_set_initial(cs, "from", p);
470
471 /* "$mailcap_path" precedence: config file, environment, code */
472 struct Buffer *mc = buf_pool_get();
473 struct Slist *sl_mc = NULL;
474 const char *env_mc = mutt_str_getenv("MAILCAPS");
475 if (env_mc)
476 {
477 sl_mc = slist_parse(env_mc, D_SLIST_SEP_COLON);
478 }
479 else
480 {
481 cs_str_initial_get(cs, "mailcap_path", mc);
483 buf_reset(mc);
484 }
485 slist_to_buffer(sl_mc, mc);
486 config_str_set_initial(cs, "mailcap_path", buf_string(mc));
487 slist_free(&sl_mc);
488 buf_pool_release(&mc);
489
490 /* "$tmp_dir" precedence: config file, environment, code */
491 const char *env_tmp = mutt_str_getenv("TMPDIR");
492 if (env_tmp)
493 config_str_set_initial(cs, "tmp_dir", env_tmp);
494
495 /* "$visual", "$editor" precedence: config file, environment, code */
496 const char *env_ed = mutt_str_getenv("VISUAL");
497 if (!env_ed)
498 env_ed = mutt_str_getenv("EDITOR");
499 if (!env_ed)
500 env_ed = "vi";
501 config_str_set_initial(cs, "editor", env_ed);
502
503 const char *charset = mutt_ch_get_langinfo_charset();
504 config_str_set_initial(cs, "charset", charset);
505 mutt_ch_set_charset(charset);
506 FREE(&charset);
507
508 char name[256] = { 0 };
509 const char *c_real_name = cs_subset_string(NeoMutt->sub, "real_name");
510 if (!c_real_name)
511 {
512 struct passwd *pw = getpwuid(getuid());
513 if (pw)
514 {
515 c_real_name = mutt_gecos_name(name, sizeof(name), pw);
516 }
517 }
518 config_str_set_initial(cs, "real_name", c_real_name);
519
520#ifdef HAVE_GETSID
521 /* Unset suspend by default if we're the session leader */
522 if (getsid(0) == getpid())
523 config_str_set_initial(cs, "suspend", "no");
524#endif
525
526 /* RFC2368, "4. Unsafe headers"
527 * The creator of a mailto URL can't expect the resolver of a URL to
528 * understand more than the "subject" and "body" headers. Clients that
529 * resolve mailto URLs into mail messages should be able to correctly
530 * create RFC822-compliant mail messages using the "subject" and "body"
531 * headers. */
532 add_to_stailq(&MailToAllow, "body");
533 add_to_stailq(&MailToAllow, "subject");
534 /* Cc, In-Reply-To, and References help with not breaking threading on
535 * mailing lists, see https://github.com/neomutt/neomutt/issues/115 */
537 add_to_stailq(&MailToAllow, "in-reply-to");
538 add_to_stailq(&MailToAllow, "references");
539
540 if (ARRAY_EMPTY(user_files))
541 {
542 const char *xdg_cfg_home = mutt_str_getenv("XDG_CONFIG_HOME");
543
544 if (!xdg_cfg_home && NeoMutt->home_dir)
545 {
546 buf_printf(buf, "%s/.config", NeoMutt->home_dir);
547 xdg_cfg_home = buf_string(buf);
548 }
549
550 char *config = find_cfg(NeoMutt->home_dir, xdg_cfg_home);
551 if (config)
552 {
553 ARRAY_ADD(user_files, config);
554 }
555 }
556 else
557 {
558 ARRAY_FOREACH(cp, user_files)
559 {
560 buf_strcpy(buf, *cp);
561 FREE(cp);
562 buf_expand_path(buf);
563 ARRAY_SET(user_files, ARRAY_FOREACH_IDX_cp, buf_strdup(buf));
564 if (access(buf_string(buf), F_OK))
565 {
566 mutt_perror("%s", buf_string(buf));
567 goto done; // TEST10: neomutt -F missing
568 }
569 }
570 }
571
572 ARRAY_FOREACH(cp, user_files)
573 {
574 if (*cp && !mutt_str_equal(*cp, "/dev/null"))
575 {
576 cs_str_string_set(cs, "alias_file", *cp, NULL);
577 break;
578 }
579 }
580
581 /* Process the global rc file if it exists and the user hasn't explicitly
582 * requested not to via "-n". */
583 if (!skip_sys_rc)
584 {
585 do
586 {
588 break;
589
590 buf_printf(buf, "%s/neomuttrc", SYSCONFDIR);
591 if (access(buf_string(buf), F_OK) == 0)
592 break;
593
594 buf_printf(buf, "%s/Muttrc", SYSCONFDIR);
595 if (access(buf_string(buf), F_OK) == 0)
596 break;
597
598 buf_printf(buf, "%s/neomuttrc", PKGDATADIR);
599 if (access(buf_string(buf), F_OK) == 0)
600 break;
601
602 buf_printf(buf, "%s/Muttrc", PKGDATADIR);
603 } while (false);
604
605 if (access(buf_string(buf), F_OK) == 0)
606 {
607 if (source_rc(buf_string(buf), err) != 0)
608 {
609 mutt_error("%s", buf_string(err));
610 need_pause = true; // TEST11: neomutt (error in /etc/neomuttrc)
611 }
612 }
613 }
614
615 /* Read the user's initialization file. */
616 ARRAY_FOREACH(cp, user_files)
617 {
618 if (*cp)
619 {
620 if (source_rc(*cp, err) != 0)
621 {
622 mutt_error("%s", buf_string(err));
623 need_pause = true; // TEST12: neomutt (error in ~/.neomuttrc)
624 }
625 }
626 }
627
628 if (execute_commands(commands) != 0)
629 need_pause = true; // TEST13: neomutt -e broken
630
631 if (!get_hostname(cs))
632 goto done;
633
634 /* The command line overrides the config */
635 if (!buf_is_empty(dlevel))
636 cs_str_reset(cs, "debug_level", NULL);
637 if (!buf_is_empty(dfile))
638 cs_str_reset(cs, "debug_file", NULL);
639
640 if (mutt_log_start() < 0)
641 {
642 mutt_perror("log file");
643 goto done;
644 }
645
646 if (need_pause && OptGui)
647 {
649 if (mutt_any_key_to_continue(NULL) == 'q')
650 goto done; // TEST14: neomutt -e broken (press 'q')
651 }
652
653 const char *const c_tmp_dir = cs_subset_path(NeoMutt->sub, "tmp_dir");
654 if (mutt_file_mkdir(c_tmp_dir, S_IRWXU) < 0)
655 {
656 mutt_error(_("Can't create %s: %s"), c_tmp_dir, strerror(errno));
657 goto done;
658 }
659
660 rc = 0;
661
662done:
663 buf_pool_release(&err);
664 buf_pool_release(&buf);
665 return rc;
666}
667
675static int get_elem_queries(struct StringArray *queries, struct HashElemArray *hea)
676{
677 int rc = 0;
678 const char **cp = NULL;
679 ARRAY_FOREACH(cp, queries)
680 {
681 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, *cp);
682 if (!he)
683 {
684 mutt_warning(_("Unknown option %s"), *cp);
685 rc = 1;
686 continue;
687 }
688
689 if (he->type & D_INTERNAL_DEPRECATED)
690 {
691 mutt_warning(_("Option %s is deprecated"), *cp);
692 rc = 1;
693 continue;
694 }
695
696 ARRAY_ADD(hea, he);
697 }
698
699 return rc; // TEST16: neomutt -Q charset
700}
701
706static void reset_tilde(struct ConfigSet *cs)
707{
708 static const char *names[] = { "folder", "mbox", "postponed", "record" };
709
710 struct Buffer *value = buf_pool_get();
711 for (size_t i = 0; i < countof(names); i++)
712 {
713 struct HashElem *he = cs_get_elem(cs, names[i]);
714 if (!he)
715 continue;
716 buf_reset(value);
717 cs_he_initial_get(cs, he, value);
718 buf_expand_path_regex(value, false);
719 config_he_set_initial(cs, he, value->data);
720 }
721 buf_pool_release(&value);
722}
723
724#ifdef ENABLE_NLS
729static void localise_config(struct ConfigSet *cs)
730{
731 struct Buffer *value = buf_pool_get();
732 struct HashElemArray hea = get_elem_list(NeoMutt->sub->cs, GEL_ALL_CONFIG);
733 struct HashElem **hep = NULL;
734
735 ARRAY_FOREACH(hep, &hea)
736 {
737 struct HashElem *he = *hep;
738 if (!(he->type & D_L10N_STRING))
739 continue;
740
741 buf_reset(value);
742 cs_he_initial_get(cs, he, value);
743
744 // Lookup the translation
745 const char *l10n = gettext(buf_string(value));
746 config_he_set_initial(cs, he, l10n);
747 }
748
749 ARRAY_FREE(&hea);
750 buf_pool_release(&value);
751}
752#endif
753
759static int start_curses(void)
760{
761 km_init(); /* must come before mutt_init */
762
763 /* should come before initscr() so that ncurses 4.2 doesn't try to install
764 * its own SIGWINCH handler */
766
767 if (!initscr())
768 {
769 mutt_error(_("Error initializing terminal"));
770 return 1;
771 }
772
773 colors_init();
774 keypad(stdscr, true);
775 cbreak();
776 noecho();
777 nonl();
778 typeahead(-1); /* simulate smooth scrolling */
779 meta(stdscr, true);
781 /* Now that curses is set up, we drop back to normal screen mode.
782 * This simplifies displaying error messages to the user.
783 * The first call to refresh() will swap us back to curses screen mode. */
784 endwin();
785 return 0;
786}
787
791static void init_locale(void)
792{
793 setlocale(LC_ALL, "");
794
795#ifdef ENABLE_NLS
796 const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
797 if (domdir)
798 bindtextdomain(PACKAGE, domdir);
799 else
800 bindtextdomain(PACKAGE, MUTTLOCALEDIR);
801 textdomain(PACKAGE);
802#endif
803#ifndef LOCALES_HACK
804 /* Do we have a locale definition? */
805 if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
806 {
807 OptLocales = true;
808 }
809#endif
810}
811
819static bool get_user_info(struct ConfigSet *cs)
820{
821 const char *shell = mutt_str_getenv("SHELL");
822
823 /* Get some information about the user */
824 struct passwd *pw = getpwuid(getuid());
825 if (pw)
826 {
827 if (!NeoMutt->username)
828 NeoMutt->username = mutt_str_dup(pw->pw_name);
829 if (!NeoMutt->home_dir)
830 NeoMutt->home_dir = mutt_str_dup(pw->pw_dir);
831 if (!shell)
832 shell = pw->pw_shell;
833 }
834
835 if (!NeoMutt->username)
836 {
837 mutt_error(_("unable to determine username"));
838 return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
839 }
840
841 if (!NeoMutt->home_dir)
842 {
843 mutt_error(_("unable to determine home directory"));
844 return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
845 }
846
847 if (shell)
848 config_str_set_initial(cs, "shell", shell);
849
850 return true;
851}
852
860static void log_translation(void)
861{
862 const char *header = ""; // Do not merge these two lines
863 header = _(header); // otherwise the .po files will end up badly ordered
864 const char *label = "Language:"; // the start of the lookup/needle
865 const char *lang = mutt_istr_find(header, label);
866 int len = 64;
867 if (lang)
868 {
869 lang += strlen(label); // skip label
870 SKIPWS(lang);
871 char *nl = strchr(lang, '\n');
872 if (nl)
873 len = (nl - lang);
874 }
875 else
876 {
877 lang = "NONE";
878 }
879
880 mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
881}
882
886static void log_gui(void)
887{
888 const char *term = mutt_str_getenv("TERM");
889 const char *color_term = mutt_str_getenv("COLORTERM");
890 bool true_color = false;
891#ifdef NEOMUTT_DIRECT_COLORS
892 true_color = true;
893#endif
894
895 mutt_debug(LL_DEBUG1, "GUI:\n");
896 mutt_debug(LL_DEBUG1, " Curses: %s\n", curses_version());
897 mutt_debug(LL_DEBUG1, " COLORS=%d\n", COLORS);
898 mutt_debug(LL_DEBUG1, " COLOR_PAIRS=%d\n", COLOR_PAIRS);
899 mutt_debug(LL_DEBUG1, " TERM=%s\n", NONULL(term));
900 mutt_debug(LL_DEBUG1, " COLORTERM=%s\n", NONULL(color_term));
901 mutt_debug(LL_DEBUG1, " True color support: %s\n", true_color ? "YES" : "NO");
902 mutt_debug(LL_DEBUG1, " Screen: %dx%d\n", RootWindow->state.cols,
903 RootWindow->state.rows);
904}
905
910{
911 static time_t last_run = 0;
912
913 if (nc->event_type != NT_TIMEOUT)
914 return 0;
915
916 const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
917 if (c_timeout <= 0)
918 goto done;
919
920 time_t now = mutt_date_now();
921 if (now < (last_run + c_timeout))
922 goto done;
923
924 // Limit hook to running under the Index or Pager
926 struct MuttWindow *dlg = dialog_find(focus);
927 if (!dlg || (dlg->type != WT_DLG_INDEX))
928 goto done;
929
930 last_run = now;
932
933done:
934 mutt_debug(LL_DEBUG5, "timeout done\n");
935 return 0;
936}
937
943static bool show_help(struct CliHelp *help)
944{
945 if (!help->is_set)
946 return true;
947
949
950 const bool tty = isatty(STDOUT_FILENO);
951
952 if (help->help)
953 {
954 show_cli(help->mode, tty);
955 }
956 else if (help->license)
957 {
959 }
960 else
961 {
962 print_version(stdout, tty);
963 }
964
965 return false; // Stop
966}
967
974static bool init_logging(struct CliShared *shared, struct ConfigSet *cs)
975{
976 if (!shared->is_set)
977 return true;
978
979 if (!buf_is_empty(&shared->log_file))
980 config_str_set_initial(cs, "debug_file", buf_string(&shared->log_file));
981
982 if (!buf_is_empty(&shared->log_level))
983 {
984 const char *dlevel = buf_string(&shared->log_level);
985 short num = 0;
986 if (!mutt_str_atos_full(dlevel, &num) || (num < LL_MESSAGE) || (num >= LL_MAX))
987 {
988 mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
989 return false;
990 }
991
992 config_str_set_initial(cs, "debug_level", dlevel);
993 }
994
995 return true;
996}
997
1003static void init_nntp(struct Buffer *server, struct ConfigSet *cs)
1004{
1005 const char *cli_nntp = NULL;
1006 if (!buf_is_empty(server))
1007 cli_nntp = buf_string(server);
1008
1009 /* "$news_server" precedence: command line, config file, environment, system file */
1010 if (cli_nntp)
1011 cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
1012
1013 if (!cli_nntp)
1014 cli_nntp = mutt_str_getenv("NNTPSERVER");
1015
1016 if (!cli_nntp)
1017 {
1018 char buf[1024] = { 0 };
1019 cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
1020 }
1021
1022 if (cli_nntp)
1023 config_str_set_initial(cs, "news_server", cli_nntp);
1024}
1025
1032static bool dump_info(struct CliInfo *ci, struct ConfigSet *cs)
1033{
1034 if (!ci->is_set)
1035 return true;
1036
1037 if (ci->dump_config || !ARRAY_EMPTY(&ci->queries))
1038 {
1039 const bool tty = isatty(STDOUT_FILENO);
1040
1042 if (tty)
1043 cdflags |= CS_DUMP_LINK_DOCS;
1044 if (ci->hide_sensitive)
1045 cdflags |= CS_DUMP_HIDE_SENSITIVE;
1046 if (ci->show_help)
1047 cdflags |= CS_DUMP_SHOW_DOCS;
1048
1049 struct HashElemArray hea = ARRAY_HEAD_INITIALIZER;
1050 if (ci->dump_config)
1051 {
1053 hea = get_elem_list(cs, gel_flags);
1054 }
1055 else
1056 {
1057 get_elem_queries(&ci->queries, &hea);
1058 }
1059
1060 dump_config(cs, &hea, cdflags, stdout);
1061 ARRAY_FREE(&hea);
1062 }
1063 else if (!ARRAY_EMPTY(&ci->alias_queries))
1064 {
1065 const char **cp = NULL;
1067 {
1068 struct AddressList *al = alias_lookup(*cp);
1069 if (al)
1070 {
1071 /* output in machine-readable form */
1072 mutt_addrlist_to_intl(al, NULL);
1073 struct Buffer *buf = buf_pool_get();
1074 mutt_addrlist_write(al, buf, false);
1075 printf("%s\n", buf_string(buf));
1076 buf_pool_release(&buf);
1077 }
1078 else
1079 {
1080 printf("%s\n", NONULL(*cp)); // TEST19: neomutt -A unknown
1081 }
1082 }
1083 }
1084
1085 return false; // Stop
1086}
1087
1096int main(int argc, char *argv[], char *envp[])
1097{
1098 struct Email *e = NULL;
1099 SendFlags sendflags = SEND_NO_FLAGS;
1100 int rc = 1;
1101 bool repeat_error = false;
1102 struct Buffer *expanded_infile = buf_pool_get();
1103 struct Buffer *tempfile = buf_pool_get();
1104 struct ConfigSet *cs = NULL;
1105 struct CommandLine *cli = command_line_new();
1106
1108
1109 /* sanity check against stupid administrators */
1110 if (getegid() != getgid())
1111 {
1112 mutt_error("%s: I don't want to run with privileges!", (argc != 0) ? argv[0] : "neomutt");
1113 goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
1114 }
1115
1116 init_locale();
1117 OptGui = true;
1118
1119 cs = cs_new(500);
1120 if (!cs)
1121 goto main_curses;
1122
1123 NeoMutt = neomutt_new(cs);
1124
1125 NeoMutt->env = envlist_init(envp);
1128
1129 init_config(cs);
1130
1131 cli_parse(argc, argv, cli);
1132
1133 if (!show_help(&cli->help))
1134 goto main_ok;
1135
1136 // Change the current umask, and save the original one
1137 NeoMutt->user_default_umask = umask(077);
1138 subjrx_init();
1139 attach_init();
1141
1142#ifdef USE_DEBUG_NOTIFY
1144#endif
1145
1146 if (!get_user_info(cs))
1147 goto main_exit;
1148
1149 reset_tilde(cs);
1150#ifdef ENABLE_NLS
1151 localise_config(cs);
1152#endif
1153
1154 if (!init_logging(&cli->shared, cs))
1155 goto main_exit;
1156
1157 mutt_log_prep();
1160 mutt_debug(LL_DEBUG1, "user's umask %03o\n", NeoMutt->user_default_umask);
1161 mutt_debug(LL_DEBUG3, "umask set to 077\n");
1162
1163 /* Check for a batch send. */
1164 if (!isatty(STDIN_FILENO) || !ARRAY_EMPTY(&cli->info.queries) ||
1166 {
1167 OptGui = false;
1168 sendflags |= SEND_BATCH;
1171 }
1172
1173 /* Check to make sure stdout is available in curses mode. */
1174 if (OptGui && !isatty(STDOUT_FILENO))
1175 goto main_curses;
1176
1177 /* This must come before mutt_init() because curses needs to be started
1178 * before calling the init_pair() function to set the color scheme. */
1179 if (OptGui)
1180 {
1181 int crc = start_curses();
1182 if (crc != 0)
1183 goto main_curses; // TEST08: can't test -- fake term?
1184 }
1185
1186 /* Always create the mutt_windows because batch mode has some shared code
1187 * paths that end up referencing them. */
1188 rootwin_new();
1189
1190 if (OptGui)
1191 {
1192 /* check whether terminal status is supported (must follow curses init) */
1195 log_gui();
1196 }
1197
1199 alias_init();
1200 commands_init();
1201 hooks_init();
1203 imap_init();
1204#ifdef USE_LUA
1205 mutt_lua_init();
1206#endif
1208
1209 menu_init();
1210 sb_init();
1211#ifdef USE_NOTMUCH
1212 nm_init();
1213#endif
1214
1215 /* set defaults and read init files */
1216 int rc2 = mutt_init(cs, &cli->shared.log_level, &cli->shared.log_file,
1218 &cli->shared.commands);
1219 if (rc2 != 0)
1220 goto main_curses;
1221
1224
1225#ifdef USE_NOTMUCH
1226 const bool c_virtual_spool_file = cs_subset_bool(NeoMutt->sub, "virtual_spool_file");
1227 if (c_virtual_spool_file)
1228 {
1229 /* Find the first virtual folder and open it */
1230 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
1232 struct MailboxNode *mp = STAILQ_FIRST(&ml);
1233 if (mp)
1234 cs_str_string_set(cs, "spool_file", mailbox_path(mp->mailbox), NULL);
1236 }
1237#endif
1238
1240
1241 init_nntp(&cli->tui.nntp_server, cs);
1242
1243 /* Initialize crypto backends. */
1244 crypt_init();
1245
1246 if (!buf_is_empty(&cli->shared.mbox_type) &&
1247 !config_str_set_initial(cs, "mbox_type", buf_string(&cli->shared.mbox_type)))
1248 {
1249 goto main_curses;
1250 }
1251
1252 if (!dump_info(&cli->info, cs))
1253 goto main_ok;
1254
1255 if (OptGui)
1256 {
1258 clear();
1262 }
1263
1264#ifdef USE_AUTOCRYPT
1265 /* Initialize autocrypt after curses messages are working,
1266 * because of the initial account setup screens. */
1267 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
1268 if (c_autocrypt)
1269 mutt_autocrypt_init(!(sendflags & SEND_BATCH));
1270#endif
1271
1272 /* Create the `$folder` directory if it doesn't exist. */
1273 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1274 if (OptGui && c_folder)
1275 {
1276 struct stat st = { 0 };
1277 struct Buffer *fpath = buf_pool_get();
1278
1279 buf_strcpy(fpath, c_folder);
1280 buf_expand_path(fpath);
1281 bool skip = false;
1282 /* we're not connected yet - skip mail folder creation */
1283 skip |= (imap_path_probe(buf_string(fpath), NULL) == MUTT_IMAP);
1284 skip |= (pop_path_probe(buf_string(fpath), NULL) == MUTT_POP);
1285 skip |= (nntp_path_probe(buf_string(fpath), NULL) == MUTT_NNTP);
1286 if (!skip && (stat(buf_string(fpath), &st) == -1) && (errno == ENOENT))
1287 {
1288 char msg2[256] = { 0 };
1289 snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
1290 if (query_yesorno(msg2, MUTT_YES) == MUTT_YES)
1291 {
1292 if ((mkdir(buf_string(fpath), 0700) == -1) && (errno != EEXIST))
1293 mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
1294 }
1295 }
1296 buf_pool_release(&fpath);
1297 }
1298
1299 StartupComplete = true;
1300
1305
1306 if (cli->tui.start_postponed)
1307 {
1308 if (OptGui)
1309 mutt_flushinp();
1310 if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
1311 rc = 0;
1312 // TEST23: neomutt -p (postponed message, cancel)
1313 // TEST24: neomutt -p (no postponed message)
1315 repeat_error = true;
1316 goto main_curses;
1317 }
1318 else if (cli->send.is_set)
1319 {
1320 FILE *fp_in = NULL;
1321 FILE *fp_out = NULL;
1322 const char *infile = NULL;
1323 char *bodytext = NULL;
1324 const char *bodyfile = NULL;
1325 int rv = 0;
1326
1327 if (OptGui)
1328 mutt_flushinp();
1329
1330 e = email_new();
1331 e->env = mutt_env_new();
1332
1333 const char **cp = NULL;
1334 ARRAY_FOREACH(cp, &cli->send.bcc_list)
1335 {
1336 mutt_addrlist_parse(&e->env->bcc, *cp);
1337 }
1338
1339 ARRAY_FOREACH(cp, &cli->send.cc_list)
1340 {
1341 mutt_addrlist_parse(&e->env->cc, *cp);
1342 }
1343
1344 ARRAY_FOREACH(cp, &cli->send.addresses)
1345 {
1346 if (url_check_scheme(*cp) == U_MAILTO)
1347 {
1348 if (!mutt_parse_mailto(e->env, &bodytext, *cp))
1349 {
1350 mutt_error(_("Failed to parse mailto: link"));
1351 email_free(&e);
1352 goto main_curses; // TEST25: neomutt mailto:?
1353 }
1354 }
1355 else
1356 {
1357 mutt_addrlist_parse(&e->env->to, *cp);
1358 }
1359 }
1360
1361 const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
1362 if (buf_is_empty(&cli->send.draft_file) && c_auto_edit &&
1363 TAILQ_EMPTY(&e->env->to) && TAILQ_EMPTY(&e->env->cc))
1364 {
1365 mutt_error(_("No recipients specified"));
1366 email_free(&e);
1367 goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
1368 }
1369
1370 if (!buf_is_empty(&cli->send.subject))
1371 {
1372 /* prevent header injection */
1375 }
1376
1377 if (!buf_is_empty(&cli->send.draft_file))
1378 {
1379 infile = buf_string(&cli->send.draft_file);
1380 }
1381 else if (!buf_is_empty(&cli->send.include_file))
1382 {
1383 infile = buf_string(&cli->send.include_file);
1384 }
1385 else
1386 {
1387 cli->send.edit_infile = false;
1388 }
1389
1390 if (infile || bodytext)
1391 {
1392 /* Prepare fp_in and expanded_infile. */
1393 if (infile)
1394 {
1395 if (mutt_str_equal("-", infile))
1396 {
1397 if (cli->send.edit_infile)
1398 {
1399 mutt_error(_("Can't use -E flag with stdin"));
1400 email_free(&e);
1401 goto main_curses; // TEST27: neomutt -E -H -
1402 }
1403 fp_in = stdin;
1404 }
1405 else
1406 {
1407 buf_strcpy(expanded_infile, infile);
1408 buf_expand_path(expanded_infile);
1409 fp_in = mutt_file_fopen(buf_string(expanded_infile), "r");
1410 if (!fp_in)
1411 {
1412 mutt_perror("%s", buf_string(expanded_infile));
1413 email_free(&e);
1414 goto main_curses; // TEST28: neomutt -E -H missing
1415 }
1416 }
1417 }
1418
1419 if (cli->send.edit_infile)
1420 {
1421 /* If editing the infile, keep it around afterwards so
1422 * it doesn't get unlinked, and we can rebuild the draft_file */
1423 sendflags |= SEND_NO_FREE_HEADER;
1424 }
1425 else
1426 {
1427 /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1428 * Note: stdin is always copied to a tempfile, ensuring draft_file
1429 * can stat and get the correct st_size below. */
1430 buf_mktemp(tempfile);
1431
1432 fp_out = mutt_file_fopen(buf_string(tempfile), "w");
1433 if (!fp_out)
1434 {
1435 mutt_file_fclose(&fp_in);
1436 mutt_perror("%s", buf_string(tempfile));
1437 email_free(&e);
1438 goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1439 }
1440 if (fp_in)
1441 {
1442 mutt_file_copy_stream(fp_in, fp_out);
1443 if (fp_in == stdin)
1444 sendflags |= SEND_CONSUMED_STDIN;
1445 else
1446 mutt_file_fclose(&fp_in);
1447 }
1448 else if (bodytext)
1449 {
1450 fputs(bodytext, fp_out);
1451 }
1452 mutt_file_fclose(&fp_out);
1453
1454 fp_in = mutt_file_fopen(buf_string(tempfile), "r");
1455 if (!fp_in)
1456 {
1457 mutt_perror("%s", buf_string(tempfile));
1458 email_free(&e);
1459 goto main_curses; // TEST30: can't test
1460 }
1461 }
1462
1463 /* Parse the draft_file into the full Email/Body structure.
1464 * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1465 * our e->body. */
1466 if (!buf_is_empty(&cli->send.draft_file))
1467 {
1468 struct Envelope *opts_env = e->env;
1469 struct stat st = { 0 };
1470
1471 sendflags |= SEND_DRAFT_FILE;
1472
1473 /* Set up a tmp Email with just enough information so that
1474 * mutt_prepare_template() can parse the message in fp_in. */
1475 struct Email *e_tmp = email_new();
1476 e_tmp->offset = 0;
1477 e_tmp->body = mutt_body_new();
1478 if (fstat(fileno(fp_in), &st) != 0)
1479 {
1480 mutt_perror("%s", buf_string(&cli->send.draft_file));
1481 email_free(&e);
1482 email_free(&e_tmp);
1483 goto main_curses; // TEST31: can't test
1484 }
1485 e_tmp->body->length = st.st_size;
1486
1487 if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1488 {
1489 mutt_error(_("Can't parse message template: %s"),
1490 buf_string(&cli->send.draft_file));
1491 email_free(&e);
1492 email_free(&e_tmp);
1493 goto main_curses;
1494 }
1495
1496 /* Scan for neomutt header to set `$resume_draft_files` */
1497 struct ListNode *tmp = NULL;
1498 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1499 struct ListNode *np = NULL;
1500 STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1501 {
1502 if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1503 {
1504 if (c_resume_edited_draft_files)
1505 cs_str_native_set(cs, "resume_draft_files", true, NULL);
1506
1507 STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1508 FREE(&np->data);
1509 FREE(&np);
1510 }
1511 }
1512
1513 mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1514 mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1515 mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1516 if (opts_env->subject)
1517 mutt_env_set_subject(e->env, opts_env->subject);
1518
1519 mutt_env_free(&opts_env);
1520 email_free(&e_tmp);
1521 }
1522 else if (cli->send.edit_infile)
1523 {
1524 /* Editing the include_file: pass it directly in.
1525 * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1526 bodyfile = buf_string(expanded_infile);
1527 }
1528 else
1529 {
1530 // For bodytext and unedited include_file: use the tempfile.
1531 bodyfile = buf_string(tempfile);
1532 }
1533
1534 mutt_file_fclose(&fp_in);
1535 }
1536
1537 FREE(&bodytext);
1538
1539 if (!ARRAY_EMPTY(&cli->send.attach))
1540 {
1541 struct Body *b = e->body;
1542
1543 while (b && b->next)
1544 b = b->next;
1545
1546 ARRAY_FOREACH(cp, &cli->send.attach)
1547 {
1548 if (b)
1549 {
1551 b = b->next;
1552 }
1553 else
1554 {
1556 e->body = b;
1557 }
1558 if (!b)
1559 {
1560 mutt_error(_("%s: unable to attach file"), *cp);
1561 email_free(&e);
1562 goto main_curses; // TEST32: neomutt john@example.com -a missing
1563 }
1564 }
1565 }
1566
1567 rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1568 /* We WANT the "Mail sent." and any possible, later error */
1570 if (ErrorBufMessage)
1571 mutt_message("%s", ErrorBuf);
1572
1573 if (cli->send.edit_infile)
1574 {
1575 if (!buf_is_empty(&cli->send.draft_file))
1576 {
1577 if (truncate(buf_string(expanded_infile), 0) == -1)
1578 {
1579 mutt_perror("%s", buf_string(expanded_infile));
1580 email_free(&e);
1581 goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1582 }
1583 fp_out = mutt_file_fopen(buf_string(expanded_infile), "a");
1584 if (!fp_out)
1585 {
1586 mutt_perror("%s", buf_string(expanded_infile));
1587 email_free(&e);
1588 goto main_curses; // TEST34: can't test
1589 }
1590
1591 /* If the message was sent or postponed, these will already
1592 * have been done. */
1593 if (rv < 0)
1594 {
1595 if (e->body->next)
1596 e->body = mutt_make_multipart(e->body);
1598 mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1599 mutt_env_to_intl(e->env, NULL, NULL);
1600 }
1601
1602 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1604 c_crypt_protected_headers_read &&
1606 NeoMutt->sub);
1607 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1608 if (c_resume_edited_draft_files)
1609 fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1610 fputc('\n', fp_out);
1611 if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1612 {
1613 mutt_file_fclose(&fp_out);
1614 email_free(&e);
1615 goto main_curses; // TEST35: can't test
1616 }
1617 mutt_file_fclose(&fp_out);
1618 }
1619
1620 email_free(&e);
1621 }
1622
1623 /* !edit_infile && draft_file will leave the tempfile around */
1624 if (!buf_is_empty(tempfile))
1625 unlink(buf_string(tempfile));
1626
1628
1629 if (rv != 0)
1630 goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1631 }
1632 else if (sendflags & SEND_BATCH)
1633 {
1634 /* This guards against invoking `neomutt < /dev/null` and accidentally
1635 * sending an email due to a my_hdr or other setting. */
1636 mutt_error(_("No recipients specified"));
1637 goto main_curses;
1638 }
1639 else
1640 {
1641 struct Buffer *folder = &cli->tui.folder;
1642 bool explicit_folder = !buf_is_empty(folder);
1643
1644 if (cli->tui.start_new_mail)
1645 {
1646 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1647 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1649 if (mutt_mailbox_check(NULL, csflags) == 0)
1650 {
1651 mutt_message(_("No mailbox with new mail"));
1652 repeat_error = true;
1653 goto main_curses; // TEST37: neomutt -Z (no new mail)
1654 }
1655 buf_reset(folder);
1656 mutt_mailbox_next(NULL, folder);
1657 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1658 }
1659 else if (cli->tui.start_nntp || cli->tui.start_browser)
1660 {
1661 if (cli->tui.start_nntp)
1662 {
1663 const char *const c_news_server = cs_subset_string(NeoMutt->sub, "news_server");
1664 OptNews = true;
1665 CurrentNewsSrv = nntp_select_server(NULL, c_news_server, false);
1666 if (!CurrentNewsSrv)
1667 goto main_curses; // TEST38: neomutt -G (unset news_server)
1668 }
1669 else if (TAILQ_EMPTY(&NeoMutt->accounts))
1670 {
1671 mutt_error(_("No incoming mailboxes defined"));
1672 goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1673 }
1674 buf_reset(folder);
1675 dlg_browser(folder, MUTT_SEL_FOLDER | MUTT_SEL_MAILBOX, NULL, NULL, NULL);
1676 if (buf_is_empty(folder))
1677 {
1678 goto main_ok; // TEST40: neomutt -y (quit selection)
1679 }
1680 }
1681
1682 if (buf_is_empty(folder))
1683 {
1684 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1685 if (c_spool_file)
1686 {
1687 // Check if `$spool_file` corresponds a mailboxes' description.
1688 struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1689 if (m_desc)
1690 buf_strcpy(folder, m_desc->realpath);
1691 else
1692 buf_strcpy(folder, c_spool_file);
1693 }
1694 else if (c_folder)
1695 {
1696 buf_strcpy(folder, c_folder);
1697 }
1698 /* else no folder */
1699 }
1700
1701 if (OptNews)
1702 {
1703 OptNews = false;
1704 buf_alloc(folder, PATH_MAX);
1705 nntp_expand_path(folder->data, folder->dsize, &CurrentNewsSrv->conn->account);
1706 }
1707 else
1708 {
1709 buf_expand_path(folder);
1710 }
1711
1714
1715 if (cli->tui.start_any_mail || cli->tui.start_new_mail)
1716 {
1717 /* check to see if there are any messages in the folder */
1718 switch (mx_path_is_empty(folder))
1719 {
1720 case -1:
1721 mutt_perror("%s", buf_string(folder));
1722 goto main_curses; // TEST41: neomutt -z -f missing
1723 case 1:
1724 mutt_error(_("Mailbox is empty"));
1725 goto main_curses; // TEST42: neomutt -z -f /dev/null
1726 }
1727 }
1728
1729 struct Mailbox *m_cur = mailbox_find(buf_string(folder));
1730 // Take a copy of the name just in case the hook alters m_cur
1731 const char *name = m_cur ? mutt_str_dup(m_cur->name) : NULL;
1733 FREE(&name);
1735 mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1737
1739 window_redraw(NULL);
1740
1741 repeat_error = true;
1742 struct Mailbox *m = mx_resolve(buf_string(folder));
1743 const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1744 if (!mx_mbox_open(m, (cli->tui.read_only || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1745 {
1746 if (m->account)
1748
1749 mailbox_free(&m);
1750 mutt_error(_("Unable to open mailbox %s"), buf_string(folder));
1751 repeat_error = false;
1752 }
1753 if (m || !explicit_folder)
1754 {
1755 struct MuttWindow *dlg = index_pager_init();
1756 dialog_push(dlg);
1757
1759 m = dlg_index(dlg, m);
1761 mailbox_free(&m);
1762
1763 dialog_pop();
1764 mutt_window_free(&dlg);
1766 repeat_error = false;
1767 }
1769#ifdef USE_SASL_CYRUS
1771#endif
1772#ifdef USE_SASL_GNU
1774#endif
1775#ifdef USE_AUTOCRYPT
1777#endif
1778 // TEST43: neomutt (no change to mailbox)
1779 // TEST44: neomutt (change mailbox)
1780 }
1781
1782main_ok:
1783 rc = 0;
1784main_curses:
1785 mutt_endwin();
1787 /* Repeat the last message to the user */
1788 if (repeat_error && ErrorBufMessage)
1789 puts(ErrorBuf);
1790main_exit:
1791 if (NeoMutt && NeoMutt->sub)
1792 {
1797 }
1799 buf_pool_release(&expanded_infile);
1800 buf_pool_release(&tempfile);
1804 if (NeoMutt)
1808 menu_cleanup();
1809 crypt_cleanup();
1811 command_line_free(&cli);
1812
1814
1815 alias_cleanup();
1816 sb_cleanup();
1817
1823
1826
1827 /* Lists of strings */
1836
1838
1840 FREE(&LastFolder);
1842
1844
1846
1849
1851 if (NeoMutt)
1853
1861 cs_free(&cs);
1863 mutt_log_stop();
1864 return rc;
1865}
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.
void alias_cleanup(void)
Clean up the Alias globals.
Definition alias.c:719
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition alias.c:277
void alias_init(void)
Set up the Alias globals.
Definition alias.c:711
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.
#define ARRAY_SET(head, idx, elem)
Set an element in the array.
Definition array.h:123
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:156
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:214
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
void attach_init(void)
Set up the attachments lists.
Definition commands.c:106
void attach_cleanup(void)
Free the attachments lists.
Definition commands.c:92
GUI display the mailboxes in a side panel.
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
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
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition buffer.c:622
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
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition buffer.c:509
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
Parse the Command Line.
bool cli_parse(int argc, char *const *argv, struct CommandLine *cli)
Parse the Command Line.
Definition parse.c:93
Color and attribute parsing.
void colors_cleanup(void)
Cleanup all the colours.
Definition color.c:84
void colors_init(void)
Initialize colours.
Definition color.c:49
@ MT_COLOR_NORMAL
Plain text.
Definition color.h:54
CommandResult
Error codes for command_t parse functions.
Definition command.h:35
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:36
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition command.h:37
void source_stack_cleanup(void)
Free memory from the stack used for the source command.
Definition commands.c:1671
bool commands_init(void)
Initialize commands array and register default commands.
Definition commands.c:1748
int source_rc(const char *rcfile_path, struct Buffer *err)
Read an initialization file.
Definition commands.c:219
Functions to parse commands in a config file.
void mutt_comp_init(void)
Setup Compressed Mailbox commands.
Definition compress.c:90
Compressed mbox local mailbox type.
bool dump_config(struct ConfigSet *cs, struct HashElemArray *hea, ConfigDumpFlags flags, FILE *fp)
Write all the config to a file.
Definition dump.c:196
#define CS_DUMP_HIDE_SENSITIVE
Obscure sensitive information like passwords.
Definition dump.h:38
uint16_t ConfigDumpFlags
Flags for dump_config(), e.g. CS_DUMP_ONLY_CHANGED.
Definition dump.h:35
#define CS_DUMP_LINK_DOCS
Link to the online docs.
Definition dump.h:47
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition dump.h:36
#define CS_DUMP_SHOW_DOCS
Show one-liner documentation for the config item.
Definition dump.h:46
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
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
bool config_str_set_initial(struct ConfigSet *cs, const char *name, const char *value)
Set the initial value of a Config Option.
Definition helpers.c:332
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
bool config_he_set_initial(struct ConfigSet *cs, struct HashElem *he, const char *value)
Set the initial value of a Config Option.
Definition helpers.c:312
Convenience wrapper for the config headers.
int cs_str_initial_get(const struct ConfigSet *cs, const char *name, struct Buffer *result)
Get the initial, or parent, value of a config item.
Definition set.c:593
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition set.c:175
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:446
struct ConfigSet * cs_new(size_t size)
Create a new Config Set.
Definition set.c:127
int cs_str_string_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition set.c:668
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:788
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:557
bool StartupComplete
When the config has been read.
Definition address.c:13
void config_cache_cleanup(void)
Cleanup the cache of charset config variables.
Connection Library.
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition account.c:98
void commands_clear(struct CommandArray *ca)
Clear an Array of Commands.
Definition command.c:70
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
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:223
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:51
@ 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:1101
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
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
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:196
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.
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
struct ReplaceList SpamList
List of regexes to match subscribed mailing lists.
Definition globals.c:46
struct RegexList SubscribedLists
List of header patterns to unignore (see)
Definition globals.c:48
struct RegexList UnSubscribedLists
Definition globals.c:54
struct RegexList UnMailLists
List of regexes to exclude false matches in SubscribedLists.
Definition globals.c:52
struct RegexList MailLists
List of permitted fields in a mailto: url.
Definition globals.c:40
struct ListHead MailToAllow
List of regexes to identify non-spam emails.
Definition globals.c:42
struct ListHead Ignore
List of regexes to match mailing lists.
Definition globals.c:38
struct RegexList NoSpamList
List of regexes and patterns to match spam emails.
Definition globals.c:44
struct ListHead UnIgnore
List of regexes to exclude false matches in MailLists.
Definition globals.c:50
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:1753
void mutt_filter_commandline_header_value(char *header)
Sanitise characters in a header value.
Definition parse.c:92
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 init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition extended.c:113
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:225
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:685
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
Definition file.c:1299
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:851
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition file.h:40
int getdnsdomainname(struct Buffer *result)
Lookup the host's name using DNS.
Definition getdomain.c:124
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:64
char * LastFolder
Previously selected mailbox.
Definition globals.c:40
char * ShortHostname
Short version of the hostname.
Definition globals.c:37
struct ListHead MimeLookupList
List of mime types that that shouldn't use the mailcap entry.
Definition globals.c:47
struct ListHead AlternativeOrderList
List of preferred mime types to display.
Definition globals.c:44
struct ListHead AutoViewList
List of mime types to auto view.
Definition globals.c:45
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:39
bool OptGui
(pseudo) when the gui (and curses) are started
Definition globals.c:59
struct ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition globals.c:49
struct ListHead HeaderOrderList
List of header fields in the order they should be displayed.
Definition globals.c:46
Global variables.
void mutt_grouplist_init(void)
Initialize the GroupList singleton.
Definition group.c:95
void mutt_grouplist_cleanup(void)
Free GroupList singleton resource.
Definition group.c:107
enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'my_hdr' command - Implements Command::parse() -.
Definition commands.c:849
void dlg_browser(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file -.
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition dlg_index.c:1100
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:378
#define mutt_warning(...)
Definition logging2.h:91
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:421
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 -.
#define mutt_error(...)
Definition logging2.h:93
#define mutt_message(...)
Definition logging2.h:92
#define mutt_debug(LEVEL,...)
Definition logging2.h:90
#define mutt_perror(...)
Definition logging2.h:94
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox?
Definition nntp.c:2785
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox?
Definition pop.c:1156
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2349
int main_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition init.c:147
int main_hist_observer(struct NotifyCallback *nc)
Notification that a Config Variable has change - Implements observer_t -.
Definition history.c:701
static int main_timeout_observer(struct NotifyCallback *nc)
Notification that a timeout has occurred - Implements observer_t -.
Definition main.c:909
int main_log_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
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_hist_read_file(void)
Read the History from a file.
Definition history.c:592
void mutt_hist_init(void)
Create a set of empty History ring buffers.
Definition history.c:464
void mutt_hist_cleanup(void)
Free all the history lists.
Definition history.c:437
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_delete_hooks(HookFlags type)
Delete matching hooks.
Definition hook.c:397
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition hook.c:630
void hooks_init(void)
Setup feature commands.
Definition hook.c:1051
Parse and execute user-defined hooks.
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition hook.h:54
#define MUTT_HOOK_NO_FLAGS
No flags are set.
Definition hook.h:36
IMAP network mailbox.
void imap_logout_all(void)
Close all open connections.
Definition imap.c:556
void imap_init(void)
Setup feature commands.
Definition imap.c:95
GUI manage the main index (list of emails)
void km_init(void)
Initialise all the menu keybindings.
Definition init.c:73
void mutt_keys_cleanup(void)
Free the key maps.
Definition init.c:112
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition init.c:125
Manage keymappings.
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
int log_dispatcher_t MuttLogger
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:46
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:48
@ LL_MESSAGE
Log informational message.
Definition logging2.h:43
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:44
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:49
@ LL_MAX
Definition logging2.h:51
static char * find_cfg(const char *home, const char *xdg_cfg_home)
Find a config file.
Definition main.c:241
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition main.c:791
static char * getmailname(void)
Try to retrieve the FQDN from mailname files.
Definition main.c:288
static void localise_config(struct ConfigSet *cs)
Localise some config.
Definition main.c:729
static bool init_logging(struct CliShared *shared, struct ConfigSet *cs)
Initialise the Logging.
Definition main.c:974
static void log_translation(void)
Log the translation being used.
Definition main.c:860
static void log_gui(void)
Log info about the GUI.
Definition main.c:886
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition main.c:706
static void init_nntp(struct Buffer *server, struct ConfigSet *cs)
Initialise the NNTP config.
Definition main.c:1003
static bool show_help(struct CliHelp *help)
Show the Help.
Definition main.c:943
static int start_curses(void)
Start the Curses UI.
Definition main.c:759
static bool dump_info(struct CliInfo *ci, struct ConfigSet *cs)
Show config info.
Definition main.c:1032
static bool get_user_info(struct ConfigSet *cs)
Find the user's name, home and shell.
Definition main.c:819
void show_cli(enum HelpMode mode, bool use_color)
Show Instructions on how to run NeoMutt.
Definition usage.c:332
static bool get_hostname(struct ConfigSet *cs)
Find the Fully-Qualified Domain Name.
Definition main.c:321
static int get_elem_queries(struct StringArray *queries, struct HashElemArray *hea)
Lookup the HashElems for a set of queries.
Definition main.c:675
static int execute_commands(struct StringArray *sa)
Execute a set of NeoMutt commands.
Definition main.c:209
int main(int argc, char *argv[], char *envp[])
Start NeoMutt.
Definition main.c:1096
static int mutt_init(struct ConfigSet *cs, struct Buffer *dlevel, struct Buffer *dfile, bool skip_sys_rc, struct StringArray *user_files, struct StringArray *commands)
Initialise NeoMutt.
Definition main.c:407
bool OptLocales
(pseudo) set if user has valid locale definition
Definition mbyte.c:44
#define countof(x)
Definition memory.h:44
#define FREE(x)
Definition memory.h:62
GUI present the user with a selectable list.
void menu_init(void)
Initialise all the Menus.
Definition menu.c:79
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
char * mutt_ch_get_langinfo_charset(void)
Get the user's choice of character set.
Definition charset.c:486
void mutt_ch_cache_cleanup(void)
Clean up the cached iconv handles and charset strings.
Definition charset.c:1175
void mutt_ch_set_charset(const char *charset)
Update the records for a new character set.
Definition charset.c:1075
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.
void log_queue_empty(void)
Free the contents of the queue.
Definition logging.c:325
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition logging.c:313
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition logging.c:347
#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
void mutt_regexlist_free(struct RegexList *rl)
Free a RegexList object.
Definition regex.c:179
void mutt_replacelist_free(struct ReplaceList *rl)
Free a ReplaceList object.
Definition regex.c:450
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition slist.c:177
void slist_free(struct Slist **ptr)
Free an Slist object.
Definition slist.c:124
int slist_to_buffer(const struct Slist *list, struct Buffer *buf)
Export an Slist to a Buffer.
Definition slist.c:269
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition string.c:382
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:255
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:803
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:523
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:244
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:282
Many unsorted constants and some structs.
#define PATH_MAX
Definition mutt.h:42
void mutt_temp_attachments_cleanup(void)
Delete all temporary attachments.
void init_config(struct ConfigSet *cs)
Initialise the config system.
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.
int mutt_log_start(void)
Enable file logging.
void mutt_log_prep(void)
Prepare to log.
NeoMutt Logging.
void mutt_lua_init(void)
Setup feature commands.
Definition mutt_lua.c:469
Integrated Lua scripting.
int mutt_mailbox_check(struct Mailbox *m_cur, CheckStatsFlags flags)
Check all all Mailboxes for new mail.
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
Mailbox helper functions.
void mutt_signal_init(void)
Initialise the signal handling.
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
struct MuttWindow * window_get_focus(void)
Get the currently focused Window.
@ WT_DLG_INDEX
Index Dialog, dlg_index()
Definition mutt_window.h:87
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition muttlib.c:331
void add_to_stailq(struct ListHead *head, const char *str)
Add a string to a list.
Definition muttlib.c:1038
void buf_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition muttlib.c:121
int mutt_set_xdg_path(enum XdgType type, struct Buffer *buf)
Find an XDG path or its fallback.
Definition muttlib.c:882
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition muttlib.c:314
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:1710
int mx_path_is_empty(struct Buffer *path)
Is the mailbox empty.
Definition mx.c:1257
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:53
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition mxapi.h:40
uint8_t CheckStatsFlags
Flags for mutt_mailbox_check.
Definition mxapi.h:49
API for encryption/signing of emails.
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition neomutt.c:173
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition neomutt.c:196
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:67
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:76
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
Notmuch virtual mailbox type.
void nm_init(void)
Setup feature commands.
Definition notmuch.c:109
struct CommandLine * command_line_new(void)
Create a new CommandLine.
Definition objects.c:105
void command_line_free(struct CommandLine **ptr)
Free a CommandLine.
Definition objects.c:114
HelpMode
Show detailed help.
Definition objects.h:33
Text parsing functions.
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:487
void mutt_prex_cleanup(void)
Cleanup heap memory allocated by compiled regexes.
Definition prex.c:339
Prototypes for many functions.
@ XDG_CONFIG_DIRS
XDG system dir: /etc/xdg.
Definition protos.h:46
@ 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:326
#define STAILQ_REMOVE(head, elm, type, field)
Definition queue.h:441
#define STAILQ_HEAD_INITIALIZER(head)
Definition queue.h:324
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:400
#define TAILQ_EMPTY(head)
Definition queue.h:778
enum CommandResult parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition rc.c:109
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:1489
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:2034
#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_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:606
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition sendlib.c:779
GUI display the mailboxes in a side panel.
void sb_init(void)
Set up the Sidebar.
Definition sidebar.c:204
void sb_cleanup(void)
Clean up the Sidebar.
Definition sidebar.c:220
int endwin(void)
#define NONULL(x)
Definition string2.h:43
#define SKIPWS(ch)
Definition string2.h:51
The body of an email.
Definition body.h:36
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
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
Help Mode Command Line options.
Definition objects.h:64
bool license
-vv Print license
Definition objects.h:68
enum HelpMode mode
Display detailed help.
Definition objects.h:70
bool help
-h Print help
Definition objects.h:66
bool is_set
This struct has been used.
Definition objects.h:65
Info Mode Command Line options.
Definition objects.h:77
bool show_help
-O Show one-liner help
Definition objects.h:81
bool is_set
This struct has been used.
Definition objects.h:78
struct StringArray queries
-Q Query a config option
Definition objects.h:85
struct StringArray alias_queries
-A Lookup an alias
Definition objects.h:84
bool dump_config
-D Dump the config
Definition objects.h:79
bool dump_changed
-DD Dump the changed config
Definition objects.h:80
bool hide_sensitive
-S Hide sensitive config
Definition objects.h:82
struct Buffer draft_file
-H Use this draft file
Definition objects.h:102
bool is_set
This struct has been used.
Definition objects.h:93
struct Buffer include_file
-i Use this include file
Definition objects.h:103
struct StringArray cc_list
-c Add a Cc:
Definition objects.h:99
struct StringArray attach
-a Attach a file
Definition objects.h:97
bool edit_infile
-E Edit the draft/include
Definition objects.h:95
struct StringArray bcc_list
-b Add a Bcc:
Definition objects.h:98
struct StringArray addresses
Send to these addresses.
Definition objects.h:100
struct Buffer subject
-s Use this Subject:
Definition objects.h:104
Shared Command Line options.
Definition objects.h:47
struct Buffer log_level
-d Debug log level
Definition objects.h:56
struct Buffer log_file
-l Debug log file
Definition objects.h:57
struct StringArray commands
-e Run these commands
Definition objects.h:53
bool is_set
This struct has been used.
Definition objects.h:48
bool disable_system
-n Don't read the system config file
Definition objects.h:51
struct StringArray user_files
-F Use these user config files
Definition objects.h:50
struct Buffer mbox_type
-m Set the default Mailbox type
Definition objects.h:54
bool read_only
-R Open Mailbox read-only
Definition objects.h:113
bool start_any_mail
-z Check for Any Mail
Definition objects.h:118
bool start_nntp
-G Open an NNTP Mailbox
Definition objects.h:116
struct Buffer nntp_server
-g Open this NNTP Mailbox
Definition objects.h:121
struct Buffer folder
-f Open this Mailbox
Definition objects.h:120
bool start_postponed
-p Open Postponed emails
Definition objects.h:114
bool start_new_mail
-Z Check for New Mail
Definition objects.h:117
bool start_browser
-y Open the Mailbox Browser
Definition objects.h:115
Command Line options.
Definition objects.h:128
struct CliSend send
Send Mode command line options.
Definition objects.h:132
struct CliShared shared
Shared command line options.
Definition objects.h:129
struct CliHelp help
Help Mode command line options.
Definition objects.h:130
struct CliInfo info
Info Mode command line options.
Definition objects.h:131
struct CliTui tui
Tui Mode command line options.
Definition objects.h:133
Container for lots of config items.
Definition set.h:248
struct Notify * notify
Notifications: NotifyConfig, EventConfig.
Definition subset.h:51
struct ConfigSet * cs
Parent ConfigSet.
Definition subset.h:50
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:44
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition hash.h:45
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
List of Mailboxes.
Definition mailbox.h:166
struct Mailbox * mailbox
Mailbox in the list.
Definition mailbox.h:167
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 MuttWindow * focus
Focused Window.
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Container for Accounts, Notifications.
Definition neomutt.h:43
struct CommandArray commands
NeoMutt commands.
Definition neomutt.h:51
struct Notify * notify_resize
Window resize notifications handler.
Definition neomutt.h:45
char ** env
Private copy of the environment variables.
Definition neomutt.h:55
char * username
User's login name.
Definition neomutt.h:54
struct AccountList accounts
List of all Accounts.
Definition neomutt.h:48
mode_t user_default_umask
User's default file writing permissions (inferred from umask)
Definition neomutt.h:50
char * home_dir
User's home directory.
Definition neomutt.h:53
struct Notify * notify
Notifications handler.
Definition neomutt.h:44
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:47
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
String list.
Definition slist.h:37
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:303
struct HashElemArray get_elem_list(struct ConfigSet *cs, enum GetElemListFlags flags)
Create a sorted list of all config items.
Definition subset.c:81
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition subset.c:193
GetElemListFlags
Flags for get_elem_list()
Definition subset.h:80
@ GEL_CHANGED_CONFIG
Only config that has been changed.
Definition subset.h:82
@ GEL_ALL_CONFIG
All the normal config (no synonyms or deprecated)
Definition subset.h:81
void driver_tags_cleanup(void)
Deinitialize structures used for tags.
Definition tags.c:245
void driver_tags_init(void)
Initialize structures used for tags.
Definition tags.c:233
bool TsSupported
Terminal Setting is supported.
Definition terminal.c:53
bool mutt_ts_capability(void)
Check terminal capabilities.
Definition terminal.c:83
#define buf_mktemp(buf)
Definition tmp.h:33
#define D_SLIST_SEP_COLON
Slist items are colon-separated.
Definition types.h:111
#define D_INTERNAL_DEPRECATED
Config item shouldn't be used any more.
Definition types.h:87
#define D_L10N_STRING
String can be localised.
Definition types.h:81
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition url.c:225
@ U_MAILTO
Url is mailto://.
Definition url.h:45
bool print_copyright(void)
Print copyright message.
Definition version.c:702
bool print_version(FILE *fp, bool use_ansi)
Print system and compile info to a file.
Definition version.c:591
Display version and copyright about NeoMutt.