NeoMutt  2019-11-11
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/mutt.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/conn.h"
#include "mutt.h"
#include "alias.h"
#include "browser.h"
#include "color.h"
#include "context.h"
#include "curs_lib.h"
#include "globals.h"
#include "hook.h"
#include "index.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_commands.h"
#include "mutt_curses.h"
#include "mutt_history.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "myvar.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "protos.h"
#include "send.h"
#include "sendlib.h"
#include "terminal.h"
#include "version.h"
#include <libintl.h>
#include "sidebar.h"
#include "imap/imap.h"
#include "nntp/nntp.h"
#include "autocrypt/autocrypt.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 test_parse_set (void)
 Test the config parsing. More...
 
static void reset_tilde (struct ConfigSet *cs)
 Temporary measure. More...
 
void mutt_exit (int code)
 Leave NeoMutt NOW. More...
 
static void usage (void)
 Display NeoMutt command line. More...
 
static int start_curses (void)
 Start the curses or slang UI. More...
 
static void init_locale (void)
 Initialise the Locale/NLS settings. More...
 
bool get_user_info (struct ConfigSet *cs)
 Find the user's name, home and shell. More...
 
int main (int argc, char *argv[], char *envp[])
 Start NeoMutt. More...
 

Variables

bool C_ResumeEditedDraftFiles
 Config: Resume editing previously saved draft files. More...
 

Detailed Description

Command line processing.

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

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 32 of file main.c.

◆ GNULIB_defined_setlocale

#define GNULIB_defined_setlocale

Definition at line 33 of file main.c.

◆ MUTT_CLI_NO_FLAGS

#define MUTT_CLI_NO_FLAGS   0

No flags are set.

Definition at line 103 of file main.c.

◆ MUTT_CLI_IGNORE

#define MUTT_CLI_IGNORE   (1 << 0)

-z Open first mailbox if it has mail

Definition at line 104 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 105 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 106 of file main.c.

◆ MUTT_CLI_RO

#define MUTT_CLI_RO   (1 << 3)

-R Open mailbox in read-only mode

Definition at line 107 of file main.c.

◆ MUTT_CLI_SELECT

#define MUTT_CLI_SELECT   (1 << 4)

-y Start with a list of all mailboxes

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

Typedef Documentation

◆ CliFlags

typedef uint8_t CliFlags

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

Definition at line 102 of file main.c.

Function Documentation

◆ test_parse_set()

static void test_parse_set ( void  )
static

Test the config parsing.

Definition at line 117 of file main.c.

118 {
119  const char *vars[] = {
120  "from", // ADDRESS
121  "beep", // BOOL
122  "ispell", // COMMAND
123  "mbox_type", // MAGIC
124  "to_chars", // MBTABLE
125  "net_inc", // NUMBER
126  "signature", // PATH
127  "print", // QUAD
128  "mask", // REGEX
129  "sort", // SORT
130  "attribution", // STRING
131  "zzz", // UNKNOWN
132  "my_var", // MY_VAR
133  };
134 
135  const char *commands[] = {
136  "set",
137  "toggle",
138  "reset",
139  "unset",
140  };
141 
142  const char *tests[] = {
143  "%s %s", "%s %s=42", "%s %s?", "%s ?%s", "%s ?%s=42",
144  "%s ?%s?", "%s no%s", "%s no%s=42", "%s no%s?", "%s inv%s",
145  "%s inv%s=42", "%s inv%s?", "%s &%s", "%s &%s=42", "%s &%s?",
146  };
147 
148  struct Buffer tmp = mutt_buffer_make(256);
149  struct Buffer err = mutt_buffer_make(256);
150  char line[64];
151 
152  for (size_t v = 0; v < mutt_array_size(vars); v++)
153  {
154  // printf("--------------------------------------------------------------------------------\n");
155  // printf("VARIABLE %s\n", vars[v]);
156  for (size_t c = 0; c < mutt_array_size(commands); c++)
157  {
158  // printf("----------------------------------------\n");
159  // printf("COMMAND %s\n", commands[c]);
160  for (size_t t = 0; t < mutt_array_size(tests); t++)
161  {
162  mutt_buffer_reset(&tmp);
163  mutt_buffer_reset(&err);
164 
165  snprintf(line, sizeof(line), tests[t], commands[c], vars[v]);
166  printf("%-26s", line);
167  enum CommandResult rc = mutt_parse_rc_line(line, &tmp, &err);
168  printf("%2d %s\n", rc, err.data);
169  }
170  printf("\n");
171  }
172  // printf("\n");
173  }
174 
175  mutt_buffer_dealloc(&tmp);
176  mutt_buffer_dealloc(&err);
177 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:33
static const struct TestValue tests[]
Definition: mutt_str_atoi.c:36
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
#define mutt_array_size(x)
Definition: memory.h:33
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
const char * line
Definition: common.c:36
char * data
Pointer to data.
Definition: buffer.h:35
enum CommandResult mutt_parse_rc_line(char *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:3232
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ reset_tilde()

static void reset_tilde ( struct ConfigSet cs)
static

Temporary measure.

Definition at line 182 of file main.c.

183 {
184  static const char *names[] = {
185  "alias_file", "certificate_file", "debug_file",
186  "folder", "history_file", "mbox",
187  "newsrc", "news_cache_dir", "postponed",
188  "record", "signature",
189  };
190 
191  struct Buffer value = mutt_buffer_make(256);
192  for (size_t i = 0; i < mutt_array_size(names); i++)
193  {
194  struct HashElem *he = cs_get_elem(cs, names[i]);
195  if (!he)
196  continue;
197  mutt_buffer_reset(&value);
198  cs_he_initial_get(cs, he, &value);
199  mutt_expand_path(value.data, value.dsize);
200  cs_he_initial_set(cs, he, value.data, NULL);
201  cs_he_reset(cs, he, NULL);
202  }
203  mutt_buffer_dealloc(&value);
204 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
#define mutt_array_size(x)
Definition: memory.h:33
size_t dsize
Length of data.
Definition: buffer.h:37
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
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:375
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition: set.c:216
char * data
Pointer to data.
Definition: buffer.h:35
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:513
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:446
The item stored in a Hash Table.
Definition: hash.h:42
+ 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 210 of file main.c.

211 {
212  clear();
213  refresh();
214  mutt_endwin();
215  exit(code);
216 }
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:544
static const char clear[]
+ Here is the caller graph for this function:

◆ usage()

static void usage ( void  )
static

Display NeoMutt command line.

Definition at line 222 of file main.c.

223 {
224  puts(mutt_make_version());
225 
226  /* L10N: Try to limit to 80 columns */
227  puts(_("usage:\n"
228  " neomutt [-Enx] [-e <command>] [-F <config>] [-H <draft>] [-i <include>]\n"
229  " [-b <address>] [-c <address>] [-s <subject>] [-a <file> [...] --]\n"
230  " <address> [...]\n"
231  " neomutt [-nx] [-e <command>] [-F <config>] [-b <address>] [-c <address>]\n"
232  " [-s <subject>] [-a <file> [...] --] <address> [...] < message\n"
233  " neomutt [-nRy] [-e <command>] [-F <config>] [-f <mailbox>] [-m <type>]\n"
234  " neomutt [-n] [-e <command>] [-F <config>] -A <alias>\n"
235  " neomutt [-n] [-e <command>] [-F <config>] -B\n"
236  " neomutt [-n] [-e <command>] [-F <config>] -D [-S]\n"
237  " neomutt [-n] [-e <command>] [-F <config>] -d <level> -l <file>\n"
238  " neomutt [-n] [-e <command>] [-F <config>] -G\n"
239  " neomutt [-n] [-e <command>] [-F <config>] -g <server>\n"
240  " neomutt [-n] [-e <command>] [-F <config>] -p\n"
241  " neomutt [-n] [-e <command>] [-F <config>] -Q <variable>\n"
242  " neomutt [-n] [-e <command>] [-F <config>] -Z\n"
243  " neomutt [-n] [-e <command>] [-F <config>] -z [-f <mailbox>]\n"
244  " neomutt -v[v]\n"));
245 
246  /* L10N: Try to limit to 80 columns. If more space is needed add an indented line */
247  puts(_("options:\n"
248  " -- Special argument forces NeoMutt to stop option parsing and treat\n"
249  " remaining arguments as addresses even if they start with a dash\n"
250  " -A <alias> Print an expanded version of the given alias to stdout and exit\n"
251  " -a <file> Attach one or more files to a message (must be the last option)\n"
252  " Add any addresses after the '--' argument\n"
253  " -B Run in batch mode (do not start the ncurses UI)\n"
254  " -b <address> Specify a blind carbon copy (Bcc) recipient\n"
255  " -c <address> Specify a carbon copy (Cc) recipient\n"
256  " -D Dump all config variables as 'name=value' pairs to stdout\n"
257  " -D -S Like -D, but hide the value of sensitive variables\n"
258  " -d <level> Log debugging output to a file (default is \"~/.neomuttdebug0\")\n"
259  " The level can range from 1-5 and affects verbosity\n"
260  " -E Edit draft (-H) or include (-i) file during message composition\n"
261  " -e <command> Specify a command to be run after reading the config files\n"
262  " -F <config> Specify an alternative initialization file to read\n"
263  " -f <mailbox> Specify a mailbox (as defined with 'mailboxes' command) to load\n"
264  " -G Start NeoMutt with a listing of subscribed newsgroups\n"
265  " -g <server> Like -G, but start at specified news server\n"
266  " -H <draft> Specify a draft file with header and body for message composing\n"
267  " -h Print this help message and exit\n"
268  " -i <include> Specify an include file to be embedded in the body of a message\n"
269  " -l <file> Specify a file for debugging output (default \"~/.neomuttdebug0\")\n"
270  " -m <type> Specify a default mailbox format type for newly created folders\n"
271  " The type is either MH, MMDF, Maildir or mbox (case-insensitive)\n"
272  " -n Do not read the system-wide configuration file\n"
273  " -p Resume a prior postponed message, if any\n"
274  " -Q <variable> Query a configuration variable and print its value to stdout\n"
275  " (after the config has been read and any commands executed)\n"
276  " -R Open mailbox in read-only mode\n"
277  " -s <subject> Specify a subject (must be enclosed in quotes if it has spaces)\n"
278  " -v Print the NeoMutt version and compile-time definitions and exit\n"
279  " -vv Print the NeoMutt license and copyright information and exit\n"
280  " -x Simulate the mailx(1) send mode\n"
281  " -y Start NeoMutt with a listing of all defined mailboxes\n"
282  " -Z Open the first mailbox with new message or exit immediately with\n"
283  " exit code 1 if none is found in all defined mailboxes\n"
284  " -z Open the first or specified (-f) mailbox if it holds any message\n"
285  " or exit immediately with exit code 1 otherwise"));
286 }
#define _(a)
Definition: message.h:28
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1560
+ 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 or slang UI.

Return values
0Success
1Failure

Definition at line 294 of file main.c.

295 {
296  km_init(); /* must come before mutt_init */
297 
298 #ifdef USE_SLANG_CURSES
299  SLtt_Ignore_Beep = 1; /* don't do that #*$@^! annoying visual beep! */
300  SLsmg_Display_Eight_Bit = 128; /* characters above this are printable */
301  SLtt_set_color(0, NULL, "default", "default");
302 #if SLANG_VERSION >= 20000
303  SLutf8_enable(-1);
304 #endif
305 #else
306  /* should come before initscr() so that ncurses 4.2 doesn't try to install
307  * its own SIGWINCH handler */
309 #endif
310  if (!initscr())
311  {
312  mutt_error(_("Error initializing terminal"));
313  return 1;
314  }
315  /* slang requires the signal handlers to be set after initializing */
318  keypad(stdscr, true);
319  cbreak();
320  noecho();
321  nonl();
322 #ifdef HAVE_TYPEAHEAD
323  typeahead(-1); /* simulate smooth scrolling */
324 #endif
325 #ifdef HAVE_META
326  meta(stdscr, true);
327 #endif
329  /* Now that curses is set up, we drop back to normal screen mode.
330  * This simplifies displaying error messages to the user.
331  * The first call to refresh() will swap us back to curses screen mode. */
332  endwin();
333  return 0;
334 }
#define _(a)
Definition: message.h:28
void km_init(void)
Initialise all the menu keybindings.
Definition: keymap.c:927
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: keymap.c:897
void mutt_signal_init(void)
Initialise the signal handling.
Definition: mutt_signal.c:130
struct Colors * mutt_colors_new(void)
Create new colours.
Definition: color.c:372
Definition: color.h:130
#define mutt_error(...)
Definition: logging.h:84
+ 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 339 of file main.c.

340 {
341  setlocale(LC_ALL, "");
342 
343 #ifdef ENABLE_NLS
344  const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
345  if (domdir)
346  bindtextdomain(PACKAGE, domdir);
347  else
348  bindtextdomain(PACKAGE, MUTTLOCALEDIR);
349  textdomain(PACKAGE);
350 #endif
351 #ifndef LOCALES_HACK
352  /* Do we have a locale definition? */
353  if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
354  {
355  OptLocales = true;
356  }
357 #endif
358 }
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:1048
bool OptLocales
(pseudo) set if user has valid locale definition
Definition: mbyte.c:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_user_info()

bool get_user_info ( struct ConfigSet cs)

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 367 of file main.c.

368 {
371 
372  const char *shell = mutt_str_getenv("SHELL");
373  if (shell)
374  cs_str_initial_set(cs, "shell", shell, NULL);
375 
376  /* Get some information about the user */
377  struct passwd *pw = getpwuid(getuid());
378  if (pw)
379  {
380  if (!Username)
381  Username = mutt_str_strdup(pw->pw_name);
382  if (!HomeDir)
383  HomeDir = mutt_str_strdup(pw->pw_dir);
384  if (!shell)
385  cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
386  }
387 
388  if (!Username)
389  {
390  mutt_error(_("unable to determine username"));
391  return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
392  }
393 
394  if (!HomeDir)
395  {
396  mutt_error(_("unable to determine home directory"));
397  return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
398  }
399 
400  cs_str_reset(cs, "shell", NULL);
401  return true;
402 }
WHERE char * Username
User&#39;s login name.
Definition: globals.h:54
#define _(a)
Definition: message.h:28
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:1048
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:487
WHERE char * HomeDir
User&#39;s home directory.
Definition: globals.h:51
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
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:423
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:84
+ 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 412 of file main.c.

413 {
414  char *subject = NULL;
415  char *include_file = NULL;
416  char *draft_file = NULL;
417  char *new_magic = NULL;
418  char *dlevel = NULL;
419  char *dfile = NULL;
420 #ifdef USE_NNTP
421  char *cli_nntp = NULL;
422 #endif
423  struct Email *e = NULL;
424  struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
425  struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
426  struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
427  struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
428  struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
429  struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
430  SendFlags sendflags = SEND_NO_FLAGS;
431  CliFlags flags = MUTT_CLI_NO_FLAGS;
432  int version = 0;
433  int i;
434  bool explicit_folder = false;
435  bool dump_variables = false;
436  bool hide_sensitive = false;
437  bool batch_mode = false;
438  bool edit_infile = false;
439  bool test_config = false;
440  extern char *optarg;
441  extern int optind;
442  int double_dash = argc, nargc = 1;
443  int rc = 1;
444  bool repeat_error = false;
445  struct Buffer folder = mutt_buffer_make(0);
446  struct Buffer expanded_infile = mutt_buffer_make(0);
447  struct Buffer tempfile = mutt_buffer_make(0);
448 
450 
451  /* sanity check against stupid administrators */
452  if (getegid() != getgid())
453  {
454  mutt_error("%s: I don't want to run with privileges!", argv[0]);
455  goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
456  }
457 
458  init_locale();
459 
460  int out = 0;
461  if (mutt_randbuf(&out, sizeof(out)) < 0)
462  goto main_exit; // TEST02: neomutt (as root on non-Linux OS, rename /dev/urandom)
463 
464  umask(077);
465 
466  mutt_envlist_init(envp);
467  for (optind = 1; optind < double_dash;)
468  {
469  /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
470  * encounters a non-option. That could be a file to attach
471  * (all non-options between -a and --) or it could be an address
472  * (which gets collapsed to the front of argv). */
473  for (; optind < argc; optind++)
474  {
475  if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
476  {
477  if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
478  double_dash = optind; /* quit outer loop after getopt */
479  break; /* drop through to getopt */
480  }
481 
482  /* non-option, either an attachment or address */
483  if (!STAILQ_EMPTY(&attach))
484  mutt_list_insert_tail(&attach, mutt_str_strdup(argv[optind]));
485  else
486  argv[nargc++] = argv[optind];
487  }
488 
489  /* USE_NNTP 'g:G' */
490  i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:i:hm:npQ:RSs:TvxyzZ");
491  if (i != EOF)
492  {
493  switch (i)
494  {
495  case 'A':
496  mutt_list_insert_tail(&alias_queries, mutt_str_strdup(optarg));
497  break;
498  case 'a':
499  mutt_list_insert_tail(&attach, mutt_str_strdup(optarg));
500  break;
501  case 'B':
502  batch_mode = true;
503  break;
504  case 'b':
505  mutt_list_insert_tail(&bcc_list, mutt_str_strdup(optarg));
506  break;
507  case 'c':
508  mutt_list_insert_tail(&cc_list, mutt_str_strdup(optarg));
509  break;
510  case 'D':
511  dump_variables = true;
512  break;
513  case 'd':
514  dlevel = optarg;
515  break;
516  case 'E':
517  edit_infile = true;
518  break;
519  case 'e':
520  mutt_list_insert_tail(&commands, mutt_str_strdup(optarg));
521  break;
522  case 'F':
523  mutt_list_insert_tail(&Muttrc, mutt_str_strdup(optarg));
524  break;
525  case 'f':
526  mutt_buffer_strcpy(&folder, optarg);
527  explicit_folder = true;
528  break;
529 #ifdef USE_NNTP
530  case 'g': /* Specify a news server */
531  cli_nntp = optarg;
532  /* fallthrough */
533  case 'G': /* List of newsgroups */
534  flags |= MUTT_CLI_SELECT | MUTT_CLI_NEWS;
535  break;
536 #endif
537  case 'H':
538  draft_file = optarg;
539  break;
540  case 'i':
541  include_file = optarg;
542  break;
543  case 'l':
544  dfile = optarg;
545  break;
546  case 'm':
547  new_magic = optarg;
548  break;
549  case 'n':
550  flags |= MUTT_CLI_NOSYSRC;
551  break;
552  case 'p':
553  sendflags |= SEND_POSTPONED;
554  break;
555  case 'Q':
556  mutt_list_insert_tail(&queries, mutt_str_strdup(optarg));
557  break;
558  case 'R':
559  flags |= MUTT_CLI_RO; /* read-only mode */
560  break;
561  case 'S':
562  hide_sensitive = true;
563  break;
564  case 's':
565  subject = optarg;
566  break;
567  case 'T':
568  test_config = true;
569  break;
570  case 'v':
571  version++;
572  break;
573  case 'x': /* mailx compatible send mode */
574  sendflags |= SEND_MAILX;
575  break;
576  case 'y': /* My special hack mode */
577  flags |= MUTT_CLI_SELECT;
578  break;
579  case 'Z':
581  break;
582  case 'z':
583  flags |= MUTT_CLI_IGNORE;
584  break;
585  default:
586  usage();
587  OptNoCurses = true;
588  goto main_ok; // TEST03: neomutt -9
589  }
590  }
591  }
592 
593  /* collapse remaining argv */
594  while (optind < argc)
595  argv[nargc++] = argv[optind++];
596  optind = 1;
597  argc = nargc;
598 
599  if (version > 0)
600  {
602  if (version == 1)
603  print_version(stdout);
604  else
605  print_copyright();
606  OptNoCurses = true;
607  goto main_ok; // TEST04: neomutt -v
608  }
609 
610  Config = init_config(500);
611  if (!Config)
612  goto main_curses;
614 
616 
617  if (!get_user_info(Config))
618  goto main_exit;
619 
620  if (test_config)
621  {
622  cs_str_initial_set(Config, "from", "rich@flatcap.org", NULL);
623  cs_str_reset(Config, "from", NULL);
624  myvar_set("my_var", "foo");
625  test_parse_set();
626  goto main_ok;
627  }
628 
630 
631  if (dfile)
632  {
633  cs_str_initial_set(Config, "debug_file", dfile, NULL);
634  cs_str_reset(Config, "debug_file", NULL);
635  }
636 
637  if (dlevel)
638  {
639  short num = 0;
640  if ((mutt_str_atos(dlevel, &num) < 0) || (num < LL_MESSAGE) || (num >= LL_MAX))
641  {
642  mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
643  goto main_exit; // TEST07: neomutt -d xyz
644  }
645  cs_str_initial_set(Config, "debug_level", dlevel, NULL);
646  cs_str_reset(Config, "debug_level", NULL);
647  }
648 
649  mutt_log_prep();
650  if (dlevel)
651  mutt_log_start();
652 
654 
655  if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
656  {
657  e = email_new();
658  e->env = mutt_env_new();
659 
660  struct ListNode *np = NULL;
661  STAILQ_FOREACH(np, &bcc_list, entries)
662  {
663  mutt_addrlist_parse(&e->env->bcc, np->data);
664  }
665 
666  STAILQ_FOREACH(np, &cc_list, entries)
667  {
668  mutt_addrlist_parse(&e->env->cc, np->data);
669  }
670 
671  mutt_list_free(&bcc_list);
672  mutt_list_free(&cc_list);
673  }
674 
675  /* Check for a batch send. */
676  if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
677  dump_variables || batch_mode)
678  {
679  OptNoCurses = true;
680  sendflags = SEND_BATCH;
683  }
684 
685  /* Always create the mutt_windows because batch mode has some shared code
686  * paths that end up referencing them. */
688 
689  /* This must come before mutt_init() because curses needs to be started
690  * before calling the init_pair() function to set the color scheme. */
691  if (!OptNoCurses)
692  {
693  int crc = start_curses();
694 
695  if (crc != 0)
696  goto main_curses; // TEST08: can't test -- fake term?
697 
698  /* check whether terminal status is supported (must follow curses init) */
701  }
702 
703  /* set defaults and read init files */
704  int rc2 = mutt_init(flags & MUTT_CLI_NOSYSRC, &commands);
705  mutt_list_free(&commands);
706  if (rc2 != 0)
707  goto main_curses;
708 
709  /* The command line overrides the config */
710  if (dlevel)
711  cs_str_reset(Config, "debug_level", NULL);
712  if (dfile)
713  cs_str_reset(Config, "debug_file", NULL);
714 
715  if (mutt_log_start() < 0)
716  {
717  mutt_perror("log file");
718  goto main_exit;
719  }
720 
721 #ifdef USE_NNTP
722  /* "$news_server" precedence: command line, config file, environment, system file */
723  if (cli_nntp)
724  cs_str_string_set(Config, "news_server", cli_nntp, NULL);
725  if (!C_NewsServer)
726  {
727  const char *env_nntp = mutt_str_getenv("NNTPSERVER");
728  cs_str_string_set(Config, "news_server", env_nntp, NULL);
729  }
730  if (!C_NewsServer)
731  {
732  char buf[1024];
733  char *server = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
734  cs_str_string_set(Config, "news_server", server, NULL);
735  }
736  if (C_NewsServer)
737  cs_str_initial_set(Config, "news_server", C_NewsServer, NULL);
738 #endif
739 
740  /* Initialize crypto backends. */
741  crypt_init();
742 
743  if (new_magic)
744  {
745  struct Buffer err = mutt_buffer_make(0);
746  int r = cs_str_initial_set(Config, "mbox_type", new_magic, &err);
747  if (CSR_RESULT(r) != CSR_SUCCESS)
748  {
749  mutt_error(err.data);
750  mutt_buffer_dealloc(&err);
751  goto main_curses;
752  }
753  cs_str_reset(Config, "mbox_type", NULL);
754  }
755 
756  if (!STAILQ_EMPTY(&queries))
757  {
758  rc = mutt_query_variables(&queries);
759  goto main_curses;
760  }
761 
762  if (dump_variables)
763  {
764  dump_config(Config, hide_sensitive ? CS_DUMP_HIDE_SENSITIVE : CS_DUMP_NO_FLAGS, stdout);
765  goto main_ok; // TEST18: neomutt -D
766  }
767 
768  if (!STAILQ_EMPTY(&alias_queries))
769  {
770  rc = 0;
771  for (; optind < argc; optind++)
772  mutt_list_insert_tail(&alias_queries, mutt_str_strdup(argv[optind]));
773  struct ListNode *np = NULL;
774  STAILQ_FOREACH(np, &alias_queries, entries)
775  {
776  struct AddressList *al = mutt_alias_lookup(np->data);
777  if (al)
778  {
779  /* output in machine-readable form */
780  mutt_addrlist_to_intl(al, NULL);
781  mutt_write_addrlist(al, stdout, 0, 0);
782  }
783  else
784  {
785  rc = 1;
786  printf("%s\n", np->data); // TEST19: neomutt -A unknown
787  }
788  }
789  mutt_list_free(&alias_queries);
790  goto main_curses; // TEST20: neomutt -A alias
791  }
792 
793  if (!OptNoCurses)
794  {
796  clear();
800  }
801 
802  /* Initialize autocrypt after curses messages are working,
803  * because of the initial account setup screens. */
804 #ifdef USE_AUTOCRYPT
805  if (C_Autocrypt)
806  mutt_autocrypt_init(!(sendflags & SEND_BATCH));
807 #endif
808 
809  /* Create the C_Folder directory if it doesn't exist. */
810  if (!OptNoCurses && C_Folder)
811  {
812  struct stat sb;
813  struct Buffer *fpath = mutt_buffer_pool_get();
814 
817  bool skip = false;
818 #ifdef USE_IMAP
819  /* we're not connected yet - skip mail folder creation */
820  skip |= (imap_path_probe(mutt_b2s(fpath), NULL) == MUTT_IMAP);
821 #endif
822 #ifdef USE_NNTP
823  skip |= (nntp_path_probe(mutt_b2s(fpath), NULL) == MUTT_NNTP);
824 #endif
825  if (!skip && (stat(mutt_b2s(fpath), &sb) == -1) && (errno == ENOENT))
826  {
827  char msg2[256];
828  snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), C_Folder);
829  if (mutt_yesorno(msg2, MUTT_YES) == MUTT_YES)
830  {
831  if ((mkdir(mutt_b2s(fpath), 0700) == -1) && (errno != EEXIST))
832  mutt_error(_("Can't create %s: %s"), C_Folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
833  }
834  }
835  mutt_buffer_pool_release(&fpath);
836  }
837 
838  if (batch_mode)
839  {
840  goto main_ok; // TEST22: neomutt -B
841  }
842 
847  if (Colors)
849 
850  if (sendflags & SEND_POSTPONED)
851  {
852  if (!OptNoCurses)
853  mutt_flushinp();
854  if (ci_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL) == 0)
855  rc = 0;
856  // TEST23: neomutt -p (postponed message, cancel)
857  // TEST24: neomutt -p (no postponed message)
858  log_queue_empty();
859  repeat_error = true;
860  goto main_curses;
861  }
862  else if (subject || e || sendflags || draft_file || include_file ||
863  !STAILQ_EMPTY(&attach) || (optind < argc))
864  {
865  FILE *fp_in = NULL;
866  FILE *fp_out = NULL;
867  char *infile = NULL;
868  char *bodytext = NULL;
869  const char *bodyfile = NULL;
870  int rv = 0;
871 
872  if (!OptNoCurses)
873  mutt_flushinp();
874 
875  if (!e)
876  e = email_new();
877  if (!e->env)
878  e->env = mutt_env_new();
879 
880  for (i = optind; i < argc; i++)
881  {
882  if (url_check_scheme(argv[i]) == U_MAILTO)
883  {
884  if (mutt_parse_mailto(e->env, &bodytext, argv[i]) < 0)
885  {
886  mutt_error(_("Failed to parse mailto: link"));
887  email_free(&e);
888  goto main_curses; // TEST25: neomutt mailto:
889  }
890  }
891  else
892  mutt_addrlist_parse(&e->env->to, argv[i]);
893  }
894 
895  if (!draft_file && C_Autoedit && TAILQ_EMPTY(&e->env->to) &&
896  TAILQ_EMPTY(&e->env->cc))
897  {
898  mutt_error(_("No recipients specified"));
899  email_free(&e);
900  goto main_curses; // TEST26: neomutt -s test (with autoedit=yes)
901  }
902 
903  if (subject)
904  e->env->subject = mutt_str_strdup(subject);
905 
906  if (draft_file)
907  {
908  infile = draft_file;
909  include_file = NULL;
910  }
911  else if (include_file)
912  infile = include_file;
913  else
914  edit_infile = false;
915 
916  if (infile || bodytext)
917  {
918  /* Prepare fp_in and expanded_infile. */
919  if (infile)
920  {
921  if (mutt_str_strcmp("-", infile) == 0)
922  {
923  if (edit_infile)
924  {
925  mutt_error(_("Can't use -E flag with stdin"));
926  email_free(&e);
927  goto main_curses; // TEST27: neomutt -E -H -
928  }
929  fp_in = stdin;
930  }
931  else
932  {
933  mutt_buffer_strcpy(&expanded_infile, infile);
934  mutt_buffer_expand_path(&expanded_infile);
935  fp_in = fopen(mutt_b2s(&expanded_infile), "r");
936  if (!fp_in)
937  {
938  mutt_perror(mutt_b2s(&expanded_infile));
939  email_free(&e);
940  goto main_curses; // TEST28: neomutt -E -H missing
941  }
942  }
943  }
944 
945  /* Copy input to a tempfile, and re-point fp_in to the tempfile.
946  * Note: stdin is always copied to a tempfile, ensuring draft_file
947  * can stat and get the correct st_size below. */
948  if (!edit_infile)
949  {
950  mutt_buffer_mktemp(&tempfile);
951 
952  fp_out = mutt_file_fopen(mutt_b2s(&tempfile), "w");
953  if (!fp_out)
954  {
955  mutt_file_fclose(&fp_in);
956  mutt_perror(mutt_b2s(&tempfile));
957  email_free(&e);
958  goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
959  }
960  if (fp_in)
961  {
962  mutt_file_copy_stream(fp_in, fp_out);
963  if (fp_in != stdin)
964  mutt_file_fclose(&fp_in);
965  }
966  else if (bodytext)
967  fputs(bodytext, fp_out);
968  mutt_file_fclose(&fp_out);
969 
970  fp_in = fopen(mutt_b2s(&tempfile), "r");
971  if (!fp_in)
972  {
973  mutt_perror(mutt_b2s(&tempfile));
974  email_free(&e);
975  goto main_curses; // TEST30: can't test
976  }
977  }
978  /* If editing the infile, keep it around afterwards so
979  * it doesn't get unlinked, and we can rebuild the draft_file */
980  else
981  sendflags |= SEND_NO_FREE_HEADER;
982 
983  /* Parse the draft_file into the full Email/Body structure.
984  * Set SEND_DRAFT_FILE so ci_send_message doesn't overwrite
985  * our e->content. */
986  if (draft_file)
987  {
988  struct Envelope *opts_env = e->env;
989  struct stat st;
990 
991  sendflags |= SEND_DRAFT_FILE;
992 
993  /* Set up a tmp Email with just enough information so that
994  * mutt_prepare_template() can parse the message in fp_in. */
995  struct Email *e_tmp = email_new();
996  e_tmp->offset = 0;
997  e_tmp->content = mutt_body_new();
998  if (fstat(fileno(fp_in), &st) != 0)
999  {
1000  mutt_perror(draft_file);
1001  email_free(&e);
1002  email_free(&e_tmp);
1003  goto main_curses; // TEST31: can't test
1004  }
1005  e_tmp->content->length = st.st_size;
1006 
1007  if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1008  {
1009  mutt_error(_("Can't parse message template: %s"), draft_file);
1010  email_free(&e);
1011  email_free(&e_tmp);
1012  goto main_curses;
1013  }
1014 
1015  /* Scan for neomutt header to set C_ResumeDraftFiles */
1016  struct ListNode *np = NULL, *tmp = NULL;
1017  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1018  {
1019  if (mutt_str_startswith(np->data, "X-Mutt-Resume-Draft:", CASE_IGNORE))
1020  {
1022  cs_str_native_set(Config, "resume_draft_files", true, NULL);
1023 
1024  STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1025  FREE(&np->data);
1026  FREE(&np);
1027  }
1028  }
1029 
1030  mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1031  mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1032  mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1033  if (opts_env->subject)
1034  mutt_str_replace(&e->env->subject, opts_env->subject);
1035 
1036  mutt_env_free(&opts_env);
1037  email_free(&e_tmp);
1038  }
1039  /* Editing the include_file: pass it directly in.
1040  * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1041  else if (edit_infile)
1042  bodyfile = mutt_b2s(&expanded_infile);
1043  /* For bodytext and unedited include_file: use the tempfile.
1044  */
1045  else
1046  bodyfile = mutt_b2s(&tempfile);
1047 
1048  mutt_file_fclose(&fp_in);
1049  }
1050 
1051  FREE(&bodytext);
1052 
1053  if (!STAILQ_EMPTY(&attach))
1054  {
1055  struct Body *b = e->content;
1056 
1057  while (b && b->next)
1058  b = b->next;
1059 
1060  struct ListNode *np = NULL;
1061  STAILQ_FOREACH(np, &attach, entries)
1062  {
1063  if (b)
1064  {
1065  b->next = mutt_make_file_attach(np->data);
1066  b = b->next;
1067  }
1068  else
1069  {
1070  b = mutt_make_file_attach(np->data);
1071  e->content = b;
1072  }
1073  if (!b)
1074  {
1075  mutt_error(_("%s: unable to attach file"), np->data);
1076  mutt_list_free(&attach);
1077  email_free(&e);
1078  goto main_curses; // TEST32: neomutt john@example.com -a missing
1079  }
1080  }
1081  mutt_list_free(&attach);
1082  }
1083 
1084  rv = ci_send_message(sendflags, e, bodyfile, NULL, NULL);
1085  /* We WANT the "Mail sent." and any possible, later error */
1086  log_queue_empty();
1087  if (ErrorBufMessage)
1088  mutt_message("%s", ErrorBuf);
1089 
1090  if (edit_infile)
1091  {
1092  if (include_file)
1093  e->content->unlink = false;
1094  else if (draft_file)
1095  {
1096  if (truncate(mutt_b2s(&expanded_infile), 0) == -1)
1097  {
1098  mutt_perror(mutt_b2s(&expanded_infile));
1099  email_free(&e);
1100  goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1101  }
1102  fp_out = mutt_file_fopen(mutt_b2s(&expanded_infile), "a");
1103  if (!fp_out)
1104  {
1105  mutt_perror(mutt_b2s(&expanded_infile));
1106  email_free(&e);
1107  goto main_curses; // TEST34: can't test
1108  }
1109 
1110  /* If the message was sent or postponed, these will already
1111  * have been done. */
1112  if (rv < 0)
1113  {
1114  if (e->content->next)
1117  mutt_prepare_envelope(e->env, false);
1118  mutt_env_to_intl(e->env, NULL, NULL);
1119  }
1120 
1122  fp_out, e->env, e->content, MUTT_WRITE_HEADER_POSTPONE, false,
1125  fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1126  fputc('\n', fp_out);
1127  if ((mutt_write_mime_body(e->content, fp_out) == -1))
1128  {
1129  mutt_file_fclose(&fp_out);
1130  email_free(&e);
1131  goto main_curses; // TEST35: can't test
1132  }
1133  mutt_file_fclose(&fp_out);
1134  }
1135 
1136  email_free(&e);
1137  }
1138 
1139  /* !edit_infile && draft_file will leave the tempfile around */
1140  if (!mutt_buffer_is_empty(&tempfile))
1141  unlink(mutt_b2s(&tempfile));
1142 
1144 
1145  if (rv != 0)
1146  goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1147  }
1148  else
1149  {
1150  if (flags & MUTT_CLI_MAILBOX)
1151  {
1152 #ifdef USE_IMAP
1153  bool passive = C_ImapPassive;
1154  C_ImapPassive = false;
1155 #endif
1156  if (mutt_mailbox_check(Context ? Context->mailbox : NULL, 0) == 0)
1157  {
1158  mutt_message(_("No mailbox with new mail"));
1159  goto main_curses; // TEST37: neomutt -Z (no new mail)
1160  }
1161  mutt_buffer_reset(&folder);
1162  mutt_mailbox_next_buffer(Context ? Context->mailbox : NULL, &folder);
1163 #ifdef USE_IMAP
1164  C_ImapPassive = passive;
1165 #endif
1166  }
1167  else if (flags & MUTT_CLI_SELECT)
1168  {
1169 #ifdef USE_NNTP
1170  if (flags & MUTT_CLI_NEWS)
1171  {
1172  OptNews = true;
1173  CurrentNewsSrv =
1175  if (!CurrentNewsSrv)
1176  goto main_curses; // TEST38: neomutt -G (unset news_server)
1177  }
1178  else
1179 #endif
1180  if (TAILQ_EMPTY(&NeoMutt->accounts))
1181  {
1182  mutt_error(_("No incoming mailboxes defined"));
1183  goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1184  }
1185  mutt_buffer_reset(&folder);
1187  if (mutt_buffer_is_empty(&folder))
1188  {
1189  goto main_ok; // TEST40: neomutt -y (quit selection)
1190  }
1191  }
1192 
1193  if (mutt_buffer_is_empty(&folder))
1194  {
1195  if (C_Spoolfile)
1196  {
1197  // Check if C_Spoolfile corresponds a mailboxes' description.
1198  struct Mailbox *m_desc = mailbox_find_name(C_Spoolfile);
1199  if (m_desc)
1200  mutt_buffer_strcpy(&folder, m_desc->realpath);
1201  else
1202  mutt_buffer_strcpy(&folder, C_Spoolfile);
1203  }
1204  else if (C_Folder)
1205  mutt_buffer_strcpy(&folder, C_Folder);
1206  /* else no folder */
1207  }
1208 
1209 #ifdef USE_NNTP
1210  if (OptNews)
1211  {
1212  OptNews = false;
1213  mutt_buffer_alloc(&folder, PATH_MAX);
1214  nntp_expand_path(folder.data, folder.dsize, &CurrentNewsSrv->conn->account);
1215  }
1216  else
1217 #endif
1218  mutt_buffer_expand_path(&folder);
1219 
1221  mutt_str_replace(&LastFolder, mutt_b2s(&folder));
1222 
1223  if (flags & MUTT_CLI_IGNORE)
1224  {
1225  /* check to see if there are any messages in the folder */
1226  switch (mx_check_empty(mutt_b2s(&folder)))
1227  {
1228  case -1:
1229  mutt_perror(mutt_b2s(&folder));
1230  goto main_curses; // TEST41: neomutt -z -f missing
1231  case 1:
1232  mutt_error(_("Mailbox is empty"));
1233  goto main_curses; // TEST42: neomutt -z -f /dev/null
1234  }
1235  }
1236 
1237  mutt_folder_hook(mutt_b2s(&folder), NULL);
1240 
1241  repeat_error = true;
1242  struct Mailbox *m = mx_path_resolve(mutt_b2s(&folder));
1244  if (!Context)
1245  {
1246  if (m->account)
1247  {
1249  mailbox_free(&m);
1250  m = NULL;
1251  }
1252  else
1253  mailbox_free(&m);
1254  }
1255  if (Context || !explicit_folder)
1256  {
1257 #ifdef USE_SIDEBAR
1259 #endif
1260  mutt_index_menu();
1261  ctx_free(&Context);
1262  }
1263 #ifdef USE_IMAP
1264  imap_logout_all();
1265 #endif
1266 #ifdef USE_SASL
1267  mutt_sasl_done();
1268 #endif
1269 #ifdef USE_AUTOCRYPT
1271 #endif
1272  // TEST43: neomutt (no change to mailbox)
1273  // TEST44: neomutt (change mailbox)
1276  }
1277 
1278 main_ok:
1279  rc = 0;
1280 main_curses:
1281  clear();
1282  refresh();
1283  mutt_endwin();
1286  /* Repeat the last message to the user */
1287  if (repeat_error && ErrorBufMessage)
1288  puts(ErrorBuf);
1289 main_exit:
1290  mutt_buffer_dealloc(&folder);
1291  mutt_buffer_dealloc(&expanded_infile);
1292  mutt_buffer_dealloc(&tempfile);
1293  mutt_list_free(&queries);
1299  mutt_opts_free();
1300  mutt_keys_free();
1303  cs_free(&Config);
1304  log_queue_empty();
1305  mutt_log_stop();
1306  return rc;
1307 }
void mutt_mailbox_next_buffer(struct Mailbox *m_cur, struct Buffer *s)
incoming folders completion routine
Definition: mutt_mailbox.c:290
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:50
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:94
The "current" mailbox.
Definition: context.h:36
struct ConfigSet * init_config(size_t size)
Initialise the config system.
Definition: init.c:3778
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:102
struct NntpAccountData * nntp_select_server(struct Mailbox *m, char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:982
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:106
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
WHERE bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: globals.h:203
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:400
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct AddressList * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:285
int mutt_randbuf(void *buf, size_t buflen)
Fill a buffer with randomness.
Definition: muttlib.c:486
bool C_ResumeEditedDraftFiles
Config: Resume editing previously saved draft files.
Definition: main.c:99
The envelope/body of an email.
Definition: email.h:37
int mutt_log_start(void)
Enable file logging.
Definition: mutt_logging.c:284
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#define mutt_perror(...)
Definition: logging.h:85
struct Notify * notify
Notifications system.
Definition: color.h:150
#define CSR_RESULT(x)
Definition: set.h:62
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2430
struct ConnAccount account
Definition: connection.h:36
void mutt_window_init(void)
Create the default Windows.
Definition: mutt_window.c:179
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: browser.c:123
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:51
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1148
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:457
int cs_str_string_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: set.c:627
#define mutt_message(...)
Definition: logging.h:83
int mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1593
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:39
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
#define SEND_DRAFT_FILE
Used by the -H flag.
Definition: send.h:99
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:49
void mutt_window_free_all(void)
Free all the default Windows.
Definition: mutt_window.c:142
bool mutt_ts_capability(void)
Check terminal capabilities.
Definition: terminal.c:54
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:848
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1082
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:95
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:727
struct Body * content
List of MIME parts.
Definition: email.h:90
void mutt_envlist_init(char *envp[])
Create a copy of the environment.
Definition: envlist.c:55
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
void print_version(FILE *fp)
Print system and compile info to a file.
Definition: version.c:381
void neomutt_free(struct NeoMutt **ptr)
Free a NeoMutt.
Definition: neomutt.c:63
A postponed Email, just the envelope info.
Definition: sendlib.h:61
String manipulation buffer.
Definition: buffer.h:33
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
#define _(a)
Definition: message.h:28
WHERE struct ConfigSet * Config
Wrapper around the user&#39;s config settings.
Definition: globals.h:41
struct Body * next
next attachment in the list
Definition: body.h:53
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:253
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:46
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:57
Definition: logging.h:63
Log informational message.
Definition: logging.h:55
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:53
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1197
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:357
uint16_t SendFlags
Flags for ci_send_message(), e.g. SEND_REPLY.
Definition: send.h:86
log_dispatcher_t MuttLogger
The log dispatcher.
Definition: logging.c:52
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope&#39;s Address fields to Punycode format.
Definition: envelope.c:309
int mutt_str_atos(const char *str, short *dst)
Convert ASCII string to a short.
Definition: string.c:232
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:92
Container for Accounts, Notifications.
Definition: neomutt.h:35
enum UrlScheme url_check_scheme(const char *s)
Check the protocol of a URL.
Definition: url.c:132
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:89
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
The body of an email.
Definition: body.h:34
void mutt_prepare_envelope(struct Envelope *env, bool final)
Prepare an email header.
Definition: sendlib.c:3007
#define CS_DUMP_HIDE_SENSITIVE
Obscure sensitive information like passwords.
Definition: dump.h:37
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: browser.h:47
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject)
Write out one RFC822 header line.
Definition: sendlib.c:2334
void imap_logout_all(void)
close all open connections
Definition: imap.c:687
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:1048
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:87
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:182
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:487
int mutt_query_variables(struct ListHead *queries)
Implement the -Q command line flag.
Definition: init.c:3289
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:502
size_t dsize
Length of data.
Definition: buffer.h:37
bool notify_observer_add(struct Notify *notify, enum NotifyType type, int subtype, observer_t callback, intptr_t data)
Add an observer to an object.
Definition: notify.c:159
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:846
#define SEND_MAILX
Send email in Mailx compatibility mode.
Definition: send.h:94
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:375
int mx_check_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1162
struct Mailbox * mailbox
Definition: context.h:50
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
struct Body * mutt_make_file_attach(const char *path)
Create a file attachment.
Definition: sendlib.c:1651
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:55
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
struct Envelope * env
Envelope information.
Definition: email.h:89
struct MyVarList MyVars
List of all the user&#39;s custom config variables.
Definition: myvar.c:34
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:107
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
WHERE bool C_Autoedit
Config: Skip the initial compose menu and edit the email.
Definition: globals.h:206
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:56
bool get_user_info(struct ConfigSet *cs)
Find the user&#39;s name, home and shell.
Definition: main.c:367
int log_disp_queue(time_t stamp, const char *file, int line, const char *function, int level,...)
Save a log line to an internal queue - Implements log_dispatcher_t.
Definition: logging.c:409
WHERE bool C_ReadOnly
Config: Open folders in read-only mode.
Definition: globals.h:250
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:360
static int start_curses(void)
Start the curses or slang UI.
Definition: main.c:294
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:46
void mutt_window_reflow(void)
Resize the Windows to fit the screen.
Definition: mutt_window.c:264
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: sendlib.c:1747
Plain text.
Definition: color.h:78
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
#define MUTT_CLI_SELECT
-y Start with a list of all mailboxes
Definition: main.c:108
void myvar_set(const char *var, const char *val)
Set the value of a "my_" variable.
Definition: myvar.c:91
void mutt_autocrypt_cleanup(void)
Shutdown Autocrypt.
Definition: autocrypt.c:127
#define mutt_b2s(buf)
Definition: buffer.h:41
WHERE char * C_NewsServer
Config: (nntp) Url of the news server.
Definition: globals.h:131
int mutt_reply_observer(struct NotifyCallback *nc)
Listen for config changes to "reply_regex" - Implements observer_t()
Definition: index.c:3732
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition: logging.c:323
Colour has changed.
Definition: notify_type.h:39
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:544
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:121
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:115
int log_disp_curses(time_t stamp, const char *file, int line, const char *function, int level,...)
Display a log line in the message line - Implements log_dispatcher_t.
Definition: mutt_logging.c:129
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1601
A mailbox.
Definition: mailbox.h:92
#define PATH_MAX
Definition: mutt.h:50
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:127
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
WHERE char ErrorBuf[256]
Copy of the last error message.
Definition: globals.h:47
void mutt_encode_descriptions(struct Body *b, bool recurse)
rfc2047 encode the content-descriptions
Definition: send.c:1436
void myvarlist_free(struct MyVarList *list)
Free a List of MyVars.
Definition: myvar.c:131
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:105
int mutt_write_mime_body(struct Body *a, FILE *fp)
Write a MIME part.
Definition: sendlib.c:556
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
void log_queue_empty(void)
Free the contents of the queue.
Definition: logging.c:335
char * data
Pointer to data.
Definition: buffer.h:35
WHERE bool ErrorBufMessage
true if the last message was an error
Definition: globals.h:46
Not object-related.
Definition: notify_type.h:32
static void test_parse_set(void)
Test the config parsing.
Definition: main.c:117
Ignore case when comparing strings.
Definition: string2.h:68
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:225
int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el)
Send an email.
Definition: send.c:1868
void crypt_init(void)
Initialise the crypto backends.
Definition: cryptglue.c:93
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
struct Notify * notify
Notifications handler.
Definition: neomutt.h:37
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:42
bool dump_config(struct ConfigSet *cs, ConfigDumpFlags flags, FILE *fp)
Write all the config to a file.
Definition: dump.c:198
WHERE bool C_CryptProtectedHeadersRead
Config: Display protected headers (Memory Hole) in the pager.
Definition: globals.h:279
Definition: color.h:130
void mutt_opts_free(void)
clean up before quitting
Definition: init.c:2890
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
void mutt_envlist_free(void)
Free the private copy of the environment.
Definition: envlist.c:40
void mutt_write_addrlist(struct AddressList *al, FILE *fp, int linelen, bool display)
wrapper around mutt_write_address()
Definition: sendlib.c:1797
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
Definition: file.c:1369
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:551
void cs_free(struct ConfigSet **ptr)
Free a Config Set.
Definition: set.c:198
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:98
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
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:423
Config has changed.
Definition: notify_type.h:33
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:45
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:103
struct Connection * conn
Definition: nntp.h:102
char * data
String.
Definition: list.h:35
char * subject
Email&#39;s subject.
Definition: envelope.h:66
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:343
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:142
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1216
NeoMutt is initialised.
Definition: neomutt.h:49
WHERE char * C_Spoolfile
Config: Inbox.
Definition: globals.h:146
static void usage(void)
Display NeoMutt command line.
Definition: main.c:222
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
struct Notify * notify
Notifications system.
Definition: set.h:191
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:84
void mutt_sasl_done(void)
Invoke when processing is complete.
Definition: sasl.c:723
#define mutt_error(...)
Definition: logging.h:84
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition: main.c:339
WHERE bool C_ImapPassive
Config: (imap) Reuse an existing IMAP connection to check for new mail.
Definition: globals.h:230
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:110
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1552
Url is mailto://.
Definition: url.h:44
#define STAILQ_EMPTY(head)
Definition: queue.h:346
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:322
void crypto_module_free(void)
Clean up the crypto modules.
Definition: crypt_mod.c:81
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
int mutt_hist_observer(struct NotifyCallback *nc)
Listen for config changes affecting the history - Implements observer_t()
Definition: mutt_history.c:151
struct Email * email_new(void)
Create a new Email.
Definition: email.c:68
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:215
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:49
#define TAILQ_EMPTY(head)
Definition: queue.h:715
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe()
Definition: nntp.c:2824
void mutt_buffer_pool_free(void)
Release the Buffer pool.
Definition: pool.c:86
int mutt_init(bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:2977
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
int mutt_index_menu(void)
Display a list of emails.
Definition: index.c:1067
A List node for strings.
Definition: list.h:33
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
int mutt_log_observer(struct NotifyCallback *nc)
Listen for config changes affecting the log file - Implements observer_t()
Definition: mutt_logging.c:325
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:52
bool notify_send(struct Notify *notify, int type, int subtype, intptr_t data)
Send out a notification message.
Definition: notify.c:145
struct NeoMutt * neomutt_new(struct ConfigSet *cs)
Create the master NeoMutt object.
Definition: neomutt.c:44
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:43
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:104
int log_disp_terminal(time_t stamp, const char *file, int line, const char *function, int level,...)
Save a log line to the terminal - Implements log_dispatcher_t.
Definition: logging.c:450
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:64
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
static const char clear[]
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:599
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:93
The header of an Email.
Definition: envelope.h:54
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:75
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
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:772
void print_copyright(void)
Print copyright message.
Definition: version.c:463

Variable Documentation

◆ C_ResumeEditedDraftFiles

bool C_ResumeEditedDraftFiles

Config: Resume editing previously saved draft files.

Definition at line 99 of file main.c.