NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
main.c File Reference

Command line processing. More...

#include "config.h"
#include <errno.h>
#include <getopt.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 "nntp/mdata.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 210 of file main.c.

◆ MUTT_CLI_IGNORE

#define MUTT_CLI_IGNORE   (1 << 0)

-z Open first mailbox if it has mail

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

◆ MUTT_CLI_RO

#define MUTT_CLI_RO   (1 << 3)

-R Open mailbox in read-only mode

Definition at line 214 of file main.c.

◆ MUTT_CLI_SELECT

#define MUTT_CLI_SELECT   (1 << 4)

-y Start with a list of all mailboxes

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

Typedef Documentation

◆ CliFlags

typedef uint8_t CliFlags

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

Definition at line 209 of file main.c.

Function Documentation

◆ reset_tilde()

static void reset_tilde ( struct ConfigSet cs)
static

Temporary measure.

Parameters
csConfig Set

Definition at line 225 of file main.c.

226{
227 static const char *names[] = { "folder", "mbox", "postponed", "record" };
228
229 struct Buffer value = mutt_buffer_make(256);
230 for (size_t i = 0; i < mutt_array_size(names); i++)
231 {
232 struct HashElem *he = cs_get_elem(cs, names[i]);
233 if (!he)
234 continue;
235 mutt_buffer_reset(&value);
236 cs_he_initial_get(cs, he, &value);
237 mutt_buffer_expand_path_regex(&value, false);
238 cs_he_initial_set(cs, he, value.data, NULL);
239 cs_he_reset(cs, he, NULL);
240 }
241 mutt_buffer_dealloc(&value);
242}
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 248 of file main.c.

249{
250 mutt_endwin();
251#ifdef HAVE_LIBUNWIND
252 if (code != 0)
254#endif
255 exit(code);
256}
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 262 of file main.c.

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

340{
341 km_init(); /* must come before mutt_init */
342
343 /* should come before initscr() so that ncurses 4.2 doesn't try to install
344 * its own SIGWINCH handler */
346
347 if (!initscr())
348 {
349 mutt_error(_("Error initializing terminal"));
350 return 1;
351 }
354 keypad(stdscr, true);
355 cbreak();
356 noecho();
357 nonl();
358 typeahead(-1); /* simulate smooth scrolling */
359 meta(stdscr, true);
361 /* Now that curses is set up, we drop back to normal screen mode.
362 * This simplifies displaying error messages to the user.
363 * The first call to refresh() will swap us back to curses screen mode. */
364 endwin();
365 return 0;
366}
void mutt_colors_init(void)
Initialize colours.
Definition: color.c:80
#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 371 of file main.c.

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

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

441{
442 const char *header = ""; // Do not merge these two lines
443 header = _(header); // otherwise the .po files will end up badly ordered
444 const char *label = "Language:"; // the start of the lookup/needle
445 const char *lang = mutt_istr_find(header, label);
446 int len = 64;
447 if (lang)
448 {
449 lang += strlen(label); // skip label
450 SKIPWS(lang);
451 char *nl = strchr(lang, '\n');
452 if (nl)
453 len = (nl - lang);
454 }
455 else
456 {
457 lang = "NONE";
458 }
459
460 mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
461}
#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 475 of file main.c.

478{
479 char *subject = NULL;
480 char *include_file = NULL;
481 char *draft_file = NULL;
482 char *new_type = NULL;
483 char *dlevel = NULL;
484 char *dfile = NULL;
485#ifdef USE_NNTP
486 const char *cli_nntp = NULL;
487#endif
488 struct Email *e = NULL;
489 struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
490 struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
491 struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
492 struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
493 struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
494 struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
495 SendFlags sendflags = SEND_NO_FLAGS;
497 int version = 0;
498 int i;
499 bool explicit_folder = false;
500 bool dump_variables = false;
501 bool one_liner = false;
502 bool hide_sensitive = false;
503 bool batch_mode = false;
504 bool edit_infile = false;
505#ifdef USE_DEBUG_PARSE_TEST
506 bool test_config = false;
507#endif
508 int double_dash = argc, nargc = 1;
509 int rc = 1;
510 bool repeat_error = false;
511 struct Buffer folder = mutt_buffer_make(0);
512 struct Buffer expanded_infile = mutt_buffer_make(0);
513 struct Buffer tempfile = mutt_buffer_make(0);
514 struct ConfigSet *cs = NULL;
515
517
518 /* sanity check against stupid administrators */
519 if (getegid() != getgid())
520 {
521 mutt_error("%s: I don't want to run with privileges!", (argc != 0) ? argv[0] : "neomutt");
522 goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
523 }
524
525 init_locale();
526
527 umask(077);
528
529 mutt_envlist_init(envp);
530 for (optind = 1; optind < double_dash;)
531 {
532 /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
533 * encounters a non-option. That could be a file to attach
534 * (all non-options between -a and --) or it could be an address
535 * (which gets collapsed to the front of argv). */
536 for (; optind < argc; optind++)
537 {
538 if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
539 {
540 if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
541 double_dash = optind; /* quit outer loop after getopt */
542 break; /* drop through to getopt */
543 }
544
545 /* non-option, either an attachment or address */
546 if (!STAILQ_EMPTY(&attach))
547 mutt_list_insert_tail(&attach, mutt_str_dup(argv[optind]));
548 else
549 argv[nargc++] = argv[optind];
550 }
551
552 /* USE_NNTP 'g:G' */
553 i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:i:hm:nOpQ:RSs:TvxyzZ");
554 if (i != EOF)
555 {
556 switch (i)
557 {
558 case 'A':
559 mutt_list_insert_tail(&alias_queries, mutt_str_dup(optarg));
560 break;
561 case 'a':
562 mutt_list_insert_tail(&attach, mutt_str_dup(optarg));
563 break;
564 case 'B':
565 batch_mode = true;
566 break;
567 case 'b':
568 mutt_list_insert_tail(&bcc_list, mutt_str_dup(optarg));
569 break;
570 case 'c':
571 mutt_list_insert_tail(&cc_list, mutt_str_dup(optarg));
572 break;
573 case 'D':
574 dump_variables = true;
575 break;
576 case 'd':
577 dlevel = optarg;
578 break;
579 case 'E':
580 edit_infile = true;
581 break;
582 case 'e':
584 break;
585 case 'F':
587 break;
588 case 'f':
589 mutt_buffer_strcpy(&folder, optarg);
590 explicit_folder = true;
591 break;
592#ifdef USE_NNTP
593 case 'g': /* Specify a news server */
594 cli_nntp = optarg;
595 /* fallthrough */
596 case 'G': /* List of newsgroups */
598 break;
599#endif
600 case 'H':
601 draft_file = optarg;
602 break;
603 case 'i':
604 include_file = optarg;
605 break;
606 case 'l':
607 dfile = optarg;
608 break;
609 case 'm':
610 new_type = optarg;
611 break;
612 case 'n':
613 flags |= MUTT_CLI_NOSYSRC;
614 break;
615 case 'O':
616 one_liner = true;
617 break;
618 case 'p':
619 sendflags |= SEND_POSTPONED;
620 break;
621 case 'Q':
622 mutt_list_insert_tail(&queries, mutt_str_dup(optarg));
623 break;
624 case 'R':
625 flags |= MUTT_CLI_RO; /* read-only mode */
626 break;
627 case 'S':
628 hide_sensitive = true;
629 break;
630 case 's':
631 subject = optarg;
632 break;
633#ifdef USE_DEBUG_PARSE_TEST
634 case 'T':
635 test_config = true;
636 break;
637#endif
638 case 'v':
639 version++;
640 break;
641 case 'y': /* My special hack mode */
642 flags |= MUTT_CLI_SELECT;
643 break;
644 case 'Z':
646 break;
647 case 'z':
648 flags |= MUTT_CLI_IGNORE;
649 break;
650 default:
651 OptNoCurses = true;
652 if (usage())
653 goto main_ok; // TEST03: neomutt -9
654 else
655 goto main_curses;
656 }
657 }
658 }
659
660 /* collapse remaining argv */
661 while (optind < argc)
662 argv[nargc++] = argv[optind++];
663 optind = 1;
664 argc = nargc;
665
666 if (version > 0)
667 {
669 bool done;
670 if (version == 1)
671 done = print_version(stdout);
672 else
673 done = print_copyright();
674 OptNoCurses = true;
675 if (done)
676 goto main_ok; // TEST04: neomutt -v
677 else
678 goto main_curses;
679 }
680
683
684 cs = cs_new(500);
685 if (!cs)
686 goto main_curses;
687
688 NeoMutt = neomutt_new(cs);
689 init_config(cs);
690 subjrx_init();
691 attach_init();
693
694#ifdef USE_DEBUG_NOTIFY
696#endif
697
698 if (!get_user_info(cs))
699 goto main_exit;
700
701#ifdef USE_DEBUG_PARSE_TEST
702 if (test_config)
703 {
704 cs_str_initial_set(cs, "from", "rich@flatcap.org", NULL);
705 cs_str_reset(cs, "from", NULL);
706 myvar_set("my_var", "foo");
708 goto main_ok;
709 }
710#endif
711
712 reset_tilde(cs);
713
714 if (dfile)
715 {
716 cs_str_initial_set(cs, "debug_file", dfile, NULL);
717 cs_str_reset(cs, "debug_file", NULL);
718 }
719
720 if (dlevel)
721 {
722 short num = 0;
723 if (!mutt_str_atos_full(dlevel, &num) || (num < LL_MESSAGE) || (num >= LL_MAX))
724 {
725 mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
726 goto main_exit; // TEST07: neomutt -d xyz
727 }
728 cs_str_initial_set(cs, "debug_level", dlevel, NULL);
729 cs_str_reset(cs, "debug_level", NULL);
730 }
731
735
736 if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
737 {
738 e = email_new();
739 e->env = mutt_env_new();
740
741 struct ListNode *np = NULL;
742 STAILQ_FOREACH(np, &bcc_list, entries)
743 {
744 mutt_addrlist_parse(&e->env->bcc, np->data);
745 }
746
747 STAILQ_FOREACH(np, &cc_list, entries)
748 {
749 mutt_addrlist_parse(&e->env->cc, np->data);
750 }
751
752 mutt_list_free(&bcc_list);
753 mutt_list_free(&cc_list);
754 }
755
756 /* Check for a batch send. */
757 if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
758 dump_variables || batch_mode)
759 {
760 OptNoCurses = true;
761 sendflags = SEND_BATCH;
764 }
765
766 /* Check to make sure stdout is available in curses mode. */
767 if (!OptNoCurses && !isatty(1))
768 goto main_curses;
769
770 /* Always create the mutt_windows because batch mode has some shared code
771 * paths that end up referencing them. */
772 rootwin_new();
773
774 /* This must come before mutt_init() because curses needs to be started
775 * before calling the init_pair() function to set the color scheme. */
776 if (!OptNoCurses)
777 {
778 int crc = start_curses();
779 if (crc != 0)
780 goto main_curses; // TEST08: can't test -- fake term?
781
782 /* check whether terminal status is supported (must follow curses init) */
784 rootwin_set_size(COLS, LINES);
785 }
786
787 /* set defaults and read init files */
788 int rc2 = mutt_init(cs, flags & MUTT_CLI_NOSYSRC, &commands);
789 if (rc2 != 0)
790 goto main_curses;
791
793
794 /* The command line overrides the config */
795 if (dlevel)
796 cs_str_reset(cs, "debug_level", NULL);
797 if (dfile)
798 cs_str_reset(cs, "debug_file", NULL);
799
800 if (mutt_log_start() < 0)
801 {
802 mutt_perror("log file");
803 goto main_exit;
804 }
805
806#ifdef USE_NNTP
807 {
808 /* "$news_server" precedence: command line, config file, environment, system file */
809 if (!cli_nntp)
810 cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
811
812 if (!cli_nntp)
813 cli_nntp = mutt_str_getenv("NNTPSERVER");
814
815 if (!cli_nntp)
816 {
817 char buf[1024] = { 0 };
818 cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
819 }
820
821 if (cli_nntp)
822 {
823 cs_str_initial_set(cs, "news_server", cli_nntp, NULL);
824 cs_str_reset(cs, "news_server", NULL);
825 }
826 }
827#endif
828
829 /* Initialize crypto backends. */
830 crypt_init();
831
832 if (new_type)
833 {
834 struct Buffer err = mutt_buffer_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(err.data);
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 mutt_addrlist_write_file(al, stdout, 0, false);
876 }
877 else
878 {
879 rc = 1;
880 printf("%s\n", np->data); // TEST19: neomutt -A unknown
881 }
882 }
883 mutt_list_free(&alias_queries);
884 goto main_curses; // TEST20: neomutt -A alias
885 }
886
887 if (!OptNoCurses)
888 {
890 clear();
894 }
895
896#ifdef USE_AUTOCRYPT
897 /* Initialize autocrypt after curses messages are working,
898 * because of the initial account setup screens. */
899 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
900 if (c_autocrypt)
901 mutt_autocrypt_init(!(sendflags & SEND_BATCH));
902#endif
903
904 /* Create the `$folder` directory if it doesn't exist. */
905 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
906 if (!OptNoCurses && c_folder)
907 {
908 struct stat st = { 0 };
909 struct Buffer *fpath = mutt_buffer_pool_get();
910
911 mutt_buffer_strcpy(fpath, c_folder);
913 bool skip = false;
914#ifdef USE_IMAP
915 /* we're not connected yet - skip mail folder creation */
916 skip |= (imap_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_IMAP);
917#endif
918#ifdef USE_POP
919 skip |= (pop_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_POP);
920#endif
921#ifdef USE_NNTP
922 skip |= (nntp_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_NNTP);
923#endif
924 if (!skip && (stat(mutt_buffer_string(fpath), &st) == -1) && (errno == ENOENT))
925 {
926 char msg2[256];
927 snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
928 if (mutt_yesorno(msg2, MUTT_YES) == MUTT_YES)
929 {
930 if ((mkdir(mutt_buffer_string(fpath), 0700) == -1) && (errno != EEXIST))
931 mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
932 }
933 }
935 }
936
937 if (batch_mode)
938 {
939 goto main_ok; // TEST22: neomutt -B
940 }
941
945
946 if (sendflags & SEND_POSTPONED)
947 {
948 if (!OptNoCurses)
950 if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
951 rc = 0;
952 // TEST23: neomutt -p (postponed message, cancel)
953 // TEST24: neomutt -p (no postponed message)
955 repeat_error = true;
956 goto main_curses;
957 }
958 else if (subject || e || draft_file || include_file ||
959 !STAILQ_EMPTY(&attach) || (optind < argc))
960 {
961 FILE *fp_in = NULL;
962 FILE *fp_out = NULL;
963 char *infile = NULL;
964 char *bodytext = NULL;
965 const char *bodyfile = NULL;
966 int rv = 0;
967
968 if (!OptNoCurses)
970
971 if (!e)
972 e = email_new();
973 if (!e->env)
974 e->env = mutt_env_new();
975
976 for (i = optind; i < argc; i++)
977 {
978 if (url_check_scheme(argv[i]) == U_MAILTO)
979 {
980 if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
981 {
982 mutt_error(_("Failed to parse mailto: link"));
983 email_free(&e);
984 goto main_curses; // TEST25: neomutt mailto:?
985 }
986 }
987 else
988 mutt_addrlist_parse(&e->env->to, argv[i]);
989 }
990
991 const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
992 if (!draft_file && c_auto_edit && TAILQ_EMPTY(&e->env->to) &&
993 TAILQ_EMPTY(&e->env->cc))
994 {
995 mutt_error(_("No recipients specified"));
996 email_free(&e);
997 goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
998 }
999
1000 if (subject)
1001 {
1002 mutt_str_replace(&e->env->subject, subject);
1003 }
1004
1005 if (draft_file)
1006 {
1007 infile = draft_file;
1008 include_file = NULL;
1009 }
1010 else if (include_file)
1011 infile = include_file;
1012 else
1013 edit_infile = false;
1014
1015 if (infile || bodytext)
1016 {
1017 /* Prepare fp_in and expanded_infile. */
1018 if (infile)
1019 {
1020 if (mutt_str_equal("-", infile))
1021 {
1022 if (edit_infile)
1023 {
1024 mutt_error(_("Can't use -E flag with stdin"));
1025 email_free(&e);
1026 goto main_curses; // TEST27: neomutt -E -H -
1027 }
1028 fp_in = stdin;
1029 }
1030 else
1031 {
1032 mutt_buffer_strcpy(&expanded_infile, infile);
1033 mutt_buffer_expand_path(&expanded_infile);
1034 fp_in = fopen(mutt_buffer_string(&expanded_infile), "r");
1035 if (!fp_in)
1036 {
1037 mutt_perror(mutt_buffer_string(&expanded_infile));
1038 email_free(&e);
1039 goto main_curses; // TEST28: neomutt -E -H missing
1040 }
1041 }
1042 }
1043
1044 /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1045 * Note: stdin is always copied to a tempfile, ensuring draft_file
1046 * can stat and get the correct st_size below. */
1047 if (!edit_infile)
1048 {
1049 mutt_buffer_mktemp(&tempfile);
1050
1051 fp_out = mutt_file_fopen(mutt_buffer_string(&tempfile), "w");
1052 if (!fp_out)
1053 {
1054 mutt_file_fclose(&fp_in);
1055 mutt_perror(mutt_buffer_string(&tempfile));
1056 email_free(&e);
1057 goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1058 }
1059 if (fp_in)
1060 {
1061 mutt_file_copy_stream(fp_in, fp_out);
1062 if (fp_in != stdin)
1063 mutt_file_fclose(&fp_in);
1064 }
1065 else if (bodytext)
1066 fputs(bodytext, fp_out);
1067 mutt_file_fclose(&fp_out);
1068
1069 fp_in = fopen(mutt_buffer_string(&tempfile), "r");
1070 if (!fp_in)
1071 {
1072 mutt_perror(mutt_buffer_string(&tempfile));
1073 email_free(&e);
1074 goto main_curses; // TEST30: can't test
1075 }
1076 }
1077 /* If editing the infile, keep it around afterwards so
1078 * it doesn't get unlinked, and we can rebuild the draft_file */
1079 else
1080 sendflags |= SEND_NO_FREE_HEADER;
1081
1082 /* Parse the draft_file into the full Email/Body structure.
1083 * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1084 * our e->body. */
1085 if (draft_file)
1086 {
1087 struct Envelope *opts_env = e->env;
1088 struct stat st = { 0 };
1089
1090 sendflags |= SEND_DRAFT_FILE;
1091
1092 /* Set up a tmp Email with just enough information so that
1093 * mutt_prepare_template() can parse the message in fp_in. */
1094 struct Email *e_tmp = email_new();
1095 e_tmp->offset = 0;
1096 e_tmp->body = mutt_body_new();
1097 if (fstat(fileno(fp_in), &st) != 0)
1098 {
1099 mutt_perror(draft_file);
1100 email_free(&e);
1101 email_free(&e_tmp);
1102 goto main_curses; // TEST31: can't test
1103 }
1104 e_tmp->body->length = st.st_size;
1105
1106 if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1107 {
1108 mutt_error(_("Can't parse message template: %s"), draft_file);
1109 email_free(&e);
1110 email_free(&e_tmp);
1111 goto main_curses;
1112 }
1113
1114 /* Scan for neomutt header to set `$resume_draft_files` */
1115 struct ListNode *np = NULL, *tmp = NULL;
1116 STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1117 {
1118 if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1119 {
1120 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1121 if (c_resume_edited_draft_files)
1122 cs_str_native_set(cs, "resume_draft_files", true, NULL);
1123
1124 STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1125 FREE(&np->data);
1126 FREE(&np);
1127 }
1128 }
1129
1130 mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1131 mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1132 mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1133 if (opts_env->subject)
1134 mutt_str_replace(&e->env->subject, opts_env->subject);
1135
1136 mutt_env_free(&opts_env);
1137 email_free(&e_tmp);
1138 }
1139 /* Editing the include_file: pass it directly in.
1140 * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1141 else if (edit_infile)
1142 bodyfile = mutt_buffer_string(&expanded_infile);
1143 // For bodytext and unedited include_file: use the tempfile.
1144 else
1145 bodyfile = mutt_buffer_string(&tempfile);
1146
1147 mutt_file_fclose(&fp_in);
1148 }
1149
1150 FREE(&bodytext);
1151
1152 if (!STAILQ_EMPTY(&attach))
1153 {
1154 struct Body *b = e->body;
1155
1156 while (b && b->next)
1157 b = b->next;
1158
1159 struct ListNode *np = NULL;
1160 STAILQ_FOREACH(np, &attach, entries)
1161 {
1162 if (b)
1163 {
1165 b = b->next;
1166 }
1167 else
1168 {
1170 e->body = b;
1171 }
1172 if (!b)
1173 {
1174 mutt_error(_("%s: unable to attach file"), np->data);
1175 mutt_list_free(&attach);
1176 email_free(&e);
1177 goto main_curses; // TEST32: neomutt john@example.com -a missing
1178 }
1179 }
1180 mutt_list_free(&attach);
1181 }
1182
1183 rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1184 /* We WANT the "Mail sent." and any possible, later error */
1186 if (ErrorBufMessage)
1187 mutt_message("%s", ErrorBuf);
1188
1189 if (edit_infile)
1190 {
1191 if (draft_file)
1192 {
1193 if (truncate(mutt_buffer_string(&expanded_infile), 0) == -1)
1194 {
1195 mutt_perror(mutt_buffer_string(&expanded_infile));
1196 email_free(&e);
1197 goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1198 }
1199 fp_out = mutt_file_fopen(mutt_buffer_string(&expanded_infile), "a");
1200 if (!fp_out)
1201 {
1202 mutt_perror(mutt_buffer_string(&expanded_infile));
1203 email_free(&e);
1204 goto main_curses; // TEST34: can't test
1205 }
1206
1207 /* If the message was sent or postponed, these will already
1208 * have been done. */
1209 if (rv < 0)
1210 {
1211 if (e->body->next)
1212 e->body = mutt_make_multipart(e->body);
1214 mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1215 mutt_env_to_intl(e->env, NULL, NULL);
1216 }
1217
1218 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1220 c_crypt_protected_headers_read &&
1222 NeoMutt->sub);
1223 const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1224 if (c_resume_edited_draft_files)
1225 fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1226 fputc('\n', fp_out);
1227 if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1228 {
1229 mutt_file_fclose(&fp_out);
1230 email_free(&e);
1231 goto main_curses; // TEST35: can't test
1232 }
1233 mutt_file_fclose(&fp_out);
1234 }
1235
1236 email_free(&e);
1237 }
1238
1239 /* !edit_infile && draft_file will leave the tempfile around */
1240 if (!mutt_buffer_is_empty(&tempfile))
1241 unlink(mutt_buffer_string(&tempfile));
1242
1243 rootwin_free();
1244
1245 if (rv != 0)
1246 goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1247 }
1248 else if (sendflags & SEND_BATCH)
1249 {
1250 /* This guards against invoking `neomutt < /dev/null` and accidentally
1251 * sending an email due to a my_hdr or other setting. */
1252 mutt_error(_("No recipients specified"));
1253 goto main_curses;
1254 }
1255 else
1256 {
1257 if (flags & MUTT_CLI_MAILBOX)
1258 {
1259#ifdef USE_IMAP
1260 const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1261 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1262#endif
1264 if (mutt_mailbox_check(NULL, csflags) == 0)
1265 {
1266 mutt_message(_("No mailbox with new mail"));
1267 goto main_curses; // TEST37: neomutt -Z (no new mail)
1268 }
1269 mutt_buffer_reset(&folder);
1270 mutt_mailbox_next(NULL, &folder);
1271#ifdef USE_IMAP
1272 cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1273#endif
1274 }
1275 else if (flags & MUTT_CLI_SELECT)
1276 {
1277#ifdef USE_NNTP
1278 if (flags & MUTT_CLI_NEWS)
1279 {
1280 const char *const c_news_server = cs_subset_string(NeoMutt->sub, "news_server");
1281 OptNews = true;
1282 struct Mailbox *m_cur = get_current_mailbox();
1283 CurrentNewsSrv = nntp_select_server(m_cur, c_news_server, false);
1284 if (!CurrentNewsSrv)
1285 goto main_curses; // TEST38: neomutt -G (unset news_server)
1286 }
1287 else
1288#endif
1290 {
1291 mutt_error(_("No incoming mailboxes defined"));
1292 goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1293 }
1294 mutt_buffer_reset(&folder);
1295 struct Mailbox *m_cur = get_current_mailbox();
1296 mutt_buffer_select_file(&folder, MUTT_SEL_FOLDER | MUTT_SEL_MAILBOX, m_cur, NULL, NULL);
1297 if (mutt_buffer_is_empty(&folder))
1298 {
1299 goto main_ok; // TEST40: neomutt -y (quit selection)
1300 }
1301 }
1302
1303 if (mutt_buffer_is_empty(&folder))
1304 {
1305 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1306 if (c_spool_file)
1307 {
1308 // Check if `$spool_file` corresponds a mailboxes' description.
1309 struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1310 if (m_desc)
1311 mutt_buffer_strcpy(&folder, m_desc->realpath);
1312 else
1313 mutt_buffer_strcpy(&folder, c_spool_file);
1314 }
1315 else if (c_folder)
1316 mutt_buffer_strcpy(&folder, c_folder);
1317 /* else no folder */
1318 }
1319
1320#ifdef USE_NNTP
1321 if (OptNews)
1322 {
1323 OptNews = false;
1324 mutt_buffer_alloc(&folder, PATH_MAX);
1326 }
1327 else
1328#endif
1329 mutt_buffer_expand_path(&folder);
1330
1333
1334 if (flags & MUTT_CLI_IGNORE)
1335 {
1336 /* check to see if there are any messages in the folder */
1337 switch (mx_path_is_empty(mutt_buffer_string(&folder)))
1338 {
1339 case -1:
1341 goto main_curses; // TEST41: neomutt -z -f missing
1342 case 1:
1343 mutt_error(_("Mailbox is empty"));
1344 goto main_curses; // TEST42: neomutt -z -f /dev/null
1345 }
1346 }
1347
1348 mutt_folder_hook(mutt_buffer_string(&folder), NULL);
1350 mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1352
1353 repeat_error = true;
1354 struct Mailbox *m = mx_resolve(mutt_buffer_string(&folder));
1355 const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1356 if (!mx_mbox_open(m, ((flags & MUTT_CLI_RO) || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1357 {
1358 if (m->account)
1360
1361 mailbox_free(&m);
1362 mutt_error(_("Unable to open mailbox %s"), mutt_buffer_string(&folder));
1363 repeat_error = false;
1364 }
1365 if (m || !explicit_folder)
1366 {
1367 struct MuttWindow *dlg = index_pager_init();
1368 dialog_push(dlg);
1369
1371 m = mutt_index_menu(dlg, m);
1373 mailbox_free(&m);
1374
1375 dialog_pop();
1376 mutt_window_free(&dlg);
1378 repeat_error = false;
1379 }
1380#ifdef USE_IMAP
1382#endif
1383#ifdef USE_SASL_CYRUS
1385#endif
1386#ifdef USE_AUTOCRYPT
1388#endif
1389 // TEST43: neomutt (no change to mailbox)
1390 // TEST44: neomutt (change mailbox)
1391 }
1392
1393main_ok:
1394 rc = 0;
1395main_curses:
1396 mutt_endwin();
1398 /* Repeat the last message to the user */
1399 if (repeat_error && ErrorBufMessage)
1400 puts(ErrorBuf);
1401main_exit:
1404 mutt_buffer_dealloc(&folder);
1405 mutt_buffer_dealloc(&expanded_infile);
1406 mutt_buffer_dealloc(&tempfile);
1407 mutt_list_free(&queries);
1409 rootwin_free();
1414 menu_cleanup();
1415 crypt_cleanup();
1417 subjrx_free();
1418 attach_free();
1424 cs_free(&cs);
1427 mutt_log_stop();
1428 return rc;
1429}
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:54
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:1078
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:1052
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1397
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:260
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
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:1438
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: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:2400
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
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:624
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:918
void mutt_opts_free(void)
Clean up before quitting.
Definition: init.c:519
int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:575
void init_config(struct ConfigSet *cs)
Initialise the config system.
Definition: mutt_config.c:785
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:215
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition: main.c:371
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:209
static void log_translation(void)
Log the translation being used.
Definition: main.c:440
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:212
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:225
static bool usage(void)
Display NeoMutt command line.
Definition: main.c:262
static int start_curses(void)
Start the Curses UI.
Definition: main.c:339
static bool get_user_info(struct ConfigSet *cs)
Find the user's name, home and shell.
Definition: main.c:399
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:214
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:210
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:211
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:217
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:213
#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:1671
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:346
@ 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:536
bool print_version(FILE *fp)
Print system and compile info to a file.
Definition: version.c:408