NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
main.c
Go to the documentation of this file.
1 
169 #define MAIN_C 1
170 #define GNULIB_defined_setlocale
171 
172 #include "config.h"
173 #include <errno.h>
174 #include <getopt.h>
175 #include <limits.h>
176 #include <locale.h>
177 #include <pwd.h>
178 #include <stdbool.h>
179 #include <stdint.h>
180 #include <stdio.h>
181 #include <stdlib.h>
182 #include <string.h>
183 #include <sys/stat.h>
184 #include <unistd.h>
185 #include "mutt/lib.h"
186 #include "address/lib.h"
187 #include "config/lib.h"
188 #include "email/lib.h"
189 #include "core/lib.h"
190 #include "alias/lib.h"
191 #include "conn/lib.h"
192 #include "gui/lib.h"
193 #include "index/lib.h"
194 #include "menu/lib.h"
195 #include "ncrypt/lib.h"
196 #include "question/lib.h"
197 #include "send/lib.h"
198 #include "alternates.h"
199 #include "attachments.h"
200 #include "browser.h"
201 #include "commands.h"
202 #include "context.h"
203 #include "hook.h"
204 #include "init.h"
205 #include "keymap.h"
206 #include "mutt_attach.h"
207 #include "mutt_globals.h"
208 #include "mutt_history.h"
209 #include "mutt_logging.h"
210 #include "mutt_mailbox.h"
211 #include "muttlib.h"
212 #include "mx.h"
213 #include "myvar.h"
214 #include "options.h"
215 #include "protos.h"
216 #include "subjectrx.h"
217 #include "version.h"
218 #ifdef ENABLE_NLS
219 #include <libintl.h>
220 #endif
221 #ifdef USE_IMAP
222 #include "imap/lib.h"
223 #endif
224 #ifdef USE_POP
225 #include "pop/lib.h"
226 #endif
227 #ifdef USE_NNTP
228 #include "nntp/lib.h"
229 #include "nntp/adata.h" // IWYU pragma: keep
230 #include "nntp/mdata.h" // IWYU pragma: keep
231 #endif
232 #ifdef USE_AUTOCRYPT
233 #include "autocrypt/lib.h"
234 #endif
235 #ifdef USE_DEBUG_NOTIFY
236 #include "debug/lib.h"
237 #endif
238 
239 // clang-format off
240 typedef uint8_t CliFlags;
241 #define MUTT_CLI_NO_FLAGS 0
242 #define MUTT_CLI_IGNORE (1 << 0)
243 #define MUTT_CLI_MAILBOX (1 << 1)
244 #define MUTT_CLI_NOSYSRC (1 << 2)
245 #define MUTT_CLI_RO (1 << 3)
246 #define MUTT_CLI_SELECT (1 << 4)
247 #ifdef USE_NNTP
248 #define MUTT_CLI_NEWS (1 << 5)
249 #endif
250 // clang-format on
251 
256 static void reset_tilde(struct ConfigSet *cs)
257 {
258  static const char *names[] = { "folder", "mbox", "postponed", "record" };
259 
260  struct Buffer value = mutt_buffer_make(256);
261  for (size_t i = 0; i < mutt_array_size(names); i++)
262  {
263  struct HashElem *he = cs_get_elem(cs, names[i]);
264  if (!he)
265  continue;
266  mutt_buffer_reset(&value);
267  cs_he_initial_get(cs, he, &value);
268  mutt_buffer_expand_path_regex(&value, false);
269  cs_he_initial_set(cs, he, value.data, NULL);
270  cs_he_reset(cs, he, NULL);
271  }
272  mutt_buffer_dealloc(&value);
273 }
274 
279 void mutt_exit(int code)
280 {
281  mutt_endwin();
282 #ifdef HAVE_LIBUNWIND
283  if (code != 0)
284  show_backtrace();
285 #endif
286  exit(code);
287 }
288 
289 // clang-format off
293 static void usage(void)
294 {
295  puts(mutt_make_version());
296 
297  /* L10N: Try to limit to 80 columns */
298  puts(_("usage:"));
299  puts(_(" neomutt [-Enx] [-e <command>] [-F <config>] [-H <draft>] [-i <include>]\n"
300  " [-b <address>] [-c <address>] [-s <subject>] [-a <file> [...] --]\n"
301  " <address> [...]"));
302  puts(_(" neomutt [-nx] [-e <command>] [-F <config>] [-b <address>] [-c <address>]\n"
303  " [-s <subject>] [-a <file> [...] --] <address> [...] < message"));
304  puts(_(" neomutt [-nRy] [-e <command>] [-F <config>] [-f <mailbox>] [-m <type>]"));
305  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -A <alias>"));
306  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -B"));
307  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -D [-S] [-O]"));
308  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -d <level> -l <file>"));
309  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -G"));
310  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -g <server>"));
311  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -p"));
312  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -Q <variable> [-O]"));
313  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -Z"));
314  puts(_(" neomutt [-n] [-e <command>] [-F <config>] -z [-f <mailbox>]"));
315  puts(_(" neomutt -v[v]\n"));
316 
317  /* L10N: Try to limit to 80 columns. If more space is needed add an indented line */
318  puts(_("options:"));
319  puts(_(" -- Special argument forces NeoMutt to stop option parsing and treat\n"
320  " remaining arguments as addresses even if they start with a dash"));
321  puts(_(" -A <alias> Print an expanded version of the given alias to stdout and exit"));
322  puts(_(" -a <file> Attach one or more files to a message (must be the last option)\n"
323  " Add any addresses after the '--' argument"));
324  puts(_(" -B Run in batch mode (do not start the ncurses UI)"));
325  puts(_(" -b <address> Specify a blind carbon copy (Bcc) recipient"));
326  puts(_(" -c <address> Specify a carbon copy (Cc) recipient"));
327  puts(_(" -D Dump all config variables as 'name=value' pairs to stdout"));
328  puts(_(" -D -O Like -D, but show one-liner documentation"));
329  puts(_(" -D -S Like -D, but hide the value of sensitive variables"));
330  puts(_(" -d <level> Log debugging output to a file (default is \"~/.neomuttdebug0\")\n"
331  " The level can range from 1-5 and affects verbosity"));
332  puts(_(" -E Edit draft (-H) or include (-i) file during message composition"));
333  puts(_(" -e <command> Specify a command to be run after reading the config files"));
334  puts(_(" -F <config> Specify an alternative initialization file to read"));
335  puts(_(" -f <mailbox> Specify a mailbox (as defined with 'mailboxes' command) to load"));
336  puts(_(" -G Start NeoMutt with a listing of subscribed newsgroups"));
337  puts(_(" -g <server> Like -G, but start at specified news server"));
338  puts(_(" -H <draft> Specify a draft file with header and body for message composing"));
339  puts(_(" -h Print this help message and exit"));
340  puts(_(" -i <include> Specify an include file to be embedded in the body of a message"));
341  puts(_(" -l <file> Specify a file for debugging output (default \"~/.neomuttdebug0\")"));
342  puts(_(" -m <type> Specify a default mailbox format type for newly created folders\n"
343  " The type is either MH, MMDF, Maildir or mbox (case-insensitive)"));
344  puts(_(" -n Do not read the system-wide configuration file"));
345  puts(_(" -p Resume a prior postponed message, if any"));
346  puts(_(" -Q <variable> Query a configuration variable and print its value to stdout\n"
347  " (after the config has been read and any commands executed)\n"
348  " Add -O for one-liner documentation"));
349  puts(_(" -R Open mailbox in read-only mode"));
350  puts(_(" -s <subject> Specify a subject (must be enclosed in quotes if it has spaces)"));
351  puts(_(" -v Print the NeoMutt version and compile-time definitions and exit"));
352  puts(_(" -vv Print the NeoMutt license and copyright information and exit"));
353  puts(_(" -y Start NeoMutt with a listing of all defined mailboxes"));
354  puts(_(" -Z Open the first mailbox with new message or exit immediately with\n"
355  " exit code 1 if none is found in all defined mailboxes"));
356  puts(_(" -z Open the first or specified (-f) mailbox if it holds any message\n"
357  " or exit immediately with exit code 1 otherwise"));
358 }
359 // clang-format on
360 
366 static int start_curses(void)
367 {
368  km_init(); /* must come before mutt_init */
369 
370 #ifdef USE_SLANG_CURSES
371  SLtt_Ignore_Beep = 1; /* don't do that #*$@^! annoying visual beep! */
372  SLsmg_Display_Eight_Bit = 128; /* characters above this are printable */
373  SLtt_set_color(0, NULL, "default", "default");
374 #if (SLANG_VERSION >= 20000)
375  SLutf8_enable(-1);
376 #endif
377 #else
378  /* should come before initscr() so that ncurses 4.2 doesn't try to install
379  * its own SIGWINCH handler */
381 #endif
382  if (!initscr())
383  {
384  mutt_error(_("Error initializing terminal"));
385  return 1;
386  }
387  /* slang requires the signal handlers to be set after initializing */
390  keypad(stdscr, true);
391  cbreak();
392  noecho();
393  nonl();
394 #ifdef HAVE_TYPEAHEAD
395  typeahead(-1); /* simulate smooth scrolling */
396 #endif
397 #ifdef HAVE_META
398  meta(stdscr, true);
399 #endif
401  /* Now that curses is set up, we drop back to normal screen mode.
402  * This simplifies displaying error messages to the user.
403  * The first call to refresh() will swap us back to curses screen mode. */
404  endwin();
405  return 0;
406 }
407 
411 static void init_locale(void)
412 {
413  setlocale(LC_ALL, "");
414 
415 #ifdef ENABLE_NLS
416  const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
417  if (domdir)
418  bindtextdomain(PACKAGE, domdir);
419  else
420  bindtextdomain(PACKAGE, MUTTLOCALEDIR);
421  textdomain(PACKAGE);
422 #endif
423 #ifndef LOCALES_HACK
424  /* Do we have a locale definition? */
425  if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
426  {
427  OptLocales = true;
428  }
429 #endif
430 }
431 
439 static bool get_user_info(struct ConfigSet *cs)
440 {
441  const char *shell = mutt_str_getenv("SHELL");
442  if (shell)
443  cs_str_initial_set(cs, "shell", shell, NULL);
444 
445  /* Get some information about the user */
446  struct passwd *pw = getpwuid(getuid());
447  if (pw)
448  {
449  if (!Username)
450  Username = mutt_str_dup(pw->pw_name);
451  if (!HomeDir)
452  HomeDir = mutt_str_dup(pw->pw_dir);
453  if (!shell)
454  cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
455  }
456 
457  if (!Username)
458  {
459  mutt_error(_("unable to determine username"));
460  return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
461  }
462 
463  if (!HomeDir)
464  {
465  mutt_error(_("unable to determine home directory"));
466  return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
467  }
468 
469  cs_str_reset(cs, "shell", NULL);
470  return true;
471 }
472 
480 static void log_translation(void)
481 {
482  const char *header = ""; // Do not merge these two lines
483  header = _(header); // otherwise the .po files will end up badly ordered
484  const char *lang = strcasestr(header, "Language:");
485  int len = 64;
486  if (lang)
487  {
488  lang += 9; // skip label
489  SKIPWS(lang);
490  char *nl = strchr(lang, '\n');
491  if (nl)
492  len = (nl - lang);
493  }
494  else
495  {
496  lang = "NONE";
497  }
498 
499  mutt_debug(LL_DEBUG1, "Translation: %.*s\n", len, lang);
500 }
501 
510 int main(int argc, char *argv[], char *envp[])
511 {
512  char *subject = NULL;
513  char *include_file = NULL;
514  char *draft_file = NULL;
515  char *new_type = NULL;
516  char *dlevel = NULL;
517  char *dfile = NULL;
518 #ifdef USE_NNTP
519  const char *cli_nntp = NULL;
520 #endif
521  struct Email *e = NULL;
522  struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
523  struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
524  struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
525  struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
526  struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
527  struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
528  SendFlags sendflags = SEND_NO_FLAGS;
529  CliFlags flags = MUTT_CLI_NO_FLAGS;
530  int version = 0;
531  int i;
532  bool explicit_folder = false;
533  bool dump_variables = false;
534  bool one_liner = false;
535  bool hide_sensitive = false;
536  bool batch_mode = false;
537  bool edit_infile = false;
538 #ifdef USE_DEBUG_PARSE_TEST
539  bool test_config = false;
540 #endif
541  int double_dash = argc, nargc = 1;
542  int rc = 1;
543  bool repeat_error = false;
544  struct Buffer folder = mutt_buffer_make(0);
545  struct Buffer expanded_infile = mutt_buffer_make(0);
546  struct Buffer tempfile = mutt_buffer_make(0);
547  struct ConfigSet *cs = NULL;
548 
550 
551  /* sanity check against stupid administrators */
552  if (getegid() != getgid())
553  {
554  mutt_error("%s: I don't want to run with privileges!", argv[0]);
555  goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
556  }
557 
558  init_locale();
559 
560  umask(077);
561 
562  mutt_envlist_init(envp);
563  for (optind = 1; optind < double_dash;)
564  {
565  /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
566  * encounters a non-option. That could be a file to attach
567  * (all non-options between -a and --) or it could be an address
568  * (which gets collapsed to the front of argv). */
569  for (; optind < argc; optind++)
570  {
571  if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
572  {
573  if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
574  double_dash = optind; /* quit outer loop after getopt */
575  break; /* drop through to getopt */
576  }
577 
578  /* non-option, either an attachment or address */
579  if (!STAILQ_EMPTY(&attach))
580  mutt_list_insert_tail(&attach, mutt_str_dup(argv[optind]));
581  else
582  argv[nargc++] = argv[optind];
583  }
584 
585  /* USE_NNTP 'g:G' */
586  i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:i:hm:nOpQ:RSs:TvxyzZ");
587  if (i != EOF)
588  {
589  switch (i)
590  {
591  case 'A':
592  mutt_list_insert_tail(&alias_queries, mutt_str_dup(optarg));
593  break;
594  case 'a':
595  mutt_list_insert_tail(&attach, mutt_str_dup(optarg));
596  break;
597  case 'B':
598  batch_mode = true;
599  break;
600  case 'b':
601  mutt_list_insert_tail(&bcc_list, mutt_str_dup(optarg));
602  break;
603  case 'c':
604  mutt_list_insert_tail(&cc_list, mutt_str_dup(optarg));
605  break;
606  case 'D':
607  dump_variables = true;
608  break;
609  case 'd':
610  dlevel = optarg;
611  break;
612  case 'E':
613  edit_infile = true;
614  break;
615  case 'e':
616  mutt_list_insert_tail(&commands, mutt_str_dup(optarg));
617  break;
618  case 'F':
619  mutt_list_insert_tail(&Muttrc, mutt_str_dup(optarg));
620  break;
621  case 'f':
622  mutt_buffer_strcpy(&folder, optarg);
623  explicit_folder = true;
624  break;
625 #ifdef USE_NNTP
626  case 'g': /* Specify a news server */
627  cli_nntp = optarg;
628  /* fallthrough */
629  case 'G': /* List of newsgroups */
630  flags |= MUTT_CLI_SELECT | MUTT_CLI_NEWS;
631  break;
632 #endif
633  case 'H':
634  draft_file = optarg;
635  break;
636  case 'i':
637  include_file = optarg;
638  break;
639  case 'l':
640  dfile = optarg;
641  break;
642  case 'm':
643  new_type = optarg;
644  break;
645  case 'n':
646  flags |= MUTT_CLI_NOSYSRC;
647  break;
648  case 'O':
649  one_liner = true;
650  break;
651  case 'p':
652  sendflags |= SEND_POSTPONED;
653  break;
654  case 'Q':
655  mutt_list_insert_tail(&queries, mutt_str_dup(optarg));
656  break;
657  case 'R':
658  flags |= MUTT_CLI_RO; /* read-only mode */
659  break;
660  case 'S':
661  hide_sensitive = true;
662  break;
663  case 's':
664  subject = optarg;
665  break;
666 #ifdef USE_DEBUG_PARSE_TEST
667  case 'T':
668  test_config = true;
669  break;
670 #endif
671  case 'v':
672  version++;
673  break;
674  case 'y': /* My special hack mode */
675  flags |= MUTT_CLI_SELECT;
676  break;
677  case 'Z':
679  break;
680  case 'z':
681  flags |= MUTT_CLI_IGNORE;
682  break;
683  default:
684  usage();
685  OptNoCurses = true;
686  goto main_ok; // TEST03: neomutt -9
687  }
688  }
689  }
690 
691  /* collapse remaining argv */
692  while (optind < argc)
693  argv[nargc++] = argv[optind++];
694  optind = 1;
695  argc = nargc;
696 
697  if (version > 0)
698  {
700  if (version == 1)
701  print_version(stdout);
702  else
703  print_copyright();
704  OptNoCurses = true;
705  goto main_ok; // TEST04: neomutt -v
706  }
707 
710 
711  cs = cs_new(500);
712  if (!cs)
713  goto main_curses;
714 
715  NeoMutt = neomutt_new(cs);
716  init_config(cs);
717  subjrx_init();
718  attach_init();
719  alternates_init();
720 
721 #ifdef USE_DEBUG_NOTIFY
723 #endif
724 
725  if (!get_user_info(cs))
726  goto main_exit;
727 
728 #ifdef USE_DEBUG_PARSE_TEST
729  if (test_config)
730  {
731  cs_str_initial_set(cs, "from", "rich@flatcap.org", NULL);
732  cs_str_reset(cs, "from", NULL);
733  myvar_set("my_var", "foo");
734  test_parse_set();
735  goto main_ok;
736  }
737 #endif
738 
739  reset_tilde(cs);
740 
741  if (dfile)
742  {
743  cs_str_initial_set(cs, "debug_file", dfile, NULL);
744  cs_str_reset(cs, "debug_file", NULL);
745  }
746 
747  if (dlevel)
748  {
749  short num = 0;
750  if ((mutt_str_atos(dlevel, &num) < 0) || (num < LL_MESSAGE) || (num >= LL_MAX))
751  {
752  mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
753  goto main_exit; // TEST07: neomutt -d xyz
754  }
755  cs_str_initial_set(cs, "debug_level", dlevel, NULL);
756  cs_str_reset(cs, "debug_level", NULL);
757  }
758 
759  mutt_log_prep();
760  if (dlevel)
761  mutt_log_start();
762 
764 
765  log_translation();
766 
767  if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
768  {
769  e = email_new();
770  e->env = mutt_env_new();
771 
772  struct ListNode *np = NULL;
773  STAILQ_FOREACH(np, &bcc_list, entries)
774  {
775  mutt_addrlist_parse(&e->env->bcc, np->data);
776  }
777 
778  STAILQ_FOREACH(np, &cc_list, entries)
779  {
780  mutt_addrlist_parse(&e->env->cc, np->data);
781  }
782 
783  mutt_list_free(&bcc_list);
784  mutt_list_free(&cc_list);
785  }
786 
787  /* Check for a batch send. */
788  if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
789  dump_variables || batch_mode)
790  {
791  OptNoCurses = true;
792  sendflags = SEND_BATCH;
795  }
796 
797  /* Always create the mutt_windows because batch mode has some shared code
798  * paths that end up referencing them. */
799  rootwin_new();
800 
801  /* This must come before mutt_init() because curses needs to be started
802  * before calling the init_pair() function to set the color scheme. */
803  if (!OptNoCurses)
804  {
805  int crc = start_curses();
806  if (crc != 0)
807  goto main_curses; // TEST08: can't test -- fake term?
808 
809  /* check whether terminal status is supported (must follow curses init) */
811  rootwin_set_size(COLS, LINES);
812  }
813 
814  /* set defaults and read init files */
815  int rc2 = mutt_init(cs, flags & MUTT_CLI_NOSYSRC, &commands);
816  mutt_list_free(&commands);
817  if (rc2 != 0)
818  goto main_curses;
819 
821 
822  /* The command line overrides the config */
823  if (dlevel)
824  cs_str_reset(cs, "debug_level", NULL);
825  if (dfile)
826  cs_str_reset(cs, "debug_file", NULL);
827 
828  if (mutt_log_start() < 0)
829  {
830  mutt_perror("log file");
831  goto main_exit;
832  }
833 
834 #ifdef USE_NNTP
835  {
836  /* "$news_server" precedence: command line, config file, environment, system file */
837  if (!cli_nntp)
838  cli_nntp = cs_subset_string(NeoMutt->sub, "news_server");
839 
840  if (!cli_nntp)
841  cli_nntp = mutt_str_getenv("NNTPSERVER");
842 
843  char buf[1024] = { 0 };
844  if (!cli_nntp)
845  cli_nntp = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
846 
847  if (cli_nntp)
848  {
849  cs_str_initial_set(cs, "news_server", cli_nntp, NULL);
850  cs_str_reset(cs, "news_server", NULL);
851  }
852  }
853 #endif
854 
855  /* Initialize crypto backends. */
856  crypt_init();
857 
858  if (new_type)
859  {
860  struct Buffer err = mutt_buffer_make(0);
861  int r = cs_str_initial_set(cs, "mbox_type", new_type, &err);
862  if (CSR_RESULT(r) != CSR_SUCCESS)
863  {
864  mutt_error(err.data);
865  mutt_buffer_dealloc(&err);
866  goto main_curses;
867  }
868  cs_str_reset(cs, "mbox_type", NULL);
869  }
870 
871  if (!STAILQ_EMPTY(&queries))
872  {
873  rc = mutt_query_variables(&queries, one_liner);
874  goto main_curses;
875  }
876 
877  if (dump_variables)
878  {
880  if (hide_sensitive)
881  cdflags |= CS_DUMP_HIDE_SENSITIVE;
882  if (one_liner)
883  cdflags |= CS_DUMP_SHOW_DOCS;
884  dump_config(cs, cdflags, stdout);
885  goto main_ok; // TEST18: neomutt -D
886  }
887 
888  if (!STAILQ_EMPTY(&alias_queries))
889  {
890  rc = 0;
891  for (; optind < argc; optind++)
892  mutt_list_insert_tail(&alias_queries, mutt_str_dup(argv[optind]));
893  struct ListNode *np = NULL;
894  STAILQ_FOREACH(np, &alias_queries, entries)
895  {
896  struct AddressList *al = alias_lookup(np->data);
897  if (al)
898  {
899  /* output in machine-readable form */
900  mutt_addrlist_to_intl(al, NULL);
901  mutt_addrlist_write_file(al, stdout, 0, false);
902  }
903  else
904  {
905  rc = 1;
906  printf("%s\n", np->data); // TEST19: neomutt -A unknown
907  }
908  }
909  mutt_list_free(&alias_queries);
910  goto main_curses; // TEST20: neomutt -A alias
911  }
912 
913  if (!OptNoCurses)
914  {
916  clear();
920  }
921 
922 #ifdef USE_AUTOCRYPT
923  /* Initialize autocrypt after curses messages are working,
924  * because of the initial account setup screens. */
925  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
926  if (c_autocrypt)
927  mutt_autocrypt_init(NULL, !(sendflags & SEND_BATCH));
928 #endif
929 
930  /* Create the `$folder` directory if it doesn't exist. */
931  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
932  if (!OptNoCurses && c_folder)
933  {
934  struct stat sb;
935  struct Buffer *fpath = mutt_buffer_pool_get();
936 
937  mutt_buffer_strcpy(fpath, c_folder);
939  bool skip = false;
940 #ifdef USE_IMAP
941  /* we're not connected yet - skip mail folder creation */
942  skip |= (imap_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_IMAP);
943 #endif
944 #ifdef USE_POP
945  skip |= (pop_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_POP);
946 #endif
947 #ifdef USE_NNTP
948  skip |= (nntp_path_probe(mutt_buffer_string(fpath), NULL) == MUTT_NNTP);
949 #endif
950  if (!skip && (stat(mutt_buffer_string(fpath), &sb) == -1) && (errno == ENOENT))
951  {
952  char msg2[256];
953  snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), c_folder);
954  if (mutt_yesorno(msg2, MUTT_YES) == MUTT_YES)
955  {
956  if ((mkdir(mutt_buffer_string(fpath), 0700) == -1) && (errno != EEXIST))
957  mutt_error(_("Can't create %s: %s"), c_folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
958  }
959  }
960  mutt_buffer_pool_release(&fpath);
961  }
962 
963  if (batch_mode)
964  {
965  goto main_ok; // TEST22: neomutt -B
966  }
967 
971 
972  if (sendflags & SEND_POSTPONED)
973  {
974  if (!OptNoCurses)
975  mutt_flushinp();
976  if (mutt_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL, NeoMutt->sub) == 0)
977  rc = 0;
978  // TEST23: neomutt -p (postponed message, cancel)
979  // TEST24: neomutt -p (no postponed message)
980  log_queue_empty();
981  repeat_error = true;
982  goto main_curses;
983  }
984  else if (subject || e || sendflags || draft_file || include_file ||
985  !STAILQ_EMPTY(&attach) || (optind < argc))
986  {
987  FILE *fp_in = NULL;
988  FILE *fp_out = NULL;
989  char *infile = NULL;
990  char *bodytext = NULL;
991  const char *bodyfile = NULL;
992  int rv = 0;
993 
994  if (!OptNoCurses)
995  mutt_flushinp();
996 
997  if (!e)
998  e = email_new();
999  if (!e->env)
1000  e->env = mutt_env_new();
1001 
1002  for (i = optind; i < argc; i++)
1003  {
1004  if (url_check_scheme(argv[i]) == U_MAILTO)
1005  {
1006  if (!mutt_parse_mailto(e->env, &bodytext, argv[i]))
1007  {
1008  mutt_error(_("Failed to parse mailto: link"));
1009  email_free(&e);
1010  goto main_curses; // TEST25: neomutt mailto:?
1011  }
1012  }
1013  else
1014  mutt_addrlist_parse(&e->env->to, argv[i]);
1015  }
1016 
1017  const bool c_auto_edit = cs_subset_bool(NeoMutt->sub, "auto_edit");
1018  if (!draft_file && c_auto_edit && TAILQ_EMPTY(&e->env->to) &&
1019  TAILQ_EMPTY(&e->env->cc))
1020  {
1021  mutt_error(_("No recipients specified"));
1022  email_free(&e);
1023  goto main_curses; // TEST26: neomutt -s test (with auto_edit=yes)
1024  }
1025 
1026  if (subject)
1027  e->env->subject = mutt_str_dup(subject);
1028 
1029  if (draft_file)
1030  {
1031  infile = draft_file;
1032  include_file = NULL;
1033  }
1034  else if (include_file)
1035  infile = include_file;
1036  else
1037  edit_infile = false;
1038 
1039  if (infile || bodytext)
1040  {
1041  /* Prepare fp_in and expanded_infile. */
1042  if (infile)
1043  {
1044  if (mutt_str_equal("-", infile))
1045  {
1046  if (edit_infile)
1047  {
1048  mutt_error(_("Can't use -E flag with stdin"));
1049  email_free(&e);
1050  goto main_curses; // TEST27: neomutt -E -H -
1051  }
1052  fp_in = stdin;
1053  }
1054  else
1055  {
1056  mutt_buffer_strcpy(&expanded_infile, infile);
1057  mutt_buffer_expand_path(&expanded_infile);
1058  fp_in = fopen(mutt_buffer_string(&expanded_infile), "r");
1059  if (!fp_in)
1060  {
1061  mutt_perror(mutt_buffer_string(&expanded_infile));
1062  email_free(&e);
1063  goto main_curses; // TEST28: neomutt -E -H missing
1064  }
1065  }
1066  }
1067 
1068  /* Copy input to a tempfile, and re-point fp_in to the tempfile.
1069  * Note: stdin is always copied to a tempfile, ensuring draft_file
1070  * can stat and get the correct st_size below. */
1071  if (!edit_infile)
1072  {
1073  mutt_buffer_mktemp(&tempfile);
1074 
1075  fp_out = mutt_file_fopen(mutt_buffer_string(&tempfile), "w");
1076  if (!fp_out)
1077  {
1078  mutt_file_fclose(&fp_in);
1079  mutt_perror(mutt_buffer_string(&tempfile));
1080  email_free(&e);
1081  goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
1082  }
1083  if (fp_in)
1084  {
1085  mutt_file_copy_stream(fp_in, fp_out);
1086  if (fp_in != stdin)
1087  mutt_file_fclose(&fp_in);
1088  }
1089  else if (bodytext)
1090  fputs(bodytext, fp_out);
1091  mutt_file_fclose(&fp_out);
1092 
1093  fp_in = fopen(mutt_buffer_string(&tempfile), "r");
1094  if (!fp_in)
1095  {
1096  mutt_perror(mutt_buffer_string(&tempfile));
1097  email_free(&e);
1098  goto main_curses; // TEST30: can't test
1099  }
1100  }
1101  /* If editing the infile, keep it around afterwards so
1102  * it doesn't get unlinked, and we can rebuild the draft_file */
1103  else
1104  sendflags |= SEND_NO_FREE_HEADER;
1105 
1106  /* Parse the draft_file into the full Email/Body structure.
1107  * Set SEND_DRAFT_FILE so mutt_send_message doesn't overwrite
1108  * our e->body. */
1109  if (draft_file)
1110  {
1111  struct Envelope *opts_env = e->env;
1112  struct stat st;
1113 
1114  sendflags |= SEND_DRAFT_FILE;
1115 
1116  /* Set up a tmp Email with just enough information so that
1117  * mutt_prepare_template() can parse the message in fp_in. */
1118  struct Email *e_tmp = email_new();
1119  e_tmp->offset = 0;
1120  e_tmp->body = mutt_body_new();
1121  if (fstat(fileno(fp_in), &st) != 0)
1122  {
1123  mutt_perror(draft_file);
1124  email_free(&e);
1125  email_free(&e_tmp);
1126  goto main_curses; // TEST31: can't test
1127  }
1128  e_tmp->body->length = st.st_size;
1129 
1130  if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1131  {
1132  mutt_error(_("Can't parse message template: %s"), draft_file);
1133  email_free(&e);
1134  email_free(&e_tmp);
1135  goto main_curses;
1136  }
1137 
1138  /* Scan for neomutt header to set `$resume_draft_files` */
1139  struct ListNode *np = NULL, *tmp = NULL;
1140  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1141  {
1142  if (mutt_istr_startswith(np->data, "X-Mutt-Resume-Draft:"))
1143  {
1144  const bool c_resume_edited_draft_files =
1145  cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1146  if (c_resume_edited_draft_files)
1147  cs_str_native_set(cs, "resume_draft_files", true, NULL);
1148 
1149  STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1150  FREE(&np->data);
1151  FREE(&np);
1152  }
1153  }
1154 
1155  mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1156  mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1157  mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1158  if (opts_env->subject)
1159  mutt_str_replace(&e->env->subject, opts_env->subject);
1160 
1161  mutt_env_free(&opts_env);
1162  email_free(&e_tmp);
1163  }
1164  /* Editing the include_file: pass it directly in.
1165  * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1166  else if (edit_infile)
1167  bodyfile = mutt_buffer_string(&expanded_infile);
1168  // For bodytext and unedited include_file: use the tempfile.
1169  else
1170  bodyfile = mutt_buffer_string(&tempfile);
1171 
1172  mutt_file_fclose(&fp_in);
1173  }
1174 
1175  FREE(&bodytext);
1176 
1177  if (!STAILQ_EMPTY(&attach))
1178  {
1179  struct Body *b = e->body;
1180 
1181  while (b && b->next)
1182  b = b->next;
1183 
1184  struct ListNode *np = NULL;
1185  STAILQ_FOREACH(np, &attach, entries)
1186  {
1187  if (b)
1188  {
1190  b = b->next;
1191  }
1192  else
1193  {
1195  e->body = b;
1196  }
1197  if (!b)
1198  {
1199  mutt_error(_("%s: unable to attach file"), np->data);
1200  mutt_list_free(&attach);
1201  email_free(&e);
1202  goto main_curses; // TEST32: neomutt john@example.com -a missing
1203  }
1204  }
1205  mutt_list_free(&attach);
1206  }
1207 
1208  rv = mutt_send_message(sendflags, e, bodyfile, NULL, NULL, NeoMutt->sub);
1209  /* We WANT the "Mail sent." and any possible, later error */
1210  log_queue_empty();
1211  if (ErrorBufMessage)
1212  mutt_message("%s", ErrorBuf);
1213 
1214  if (edit_infile)
1215  {
1216  if (include_file)
1217  e->body->unlink = false;
1218  else if (draft_file)
1219  {
1220  if (truncate(mutt_buffer_string(&expanded_infile), 0) == -1)
1221  {
1222  mutt_perror(mutt_buffer_string(&expanded_infile));
1223  email_free(&e);
1224  goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1225  }
1226  fp_out = mutt_file_fopen(mutt_buffer_string(&expanded_infile), "a");
1227  if (!fp_out)
1228  {
1229  mutt_perror(mutt_buffer_string(&expanded_infile));
1230  email_free(&e);
1231  goto main_curses; // TEST34: can't test
1232  }
1233 
1234  /* If the message was sent or postponed, these will already
1235  * have been done. */
1236  if (rv < 0)
1237  {
1238  if (e->body->next)
1239  e->body = mutt_make_multipart(e->body);
1241  mutt_prepare_envelope(e->env, false, NeoMutt->sub);
1242  mutt_env_to_intl(e->env, NULL, NULL);
1243  }
1244 
1245  const bool c_crypt_protected_headers_read =
1246  cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1248  fp_out, e->env, e->body, MUTT_WRITE_HEADER_POSTPONE, false,
1249  c_crypt_protected_headers_read && mutt_should_hide_protected_subject(e),
1250  NeoMutt->sub);
1251  const bool c_resume_edited_draft_files =
1252  cs_subset_bool(NeoMutt->sub, "resume_edited_draft_files");
1253  if (c_resume_edited_draft_files)
1254  fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1255  fputc('\n', fp_out);
1256  if ((mutt_write_mime_body(e->body, fp_out, NeoMutt->sub) == -1))
1257  {
1258  mutt_file_fclose(&fp_out);
1259  email_free(&e);
1260  goto main_curses; // TEST35: can't test
1261  }
1262  mutt_file_fclose(&fp_out);
1263  }
1264 
1265  email_free(&e);
1266  }
1267 
1268  /* !edit_infile && draft_file will leave the tempfile around */
1269  if (!mutt_buffer_is_empty(&tempfile))
1270  unlink(mutt_buffer_string(&tempfile));
1271 
1272  rootwin_free();
1273 
1274  if (rv != 0)
1275  goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1276  }
1277  else
1278  {
1279  if (flags & MUTT_CLI_MAILBOX)
1280  {
1281 #ifdef USE_IMAP
1282  const bool c_imap_passive = cs_subset_bool(NeoMutt->sub, "imap_passive");
1283  cs_subset_str_native_set(NeoMutt->sub, "imap_passive", false, NULL);
1284 #endif
1285  if (mutt_mailbox_check(NULL, 0) == 0)
1286  {
1287  mutt_message(_("No mailbox with new mail"));
1288  goto main_curses; // TEST37: neomutt -Z (no new mail)
1289  }
1290  mutt_buffer_reset(&folder);
1291  mutt_mailbox_next(NULL, &folder);
1292 #ifdef USE_IMAP
1293  cs_subset_str_native_set(NeoMutt->sub, "imap_passive", c_imap_passive, NULL);
1294 #endif
1295  }
1296  else if (flags & MUTT_CLI_SELECT)
1297  {
1298 #ifdef USE_NNTP
1299  if (flags & MUTT_CLI_NEWS)
1300  {
1301  const char *const c_news_server =
1302  cs_subset_string(NeoMutt->sub, "news_server");
1303  OptNews = true;
1305  c_news_server, false);
1306  if (!CurrentNewsSrv)
1307  goto main_curses; // TEST38: neomutt -G (unset news_server)
1308  }
1309  else
1310 #endif
1311  if (TAILQ_EMPTY(&NeoMutt->accounts))
1312  {
1313  mutt_error(_("No incoming mailboxes defined"));
1314  goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1315  }
1316  mutt_buffer_reset(&folder);
1318  ctx_mailbox(Context), NULL, NULL);
1319  if (mutt_buffer_is_empty(&folder))
1320  {
1321  goto main_ok; // TEST40: neomutt -y (quit selection)
1322  }
1323  }
1324 
1325  if (mutt_buffer_is_empty(&folder))
1326  {
1327  const char *const c_spool_file =
1328  cs_subset_string(NeoMutt->sub, "spool_file");
1329  if (c_spool_file)
1330  {
1331  // Check if `$spool_file` corresponds a mailboxes' description.
1332  struct Mailbox *m_desc = mailbox_find_name(c_spool_file);
1333  if (m_desc)
1334  mutt_buffer_strcpy(&folder, m_desc->realpath);
1335  else
1336  mutt_buffer_strcpy(&folder, c_spool_file);
1337  }
1338  else if (c_folder)
1339  mutt_buffer_strcpy(&folder, c_folder);
1340  /* else no folder */
1341  }
1342 
1343 #ifdef USE_NNTP
1344  if (OptNews)
1345  {
1346  OptNews = false;
1347  mutt_buffer_alloc(&folder, PATH_MAX);
1348  nntp_expand_path(folder.data, folder.dsize, &CurrentNewsSrv->conn->account);
1349  }
1350  else
1351 #endif
1352  mutt_buffer_expand_path(&folder);
1353 
1356 
1357  if (flags & MUTT_CLI_IGNORE)
1358  {
1359  /* check to see if there are any messages in the folder */
1360  switch (mx_path_is_empty(mutt_buffer_string(&folder)))
1361  {
1362  case -1:
1363  mutt_perror(mutt_buffer_string(&folder));
1364  goto main_curses; // TEST41: neomutt -z -f missing
1365  case 1:
1366  mutt_error(_("Mailbox is empty"));
1367  goto main_curses; // TEST42: neomutt -z -f /dev/null
1368  }
1369  }
1370 
1371  mutt_folder_hook(mutt_buffer_string(&folder), NULL);
1373  mutt_debug(LL_NOTIFY, "NT_GLOBAL_STARTUP\n");
1375 
1376  repeat_error = true;
1377  struct Mailbox *m = mx_resolve(mutt_buffer_string(&folder));
1378  const bool c_read_only = cs_subset_bool(NeoMutt->sub, "read_only");
1379  if (!mx_mbox_open(m, ((flags & MUTT_CLI_RO) || c_read_only) ? MUTT_READONLY : MUTT_OPEN_NO_FLAGS))
1380  {
1381  if (m->account)
1383 
1384  mailbox_free(&m);
1385  mutt_error(_("Unable to open mailbox %s"), mutt_buffer_string(&folder));
1386  repeat_error = false;
1387  }
1388  if (m || !explicit_folder)
1389  {
1390  struct MuttWindow *dlg = index_pager_init();
1391  dialog_push(dlg);
1392 
1393  struct EventMailbox ev_m = { m };
1394  mutt_debug(LL_NOTIFY, "NT_MAILBOX_SWITCH: %p\n", m);
1396 
1397  mutt_index_menu(dlg, m);
1398  dialog_pop();
1399  mutt_window_free(&dlg);
1400  log_queue_empty();
1401  repeat_error = false;
1402  }
1403 #ifdef USE_IMAP
1404  imap_logout_all();
1405 #endif
1406 #ifdef USE_SASL
1407  mutt_sasl_done();
1408 #endif
1409 #ifdef USE_AUTOCRYPT
1411 #endif
1412  // TEST43: neomutt (no change to mailbox)
1413  // TEST44: neomutt (change mailbox)
1414  }
1415 
1416 main_ok:
1417  rc = 0;
1418 main_curses:
1419  mutt_endwin();
1421  /* Repeat the last message to the user */
1422  if (repeat_error && ErrorBufMessage)
1423  puts(ErrorBuf);
1424 main_exit:
1426  mutt_buffer_dealloc(&folder);
1427  mutt_buffer_dealloc(&expanded_infile);
1428  mutt_buffer_dealloc(&tempfile);
1429  mutt_list_free(&queries);
1431  rootwin_free();
1436  menu_cleanup();
1437  crypt_cleanup();
1438  mutt_opts_free();
1439  subjrx_free();
1440  attach_free();
1441  alternates_free();
1442  mutt_keys_free();
1444  mutt_prex_free();
1446  cs_free(&cs);
1448  log_queue_empty();
1449  mutt_log_stop();
1450  return rc;
1451 }
#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:904
enum UrlScheme url_check_scheme(const char *str)
Check the protocol of a URL.
Definition: url.c:221
Convenience wrapper for the gui headers.
int mx_path_is_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1247
The "current" mailbox.
Definition: context.h:37
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:240
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:244
void mutt_colors_init(void)
Initialize colours.
Definition: color.c:393
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
Container for lots of config items.
Definition: set.h:259
Manage keymappings.
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
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:284
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
void crypt_cleanup(void)
Clean up backend.
Definition: cryptglue.c:143
A postponed Email, just the envelope info.
Definition: header.h:42
Config/command parsing.
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
struct Body * body
List of MIME parts.
Definition: email.h:91
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: browser.c:160
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:444
Log of notifications.
Definition: logging.h:45
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
Structs that make up an email.
#define mutt_error(...)
Definition: logging.h:88
The "currently-open" mailbox.
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.
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:50
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:56
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe() -.
Definition: pop.c:1165
bool mutt_ts_capability(void)
Check terminal capabilities.
Definition: terminal.c:55
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 -This log dispatcher saves a line ...
Definition: logging.c:400
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:668
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1108
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
NeoMutt Logging.
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
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
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
log_dispatcher_t MuttLogger
The log dispatcher -This function pointer controls where log messages are redirected.
Definition: logging.c:52
void neomutt_free(struct NeoMutt **ptr)
Free a NeoMutt.
Definition: neomutt.c:64
String manipulation buffer.
Definition: buffer.h:33
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:480
#define _(a)
Definition: message.h:28
void km_init(void)
Initialise all the menu keybindings.
Definition: keymap.c:1017
int debug_all_observer(struct NotifyCallback *nc)
Definition: notify.c:318
struct Body * next
next attachment in the list
Definition: body.h:53
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:47
Definition: logging.h:47
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
Alternate address handling.
Log informational message.
Definition: logging.h:39
WHERE char ErrorBuf[256]
Copy of the last error message.
Definition: mutt_globals.h:43
struct Mailbox * mutt_mailbox_next(struct Mailbox *m_cur, struct Buffer *s)
incoming folders completion routine
Definition: mutt_mailbox.c:314
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1275
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:190
uint16_t SendFlags
Flags for mutt_send_message(), e.g. SEND_REPLY.
Definition: send.h:36
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:44
#define mutt_perror(...)
Definition: logging.h:89
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:39
#define CSR_RESULT(x)
Definition: set.h:52
void imap_logout_all(void)
close all open connections
Definition: imap.c:564
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:45
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:1024
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:134
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:200
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:39
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:256
WHERE char * Username
User&#39;s login name.
Definition: mutt_globals.h:48
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:346
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: keymap.c:988
#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:529
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:863
void mutt_signal_init(void)
Initialise the signal handling.
Definition: mutt_signal.c:140
static bool get_user_info(struct ConfigSet *cs)
Find the user&#39;s name, home and shell.
Definition: main.c:439
struct ConfigSet * cs_new(size_t size)
Create a new Config Set.
Definition: set.c:156
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
struct Mailbox * mailbox
Definition: context.h:49
int main_hist_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: mutt_history.c:61
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:1243
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:1612
int main_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: keymap.c:871
int cs_he_initial_set(const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:416
API for mailboxes.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
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:282
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:1738
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:1088
struct MyVarList MyVars
List of all the user&#39;s custom config variables.
Definition: myvar.c:34
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2125
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:245
#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
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2402
int cs_str_initial_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:458
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:105
Email Aliases.
Subject Regex handling.
int main_log_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: mutt_logging.c:321
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:189
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1017
void rootwin_new(void)
Create the default Windows.
Definition: rootwin.c:186
static int start_curses(void)
Start the curses or slang UI.
Definition: main.c:366
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:58
void test_parse_set(void)
Test the config parsing.
Definition: parse_test.c:39
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 -This log dispatcher saves a line of te...
Definition: logging.c:441
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:246
void mutt_autocrypt_cleanup(void)
Shutdown Autocrypt.
Definition: autocrypt.c:141
void mutt_init_abort_key(void)
Parse the abort_key config string.
Definition: keymap.c:849
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:1063
int mutt_autocrypt_init(struct Mailbox *m, bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:98
int mutt_init(struct ConfigSet *cs, bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:715
&#39;POP3&#39; Mailbox type
Definition: mailbox.h:55
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:422
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:162
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1743
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:40
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:137
#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:161
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:243
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1406
void init_config(struct ConfigSet *cs)
Initialise the config system.
Definition: mutt_config.c:770
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:484
char * data
Pointer to data.
Definition: buffer.h:35
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:63
Nntp-specific Mailbox data.
void subjrx_init(void)
Create new Subject Regex List.
Definition: subjectrx.c:55
POP network mailbox.
Not object-related, NotifyGlobal.
Definition: notify_type.h:45
bool dump_config(struct ConfigSet *cs, ConfigDumpFlags flags, FILE *fp)
Write all the config to a file.
Definition: dump.c:165
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
struct Mailbox * mutt_index_menu(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails.
Definition: dlg_index.c:1035
API for encryption/signing of emails.
Ask the user a question.
void myvar_set(const char *var, const char *val)
Set the value of a "my_" variable.
Definition: myvar.c:109
#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:221
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:94
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
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
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
void mutt_opts_free(void)
clean up before quitting
Definition: init.c:638
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:1385
WHERE char * LastFolder
Previously selected mailbox.
Definition: mutt_globals.h:51
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:49
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
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:42
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:37
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:279
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:241
struct Connection * conn
Definition: adata.h:63
void cs_free(struct ConfigSet **ptr)
Free a Config Set.
Definition: set.c:170
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:322
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:1305
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:293
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:342
void mutt_sasl_done(void)
Invoke when processing is complete.
Definition: sasl.c:779
Current Mailbox has changed.
Definition: mailbox.h:182
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:411
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:139
uint16_t ConfigDumpFlags
Flags for dump_config(), e.g. CS_DUMP_ONLY_CHANGED.
Definition: dump.h:32
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe() -.
Definition: nntp.c:2709
void alternates_init(void)
Set up the alternates lists.
Definition: alternates.c:61
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: mutt_globals.h:50
void show_backtrace(void)
Log the program&#39;s call stack.
Definition: backtrace.c:39
Connection Library.
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:126
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1254
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:248
#define mutt_message(...)
Definition: logging.h:87
#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:95
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:48
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mxapi.h:60
Url is mailto://.
Definition: url.h:45
#define STAILQ_EMPTY(head)
Definition: queue.h:348
void subjrx_free(void)
Free the Subject Regex List.
Definition: subjectrx.c:46
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:78
void mutt_commands_cleanup(void)
Clean up commands globals.
Definition: commands.c:95
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
void attach_free(void)
Free the attachments lists.
Definition: attachments.c:92
The item stored in a Hash Table.
Definition: hash.h:43
int cs_str_native_set(const struct ConfigSet *cs, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: set.c:737
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:211
int cs_str_reset(const struct ConfigSet *cs, const char *name, struct Buffer *err)
Reset a config item to its initial value.
Definition: set.c:393
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
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:42
void attach_init(void)
Set up the attachments lists.
Definition: attachments.c:106
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void mutt_buffer_pool_free(void)
Release the Buffer pool.
Definition: pool.c:87
void rootwin_set_size(int cols, int rows)
Set the dimensions of the Root Window.
Definition: rootwin.c:222
void alternates_free(void)
Free the alternates lists.
Definition: alternates.c:50
bool OptLocales
(pseudo) set if user has valid locale definition
Definition: mbyte.c:43
Nntp-specific Account data.
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
int main(int argc, char *argv[], char *envp[])
Start NeoMutt.
Definition: main.c:510
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:559
GUI manage the main index (list of emails)
Miscellaneous email parsing routines.
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:204
&#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:44
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
rfc2047 encode the content-descriptions
Definition: send.c:1573
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:242
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:58
Mailbox helper functions.
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:736
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:574
void rootwin_free(void)
Free all the default Windows.
Definition: rootwin.c:176
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:45
The header of an Email.
Definition: envelope.h:54
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1476
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
void print_copyright(void)
Print copyright message.
Definition: version.c:541