NeoMutt  2025-01-09-117-gace867
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
127#define GNULIB_defined_setlocale
128
129#include "config.h"
130#include <errno.h>
131#include <limits.h>
132#include <locale.h>
133#include <pwd.h>
134#include <stdbool.h>
135#include <stdint.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 "color/lib.h"
154#include "compmbox/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 "notmuch/lib.h"
163#include "parse/lib.h"
164#include "pop/lib.h"
165#include "postpone/lib.h"
166#include "question/lib.h"
167#include "send/lib.h"
168#include "sidebar/lib.h"
169#include "alternates.h"
170#include "commands.h"
171#include "external.h"
172#include "globals.h"
173#include "hook.h"
174#include "mutt_logging.h"
175#include "mutt_mailbox.h"
176#include "muttlib.h"
177#include "mx.h"
178#include "nntp/adata.h" // IWYU pragma: keep
179#include "protos.h"
180#include "subjectrx.h"
181#include "version.h"
182#ifdef ENABLE_NLS
183#include <libintl.h>
184#endif
185#ifdef USE_AUTOCRYPT
186#include "autocrypt/lib.h"
187#endif
188#if defined(USE_DEBUG_NOTIFY) || defined(USE_DEBUG_BACKTRACE)
189#include "debug/lib.h"
190#endif
191#ifndef DOMAIN
192#include "conn/lib.h"
193#endif
194#ifdef USE_LUA
195#include "mutt_lua.h"
196#endif
197
198bool StartupComplete = false;
199
200// clang-format off
201typedef uint8_t CliFlags;
202#define MUTT_CLI_NO_FLAGS 0
203#define MUTT_CLI_IGNORE (1 << 0)
204#define MUTT_CLI_MAILBOX (1 << 1)
205#define MUTT_CLI_NOSYSRC (1 << 2)
206#define MUTT_CLI_RO (1 << 3)
207#define MUTT_CLI_SELECT (1 << 4)
208#define MUTT_CLI_NEWS (1 << 5)
209// clang-format on
210
217static int execute_commands(struct ListHead *p)
218{
219 int rc = 0;
220 struct Buffer *err = buf_pool_get();
221
222 struct ListNode *np = NULL;
223 STAILQ_FOREACH(np, p, entries)
224 {
225 enum CommandResult rc2 = parse_rc_line(np->data, err);
226 if (rc2 == MUTT_CMD_ERROR)
227 mutt_error(_("Error in command line: %s"), buf_string(err));
228 else if (rc2 == MUTT_CMD_WARNING)
229 mutt_warning(_("Warning in command line: %s"), buf_string(err));
230
231 if ((rc2 == MUTT_CMD_ERROR) || (rc2 == MUTT_CMD_WARNING))
232 {
233 buf_pool_release(&err);
234 return -1;
235 }
236 }
237 buf_pool_release(&err);
238
239 return rc;
240}
241
249static char *find_cfg(const char *home, const char *xdg_cfg_home)
250{
251 const char *names[] = {
252 "neomuttrc",
253 "muttrc",
254 NULL,
255 };
256
257 const char *locations[][2] = {
258 { xdg_cfg_home, "neomutt/" },
259 { xdg_cfg_home, "mutt/" },
260 { home, ".neomutt/" },
261 { home, ".mutt/" },
262 { home, "." },
263 { NULL, NULL },
264 };
265
266 for (int i = 0; locations[i][0] || locations[i][1]; i++)
267 {
268 if (!locations[i][0])
269 continue;
270
271 for (int j = 0; names[j]; j++)
272 {
273 char buf[256] = { 0 };
274
275 snprintf(buf, sizeof(buf), "%s/%s%s", locations[i][0], locations[i][1], names[j]);
276 if (access(buf, F_OK) == 0)
277 return mutt_str_dup(buf);
278 }
279 }
280
281 return NULL;
282}
283
284#ifndef DOMAIN
290static char *getmailname(void)
291{
292 char *mailname = NULL;
293 static const char *mn_files[] = { "/etc/mailname", "/etc/mail/mailname" };
294
295 for (size_t i = 0; i < mutt_array_size(mn_files); i++)
296 {
297 FILE *fp = mutt_file_fopen(mn_files[i], "r");
298 if (!fp)
299 continue;
300
301 size_t len = 0;
302 mailname = mutt_file_read_line(NULL, &len, fp, NULL, MUTT_RL_NO_FLAGS);
303 mutt_file_fclose(&fp);
304 if (mailname && *mailname)
305 break;
306
307 FREE(&mailname);
308 }
309
310 return mailname;
311}
312#endif
313
323static bool get_hostname(struct ConfigSet *cs)
324{
325 const char *short_host = NULL;
326 struct utsname utsname = { 0 };
327
328 const char *const c_hostname = cs_subset_string(NeoMutt->sub, "hostname");
329 if (c_hostname)
330 {
331 short_host = c_hostname;
332 }
333 else
334 {
335 /* The call to uname() shouldn't fail, but if it does, the system is horribly
336 * broken, and the system's networking configuration is in an unreliable
337 * state. We should bail. */
338 if ((uname(&utsname)) == -1)
339 {
340 mutt_perror(_("unable to determine nodename via uname()"));
341 return false; // TEST09: can't test
342 }
343
344 short_host = utsname.nodename;
345 }
346
347 /* some systems report the FQDN instead of just the hostname */
348 char *dot = strchr(short_host, '.');
349 if (dot)
350 ShortHostname = mutt_strn_dup(short_host, dot - short_host);
351 else
352 ShortHostname = mutt_str_dup(short_host);
353
354 // All the code paths from here alloc memory for the fqdn
355 char *fqdn = mutt_str_dup(c_hostname);
356 if (!fqdn)
357 {
358 mutt_debug(LL_DEBUG1, "Setting $hostname\n");
359 /* now get FQDN. Use configured domain first, DNS next, then uname */
360#ifdef DOMAIN
361 /* we have a compile-time domain name, use that for `$hostname` */
362 mutt_str_asprintf(&fqdn, "%s.%s", NONULL(ShortHostname), DOMAIN);
363#else
364 fqdn = getmailname();
365 if (!fqdn)
366 {
367 struct Buffer *domain = buf_pool_get();
368 if (getdnsdomainname(domain) == 0)
369 {
370 mutt_str_asprintf(&fqdn, "%s.%s", NONULL(ShortHostname), buf_string(domain));
371 }
372 else
373 {
374 /* DNS failed, use the nodename. Whether or not the nodename had a '.'
375 * in it, we can use the nodename as the FQDN. On hosts where DNS is
376 * not being used, e.g. small network that relies on hosts files, a
377 * short host name is all that is required for SMTP to work correctly.
378 * It could be wrong, but we've done the best we can, at this point the
379 * onus is on the user to provide the correct hostname if the nodename
380 * won't work in their network. */
381 fqdn = mutt_str_dup(utsname.nodename);
382 }
383 buf_pool_release(&domain);
384 mutt_debug(LL_DEBUG1, "Hostname: %s\n", NONULL(fqdn));
385 }
386#endif
387 }
388
389 if (fqdn)
390 {
391 config_str_set_initial(cs, "hostname", fqdn);
392 FREE(&fqdn);
393 }
394
395 return true;
396}
397
408static int mutt_init(struct ConfigSet *cs, const char *dlevel, const char *dfile,
409 bool skip_sys_rc, struct ListHead *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
416#ifdef NEOMUTT_DIRECT_COLORS
417 /* Test if we run in a terminal which supports direct colours.
418 *
419 * The user/terminal can indicate their capability independent of the
420 * terminfo file by setting the COLORTERM environment variable to "truecolor"
421 * or "24bit" (case sensitive).
422 *
423 * Note: This is to test is less about whether the terminal understands
424 * direct color commands but more about whether ncurses believes it can send
425 * them to the terminal, e.g. ncurses ignores COLORTERM.
426 */
427 if (COLORS == 16777216) // 2^24
428 {
429 /* Ncurses believes the Terminal supports it check the environment variable
430 * to respect the user's choice */
431 const char *env_colorterm = mutt_str_getenv("COLORTERM");
432 if (env_colorterm && (mutt_str_equal(env_colorterm, "truecolor") ||
433 mutt_str_equal(env_colorterm, "24bit")))
434 {
435 config_str_set_initial(cs, "color_directcolor", "yes");
436 }
437 }
438#endif
439
440 /* "$spool_file" precedence: config file, environment */
441 const char *p = mutt_str_getenv("MAIL");
442 if (!p)
443 p = mutt_str_getenv("MAILDIR");
444 if (!p)
445 {
446#ifdef HOMESPOOL
447 buf_concat_path(buf, NONULL(NeoMutt->home_dir), MAILPATH);
448#else
449 buf_concat_path(buf, MAILPATH, NONULL(NeoMutt->username));
450#endif
451 p = buf_string(buf);
452 }
453 config_str_set_initial(cs, "spool_file", p);
454
455 p = mutt_str_getenv("REPLYTO");
456 if (p)
457 {
458 struct Buffer *token = buf_pool_get();
459
460 buf_printf(buf, "Reply-To: %s", p);
461 buf_seek(buf, 0);
462 parse_my_hdr(token, buf, 0, err); /* adds to UserHeader */
463 buf_pool_release(&token);
464 }
465
466 p = mutt_str_getenv("EMAIL");
467 if (p)
468 config_str_set_initial(cs, "from", p);
469
470 /* "$mailcap_path" precedence: config file, environment, code */
471 struct Buffer *mc = buf_pool_get();
472 struct Slist *sl_mc = NULL;
473 const char *env_mc = mutt_str_getenv("MAILCAPS");
474 if (env_mc)
475 {
476 sl_mc = slist_parse(env_mc, D_SLIST_SEP_COLON);
477 }
478 else
479 {
480 cs_str_initial_get(cs, "mailcap_path", mc);
482 buf_reset(mc);
483 }
484 slist_to_buffer(sl_mc, mc);
485 config_str_set_initial(cs, "mailcap_path", buf_string(mc));
486 slist_free(&sl_mc);
487 buf_pool_release(&mc);
488
489 /* "$tmp_dir" precedence: config file, environment, code */
490 const char *env_tmp = mutt_str_getenv("TMPDIR");
491 if (env_tmp)
492 config_str_set_initial(cs, "tmp_dir", env_tmp);
493
494 /* "$visual", "$editor" precedence: config file, environment, code */
495 const char *env_ed = mutt_str_getenv("VISUAL");
496 if (!env_ed)
497 env_ed = mutt_str_getenv("EDITOR");
498 if (!env_ed)
499 env_ed = "vi";
500 config_str_set_initial(cs, "editor", env_ed);
501
502 const char *charset = mutt_ch_get_langinfo_charset();
503 config_str_set_initial(cs, "charset", charset);
504 mutt_ch_set_charset(charset);
505 FREE(&charset);
506
507 char name[256] = { 0 };
508 const char *c_real_name = cs_subset_string(NeoMutt->sub, "real_name");
509 if (!c_real_name)
510 {
511 struct passwd *pw = getpwuid(getuid());
512 if (pw)
513 {
514 c_real_name = mutt_gecos_name(name, sizeof(name), pw);
515 }
516 }
517 config_str_set_initial(cs, "real_name", c_real_name);
518
519#ifdef HAVE_GETSID
520 /* Unset suspend by default if we're the session leader */
521 if (getsid(0) == getpid())
522 config_str_set_initial(cs, "suspend", "no");
523#endif
524
525 /* RFC2368, "4. Unsafe headers"
526 * The creator of a mailto URL can't expect the resolver of a URL to
527 * understand more than the "subject" and "body" headers. Clients that
528 * resolve mailto URLs into mail messages should be able to correctly
529 * create RFC822-compliant mail messages using the "subject" and "body"
530 * headers. */
531 add_to_stailq(&MailToAllow, "body");
532 add_to_stailq(&MailToAllow, "subject");
533 /* Cc, In-Reply-To, and References help with not breaking threading on
534 * mailing lists, see https://github.com/neomutt/neomutt/issues/115 */
536 add_to_stailq(&MailToAllow, "in-reply-to");
537 add_to_stailq(&MailToAllow, "references");
538
539 if (STAILQ_EMPTY(&Muttrc))
540 {
541 const char *xdg_cfg_home = mutt_str_getenv("XDG_CONFIG_HOME");
542
543 if (!xdg_cfg_home && NeoMutt->home_dir)
544 {
545 buf_printf(buf, "%s/.config", NeoMutt->home_dir);
546 xdg_cfg_home = buf_string(buf);
547 }
548
549 char *config = find_cfg(NeoMutt->home_dir, xdg_cfg_home);
550 if (config)
551 {
553 }
554 }
555 else
556 {
557 struct ListNode *np = NULL;
558 STAILQ_FOREACH(np, &Muttrc, entries)
559 {
560 buf_strcpy(buf, np->data);
561 FREE(&np->data);
562 buf_expand_path(buf);
563 np->data = buf_strdup(buf);
564 if (access(np->data, F_OK))
565 {
566 mutt_perror("%s", np->data);
567 goto done; // TEST10: neomutt -F missing
568 }
569 }
570 }
571
572 struct ListNode *np = NULL;
573 STAILQ_FOREACH(np, &Muttrc, entries)
574 {
575 if (np->data && !mutt_str_equal(np->data, "/dev/null"))
576 {
577 cs_str_string_set(cs, "alias_file", np->data, NULL);
578 break;
579 }
580 }
581
582 /* Process the global rc file if it exists and the user hasn't explicitly
583 * requested not to via "-n". */
584 if (!skip_sys_rc)
585 {
586 do
587 {
589 break;
590
591 buf_printf(buf, "%s/neomuttrc", SYSCONFDIR);
592 if (access(buf_string(buf), F_OK) == 0)
593 break;
594
595 buf_printf(buf, "%s/Muttrc", SYSCONFDIR);
596 if (access(buf_string(buf), F_OK) == 0)
597 break;
598
599 buf_printf(buf, "%s/neomuttrc", PKGDATADIR);
600 if (access(buf_string(buf), F_OK) == 0)
601 break;
602
603 buf_printf(buf, "%s/Muttrc", PKGDATADIR);
604 } while (false);
605
606 if (access(buf_string(buf), F_OK) == 0)
607 {
608 if (source_rc(buf_string(buf), err) != 0)
609 {
610 mutt_error("%s", buf_string(err));
611 need_pause = true; // TEST11: neomutt (error in /etc/neomuttrc)
612 }
613 }
614 }
615
616 /* Read the user's initialization file. */
617 STAILQ_FOREACH(np, &Muttrc, entries)
618 {
619 if (np->data)
620 {
621 if (source_rc(np->data, err) != 0)
622 {
623 mutt_error("%s", buf_string(err));
624 need_pause = true; // TEST12: neomutt (error in ~/.neomuttrc)
625 }
626 }
627 }
628
629 if (execute_commands(commands) != 0)
630 need_pause = true; // TEST13: neomutt -e broken
631
632 if (!get_hostname(cs))
633 goto done;
634
635 /* The command line overrides the config */
636 if (dlevel)
637 cs_str_reset(cs, "debug_level", NULL);
638 if (dfile)
639 cs_str_reset(cs, "debug_file", NULL);
640
641 if (mutt_log_start() < 0)
642 {
643 mutt_perror("log file");
644 goto done;
645 }
646
647 if (need_pause && !OptNoCurses)
648 {
650 if (mutt_any_key_to_continue(NULL) == 'q')
651 goto done; // TEST14: neomutt -e broken (press 'q')
652 }
653
654 const char *const c_tmp_dir = cs_subset_path(NeoMutt->sub, "tmp_dir");
655 if (mutt_file_mkdir(c_tmp_dir, S_IRWXU) < 0)
656 {
657 mutt_error(_("Can't create %s: %s"), c_tmp_dir, strerror(errno));
658 goto done;
659 }
660
661 rc = 0;
662
663done:
664 buf_pool_release(&err);
665 buf_pool_release(&buf);
666 return rc;
667}
668
676static int get_elem_queries(struct ListHead *queries, struct HashElemArray *hea)
677{
678 int rc = 0;
679 struct ListNode *np = NULL;
680 STAILQ_FOREACH(np, queries, entries)
681 {
682 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, np->data);
683 if (!he)
684 {
685 mutt_warning(_("Unknown option %s"), np->data);
686 rc = 1;
687 continue;
688 }
689
690 if (he->type & D_INTERNAL_DEPRECATED)
691 {
692 mutt_warning(_("Option %s is deprecated"), np->data);
693 rc = 1;
694 continue;
695 }
696
697 ARRAY_ADD(hea, he);
698 }
699
700 return rc; // TEST16: neomutt -Q charset
701}
702
707static void reset_tilde(struct ConfigSet *cs)
708{
709 static const char *names[] = { "folder", "mbox", "postponed", "record" };
710
711 struct Buffer *value = buf_pool_get();
712 for (size_t i = 0; i < mutt_array_size(names); i++)
713 {
714 struct HashElem *he = cs_get_elem(cs, names[i]);
715 if (!he)
716 continue;
717 buf_reset(value);
718 cs_he_initial_get(cs, he, value);
719 buf_expand_path_regex(value, false);
720 config_he_set_initial(cs, he, value->data);
721 }
722 buf_pool_release(&value);
723}
724
725#ifdef ENABLE_NLS
730static void localise_config(struct ConfigSet *cs)
731{
732 struct Buffer *value = buf_pool_get();
733 struct HashElemArray hea = get_elem_list(NeoMutt->sub->cs, GEL_ALL_CONFIG);
734 struct HashElem **hep = NULL;
735
736 ARRAY_FOREACH(hep, &hea)
737 {
738 struct HashElem *he = *hep;
739 if (!(he->type & D_L10N_STRING))
740 continue;
741
742 buf_reset(value);
743 cs_he_initial_get(cs, he, value);
744
745 // Lookup the translation
746 const char *l10n = gettext(buf_string(value));
747 config_he_set_initial(cs, he, l10n);
748 }
749
750 ARRAY_FREE(&hea);
751 buf_pool_release(&value);
752}
753#endif
754
759static bool usage(void)
760{
761 puts(mutt_make_version());
762
763 // clang-format off
764 /* L10N: Try to limit to 80 columns */
765 puts(_("usage:"));
766 puts(_(" neomutt [-CEn] [-e <command>] [-F <config>] [-H <draft>] [-i <include>]\n"
767 " [-b <address>] [-c <address>] [-s <subject>] [-a <file> [...] --]\n"
768 " <address> [...]"));
769 puts(_(" neomutt [-Cn] [-e <command>] [-F <config>] [-b <address>] [-c <address>]\n"
770 " [-s <subject>] [-a <file> [...] --] <address> [...] < message"));
771 puts(_(" neomutt [-nRy] [-e <command>] [-F <config>] [-f <mailbox>] [-m <type>]"));
772 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -A <alias>"));
773 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -D [-D] [-O] [-S]"));
774 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -d <level> -l <file>"));
775 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -G"));
776 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -g <server>"));
777 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -p"));
778 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -Q <variable> [-O]"));
779 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -Z"));
780 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -z [-f <mailbox>]"));
781 puts(_(" neomutt -v[v]\n"));
782
783 /* L10N: Try to limit to 80 columns. If more space is needed add an indented line */
784 puts(_("options:"));
785 puts(_(" -- Special argument forces NeoMutt to stop option parsing and treat\n"
786 " remaining arguments as addresses even if they start with a dash"));
787 puts(_(" -A <alias> Print an expanded version of the given alias to stdout and exit"));
788 puts(_(" -a <file> Attach one or more files to a message (must be the last option)\n"
789 " Add any addresses after the '--' argument"));
790 puts(_(" -b <address> Specify a blind carbon copy (Bcc) recipient"));
791 puts(_(" -c <address> Specify a carbon copy (Cc) recipient"));
792 puts(_(" -C Enable Command-line Crypto (signing/encryption)"));
793 puts(_(" -D Dump all config variables as 'name=value' pairs to stdout"));
794 puts(_(" -D -D (or -DD) Like -D, but only show changed config"));
795 puts(_(" -D -O Like -D, but show one-liner documentation"));
796 puts(_(" -D -S Like -D, but hide the value of sensitive variables"));
797 puts(_(" -d <level> Log debugging output to a file (default is \"~/.neomuttdebug0\")\n"
798 " The level can range from 1-5 and affects verbosity"));
799 puts(_(" -E Edit draft (-H) or include (-i) file during message composition"));
800 puts(_(" -e <command> Specify a command to be run after reading the config files"));
801 puts(_(" -F <config> Specify an alternative initialization file to read"));
802 puts(_(" -f <mailbox> Specify a mailbox (as defined with 'mailboxes' command) to load"));
803 puts(_(" -G Start NeoMutt with a listing of subscribed newsgroups"));
804 puts(_(" -g <server> Like -G, but start at specified news server"));
805 puts(_(" -H <draft> Specify a draft file with header and body for message composing"));
806 puts(_(" -h Print this help message and exit"));
807 puts(_(" -i <include> Specify an include file to be embedded in the body of a message"));
808 puts(_(" -l <file> Specify a file for debugging output (default \"~/.neomuttdebug0\")"));
809 puts(_(" -m <type> Specify a default mailbox format type for newly created folders\n"
810 " The type is either MH, MMDF, Maildir or mbox (case-insensitive)"));
811 puts(_(" -n Do not read the system-wide configuration file"));
812 puts(_(" -p Resume a prior postponed message, if any"));
813 puts(_(" -Q <variable> Query a configuration variable and print its value to stdout\n"
814 " (after the config has been read and any commands executed)\n"
815 " Add -O for one-liner documentation"));
816 puts(_(" -R Open mailbox in read-only mode"));
817 puts(_(" -s <subject> Specify a subject (must be enclosed in quotes if it has spaces)"));
818 puts(_(" -v Print the NeoMutt version and compile-time definitions and exit"));
819 puts(_(" -vv Print the NeoMutt license and copyright information and exit"));
820 puts(_(" -y Start NeoMutt with a listing of all defined mailboxes"));
821 puts(_(" -Z Open the first mailbox with new message or exit immediately with\n"
822 " exit code 1 if none is found in all defined mailboxes"));
823 puts(_(" -z Open the first or specified (-f) mailbox if it holds any message\n"
824 " or exit immediately with exit code 1 otherwise"));
825 // clang-format on
826
827 fflush(stdout);
828 return !ferror(stdout);
829}
830
836static int start_curses(void)
837{
838 km_init(); /* must come before mutt_init */
839
840 /* should come before initscr() so that ncurses 4.2 doesn't try to install
841 * its own SIGWINCH handler */
843
844 if (!initscr())
845 {
846 mutt_error(_("Error initializing terminal"));
847 return 1;
848 }
849
850 colors_init();
851 keypad(stdscr, true);
852 cbreak();
853 noecho();
854 nonl();
855 typeahead(-1); /* simulate smooth scrolling */
856 meta(stdscr, true);
858 /* Now that curses is set up, we drop back to normal screen mode.
859 * This simplifies displaying error messages to the user.
860 * The first call to refresh() will swap us back to curses screen mode. */
861 endwin();
862 return 0;
863}
864
868static void init_locale(void)
869{
870 setlocale(LC_ALL, "");
871
872#ifdef ENABLE_NLS
873 const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
874 if (domdir)
875 bindtextdomain(PACKAGE, domdir);
876 else
877 bindtextdomain(PACKAGE, MUTTLOCALEDIR);
878 textdomain(PACKAGE);
879#endif
880#ifndef LOCALES_HACK
881 /* Do we have a locale definition? */
882 if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
883 {
884 OptLocales = true;
885 }
886#endif
887}
888
896static bool get_user_info(struct ConfigSet *cs)
897{
898 const char *shell = mutt_str_getenv("SHELL");
899
900 /* Get some information about the user */
901 struct passwd *pw = getpwuid(getuid());
902 if (pw)
903 {
904 if (!NeoMutt->username)
905 NeoMutt->username = mutt_str_dup(pw->pw_name);
906 if (!NeoMutt->home_dir)
907 NeoMutt->home_dir = mutt_str_dup(pw->pw_dir);
908 if (!shell)
909 shell = pw->pw_shell;
910 }
911
912 if (!NeoMutt->username)
913 {
914 mutt_error(_("unable to determine username"));
915 return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
916 }
917
918 if (!NeoMutt->home_dir)
919 {
920 mutt_error(_("unable to determine home directory"));
921 return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
922 }
923
924 if (shell)
925 config_str_set_initial(cs, "shell", shell);
926
927 return true;
928}
929
937static void log_translation(void)
938{
939 const char *header = ""; // Do not merge these two lines
940 header = _(header); // otherwise the .po files will end up badly ordered
941 const char *label = "Language:"; // the start of the lookup/needle
942 const char *lang = mutt_istr_find(header, label);
943 int len = 64;
944 if (lang)
945 {
946 lang += strlen(label); // skip label
947 SKIPWS(lang);
948 char *nl = strchr(lang, '\n');
949 if (nl)
950 len = (nl - lang);
951 }
952 else
953 {
954 lang = "NONE";
955 }
956
957 mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
958}
959
963static void log_gui(void)
964{
965 const char *term = mutt_str_getenv("TERM");
966 const char *color_term = mutt_str_getenv("COLORTERM");
967 bool true_color = false;
968#ifdef NEOMUTT_DIRECT_COLORS
969 true_color = true;
970#endif
971
972 mutt_debug(LL_DEBUG1, "GUI:\n");
973 mutt_debug(LL_DEBUG1, " Curses: %s\n", curses_version());
974 mutt_debug(LL_DEBUG1, " COLORS=%d\n", COLORS);
975 mutt_debug(LL_DEBUG1, " COLOR_PAIRS=%d\n", COLOR_PAIRS);
976 mutt_debug(LL_DEBUG1, " TERM=%s\n", NONULL(term));
977 mutt_debug(LL_DEBUG1, " COLORTERM=%s\n", NONULL(color_term));
978 mutt_debug(LL_DEBUG1, " True color support: %s\n", true_color ? "YES" : "NO");
979 mutt_debug(LL_DEBUG1, " Screen: %dx%d\n", RootWindow->state.cols,
981}
982
987{
988 static time_t last_run = 0;
989
990 if (nc->event_type != NT_TIMEOUT)
991 return 0;
992
993 const short c_timeout = cs_subset_number(NeoMutt->sub, "timeout");
994 if (c_timeout <= 0)
995 goto done;
996
997 time_t now = mutt_date_now();
998 if (now < (last_run + c_timeout))
999 goto done;
1000
1001 // Limit hook to running under the Index or Pager
1002 struct MuttWindow *focus = window_get_focus();
1003 struct MuttWindow *dlg = dialog_find(focus);
1004 if (!dlg || (dlg->type != WT_DLG_INDEX))
1005 goto done;
1006
1007 last_run = now;
1009
1010done:
1011 mutt_debug(LL_DEBUG5, "timeout done\n");
1012 return 0;
1013}
1014
1023int main(int argc, char *argv[], char *envp[])
1024{
1025 char *subject = NULL;
1026 char *include_file = NULL;
1027 char *draft_file = NULL;
1028 char *new_type = NULL;
1029 char *dlevel = NULL;
1030 char *dfile = NULL;
1031 const char *cli_nntp = NULL;
1032 struct Email *e = NULL;
1033 struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
1034 struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
1035 struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
1036 struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
1037 struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
1038 struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
1039 SendFlags sendflags = SEND_NO_FLAGS;
1041 int version = 0;
1042 int i;
1043 bool explicit_folder = false;
1044 bool dump_variables = false;
1045 bool dump_changed = false;
1046 bool one_liner = false;
1047 bool hide_sensitive = false;
1048 bool edit_infile = false;
1049 int double_dash = argc, nargc = 1;
1050 int rc = 1;
1051 bool repeat_error = false;
1052 struct Buffer *folder = buf_pool_get();
1053 struct Buffer *expanded_infile = buf_pool_get();
1054 struct Buffer *tempfile = buf_pool_get();
1055 struct ConfigSet *cs = NULL;
1056
1058
1059 /* sanity check against stupid administrators */
1060 if (getegid() != getgid())
1061 {
1062 mutt_error("%s: I don't want to run with privileges!", (argc != 0) ? argv[0] : "neomutt");
1063 goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
1064 }
1065
1066 init_locale();
1067
1068 cs = cs_new(500);
1069 if (!cs)
1070 goto main_curses;
1071
1072 NeoMutt = neomutt_new(cs);
1073
1074 NeoMutt->env = envlist_init(envp);
1077
1078 init_config(cs);
1079
1080 for (optind = 1; optind < double_dash;)
1081 {
1082 /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
1083 * encounters a non-option. That could be a file to attach
1084 * (all non-options between -a and --) or it could be an address
1085 * (which gets collapsed to the front of argv). */
1086 for (; optind < argc; optind++)
1087 {
1088 if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
1089 {
1090 if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
1091 double_dash = optind; /* quit outer loop after getopt */
1092 break; /* drop through to getopt */
1093 }
1094
1095 /* non-option, either an attachment or address */
1096 if (!STAILQ_EMPTY(&attach))
1097 mutt_list_insert_tail(&attach, mutt_str_dup(argv[optind]));
1098 else
1099 argv[nargc++] = argv[optind];
1100 }
1101
1102 i = getopt(argc, argv, "+A:a:b:F:f:Cc:Dd:l:Ee:g:GH:i:hm:nOpQ:RSs:TvyzZ");
1103 if (i != EOF)
1104 {
1105 switch (i)
1106 {
1107 case 'A':
1108 mutt_list_insert_tail(&alias_queries, mutt_str_dup(optarg));
1109 break;
1110 case 'a':
1111 mutt_list_insert_tail(&attach, mutt_str_dup(optarg));
1112 break;
1113 case 'b':
1114 mutt_list_insert_tail(&bcc_list, mutt_str_dup(optarg));
1115 break;
1116 case 'C':
1117 sendflags |= SEND_CLI_CRYPTO;
1118 break;
1119 case 'c':
1120 mutt_list_insert_tail(&cc_list, mutt_str_dup(optarg));
1121 break;
1122 case 'D':
1123 if (dump_variables)
1124 dump_changed = true;
1125 else
1126 dump_variables = true;
1127 break;
1128 case 'd':
1129 dlevel = optarg;
1130 break;
1131 case 'E':
1132 edit_infile = true;
1133 break;
1134 case 'e':
1135 mutt_list_insert_tail(&commands, mutt_str_dup(optarg));
1136 break;
1137 case 'F':
1139 break;
1140 case 'f':
1141 buf_strcpy(folder, optarg);
1142 explicit_folder = true;
1143 break;
1144 case 'g': /* Specify a news server */
1145 cli_nntp = optarg;
1147
1148 case 'G': /* List of newsgroups */
1149 flags |= MUTT_CLI_SELECT | MUTT_CLI_NEWS;
1150 break;
1151 case 'H':
1152 draft_file = optarg;
1153 break;
1154 case 'i':
1155 include_file = optarg;
1156 break;
1157 case 'l':
1158 dfile = optarg;
1159 break;
1160 case 'm':
1161 new_type = optarg;
1162 break;
1163 case 'n':
1164 flags |= MUTT_CLI_NOSYSRC;
1165 break;
1166 case 'O':
1167 one_liner = true;
1168 break;
1169 case 'p':
1170 sendflags |= SEND_POSTPONED;
1171 break;
1172 case 'Q':
1173 mutt_list_insert_tail(&queries, mutt_str_dup(optarg));
1174 break;
1175 case 'R':
1176 flags |= MUTT_CLI_RO; /* read-only mode */
1177 break;
1178 case 'S':
1179 hide_sensitive = true;
1180 break;
1181 case 's':
1182 subject = optarg;
1183 break;
1184 case 'v':
1185 version++;
1186 break;
1187 case 'y': /* My special hack mode */
1188 flags |= MUTT_CLI_SELECT;
1189 break;
1190 case 'Z':
1192 break;
1193 case 'z':
1194 flags |= MUTT_CLI_IGNORE;
1195 break;
1196 default:
1197 OptNoCurses = true;
1198 if (usage())
1199 goto main_ok; // TEST03: neomutt -9
1200 else
1201 goto main_curses;
1202 }
1203 }
1204 }
1205
1206 /* collapse remaining argv */
1207 while (optind < argc)
1208 argv[nargc++] = argv[optind++];
1209 optind = 1;
1210 argc = nargc;
1211
1212 if (version > 0)
1213 {
1215 bool done;
1216 if (version == 1)
1217 done = print_version(stdout);
1218 else
1219 done = print_copyright();
1220 OptNoCurses = true;
1221 if (done)
1222 goto main_ok; // TEST04: neomutt -v
1223 else
1224 goto main_curses;
1225 }
1226
1227 // Change the current umask, and save the original one
1228 NeoMutt->user_default_umask = umask(077);
1229 subjrx_init();
1230 attach_init();
1232
1233#ifdef USE_DEBUG_NOTIFY
1235#endif
1236
1237 if (!get_user_info(cs))
1238 goto main_exit;
1239
1240 reset_tilde(cs);
1241#ifdef ENABLE_NLS
1242 localise_config(cs);
1243#endif
1244
1245 if (dfile)
1246 config_str_set_initial(cs, "debug_file", dfile);
1247
1248 if (dlevel)
1249 {
1250 short num = 0;
1251 if (!mutt_str_atos_full(dlevel, &num) || (num < LL_MESSAGE) || (num >= LL_MAX))
1252 {
1253 mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
1254 goto main_exit; // TEST07: neomutt -d xyz
1255 }
1256
1257 config_str_set_initial(cs, "debug_level", dlevel);
1258 }
1259
1260 mutt_log_prep();
1263 mutt_debug(LL_DEBUG1, "user's umask %03o\n", NeoMutt->user_default_umask);
1264 mutt_debug(LL_DEBUG3, "umask set to 077\n");
1265
1266 if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
1267 {
1268 e = email_new();
1269 e->env = mutt_env_new();
1270
1271 struct ListNode *np = NULL;
1272 STAILQ_FOREACH(np, &bcc_list, entries)
1273 {
1274 mutt_addrlist_parse(&e->env->bcc, np->data);
1275 }
1276
1277 STAILQ_FOREACH(np, &cc_list, entries)
1278 {
1279 mutt_addrlist_parse(&e->env->cc, np->data);
1280 }
1281
1282 mutt_list_free(&bcc_list);
1283 mutt_list_free(&cc_list);
1284 }
1285
1286 /* Check for a batch send. */
1287 if (!isatty(STDIN_FILENO) || !STAILQ_EMPTY(&queries) ||
1288 !STAILQ_EMPTY(&alias_queries) || dump_variables)
1289 {
1290 OptNoCurses = true;
1291 sendflags |= SEND_BATCH;
1294 }
1295
1296 /* Check to make sure stdout is available in curses mode. */
1297 if (!OptNoCurses && !isatty(STDOUT_FILENO))
1298 goto main_curses;
1299
1300 /* This must come before mutt_init() because curses needs to be started
1301 * before calling the init_pair() function to set the color scheme. */
1302 if (!OptNoCurses)
1303 {
1304 int crc = start_curses();
1305 if (crc != 0)
1306 goto main_curses; // TEST08: can't test -- fake term?
1307 }
1308
1309 /* Always create the mutt_windows because batch mode has some shared code
1310 * paths that end up referencing them. */
1311 rootwin_new();
1312
1313 if (!OptNoCurses)
1314 {
1315 /* check whether terminal status is supported (must follow curses init) */
1318 log_gui();
1319 }
1320
1322 alias_init();
1323 commands_init();
1324 hooks_init();
1326 imap_init();
1327#ifdef USE_LUA
1328 mutt_lua_init();
1329#endif
1331
1332 menu_init();
1333 sb_init();
1334#ifdef USE_NOTMUCH
1335 nm_init();
1336#endif
1337
1338 /* set defaults and read init files */
1339 int rc2 = mutt_init(cs, dlevel, dfile, flags & MUTT_CLI_NOSYSRC, &commands);
1340 if (rc2 != 0)
1341 goto main_curses;
1342
1345
1346#ifdef USE_NOTMUCH
1347 const bool c_virtual_spool_file = cs_subset_bool(NeoMutt->sub, "virtual_spool_file");
1348 if (c_virtual_spool_file)
1349 {
1350 /* Find the first virtual folder and open it */
1351 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
1353 struct MailboxNode *mp = STAILQ_FIRST(&ml);
1354 if (mp)
1355 cs_str_string_set(cs, "spool_file", mailbox_path(mp->mailbox), NULL);
1357 }
1358#endif
1359
1361
1362 /* "$news_server" precedence: command line, config file, environment, system file */
1363 if (!cli_nntp)
1364 cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
1365
1366 if (!cli_nntp)
1367 cli_nntp = mutt_str_getenv("NNTPSERVER");
1368
1369 if (!cli_nntp)
1370 {
1371 char buf[1024] = { 0 };
1372 cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
1373 }
1374
1375 if (cli_nntp)
1376 config_str_set_initial(cs, "news_server", cli_nntp);
1377
1378 /* Initialize crypto backends. */
1379 crypt_init();
1380
1381 if (new_type && !config_str_set_initial(cs, "mbox_type", new_type))
1382 goto main_curses;
1383
1384 if (dump_variables || !STAILQ_EMPTY(&queries))
1385 {
1386 const bool tty = isatty(STDOUT_FILENO);
1387
1389 if (tty)
1390 cdflags |= CS_DUMP_LINK_DOCS;
1391 if (hide_sensitive)
1392 cdflags |= CS_DUMP_HIDE_SENSITIVE;
1393 if (one_liner)
1394 cdflags |= CS_DUMP_SHOW_DOCS;
1395
1396 struct HashElemArray hea = ARRAY_HEAD_INITIALIZER;
1397 if (dump_variables)
1398 {
1399 enum GetElemListFlags gel_flags = dump_changed ? GEL_CHANGED_CONFIG : GEL_ALL_CONFIG;
1400 hea = get_elem_list(cs, gel_flags);
1401 rc = 0;
1402 }
1403 else
1404 {
1405 rc = get_elem_queries(&queries, &hea);
1406 }
1407
1408 dump_config(cs, &hea, cdflags, stdout);
1409 ARRAY_FREE(&hea);
1410 goto main_curses;
1411 }
1412
1413 if (!STAILQ_EMPTY(&alias_queries))
1414 {
1415 rc = 0;
1416 for (; optind < argc; optind++)
1417 mutt_list_insert_tail(&alias_queries, mutt_str_dup(argv[optind]));
1418 struct ListNode *np = NULL;
1419 STAILQ_FOREACH(np, &alias_queries, entries)
1420 {
1421 struct AddressList *al = alias_lookup(np->data);
1422 if (al)
1423 {
1424 /* output in machine-readable form */
1425 mutt_addrlist_to_intl(al, NULL);
1426 struct Buffer *buf = buf_pool_get();
1427 mutt_addrlist_write(al, buf, false);
1428 printf("%s\n", buf_string(buf));
1429 buf_pool_release(&buf);
1430 }
1431 else
1432 {
1433 rc = 1;
1434 printf("%s\n", NONULL(np->data)); // TEST19: neomutt -A unknown
1435 }
1436 }
1437 mutt_list_free(&alias_queries);
1438 goto main_curses; // TEST20: neomutt -A alias
1439 }
1440
1441 if (!OptNoCurses)
1442 {
1444 clear();
1448 }
1449
1450#ifdef USE_AUTOCRYPT
1451 /* Initialize autocrypt after curses messages are working,
1452 * because of the initial account setup screens. */
1453 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
1454 if (c_autocrypt)
1455 mutt_autocrypt_init(!(sendflags & SEND_BATCH));
1456#endif
1457
1458 /* Create the `$folder` directory if it doesn't exist. */
1459 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1460 if (!OptNoCurses && c_folder)
1461 {
1462 struct stat st = { 0 };
1463 struct Buffer *fpath = buf_pool_get();
1464
1465 buf_strcpy(fpath, c_folder);
1466 buf_expand_path(fpath);
1467 bool skip = false;
1468 /* we're not connected yet - skip mail folder creation */
1469 skip |= (imap_path_probe(buf_string(fpath), NULL) == MUTT_IMAP);
1470 skip |= (pop_path_probe(buf_string(fpath), NULL) == MUTT_POP);
1471 skip |= (nntp_path_probe(buf_string(fpath), NULL) == MUTT_NNTP);
1472 if (!skip && (stat(buf_string(fpath), &st) == -1) && (errno == ENOENT))
1473 {
1474 char msg2[256] = { 0 };
1475 snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
1476 if (query_yesorno(msg2, MUTT_YES) == MUTT_YES)
1477 {
1478 if ((mkdir(buf_string(fpath), 0700) == -1) && (errno != EEXIST))
1479 mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
1480 }
1481 }
1482 buf_pool_release(&fpath);
1483 }
1484
1485 StartupComplete = true;
1486
1491
1492 if (sendflags & SEND_POSTPONED)
1493 {
1494 if (!OptNoCurses)
1495 mutt_flushinp();
1496 if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
1497 rc = 0;
1498 // TEST23: neomutt -p (postponed message, cancel)
1499 // TEST24: neomutt -p (no postponed message)
1501 repeat_error = true;
1502 goto main_curses;
1503 }
1504 else if (subject || e || draft_file || include_file ||
1505 !STAILQ_EMPTY(&attach) || (optind < argc))
1506 {
1507 FILE *fp_in = NULL;
1508 FILE *fp_out = NULL;
1509 char *infile = NULL;
1510 char *bodytext = NULL;
1511 const char *bodyfile = NULL;
1512 int rv = 0;
1513
1514 if (!OptNoCurses)
1515 mutt_flushinp();
1516
1517 if (!e)
1518 e = email_new();
1519 if (!e->env)
1520 e->env = mutt_env_new();
1521
1522 for (i = optind; i < argc; i++)
1523 {
1524 if (url_check_scheme(argv[i]) == U_MAILTO)
1525 {
1526 if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
1527 {
1528 mutt_error(_("Failed to parse mailto: link"));
1529 email_free(&e);
1530 goto main_curses; // TEST25: neomutt mailto:?
1531 }
1532 }
1533 else
1534 {
1535 mutt_addrlist_parse(&e->env->to, argv[i]);
1536 }
1537 }
1538
1539 const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
1540 if (!draft_file && c_auto_edit && TAILQ_EMPTY(&e->env->to) &&
1541 TAILQ_EMPTY(&e->env->cc))
1542 {
1543 mutt_error(_("No recipients specified"));
1544 email_free(&e);
1545 goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
1546 }
1547
1548 if (subject)
1549 {
1550 /* prevent header injection */
1552 mutt_env_set_subject(e->env, subject);
1553 }
1554
1555 if (draft_file)
1556 {
1557 infile = draft_file;
1558 include_file = NULL;
1559 }
1560 else if (include_file)
1561 {
1562 infile = include_file;
1563 }
1564 else
1565 {
1566 edit_infile = false;
1567 }
1568
1569 if (infile || bodytext)
1570 {
1571 /* Prepare fp_in and expanded_infile. */
1572 if (infile)
1573 {
1574 if (mutt_str_equal("-", infile))
1575 {
1576 if (edit_infile)
1577 {
1578 mutt_error(_("Can't use -E flag with stdin"));
1579 email_free(&e);
1580 goto main_curses; // TEST27: neomutt -E -H -
1581 }
1582 fp_in = stdin;
1583 }
1584 else
1585 {
1586 buf_strcpy(expanded_infile, infile);
1587 buf_expand_path(expanded_infile);
1588 fp_in = mutt_file_fopen(buf_string(expanded_infile), "r");
1589 if (!fp_in)
1590 {
1591 mutt_perror("%s", buf_string(expanded_infile));
1592 email_free(&e);
1593 goto main_curses; // TEST28: neomutt -E -H missing
1594 }
1595 }
1596 }
1597
1598 if (edit_infile)
1599 {
1600 /* If editing the infile, keep it around afterwards so
1601 * it doesn't get unlinked, and we can rebuild the draft_file */
1602 sendflags |= SEND_NO_FREE_HEADER;
1603 }
1604 else
1605 {
1606 /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1607 * Note: stdin is always copied to a tempfile, ensuring draft_file
1608 * can stat and get the correct st_size below. */
1609 buf_mktemp(tempfile);
1610
1611 fp_out = mutt_file_fopen(buf_string(tempfile), "w");
1612 if (!fp_out)
1613 {
1614 mutt_file_fclose(&fp_in);
1615 mutt_perror("%s", buf_string(tempfile));
1616 email_free(&e);
1617 goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1618 }
1619 if (fp_in)
1620 {
1621 mutt_file_copy_stream(fp_in, fp_out);
1622 if (fp_in == stdin)
1623 sendflags |= SEND_CONSUMED_STDIN;
1624 else
1625 mutt_file_fclose(&fp_in);
1626 }
1627 else if (bodytext)
1628 {
1629 fputs(bodytext, fp_out);
1630 }
1631 mutt_file_fclose(&fp_out);
1632
1633 fp_in = mutt_file_fopen(buf_string(tempfile), "r");
1634 if (!fp_in)
1635 {
1636 mutt_perror("%s", buf_string(tempfile));
1637 email_free(&e);
1638 goto main_curses; // TEST30: can't test
1639 }
1640 }
1641
1642 /* Parse the draft_file into the full Email/Body structure.
1643 * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1644 * our e->body. */
1645 if (draft_file)
1646 {
1647 struct Envelope *opts_env = e->env;
1648 struct stat st = { 0 };
1649
1650 sendflags |= SEND_DRAFT_FILE;
1651
1652 /* Set up a tmp Email with just enough information so that
1653 * mutt_prepare_template() can parse the message in fp_in. */
1654 struct Email *e_tmp = email_new();
1655 e_tmp->offset = 0;
1656 e_tmp->body = mutt_body_new();
1657 if (fstat(fileno(fp_in), &st) != 0)
1658 {
1659 mutt_perror("%s", draft_file);
1660 email_free(&e);
1661 email_free(&e_tmp);
1662 goto main_curses; // TEST31: can't test
1663 }
1664 e_tmp->body->length = st.st_size;
1665
1666 if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1667 {
1668 mutt_error(_("Can't parse message template: %s"), draft_file);
1669 email_free(&e);
1670 email_free(&e_tmp);
1671 goto main_curses;
1672 }
1673
1674 /* Scan for neomutt header to set `$resume_draft_files` */
1675 struct ListNode *np = NULL, *tmp = NULL;
1676 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1677 STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1678 {
1679 if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1680 {
1681 if (c_resume_edited_draft_files)
1682 cs_str_native_set(cs, "resume_draft_files", true, NULL);
1683
1684 STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1685 FREE(&np->data);
1686 FREE(&np);
1687 }
1688 }
1689
1690 mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1691 mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1692 mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1693 if (opts_env->subject)
1694 mutt_env_set_subject(e->env, opts_env->subject);
1695
1696 mutt_env_free(&opts_env);
1697 email_free(&e_tmp);
1698 }
1699 else if (edit_infile)
1700 {
1701 /* Editing the include_file: pass it directly in.
1702 * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1703 bodyfile = buf_string(expanded_infile);
1704 }
1705 else
1706 {
1707 // For bodytext and unedited include_file: use the tempfile.
1708 bodyfile = buf_string(tempfile);
1709 }
1710
1711 mutt_file_fclose(&fp_in);
1712 }
1713
1714 FREE(&bodytext);
1715
1716 if (!STAILQ_EMPTY(&attach))
1717 {
1718 struct Body *b = e->body;
1719
1720 while (b && b->next)
1721 b = b->next;
1722
1723 struct ListNode *np = NULL;
1724 STAILQ_FOREACH(np, &attach, entries)
1725 {
1726 if (b)
1727 {
1729 b = b->next;
1730 }
1731 else
1732 {
1734 e->body = b;
1735 }
1736 if (!b)
1737 {
1738 mutt_error(_("%s: unable to attach file"), np->data);
1739 mutt_list_free(&attach);
1740 email_free(&e);
1741 goto main_curses; // TEST32: neomutt john@example.com -a missing
1742 }
1743 }
1744 mutt_list_free(&attach);
1745 }
1746
1747 rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1748 /* We WANT the "Mail sent." and any possible, later error */
1750 if (ErrorBufMessage)
1751 mutt_message("%s", ErrorBuf);
1752
1753 if (edit_infile)
1754 {
1755 if (draft_file)
1756 {
1757 if (truncate(buf_string(expanded_infile), 0) == -1)
1758 {
1759 mutt_perror("%s", buf_string(expanded_infile));
1760 email_free(&e);
1761 goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1762 }
1763 fp_out = mutt_file_fopen(buf_string(expanded_infile), "a");
1764 if (!fp_out)
1765 {
1766 mutt_perror("%s", buf_string(expanded_infile));
1767 email_free(&e);
1768 goto main_curses; // TEST34: can't test
1769 }
1770
1771 /* If the message was sent or postponed, these will already
1772 * have been done. */
1773 if (rv < 0)
1774 {
1775 if (e->body->next)
1776 e->body = mutt_make_multipart(e->body);
1778 mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1779 mutt_env_to_intl(e->env, NULL, NULL);
1780 }
1781
1782 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1784 c_crypt_protected_headers_read &&
1786 NeoMutt->sub);
1787 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1788 if (c_resume_edited_draft_files)
1789 fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1790 fputc('\n', fp_out);
1791 if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1792 {
1793 mutt_file_fclose(&fp_out);
1794 email_free(&e);
1795 goto main_curses; // TEST35: can't test
1796 }
1797 mutt_file_fclose(&fp_out);
1798 }
1799
1800 email_free(&e);
1801 }
1802
1803 /* !edit_infile && draft_file will leave the tempfile around */
1804 if (!buf_is_empty(tempfile))
1805 unlink(buf_string(tempfile));
1806
1808
1809 if (rv != 0)
1810 goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1811 }
1812 else if (sendflags & SEND_BATCH)
1813 {
1814 /* This guards against invoking `neomutt < /dev/null` and accidentally
1815 * sending an email due to a my_hdr or other setting. */
1816 mutt_error(_("No recipients specified"));
1817 goto main_curses;
1818 }
1819 else
1820 {
1821 if (flags & MUTT_CLI_MAILBOX)
1822 {
1823 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1824 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1826 if (mutt_mailbox_check(NULL, csflags) == 0)
1827 {
1828 mutt_message(_("No mailbox with new mail"));
1829 repeat_error = true;
1830 goto main_curses; // TEST37: neomutt -Z (no new mail)
1831 }
1832 buf_reset(folder);
1833 mutt_mailbox_next(NULL, folder);
1834 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1835 }
1836 else if (flags & MUTT_CLI_SELECT)
1837 {
1838 if (flags & MUTT_CLI_NEWS)
1839 {
1840 const char *const c_news_server = cs_subset_string(NeoMutt->sub, "news_server");
1841 OptNews = true;
1842 CurrentNewsSrv = nntp_select_server(NULL, c_news_server, false);
1843 if (!CurrentNewsSrv)
1844 goto main_curses; // TEST38: neomutt -G (unset news_server)
1845 }
1846 else if (TAILQ_EMPTY(&NeoMutt->accounts))
1847 {
1848 mutt_error(_("No incoming mailboxes defined"));
1849 goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1850 }
1851 buf_reset(folder);
1852 dlg_browser(folder, MUTT_SEL_FOLDER | MUTT_SEL_MAILBOX, NULL, NULL, NULL);
1853 if (buf_is_empty(folder))
1854 {
1855 goto main_ok; // TEST40: neomutt -y (quit selection)
1856 }
1857 }
1858
1859 if (buf_is_empty(folder))
1860 {
1861 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1862 if (c_spool_file)
1863 {
1864 // Check if `$spool_file` corresponds a mailboxes' description.
1865 struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1866 if (m_desc)
1867 buf_strcpy(folder, m_desc->realpath);
1868 else
1869 buf_strcpy(folder, c_spool_file);
1870 }
1871 else if (c_folder)
1872 {
1873 buf_strcpy(folder, c_folder);
1874 }
1875 /* else no folder */
1876 }
1877
1878 if (OptNews)
1879 {
1880 OptNews = false;
1881 buf_alloc(folder, PATH_MAX);
1882 nntp_expand_path(folder->data, folder->dsize, &CurrentNewsSrv->conn->account);
1883 }
1884 else
1885 {
1886 buf_expand_path(folder);
1887 }
1888
1891
1892 if (flags & MUTT_CLI_IGNORE)
1893 {
1894 /* check to see if there are any messages in the folder */
1895 switch (mx_path_is_empty(folder))
1896 {
1897 case -1:
1898 mutt_perror("%s", buf_string(folder));
1899 goto main_curses; // TEST41: neomutt -z -f missing
1900 case 1:
1901 mutt_error(_("Mailbox is empty"));
1902 goto main_curses; // TEST42: neomutt -z -f /dev/null
1903 }
1904 }
1905
1906 struct Mailbox *m_cur = mailbox_find(buf_string(folder));
1907 // Take a copy of the name just in case the hook alters m_cur
1908 const char *name = m_cur ? mutt_str_dup(m_cur->name) : NULL;
1910 FREE(&name);
1912 mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1914
1916 window_redraw(NULL);
1917
1918 repeat_error = true;
1919 struct Mailbox *m = mx_resolve(buf_string(folder));
1920 const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1921 if (!mx_mbox_open(m, ((flags & MUTT_CLI_RO) || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1922 {
1923 if (m->account)
1925
1926 mailbox_free(&m);
1927 mutt_error(_("Unable to open mailbox %s"), buf_string(folder));
1928 repeat_error = false;
1929 }
1930 if (m || !explicit_folder)
1931 {
1932 struct MuttWindow *dlg = index_pager_init();
1933 dialog_push(dlg);
1934
1936 m = dlg_index(dlg, m);
1938 mailbox_free(&m);
1939
1940 dialog_pop();
1941 mutt_window_free(&dlg);
1943 repeat_error = false;
1944 }
1946#ifdef USE_SASL_CYRUS
1948#endif
1949#ifdef USE_SASL_GNU
1951#endif
1952#ifdef USE_AUTOCRYPT
1954#endif
1955 // TEST43: neomutt (no change to mailbox)
1956 // TEST44: neomutt (change mailbox)
1957 }
1958
1959main_ok:
1960 rc = 0;
1961main_curses:
1962 mutt_endwin();
1964 /* Repeat the last message to the user */
1965 if (repeat_error && ErrorBufMessage)
1966 puts(ErrorBuf);
1967main_exit:
1968 if (NeoMutt && NeoMutt->sub)
1969 {
1974 }
1975 mutt_list_free(&commands);
1977 buf_pool_release(&folder);
1978 buf_pool_release(&expanded_infile);
1979 buf_pool_release(&tempfile);
1980 mutt_list_free(&queries);
1984 if (NeoMutt)
1988 menu_cleanup();
1989 crypt_cleanup();
1991
1993
1994 alias_cleanup();
1995 sb_cleanup();
1996
2002
2005
2006 /* Lists of strings */
2016
2018
2020 FREE(&LastFolder);
2022
2024
2026
2029
2031 if (NeoMutt)
2033
2041 cs_free(&cs);
2043 mutt_log_stop();
2044 return rc;
2045}
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_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_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
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
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
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:55
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
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
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: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
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.
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
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: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: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
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: globals.c:66
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
struct ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition: globals.c:50
struct ListHead Muttrc
List of config files to read.
Definition: globals.c:48
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 -.
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: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 -.
Definition: mutt_logging.c:88
#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? - 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:2348
int main_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: init.c:250
int main_hist_observer(struct NotifyCallback *nc)
Notification that a Config Variable has change - Implements observer_t -.
Definition: history.c:709
static int main_timeout_observer(struct NotifyCallback *nc)
Notification that a timeout has occurred - Implements observer_t -.
Definition: main.c:986
int main_log_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: mutt_logging.c:284
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:600
void mutt_hist_init(void)
Create a set of empty History ring buffers.
Definition: history.c:472
void mutt_hist_cleanup(void)
Free all the history lists.
Definition: history.c:445
void mutt_timeout_hook(void)
Execute any timeout hooks.
Definition: hook.c:933
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:965
void mutt_delete_hooks(HookFlags type)
Delete matching hooks.
Definition: hook.c:398
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:632
void hooks_init(void)
Setup feature commands.
Definition: hook.c:1053
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:557
void imap_init(void)
Setup feature commands.
Definition: imap.c:96
GUI manage the main index (list of emails)
void km_init(void)
Initialise all the menu keybindings.
Definition: init.c:176
void mutt_keys_cleanup(void)
Free the key maps.
Definition: init.c:215
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: init.c:133
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: init.c:228
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: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:249
#define MUTT_CLI_SELECT
-y Start with a list of all mailboxes
Definition: main.c:207
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition: main.c:868
static char * getmailname(void)
Try to retrieve the FQDN from mailname files.
Definition: main.c:290
static void localise_config(struct ConfigSet *cs)
Localise some config.
Definition: main.c:730
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:201
static void log_translation(void)
Log the translation being used.
Definition: main.c:937
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:204
static int execute_commands(struct ListHead *p)
Execute a set of NeoMutt commands.
Definition: main.c:217
static void log_gui(void)
Log info about the GUI.
Definition: main.c:963
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:707
static bool usage(void)
Display NeoMutt command line.
Definition: main.c:759
static int get_elem_queries(struct ListHead *queries, struct HashElemArray *hea)
Lookup the HashElems for a set of queries.
Definition: main.c:676
static int start_curses(void)
Start the Curses UI.
Definition: main.c:836
static int mutt_init(struct ConfigSet *cs, const char *dlevel, const char *dfile, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: main.c:408
bool StartupComplete
When the config has been read.
Definition: main.c:198
static bool get_user_info(struct ConfigSet *cs)
Find the user's name, home and shell.
Definition: main.c:896
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:206
static bool get_hostname(struct ConfigSet *cs)
Find the Fully-Qualified Domain Name.
Definition: main.c:323
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:202
int main(int argc, char *argv[], char *envp[])
Start NeoMutt.
Definition: main.c:1023
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:203
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:208
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:205
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_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.
#define FALLTHROUGH
Definition: lib.h:111
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:381
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:254
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:804
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:661
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:727
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:522
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:243
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:281
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:1305
void init_config(struct ConfigSet *cs)
Initialise the config system.
Definition: mutt_config.c:930
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
int mutt_log_start(void)
Enable file logging.
Definition: mutt_logging.c:248
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:171
NeoMutt Logging.
void mutt_lua_init(void)
Setup feature commands.
Definition: mutt_lua.c:468
Integrated Lua scripting.
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:135
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:599
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:205
struct MuttWindow * window_get_focus(void)
Get the currently focused Window.
Definition: mutt_window.c:633
@ 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:332
void add_to_stailq(struct ListHead *head, const char *str)
Add a string to a list.
Definition: muttlib.c:1052
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:857
int mutt_set_xdg_path(enum XdgType type, struct Buffer *buf)
Find an XDG path or its fallback.
Definition: muttlib.c:896
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: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: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
Notmuch virtual mailbox type.
void nm_init(void)
Setup feature commands.
Definition: notmuch.c:109
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:327
#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(var, head, field)
Definition: queue.h:390
#define STAILQ_EMPTY(head)
Definition: queue.h:382
#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_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
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: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:248
struct Notify * notify
Notifications: NotifyConfig, EventConfig.
Definition: subset.h:51
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:50
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: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 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: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
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
String list.
Definition: slist.h:37
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:299
struct HashElemArray get_elem_list(struct ConfigSet *cs, enum GetElemListFlags flags)
Create a sorted list of all config items.
Definition: subset.c:80
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:189
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:42
bool mutt_ts_capability(void)
Check terminal capabilities.
Definition: terminal.c:72
#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: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.