NeoMutt  2020-08-21-74-g346364
Teaching an old dog new tricks
DOXYGEN
main.c
Go to the documentation of this file.
1 
32 #define MAIN_C 1
33 #define GNULIB_defined_setlocale
34 
35 #include "config.h"
36 #include <errno.h>
37 #include <getopt.h>
38 #include <limits.h>
39 #include <locale.h>
40 #include <pwd.h>
41 #include <stdbool.h>
42 #include <stdint.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/stat.h>
47 #include <unistd.h>
48 #include "mutt/lib.h"
49 #include "address/lib.h"
50 #include "config/lib.h"
51 #include "email/lib.h"
52 #include "core/lib.h"
53 #include "alias/lib.h"
54 #include "conn/lib.h"
55 #include "gui/lib.h"
56 #include "debug/lib.h"
57 #include "ncrypt/lib.h"
58 #include "send/lib.h"
59 #include "browser.h"
60 #include "commands.h"
61 #include "context.h"
62 #include "hook.h"
63 #include "index.h"
64 #include "init.h"
65 #include "keymap.h"
66 #include "mutt_attach.h"
67 #include "mutt_globals.h"
68 #include "mutt_history.h"
69 #include "mutt_logging.h"
70 #include "mutt_mailbox.h"
71 #include "mutt_menu.h"
72 #include "muttlib.h"
73 #include "mx.h"
74 #include "myvar.h"
75 #include "options.h"
76 #include "protos.h"
77 #include "version.h"
78 #ifdef ENABLE_NLS
79 #include <libintl.h>
80 #endif
81 #ifdef USE_IMAP
82 #include "imap/lib.h"
83 #endif
84 #ifdef USE_NNTP
85 #include "nntp/lib.h"
86 #endif
87 #ifdef USE_AUTOCRYPT
88 #include "autocrypt/lib.h"
89 #endif
90 
91 /* These Config Variables are only used in main.c */
93 
94 // clang-format off
95 typedef uint8_t CliFlags;
96 #define MUTT_CLI_NO_FLAGS 0
97 #define MUTT_CLI_IGNORE (1 << 0)
98 #define MUTT_CLI_MAILBOX (1 << 1)
99 #define MUTT_CLI_NOSYSRC (1 << 2)
100 #define MUTT_CLI_RO (1 << 3)
101 #define MUTT_CLI_SELECT (1 << 4)
102 #ifdef USE_NNTP
103 #define MUTT_CLI_NEWS (1 << 5)
104 #endif
105 // clang-format on
106 
111 static void reset_tilde(struct ConfigSet *cs)
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 }
129 
134 void mutt_exit(int code)
135 {
136  mutt_endwin();
137 #ifdef HAVE_LIBUNWIND
138  if (code != 0)
139  show_backtrace();
140 #endif
141  exit(code);
142 }
143 
144 // clang-format off
148 static void usage(void)
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 }
214 // clang-format on
215 
221 static int start_curses(void)
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 }
262 
266 static void init_locale(void)
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 }
286 
294 static bool get_user_info(struct ConfigSet *cs)
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 }
327 
335 static void log_translation(void)
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 }
356 
365 int main(int argc, char *argv[], char *envp[])
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
Convenience wrapper for the gui headers.
#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
Manage keymappings.
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:399
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
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool C_ResumeEditedDraftFiles
Config: Resume editing previously saved draft files.
Definition: main.c:92
IMAP network mailbox.
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
Config/command parsing.
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
Structs that make up an email.
The "currently-open" mailbox.
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1157
Autocrypt end-to-end encryption.
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
Convenience wrapper for the send headers.
GUI manage the main index (list of emails)
#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
NeoMutt Logging.
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
void km_init(void)
Initialise all the menu keybindings.
Definition: keymap.c:1010
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
Convenience wrapper for the config headers.
GUI component for displaying/selecting items from a list.
#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
Email Address Handling.
void mutt_buffer_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:140
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
Some miscellaneous functions.
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
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: keymap.c:981
#define mutt_array_size(x)
Definition: memory.h:33
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
void mutt_signal_init(void)
Initialise the signal handling.
Definition: mutt_signal.c:132
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
Parse and execute user-defined hooks.
bool mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1591
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
API for mailboxes.
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
Convenience wrapper for the core headers.
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
#define SKIPWS(ch)
Definition: string2.h:46
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
Email Aliases.
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
Usenet network mailbox type; talk to an NNTP server.
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
Prototypes for many functions.
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
Manage where the email is piped to external commands.
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
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
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
GUI present the user with a selectable list.
API for encryption/signing of emails.
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
Handling of email attachments.
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 Colors * mutt_colors_new(void)
Create new colours.
Definition: color.c:373
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
Display version and copyright about NeoMutt.
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
Read/write command history from/to a file.
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:37
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:41
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:134
#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
Convenience wrapper for the debug headers.
NeoMutt is initialised.
Definition: neomutt.h:50
Log at debug level 1.
Definition: logging.h:40
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
void show_backtrace(void)
Log the program&#39;s call stack.
Definition: backtrace.c:39
Connection Library.
#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
The item stored in a Hash Table.
Definition: hash.h:43
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
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
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
bool OptLocales
(pseudo) set if user has valid locale definition
Definition: mbyte.c:44
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
int main(int argc, char *argv[], char *envp[])
Start NeoMutt.
Definition: main.c:365
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
Handling of personal config (&#39;my&#39; variables)
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition: set.c:214
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
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1460
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