NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
main.c File Reference

Command line processing. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "attach/lib.h"
#include "browser/lib.h"
#include "color/lib.h"
#include "history/lib.h"
#include "imap/lib.h"
#include "index/lib.h"
#include "key/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "nntp/lib.h"
#include "pop/lib.h"
#include "postpone/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "alternates.h"
#include "external.h"
#include "globals.h"
#include "hook.h"
#include "init.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "muttlib.h"
#include "mx.h"
#include "nntp/adata.h"
#include "protos.h"
#include "subjectrx.h"
#include "version.h"
#include <libintl.h>
#include "autocrypt/lib.h"
+ Include dependency graph for main.c:

Go to the source code of this file.

Macros

#define GNULIB_defined_setlocale
 
#define MUTT_CLI_NO_FLAGS   0
 No flags are set.
 
#define MUTT_CLI_IGNORE   (1 << 0)
 -z Open first mailbox if it has mail
 
#define MUTT_CLI_MAILBOX   (1 << 1)
 -Z Open first mailbox if is has new mail
 
#define MUTT_CLI_NOSYSRC   (1 << 2)
 -n Do not read the system-wide config file
 
#define MUTT_CLI_RO   (1 << 3)
 -R Open mailbox in read-only mode
 
#define MUTT_CLI_SELECT   (1 << 4)
 -y Start with a list of all mailboxes
 
#define MUTT_CLI_NEWS   (1 << 5)
 -g/-G Start with a list of all newsgroups
 

Typedefs

typedef uint8_t CliFlags
 Flags for command line options, e.g. MUTT_CLI_IGNORE.
 

Functions

static void reset_tilde (struct ConfigSet *cs)
 Temporary measure.
 
void mutt_exit (int code)
 Leave NeoMutt NOW.
 
static bool usage (void)
 Display NeoMutt command line.
 
static int start_curses (void)
 Start the Curses UI.
 
static void init_locale (void)
 Initialise the Locale/NLS settings.
 
static bool get_user_info (struct ConfigSet *cs)
 Find the user's name, home and shell.
 
static void log_translation (void)
 Log the translation being used.
 
static void log_gui (void)
 Log info about the GUI.
 
int main_timeout_observer (struct NotifyCallback *nc)
 Notification that a timeout has occurred - Implements observer_t -.
 
int main (int argc, char *argv[], char *envp[])
 Start NeoMutt.
 

Variables

bool StartupComplete = false
 When the config has been read.
 

Detailed Description

Command line processing.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • g10 Code GmbH
  • Pietro Cerutti
  • R Primus

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file main.c.

Macro Definition Documentation

◆ GNULIB_defined_setlocale

#define GNULIB_defined_setlocale

Definition at line 129 of file main.c.

◆ MUTT_CLI_NO_FLAGS

#define MUTT_CLI_NO_FLAGS   0

No flags are set.

Definition at line 192 of file main.c.

◆ MUTT_CLI_IGNORE

#define MUTT_CLI_IGNORE   (1 << 0)

-z Open first mailbox if it has mail

Definition at line 193 of file main.c.

◆ MUTT_CLI_MAILBOX

#define MUTT_CLI_MAILBOX   (1 << 1)

-Z Open first mailbox if is has new mail

Definition at line 194 of file main.c.

◆ MUTT_CLI_NOSYSRC

#define MUTT_CLI_NOSYSRC   (1 << 2)

-n Do not read the system-wide config file

Definition at line 195 of file main.c.

◆ MUTT_CLI_RO

#define MUTT_CLI_RO   (1 << 3)

-R Open mailbox in read-only mode

Definition at line 196 of file main.c.

◆ MUTT_CLI_SELECT

#define MUTT_CLI_SELECT   (1 << 4)

-y Start with a list of all mailboxes

Definition at line 197 of file main.c.

◆ MUTT_CLI_NEWS

#define MUTT_CLI_NEWS   (1 << 5)

-g/-G Start with a list of all newsgroups

Definition at line 198 of file main.c.

Typedef Documentation

◆ CliFlags

typedef uint8_t CliFlags

Flags for command line options, e.g. MUTT_CLI_IGNORE.

Definition at line 191 of file main.c.

Function Documentation

◆ reset_tilde()

static void reset_tilde ( struct ConfigSet cs)
static

Temporary measure.

Parameters
csConfig Set

Definition at line 205 of file main.c.

206{
207 static const char *names[] = { "folder", "mbox", "postponed", "record" };
208
209 struct Buffer *value = buf_pool_get();
210 for (size_t i = 0; i < mutt_array_size(names); i++)
211 {
212 struct HashElem *he = cs_get_elem(cs, names[i]);
213 if (!he)
214 continue;
215 buf_reset(value);
216 cs_he_initial_get(cs, he, value);
217 buf_expand_path_regex(value, false);
218 cs_he_initial_set(cs, he, value->data, NULL);
219 cs_he_reset(cs, he, NULL);
220 }
221 buf_pool_release(&value);
222}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition: set.c:172
int cs_he_reset(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *err)
Reset a config item to its initial value.
Definition: set.c:390
int cs_he_initial_set(const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:460
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:528
#define mutt_array_size(x)
Definition: memory.h:38
void buf_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:136
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
The item stored in a Hash Table.
Definition: hash.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_exit()

void mutt_exit ( int  code)

Leave NeoMutt NOW.

Parameters
codeValue to return to the calling environment

Definition at line 228 of file main.c.

229{
230 mutt_endwin();
231#ifdef USE_DEBUG_BACKTRACE
232 if (code != 0)
234#endif
235 exit(code);
236}
void show_backtrace(void)
Log the program's call stack.
Definition: backtrace.c:39
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:150
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ usage()

static bool usage ( void  )
static

Display NeoMutt command line.

Return values
trueText displayed

Definition at line 242 of file main.c.

243{
244 puts(mutt_make_version());
245
246 // clang-format off
247 /* L10N: Try to limit to 80 columns */
248 puts(_("usage:"));
249 puts(_(" neomutt [-Enx] [-e <command>] [-F <config>] [-H <draft>] [-i <include>]\n"
250 " [-b <address>] [-c <address>] [-s <subject>] [-a <file> [...] --]\n"
251 " <address> [...]"));
252 puts(_(" neomutt [-nx] [-e <command>] [-F <config>] [-b <address>] [-c <address>]\n"
253 " [-s <subject>] [-a <file> [...] --] <address> [...] < message"));
254 puts(_(" neomutt [-nRy] [-e <command>] [-F <config>] [-f <mailbox>] [-m <type>]"));
255 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -A <alias>"));
256 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -B"));
257 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -D [-S] [-O]"));
258 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -d <level> -l <file>"));
259 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -G"));
260 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -g <server>"));
261 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -p"));
262 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -Q <variable> [-O]"));
263 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -Z"));
264 puts(_(" neomutt [-n] [-e <command>] [-F <config>] -z [-f <mailbox>]"));
265 puts(_(" neomutt -v[v]\n"));
266
267 /* L10N: Try to limit to 80 columns. If more space is needed add an indented line */
268 puts(_("options:"));
269 puts(_(" -- Special argument forces NeoMutt to stop option parsing and treat\n"
270 " remaining arguments as addresses even if they start with a dash"));
271 puts(_(" -A <alias> Print an expanded version of the given alias to stdout and exit"));
272 puts(_(" -a <file> Attach one or more files to a message (must be the last option)\n"
273 " Add any addresses after the '--' argument"));
274 puts(_(" -B Run in batch mode (do not start the ncurses UI)"));
275 puts(_(" -b <address> Specify a blind carbon copy (Bcc) recipient"));
276 puts(_(" -c <address> Specify a carbon copy (Cc) recipient"));
277 puts(_(" -D Dump all config variables as 'name=value' pairs to stdout"));
278 puts(_(" -D -O Like -D, but show one-liner documentation"));
279 puts(_(" -D -S Like -D, but hide the value of sensitive variables"));
280 puts(_(" -d <level> Log debugging output to a file (default is \"~/.neomuttdebug0\")\n"
281 " The level can range from 1-5 and affects verbosity"));
282 puts(_(" -E Edit draft (-H) or include (-i) file during message composition"));
283 puts(_(" -e <command> Specify a command to be run after reading the config files"));
284 puts(_(" -F <config> Specify an alternative initialization file to read"));
285 puts(_(" -f <mailbox> Specify a mailbox (as defined with 'mailboxes' command) to load"));
286 puts(_(" -G Start NeoMutt with a listing of subscribed newsgroups"));
287 puts(_(" -g <server> Like -G, but start at specified news server"));
288 puts(_(" -H <draft> Specify a draft file with header and body for message composing"));
289 puts(_(" -h Print this help message and exit"));
290 puts(_(" -i <include> Specify an include file to be embedded in the body of a message"));
291 puts(_(" -l <file> Specify a file for debugging output (default \"~/.neomuttdebug0\")"));
292 puts(_(" -m <type> Specify a default mailbox format type for newly created folders\n"
293 " The type is either MH, MMDF, Maildir or mbox (case-insensitive)"));
294 puts(_(" -n Do not read the system-wide configuration file"));
295 puts(_(" -p Resume a prior postponed message, if any"));
296 puts(_(" -Q <variable> Query a configuration variable and print its value to stdout\n"
297 " (after the config has been read and any commands executed)\n"
298 " Add -O for one-liner documentation"));
299 puts(_(" -R Open mailbox in read-only mode"));
300 puts(_(" -s <subject> Specify a subject (must be enclosed in quotes if it has spaces)"));
301 puts(_(" -v Print the NeoMutt version and compile-time definitions and exit"));
302 puts(_(" -vv Print the NeoMutt license and copyright information and exit"));
303 puts(_(" -y Start NeoMutt with a listing of all defined mailboxes"));
304 puts(_(" -Z Open the first mailbox with new message or exit immediately with\n"
305 " exit code 1 if none is found in all defined mailboxes"));
306 puts(_(" -z Open the first or specified (-f) mailbox if it holds any message\n"
307 " or exit immediately with exit code 1 otherwise"));
308 // clang-format on
309
310 fflush(stdout);
311 return !ferror(stdout);
312}
#define _(a)
Definition: message.h:28
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1433
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ start_curses()

static int start_curses ( void  )
static

Start the Curses UI.

Return values
0Success
1Failure

Definition at line 319 of file main.c.

320{
321 km_init(); /* must come before mutt_init */
322
323 /* should come before initscr() so that ncurses 4.2 doesn't try to install
324 * its own SIGWINCH handler */
326
327 if (!initscr())
328 {
329 mutt_error(_("Error initializing terminal"));
330 return 1;
331 }
334 keypad(stdscr, true);
335 cbreak();
336 noecho();
337 nonl();
338 typeahead(-1); /* simulate smooth scrolling */
339 meta(stdscr, true);
341 /* Now that curses is set up, we drop back to normal screen mode.
342 * This simplifies displaying error messages to the user.
343 * The first call to refresh() will swap us back to curses screen mode. */
344 endwin();
345 return 0;
346}
void mutt_colors_init(void)
Initialize colours.
Definition: color.c:73
#define mutt_error(...)
Definition: logging2.h:92
void km_init(void)
Initialise all the menu keybindings.
Definition: init.c:180
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: init.c:137
void mutt_signal_init(void)
Initialise the signal handling.
Definition: mutt_signal.c:131
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_locale()

static void init_locale ( void  )
static

Initialise the Locale/NLS settings.

Definition at line 351 of file main.c.

352{
353 setlocale(LC_ALL, "");
354
355#ifdef ENABLE_NLS
356 const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
357 if (domdir)
358 bindtextdomain(PACKAGE, domdir);
359 else
360 bindtextdomain(PACKAGE, MUTTLOCALEDIR);
361 textdomain(PACKAGE);
362#endif
363#ifndef LOCALES_HACK
364 /* Do we have a locale definition? */
365 if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
366 {
367 OptLocales = true;
368 }
369#endif
370}
bool OptLocales
(pseudo) set if user has valid locale definition
Definition: mbyte.c:43
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:918
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_user_info()

static bool get_user_info ( struct ConfigSet cs)
static

Find the user's name, home and shell.

Parameters
csConfig Set
Return values
trueSuccess

Find the login name, real name, home directory and shell.

Definition at line 379 of file main.c.

380{
381 const char *shell = mutt_str_getenv("SHELL");
382 if (shell)
383 cs_str_initial_set(cs, "shell", shell, NULL);
384
385 /* Get some information about the user */
386 struct passwd *pw = getpwuid(getuid());
387 if (pw)
388 {
389 if (!Username)
390 Username = mutt_str_dup(pw->pw_name);
391 if (!HomeDir)
392 HomeDir = mutt_str_dup(pw->pw_dir);
393 if (!shell)
394 cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
395 }
396
397 if (!Username)
398 {
399 mutt_error(_("unable to determine username"));
400 return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
401 }
402
403 if (!HomeDir)
404 {
405 mutt_error(_("unable to determine home directory"));
406 return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
407 }
408
409 cs_str_reset(cs, "shell", NULL);
410 return true;
411}
char * HomeDir
User's home directory.
Definition: globals.c:39
int cs_str_initial_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:502
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:437
char * Username
User's login name.
Definition: globals.c:42
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ log_translation()

static void log_translation ( void  )
static

Log the translation being used.

Read the header info from the translation file.

Note
Call bindtextdomain() first

Definition at line 420 of file main.c.

421{
422 const char *header = ""; // Do not merge these two lines
423 header = _(header); // otherwise the .po files will end up badly ordered
424 const char *label = "Language:"; // the start of the lookup/needle
425 const char *lang = mutt_istr_find(header, label);
426 int len = 64;
427 if (lang)
428 {
429 lang += strlen(label); // skip label
430 SKIPWS(lang);
431 char *nl = strchr(lang, '\n');
432 if (nl)
433 len = (nl - lang);
434 }
435 else
436 {
437 lang = "NONE";
438 }
439
440 mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
441}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:593
#define SKIPWS(ch)
Definition: string2.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ log_gui()

static void log_gui ( void  )
static

Log info about the GUI.

Definition at line 446 of file main.c.

447{
448 const char *term = mutt_str_getenv("TERM");
449 const char *color_term = mutt_str_getenv("COLORTERM");
450 bool true_color = false;
451#ifdef NEOMUTT_DIRECT_COLORS
452 true_color = true;
453#endif
454
455 mutt_debug(LL_DEBUG1, "GUI:\n");
456 mutt_debug(LL_DEBUG1, " Curses: %s\n", curses_version());
457 mutt_debug(LL_DEBUG1, " COLORS=%d\n", COLORS);
458 mutt_debug(LL_DEBUG1, " COLOR_PAIRS=%d\n", COLOR_PAIRS);
459 mutt_debug(LL_DEBUG1, " TERM=%s\n", NONULL(term));
460 mutt_debug(LL_DEBUG1, " COLORTERM=%s\n", NONULL(color_term));
461 mutt_debug(LL_DEBUG1, " True color support: %s\n", true_color ? "YES" : "NO");
462 mutt_debug(LL_DEBUG1, " Screen: %dx%d\n", RootWindow->state.cols,
464}
struct MuttWindow * RootWindow
Parent of all Windows.
Definition: rootwin.c:106
#define NONULL(x)
Definition: string2.h:37
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *  argv[],
char *  envp[] 
)

Start NeoMutt.

Parameters
argcNumber of command line arguments
argvList of command line arguments
envpCopy of the environment
Return values
0Success
1Error

Definition at line 510 of file main.c.

513{
514 char *subject = NULL;
515 char *include_file = NULL;
516 char *draft_file = NULL;
517 char *new_type = NULL;
518 char *dlevel = NULL;
519 char *dfile = NULL;
520 const char *cli_nntp = NULL;
521 struct Email *e = NULL;
522 struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
523 struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
524 struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
525 struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
526 struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
527 struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
528 SendFlags sendflags = SEND_NO_FLAGS;
530 int version = 0;
531 int i;
532 bool explicit_folder = false;
533 bool dump_variables = false;
534 bool one_liner = false;
535 bool hide_sensitive = false;
536 bool batch_mode = false;
537 bool edit_infile = false;
538 int double_dash = argc, nargc = 1;
539 int rc = 1;
540 bool repeat_error = false;
541 struct Buffer folder = buf_make(0);
542 struct Buffer expanded_infile = buf_make(0);
543 struct Buffer tempfile = buf_make(0);
544 struct ConfigSet *cs = NULL;
545
547
548 /* sanity check against stupid administrators */
549 if (getegid() != getgid())
550 {
551 mutt_error("%s: I don't want to run with privileges!", (argc != 0) ? argv[0] : "neomutt");
552 goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
553 }
554
555 init_locale();
556
557 umask(077);
558
559 EnvList = envlist_init(envp);
560 for (optind = 1; optind < double_dash;)
561 {
562 /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
563 * encounters a non-option. That could be a file to attach
564 * (all non-options between -a and --) or it could be an address
565 * (which gets collapsed to the front of argv). */
566 for (; optind < argc; optind++)
567 {
568 if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
569 {
570 if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
571 double_dash = optind; /* quit outer loop after getopt */
572 break; /* drop through to getopt */
573 }
574
575 /* non-option, either an attachment or address */
576 if (!STAILQ_EMPTY(&attach))
577 mutt_list_insert_tail(&attach, mutt_str_dup(argv[optind]));
578 else
579 argv[nargc++] = argv[optind];
580 }
581
582 i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:i:hm:nOpQ:RSs:TvxyzZ");
583 if (i != EOF)
584 {
585 switch (i)
586 {
587 case 'A':
588 mutt_list_insert_tail(&alias_queries, mutt_str_dup(optarg));
589 break;
590 case 'a':
591 mutt_list_insert_tail(&attach, mutt_str_dup(optarg));
592 break;
593 case 'B':
594 batch_mode = true;
595 break;
596 case 'b':
597 mutt_list_insert_tail(&bcc_list, mutt_str_dup(optarg));
598 break;
599 case 'c':
600 mutt_list_insert_tail(&cc_list, mutt_str_dup(optarg));
601 break;
602 case 'D':
603 dump_variables = true;
604 break;
605 case 'd':
606 dlevel = optarg;
607 break;
608 case 'E':
609 edit_infile = true;
610 break;
611 case 'e':
612 mutt_list_insert_tail(&commands, mutt_str_dup(optarg));
613 break;
614 case 'F':
616 break;
617 case 'f':
618 buf_strcpy(&folder, optarg);
619 explicit_folder = true;
620 break;
621 case 'g': /* Specify a news server */
622 cli_nntp = optarg;
624
625 case 'G': /* List of newsgroups */
627 break;
628 case 'H':
629 draft_file = optarg;
630 break;
631 case 'i':
632 include_file = optarg;
633 break;
634 case 'l':
635 dfile = optarg;
636 break;
637 case 'm':
638 new_type = optarg;
639 break;
640 case 'n':
641 flags |= MUTT_CLI_NOSYSRC;
642 break;
643 case 'O':
644 one_liner = true;
645 break;
646 case 'p':
647 sendflags |= SEND_POSTPONED;
648 break;
649 case 'Q':
650 mutt_list_insert_tail(&queries, mutt_str_dup(optarg));
651 break;
652 case 'R':
653 flags |= MUTT_CLI_RO; /* read-only mode */
654 break;
655 case 'S':
656 hide_sensitive = true;
657 break;
658 case 's':
659 subject = optarg;
660 break;
661 case 'v':
662 version++;
663 break;
664 case 'y': /* My special hack mode */
665 flags |= MUTT_CLI_SELECT;
666 break;
667 case 'Z':
669 break;
670 case 'z':
671 flags |= MUTT_CLI_IGNORE;
672 break;
673 default:
674 OptNoCurses = true;
675 if (usage())
676 goto main_ok; // TEST03: neomutt -9
677 else
678 goto main_curses;
679 }
680 }
681 }
682
683 /* collapse remaining argv */
684 while (optind < argc)
685 argv[nargc++] = argv[optind++];
686 optind = 1;
687 argc = nargc;
688
689 if (version > 0)
690 {
692 bool done;
693 if (version == 1)
694 done = print_version(stdout);
695 else
696 done = print_copyright();
697 OptNoCurses = true;
698 if (done)
699 goto main_ok; // TEST04: neomutt -v
700 else
701 goto main_curses;
702 }
703
706
707 cs = cs_new(500);
708 if (!cs)
709 goto main_curses;
710
711 NeoMutt = neomutt_new(cs);
712 init_config(cs);
713 subjrx_init();
714 attach_init();
716
717#ifdef USE_DEBUG_NOTIFY
719#endif
720
721 if (!get_user_info(cs))
722 goto main_exit;
723
724 reset_tilde(cs);
725
726 if (dfile)
727 {
728 cs_str_initial_set(cs, "debug_file", dfile, NULL);
729 cs_str_reset(cs, "debug_file", NULL);
730 }
731
732 if (dlevel)
733 {
734 short num = 0;
735 if (!mutt_str_atos_full(dlevel, &num) || (num < LL_MESSAGE) || (num >= LL_MAX))
736 {
737 mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
738 goto main_exit; // TEST07: neomutt -d xyz
739 }
740 cs_str_initial_set(cs, "debug_level", dlevel, NULL);
741 cs_str_reset(cs, "debug_level", NULL);
742 }
743
747
748 if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
749 {
750 e = email_new();
751 e->env = mutt_env_new();
752
753 struct ListNode *np = NULL;
754 STAILQ_FOREACH(np, &bcc_list, entries)
755 {
756 mutt_addrlist_parse(&e->env->bcc, np->data);
757 }
758
759 STAILQ_FOREACH(np, &cc_list, entries)
760 {
761 mutt_addrlist_parse(&e->env->cc, np->data);
762 }
763
764 mutt_list_free(&bcc_list);
765 mutt_list_free(&cc_list);
766 }
767
768 /* Check for a batch send. */
769 if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
770 dump_variables || batch_mode)
771 {
772 OptNoCurses = true;
773 sendflags = SEND_BATCH;
776 }
777
778 /* Check to make sure stdout is available in curses mode. */
779 if (!OptNoCurses && !isatty(1))
780 goto main_curses;
781
782 /* This must come before mutt_init() because curses needs to be started
783 * before calling the init_pair() function to set the color scheme. */
784 if (!OptNoCurses)
785 {
786 int crc = start_curses();
787 if (crc != 0)
788 goto main_curses; // TEST08: can't test -- fake term?
789 }
790
791 /* Always create the mutt_windows because batch mode has some shared code
792 * paths that end up referencing them. */
793 rootwin_new();
794
795 if (!OptNoCurses)
796 {
797 /* check whether terminal status is supported (must follow curses init) */
800 log_gui();
801 }
802
803 /* set defaults and read init files */
804 int rc2 = mutt_init(cs, dlevel, dfile, flags & MUTT_CLI_NOSYSRC, &commands);
805 if (rc2 != 0)
806 goto main_curses;
807
809
810 /* "$news_server" precedence: command line, config file, environment, system file */
811 if (!cli_nntp)
812 cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
813
814 if (!cli_nntp)
815 cli_nntp = mutt_str_getenv("NNTPSERVER");
816
817 if (!cli_nntp)
818 {
819 char buf[1024] = { 0 };
820 cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
821 }
822
823 if (cli_nntp)
824 {
825 cs_str_initial_set(cs, "news_server", cli_nntp, NULL);
826 cs_str_reset(cs, "news_server", NULL);
827 }
828
829 /* Initialize crypto backends. */
830 crypt_init();
831
832 if (new_type)
833 {
834 struct Buffer err = buf_make(0);
835 int r = cs_str_initial_set(cs, "mbox_type", new_type, &err);
836 if (CSR_RESULT(r) != CSR_SUCCESS)
837 {
838 mutt_error("%s", err.data);
839 buf_dealloc(&err);
840 goto main_curses;
841 }
842 cs_str_reset(cs, "mbox_type", NULL);
843 }
844
845 if (!STAILQ_EMPTY(&queries))
846 {
847 rc = mutt_query_variables(&queries, one_liner);
848 goto main_curses;
849 }
850
851 if (dump_variables)
852 {
854 if (hide_sensitive)
855 cdflags |= CS_DUMP_HIDE_SENSITIVE;
856 if (one_liner)
857 cdflags |= CS_DUMP_SHOW_DOCS;
858 dump_config(cs, cdflags, stdout);
859 goto main_ok; // TEST18: neomutt -D
860 }
861
862 if (!STAILQ_EMPTY(&alias_queries))
863 {
864 rc = 0;
865 for (; optind < argc; optind++)
866 mutt_list_insert_tail(&alias_queries, mutt_str_dup(argv[optind]));
867 struct ListNode *np = NULL;
868 STAILQ_FOREACH(np, &alias_queries, entries)
869 {
870 struct AddressList *al = alias_lookup(np->data);
871 if (al)
872 {
873 /* output in machine-readable form */
874 mutt_addrlist_to_intl(al, NULL);
875 struct Buffer *buf = buf_pool_get();
876 mutt_addrlist_write(al, buf, false);
877 printf("%s\n", buf_string(buf));
878 buf_pool_release(&buf);
879 }
880 else
881 {
882 rc = 1;
883 printf("%s\n", np->data); // TEST19: neomutt -A unknown
884 }
885 }
886 mutt_list_free(&alias_queries);
887 goto main_curses; // TEST20: neomutt -A alias
888 }
889
890 if (!OptNoCurses)
891 {
893 clear();
897 }
898
899#ifdef USE_AUTOCRYPT
900 /* Initialize autocrypt after curses messages are working,
901 * because of the initial account setup screens. */
902 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
903 if (c_autocrypt)
904 mutt_autocrypt_init(!(sendflags & SEND_BATCH));
905#endif
906
907 /* Create the `$folder` directory if it doesn't exist. */
908 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
909 if (!OptNoCurses && c_folder)
910 {
911 struct stat st = { 0 };
912 struct Buffer *fpath = buf_pool_get();
913
914 buf_strcpy(fpath, c_folder);
915 buf_expand_path(fpath);
916 bool skip = false;
917 /* we're not connected yet - skip mail folder creation */
918 skip |= (imap_path_probe(buf_string(fpath), NULL) == MUTT_IMAP);
919 skip |= (pop_path_probe(buf_string(fpath), NULL) == MUTT_POP);
920 skip |= (nntp_path_probe(buf_string(fpath), NULL) == MUTT_NNTP);
921 if (!skip && (stat(buf_string(fpath), &st) == -1) && (errno == ENOENT))
922 {
923 char msg2[256];
924 snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
925 if (query_yesorno(msg2, MUTT_YES) == MUTT_YES)
926 {
927 if ((mkdir(buf_string(fpath), 0700) == -1) && (errno != EEXIST))
928 mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
929 }
930 }
931 buf_pool_release(&fpath);
932 }
933
934 if (batch_mode)
935 {
936 goto main_ok; // TEST22: neomutt -B
937 }
938 StartupComplete = true;
939
944
945 if (sendflags & SEND_POSTPONED)
946 {
947 if (!OptNoCurses)
949 if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
950 rc = 0;
951 // TEST23: neomutt -p (postponed message, cancel)
952 // TEST24: neomutt -p (no postponed message)
954 repeat_error = true;
955 goto main_curses;
956 }
957 else if (subject || e || draft_file || include_file ||
958 !STAILQ_EMPTY(&attach) || (optind < argc))
959 {
960 FILE *fp_in = NULL;
961 FILE *fp_out = NULL;
962 char *infile = NULL;
963 char *bodytext = NULL;
964 const char *bodyfile = NULL;
965 int rv = 0;
966
967 if (!OptNoCurses)
969
970 if (!e)
971 e = email_new();
972 if (!e->env)
973 e->env = mutt_env_new();
974
975 for (i = optind; i < argc; i++)
976 {
977 if (url_check_scheme(argv[i]) == U_MAILTO)
978 {
979 if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
980 {
981 mutt_error(_("Failed to parse mailto: link"));
982 email_free(&e);
983 goto main_curses; // TEST25: neomutt mailto:?
984 }
985 }
986 else
987 {
988 mutt_addrlist_parse(&e->env->to, argv[i]);
989 }
990 }
991
992 const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
993 if (!draft_file && c_auto_edit && TAILQ_EMPTY(&e->env->to) &&
994 TAILQ_EMPTY(&e->env->cc))
995 {
996 mutt_error(_("No recipients specified"));
997 email_free(&e);
998 goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
999 }
1000
1001 if (subject)
1002 {
1003 mutt_str_replace(&e->env->subject, subject);
1004 }
1005
1006 if (draft_file)
1007 {
1008 infile = draft_file;
1009 include_file = NULL;
1010 }
1011 else if (include_file)
1012 {
1013 infile = include_file;
1014 }
1015 else
1016 {
1017 edit_infile = false;
1018 }
1019
1020 if (infile || bodytext)
1021 {
1022 /* Prepare fp_in and expanded_infile. */
1023 if (infile)
1024 {
1025 if (mutt_str_equal("-", infile))
1026 {
1027 if (edit_infile)
1028 {
1029 mutt_error(_("Can't use -E flag with stdin"));
1030 email_free(&e);
1031 goto main_curses; // TEST27: neomutt -E -H -
1032 }
1033 fp_in = stdin;
1034 }
1035 else
1036 {
1037 buf_strcpy(&expanded_infile, infile);
1038 buf_expand_path(&expanded_infile);
1039 fp_in = fopen(buf_string(&expanded_infile), "r");
1040 if (!fp_in)
1041 {
1042 mutt_perror("%s", buf_string(&expanded_infile));
1043 email_free(&e);
1044 goto main_curses; // TEST28: neomutt -E -H missing
1045 }
1046 }
1047 }
1048
1049 if (edit_infile)
1050 {
1051 /* If editing the infile, keep it around afterwards so
1052 * it doesn't get unlinked, and we can rebuild the draft_file */
1053 sendflags |= SEND_NO_FREE_HEADER;
1054 }
1055 else
1056 {
1057 /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1058 * Note: stdin is always copied to a tempfile, ensuring draft_file
1059 * can stat and get the correct st_size below. */
1060 buf_mktemp(&tempfile);
1061
1062 fp_out = mutt_file_fopen(buf_string(&tempfile), "w");
1063 if (!fp_out)
1064 {
1065 mutt_file_fclose(&fp_in);
1066 mutt_perror("%s", buf_string(&tempfile));
1067 email_free(&e);
1068 goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1069 }
1070 if (fp_in)
1071 {
1072 mutt_file_copy_stream(fp_in, fp_out);
1073 if (fp_in != stdin)
1074 mutt_file_fclose(&fp_in);
1075 }
1076 else if (bodytext)
1077 {
1078 fputs(bodytext, fp_out);
1079 }
1080 mutt_file_fclose(&fp_out);
1081
1082 fp_in = fopen(buf_string(&tempfile), "r");
1083 if (!fp_in)
1084 {
1085 mutt_perror("%s", buf_string(&tempfile));
1086 email_free(&e);
1087 goto main_curses; // TEST30: can't test
1088 }
1089 }
1090
1091 /* Parse the draft_file into the full Email/Body structure.
1092 * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1093 * our e->body. */
1094 if (draft_file)
1095 {
1096 struct Envelope *opts_env = e->env;
1097 struct stat st = { 0 };
1098
1099 sendflags |= SEND_DRAFT_FILE;
1100
1101 /* Set up a tmp Email with just enough information so that
1102 * mutt_prepare_template() can parse the message in fp_in. */
1103 struct Email *e_tmp = email_new();
1104 e_tmp->offset = 0;
1105 e_tmp->body = mutt_body_new();
1106 if (fstat(fileno(fp_in), &st) != 0)
1107 {
1108 mutt_perror("%s", draft_file);
1109 email_free(&e);
1110 email_free(&e_tmp);
1111 goto main_curses; // TEST31: can't test
1112 }
1113 e_tmp->body->length = st.st_size;
1114
1115 if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1116 {
1117 mutt_error(_("Can't parse message template: %s"), draft_file);
1118 email_free(&e);
1119 email_free(&e_tmp);
1120 goto main_curses;
1121 }
1122
1123 /* Scan for neomutt header to set `$resume_draft_files` */
1124 struct ListNode *np = NULL, *tmp = NULL;
1125 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1126 STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1127 {
1128 if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1129 {
1130 if (c_resume_edited_draft_files)
1131 cs_str_native_set(cs, "resume_draft_files", true, NULL);
1132
1133 STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1134 FREE(&np->data);
1135 FREE(&np);
1136 }
1137 }
1138
1139 mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1140 mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1141 mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1142 if (opts_env->subject)
1143 mutt_str_replace(&e->env->subject, opts_env->subject);
1144
1145 mutt_env_free(&opts_env);
1146 email_free(&e_tmp);
1147 }
1148 /* Editing the include_file: pass it directly in.
1149 * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1150 else if (edit_infile)
1151 bodyfile = buf_string(&expanded_infile);
1152 // For bodytext and unedited include_file: use the tempfile.
1153 else
1154 bodyfile = buf_string(&tempfile);
1155
1156 mutt_file_fclose(&fp_in);
1157 }
1158
1159 FREE(&bodytext);
1160
1161 if (!STAILQ_EMPTY(&attach))
1162 {
1163 struct Body *b = e->body;
1164
1165 while (b && b->next)
1166 b = b->next;
1167
1168 struct ListNode *np = NULL;
1169 STAILQ_FOREACH(np, &attach, entries)
1170 {
1171 if (b)
1172 {
1174 b = b->next;
1175 }
1176 else
1177 {
1179 e->body = b;
1180 }
1181 if (!b)
1182 {
1183 mutt_error(_("%s: unable to attach file"), np->data);
1184 mutt_list_free(&attach);
1185 email_free(&e);
1186 goto main_curses; // TEST32: neomutt john@example.com -a missing
1187 }
1188 }
1189 mutt_list_free(&attach);
1190 }
1191
1192 rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1193 /* We WANT the "Mail sent." and any possible, later error */
1195 if (ErrorBufMessage)
1196 mutt_message("%s", ErrorBuf);
1197
1198 if (edit_infile)
1199 {
1200 if (draft_file)
1201 {
1202 if (truncate(buf_string(&expanded_infile), 0) == -1)
1203 {
1204 mutt_perror("%s", buf_string(&expanded_infile));
1205 email_free(&e);
1206 goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1207 }
1208 fp_out = mutt_file_fopen(buf_string(&expanded_infile), "a");
1209 if (!fp_out)
1210 {
1211 mutt_perror("%s", buf_string(&expanded_infile));
1212 email_free(&e);
1213 goto main_curses; // TEST34: can't test
1214 }
1215
1216 /* If the message was sent or postponed, these will already
1217 * have been done. */
1218 if (rv < 0)
1219 {
1220 if (e->body->next)
1221 e->body = mutt_make_multipart(e->body);
1223 mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1224 mutt_env_to_intl(e->env, NULL, NULL);
1225 }
1226
1227 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1229 c_crypt_protected_headers_read &&
1231 NeoMutt->sub);
1232 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1233 if (c_resume_edited_draft_files)
1234 fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1235 fputc('\n', fp_out);
1236 if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1237 {
1238 mutt_file_fclose(&fp_out);
1239 email_free(&e);
1240 goto main_curses; // TEST35: can't test
1241 }
1242 mutt_file_fclose(&fp_out);
1243 }
1244
1245 email_free(&e);
1246 }
1247
1248 /* !edit_infile && draft_file will leave the tempfile around */
1249 if (!buf_is_empty(&tempfile))
1250 unlink(buf_string(&tempfile));
1251
1253
1254 if (rv != 0)
1255 goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1256 }
1257 else if (sendflags & SEND_BATCH)
1258 {
1259 /* This guards against invoking `neomutt < /dev/null` and accidentally
1260 * sending an email due to a my_hdr or other setting. */
1261 mutt_error(_("No recipients specified"));
1262 goto main_curses;
1263 }
1264 else
1265 {
1266 if (flags & MUTT_CLI_MAILBOX)
1267 {
1268 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1269 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1271 if (mutt_mailbox_check(NULL, csflags) == 0)
1272 {
1273 mutt_message(_("No mailbox with new mail"));
1274 goto main_curses; // TEST37: neomutt -Z (no new mail)
1275 }
1276 buf_reset(&folder);
1277 mutt_mailbox_next(NULL, &folder);
1278 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1279 }
1280 else if (flags & MUTT_CLI_SELECT)
1281 {
1282 if (flags & MUTT_CLI_NEWS)
1283 {
1284 const char *const c_news_server = cs_subset_string(NeoMutt->sub, "news_server");
1285 OptNews = true;
1286 struct Mailbox *m_cur = get_current_mailbox();
1287 CurrentNewsSrv = nntp_select_server(m_cur, c_news_server, false);
1288 if (!CurrentNewsSrv)
1289 goto main_curses; // TEST38: neomutt -G (unset news_server)
1290 }
1291 else if (TAILQ_EMPTY(&NeoMutt->accounts))
1292 {
1293 mutt_error(_("No incoming mailboxes defined"));
1294 goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1295 }
1296 buf_reset(&folder);
1297 struct Mailbox *m_cur = get_current_mailbox();
1298 dlg_browser(&folder, MUTT_SEL_FOLDER | MUTT_SEL_MAILBOX, m_cur, NULL, NULL);
1299 if (buf_is_empty(&folder))
1300 {
1301 goto main_ok; // TEST40: neomutt -y (quit selection)
1302 }
1303 }
1304
1305 if (buf_is_empty(&folder))
1306 {
1307 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1308 if (c_spool_file)
1309 {
1310 // Check if `$spool_file` corresponds a mailboxes' description.
1311 struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1312 if (m_desc)
1313 buf_strcpy(&folder, m_desc->realpath);
1314 else
1315 buf_strcpy(&folder, c_spool_file);
1316 }
1317 else if (c_folder)
1318 {
1319 buf_strcpy(&folder, c_folder);
1320 }
1321 /* else no folder */
1322 }
1323
1324 if (OptNews)
1325 {
1326 OptNews = false;
1327 buf_alloc(&folder, PATH_MAX);
1329 }
1330 else
1331 {
1332 buf_expand_path(&folder);
1333 }
1334
1337
1338 if (flags & MUTT_CLI_IGNORE)
1339 {
1340 /* check to see if there are any messages in the folder */
1341 switch (mx_path_is_empty(&folder))
1342 {
1343 case -1:
1344 mutt_perror("%s", buf_string(&folder));
1345 goto main_curses; // TEST41: neomutt -z -f missing
1346 case 1:
1347 mutt_error(_("Mailbox is empty"));
1348 goto main_curses; // TEST42: neomutt -z -f /dev/null
1349 }
1350 }
1351
1352 mutt_folder_hook(buf_string(&folder), NULL);
1354 mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1356
1358 window_redraw(NULL);
1359
1360 repeat_error = true;
1361 struct Mailbox *m = mx_resolve(buf_string(&folder));
1362 const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1363 if (!mx_mbox_open(m, ((flags & MUTT_CLI_RO) || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1364 {
1365 if (m->account)
1367
1368 mailbox_free(&m);
1369 mutt_error(_("Unable to open mailbox %s"), buf_string(&folder));
1370 repeat_error = false;
1371 }
1372 if (m || !explicit_folder)
1373 {
1374 struct MuttWindow *dlg = index_pager_init();
1375 dialog_push(dlg);
1376
1378 m = dlg_index(dlg, m);
1380 mailbox_free(&m);
1381
1382 dialog_pop();
1383 mutt_window_free(&dlg);
1385 repeat_error = false;
1386 }
1388#ifdef USE_SASL_CYRUS
1390#endif
1391#ifdef USE_SASL_GNU
1393#endif
1394#ifdef USE_AUTOCRYPT
1396#endif
1397 // TEST43: neomutt (no change to mailbox)
1398 // TEST44: neomutt (change mailbox)
1399 }
1400
1401main_ok:
1402 rc = 0;
1403main_curses:
1404 mutt_endwin();
1406 /* Repeat the last message to the user */
1407 if (repeat_error && ErrorBufMessage)
1408 puts(ErrorBuf);
1409main_exit:
1410 if (NeoMutt && NeoMutt->sub)
1411 {
1416 }
1417 mutt_list_free(&commands);
1419 buf_dealloc(&folder);
1420 buf_dealloc(&expanded_infile);
1421 buf_dealloc(&tempfile);
1422 mutt_list_free(&queries);
1429 menu_cleanup();
1430 crypt_cleanup();
1440 cs_free(&cs);
1442 mutt_log_stop();
1443 return rc;
1444}
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:97
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:762
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1207
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:478
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1294
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:280
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
void attach_init(void)
Set up the attachments lists.
Definition: attachments.c:105
void attach_cleanup(void)
Free the attachments lists.
Definition: attachments.c:91
void mutt_autocrypt_cleanup(void)
Shutdown Autocrypt.
Definition: autocrypt.c:128
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:96
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: lib.h:58
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: lib.h:60
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:389
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:349
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:58
bool dump_config(struct ConfigSet *cs, ConfigDumpFlags flags, FILE *fp)
Write all the config to a file.
Definition: dump.c:165
#define CS_DUMP_HIDE_SENSITIVE
Obscure sensitive information like passwords.
Definition: dump.h:37
uint16_t ConfigDumpFlags
Flags for dump_config(), e.g. CS_DUMP_ONLY_CHANGED.
Definition: dump.h:34
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
#define CS_DUMP_SHOW_DOCS
Show one-liner documentation for the config item.
Definition: dump.h:45
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
void cs_free(struct ConfigSet **ptr)
Free a Config Set.
Definition: set.c:138
struct ConfigSet * cs_new(size_t size)
Create a new Config Set.
Definition: set.c:124
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:781
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
void config_cache_cleanup(void)
Cleanup the cache of charset config variables.
Definition: config_cache.c:144
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1089
void crypto_module_cleanup(void)
Clean up the crypto modules.
Definition: crypt_mod.c:83
void crypt_cleanup(void)
Clean up backend.
Definition: cryptglue.c:142
void crypt_init(void)
Initialise the crypto backends.
Definition: cryptglue.c:94
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: get.c:57
int debug_all_observer(struct NotifyCallback *nc)
Definition: notify.c:205
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:109
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:142
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: dlg_browser.c:153
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1391
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1694
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:326
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
void envlist_free(char ***envp)
Free the private copy of the environment.
Definition: envlist.c:41
char ** envlist_init(char **envp)
Create a copy of the environment.
Definition: envlist.c:57
void external_cleanup(void)
Clean up commands globals.
Definition: external.c:80
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:262
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
Definition: file.c:1447
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:75
char * LastFolder
Previously selected mailbox.
Definition: globals.c:45
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: globals.c:77
char ErrorBuf[1024]
Copy of the last error message.
Definition: globals.c:37
bool ErrorBufMessage
true if the last message was an error
Definition: globals.c:36
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:44
struct ListHead Muttrc
List of config files to read.
Definition: globals.c:53
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:83
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:1226
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition: dlg_index.c:1057
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:397
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:440
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:87
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_perror(...)
Definition: logging2.h:93
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe() -.
Definition: nntp.c:2738
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe() -.
Definition: pop.c:1157
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2327
int main_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: init.c:265
int main_hist_observer(struct NotifyCallback *nc)
Notification that a Config Variable has change - Implements observer_t -.
Definition: history.c:699
int main_timeout_observer(struct NotifyCallback *nc)
Notification that a timeout has occurred - Implements observer_t -.
Definition: main.c:469
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:148
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:575
@ MUTT_WRITE_HEADER_POSTPONE
A postponed Email, just the envelope info.
Definition: header.h:42
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:930
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:597
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:54
void imap_logout_all(void)
Close all open connections.
Definition: imap.c:546
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:662
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:618
int mutt_init(struct ConfigSet *cs, const char *dlevel, const char *dfile, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:316
void mutt_opts_cleanup(void)
Clean up before quitting.
Definition: init.c:260
void init_config(struct ConfigSet *cs)
Initialise the config system.
Definition: mutt_config.c:721
void mutt_keys_cleanup(void)
Free the key maps.
Definition: init.c:230
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: init.c:243
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
int(*) log_dispatcher_ MuttLogger)
@ LL_MESSAGE
Log informational message.
Definition: logging2.h:42
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
@ LL_MAX
Definition: logging2.h:50
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:90
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:180
@ 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
#define MUTT_CLI_SELECT
-y Start with a list of all mailboxes
Definition: main.c:197
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition: main.c:351
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:191
static void log_translation(void)
Log the translation being used.
Definition: main.c:420
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:194
static void log_gui(void)
Log info about the GUI.
Definition: main.c:446
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:205
static bool usage(void)
Display NeoMutt command line.
Definition: main.c:242
static int start_curses(void)
Start the Curses UI.
Definition: main.c:319
bool StartupComplete
When the config has been read.
Definition: main.c:188
static bool get_user_info(struct ConfigSet *cs)
Find the user's name, home and shell.
Definition: main.c:379
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:196
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:192
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:193
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:198
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:195
#define FREE(x)
Definition: memory.h:45
void menu_cleanup(void)
Free the saved Menu searches.
Definition: menu.c:66
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
void mutt_ch_cache_cleanup(void)
Clean up the cached iconv handles and charset strings.
Definition: charset.c:1173
#define FALLTHROUGH
Definition: lib.h:111
void log_queue_empty(void)
Free the contents of the queue.
Definition: logging.c:323
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition: logging.c:311
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:345
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
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
#define PATH_MAX
Definition: mutt.h:41
void mutt_temp_attachments_cleanup(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1308
enum MuttCursorState mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:96
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:81
void mutt_resize_screen(void)
Update NeoMutt's opinion about the window size.
Definition: resize.c:74
@ MUTT_CURSOR_INVISIBLE
Hide the cursor.
Definition: mutt_curses.h:59
@ MUTT_CURSOR_VISIBLE
Display a normal cursor.
Definition: mutt_curses.h:60
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:180
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:170
int mutt_mailbox_check(struct Mailbox *m_cur, CheckStatsFlags flags)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:166
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
Definition: mutt_mailbox.c:366
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:634
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:202
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:329
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:284
struct Mailbox * mx_resolve(const char *path_or_name)
Get a Mailbox from either a path or name.
Definition: mx.c:1721
int mx_path_is_empty(struct Buffer *path)
Is the mailbox empty.
Definition: mx.c:1257
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:43
#define MUTT_MAILBOX_CHECK_IMMEDIATE
Don't postpone the actual checking.
Definition: mxapi.h:56
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:40
#define MUTT_MAILBOX_CHECK_FORCE
Ignore MailboxTime and check for new mail.
Definition: mxapi.h:54
uint8_t CheckStatsFlags
Flags for mutt_mailbox_check.
Definition: mxapi.h:52
struct NeoMutt * neomutt_new(struct ConfigSet *cs)
Create the main NeoMutt object.
Definition: neomutt.c:44
void neomutt_free(struct NeoMutt **ptr)
Free a NeoMutt.
Definition: neomutt.c:80
@ NT_GLOBAL_STARTUP
NeoMutt is initialised.
Definition: neomutt.h:59
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:564
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:1021
@ 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
void buf_pool_cleanup(void)
Release the Buffer pool.
Definition: pool.c:67
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:481
void mutt_prex_cleanup(void)
Cleanup heap memory allocated by compiled regexes.
Definition: prex.c:330
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:330
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void rootwin_cleanup(void)
Free all the default Windows.
Definition: rootwin.c:202
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:785
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:301
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
RFC2047 encode the content-descriptions.
Definition: send.c:1554
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:2099
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:45
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:49
#define SEND_DRAFT_FILE
Used by the -H flag.
Definition: send.h:50
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:44
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:39
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:38
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:605
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:778
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:71
size_t dsize
Length of data.
Definition: buffer.h:37
Container for lots of config items.
Definition: set.h:252
struct Notify * notify
Notifications: NotifyConfig, EventConfig.
Definition: subset.h:52
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
The envelope/body of an email.
Definition: email.h:37
struct Envelope * env
Envelope information.
Definition: email.h:66
struct Body * body
List of MIME parts.
Definition: email.h:67
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
The header of an Email.
Definition: envelope.h:57
struct ListHead userhdrs
user defined headers
Definition: envelope.h:85
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
char * subject
Email's subject.
Definition: envelope.h:70
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
A mailbox.
Definition: mailbox.h:79
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:126
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct Notify * notify_resize
Window resize notifications handler.
Definition: neomutt.h:43
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:46
struct Notify * notify
Notifications handler.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
struct Connection * conn
Connection to NNTP Server.
Definition: adata.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
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:304
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:41
bool mutt_ts_capability(void)
Check terminal capabilities.
Definition: terminal.c:55
#define buf_mktemp(buf)
Definition: tmp.h:33
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:225
@ U_MAILTO
Url is mailto://.
Definition: url.h:45
bool print_copyright(void)
Print copyright message.
Definition: version.c:519
bool print_version(FILE *fp)
Print system and compile info to a file.
Definition: version.c:394

Variable Documentation

◆ StartupComplete

bool StartupComplete = false

When the config has been read.

Definition at line 188 of file main.c.