NeoMutt  2021-10-22-8-g9cb437
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 "color/lib.h"
#include "index/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "alternates.h"
#include "browser.h"
#include "commands.h"
#include "context.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 143 of file main.c.

◆ GNULIB_defined_setlocale

#define GNULIB_defined_setlocale

Definition at line 144 of file main.c.

◆ MUTT_CLI_NO_FLAGS

#define MUTT_CLI_NO_FLAGS   0

No flags are set.

Definition at line 215 of file main.c.

◆ MUTT_CLI_IGNORE

#define MUTT_CLI_IGNORE   (1 << 0)

-z Open first mailbox if it has mail

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

◆ MUTT_CLI_RO

#define MUTT_CLI_RO   (1 << 3)

-R Open mailbox in read-only mode

Definition at line 219 of file main.c.

◆ MUTT_CLI_SELECT

#define MUTT_CLI_SELECT   (1 << 4)

-y Start with a list of all mailboxes

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

Typedef Documentation

◆ CliFlags

typedef uint8_t CliFlags

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

Definition at line 214 of file main.c.

Function Documentation

◆ reset_tilde()

static void reset_tilde ( struct ConfigSet cs)
static

Temporary measure.

Parameters
csConfig Set

Definition at line 230 of file main.c.

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

254 {
255  mutt_endwin();
256 #ifdef HAVE_LIBUNWIND
257  if (code != 0)
258  show_backtrace();
259 #endif
260  exit(code);
261 }
void show_backtrace(void)
Log the program's call stack.
Definition: backtrace.c:39
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:422
+ 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 267 of file main.c.

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

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

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

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

446 {
447  const char *header = ""; // Do not merge these two lines
448  header = _(header); // otherwise the .po files will end up badly ordered
449  const char *lang = strcasestr(header, "Language:");
450  int len = 64;
451  if (lang)
452  {
453  lang += 9; // skip label
454  SKIPWS(lang);
455  char *nl = strchr(lang, '\n');
456  if (nl)
457  len = (nl - lang);
458  }
459  else
460  {
461  lang = "NONE";
462  }
463 
464  mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
465 }
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define SKIPWS(ch)
Definition: string2.h:46
+ 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.

476 {
477  char *subject = NULL;
478  char *include_file = NULL;
479  char *draft_file = NULL;
480  char *new_type = NULL;
481  char *dlevel = NULL;
482  char *dfile = NULL;
483 #ifdef USE_NNTP
484  const char *cli_nntp = NULL;
485 #endif
486  struct Email *e = NULL;
487  struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
488  struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
489  struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
490  struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
491  struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
492  struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
493  SendFlags sendflags = SEND_NO_FLAGS;
494  CliFlags flags = MUTT_CLI_NO_FLAGS;
495  int version = 0;
496  int i;
497  bool explicit_folder = false;
498  bool dump_variables = false;
499  bool one_liner = false;
500  bool hide_sensitive = false;
501  bool batch_mode = false;
502  bool edit_infile = false;
503 #ifdef USE_DEBUG_PARSE_TEST
504  bool test_config = false;
505 #endif
506  int double_dash = argc, nargc = 1;
507  int rc = 1;
508  bool repeat_error = false;
509  struct Buffer folder = mutt_buffer_make(0);
510  struct Buffer expanded_infile = mutt_buffer_make(0);
511  struct Buffer tempfile = mutt_buffer_make(0);
512  struct ConfigSet *cs = NULL;
513 
515 
516  /* sanity check against stupid administrators */
517  if (getegid() != getgid())
518  {
519  mutt_error("%s: I don't want to run with privileges!", argv[0]);
520  goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
521  }
522 
523  init_locale();
524 
525  umask(077);
526 
527  mutt_envlist_init(envp);
528  for (optind = 1; optind < double_dash;)
529  {
530  /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
531  * encounters a non-option. That could be a file to attach
532  * (all non-options between -a and --) or it could be an address
533  * (which gets collapsed to the front of argv). */
534  for (; optind < argc; optind++)
535  {
536  if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
537  {
538  if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
539  double_dash = optind; /* quit outer loop after getopt */
540  break; /* drop through to getopt */
541  }
542 
543  /* non-option, either an attachment or address */
544  if (!STAILQ_EMPTY(&attach))
545  mutt_list_insert_tail(&attach, mutt_str_dup(argv[optind]));
546  else
547  argv[nargc++] = argv[optind];
548  }
549 
550  /* USE_NNTP 'g:G' */
551  i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:i:hm:nOpQ:RSs:TvxyzZ");
552  if (i != EOF)
553  {
554  switch (i)
555  {
556  case 'A':
557  mutt_list_insert_tail(&alias_queries, mutt_str_dup(optarg));
558  break;
559  case 'a':
560  mutt_list_insert_tail(&attach, mutt_str_dup(optarg));
561  break;
562  case 'B':
563  batch_mode = true;
564  break;
565  case 'b':
566  mutt_list_insert_tail(&bcc_list, mutt_str_dup(optarg));
567  break;
568  case 'c':
569  mutt_list_insert_tail(&cc_list, mutt_str_dup(optarg));
570  break;
571  case 'D':
572  dump_variables = true;
573  break;
574  case 'd':
575  dlevel = optarg;
576  break;
577  case 'E':
578  edit_infile = true;
579  break;
580  case 'e':
581  mutt_list_insert_tail(&commands, mutt_str_dup(optarg));
582  break;
583  case 'F':
585  break;
586  case 'f':
587  mutt_buffer_strcpy(&folder, optarg);
588  explicit_folder = true;
589  break;
590 #ifdef USE_NNTP
591  case 'g': /* Specify a news server */
592  cli_nntp = optarg;
593  /* fallthrough */
594  case 'G': /* List of newsgroups */
595  flags |= MUTT_CLI_SELECT | MUTT_CLI_NEWS;
596  break;
597 #endif
598  case 'H':
599  draft_file = optarg;
600  break;
601  case 'i':
602  include_file = optarg;
603  break;
604  case 'l':
605  dfile = optarg;
606  break;
607  case 'm':
608  new_type = optarg;
609  break;
610  case 'n':
611  flags |= MUTT_CLI_NOSYSRC;
612  break;
613  case 'O':
614  one_liner = true;
615  break;
616  case 'p':
617  sendflags |= SEND_POSTPONED;
618  break;
619  case 'Q':
620  mutt_list_insert_tail(&queries, mutt_str_dup(optarg));
621  break;
622  case 'R':
623  flags |= MUTT_CLI_RO; /* read-only mode */
624  break;
625  case 'S':
626  hide_sensitive = true;
627  break;
628  case 's':
629  subject = optarg;
630  break;
631 #ifdef USE_DEBUG_PARSE_TEST
632  case 'T':
633  test_config = true;
634  break;
635 #endif
636  case 'v':
637  version++;
638  break;
639  case 'y': /* My special hack mode */
640  flags |= MUTT_CLI_SELECT;
641  break;
642  case 'Z':
644  break;
645  case 'z':
646  flags |= MUTT_CLI_IGNORE;
647  break;
648  default:
649  OptNoCurses = true;
650  if (usage())
651  goto main_ok; // TEST03: neomutt -9
652  else
653  goto main_curses;
654  }
655  }
656  }
657 
658  /* collapse remaining argv */
659  while (optind < argc)
660  argv[nargc++] = argv[optind++];
661  optind = 1;
662  argc = nargc;
663 
664  if (version > 0)
665  {
667  bool done;
668  if (version == 1)
669  done = print_version(stdout);
670  else
671  done = print_copyright();
672  OptNoCurses = true;
673  if (done)
674  goto main_ok; // TEST04: neomutt -v
675  else
676  goto main_curses;
677  }
678 
681 
682  cs = cs_new(500);
683  if (!cs)
684  goto main_curses;
685 
686  NeoMutt = neomutt_new(cs);
687  init_config(cs);
688  subjrx_init();
689  attach_init();
690  alternates_init();
691 
692 #ifdef USE_DEBUG_NOTIFY
694 #endif
695 
696  if (!get_user_info(cs))
697  goto main_exit;
698 
699 #ifdef USE_DEBUG_PARSE_TEST
700  if (test_config)
701  {
702  cs_str_initial_set(cs, "from", "rich@flatcap.org", NULL);
703  cs_str_reset(cs, "from", NULL);
704  myvar_set("my_var", "foo");
705  test_parse_set();
706  goto main_ok;
707  }
708 #endif
709 
710  reset_tilde(cs);
711 
712  if (dfile)
713  {
714  cs_str_initial_set(cs, "debug_file", dfile, NULL);
715  cs_str_reset(cs, "debug_file", NULL);
716  }
717 
718  if (dlevel)
719  {
720  short num = 0;
721  if ((mutt_str_atos(dlevel, &num) < 0) || (num < LL_MESSAGE) || (num >= LL_MAX))
722  {
723  mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
724  goto main_exit; // TEST07: neomutt -d xyz
725  }
726  cs_str_initial_set(cs, "debug_level", dlevel, NULL);
727  cs_str_reset(cs, "debug_level", NULL);
728  }
729 
730  mutt_log_prep();
731  if (dlevel)
732  mutt_log_start();
733 
735 
736  log_translation();
737 
738  if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
739  {
740  e = email_new();
741  e->env = mutt_env_new();
742 
743  struct ListNode *np = NULL;
744  STAILQ_FOREACH(np, &bcc_list, entries)
745  {
746  mutt_addrlist_parse(&e->env->bcc, np->data);
747  }
748 
749  STAILQ_FOREACH(np, &cc_list, entries)
750  {
751  mutt_addrlist_parse(&e->env->cc, np->data);
752  }
753 
754  mutt_list_free(&bcc_list);
755  mutt_list_free(&cc_list);
756  }
757 
758  /* Check for a batch send. */
759  if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
760  dump_variables || batch_mode)
761  {
762  OptNoCurses = true;
763  sendflags = SEND_BATCH;
766  }
767 
768  /* Check to make sure stdout is available in curses mode. */
769  if (!OptNoCurses && !isatty(1))
770  goto main_curses;
771 
772  /* Always create the mutt_windows because batch mode has some shared code
773  * paths that end up referencing them. */
774  rootwin_new();
775 
776  /* This must come before mutt_init() because curses needs to be started
777  * before calling the init_pair() function to set the color scheme. */
778  if (!OptNoCurses)
779  {
780  int crc = start_curses();
781  if (crc != 0)
782  goto main_curses; // TEST08: can't test -- fake term?
783 
784  /* check whether terminal status is supported (must follow curses init) */
786  rootwin_set_size(COLS, LINES);
787  }
788 
789  /* set defaults and read init files */
790  int rc2 = mutt_init(cs, flags & MUTT_CLI_NOSYSRC, &commands);
791  mutt_list_free(&commands);
792  if (rc2 != 0)
793  goto main_curses;
794 
796 
797  /* The command line overrides the config */
798  if (dlevel)
799  cs_str_reset(cs, "debug_level", NULL);
800  if (dfile)
801  cs_str_reset(cs, "debug_file", NULL);
802 
803  if (mutt_log_start() < 0)
804  {
805  mutt_perror("log file");
806  goto main_exit;
807  }
808 
809 #ifdef USE_NNTP
810  {
811  /* "$news_server" precedence: command line, config file, environment, system file */
812  if (!cli_nntp)
813  cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
814 
815  if (!cli_nntp)
816  cli_nntp = mutt_str_getenv("NNTPSERVER");
817 
818  char buf[1024] = { 0 };
819  if (!cli_nntp)
820  cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
821 
822  if (cli_nntp)
823  {
824  cs_str_initial_set(cs, "news_server", cli_nntp, NULL);
825  cs_str_reset(cs, "news_server", NULL);
826  }
827  }
828 #endif
829 
830  /* Initialize crypto backends. */
831  crypt_init();
832 
833  if (new_type)
834  {
835  struct Buffer err = mutt_buffer_make(0);
836  int r = cs_str_initial_set(cs, "mbox_type", new_type, &err);
837  if (CSR_RESULT(r) != CSR_SUCCESS)
838  {
839  mutt_error(err.data);
840  mutt_buffer_dealloc(&err);
841  goto main_curses;
842  }
843  cs_str_reset(cs, "mbox_type", NULL);
844  }
845 
846  if (!STAILQ_EMPTY(&queries))
847  {
848  rc = mutt_query_variables(&queries, one_liner);
849  goto main_curses;
850  }
851 
852  if (dump_variables)
853  {
855  if (hide_sensitive)
856  cdflags |= CS_DUMP_HIDE_SENSITIVE;
857  if (one_liner)
858  cdflags |= CS_DUMP_SHOW_DOCS;
859  dump_config(cs, cdflags, stdout);
860  goto main_ok; // TEST18: neomutt -D
861  }
862 
863  if (!STAILQ_EMPTY(&alias_queries))
864  {
865  rc = 0;
866  for (; optind < argc; optind++)
867  mutt_list_insert_tail(&alias_queries, mutt_str_dup(argv[optind]));
868  struct ListNode *np = NULL;
869  STAILQ_FOREACH(np, &alias_queries, entries)
870  {
871  struct AddressList *al = alias_lookup(np->data);
872  if (al)
873  {
874  /* output in machine-readable form */
875  mutt_addrlist_to_intl(al, NULL);
876  mutt_addrlist_write_file(al, stdout, 0, false);
877  }
878  else
879  {
880  rc = 1;
881  printf("%s\n", np->data); // TEST19: neomutt -A unknown
882  }
883  }
884  mutt_list_free(&alias_queries);
885  goto main_curses; // TEST20: neomutt -A alias
886  }
887 
888  if (!OptNoCurses)
889  {
891  clear();
895  }
896 
897 #ifdef USE_AUTOCRYPT
898  /* Initialize autocrypt after curses messages are working,
899  * because of the initial account setup screens. */
900  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
901  if (c_autocrypt)
902  mutt_autocrypt_init(!(sendflags & SEND_BATCH));
903 #endif
904 
905  /* Create the `$folder` directory if it doesn't exist. */
906  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
907  if (!OptNoCurses && c_folder)
908  {
909  struct stat st = { 0 };
910  struct Buffer *fpath = mutt_buffer_pool_get();
911 
912  mutt_buffer_strcpy(fpath, c_folder);
914  bool skip = false;
915 #ifdef USE_IMAP
916  /* we're not connected yet - skip mail folder creation */
917  skip |= (imap_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_IMAP);
918 #endif
919 #ifdef USE_POP
920  skip |= (pop_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_POP);
921 #endif
922 #ifdef USE_NNTP
923  skip |= (nntp_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_NNTP);
924 #endif
925  if (!skip && (stat(mutt_buffer_string(fpath), &st) == -1) && (errno == ENOENT))
926  {
927  char msg2[256];
928  snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
929  if (mutt_yesorno(msg2, MUTT_YES) == MUTT_YES)
930  {
931  if ((mkdir(mutt_buffer_string(fpath), 0700) == -1) && (errno != EEXIST))
932  mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
933  }
934  }
935  mutt_buffer_pool_release(&fpath);
936  }
937 
938  if (batch_mode)
939  {
940  goto main_ok; // TEST22: neomutt -B
941  }
942 
946 
947  if (sendflags & SEND_POSTPONED)
948  {
949  if (!OptNoCurses)
950  mutt_flushinp();
951  if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
952  rc = 0;
953  // TEST23: neomutt -p (postponed message, cancel)
954  // TEST24: neomutt -p (no postponed message)
955  log_queue_empty();
956  repeat_error = true;
957  goto main_curses;
958  }
959  else if (subject || e || draft_file || include_file ||
960  !STAILQ_EMPTY(&attach) || (optind < argc))
961  {
962  FILE *fp_in = NULL;
963  FILE *fp_out = NULL;
964  char *infile = NULL;
965  char *bodytext = NULL;
966  const char *bodyfile = NULL;
967  int rv = 0;
968 
969  if (!OptNoCurses)
970  mutt_flushinp();
971 
972  if (!e)
973  e = email_new();
974  if (!e->env)
975  e->env = mutt_env_new();
976 
977  for (i = optind; i < argc; i++)
978  {
979  if (url_check_scheme(argv[i]) == U_MAILTO)
980  {
981  if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
982  {
983  mutt_error(_("Failed to parse mailto: link"));
984  email_free(&e);
985  goto main_curses; // TEST25: neomutt mailto:?
986  }
987  }
988  else
989  mutt_addrlist_parse(&e->env->to, argv[i]);
990  }
991 
992  const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
993  if (!draft_file && c_auto_edit && TAILQ_EMPTY(&e->env->to) &&
994  TAILQ_EMPTY(&e->env->cc))
995  {
996  mutt_error(_("No recipients specified"));
997  email_free(&e);
998  goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
999  }
1000 
1001  if (subject)
1002  e->env->subject = mutt_str_dup(subject);
1003 
1004  if (draft_file)
1005  {
1006  infile = draft_file;
1007  include_file = NULL;
1008  }
1009  else if (include_file)
1010  infile = include_file;
1011  else
1012  edit_infile = false;
1013 
1014  if (infile || bodytext)
1015  {
1016  /* Prepare fp_in and expanded_infile. */
1017  if (infile)
1018  {
1019  if (mutt_str_equal("-", infile))
1020  {
1021  if (edit_infile)
1022  {
1023  mutt_error(_("Can't use -E flag with stdin"));
1024  email_free(&e);
1025  goto main_curses; // TEST27: neomutt -E -H -
1026  }
1027  fp_in = stdin;
1028  }
1029  else
1030  {
1031  mutt_buffer_strcpy(&expanded_infile, infile);
1032  mutt_buffer_expand_path(&expanded_infile);
1033  fp_in = fopen(mutt_buffer_string(&expanded_infile), "r");
1034  if (!fp_in)
1035  {
1036  mutt_perror(mutt_buffer_string(&expanded_infile));
1037  email_free(&e);
1038  goto main_curses; // TEST28: neomutt -E -H missing
1039  }
1040  }
1041  }
1042 
1043  /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1044  * Note: stdin is always copied to a tempfile, ensuring draft_file
1045  * can stat and get the correct st_size below. */
1046  if (!edit_infile)
1047  {
1048  mutt_buffer_mktemp(&tempfile);
1049 
1050  fp_out = mutt_file_fopen(mutt_buffer_string(&tempfile), "w");
1051  if (!fp_out)
1052  {
1053  mutt_file_fclose(&fp_in);
1054  mutt_perror(mutt_buffer_string(&tempfile));
1055  email_free(&e);
1056  goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1057  }
1058  if (fp_in)
1059  {
1060  mutt_file_copy_stream(fp_in, fp_out);
1061  if (fp_in != stdin)
1062  mutt_file_fclose(&fp_in);
1063  }
1064  else if (bodytext)
1065  fputs(bodytext, fp_out);
1066  mutt_file_fclose(&fp_out);
1067 
1068  fp_in = fopen(mutt_buffer_string(&tempfile), "r");
1069  if (!fp_in)
1070  {
1071  mutt_perror(mutt_buffer_string(&tempfile));
1072  email_free(&e);
1073  goto main_curses; // TEST30: can't test
1074  }
1075  }
1076  /* If editing the infile, keep it around afterwards so
1077  * it doesn't get unlinked, and we can rebuild the draft_file */
1078  else
1079  sendflags |= SEND_NO_FREE_HEADER;
1080 
1081  /* Parse the draft_file into the full Email/Body structure.
1082  * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1083  * our e->body. */
1084  if (draft_file)
1085  {
1086  struct Envelope *opts_env = e->env;
1087  struct stat st = { 0 };
1088 
1089  sendflags |= SEND_DRAFT_FILE;
1090 
1091  /* Set up a tmp Email with just enough information so that
1092  * mutt_prepare_template() can parse the message in fp_in. */
1093  struct Email *e_tmp = email_new();
1094  e_tmp->offset = 0;
1095  e_tmp->body = mutt_body_new();
1096  if (fstat(fileno(fp_in), &st) != 0)
1097  {
1098  mutt_perror(draft_file);
1099  email_free(&e);
1100  email_free(&e_tmp);
1101  goto main_curses; // TEST31: can't test
1102  }
1103  e_tmp->body->length = st.st_size;
1104 
1105  if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1106  {
1107  mutt_error(_("Can't parse message template: %s"), draft_file);
1108  email_free(&e);
1109  email_free(&e_tmp);
1110  goto main_curses;
1111  }
1112 
1113  /* Scan for neomutt header to set `$resume_draft_files` */
1114  struct ListNode *np = NULL, *tmp = NULL;
1115  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1116  {
1117  if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1118  {
1119  const bool c_resume_edited_draft_files =
1120  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 */
1185  log_queue_empty();
1186  if (ErrorBufMessage)
1187  mutt_message("%s", ErrorBuf);
1188 
1189  if (edit_infile)
1190  {
1191  if (include_file)
1192  e->body->unlink = false;
1193  else 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 =
1221  cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1223  fp_out, e->env, e->body, MUTT_WRITE_HEADER_POSTPONE, false,
1224  c_crypt_protected_headers_read && mutt_should_hide_protected_subject(e),
1225  NeoMutt->sub);
1226  const bool c_resume_edited_draft_files =
1227  cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1228  if (c_resume_edited_draft_files)
1229  fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1230  fputc('\n', fp_out);
1231  if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1232  {
1233  mutt_file_fclose(&fp_out);
1234  email_free(&e);
1235  goto main_curses; // TEST35: can't test
1236  }
1237  mutt_file_fclose(&fp_out);
1238  }
1239 
1240  email_free(&e);
1241  }
1242 
1243  /* !edit_infile && draft_file will leave the tempfile around */
1244  if (!mutt_buffer_is_empty(&tempfile))
1245  unlink(mutt_buffer_string(&tempfile));
1246 
1247  rootwin_free();
1248 
1249  if (rv != 0)
1250  goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1251  }
1252  else if (sendflags & SEND_BATCH)
1253  {
1254  /* This guards against invoking `neomutt < /dev/null` and accidentally
1255  * sending an email due to a my_hdr or other setting. */
1256  mutt_error(_("No recipients specified"));
1257  goto main_curses;
1258  }
1259  else
1260  {
1261  if (flags & MUTT_CLI_MAILBOX)
1262  {
1263 #ifdef USE_IMAP
1264  const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1265  cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1266 #endif
1267  if (mutt_mailbox_check(NULL, 0) == 0)
1268  {
1269  mutt_message(_("No mailbox with new mail"));
1270  goto main_curses; // TEST37: neomutt -Z (no new mail)
1271  }
1272  mutt_buffer_reset(&folder);
1273  mutt_mailbox_next(NULL, &folder);
1274 #ifdef USE_IMAP
1275  cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1276 #endif
1277  }
1278  else if (flags & MUTT_CLI_SELECT)
1279  {
1280 #ifdef USE_NNTP
1281  if (flags & MUTT_CLI_NEWS)
1282  {
1283  const char *const c_news_server =
1284  cs_subset_string(NeoMutt->sub, "news_server");
1285  OptNews = true;
1287  c_news_server, false);
1288  if (!CurrentNewsSrv)
1289  goto main_curses; // TEST38: neomutt -G (unset news_server)
1290  }
1291  else
1292 #endif
1293  if (TAILQ_EMPTY(&NeoMutt->accounts))
1294  {
1295  mutt_error(_("No incoming mailboxes defined"));
1296  goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1297  }
1298  mutt_buffer_reset(&folder);
1300  ctx_mailbox(Context), NULL, NULL);
1301  if (mutt_buffer_is_empty(&folder))
1302  {
1303  goto main_ok; // TEST40: neomutt -y (quit selection)
1304  }
1305  }
1306 
1307  if (mutt_buffer_is_empty(&folder))
1308  {
1309  const char *const c_spool_file =
1310  cs_subset_string(NeoMutt->sub, "spool_file");
1311  if (c_spool_file)
1312  {
1313  // Check if `$spool_file` corresponds a mailboxes' description.
1314  struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1315  if (m_desc)
1316  mutt_buffer_strcpy(&folder, m_desc->realpath);
1317  else
1318  mutt_buffer_strcpy(&folder, c_spool_file);
1319  }
1320  else if (c_folder)
1321  mutt_buffer_strcpy(&folder, c_folder);
1322  /* else no folder */
1323  }
1324 
1325 #ifdef USE_NNTP
1326  if (OptNews)
1327  {
1328  OptNews = false;
1329  mutt_buffer_alloc(&folder, PATH_MAX);
1330  nntp_expand_path(folder.data, folder.dsize, &CurrentNewsSrv->conn->account);
1331  }
1332  else
1333 #endif
1334  mutt_buffer_expand_path(&folder);
1335 
1338 
1339  if (flags & MUTT_CLI_IGNORE)
1340  {
1341  /* check to see if there are any messages in the folder */
1342  switch (mx_path_is_empty(mutt_buffer_string(&folder)))
1343  {
1344  case -1:
1345  mutt_perror(mutt_buffer_string(&folder));
1346  goto main_curses; // TEST41: neomutt -z -f missing
1347  case 1:
1348  mutt_error(_("Mailbox is empty"));
1349  goto main_curses; // TEST42: neomutt -z -f /dev/null
1350  }
1351  }
1352 
1353  mutt_folder_hook(mutt_buffer_string(&folder), NULL);
1355  mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1357 
1358  repeat_error = true;
1359  struct Mailbox *m = mx_resolve(mutt_buffer_string(&folder));
1360  const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1361  if (!mx_mbox_open(m, ((flags & MUTT_CLI_RO) || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1362  {
1363  if (m->account)
1365 
1366  mailbox_free(&m);
1367  mutt_error(_("Unable to open mailbox %s"), mutt_buffer_string(&folder));
1368  repeat_error = false;
1369  }
1370  if (m || !explicit_folder)
1371  {
1372  struct MuttWindow *dlg = index_pager_init();
1373  dialog_push(dlg);
1374 
1375  struct EventMailbox ev_m = { m };
1376  mutt_debug(LL_NOTIFY, "NT_MAILBOX_SWITCH: %p\n", m);
1378 
1379  m = mutt_index_menu(dlg, m);
1380  if (m && (m->flags == MB_HIDDEN))
1381  mailbox_free(&m);
1382 
1383  dialog_pop();
1384  mutt_window_free(&dlg);
1385  log_queue_empty();
1386  repeat_error = false;
1387  }
1388 #ifdef USE_IMAP
1389  imap_logout_all();
1390 #endif
1391 #ifdef USE_SASL
1392  mutt_sasl_done();
1393 #endif
1394 #ifdef USE_AUTOCRYPT
1396 #endif
1397  // TEST43: neomutt (no change to mailbox)
1398  // TEST44: neomutt (change mailbox)
1399  }
1400 
1401 main_ok:
1402  rc = 0;
1403 main_curses:
1404  mutt_endwin();
1406  /* Repeat the last message to the user */
1407  if (repeat_error && ErrorBufMessage)
1408  puts(ErrorBuf);
1409 main_exit:
1411  mutt_buffer_dealloc(&folder);
1412  mutt_buffer_dealloc(&expanded_infile);
1413  mutt_buffer_dealloc(&tempfile);
1414  mutt_list_free(&queries);
1416  rootwin_free();
1421  menu_cleanup();
1422  crypt_cleanup();
1423  mutt_opts_free();
1424  subjrx_free();
1425  attach_free();
1426  alternates_free();
1427  mutt_keys_free();
1429  mutt_prex_free();
1431  cs_free(&cs);
1433  log_queue_empty();
1434  mutt_log_stop();
1435  return rc;
1436 }
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:282
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:141
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:98
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:1252
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: browser.c:158
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:37
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: browser.h:39
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:81
struct Mailbox * ctx_mailbox(struct Context *ctx)
Wrapper to get the mailbox in a Context, or NULL.
Definition: context.c:444
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1104
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:143
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:673
void test_parse_set(void)
Test the config parsing.
Definition: parse_test.c:39
int debug_all_observer(struct NotifyCallback *nc)
Definition: notify.c:318
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:1044
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1408
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:313
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
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:271
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
Definition: file.c:1389
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
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:441
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:127
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:400
#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:2709
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe() -.
Definition: pop.c:1165
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2402
int main_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: keymap.c:863
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:321
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:862
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:528
#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:564
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:1067
void mutt_opts_free(void)
Clean up before quitting.
Definition: init.c:643
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:769
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1731
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: keymap.c:841
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:326
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition: logging.c:314
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:348
@ 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:165
@ NT_MAILBOX_SWITCH
Current Mailbox has changed.
Definition: mailbox.h:182
#define MB_HIDDEN
Definition: mailbox.h:38
@ MUTT_POP
'POP3' Mailbox type
Definition: mailbox.h:55
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:52
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:53
#define MUTT_CLI_SELECT
-y Start with a list of all mailboxes
Definition: main.c:220
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition: main.c:376
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:214
static void log_translation(void)
Log the translation being used.
Definition: main.c:445
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:217
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:230
static bool usage(void)
Display NeoMutt command line.
Definition: main.c:267
static int start_curses(void)
Start the Curses UI.
Definition: main.c:344
static bool get_user_info(struct ConfigSet *cs)
Find the user's name, home and shell.
Definition: main.c:404
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:219
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:215
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:216
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:222
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:218
#define FREE(x)
Definition: memory.h:40
void menu_cleanup(void)
Free the saved Menu searches.
Definition: menu.c:109
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:904
int mutt_str_atos(const char *str, short *dst)
Convert ASCII string to a short.
Definition: string.c:222
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
#define PATH_MAX
Definition: mutt.h:40
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1285
void mutt_curses_set_color_by_id(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:52
char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:57
bool ErrorBufMessage
true if the last message was an error
Definition: mutt_globals.h:48
char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:56
char ErrorBuf[256]
Copy of the last error message.
Definition: mutt_globals.h:49
struct ListHead Muttrc
List of config files to read.
Definition: mutt_globals.h:68
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:222
int mutt_log_start(void)
Enable file logging.
Definition: mutt_logging.c:284
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:212
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
Incoming folders completion routine.
Definition: mutt_mailbox.c:384
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:162
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:200
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:1250
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:1741
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:63
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:60
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:50
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:559
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1017
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:78
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:48
@ NT_ALL
Register for all notifications.
Definition: notify_type.h:33
@ NT_GLOBAL
Not object-related, NotifyGlobal.
Definition: notify_type.h:45
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 *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1655
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:367
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:182
#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:782
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:1557
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:2110
#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:1093
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:1251
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:35
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:66
LOFF_T length
length (in bytes) of attachment
Definition: body.h:52
struct Body * next
next attachment in the list
Definition: body.h:70
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 "current" mailbox.
Definition: context.h:38
struct Mailbox * mailbox
Current Mailbox.
Definition: context.h:49
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:55
struct ListHead userhdrs
user defined headers
Definition: envelope.h:85
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:59
char * subject
Email's subject.
Definition: envelope.h:68
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:60
An Event that happened to a Mailbox.
Definition: mailbox.h:191
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
A mailbox.
Definition: mailbox.h:82
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:131
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
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:527
bool print_version(FILE *fp)
Print system and compile info to a file.
Definition: version.c:403