NeoMutt  2022-04-29-369-gff76d0
Teaching an old dog new tricks
DOXYGEN
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 "index/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "postpone/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "alternates.h"
#include "commands.h"
#include "hook.h"
#include "init.h"
#include "keymap.h"
#include "mutt_globals.h"
#include "mutt_history.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "muttlib.h"
#include "mx.h"
#include "myvar.h"
#include "options.h"
#include "protos.h"
#include "subjectrx.h"
#include "version.h"
#include <libintl.h>
#include "imap/lib.h"
#include "pop/lib.h"
#include "nntp/lib.h"
#include "nntp/adata.h"
#include "autocrypt/lib.h"

Go to the source code of this file.

Macros

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

Typedefs

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

Functions

static void reset_tilde (struct ConfigSet *cs)
 Temporary measure. More...
 
void mutt_exit (int code)
 Leave NeoMutt NOW. More...
 
static bool usage (void)
 Display NeoMutt command line. More...
 
static int start_curses (void)
 Start the Curses UI. More...
 
static void init_locale (void)
 Initialise the Locale/NLS settings. More...
 
static bool get_user_info (struct ConfigSet *cs)
 Find the user's name, home and shell. More...
 
static void log_translation (void)
 Log the translation being used. More...
 
int main (int argc, char *argv[], char *envp[])
 Start NeoMutt. More...
 

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

◆ MAIN_C

#define MAIN_C   1

Definition at line 138 of file main.c.

◆ GNULIB_defined_setlocale

#define GNULIB_defined_setlocale

Definition at line 139 of file main.c.

◆ MUTT_CLI_NO_FLAGS

#define MUTT_CLI_NO_FLAGS   0

No flags are set.

Definition at line 208 of file main.c.

◆ MUTT_CLI_IGNORE

#define MUTT_CLI_IGNORE   (1 << 0)

-z Open first mailbox if it has mail

Definition at line 209 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 210 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 211 of file main.c.

◆ MUTT_CLI_RO

#define MUTT_CLI_RO   (1 << 3)

-R Open mailbox in read-only mode

Definition at line 212 of file main.c.

◆ MUTT_CLI_SELECT

#define MUTT_CLI_SELECT   (1 << 4)

-y Start with a list of all mailboxes

Definition at line 213 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 215 of file main.c.

Typedef Documentation

◆ CliFlags

typedef uint8_t CliFlags

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

Definition at line 207 of file main.c.

Function Documentation

◆ reset_tilde()

static void reset_tilde ( struct ConfigSet cs)
static

Temporary measure.

Parameters
csConfig Set

Definition at line 223 of file main.c.

224{
225 static const char *names[] = { "folder", "mbox", "postponed", "record" };
226
227 struct Buffer value = mutt_buffer_make(256);
228 for (size_t i = 0; i < mutt_array_size(names); i++)
229 {
230 struct HashElem *he = cs_get_elem(cs, names[i]);
231 if (!he)
232 continue;
233 mutt_buffer_reset(&value);
234 cs_he_initial_get(cs, he, &value);
235 mutt_buffer_expand_path_regex(&value, false);
236 cs_he_initial_set(cs, he, value.data, NULL);
237 cs_he_reset(cs, he, NULL);
238 }
239 mutt_buffer_dealloc(&value);
240}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
#define mutt_array_size(x)
Definition: memory.h:36
void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:135
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition: set.c:204
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:346
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:416
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:484
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 246 of file main.c.

247{
248 mutt_endwin();
249#ifdef HAVE_LIBUNWIND
250 if (code != 0)
252#endif
253 exit(code);
254}
void show_backtrace(void)
Log the program's call stack.
Definition: backtrace.c:39
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:354
+ 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 260 of file main.c.

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

338{
339 km_init(); /* must come before mutt_init */
340
341 /* should come before initscr() so that ncurses 4.2 doesn't try to install
342 * its own SIGWINCH handler */
344
345 if (!initscr())
346 {
347 mutt_error(_("Error initializing terminal"));
348 return 1;
349 }
352 keypad(stdscr, true);
353 cbreak();
354 noecho();
355 nonl();
356 typeahead(-1); /* simulate smooth scrolling */
357 meta(stdscr, true);
359 /* Now that curses is set up, we drop back to normal screen mode.
360 * This simplifies displaying error messages to the user.
361 * The first call to refresh() will swap us back to curses screen mode. */
362 endwin();
363 return 0;
364}
void mutt_colors_init(void)
Initialize colours.
Definition: color.c:81
#define mutt_error(...)
Definition: logging.h:87
void km_init(void)
Initialise all the menu keybindings.
Definition: keymap.c:1025
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: keymap.c:996
void mutt_signal_init(void)
Initialise the signal handling.
Definition: mutt_signal.c:130
+ 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 369 of file main.c.

370{
371 setlocale(LC_ALL, "");
372
373#ifdef ENABLE_NLS
374 const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
375 if (domdir)
376 bindtextdomain(PACKAGE, domdir);
377 else
378 bindtextdomain(PACKAGE, MUTTLOCALEDIR);
379 textdomain(PACKAGE);
380#endif
381#ifndef LOCALES_HACK
382 /* Do we have a locale definition? */
383 if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
384 {
385 OptLocales = true;
386 }
387#endif
388}
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:927
+ 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 397 of file main.c.

398{
399 const char *shell = mutt_str_getenv("SHELL");
400 if (shell)
401 cs_str_initial_set(cs, "shell", shell, NULL);
402
403 /* Get some information about the user */
404 struct passwd *pw = getpwuid(getuid());
405 if (pw)
406 {
407 if (!Username)
408 Username = mutt_str_dup(pw->pw_name);
409 if (!HomeDir)
410 HomeDir = mutt_str_dup(pw->pw_dir);
411 if (!shell)
412 cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
413 }
414
415 if (!Username)
416 {
417 mutt_error(_("unable to determine username"));
418 return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
419 }
420
421 if (!HomeDir)
422 {
423 mutt_error(_("unable to determine home directory"));
424 return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
425 }
426
427 cs_str_reset(cs, "shell", NULL);
428 return true;
429}
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
char * Username
User's login name.
Definition: mutt_globals.h:52
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:458
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:393
+ 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 438 of file main.c.

439{
440 const char *header = ""; // Do not merge these two lines
441 header = _(header); // otherwise the .po files will end up badly ordered
442 const char *label = "Language:"; // the start of the lookup/needle
443 const char *lang = mutt_istr_find(header, label);
444 int len = 64;
445 if (lang)
446 {
447 lang += strlen(label); // skip label
448 SKIPWS(lang);
449 char *nl = strchr(lang, '\n');
450 if (nl)
451 len = (nl - lang);
452 }
453 else
454 {
455 lang = "NONE";
456 }
457
458 mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
459}
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:592
#define SKIPWS(ch)
Definition: string2.h:46
+ 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 473 of file main.c.

476{
477 char *subject = NULL;
478 char *include_file = NULL;
479 char *draft_file = NULL;
480 char *new_type = NULL;
481 char *dlevel = NULL;
482 char *dfile = NULL;
483#ifdef USE_NNTP
484 const char *cli_nntp = NULL;
485#endif
486 struct Email *e = NULL;
487 struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
488 struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
489 struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
490 struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
491 struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
492 struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
493 SendFlags sendflags = SEND_NO_FLAGS;
495 int version = 0;
496 int i;
497 bool explicit_folder = false;
498 bool dump_variables = false;
499 bool one_liner = false;
500 bool hide_sensitive = false;
501 bool batch_mode = false;
502 bool edit_infile = false;
503#ifdef USE_DEBUG_PARSE_TEST
504 bool test_config = false;
505#endif
506 int double_dash = argc, nargc = 1;
507 int rc = 1;
508 bool repeat_error = false;
509 struct Buffer folder = mutt_buffer_make(0);
510 struct Buffer expanded_infile = mutt_buffer_make(0);
511 struct Buffer tempfile = mutt_buffer_make(0);
512 struct ConfigSet *cs = NULL;
513
515
516 /* sanity check against stupid administrators */
517 if (getegid() != getgid())
518 {
519 mutt_error("%s: I don't want to run with privileges!", (argc != 0) ? argv[0] : "neomutt");
520 goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
521 }
522
523 init_locale();
524
525 umask(077);
526
527 mutt_envlist_init(envp);
528 for (optind = 1; optind < double_dash;)
529 {
530 /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
531 * encounters a non-option. That could be a file to attach
532 * (all non-options between -a and --) or it could be an address
533 * (which gets collapsed to the front of argv). */
534 for (; optind < argc; optind++)
535 {
536 if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
537 {
538 if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
539 double_dash = optind; /* quit outer loop after getopt */
540 break; /* drop through to getopt */
541 }
542
543 /* non-option, either an attachment or address */
544 if (!STAILQ_EMPTY(&attach))
545 mutt_list_insert_tail(&attach, mutt_str_dup(argv[optind]));
546 else
547 argv[nargc++] = argv[optind];
548 }
549
550 /* USE_NNTP 'g:G' */
551 i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:i:hm:nOpQ:RSs:TvxyzZ");
552 if (i != EOF)
553 {
554 switch (i)
555 {
556 case 'A':
557 mutt_list_insert_tail(&alias_queries, mutt_str_dup(optarg));
558 break;
559 case 'a':
560 mutt_list_insert_tail(&attach, mutt_str_dup(optarg));
561 break;
562 case 'B':
563 batch_mode = true;
564 break;
565 case 'b':
566 mutt_list_insert_tail(&bcc_list, mutt_str_dup(optarg));
567 break;
568 case 'c':
569 mutt_list_insert_tail(&cc_list, mutt_str_dup(optarg));
570 break;
571 case 'D':
572 dump_variables = true;
573 break;
574 case 'd':
575 dlevel = optarg;
576 break;
577 case 'E':
578 edit_infile = true;
579 break;
580 case 'e':
582 break;
583 case 'F':
585 break;
586 case 'f':
587 mutt_buffer_strcpy(&folder, optarg);
588 explicit_folder = true;
589 break;
590#ifdef USE_NNTP
591 case 'g': /* Specify a news server */
592 cli_nntp = optarg;
593 /* fallthrough */
594 case 'G': /* List of newsgroups */
596 break;
597#endif
598 case 'H':
599 draft_file = optarg;
600 break;
601 case 'i':
602 include_file = optarg;
603 break;
604 case 'l':
605 dfile = optarg;
606 break;
607 case 'm':
608 new_type = optarg;
609 break;
610 case 'n':
611 flags |= MUTT_CLI_NOSYSRC;
612 break;
613 case 'O':
614 one_liner = true;
615 break;
616 case 'p':
617 sendflags |= SEND_POSTPONED;
618 break;
619 case 'Q':
620 mutt_list_insert_tail(&queries, mutt_str_dup(optarg));
621 break;
622 case 'R':
623 flags |= MUTT_CLI_RO; /* read-only mode */
624 break;
625 case 'S':
626 hide_sensitive = true;
627 break;
628 case 's':
629 subject = optarg;
630 break;
631#ifdef USE_DEBUG_PARSE_TEST
632 case 'T':
633 test_config = true;
634 break;
635#endif
636 case 'v':
637 version++;
638 break;
639 case 'y': /* My special hack mode */
640 flags |= MUTT_CLI_SELECT;
641 break;
642 case 'Z':
644 break;
645 case 'z':
646 flags |= MUTT_CLI_IGNORE;
647 break;
648 default:
649 OptNoCurses = true;
650 if (usage())
651 goto main_ok; // TEST03: neomutt -9
652 else
653 goto main_curses;
654 }
655 }
656 }
657
658 /* collapse remaining argv */
659 while (optind < argc)
660 argv[nargc++] = argv[optind++];
661 optind = 1;
662 argc = nargc;
663
664 if (version > 0)
665 {
667 bool done;
668 if (version == 1)
669 done = print_version(stdout);
670 else
671 done = print_copyright();
672 OptNoCurses = true;
673 if (done)
674 goto main_ok; // TEST04: neomutt -v
675 else
676 goto main_curses;
677 }
678
681
682 cs = cs_new(500);
683 if (!cs)
684 goto main_curses;
685
686 NeoMutt = neomutt_new(cs);
687 init_config(cs);
688 subjrx_init();
689 attach_init();
691
692#ifdef USE_DEBUG_NOTIFY
694#endif
695
696 if (!get_user_info(cs))
697 goto main_exit;
698
699#ifdef USE_DEBUG_PARSE_TEST
700 if (test_config)
701 {
702 cs_str_initial_set(cs, "from", "rich@flatcap.org", NULL);
703 cs_str_reset(cs, "from", NULL);
704 myvar_set("my_var", "foo");
706 goto main_ok;
707 }
708#endif
709
710 reset_tilde(cs);
711
712 if (dfile)
713 {
714 cs_str_initial_set(cs, "debug_file", dfile, NULL);
715 cs_str_reset(cs, "debug_file", NULL);
716 }
717
718 if (dlevel)
719 {
720 short num = 0;
721 if (!mutt_str_atos_full(dlevel, &num) || (num < LL_MESSAGE) || (num >= LL_MAX))
722 {
723 mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
724 goto main_exit; // TEST07: neomutt -d xyz
725 }
726 cs_str_initial_set(cs, "debug_level", dlevel, NULL);
727 cs_str_reset(cs, "debug_level", NULL);
728 }
729
733
734 if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
735 {
736 e = email_new();
737 e->env = mutt_env_new();
738
739 struct ListNode *np = NULL;
740 STAILQ_FOREACH(np, &bcc_list, entries)
741 {
742 mutt_addrlist_parse(&e->env->bcc, np->data);
743 }
744
745 STAILQ_FOREACH(np, &cc_list, entries)
746 {
747 mutt_addrlist_parse(&e->env->cc, np->data);
748 }
749
750 mutt_list_free(&bcc_list);
751 mutt_list_free(&cc_list);
752 }
753
754 /* Check for a batch send. */
755 if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
756 dump_variables || batch_mode)
757 {
758 OptNoCurses = true;
759 sendflags = SEND_BATCH;
762 }
763
764 /* Check to make sure stdout is available in curses mode. */
765 if (!OptNoCurses && !isatty(1))
766 goto main_curses;
767
768 /* Always create the mutt_windows because batch mode has some shared code
769 * paths that end up referencing them. */
770 rootwin_new();
771
772 /* This must come before mutt_init() because curses needs to be started
773 * before calling the init_pair() function to set the color scheme. */
774 if (!OptNoCurses)
775 {
776 int crc = start_curses();
777 if (crc != 0)
778 goto main_curses; // TEST08: can't test -- fake term?
779
780 /* check whether terminal status is supported (must follow curses init) */
782 rootwin_set_size(COLS, LINES);
783 }
784
785 /* set defaults and read init files */
786 int rc2 = mutt_init(cs, flags & MUTT_CLI_NOSYSRC, &commands);
787 if (rc2 != 0)
788 goto main_curses;
789
791
792 /* The command line overrides the config */
793 if (dlevel)
794 cs_str_reset(cs, "debug_level", NULL);
795 if (dfile)
796 cs_str_reset(cs, "debug_file", NULL);
797
798 if (mutt_log_start() < 0)
799 {
800 mutt_perror("log file");
801 goto main_exit;
802 }
803
804#ifdef USE_NNTP
805 {
806 /* "$news_server" precedence: command line, config file, environment, system file */
807 if (!cli_nntp)
808 cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
809
810 if (!cli_nntp)
811 cli_nntp = mutt_str_getenv("NNTPSERVER");
812
813 if (!cli_nntp)
814 {
815 char buf[1024] = { 0 };
816 cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
817 }
818
819 if (cli_nntp)
820 {
821 cs_str_initial_set(cs, "news_server", cli_nntp, NULL);
822 cs_str_reset(cs, "news_server", NULL);
823 }
824 }
825#endif
826
827 /* Initialize crypto backends. */
828 crypt_init();
829
830 if (new_type)
831 {
832 struct Buffer err = mutt_buffer_make(0);
833 int r = cs_str_initial_set(cs, "mbox_type", new_type, &err);
834 if (CSR_RESULT(r) != CSR_SUCCESS)
835 {
836 mutt_error(err.data);
838 goto main_curses;
839 }
840 cs_str_reset(cs, "mbox_type", NULL);
841 }
842
843 if (!STAILQ_EMPTY(&queries))
844 {
845 rc = mutt_query_variables(&queries, one_liner);
846 goto main_curses;
847 }
848
849 if (dump_variables)
850 {
852 if (hide_sensitive)
853 cdflags |= CS_DUMP_HIDE_SENSITIVE;
854 if (one_liner)
855 cdflags |= CS_DUMP_SHOW_DOCS;
856 dump_config(cs, cdflags, stdout);
857 goto main_ok; // TEST18: neomutt -D
858 }
859
860 if (!STAILQ_EMPTY(&alias_queries))
861 {
862 rc = 0;
863 for (; optind < argc; optind++)
864 mutt_list_insert_tail(&alias_queries, mutt_str_dup(argv[optind]));
865 struct ListNode *np = NULL;
866 STAILQ_FOREACH(np, &alias_queries, entries)
867 {
868 struct AddressList *al = alias_lookup(np->data);
869 if (al)
870 {
871 /* output in machine-readable form */
872 mutt_addrlist_to_intl(al, NULL);
873 mutt_addrlist_write_file(al, stdout, 0, false);
874 }
875 else
876 {
877 rc = 1;
878 printf("%s\n", np->data); // TEST19: neomutt -A unknown
879 }
880 }
881 mutt_list_free(&alias_queries);
882 goto main_curses; // TEST20: neomutt -A alias
883 }
884
885 if (!OptNoCurses)
886 {
888 clear();
892 }
893
894#ifdef USE_AUTOCRYPT
895 /* Initialize autocrypt after curses messages are working,
896 * because of the initial account setup screens. */
897 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
898 if (c_autocrypt)
899 mutt_autocrypt_init(!(sendflags & SEND_BATCH));
900#endif
901
902 /* Create the `$folder` directory if it doesn't exist. */
903 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
904 if (!OptNoCurses && c_folder)
905 {
906 struct stat st = { 0 };
907 struct Buffer *fpath = mutt_buffer_pool_get();
908
909 mutt_buffer_strcpy(fpath, c_folder);
911 bool skip = false;
912#ifdef USE_IMAP
913 /* we're not connected yet - skip mail folder creation */
914 skip |= (imap_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_IMAP);
915#endif
916#ifdef USE_POP
917 skip |= (pop_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_POP);
918#endif
919#ifdef USE_NNTP
920 skip |= (nntp_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_NNTP);
921#endif
922 if (!skip && (stat(mutt_buffer_string(fpath), &st) == -1) && (errno == ENOENT))
923 {
924 char msg2[256];
925 snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
926 if (mutt_yesorno(msg2, MUTT_YES) == MUTT_YES)
927 {
928 if ((mkdir(mutt_buffer_string(fpath), 0700) == -1) && (errno != EEXIST))
929 mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
930 }
931 }
933 }
934
935 if (batch_mode)
936 {
937 goto main_ok; // TEST22: neomutt -B
938 }
939
943
944 if (sendflags & SEND_POSTPONED)
945 {
946 if (!OptNoCurses)
948 if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
949 rc = 0;
950 // TEST23: neomutt -p (postponed message, cancel)
951 // TEST24: neomutt -p (no postponed message)
953 repeat_error = true;
954 goto main_curses;
955 }
956 else if (subject || e || draft_file || include_file ||
957 !STAILQ_EMPTY(&attach) || (optind < argc))
958 {
959 FILE *fp_in = NULL;
960 FILE *fp_out = NULL;
961 char *infile = NULL;
962 char *bodytext = NULL;
963 const char *bodyfile = NULL;
964 int rv = 0;
965
966 if (!OptNoCurses)
968
969 if (!e)
970 e = email_new();
971 if (!e->env)
972 e->env = mutt_env_new();
973
974 for (i = optind; i < argc; i++)
975 {
976 if (url_check_scheme(argv[i]) == U_MAILTO)
977 {
978 if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
979 {
980 mutt_error(_("Failed to parse mailto: link"));
981 email_free(&e);
982 goto main_curses; // TEST25: neomutt mailto:?
983 }
984 }
985 else
986 mutt_addrlist_parse(&e->env->to, argv[i]);
987 }
988
989 const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
990 if (!draft_file && c_auto_edit && TAILQ_EMPTY(&e->env->to) &&
991 TAILQ_EMPTY(&e->env->cc))
992 {
993 mutt_error(_("No recipients specified"));
994 email_free(&e);
995 goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
996 }
997
998 if (subject)
999 {
1000 mutt_str_replace(&e->env->subject, subject);
1001 }
1002
1003 if (draft_file)
1004 {
1005 infile = draft_file;
1006 include_file = NULL;
1007 }
1008 else if (include_file)
1009 infile = include_file;
1010 else
1011 edit_infile = false;
1012
1013 if (infile || bodytext)
1014 {
1015 /* Prepare fp_in and expanded_infile. */
1016 if (infile)
1017 {
1018 if (mutt_str_equal("-", infile))
1019 {
1020 if (edit_infile)
1021 {
1022 mutt_error(_("Can't use -E flag with stdin"));
1023 email_free(&e);
1024 goto main_curses; // TEST27: neomutt -E -H -
1025 }
1026 fp_in = stdin;
1027 }
1028 else
1029 {
1030 mutt_buffer_strcpy(&expanded_infile, infile);
1031 mutt_buffer_expand_path(&expanded_infile);
1032 fp_in = fopen(mutt_buffer_string(&expanded_infile), "r");
1033 if (!fp_in)
1034 {
1035 mutt_perror(mutt_buffer_string(&expanded_infile));
1036 email_free(&e);
1037 goto main_curses; // TEST28: neomutt -E -H missing
1038 }
1039 }
1040 }
1041
1042 /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1043 * Note: stdin is always copied to a tempfile, ensuring draft_file
1044 * can stat and get the correct st_size below. */
1045 if (!edit_infile)
1046 {
1047 mutt_buffer_mktemp(&tempfile);
1048
1049 fp_out = mutt_file_fopen(mutt_buffer_string(&tempfile), "w");
1050 if (!fp_out)
1051 {
1052 mutt_file_fclose(&fp_in);
1053 mutt_perror(mutt_buffer_string(&tempfile));
1054 email_free(&e);
1055 goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1056 }
1057 if (fp_in)
1058 {
1059 mutt_file_copy_stream(fp_in, fp_out);
1060 if (fp_in != stdin)
1061 mutt_file_fclose(&fp_in);
1062 }
1063 else if (bodytext)
1064 fputs(bodytext, fp_out);
1065 mutt_file_fclose(&fp_out);
1066
1067 fp_in = fopen(mutt_buffer_string(&tempfile), "r");
1068 if (!fp_in)
1069 {
1070 mutt_perror(mutt_buffer_string(&tempfile));
1071 email_free(&e);
1072 goto main_curses; // TEST30: can't test
1073 }
1074 }
1075 /* If editing the infile, keep it around afterwards so
1076 * it doesn't get unlinked, and we can rebuild the draft_file */
1077 else
1078 sendflags |= SEND_NO_FREE_HEADER;
1079
1080 /* Parse the draft_file into the full Email/Body structure.
1081 * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1082 * our e->body. */
1083 if (draft_file)
1084 {
1085 struct Envelope *opts_env = e->env;
1086 struct stat st = { 0 };
1087
1088 sendflags |= SEND_DRAFT_FILE;
1089
1090 /* Set up a tmp Email with just enough information so that
1091 * mutt_prepare_template() can parse the message in fp_in. */
1092 struct Email *e_tmp = email_new();
1093 e_tmp->offset = 0;
1094 e_tmp->body = mutt_body_new();
1095 if (fstat(fileno(fp_in), &st) != 0)
1096 {
1097 mutt_perror(draft_file);
1098 email_free(&e);
1099 email_free(&e_tmp);
1100 goto main_curses; // TEST31: can't test
1101 }
1102 e_tmp->body->length = st.st_size;
1103
1104 if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1105 {
1106 mutt_error(_("Can't parse message template: %s"), draft_file);
1107 email_free(&e);
1108 email_free(&e_tmp);
1109 goto main_curses;
1110 }
1111
1112 /* Scan for neomutt header to set `$resume_draft_files` */
1113 struct ListNode *np = NULL, *tmp = NULL;
1114 STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1115 {
1116 if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1117 {
1118 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1119 if (c_resume_edited_draft_files)
1120 cs_str_native_set(cs, "resume_draft_files", true, NULL);
1121
1122 STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1123 FREE(&np->data);
1124 FREE(&np);
1125 }
1126 }
1127
1128 mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1129 mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1130 mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1131 if (opts_env->subject)
1132 mutt_str_replace(&e->env->subject, opts_env->subject);
1133
1134 mutt_env_free(&opts_env);
1135 email_free(&e_tmp);
1136 }
1137 /* Editing the include_file: pass it directly in.
1138 * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1139 else if (edit_infile)
1140 bodyfile = mutt_buffer_string(&expanded_infile);
1141 // For bodytext and unedited include_file: use the tempfile.
1142 else
1143 bodyfile = mutt_buffer_string(&tempfile);
1144
1145 mutt_file_fclose(&fp_in);
1146 }
1147
1148 FREE(&bodytext);
1149
1150 if (!STAILQ_EMPTY(&attach))
1151 {
1152 struct Body *b = e->body;
1153
1154 while (b && b->next)
1155 b = b->next;
1156
1157 struct ListNode *np = NULL;
1158 STAILQ_FOREACH(np, &attach, entries)
1159 {
1160 if (b)
1161 {
1163 b = b->next;
1164 }
1165 else
1166 {
1168 e->body = b;
1169 }
1170 if (!b)
1171 {
1172 mutt_error(_("%s: unable to attach file"), np->data);
1173 mutt_list_free(&attach);
1174 email_free(&e);
1175 goto main_curses; // TEST32: neomutt john@example.com -a missing
1176 }
1177 }
1178 mutt_list_free(&attach);
1179 }
1180
1181 rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1182 /* We WANT the "Mail sent." and any possible, later error */
1184 if (ErrorBufMessage)
1185 mutt_message("%s", ErrorBuf);
1186
1187 if (edit_infile)
1188 {
1189 if (draft_file)
1190 {
1191 if (truncate(mutt_buffer_string(&expanded_infile), 0) == -1)
1192 {
1193 mutt_perror(mutt_buffer_string(&expanded_infile));
1194 email_free(&e);
1195 goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1196 }
1197 fp_out = mutt_file_fopen(mutt_buffer_string(&expanded_infile), "a");
1198 if (!fp_out)
1199 {
1200 mutt_perror(mutt_buffer_string(&expanded_infile));
1201 email_free(&e);
1202 goto main_curses; // TEST34: can't test
1203 }
1204
1205 /* If the message was sent or postponed, these will already
1206 * have been done. */
1207 if (rv < 0)
1208 {
1209 if (e->body->next)
1210 e->body = mutt_make_multipart(e->body);
1212 mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1213 mutt_env_to_intl(e->env, NULL, NULL);
1214 }
1215
1216 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1218 c_crypt_protected_headers_read &&
1220 NeoMutt->sub);
1221 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1222 if (c_resume_edited_draft_files)
1223 fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1224 fputc('\n', fp_out);
1225 if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1226 {
1227 mutt_file_fclose(&fp_out);
1228 email_free(&e);
1229 goto main_curses; // TEST35: can't test
1230 }
1231 mutt_file_fclose(&fp_out);
1232 }
1233
1234 email_free(&e);
1235 }
1236
1237 /* !edit_infile && draft_file will leave the tempfile around */
1238 if (!mutt_buffer_is_empty(&tempfile))
1239 unlink(mutt_buffer_string(&tempfile));
1240
1241 rootwin_free();
1242
1243 if (rv != 0)
1244 goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1245 }
1246 else if (sendflags & SEND_BATCH)
1247 {
1248 /* This guards against invoking `neomutt < /dev/null` and accidentally
1249 * sending an email due to a my_hdr or other setting. */
1250 mutt_error(_("No recipients specified"));
1251 goto main_curses;
1252 }
1253 else
1254 {
1255 if (flags & MUTT_CLI_MAILBOX)
1256 {
1257#ifdef USE_IMAP
1258 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1259 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1260#endif
1262 if (mutt_mailbox_check(NULL, csflags) == 0)
1263 {
1264 mutt_message(_("No mailbox with new mail"));
1265 goto main_curses; // TEST37: neomutt -Z (no new mail)
1266 }
1267 mutt_buffer_reset(&folder);
1268 mutt_mailbox_next(NULL, &folder);
1269#ifdef USE_IMAP
1270 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1271#endif
1272 }
1273 else if (flags & MUTT_CLI_SELECT)
1274 {
1275#ifdef USE_NNTP
1276 if (flags & MUTT_CLI_NEWS)
1277 {
1278 const char *const c_news_server = cs_subset_string(NeoMutt->sub, "news_server");
1279 OptNews = true;
1280 struct Mailbox *m_cur = get_current_mailbox();
1281 CurrentNewsSrv = nntp_select_server(m_cur, c_news_server, false);
1282 if (!CurrentNewsSrv)
1283 goto main_curses; // TEST38: neomutt -G (unset news_server)
1284 }
1285 else
1286#endif
1288 {
1289 mutt_error(_("No incoming mailboxes defined"));
1290 goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1291 }
1292 mutt_buffer_reset(&folder);
1293 struct Mailbox *m_cur = get_current_mailbox();
1294 mutt_buffer_select_file(&folder, MUTT_SEL_FOLDER | MUTT_SEL_MAILBOX, m_cur, NULL, NULL);
1295 if (mutt_buffer_is_empty(&folder))
1296 {
1297 goto main_ok; // TEST40: neomutt -y (quit selection)
1298 }
1299 }
1300
1301 if (mutt_buffer_is_empty(&folder))
1302 {
1303 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1304 if (c_spool_file)
1305 {
1306 // Check if `$spool_file` corresponds a mailboxes' description.
1307 struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1308 if (m_desc)
1309 mutt_buffer_strcpy(&folder, m_desc->realpath);
1310 else
1311 mutt_buffer_strcpy(&folder, c_spool_file);
1312 }
1313 else if (c_folder)
1314 mutt_buffer_strcpy(&folder, c_folder);
1315 /* else no folder */
1316 }
1317
1318#ifdef USE_NNTP
1319 if (OptNews)
1320 {
1321 OptNews = false;
1322 mutt_buffer_alloc(&folder, PATH_MAX);
1324 }
1325 else
1326#endif
1327 mutt_buffer_expand_path(&folder);
1328
1331
1332 if (flags & MUTT_CLI_IGNORE)
1333 {
1334 /* check to see if there are any messages in the folder */
1335 switch (mx_path_is_empty(mutt_buffer_string(&folder)))
1336 {
1337 case -1:
1339 goto main_curses; // TEST41: neomutt -z -f missing
1340 case 1:
1341 mutt_error(_("Mailbox is empty"));
1342 goto main_curses; // TEST42: neomutt -z -f /dev/null
1343 }
1344 }
1345
1346 mutt_folder_hook(mutt_buffer_string(&folder), NULL);
1348 mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1350
1351 repeat_error = true;
1352 struct Mailbox *m = mx_resolve(mutt_buffer_string(&folder));
1353 const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1354 if (!mx_mbox_open(m, ((flags & MUTT_CLI_RO) || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1355 {
1356 if (m->account)
1358
1359 mailbox_free(&m);
1360 mutt_error(_("Unable to open mailbox %s"), mutt_buffer_string(&folder));
1361 repeat_error = false;
1362 }
1363 if (m || !explicit_folder)
1364 {
1365 struct MuttWindow *dlg = index_pager_init();
1366 dialog_push(dlg);
1367
1369 m = mutt_index_menu(dlg, m);
1371 mailbox_free(&m);
1372
1373 dialog_pop();
1374 mutt_window_free(&dlg);
1376 repeat_error = false;
1377 }
1378#ifdef USE_IMAP
1380#endif
1381#ifdef USE_SASL_CYRUS
1383#endif
1384#ifdef USE_SASL_GNU
1386#endif
1387#ifdef USE_AUTOCRYPT
1389#endif
1390 // TEST43: neomutt (no change to mailbox)
1391 // TEST44: neomutt (change mailbox)
1392 }
1393
1394main_ok:
1395 rc = 0;
1396main_curses:
1397 mutt_endwin();
1399 /* Repeat the last message to the user */
1400 if (repeat_error && ErrorBufMessage)
1401 puts(ErrorBuf);
1402main_exit:
1405 mutt_buffer_dealloc(&folder);
1406 mutt_buffer_dealloc(&expanded_infile);
1407 mutt_buffer_dealloc(&tempfile);
1408 mutt_list_free(&queries);
1410 rootwin_free();
1415 menu_cleanup();
1416 crypt_cleanup();
1418 subjrx_free();
1419 attach_free();
1425 cs_free(&cs);
1428 mutt_log_stop();
1429 return rc;
1430}
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:96
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, int start_col, bool display)
Wrapper for mutt_write_address()
Definition: address.c:1231
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:280
void alternates_init(void)
Set up the alternates lists.
Definition: alternates.c:60
void alternates_free(void)
Free the alternates lists.
Definition: alternates.c:49
void attach_free(void)
Free the attachments lists.
Definition: attachments.c:91
void attach_init(void)
Set up the attachments lists.
Definition: attachments.c:105
void mutt_autocrypt_cleanup(void)
Shutdown Autocrypt.
Definition: autocrypt.c:139
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:97
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: lib.h:56
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: lib.h:58
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1088
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: browser.c:158
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:275
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:57
void mutt_commands_cleanup(void)
Clean up commands globals.
Definition: commands.c:81
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1076
void crypto_module_free(void)
Clean up the crypto modules.
Definition: crypt_mod.c:81
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: curs_lib.c:592
void test_parse_set(void)
Test the config parsing.
Definition: parse_test.c:39
int debug_all_observer(struct NotifyCallback *nc)
Definition: notify.c:342
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:103
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:137
struct Mailbox * mutt_index_menu(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails.
Definition: dlg_index.c:1057
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1402
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
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
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 mutt_envlist_free(void)
Free the private copy of the environment.
Definition: envlist.c:41
void mutt_envlist_init(char *envp[])
Create a copy of the environment.
Definition: envlist.c:56
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:259
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
Definition: file.c:1454
int log_disp_terminal(time_t stamp, const char *file, int line, const char *function, enum LogLevel level,...)
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,...)
Display a log line in the message line - Implements log_dispatcher_t -.
Definition: mutt_logging.c:88
log_dispatcher_t MuttLogger
The log dispatcher -.
Definition: logging.c:52
int log_disp_queue(time_t stamp, const char *file, int line, const char *function, enum LogLevel level,...)
Save a log line to an internal queue - Implements log_dispatcher_t -.
Definition: logging.c:398
#define mutt_message(...)
Definition: logging.h:86
#define mutt_perror(...)
Definition: logging.h:88
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe() -.
Definition: nntp.c:2701
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe() -.
Definition: pop.c:1158
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2399
int main_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: keymap.c:879
int main_hist_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: mutt_history.c:61
int main_log_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: mutt_logging.c:288
void mutt_gsasl_done(void)
Shutdown GNU SASL library.
Definition: gsasl.c:147
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:572
@ 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:924
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:589
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:57
void imap_logout_all(void)
Close all open connections.
Definition: imap.c:562
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:618
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:917
void mutt_opts_free(void)
Clean up before quitting.
Definition: init.c:518
int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:574
void init_config(struct ConfigSet *cs)
Initialise the config system.
Definition: mutt_config.c:788
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1668
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: keymap.c:857
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
void log_queue_empty(void)
Free the contents of the queue.
Definition: logging.c:324
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition: logging.c:312
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:346
@ LL_MESSAGE
Log informational message.
Definition: logging.h:39
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
@ LL_MAX
Definition: logging.h:47
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:176
@ 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:213
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition: main.c:369
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:207
static void log_translation(void)
Log the translation being used.
Definition: main.c:438
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:210
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:223
static bool usage(void)
Display NeoMutt command line.
Definition: main.c:260
static int start_curses(void)
Start the Curses UI.
Definition: main.c:337
static bool get_user_info(struct ConfigSet *cs)
Find the user's name, home and shell.
Definition: main.c:397
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:212
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:208
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:209
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:215
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:211
#define FREE(x)
Definition: memory.h:43
void menu_cleanup(void)
Free the saved Menu searches.
Definition: menu.c:65
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
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:189
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
#define PATH_MAX
Definition: mutt.h:40
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1300
struct CommandArray commands
enum MuttCursorState mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:96
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
@ MUTT_CURSOR_INVISIBLE
Hide the cursor.
Definition: mutt_curses.h:53
@ MUTT_CURSOR_VISIBLE
Display a normal cursor.
Definition: mutt_curses.h:54
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
bool ErrorBufMessage
true if the last message was an error
Definition: mutt_globals.h:46
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
char ErrorBuf[256]
Copy of the last error message.
Definition: mutt_globals.h:47
struct ListHead Muttrc
List of config files to read.
Definition: mutt_globals.h:64
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:184
int mutt_log_start(void)
Enable file logging.
Definition: mutt_logging.c:251
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:174
int mutt_mailbox_check(struct Mailbox *m_cur, CheckStatsFlags flags)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:156
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
Definition: mutt_mailbox.c:378
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:201
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
int mx_path_is_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1258
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Mailbox * mx_resolve(const char *path_or_name)
Get a Mailbox from either a path or name.
Definition: mx.c:1746
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:64
#define MUTT_MAILBOX_CHECK_IMMEDIATE
Don't postpone the actual checking.
Definition: mxapi.h:77
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:61
#define MUTT_MAILBOX_CHECK_FORCE
Ignore MailboxTime and check for new mail.
Definition: mxapi.h:75
uint8_t CheckStatsFlags
Flags for mutt_mailbox_check.
Definition: mxapi.h:73
struct MyVarList MyVars
List of all the user's custom config variables.
Definition: myvar.c:34
void myvar_set(const char *var, const char *val)
Set the value of a "my_" variable.
Definition: myvar.c:109
void myvarlist_free(struct MyVarList *list)
Free a List of MyVars.
Definition: myvar.c:161
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:64
@ NT_GLOBAL_STARTUP
NeoMutt is initialised.
Definition: neomutt.h:52
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:561
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:1019
@ 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
bool OptNews
(pseudo) used to change reader mode
Definition: options.h:50
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:53
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1670
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_free(void)
Release the Buffer pool.
Definition: pool.c:87
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:503
void mutt_prex_free(void)
Cleanup heap memory allocated by compiled regexes.
Definition: prex.c:349
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
#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_free(void)
Free all the default Windows.
Definition: rootwin.c:178
void rootwin_set_size(int cols, int rows)
Set the dimensions of the Root Window.
Definition: rootwin.c:226
void rootwin_new(void)
Create the default Windows.
Definition: rootwin.c:188
void mutt_sasl_done(void)
Invoke when processing is complete.
Definition: sasl.c:776
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
RFC2047 encode the content-descriptions.
Definition: send.c:1578
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2126
#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:598
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:754
void cs_free(struct ConfigSet **ptr)
Free a Config Set.
Definition: set.c:170
struct ConfigSet * cs_new(size_t size)
Create a new Config Set.
Definition: set.c:156
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:737
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
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:260
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:87
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:127
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:63
void subjrx_init(void)
Create new Subject Regex List.
Definition: subjectrx.c:54
void subjrx_free(void)
Free the Subject Regex List.
Definition: subjectrx.c:45
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:41
bool mutt_ts_capability(void)
Check terminal capabilities.
Definition: terminal.c:53
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:221
@ U_MAILTO
Url is mailto://.
Definition: url.h:45
bool print_copyright(void)
Print copyright message.
Definition: version.c:544
bool print_version(FILE *fp)
Print system and compile info to a file.
Definition: version.c:416