NeoMutt  2019-12-07-60-g0cfa53
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 "gui/lib.h"
#include "mutt.h"
#include "alias.h"
#include "browser.h"
#include "context.h"
#include "globals.h"
#include "hook.h"
#include "index.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_commands.h"
#include "mutt_history.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_menu.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 "version.h"
#include <libintl.h>
#include "sidebar.h"
#include "imap/imap.h"
#include "nntp/nntp.h"
#include "autocrypt/autocrypt.h"
+ Include dependency graph for main.c:

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

◆ MUTT_CLI_IGNORE

#define MUTT_CLI_IGNORE   (1 << 0)

-z Open first mailbox if it has mail

Definition at line 100 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 101 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 102 of file main.c.

◆ MUTT_CLI_RO

#define MUTT_CLI_RO   (1 << 3)

-R Open mailbox in read-only mode

Definition at line 103 of file main.c.

◆ MUTT_CLI_SELECT

#define MUTT_CLI_SELECT   (1 << 4)

-y Start with a list of all mailboxes

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

Typedef Documentation

◆ CliFlags

typedef uint8_t CliFlags

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

Definition at line 98 of file main.c.

Function Documentation

◆ test_parse_set()

static void test_parse_set ( void  )
static

Test the config parsing.

Definition at line 113 of file main.c.

114 {
115  const char *vars[] = {
116  "from", // ADDRESS
117  "beep", // BOOL
118  "ispell", // COMMAND
119  "mbox_type", // MAGIC
120  "to_chars", // MBTABLE
121  "net_inc", // NUMBER
122  "signature", // PATH
123  "print", // QUAD
124  "mask", // REGEX
125  "sort", // SORT
126  "attribution", // STRING
127  "zzz", // UNKNOWN
128  "my_var", // MY_VAR
129  };
130 
131  const char *commands[] = {
132  "set",
133  "toggle",
134  "reset",
135  "unset",
136  };
137 
138  const char *tests[] = {
139  "%s %s", "%s %s=42", "%s %s?", "%s ?%s", "%s ?%s=42",
140  "%s ?%s?", "%s no%s", "%s no%s=42", "%s no%s?", "%s inv%s",
141  "%s inv%s=42", "%s inv%s?", "%s &%s", "%s &%s=42", "%s &%s?",
142  };
143 
144  struct Buffer tmp = mutt_buffer_make(256);
145  struct Buffer err = mutt_buffer_make(256);
146  char line[64];
147 
148  for (size_t v = 0; v < mutt_array_size(vars); v++)
149  {
150  // printf("--------------------------------------------------------------------------------\n");
151  // printf("VARIABLE %s\n", vars[v]);
152  for (size_t c = 0; c < mutt_array_size(commands); c++)
153  {
154  // printf("----------------------------------------\n");
155  // printf("COMMAND %s\n", commands[c]);
156  for (size_t t = 0; t < mutt_array_size(tests); t++)
157  {
158  mutt_buffer_reset(&tmp);
159  mutt_buffer_reset(&err);
160 
161  snprintf(line, sizeof(line), tests[t], commands[c], vars[v]);
162  printf("%-26s", line);
163  enum CommandResult rc = mutt_parse_rc_line(line, &tmp, &err);
164  printf("%2d %s\n", rc, err.data);
165  }
166  printf("\n");
167  }
168  // printf("\n");
169  }
170 
171  mutt_buffer_dealloc(&tmp);
172  mutt_buffer_dealloc(&err);
173 }
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:3252
+ 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.

Parameters
csConfig Set

Definition at line 179 of file main.c.

180 {
181  static const char *names[] = {
182  "alias_file", "autocrypt_dir", "certificate_file",
183  "debug_file", "folder", "history_file",
184  "mbox", "newsrc", "news_cache_dir",
185  "postponed", "record", "signature",
186  };
187 
188  struct Buffer value = mutt_buffer_make(256);
189  for (size_t i = 0; i < mutt_array_size(names); i++)
190  {
191  struct HashElem *he = cs_get_elem(cs, names[i]);
192  if (!he)
193  continue;
194  mutt_buffer_reset(&value);
195  cs_he_initial_get(cs, he, &value);
196  mutt_expand_path(value.data, value.dsize);
197  cs_he_initial_set(cs, he, value.data, NULL);
198  cs_he_reset(cs, he, NULL);
199  }
200  mutt_buffer_dealloc(&value);
201 }
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:133
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:344
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:202
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:479
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:413
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 207 of file main.c.

208 {
209  clear();
210  refresh();
211  mutt_endwin();
212  exit(code);
213 }
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:545
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 219 of file main.c.

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

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

337 {
338  setlocale(LC_ALL, "");
339 
340 #ifdef ENABLE_NLS
341  const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
342  if (domdir)
343  bindtextdomain(PACKAGE, domdir);
344  else
345  bindtextdomain(PACKAGE, MUTTLOCALEDIR);
346  textdomain(PACKAGE);
347 #endif
348 #ifndef LOCALES_HACK
349  /* Do we have a locale definition? */
350  if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
351  {
352  OptLocales = true;
353  }
354 #endif
355 }
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()

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

365 {
368 
369  const char *shell = mutt_str_getenv("SHELL");
370  if (shell)
371  cs_str_initial_set(cs, "shell", shell, NULL);
372 
373  /* Get some information about the user */
374  struct passwd *pw = getpwuid(getuid());
375  if (pw)
376  {
377  if (!Username)
378  Username = mutt_str_strdup(pw->pw_name);
379  if (!HomeDir)
380  HomeDir = mutt_str_strdup(pw->pw_dir);
381  if (!shell)
382  cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
383  }
384 
385  if (!Username)
386  {
387  mutt_error(_("unable to determine username"));
388  return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
389  }
390 
391  if (!HomeDir)
392  {
393  mutt_error(_("unable to determine home directory"));
394  return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
395  }
396 
397  cs_str_reset(cs, "shell", NULL);
398  return true;
399 }
WHERE char * Username
User&#39;s login name.
Definition: globals.h:52
#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:453
WHERE char * HomeDir
User&#39;s home directory.
Definition: globals.h:49
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:390
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 409 of file main.c.

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

Variable Documentation

◆ C_ResumeEditedDraftFiles

bool C_ResumeEditedDraftFiles

Config: Resume editing previously saved draft files.

Definition at line 95 of file main.c.