NeoMutt  2020-08-21-74-g346364
Teaching an old dog new tricks
DOXYGEN
main.c File Reference

Command line processing. More...

#include "config.h"
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <locale.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "debug/lib.h"
#include "ncrypt/lib.h"
#include "send/lib.h"
#include "browser.h"
#include "commands.h"
#include "context.h"
#include "hook.h"
#include "index.h"
#include "init.h"
#include "keymap.h"
#include "mutt_attach.h"
#include "mutt_globals.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 "options.h"
#include "protos.h"
#include "version.h"
#include <libintl.h>
#include "imap/lib.h"
#include "nntp/lib.h"
#include "autocrypt/lib.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 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...
 
static void log_translation (void)
 Log the translation being used. 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 96 of file main.c.

◆ MUTT_CLI_IGNORE

#define MUTT_CLI_IGNORE   (1 << 0)

-z Open first mailbox if it has mail

Definition at line 97 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 98 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 99 of file main.c.

◆ MUTT_CLI_RO

#define MUTT_CLI_RO   (1 << 3)

-R Open mailbox in read-only mode

Definition at line 100 of file main.c.

◆ MUTT_CLI_SELECT

#define MUTT_CLI_SELECT   (1 << 4)

-y Start with a list of all mailboxes

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

Typedef Documentation

◆ CliFlags

typedef uint8_t CliFlags

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

Definition at line 95 of file main.c.

Function Documentation

◆ reset_tilde()

static void reset_tilde ( struct ConfigSet cs)
static

Temporary measure.

Parameters
csConfig Set

Definition at line 111 of file main.c.

112 {
113  static const char *names[] = { "folder", "mbox", "postponed", "record" };
114 
115  struct Buffer value = mutt_buffer_make(256);
116  for (size_t i = 0; i < mutt_array_size(names); i++)
117  {
118  struct HashElem *he = cs_get_elem(cs, names[i]);
119  if (!he)
120  continue;
121  mutt_buffer_reset(&value);
122  cs_he_initial_get(cs, he, &value);
123  mutt_buffer_expand_path_regex(&value, false);
124  cs_he_initial_set(cs, he, value.data, NULL);
125  cs_he_reset(cs, he, NULL);
126  }
127  mutt_buffer_dealloc(&value);
128 }
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
void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:140
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:356
#define mutt_array_size(x)
Definition: memory.h:33
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:431
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
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:499
char * data
Pointer to data.
Definition: buffer.h:35
The item stored in a Hash Table.
Definition: hash.h:43
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition: set.c:214
+ 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 134 of file main.c.

135 {
136  mutt_endwin();
137 #ifdef HAVE_LIBUNWIND
138  if (code != 0)
139  show_backtrace();
140 #endif
141  exit(code);
142 }
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:571
void show_backtrace(void)
Log the program&#39;s call stack.
Definition: backtrace.c:39
+ Here is the caller graph for this function:

◆ usage()

static void usage ( void  )
static

Display NeoMutt command line.

Definition at line 148 of file main.c.

149 {
150  puts(mutt_make_version());
151 
152  /* L10N: Try to limit to 80 columns */
153  puts(_("usage:\n"
154  " neomutt [-Enx] [-e <command>] [-F <config>] [-H <draft>] [-i <include>]\n"
155  " [-b <address>] [-c <address>] [-s <subject>] [-a <file> [...] --]\n"
156  " <address> [...]\n"
157  " neomutt [-nx] [-e <command>] [-F <config>] [-b <address>] [-c <address>]\n"
158  " [-s <subject>] [-a <file> [...] --] <address> [...] < message\n"
159  " neomutt [-nRy] [-e <command>] [-F <config>] [-f <mailbox>] [-m <type>]\n"
160  " neomutt [-n] [-e <command>] [-F <config>] -A <alias>\n"
161  " neomutt [-n] [-e <command>] [-F <config>] -B\n"
162  " neomutt [-n] [-e <command>] [-F <config>] -D [-S]\n"
163  " neomutt [-n] [-e <command>] [-F <config>] -d <level> -l <file>\n"
164  " neomutt [-n] [-e <command>] [-F <config>] -G\n"
165  " neomutt [-n] [-e <command>] [-F <config>] -g <server>\n"
166  " neomutt [-n] [-e <command>] [-F <config>] -p\n"
167  " neomutt [-n] [-e <command>] [-F <config>] -Q <variable>\n"
168  " neomutt [-n] [-e <command>] [-F <config>] -Z\n"
169  " neomutt [-n] [-e <command>] [-F <config>] -z [-f <mailbox>]\n"
170  " neomutt -v[v]\n"));
171 
172  /* L10N: Try to limit to 80 columns. If more space is needed add an indented line */
173  puts(_("options:\n"
174  " -- Special argument forces NeoMutt to stop option parsing and treat\n"
175  " remaining arguments as addresses even if they start with a dash\n"
176  " -A <alias> Print an expanded version of the given alias to stdout and exit\n"
177  " -a <file> Attach one or more files to a message (must be the last option)\n"
178  " Add any addresses after the '--' argument\n"
179  " -B Run in batch mode (do not start the ncurses UI)\n"
180  " -b <address> Specify a blind carbon copy (Bcc) recipient\n"
181  " -c <address> Specify a carbon copy (Cc) recipient\n"
182  " -D Dump all config variables as 'name=value' pairs to stdout\n"
183  " -D -O Like -D, but show one-liner documentation\n"
184  " -D -S Like -D, but hide the value of sensitive variables\n"
185  " -d <level> Log debugging output to a file (default is \"~/.neomuttdebug0\")\n"
186  " The level can range from 1-5 and affects verbosity\n"
187  " -E Edit draft (-H) or include (-i) file during message composition\n"
188  " -e <command> Specify a command to be run after reading the config files\n"
189  " -F <config> Specify an alternative initialization file to read\n"
190  " -f <mailbox> Specify a mailbox (as defined with 'mailboxes' command) to load\n"
191  " -G Start NeoMutt with a listing of subscribed newsgroups\n"
192  " -g <server> Like -G, but start at specified news server\n"
193  " -H <draft> Specify a draft file with header and body for message composing\n"
194  " -h Print this help message and exit\n"
195  " -i <include> Specify an include file to be embedded in the body of a message\n"
196  " -l <file> Specify a file for debugging output (default \"~/.neomuttdebug0\")\n"
197  " -m <type> Specify a default mailbox format type for newly created folders\n"
198  " The type is either MH, MMDF, Maildir or mbox (case-insensitive)\n"
199  " -n Do not read the system-wide configuration file\n"
200  " -p Resume a prior postponed message, if any\n"
201  " -Q <variable> Query a configuration variable and print its value to stdout\n"
202  " (after the config has been read and any commands executed)\n"
203  " Add -O for one-liner documentation\n"
204  " -R Open mailbox in read-only mode\n"
205  " -s <subject> Specify a subject (must be enclosed in quotes if it has spaces)\n"
206  " -v Print the NeoMutt version and compile-time definitions and exit\n"
207  " -vv Print the NeoMutt license and copyright information and exit\n"
208  " -y Start NeoMutt with a listing of all defined mailboxes\n"
209  " -Z Open the first mailbox with new message or exit immediately with\n"
210  " exit code 1 if none is found in all defined mailboxes\n"
211  " -z Open the first or specified (-f) mailbox if it holds any message\n"
212  " or exit immediately with exit code 1 otherwise"));
213 }
#define _(a)
Definition: message.h:28
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1460
+ 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 221 of file main.c.

222 {
223  km_init(); /* must come before mutt_init */
224 
225 #ifdef USE_SLANG_CURSES
226  SLtt_Ignore_Beep = 1; /* don't do that #*$@^! annoying visual beep! */
227  SLsmg_Display_Eight_Bit = 128; /* characters above this are printable */
228  SLtt_set_color(0, NULL, "default", "default");
229 #if (SLANG_VERSION >= 20000)
230  SLutf8_enable(-1);
231 #endif
232 #else
233  /* should come before initscr() so that ncurses 4.2 doesn't try to install
234  * its own SIGWINCH handler */
236 #endif
237  if (!initscr())
238  {
239  mutt_error(_("Error initializing terminal"));
240  return 1;
241  }
242  /* slang requires the signal handlers to be set after initializing */
245  keypad(stdscr, true);
246  cbreak();
247  noecho();
248  nonl();
249 #ifdef HAVE_TYPEAHEAD
250  typeahead(-1); /* simulate smooth scrolling */
251 #endif
252 #ifdef HAVE_META
253  meta(stdscr, true);
254 #endif
256  /* Now that curses is set up, we drop back to normal screen mode.
257  * This simplifies displaying error messages to the user.
258  * The first call to refresh() will swap us back to curses screen mode. */
259  endwin();
260  return 0;
261 }
#define _(a)
Definition: message.h:28
void km_init(void)
Initialise all the menu keybindings.
Definition: keymap.c:1010
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: keymap.c:981
void mutt_signal_init(void)
Initialise the signal handling.
Definition: mutt_signal.c:132
struct Colors * mutt_colors_new(void)
Create new colours.
Definition: color.c:373
Definition: color.h:129
#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 266 of file main.c.

267 {
268  setlocale(LC_ALL, "");
269 
270 #ifdef ENABLE_NLS
271  const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
272  if (domdir)
273  bindtextdomain(PACKAGE, domdir);
274  else
275  bindtextdomain(PACKAGE, MUTTLOCALEDIR);
276  textdomain(PACKAGE);
277 #endif
278 #ifndef LOCALES_HACK
279  /* Do we have a locale definition? */
280  if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
281  {
282  OptLocales = true;
283  }
284 #endif
285 }
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:991
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 294 of file main.c.

295 {
296  const char *shell = mutt_str_getenv("SHELL");
297  if (shell)
298  cs_str_initial_set(cs, "shell", shell, NULL);
299 
300  /* Get some information about the user */
301  struct passwd *pw = getpwuid(getuid());
302  if (pw)
303  {
304  if (!Username)
305  Username = mutt_str_dup(pw->pw_name);
306  if (!HomeDir)
307  HomeDir = mutt_str_dup(pw->pw_dir);
308  if (!shell)
309  cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
310  }
311 
312  if (!Username)
313  {
314  mutt_error(_("unable to determine username"));
315  return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
316  }
317 
318  if (!HomeDir)
319  {
320  mutt_error(_("unable to determine home directory"));
321  return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
322  }
323 
324  cs_str_reset(cs, "shell", NULL);
325  return true;
326 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:49
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:991
WHERE char * Username
User&#39;s login name.
Definition: mutt_globals.h:52
int cs_str_initial_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:473
#define mutt_error(...)
Definition: logging.h:84
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:408
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ log_translation()

static void log_translation ( void  )
static

Log the translation being used.

Read the header info from the translation file.

Note
Call bindtextdomain() first

Definition at line 335 of file main.c.

336 {
337  const char *header = ""; // Do not merge these two lines
338  header = _(header); // otherwise the .po files will end up badly ordered
339  const char *lang = strcasestr(header, "Language:");
340  int len = 64;
341  if (lang)
342  {
343  lang += 9; // skip label
344  SKIPWS(lang);
345  char *nl = strchr(lang, '\n');
346  if (nl)
347  len = (nl - lang);
348  }
349  else
350  {
351  lang = "NONE";
352  }
353 
354  mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
355 }
#define _(a)
Definition: message.h:28
#define SKIPWS(ch)
Definition: string2.h:46
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ 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 365 of file main.c.

366 {
367  char *subject = NULL;
368  char *include_file = NULL;
369  char *draft_file = NULL;
370  char *new_type = NULL;
371  char *dlevel = NULL;
372  char *dfile = NULL;
373 #ifdef USE_NNTP
374  char *cli_nntp = NULL;
375 #endif
376  struct Email *e = NULL;
377  struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
378  struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
379  struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
380  struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
381  struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
382  struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
383  SendFlags sendflags = SEND_NO_FLAGS;
384  CliFlags flags = MUTT_CLI_NO_FLAGS;
385  int version = 0;
386  int i;
387  bool explicit_folder = false;
388  bool dump_variables = false;
389  bool one_liner = false;
390  bool hide_sensitive = false;
391  bool batch_mode = false;
392  bool edit_infile = false;
393 #ifdef USE_DEBUG_PARSE_TEST
394  bool test_config = false;
395 #endif
396  int double_dash = argc, nargc = 1;
397  int rc = 1;
398  bool repeat_error = false;
399  struct Buffer folder = mutt_buffer_make(0);
400  struct Buffer expanded_infile = mutt_buffer_make(0);
401  struct Buffer tempfile = mutt_buffer_make(0);
402  struct ConfigSet *cs = NULL;
403 
405 
406  /* sanity check against stupid administrators */
407  if (getegid() != getgid())
408  {
409  mutt_error("%s: I don't want to run with privileges!", argv[0]);
410  goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
411  }
412 
413  init_locale();
414 
415  umask(077);
416 
417  mutt_envlist_init(envp);
418  for (optind = 1; optind < double_dash;)
419  {
420  /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
421  * encounters a non-option. That could be a file to attach
422  * (all non-options between -a and --) or it could be an address
423  * (which gets collapsed to the front of argv). */
424  for (; optind < argc; optind++)
425  {
426  if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
427  {
428  if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
429  double_dash = optind; /* quit outer loop after getopt */
430  break; /* drop through to getopt */
431  }
432 
433  /* non-option, either an attachment or address */
434  if (!STAILQ_EMPTY(&attach))
435  mutt_list_insert_tail(&attach, mutt_str_dup(argv[optind]));
436  else
437  argv[nargc++] = argv[optind];
438  }
439 
440  /* USE_NNTP 'g:G' */
441  i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:i:hm:nOpQ:RSs:TvxyzZ");
442  if (i != EOF)
443  {
444  switch (i)
445  {
446  case 'A':
447  mutt_list_insert_tail(&alias_queries, mutt_str_dup(optarg));
448  break;
449  case 'a':
450  mutt_list_insert_tail(&attach, mutt_str_dup(optarg));
451  break;
452  case 'B':
453  batch_mode = true;
454  break;
455  case 'b':
456  mutt_list_insert_tail(&bcc_list, mutt_str_dup(optarg));
457  break;
458  case 'c':
459  mutt_list_insert_tail(&cc_list, mutt_str_dup(optarg));
460  break;
461  case 'D':
462  dump_variables = true;
463  break;
464  case 'd':
465  dlevel = optarg;
466  break;
467  case 'E':
468  edit_infile = true;
469  break;
470  case 'e':
471  mutt_list_insert_tail(&commands, mutt_str_dup(optarg));
472  break;
473  case 'F':
474  mutt_list_insert_tail(&Muttrc, mutt_str_dup(optarg));
475  break;
476  case 'f':
477  mutt_buffer_strcpy(&folder, optarg);
478  explicit_folder = true;
479  break;
480 #ifdef USE_NNTP
481  case 'g': /* Specify a news server */
482  cli_nntp = optarg;
483  /* fallthrough */
484  case 'G': /* List of newsgroups */
485  flags |= MUTT_CLI_SELECT | MUTT_CLI_NEWS;
486  break;
487 #endif
488  case 'H':
489  draft_file = optarg;
490  break;
491  case 'i':
492  include_file = optarg;
493  break;
494  case 'l':
495  dfile = optarg;
496  break;
497  case 'm':
498  new_type = optarg;
499  break;
500  case 'n':
501  flags |= MUTT_CLI_NOSYSRC;
502  break;
503  case 'O':
504  one_liner = true;
505  break;
506  case 'p':
507  sendflags |= SEND_POSTPONED;
508  break;
509  case 'Q':
510  mutt_list_insert_tail(&queries, mutt_str_dup(optarg));
511  break;
512  case 'R':
513  flags |= MUTT_CLI_RO; /* read-only mode */
514  break;
515  case 'S':
516  hide_sensitive = true;
517  break;
518  case 's':
519  subject = optarg;
520  break;
521 #ifdef USE_DEBUG_PARSE_TEST
522  case 'T':
523  test_config = true;
524  break;
525 #endif
526  case 'v':
527  version++;
528  break;
529  case 'y': /* My special hack mode */
530  flags |= MUTT_CLI_SELECT;
531  break;
532  case 'Z':
534  break;
535  case 'z':
536  flags |= MUTT_CLI_IGNORE;
537  break;
538  default:
539  usage();
540  OptNoCurses = true;
541  goto main_ok; // TEST03: neomutt -9
542  }
543  }
544  }
545 
546  /* collapse remaining argv */
547  while (optind < argc)
548  argv[nargc++] = argv[optind++];
549  optind = 1;
550  argc = nargc;
551 
552  if (version > 0)
553  {
555  if (version == 1)
556  print_version(stdout);
557  else
558  print_copyright();
559  OptNoCurses = true;
560  goto main_ok; // TEST04: neomutt -v
561  }
562 
565 
566  cs = init_config(500);
567  if (!cs)
568  goto main_curses;
569  NeoMutt = neomutt_new(cs);
570 
571 #ifdef USE_DEBUG_NOTIFY
573 #endif
574 
575  if (!get_user_info(cs))
576  goto main_exit;
577 
578 #ifdef USE_DEBUG_PARSE_TEST
579  if (test_config)
580  {
581  cs_str_initial_set(cs, "from", "rich@flatcap.org", NULL);
582  cs_str_reset(cs, "from", NULL);
583  myvar_set("my_var", "foo");
584  test_parse_set();
585  goto main_ok;
586  }
587 #endif
588 
589  reset_tilde(cs);
590 
591  if (dfile)
592  {
593  cs_str_initial_set(cs, "debug_file", dfile, NULL);
594  cs_str_reset(cs, "debug_file", NULL);
595  }
596 
597  if (dlevel)
598  {
599  short num = 0;
600  if ((mutt_str_atos(dlevel, &num) < 0) || (num < LL_MESSAGE) || (num >= LL_MAX))
601  {
602  mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
603  goto main_exit; // TEST07: neomutt -d xyz
604  }
605  cs_str_initial_set(cs, "debug_level", dlevel, NULL);
606  cs_str_reset(cs, "debug_level", NULL);
607  }
608 
609  mutt_log_prep();
610  if (dlevel)
611  mutt_log_start();
612 
614 
615  log_translation();
616 
617  if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
618  {
619  e = email_new();
620  e->env = mutt_env_new();
621 
622  struct ListNode *np = NULL;
623  STAILQ_FOREACH(np, &bcc_list, entries)
624  {
625  mutt_addrlist_parse(&e->env->bcc, np->data);
626  }
627 
628  STAILQ_FOREACH(np, &cc_list, entries)
629  {
630  mutt_addrlist_parse(&e->env->cc, np->data);
631  }
632 
633  mutt_list_free(&bcc_list);
634  mutt_list_free(&cc_list);
635  }
636 
637  /* Check for a batch send. */
638  if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
639  dump_variables || batch_mode)
640  {
641  OptNoCurses = true;
642  sendflags = SEND_BATCH;
645  }
646 
647  /* Always create the mutt_windows because batch mode has some shared code
648  * paths that end up referencing them. */
650 
651  /* This must come before mutt_init() because curses needs to be started
652  * before calling the init_pair() function to set the color scheme. */
653  if (!OptNoCurses)
654  {
655  int crc = start_curses();
656  if (crc != 0)
657  goto main_curses; // TEST08: can't test -- fake term?
658 
659  /* check whether terminal status is supported (must follow curses init) */
661  mutt_window_set_root(COLS, LINES);
662  }
663 
664  /* set defaults and read init files */
665  int rc2 = mutt_init(cs, flags & MUTT_CLI_NOSYSRC, &commands);
666  mutt_list_free(&commands);
667  if (rc2 != 0)
668  goto main_curses;
669 
671 
672  /* The command line overrides the config */
673  if (dlevel)
674  cs_str_reset(cs, "debug_level", NULL);
675  if (dfile)
676  cs_str_reset(cs, "debug_file", NULL);
677 
678  if (mutt_log_start() < 0)
679  {
680  mutt_perror("log file");
681  goto main_exit;
682  }
683 
684 #ifdef USE_NNTP
685  /* "$news_server" precedence: command line, config file, environment, system file */
686  if (cli_nntp)
687  cs_str_string_set(cs, "news_server", cli_nntp, NULL);
688  if (!C_NewsServer)
689  {
690  const char *env_nntp = mutt_str_getenv("NNTPSERVER");
691  cs_str_string_set(cs, "news_server", env_nntp, NULL);
692  }
693  if (!C_NewsServer)
694  {
695  char buf[1024];
696  char *server = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
697  cs_str_string_set(cs, "news_server", server, NULL);
698  }
699  if (C_NewsServer)
700  cs_str_initial_set(cs, "news_server", C_NewsServer, NULL);
701 #endif
702 
703  /* Initialize crypto backends. */
704  crypt_init();
705 
706  if (new_type)
707  {
708  struct Buffer err = mutt_buffer_make(0);
709  int r = cs_str_initial_set(cs, "mbox_type", new_type, &err);
710  if (CSR_RESULT(r) != CSR_SUCCESS)
711  {
712  mutt_error(err.data);
713  mutt_buffer_dealloc(&err);
714  goto main_curses;
715  }
716  cs_str_reset(cs, "mbox_type", NULL);
717  }
718 
719  if (!STAILQ_EMPTY(&queries))
720  {
721  rc = mutt_query_variables(&queries, one_liner);
722  goto main_curses;
723  }
724 
725  if (dump_variables)
726  {
728  if (hide_sensitive)
729  cdflags |= CS_DUMP_HIDE_SENSITIVE;
730  if (one_liner)
731  cdflags |= CS_DUMP_SHOW_DOCS;
732  dump_config(cs, cdflags, stdout);
733  goto main_ok; // TEST18: neomutt -D
734  }
735 
736  if (!STAILQ_EMPTY(&alias_queries))
737  {
738  rc = 0;
739  for (; optind < argc; optind++)
740  mutt_list_insert_tail(&alias_queries, mutt_str_dup(argv[optind]));
741  struct ListNode *np = NULL;
742  STAILQ_FOREACH(np, &alias_queries, entries)
743  {
744  struct AddressList *al = alias_lookup(np->data);
745  if (al)
746  {
747  /* output in machine-readable form */
748  mutt_addrlist_to_intl(al, NULL);
749  mutt_addrlist_write_file(al, stdout, 0, false);
750  }
751  else
752  {
753  rc = 1;
754  printf("%s\n", np->data); // TEST19: neomutt -A unknown
755  }
756  }
757  mutt_list_free(&alias_queries);
758  goto main_curses; // TEST20: neomutt -A alias
759  }
760 
761  if (!OptNoCurses)
762  {
764  clear();
768  }
769 
770 #ifdef USE_AUTOCRYPT
771  /* Initialize autocrypt after curses messages are working,
772  * because of the initial account setup screens. */
773  if (C_Autocrypt)
774  mutt_autocrypt_init(!(sendflags & SEND_BATCH));
775 #endif
776 
777  /* Create the C_Folder directory if it doesn't exist. */
778  if (!OptNoCurses && C_Folder)
779  {
780  struct stat sb;
781  struct Buffer *fpath = mutt_buffer_pool_get();
782 
785  bool skip = false;
786 #ifdef USE_IMAP
787  /* we're not connected yet - skip mail folder creation */
788  skip |= (imap_path_probe(mutt_b2s(fpath), NULL) == MUTT_IMAP);
789 #endif
790 #ifdef USE_NNTP
791  skip |= (nntp_path_probe(mutt_b2s(fpath), NULL) == MUTT_NNTP);
792 #endif
793  if (!skip && (stat(mutt_b2s(fpath), &sb) == -1) && (errno == ENOENT))
794  {
795  char msg2[256];
796  snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), C_Folder);
797  if (mutt_yesorno(msg2, MUTT_YES) == MUTT_YES)
798  {
799  if ((mkdir(mutt_b2s(fpath), 0700) == -1) && (errno != EEXIST))
800  mutt_error(_("Can't create %s: %s"), C_Folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
801  }
802  }
803  mutt_buffer_pool_release(&fpath);
804  }
805 
806  if (batch_mode)
807  {
808  goto main_ok; // TEST22: neomutt -B
809  }
810 
816  if (Colors)
818 
819  if (sendflags & SEND_POSTPONED)
820  {
821  if (!OptNoCurses)
822  mutt_flushinp();
823  if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
824  rc = 0;
825  // TEST23: neomutt -p (postponed message, cancel)
826  // TEST24: neomutt -p (no postponed message)
827  log_queue_empty();
828  repeat_error = true;
829  goto main_curses;
830  }
831  else if (subject || e || sendflags || draft_file || include_file ||
832  !STAILQ_EMPTY(&attach) || (optind < argc))
833  {
834  FILE *fp_in = NULL;
835  FILE *fp_out = NULL;
836  char *infile = NULL;
837  char *bodytext = NULL;
838  const char *bodyfile = NULL;
839  int rv = 0;
840 
841  if (!OptNoCurses)
842  mutt_flushinp();
843 
844  if (!e)
845  e = email_new();
846  if (!e->env)
847  e->env = mutt_env_new();
848 
849  for (i = optind; i < argc; i++)
850  {
851  if (url_check_scheme(argv[i]) == U_MAILTO)
852  {
853  if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
854  {
855  mutt_error(_("Failed to parse mailto: link"));
856  email_free(&e);
857  goto main_curses; // TEST25: neomutt mailto:?
858  }
859  }
860  else
861  mutt_addrlist_parse(&e->env->to, argv[i]);
862  }
863 
864  if (!draft_file && C_Autoedit && TAILQ_EMPTY(&e->env->to) &&
865  TAILQ_EMPTY(&e->env->cc))
866  {
867  mutt_error(_("No recipients specified"));
868  email_free(&e);
869  goto main_curses; // TEST26: neomutt -s test (with autoedit=yes)
870  }
871 
872  if (subject)
873  e->env->subject = mutt_str_dup(subject);
874 
875  if (draft_file)
876  {
877  infile = draft_file;
878  include_file = NULL;
879  }
880  else if (include_file)
881  infile = include_file;
882  else
883  edit_infile = false;
884 
885  if (infile || bodytext)
886  {
887  /* Prepare fp_in and expanded_infile. */
888  if (infile)
889  {
890  if (mutt_str_equal("-", infile))
891  {
892  if (edit_infile)
893  {
894  mutt_error(_("Can't use -E flag with stdin"));
895  email_free(&e);
896  goto main_curses; // TEST27: neomutt -E -H -
897  }
898  fp_in = stdin;
899  }
900  else
901  {
902  mutt_buffer_strcpy(&expanded_infile, infile);
903  mutt_buffer_expand_path(&expanded_infile);
904  fp_in = fopen(mutt_b2s(&expanded_infile), "r");
905  if (!fp_in)
906  {
907  mutt_perror(mutt_b2s(&expanded_infile));
908  email_free(&e);
909  goto main_curses; // TEST28: neomutt -E -H missing
910  }
911  }
912  }
913 
914  /* Copy input to a tempfile, and re-point fp_in to the tempfile.
915  * Note: stdin is always copied to a tempfile, ensuring draft_file
916  * can stat and get the correct st_size below. */
917  if (!edit_infile)
918  {
919  mutt_buffer_mktemp(&tempfile);
920 
921  fp_out = mutt_file_fopen(mutt_b2s(&tempfile), "w");
922  if (!fp_out)
923  {
924  mutt_file_fclose(&fp_in);
925  mutt_perror(mutt_b2s(&tempfile));
926  email_free(&e);
927  goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
928  }
929  if (fp_in)
930  {
931  mutt_file_copy_stream(fp_in, fp_out);
932  if (fp_in != stdin)
933  mutt_file_fclose(&fp_in);
934  }
935  else if (bodytext)
936  fputs(bodytext, fp_out);
937  mutt_file_fclose(&fp_out);
938 
939  fp_in = fopen(mutt_b2s(&tempfile), "r");
940  if (!fp_in)
941  {
942  mutt_perror(mutt_b2s(&tempfile));
943  email_free(&e);
944  goto main_curses; // TEST30: can't test
945  }
946  }
947  /* If editing the infile, keep it around afterwards so
948  * it doesn't get unlinked, and we can rebuild the draft_file */
949  else
950  sendflags |= SEND_NO_FREE_HEADER;
951 
952  /* Parse the draft_file into the full Email/Body structure.
953  * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
954  * our e->body. */
955  if (draft_file)
956  {
957  struct Envelope *opts_env = e->env;
958  struct stat st;
959 
960  sendflags |= SEND_DRAFT_FILE;
961 
962  /* Set up a tmp Email with just enough information so that
963  * mutt_prepare_template() can parse the message in fp_in. */
964  struct Email *e_tmp = email_new();
965  e_tmp->offset = 0;
966  e_tmp->body = mutt_body_new();
967  if (fstat(fileno(fp_in), &st) != 0)
968  {
969  mutt_perror(draft_file);
970  email_free(&e);
971  email_free(&e_tmp);
972  goto main_curses; // TEST31: can't test
973  }
974  e_tmp->body->length = st.st_size;
975 
976  if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
977  {
978  mutt_error(_("Can't parse message template: %s"), draft_file);
979  email_free(&e);
980  email_free(&e_tmp);
981  goto main_curses;
982  }
983 
984  /* Scan for neomutt header to set C_ResumeDraftFiles */
985  struct ListNode *np = NULL, *tmp = NULL;
986  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
987  {
988  if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
989  {
991  cs_str_native_set(cs, "resume_draft_files", true, NULL);
992 
993  STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
994  FREE(&np->data);
995  FREE(&np);
996  }
997  }
998 
999  mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1000  mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1001  mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1002  if (opts_env->subject)
1003  mutt_str_replace(&e->env->subject, opts_env->subject);
1004 
1005  mutt_env_free(&opts_env);
1006  email_free(&e_tmp);
1007  }
1008  /* Editing the include_file: pass it directly in.
1009  * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1010  else if (edit_infile)
1011  bodyfile = mutt_b2s(&expanded_infile);
1012  // For bodytext and unedited include_file: use the tempfile.
1013  else
1014  bodyfile = mutt_b2s(&tempfile);
1015 
1016  mutt_file_fclose(&fp_in);
1017  }
1018 
1019  FREE(&bodytext);
1020 
1021  if (!STAILQ_EMPTY(&attach))
1022  {
1023  struct Body *b = e->body;
1024 
1025  while (b && b->next)
1026  b = b->next;
1027 
1028  struct ListNode *np = NULL;
1029  STAILQ_FOREACH(np, &attach, entries)
1030  {
1031  if (b)
1032  {
1034  b = b->next;
1035  }
1036  else
1037  {
1039  e->body = b;
1040  }
1041  if (!b)
1042  {
1043  mutt_error(_("%s: unable to attach file"), np->data);
1044  mutt_list_free(&attach);
1045  email_free(&e);
1046  goto main_curses; // TEST32: neomutt john@example.com -a missing
1047  }
1048  }
1049  mutt_list_free(&attach);
1050  }
1051 
1052  rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1053  /* We WANT the "Mail sent." and any possible, later error */
1054  log_queue_empty();
1055  if (ErrorBufMessage)
1056  mutt_message("%s", ErrorBuf);
1057 
1058  if (edit_infile)
1059  {
1060  if (include_file)
1061  e->body->unlink = false;
1062  else if (draft_file)
1063  {
1064  if (truncate(mutt_b2s(&expanded_infile), 0) == -1)
1065  {
1066  mutt_perror(mutt_b2s(&expanded_infile));
1067  email_free(&e);
1068  goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1069  }
1070  fp_out = mutt_file_fopen(mutt_b2s(&expanded_infile), "a");
1071  if (!fp_out)
1072  {
1073  mutt_perror(mutt_b2s(&expanded_infile));
1074  email_free(&e);
1075  goto main_curses; // TEST34: can't test
1076  }
1077 
1078  /* If the message was sent or postponed, these will already
1079  * have been done. */
1080  if (rv < 0)
1081  {
1082  if (e->body->next)
1083  e->body = mutt_make_multipart(e->body);
1085  mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1086  mutt_env_to_intl(e->env, NULL, NULL);
1087  }
1088 
1090  fp_out, e->env, e->body, MUTT_WRITE_HEADER_POSTPONE, false,
1092  NeoMutt->sub);
1094  fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1095  fputc('\n', fp_out);
1096  if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1097  {
1098  mutt_file_fclose(&fp_out);
1099  email_free(&e);
1100  goto main_curses; // TEST35: can't test
1101  }
1102  mutt_file_fclose(&fp_out);
1103  }
1104 
1105  email_free(&e);
1106  }
1107 
1108  /* !edit_infile && draft_file will leave the tempfile around */
1109  if (!mutt_buffer_is_empty(&tempfile))
1110  unlink(mutt_b2s(&tempfile));
1111 
1113 
1114  if (rv != 0)
1115  goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1116  }
1117  else
1118  {
1119  if (flags & MUTT_CLI_MAILBOX)
1120  {
1121 #ifdef USE_IMAP
1122  bool passive = C_ImapPassive;
1123  C_ImapPassive = false;
1124 #endif
1125  if (mutt_mailbox_check(Context ? Context->mailbox : NULL, 0) == 0)
1126  {
1127  mutt_message(_("No mailbox with new mail"));
1128  goto main_curses; // TEST37: neomutt -Z (no new mail)
1129  }
1130  mutt_buffer_reset(&folder);
1131  mutt_mailbox_next(Context ? Context->mailbox : NULL, &folder);
1132 #ifdef USE_IMAP
1133  C_ImapPassive = passive;
1134 #endif
1135  }
1136  else if (flags & MUTT_CLI_SELECT)
1137  {
1138 #ifdef USE_NNTP
1139  if (flags & MUTT_CLI_NEWS)
1140  {
1141  OptNews = true;
1142  CurrentNewsSrv =
1144  if (!CurrentNewsSrv)
1145  goto main_curses; // TEST38: neomutt -G (unset news_server)
1146  }
1147  else
1148 #endif
1149  if (TAILQ_EMPTY(&NeoMutt->accounts))
1150  {
1151  mutt_error(_("No incoming mailboxes defined"));
1152  goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1153  }
1154  mutt_buffer_reset(&folder);
1156  if (mutt_buffer_is_empty(&folder))
1157  {
1158  goto main_ok; // TEST40: neomutt -y (quit selection)
1159  }
1160  }
1161 
1162  if (mutt_buffer_is_empty(&folder))
1163  {
1164  if (C_Spoolfile)
1165  {
1166  // Check if C_Spoolfile corresponds a mailboxes' description.
1167  struct Mailbox *m_desc = mailbox_find_name(C_Spoolfile);
1168  if (m_desc)
1169  mutt_buffer_strcpy(&folder, m_desc->realpath);
1170  else
1171  mutt_buffer_strcpy(&folder, C_Spoolfile);
1172  }
1173  else if (C_Folder)
1174  mutt_buffer_strcpy(&folder, C_Folder);
1175  /* else no folder */
1176  }
1177 
1178 #ifdef USE_NNTP
1179  if (OptNews)
1180  {
1181  OptNews = false;
1182  mutt_buffer_alloc(&folder, PATH_MAX);
1183  nntp_expand_path(folder.data, folder.dsize, &CurrentNewsSrv->conn->account);
1184  }
1185  else
1186 #endif
1187  mutt_buffer_expand_path(&folder);
1188 
1190  mutt_str_replace(&LastFolder, mutt_b2s(&folder));
1191 
1192  if (flags & MUTT_CLI_IGNORE)
1193  {
1194  /* check to see if there are any messages in the folder */
1195  switch (mx_check_empty(mutt_b2s(&folder)))
1196  {
1197  case -1:
1198  mutt_perror(mutt_b2s(&folder));
1199  goto main_curses; // TEST41: neomutt -z -f missing
1200  case 1:
1201  mutt_error(_("Mailbox is empty"));
1202  goto main_curses; // TEST42: neomutt -z -f /dev/null
1203  }
1204  }
1205 
1206  mutt_folder_hook(mutt_b2s(&folder), NULL);
1209 
1210  repeat_error = true;
1211  struct Mailbox *m = mx_resolve(mutt_b2s(&folder));
1213  if (!Context)
1214  {
1215  if (m->account)
1217 
1218  mailbox_free(&m);
1219  mutt_error(_("Unable to open mailbox %s"), mutt_b2s(&folder));
1220  repeat_error = false;
1221  }
1222  if (Context || !explicit_folder)
1223  {
1224  struct MuttWindow *dlg = index_pager_init();
1225  dialog_push(dlg);
1226 
1227  struct EventMailbox em = { Context ? Context->mailbox : NULL };
1229 
1230  mutt_index_menu(dlg);
1231  dialog_pop();
1232  index_pager_shutdown(dlg);
1233  mutt_window_free(&dlg);
1234  ctx_free(&Context);
1235  log_queue_empty();
1236  repeat_error = false;
1237  }
1238 #ifdef USE_IMAP
1239  imap_logout_all();
1240 #endif
1241 #ifdef USE_SASL
1242  mutt_sasl_done();
1243 #endif
1244 #ifdef USE_AUTOCRYPT
1246 #endif
1247  // TEST43: neomutt (no change to mailbox)
1248  // TEST44: neomutt (change mailbox)
1249  }
1250 
1251 main_ok:
1252  rc = 0;
1253 main_curses:
1254  mutt_endwin();
1256  /* Repeat the last message to the user */
1257  if (repeat_error && ErrorBufMessage)
1258  puts(ErrorBuf);
1259 main_exit:
1261  mutt_buffer_dealloc(&folder);
1262  mutt_buffer_dealloc(&expanded_infile);
1263  mutt_buffer_dealloc(&tempfile);
1264  mutt_list_free(&queries);
1271  crypt_cleanup();
1272  mutt_opts_free();
1273  mutt_keys_free();
1275  mutt_prex_free();
1277  cs_free(&cs);
1279  log_queue_empty();
1280  mutt_log_stop();
1281  return rc;
1282 }
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:221
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:51
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:93
The "current" mailbox.
Definition: context.h:38
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:95
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:99
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
Container for lots of config items.
Definition: set.h:228
#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
bool C_ResumeEditedDraftFiles
Config: Resume editing previously saved draft files.
Definition: main.c:92
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
void crypt_cleanup(void)
Clean up backend.
Definition: cryptglue.c:138
struct Notify * notify
Notifications system.
Definition: color.h:149
A postponed Email, just the envelope info.
Definition: header.h:42
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2370
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
void mutt_window_init(void)
Create the default Windows.
Definition: mutt_window.c:349
struct Body * body
List of MIME parts.
Definition: email.h:91
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: browser.c:123
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1157
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
#define mutt_message(...)
Definition: logging.h:83
struct AccountList accounts
List of all Accounts.
Definition: neomutt.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:51
bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: config.c:37
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:57
void mutt_window_free_all(void)
Free all the default Windows.
Definition: mutt_window.c:314
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:1073
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
int log_disp_terminal(time_t stamp, const char *file, int line, const char *function, enum LogLevel level,...)
Save a log line to the terminal - Implements log_dispatcher_t.
Definition: logging.c:441
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:737
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:424
void neomutt_free(struct NeoMutt **ptr)
Free a NeoMutt.
Definition: neomutt.c:64
String manipulation buffer.
Definition: buffer.h:33
bool C_CryptProtectedHeadersRead
Config: Display protected headers (Memory Hole) in the pager.
Definition: config.c:58
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
static void log_translation(void)
Log the translation being used.
Definition: main.c:335
#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:303
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
Definition: logging.h:47
A division of the screen.
Definition: mutt_window.h:115
char * C_NewsServer
Config: (nntp) Url of the news server.
Definition: config.c:41
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:613
Log informational message.
Definition: logging.h:39
WHERE char ErrorBuf[256]
Copy of the last error message.
Definition: mutt_globals.h:45
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:54
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
incoming folders completion routine
Definition: mutt_mailbox.c:308
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1258
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:348
An Event that happened to a Mailbox.
Definition: mailbox.h:181
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:37
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:222
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:45
struct NntpAccountData * nntp_select_server(struct Mailbox *m, char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1008
Container for Accounts, Notifications.
Definition: neomutt.h:36
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
The body of an email.
Definition: body.h:34
#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:43
#define CSR_RESULT(x)
Definition: set.h:52
void imap_logout_all(void)
close all open connections
Definition: imap.c:538
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:49
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:991
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:186
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:40
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:111
WHERE char * Username
User&#39;s login name.
Definition: mutt_globals.h:52
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:504
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:836
static bool get_user_info(struct ConfigSet *cs)
Find the user&#39;s name, home and shell.
Definition: main.c:294
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:379
struct Notify * notify
Notifications system.
Definition: mutt_window.h:131
int mx_check_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1267
struct Mailbox * mailbox
Definition: context.h:50
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:1237
bool mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1591
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, int start_col, bool display)
Wrapper for mutt_write_address()
Definition: address.c:1231
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:276
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Mailbox * mx_resolve(const char *path_or_name)
Get a Mailbox from either a path or name.
Definition: mx.c:1765
struct Envelope * env
Envelope information.
Definition: email.h:90
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:1082
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:100
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
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:473
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:66
WHERE bool C_ReadOnly
Config: Open folders in read-only mode.
Definition: mutt_globals.h:153
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:169
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:221
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
Plain text.
Definition: color.h:77
void test_parse_set(void)
Test the config parsing.
Definition: parse_test.c:39
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define MUTT_CLI_SELECT
-y Start with a list of all mailboxes
Definition: main.c:101
void mutt_autocrypt_cleanup(void)
Shutdown Autocrypt.
Definition: autocrypt.c:133
#define mutt_b2s(buf)
Definition: buffer.h:41
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: keymap.c:866
int mutt_reply_observer(struct NotifyCallback *nc)
Listen for config changes to "reply_regex" - Implements observer_t.
Definition: index.c:3973
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition: logging.c:314
int mutt_query_variables(struct ListHead *queries, bool show_docs)
Implement the -Q command line flag.
Definition: init.c:1065
bool C_ImapPassive
Config: (imap) Reuse an existing IMAP connection to check for new mail.
Definition: config.c:52
void mutt_window_set_root(int cols, int rows)
Set the dimensions of the Root Window.
Definition: mutt_window.c:634
int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:735
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:571
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:128
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1698
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:44
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:138
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
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:98
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe()
Definition: nntp.c:2828
int mutt_abort_key_config_observer(struct NotifyCallback *nc)
Listen for abort_key config changes - Implements observer_t.
Definition: keymap.c:887
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:326
char * data
Pointer to data.
Definition: buffer.h:35
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
struct ConfigSet * init_config(size_t size)
Initialise the config system.
Definition: mutt_config.c:849
Not object-related, NotifyGlobal.
Definition: notify_type.h:40
bool dump_config(struct ConfigSet *cs, ConfigDumpFlags flags, FILE *fp)
Write all the config to a file.
Definition: dump.c:165
WHERE bool C_Autoedit
Config: Skip the initial compose menu and edit the email.
Definition: mutt_globals.h:136
void myvar_set(const char *var, const char *val)
Set the value of a "my_" variable.
Definition: myvar.c:91
#define CS_DUMP_SHOW_DOCS
Show one-liner documentation for the config item.
Definition: dump.h:45
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:223
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
void crypt_init(void)
Initialise the crypto backends.
Definition: cryptglue.c:93
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:43
Definition: color.h:129
int mutt_index_menu(struct MuttWindow *dlg)
Display a list of emails.
Definition: index.c:1139
void mutt_opts_free(void)
clean up before quitting
Definition: init.c:651
void mutt_envlist_free(void)
Free the private copy of the environment.
Definition: envlist.c:41
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
Definition: file.c:1382
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:55
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:50
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:84
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:37
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:41
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:96
struct Connection * conn
Definition: lib.h:102
void cs_free(struct ConfigSet **ptr)
Free a Config Set.
Definition: set.c:180
char * data
String.
Definition: list.h:36
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:323
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:131
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1304
WHERE char * C_Spoolfile
Config: Inbox.
Definition: mutt_globals.h:108
NeoMutt is initialised.
Definition: neomutt.h:50
Register for all notifications.
Definition: notify_type.h:33
static void usage(void)
Display NeoMutt command line.
Definition: main.c:148
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
void mutt_prex_free(void)
Cleanup heap memory allocated by compiled regexes.
Definition: prex.c:347
void mutt_sasl_done(void)
Invoke when processing is complete.
Definition: sasl.c:747
Current Mailbox has changed.
Definition: mailbox.h:173
#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:266
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:98
uint16_t ConfigDumpFlags
Flags for dump_config(), e.g. CS_DUMP_ONLY_CHANGED.
Definition: dump.h:32
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:54
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:103
#define FREE(x)
Definition: memory.h:40
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:94
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:41
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:1990
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:4106
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:76
void mutt_commands_cleanup(void)
Clean up commands globals.
Definition: commands.c:101
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:59
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
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:761
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:4089
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:408
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:50
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
WHERE bool ErrorBufMessage
true if the last message was an error
Definition: mutt_globals.h:44
#define TAILQ_EMPTY(head)
Definition: queue.h:714
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:588
int log_disp_queue(time_t stamp, const char *file, int line, const char *function, enum LogLevel level,...)
Save a log line to an internal queue - Implements log_dispatcher_t.
Definition: logging.c:400
A List node for strings.
Definition: list.h:34
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:557
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:43
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:317
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
struct NeoMutt * neomutt_new(struct ConfigSet *cs)
Create the main NeoMutt object.
Definition: neomutt.c:44
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:45
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
rfc2047 encode the content-descriptions
Definition: send.c:1444
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:97
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:64
int debug_notify_observer(struct NotifyCallback *nc)
Definition: notify.c:320
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:655
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:573
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:46
The header of an Email.
Definition: envelope.h:54
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:152
void print_copyright(void)
Print copyright message.
Definition: version.c:541

Variable Documentation

◆ C_ResumeEditedDraftFiles

bool C_ResumeEditedDraftFiles

Config: Resume editing previously saved draft files.

Definition at line 92 of file main.c.