NeoMutt  2022-04-29-70-g0c028c
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:61
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
#define mutt_array_size(x)
Definition: memory.h:33
void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:134
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
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_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)
253  show_backtrace();
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:465
+ 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:1469
+ 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:1026
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: keymap.c:997
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:904
+ 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:569
#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;
496  CliFlags flags = MUTT_CLI_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 */
597  flags |= MUTT_CLI_SELECT | MUTT_CLI_NEWS;
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();
692  alternates_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");
707  test_parse_set();
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 
732  mutt_log_prep();
733  if (dlevel)
734  mutt_log_start();
735 
737 
738  log_translation();
739 
740  if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
741  {
742  e = email_new();
743  e->env = mutt_env_new();
744 
745  struct ListNode *np = NULL;
746  STAILQ_FOREACH(np, &bcc_list, entries)
747  {
748  mutt_addrlist_parse(&e->env->bcc, np->data);
749  }
750 
751  STAILQ_FOREACH(np, &cc_list, entries)
752  {
753  mutt_addrlist_parse(&e->env->cc, np->data);
754  }
755 
756  mutt_list_free(&bcc_list);
757  mutt_list_free(&cc_list);
758  }
759 
760  /* Check for a batch send. */
761  if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
762  dump_variables || batch_mode)
763  {
764  OptNoCurses = true;
765  sendflags = SEND_BATCH;
768  }
769 
770  /* Check to make sure stdout is available in curses mode. */
771  if (!OptNoCurses && !isatty(1))
772  goto main_curses;
773 
774  /* Always create the mutt_windows because batch mode has some shared code
775  * paths that end up referencing them. */
776  rootwin_new();
777 
778  /* This must come before mutt_init() because curses needs to be started
779  * before calling the init_pair() function to set the color scheme. */
780  if (!OptNoCurses)
781  {
782  int crc = start_curses();
783  if (crc != 0)
784  goto main_curses; // TEST08: can't test -- fake term?
785 
786  /* check whether terminal status is supported (must follow curses init) */
788  rootwin_set_size(COLS, LINES);
789  }
790 
791  /* set defaults and read init files */
792  int rc2 = mutt_init(cs, flags & MUTT_CLI_NOSYSRC, &commands);
793  if (rc2 != 0)
794  goto main_curses;
795 
797 
798  /* The command line overrides the config */
799  if (dlevel)
800  cs_str_reset(cs, "debug_level", NULL);
801  if (dfile)
802  cs_str_reset(cs, "debug_file", NULL);
803 
804  if (mutt_log_start() < 0)
805  {
806  mutt_perror("log file");
807  goto main_exit;
808  }
809 
810 #ifdef USE_NNTP
811  {
812  /* "$news_server" precedence: command line, config file, environment, system file */
813  if (!cli_nntp)
814  cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
815 
816  if (!cli_nntp)
817  cli_nntp = mutt_str_getenv("NNTPSERVER");
818 
819  char buf[1024] = { 0 };
820  if (!cli_nntp)
821  cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
822 
823  if (cli_nntp)
824  {
825  cs_str_initial_set(cs, "news_server", cli_nntp, NULL);
826  cs_str_reset(cs, "news_server", NULL);
827  }
828  }
829 #endif
830 
831  /* Initialize crypto backends. */
832  crypt_init();
833 
834  if (new_type)
835  {
836  struct Buffer err = mutt_buffer_make(0);
837  int r = cs_str_initial_set(cs, "mbox_type", new_type, &err);
838  if (CSR_RESULT(r) != CSR_SUCCESS)
839  {
840  mutt_error(err.data);
841  mutt_buffer_dealloc(&err);
842  goto main_curses;
843  }
844  cs_str_reset(cs, "mbox_type", NULL);
845  }
846 
847  if (!STAILQ_EMPTY(&queries))
848  {
849  rc = mutt_query_variables(&queries, one_liner);
850  goto main_curses;
851  }
852 
853  if (dump_variables)
854  {
856  if (hide_sensitive)
857  cdflags |= CS_DUMP_HIDE_SENSITIVE;
858  if (one_liner)
859  cdflags |= CS_DUMP_SHOW_DOCS;
860  dump_config(cs, cdflags, stdout);
861  goto main_ok; // TEST18: neomutt -D
862  }
863 
864  if (!STAILQ_EMPTY(&alias_queries))
865  {
866  rc = 0;
867  for (; optind < argc; optind++)
868  mutt_list_insert_tail(&alias_queries, mutt_str_dup(argv[optind]));
869  struct ListNode *np = NULL;
870  STAILQ_FOREACH(np, &alias_queries, entries)
871  {
872  struct AddressList *al = alias_lookup(np->data);
873  if (al)
874  {
875  /* output in machine-readable form */
876  mutt_addrlist_to_intl(al, NULL);
877  mutt_addrlist_write_file(al, stdout, 0, false);
878  }
879  else
880  {
881  rc = 1;
882  printf("%s\n", np->data); // TEST19: neomutt -A unknown
883  }
884  }
885  mutt_list_free(&alias_queries);
886  goto main_curses; // TEST20: neomutt -A alias
887  }
888 
889  if (!OptNoCurses)
890  {
892  clear();
896  }
897 
898 #ifdef USE_AUTOCRYPT
899  /* Initialize autocrypt after curses messages are working,
900  * because of the initial account setup screens. */
901  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
902  if (c_autocrypt)
903  mutt_autocrypt_init(!(sendflags & SEND_BATCH));
904 #endif
905 
906  /* Create the `$folder` directory if it doesn't exist. */
907  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
908  if (!OptNoCurses && c_folder)
909  {
910  struct stat st = { 0 };
911  struct Buffer *fpath = mutt_buffer_pool_get();
912 
913  mutt_buffer_strcpy(fpath, c_folder);
915  bool skip = false;
916 #ifdef USE_IMAP
917  /* we're not connected yet - skip mail folder creation */
918  skip |= (imap_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_IMAP);
919 #endif
920 #ifdef USE_POP
921  skip |= (pop_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_POP);
922 #endif
923 #ifdef USE_NNTP
924  skip |= (nntp_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_NNTP);
925 #endif
926  if (!skip && (stat(mutt_buffer_string(fpath), &st) == -1) && (errno == ENOENT))
927  {
928  char msg2[256];
929  snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
930  if (mutt_yesorno(msg2, MUTT_YES) == MUTT_YES)
931  {
932  if ((mkdir(mutt_buffer_string(fpath), 0700) == -1) && (errno != EEXIST))
933  mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
934  }
935  }
936  mutt_buffer_pool_release(&fpath);
937  }
938 
939  if (batch_mode)
940  {
941  goto main_ok; // TEST22: neomutt -B
942  }
943 
947 
948  if (sendflags & SEND_POSTPONED)
949  {
950  if (!OptNoCurses)
951  mutt_flushinp();
952  if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
953  rc = 0;
954  // TEST23: neomutt -p (postponed message, cancel)
955  // TEST24: neomutt -p (no postponed message)
956  log_queue_empty();
957  repeat_error = true;
958  goto main_curses;
959  }
960  else if (subject || e || draft_file || include_file ||
961  !STAILQ_EMPTY(&attach) || (optind < argc))
962  {
963  FILE *fp_in = NULL;
964  FILE *fp_out = NULL;
965  char *infile = NULL;
966  char *bodytext = NULL;
967  const char *bodyfile = NULL;
968  int rv = 0;
969 
970  if (!OptNoCurses)
971  mutt_flushinp();
972 
973  if (!e)
974  e = email_new();
975  if (!e->env)
976  e->env = mutt_env_new();
977 
978  for (i = optind; i < argc; i++)
979  {
980  if (url_check_scheme(argv[i]) == U_MAILTO)
981  {
982  if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
983  {
984  mutt_error(_("Failed to parse mailto: link"));
985  email_free(&e);
986  goto main_curses; // TEST25: neomutt mailto:?
987  }
988  }
989  else
990  mutt_addrlist_parse(&e->env->to, argv[i]);
991  }
992 
993  const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
994  if (!draft_file && c_auto_edit && TAILQ_EMPTY(&e->env->to) &&
995  TAILQ_EMPTY(&e->env->cc))
996  {
997  mutt_error(_("No recipients specified"));
998  email_free(&e);
999  goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
1000  }
1001 
1002  if (subject)
1003  {
1004  mutt_str_replace(&e->env->subject, subject);
1005  }
1006 
1007  if (draft_file)
1008  {
1009  infile = draft_file;
1010  include_file = NULL;
1011  }
1012  else if (include_file)
1013  infile = include_file;
1014  else
1015  edit_infile = false;
1016 
1017  if (infile || bodytext)
1018  {
1019  /* Prepare fp_in and expanded_infile. */
1020  if (infile)
1021  {
1022  if (mutt_str_equal("-", infile))
1023  {
1024  if (edit_infile)
1025  {
1026  mutt_error(_("Can't use -E flag with stdin"));
1027  email_free(&e);
1028  goto main_curses; // TEST27: neomutt -E -H -
1029  }
1030  fp_in = stdin;
1031  }
1032  else
1033  {
1034  mutt_buffer_strcpy(&expanded_infile, infile);
1035  mutt_buffer_expand_path(&expanded_infile);
1036  fp_in = fopen(mutt_buffer_string(&expanded_infile), "r");
1037  if (!fp_in)
1038  {
1039  mutt_perror(mutt_buffer_string(&expanded_infile));
1040  email_free(&e);
1041  goto main_curses; // TEST28: neomutt -E -H missing
1042  }
1043  }
1044  }
1045 
1046  /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1047  * Note: stdin is always copied to a tempfile, ensuring draft_file
1048  * can stat and get the correct st_size below. */
1049  if (!edit_infile)
1050  {
1051  mutt_buffer_mktemp(&tempfile);
1052 
1053  fp_out = mutt_file_fopen(mutt_buffer_string(&tempfile), "w");
1054  if (!fp_out)
1055  {
1056  mutt_file_fclose(&fp_in);
1057  mutt_perror(mutt_buffer_string(&tempfile));
1058  email_free(&e);
1059  goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1060  }
1061  if (fp_in)
1062  {
1063  mutt_file_copy_stream(fp_in, fp_out);
1064  if (fp_in != stdin)
1065  mutt_file_fclose(&fp_in);
1066  }
1067  else if (bodytext)
1068  fputs(bodytext, fp_out);
1069  mutt_file_fclose(&fp_out);
1070 
1071  fp_in = fopen(mutt_buffer_string(&tempfile), "r");
1072  if (!fp_in)
1073  {
1074  mutt_perror(mutt_buffer_string(&tempfile));
1075  email_free(&e);
1076  goto main_curses; // TEST30: can't test
1077  }
1078  }
1079  /* If editing the infile, keep it around afterwards so
1080  * it doesn't get unlinked, and we can rebuild the draft_file */
1081  else
1082  sendflags |= SEND_NO_FREE_HEADER;
1083 
1084  /* Parse the draft_file into the full Email/Body structure.
1085  * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1086  * our e->body. */
1087  if (draft_file)
1088  {
1089  struct Envelope *opts_env = e->env;
1090  struct stat st = { 0 };
1091 
1092  sendflags |= SEND_DRAFT_FILE;
1093 
1094  /* Set up a tmp Email with just enough information so that
1095  * mutt_prepare_template() can parse the message in fp_in. */
1096  struct Email *e_tmp = email_new();
1097  e_tmp->offset = 0;
1098  e_tmp->body = mutt_body_new();
1099  if (fstat(fileno(fp_in), &st) != 0)
1100  {
1101  mutt_perror(draft_file);
1102  email_free(&e);
1103  email_free(&e_tmp);
1104  goto main_curses; // TEST31: can't test
1105  }
1106  e_tmp->body->length = st.st_size;
1107 
1108  if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1109  {
1110  mutt_error(_("Can't parse message template: %s"), draft_file);
1111  email_free(&e);
1112  email_free(&e_tmp);
1113  goto main_curses;
1114  }
1115 
1116  /* Scan for neomutt header to set `$resume_draft_files` */
1117  struct ListNode *np = NULL, *tmp = NULL;
1118  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1119  {
1120  if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1121  {
1122  const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1123  if (c_resume_edited_draft_files)
1124  cs_str_native_set(cs, "resume_draft_files", true, NULL);
1125 
1126  STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1127  FREE(&np->data);
1128  FREE(&np);
1129  }
1130  }
1131 
1132  mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1133  mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1134  mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1135  if (opts_env->subject)
1136  mutt_str_replace(&e->env->subject, opts_env->subject);
1137 
1138  mutt_env_free(&opts_env);
1139  email_free(&e_tmp);
1140  }
1141  /* Editing the include_file: pass it directly in.
1142  * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1143  else if (edit_infile)
1144  bodyfile = mutt_buffer_string(&expanded_infile);
1145  // For bodytext and unedited include_file: use the tempfile.
1146  else
1147  bodyfile = mutt_buffer_string(&tempfile);
1148 
1149  mutt_file_fclose(&fp_in);
1150  }
1151 
1152  FREE(&bodytext);
1153 
1154  if (!STAILQ_EMPTY(&attach))
1155  {
1156  struct Body *b = e->body;
1157 
1158  while (b && b->next)
1159  b = b->next;
1160 
1161  struct ListNode *np = NULL;
1162  STAILQ_FOREACH(np, &attach, entries)
1163  {
1164  if (b)
1165  {
1167  b = b->next;
1168  }
1169  else
1170  {
1172  e->body = b;
1173  }
1174  if (!b)
1175  {
1176  mutt_error(_("%s: unable to attach file"), np->data);
1177  mutt_list_free(&attach);
1178  email_free(&e);
1179  goto main_curses; // TEST32: neomutt john@example.com -a missing
1180  }
1181  }
1182  mutt_list_free(&attach);
1183  }
1184 
1185  rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1186  /* We WANT the "Mail sent." and any possible, later error */
1187  log_queue_empty();
1188  if (ErrorBufMessage)
1189  mutt_message("%s", ErrorBuf);
1190 
1191  if (edit_infile)
1192  {
1193  if (draft_file)
1194  {
1195  if (truncate(mutt_buffer_string(&expanded_infile), 0) == -1)
1196  {
1197  mutt_perror(mutt_buffer_string(&expanded_infile));
1198  email_free(&e);
1199  goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1200  }
1201  fp_out = mutt_file_fopen(mutt_buffer_string(&expanded_infile), "a");
1202  if (!fp_out)
1203  {
1204  mutt_perror(mutt_buffer_string(&expanded_infile));
1205  email_free(&e);
1206  goto main_curses; // TEST34: can't test
1207  }
1208 
1209  /* If the message was sent or postponed, these will already
1210  * have been done. */
1211  if (rv < 0)
1212  {
1213  if (e->body->next)
1214  e->body = mutt_make_multipart(e->body);
1216  mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1217  mutt_env_to_intl(e->env, NULL, NULL);
1218  }
1219 
1220  const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1222  c_crypt_protected_headers_read &&
1224  NeoMutt->sub);
1225  const bool c_resume_edited_draft_files = cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1226  if (c_resume_edited_draft_files)
1227  fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1228  fputc('\n', fp_out);
1229  if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1230  {
1231  mutt_file_fclose(&fp_out);
1232  email_free(&e);
1233  goto main_curses; // TEST35: can't test
1234  }
1235  mutt_file_fclose(&fp_out);
1236  }
1237 
1238  email_free(&e);
1239  }
1240 
1241  /* !edit_infile && draft_file will leave the tempfile around */
1242  if (!mutt_buffer_is_empty(&tempfile))
1243  unlink(mutt_buffer_string(&tempfile));
1244 
1245  rootwin_free();
1246 
1247  if (rv != 0)
1248  goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1249  }
1250  else if (sendflags & SEND_BATCH)
1251  {
1252  /* This guards against invoking `neomutt < /dev/null` and accidentally
1253  * sending an email due to a my_hdr or other setting. */
1254  mutt_error(_("No recipients specified"));
1255  goto main_curses;
1256  }
1257  else
1258  {
1259  if (flags & MUTT_CLI_MAILBOX)
1260  {
1261 #ifdef USE_IMAP
1262  const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1263  cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1264 #endif
1266  if (mutt_mailbox_check(NULL, csflags) == 0)
1267  {
1268  mutt_message(_("No mailbox with new mail"));
1269  goto main_curses; // TEST37: neomutt -Z (no new mail)
1270  }
1271  mutt_buffer_reset(&folder);
1272  mutt_mailbox_next(NULL, &folder);
1273 #ifdef USE_IMAP
1274  cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1275 #endif
1276  }
1277  else if (flags & MUTT_CLI_SELECT)
1278  {
1279 #ifdef USE_NNTP
1280  if (flags & MUTT_CLI_NEWS)
1281  {
1282  const char *const c_news_server = cs_subset_string(NeoMutt->sub, "news_server");
1283  OptNews = true;
1284  struct Mailbox *m_cur = get_current_mailbox();
1285  CurrentNewsSrv = nntp_select_server(m_cur, c_news_server, false);
1286  if (!CurrentNewsSrv)
1287  goto main_curses; // TEST38: neomutt -G (unset news_server)
1288  }
1289  else
1290 #endif
1291  if (TAILQ_EMPTY(&NeoMutt->accounts))
1292  {
1293  mutt_error(_("No incoming mailboxes defined"));
1294  goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1295  }
1296  mutt_buffer_reset(&folder);
1297  struct Mailbox *m_cur = get_current_mailbox();
1298  mutt_buffer_select_file(&folder, MUTT_SEL_FOLDER | MUTT_SEL_MAILBOX, m_cur, NULL, NULL);
1299  if (mutt_buffer_is_empty(&folder))
1300  {
1301  goto main_ok; // TEST40: neomutt -y (quit selection)
1302  }
1303  }
1304 
1305  if (mutt_buffer_is_empty(&folder))
1306  {
1307  const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1308  if (c_spool_file)
1309  {
1310  // Check if `$spool_file` corresponds a mailboxes' description.
1311  struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1312  if (m_desc)
1313  mutt_buffer_strcpy(&folder, m_desc->realpath);
1314  else
1315  mutt_buffer_strcpy(&folder, c_spool_file);
1316  }
1317  else if (c_folder)
1318  mutt_buffer_strcpy(&folder, c_folder);
1319  /* else no folder */
1320  }
1321 
1322 #ifdef USE_NNTP
1323  if (OptNews)
1324  {
1325  OptNews = false;
1326  mutt_buffer_alloc(&folder, PATH_MAX);
1327  nntp_expand_path(folder.data, folder.dsize, &CurrentNewsSrv->conn->account);
1328  }
1329  else
1330 #endif
1331  mutt_buffer_expand_path(&folder);
1332 
1335 
1336  if (flags & MUTT_CLI_IGNORE)
1337  {
1338  /* check to see if there are any messages in the folder */
1339  switch (mx_path_is_empty(mutt_buffer_string(&folder)))
1340  {
1341  case -1:
1342  mutt_perror(mutt_buffer_string(&folder));
1343  goto main_curses; // TEST41: neomutt -z -f missing
1344  case 1:
1345  mutt_error(_("Mailbox is empty"));
1346  goto main_curses; // TEST42: neomutt -z -f /dev/null
1347  }
1348  }
1349 
1350  mutt_folder_hook(mutt_buffer_string(&folder), NULL);
1352  mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1354 
1355  repeat_error = true;
1356  struct Mailbox *m = mx_resolve(mutt_buffer_string(&folder));
1357  const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1358  if (!mx_mbox_open(m, ((flags & MUTT_CLI_RO) || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1359  {
1360  if (m->account)
1362 
1363  mailbox_free(&m);
1364  mutt_error(_("Unable to open mailbox %s"), mutt_buffer_string(&folder));
1365  repeat_error = false;
1366  }
1367  if (m || !explicit_folder)
1368  {
1369  struct MuttWindow *dlg = index_pager_init();
1370  dialog_push(dlg);
1371 
1373  m = mutt_index_menu(dlg, m);
1375  mailbox_free(&m);
1376 
1377  dialog_pop();
1378  mutt_window_free(&dlg);
1379  log_queue_empty();
1380  repeat_error = false;
1381  }
1382 #ifdef USE_IMAP
1383  imap_logout_all();
1384 #endif
1385 #ifdef USE_SASL
1386  mutt_sasl_done();
1387 #endif
1388 #ifdef USE_AUTOCRYPT
1390 #endif
1391  // TEST43: neomutt (no change to mailbox)
1392  // TEST44: neomutt (change mailbox)
1393  }
1394 
1395 main_ok:
1396  rc = 0;
1397 main_curses:
1398  mutt_endwin();
1400  /* Repeat the last message to the user */
1401  if (repeat_error && ErrorBufMessage)
1402  puts(ErrorBuf);
1403 main_exit:
1406  mutt_buffer_dealloc(&folder);
1407  mutt_buffer_dealloc(&expanded_infile);
1408  mutt_buffer_dealloc(&tempfile);
1409  mutt_list_free(&queries);
1411  rootwin_free();
1416  menu_cleanup();
1417  crypt_cleanup();
1418  mutt_opts_free();
1419  subjrx_free();
1420  attach_free();
1421  alternates_free();
1422  mutt_keys_free();
1424  mutt_prex_free();
1426  cs_free(&cs);
1428  log_queue_empty();
1429  mutt_log_stop();
1430  return rc;
1431 }
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:279
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:92
void attach_init(void)
Set up the attachments lists.
Definition: attachments.c:106
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:1076
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:265
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
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:53
void mutt_commands_cleanup(void)
Clean up commands globals.
Definition: commands.c:80
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:703
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:1016
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1361
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:32
#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
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
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
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:2698
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:882
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
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
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:897
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:562
#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:603
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:1065
void mutt_opts_free(void)
Clean up before quitting.
Definition: init.c:644
int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:720
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:1669
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: keymap.c:860
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
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 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:40
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:784
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
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
#define PATH_MAX
Definition: mutt.h:40
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1301
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:321
#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 * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1018
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
@ 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)
@ 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:174
void rootwin_set_size(int cols, int rows)
Set the dimensions of the Root Window.
Definition: rootwin.c:220
void rootwin_new(void)
Create the default Windows.
Definition: rootwin.c:184
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:1577
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:2125
#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:36
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
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
struct ConfigSet * cs_new(size_t size)
Create a new Config Set.
Definition: set.c:156
#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:128
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