NeoMutt  2019-11-11
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/mutt.h"
49 #include "address/lib.h"
50 #include "config/lib.h"
51 #include "email/lib.h"
52 #include "core/lib.h"
53 #include "conn/conn.h"
54 #include "mutt.h"
55 #include "alias.h"
56 #include "browser.h"
57 #include "color.h"
58 #include "context.h"
59 #include "curs_lib.h"
60 #include "globals.h"
61 #include "hook.h"
62 #include "index.h"
63 #include "keymap.h"
64 #include "mutt_attach.h"
65 #include "mutt_commands.h"
66 #include "mutt_curses.h"
67 #include "mutt_history.h"
68 #include "mutt_logging.h"
69 #include "mutt_mailbox.h"
70 #include "mutt_menu.h"
71 #include "mutt_window.h"
72 #include "muttlib.h"
73 #include "mx.h"
74 #include "myvar.h"
75 #include "ncrypt/ncrypt.h"
76 #include "options.h"
77 #include "protos.h"
78 #include "send.h"
79 #include "sendlib.h"
80 #include "terminal.h"
81 #include "version.h"
82 #ifdef ENABLE_NLS
83 #include <libintl.h>
84 #endif
85 #ifdef USE_SIDEBAR
86 #include "sidebar.h"
87 #endif
88 #ifdef USE_IMAP
89 #include "imap/imap.h"
90 #endif
91 #ifdef USE_NNTP
92 #include "nntp/nntp.h"
93 #endif
94 #ifdef USE_AUTOCRYPT
95 #include "autocrypt/autocrypt.h"
96 #endif
97 
98 /* These Config Variables are only used in main.c */
100 
101 // clang-format off
102 typedef uint8_t CliFlags;
103 #define MUTT_CLI_NO_FLAGS 0
104 #define MUTT_CLI_IGNORE (1 << 0)
105 #define MUTT_CLI_MAILBOX (1 << 1)
106 #define MUTT_CLI_NOSYSRC (1 << 2)
107 #define MUTT_CLI_RO (1 << 3)
108 #define MUTT_CLI_SELECT (1 << 4)
109 #ifdef USE_NNTP
110 #define MUTT_CLI_NEWS (1 << 5)
111 #endif
112 // clang-format on
113 
117 static void test_parse_set(void)
118 {
119  const char *vars[] = {
120  "from", // ADDRESS
121  "beep", // BOOL
122  "ispell", // COMMAND
123  "mbox_type", // MAGIC
124  "to_chars", // MBTABLE
125  "net_inc", // NUMBER
126  "signature", // PATH
127  "print", // QUAD
128  "mask", // REGEX
129  "sort", // SORT
130  "attribution", // STRING
131  "zzz", // UNKNOWN
132  "my_var", // MY_VAR
133  };
134 
135  const char *commands[] = {
136  "set",
137  "toggle",
138  "reset",
139  "unset",
140  };
141 
142  const char *tests[] = {
143  "%s %s", "%s %s=42", "%s %s?", "%s ?%s", "%s ?%s=42",
144  "%s ?%s?", "%s no%s", "%s no%s=42", "%s no%s?", "%s inv%s",
145  "%s inv%s=42", "%s inv%s?", "%s &%s", "%s &%s=42", "%s &%s?",
146  };
147 
148  struct Buffer tmp = mutt_buffer_make(256);
149  struct Buffer err = mutt_buffer_make(256);
150  char line[64];
151 
152  for (size_t v = 0; v < mutt_array_size(vars); v++)
153  {
154  // printf("--------------------------------------------------------------------------------\n");
155  // printf("VARIABLE %s\n", vars[v]);
156  for (size_t c = 0; c < mutt_array_size(commands); c++)
157  {
158  // printf("----------------------------------------\n");
159  // printf("COMMAND %s\n", commands[c]);
160  for (size_t t = 0; t < mutt_array_size(tests); t++)
161  {
162  mutt_buffer_reset(&tmp);
163  mutt_buffer_reset(&err);
164 
165  snprintf(line, sizeof(line), tests[t], commands[c], vars[v]);
166  printf("%-26s", line);
167  enum CommandResult rc = mutt_parse_rc_line(line, &tmp, &err);
168  printf("%2d %s\n", rc, err.data);
169  }
170  printf("\n");
171  }
172  // printf("\n");
173  }
174 
175  mutt_buffer_dealloc(&tmp);
176  mutt_buffer_dealloc(&err);
177 }
178 
182 static void reset_tilde(struct ConfigSet *cs)
183 {
184  static const char *names[] = {
185  "alias_file", "certificate_file", "debug_file",
186  "folder", "history_file", "mbox",
187  "newsrc", "news_cache_dir", "postponed",
188  "record", "signature",
189  };
190 
191  struct Buffer value = mutt_buffer_make(256);
192  for (size_t i = 0; i < mutt_array_size(names); i++)
193  {
194  struct HashElem *he = cs_get_elem(cs, names[i]);
195  if (!he)
196  continue;
197  mutt_buffer_reset(&value);
198  cs_he_initial_get(cs, he, &value);
199  mutt_expand_path(value.data, value.dsize);
200  cs_he_initial_set(cs, he, value.data, NULL);
201  cs_he_reset(cs, he, NULL);
202  }
203  mutt_buffer_dealloc(&value);
204 }
205 
210 void mutt_exit(int code)
211 {
212  clear();
213  refresh();
214  mutt_endwin();
215  exit(code);
216 }
217 
218 // clang-format off
222 static void usage(void)
223 {
224  puts(mutt_make_version());
225 
226  /* L10N: Try to limit to 80 columns */
227  puts(_("usage:\n"
228  " neomutt [-Enx] [-e <command>] [-F <config>] [-H <draft>] [-i <include>]\n"
229  " [-b <address>] [-c <address>] [-s <subject>] [-a <file> [...] --]\n"
230  " <address> [...]\n"
231  " neomutt [-nx] [-e <command>] [-F <config>] [-b <address>] [-c <address>]\n"
232  " [-s <subject>] [-a <file> [...] --] <address> [...] < message\n"
233  " neomutt [-nRy] [-e <command>] [-F <config>] [-f <mailbox>] [-m <type>]\n"
234  " neomutt [-n] [-e <command>] [-F <config>] -A <alias>\n"
235  " neomutt [-n] [-e <command>] [-F <config>] -B\n"
236  " neomutt [-n] [-e <command>] [-F <config>] -D [-S]\n"
237  " neomutt [-n] [-e <command>] [-F <config>] -d <level> -l <file>\n"
238  " neomutt [-n] [-e <command>] [-F <config>] -G\n"
239  " neomutt [-n] [-e <command>] [-F <config>] -g <server>\n"
240  " neomutt [-n] [-e <command>] [-F <config>] -p\n"
241  " neomutt [-n] [-e <command>] [-F <config>] -Q <variable>\n"
242  " neomutt [-n] [-e <command>] [-F <config>] -Z\n"
243  " neomutt [-n] [-e <command>] [-F <config>] -z [-f <mailbox>]\n"
244  " neomutt -v[v]\n"));
245 
246  /* L10N: Try to limit to 80 columns. If more space is needed add an indented line */
247  puts(_("options:\n"
248  " -- Special argument forces NeoMutt to stop option parsing and treat\n"
249  " remaining arguments as addresses even if they start with a dash\n"
250  " -A <alias> Print an expanded version of the given alias to stdout and exit\n"
251  " -a <file> Attach one or more files to a message (must be the last option)\n"
252  " Add any addresses after the '--' argument\n"
253  " -B Run in batch mode (do not start the ncurses UI)\n"
254  " -b <address> Specify a blind carbon copy (Bcc) recipient\n"
255  " -c <address> Specify a carbon copy (Cc) recipient\n"
256  " -D Dump all config variables as 'name=value' pairs to stdout\n"
257  " -D -S Like -D, but hide the value of sensitive variables\n"
258  " -d <level> Log debugging output to a file (default is \"~/.neomuttdebug0\")\n"
259  " The level can range from 1-5 and affects verbosity\n"
260  " -E Edit draft (-H) or include (-i) file during message composition\n"
261  " -e <command> Specify a command to be run after reading the config files\n"
262  " -F <config> Specify an alternative initialization file to read\n"
263  " -f <mailbox> Specify a mailbox (as defined with 'mailboxes' command) to load\n"
264  " -G Start NeoMutt with a listing of subscribed newsgroups\n"
265  " -g <server> Like -G, but start at specified news server\n"
266  " -H <draft> Specify a draft file with header and body for message composing\n"
267  " -h Print this help message and exit\n"
268  " -i <include> Specify an include file to be embedded in the body of a message\n"
269  " -l <file> Specify a file for debugging output (default \"~/.neomuttdebug0\")\n"
270  " -m <type> Specify a default mailbox format type for newly created folders\n"
271  " The type is either MH, MMDF, Maildir or mbox (case-insensitive)\n"
272  " -n Do not read the system-wide configuration file\n"
273  " -p Resume a prior postponed message, if any\n"
274  " -Q <variable> Query a configuration variable and print its value to stdout\n"
275  " (after the config has been read and any commands executed)\n"
276  " -R Open mailbox in read-only mode\n"
277  " -s <subject> Specify a subject (must be enclosed in quotes if it has spaces)\n"
278  " -v Print the NeoMutt version and compile-time definitions and exit\n"
279  " -vv Print the NeoMutt license and copyright information and exit\n"
280  " -x Simulate the mailx(1) send mode\n"
281  " -y Start NeoMutt with a listing of all defined mailboxes\n"
282  " -Z Open the first mailbox with new message or exit immediately with\n"
283  " exit code 1 if none is found in all defined mailboxes\n"
284  " -z Open the first or specified (-f) mailbox if it holds any message\n"
285  " or exit immediately with exit code 1 otherwise"));
286 }
287 // clang-format on
288 
294 static int start_curses(void)
295 {
296  km_init(); /* must come before mutt_init */
297 
298 #ifdef USE_SLANG_CURSES
299  SLtt_Ignore_Beep = 1; /* don't do that #*$@^! annoying visual beep! */
300  SLsmg_Display_Eight_Bit = 128; /* characters above this are printable */
301  SLtt_set_color(0, NULL, "default", "default");
302 #if SLANG_VERSION >= 20000
303  SLutf8_enable(-1);
304 #endif
305 #else
306  /* should come before initscr() so that ncurses 4.2 doesn't try to install
307  * its own SIGWINCH handler */
309 #endif
310  if (!initscr())
311  {
312  mutt_error(_("Error initializing terminal"));
313  return 1;
314  }
315  /* slang requires the signal handlers to be set after initializing */
318  keypad(stdscr, true);
319  cbreak();
320  noecho();
321  nonl();
322 #ifdef HAVE_TYPEAHEAD
323  typeahead(-1); /* simulate smooth scrolling */
324 #endif
325 #ifdef HAVE_META
326  meta(stdscr, true);
327 #endif
329  /* Now that curses is set up, we drop back to normal screen mode.
330  * This simplifies displaying error messages to the user.
331  * The first call to refresh() will swap us back to curses screen mode. */
332  endwin();
333  return 0;
334 }
335 
339 static void init_locale(void)
340 {
341  setlocale(LC_ALL, "");
342 
343 #ifdef ENABLE_NLS
344  const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
345  if (domdir)
346  bindtextdomain(PACKAGE, domdir);
347  else
348  bindtextdomain(PACKAGE, MUTTLOCALEDIR);
349  textdomain(PACKAGE);
350 #endif
351 #ifndef LOCALES_HACK
352  /* Do we have a locale definition? */
353  if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
354  {
355  OptLocales = true;
356  }
357 #endif
358 }
359 
367 bool get_user_info(struct ConfigSet *cs)
368 {
371 
372  const char *shell = mutt_str_getenv("SHELL");
373  if (shell)
374  cs_str_initial_set(cs, "shell", shell, NULL);
375 
376  /* Get some information about the user */
377  struct passwd *pw = getpwuid(getuid());
378  if (pw)
379  {
380  if (!Username)
381  Username = mutt_str_strdup(pw->pw_name);
382  if (!HomeDir)
383  HomeDir = mutt_str_strdup(pw->pw_dir);
384  if (!shell)
385  cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
386  }
387 
388  if (!Username)
389  {
390  mutt_error(_("unable to determine username"));
391  return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
392  }
393 
394  if (!HomeDir)
395  {
396  mutt_error(_("unable to determine home directory"));
397  return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
398  }
399 
400  cs_str_reset(cs, "shell", NULL);
401  return true;
402 }
403 
412 int main(int argc, char *argv[], char *envp[])
413 {
414  char *subject = NULL;
415  char *include_file = NULL;
416  char *draft_file = NULL;
417  char *new_magic = NULL;
418  char *dlevel = NULL;
419  char *dfile = NULL;
420 #ifdef USE_NNTP
421  char *cli_nntp = NULL;
422 #endif
423  struct Email *e = NULL;
424  struct ListHead attach = STAILQ_HEAD_INITIALIZER(attach);
425  struct ListHead commands = STAILQ_HEAD_INITIALIZER(commands);
426  struct ListHead queries = STAILQ_HEAD_INITIALIZER(queries);
427  struct ListHead alias_queries = STAILQ_HEAD_INITIALIZER(alias_queries);
428  struct ListHead cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
429  struct ListHead bcc_list = STAILQ_HEAD_INITIALIZER(bcc_list);
430  SendFlags sendflags = SEND_NO_FLAGS;
431  CliFlags flags = MUTT_CLI_NO_FLAGS;
432  int version = 0;
433  int i;
434  bool explicit_folder = false;
435  bool dump_variables = false;
436  bool hide_sensitive = false;
437  bool batch_mode = false;
438  bool edit_infile = false;
439  bool test_config = false;
440  extern char *optarg;
441  extern int optind;
442  int double_dash = argc, nargc = 1;
443  int rc = 1;
444  bool repeat_error = false;
445  struct Buffer folder = mutt_buffer_make(0);
446  struct Buffer expanded_infile = mutt_buffer_make(0);
447  struct Buffer tempfile = mutt_buffer_make(0);
448 
450 
451  /* sanity check against stupid administrators */
452  if (getegid() != getgid())
453  {
454  mutt_error("%s: I don't want to run with privileges!", argv[0]);
455  goto main_exit; // TEST01: neomutt (as root, chgrp mail neomutt; chmod +s neomutt)
456  }
457 
458  init_locale();
459 
460  int out = 0;
461  if (mutt_randbuf(&out, sizeof(out)) < 0)
462  goto main_exit; // TEST02: neomutt (as root on non-Linux OS, rename /dev/urandom)
463 
464  umask(077);
465 
466  mutt_envlist_init(envp);
467  for (optind = 1; optind < double_dash;)
468  {
469  /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
470  * encounters a non-option. That could be a file to attach
471  * (all non-options between -a and --) or it could be an address
472  * (which gets collapsed to the front of argv). */
473  for (; optind < argc; optind++)
474  {
475  if ((argv[optind][0] == '-') && (argv[optind][1] != '\0'))
476  {
477  if ((argv[optind][1] == '-') && (argv[optind][2] == '\0'))
478  double_dash = optind; /* quit outer loop after getopt */
479  break; /* drop through to getopt */
480  }
481 
482  /* non-option, either an attachment or address */
483  if (!STAILQ_EMPTY(&attach))
484  mutt_list_insert_tail(&attach, mutt_str_strdup(argv[optind]));
485  else
486  argv[nargc++] = argv[optind];
487  }
488 
489  /* USE_NNTP 'g:G' */
490  i = getopt(argc, argv, "+A:a:Bb:F:f:c:Dd:l:Ee:g:GH:i:hm:npQ:RSs:TvxyzZ");
491  if (i != EOF)
492  {
493  switch (i)
494  {
495  case 'A':
496  mutt_list_insert_tail(&alias_queries, mutt_str_strdup(optarg));
497  break;
498  case 'a':
499  mutt_list_insert_tail(&attach, mutt_str_strdup(optarg));
500  break;
501  case 'B':
502  batch_mode = true;
503  break;
504  case 'b':
505  mutt_list_insert_tail(&bcc_list, mutt_str_strdup(optarg));
506  break;
507  case 'c':
508  mutt_list_insert_tail(&cc_list, mutt_str_strdup(optarg));
509  break;
510  case 'D':
511  dump_variables = true;
512  break;
513  case 'd':
514  dlevel = optarg;
515  break;
516  case 'E':
517  edit_infile = true;
518  break;
519  case 'e':
520  mutt_list_insert_tail(&commands, mutt_str_strdup(optarg));
521  break;
522  case 'F':
523  mutt_list_insert_tail(&Muttrc, mutt_str_strdup(optarg));
524  break;
525  case 'f':
526  mutt_buffer_strcpy(&folder, optarg);
527  explicit_folder = true;
528  break;
529 #ifdef USE_NNTP
530  case 'g': /* Specify a news server */
531  cli_nntp = optarg;
532  /* fallthrough */
533  case 'G': /* List of newsgroups */
534  flags |= MUTT_CLI_SELECT | MUTT_CLI_NEWS;
535  break;
536 #endif
537  case 'H':
538  draft_file = optarg;
539  break;
540  case 'i':
541  include_file = optarg;
542  break;
543  case 'l':
544  dfile = optarg;
545  break;
546  case 'm':
547  new_magic = optarg;
548  break;
549  case 'n':
550  flags |= MUTT_CLI_NOSYSRC;
551  break;
552  case 'p':
553  sendflags |= SEND_POSTPONED;
554  break;
555  case 'Q':
556  mutt_list_insert_tail(&queries, mutt_str_strdup(optarg));
557  break;
558  case 'R':
559  flags |= MUTT_CLI_RO; /* read-only mode */
560  break;
561  case 'S':
562  hide_sensitive = true;
563  break;
564  case 's':
565  subject = optarg;
566  break;
567  case 'T':
568  test_config = true;
569  break;
570  case 'v':
571  version++;
572  break;
573  case 'x': /* mailx compatible send mode */
574  sendflags |= SEND_MAILX;
575  break;
576  case 'y': /* My special hack mode */
577  flags |= MUTT_CLI_SELECT;
578  break;
579  case 'Z':
581  break;
582  case 'z':
583  flags |= MUTT_CLI_IGNORE;
584  break;
585  default:
586  usage();
587  OptNoCurses = true;
588  goto main_ok; // TEST03: neomutt -9
589  }
590  }
591  }
592 
593  /* collapse remaining argv */
594  while (optind < argc)
595  argv[nargc++] = argv[optind++];
596  optind = 1;
597  argc = nargc;
598 
599  if (version > 0)
600  {
602  if (version == 1)
603  print_version(stdout);
604  else
605  print_copyright();
606  OptNoCurses = true;
607  goto main_ok; // TEST04: neomutt -v
608  }
609 
610  Config = init_config(500);
611  if (!Config)
612  goto main_curses;
614 
616 
617  if (!get_user_info(Config))
618  goto main_exit;
619 
620  if (test_config)
621  {
622  cs_str_initial_set(Config, "from", "rich@flatcap.org", NULL);
623  cs_str_reset(Config, "from", NULL);
624  myvar_set("my_var", "foo");
625  test_parse_set();
626  goto main_ok;
627  }
628 
630 
631  if (dfile)
632  {
633  cs_str_initial_set(Config, "debug_file", dfile, NULL);
634  cs_str_reset(Config, "debug_file", NULL);
635  }
636 
637  if (dlevel)
638  {
639  short num = 0;
640  if ((mutt_str_atos(dlevel, &num) < 0) || (num < LL_MESSAGE) || (num >= LL_MAX))
641  {
642  mutt_error(_("Error: value '%s' is invalid for -d"), dlevel);
643  goto main_exit; // TEST07: neomutt -d xyz
644  }
645  cs_str_initial_set(Config, "debug_level", dlevel, NULL);
646  cs_str_reset(Config, "debug_level", NULL);
647  }
648 
649  mutt_log_prep();
650  if (dlevel)
651  mutt_log_start();
652 
654 
655  if (!STAILQ_EMPTY(&cc_list) || !STAILQ_EMPTY(&bcc_list))
656  {
657  e = email_new();
658  e->env = mutt_env_new();
659 
660  struct ListNode *np = NULL;
661  STAILQ_FOREACH(np, &bcc_list, entries)
662  {
663  mutt_addrlist_parse(&e->env->bcc, np->data);
664  }
665 
666  STAILQ_FOREACH(np, &cc_list, entries)
667  {
668  mutt_addrlist_parse(&e->env->cc, np->data);
669  }
670 
671  mutt_list_free(&bcc_list);
672  mutt_list_free(&cc_list);
673  }
674 
675  /* Check for a batch send. */
676  if (!isatty(0) || !STAILQ_EMPTY(&queries) || !STAILQ_EMPTY(&alias_queries) ||
677  dump_variables || batch_mode)
678  {
679  OptNoCurses = true;
680  sendflags = SEND_BATCH;
683  }
684 
685  /* Always create the mutt_windows because batch mode has some shared code
686  * paths that end up referencing them. */
688 
689  /* This must come before mutt_init() because curses needs to be started
690  * before calling the init_pair() function to set the color scheme. */
691  if (!OptNoCurses)
692  {
693  int crc = start_curses();
694 
695  if (crc != 0)
696  goto main_curses; // TEST08: can't test -- fake term?
697 
698  /* check whether terminal status is supported (must follow curses init) */
701  }
702 
703  /* set defaults and read init files */
704  int rc2 = mutt_init(flags & MUTT_CLI_NOSYSRC, &commands);
705  mutt_list_free(&commands);
706  if (rc2 != 0)
707  goto main_curses;
708 
709  /* The command line overrides the config */
710  if (dlevel)
711  cs_str_reset(Config, "debug_level", NULL);
712  if (dfile)
713  cs_str_reset(Config, "debug_file", NULL);
714 
715  if (mutt_log_start() < 0)
716  {
717  mutt_perror("log file");
718  goto main_exit;
719  }
720 
721 #ifdef USE_NNTP
722  /* "$news_server" precedence: command line, config file, environment, system file */
723  if (cli_nntp)
724  cs_str_string_set(Config, "news_server", cli_nntp, NULL);
725  if (!C_NewsServer)
726  {
727  const char *env_nntp = mutt_str_getenv("NNTPSERVER");
728  cs_str_string_set(Config, "news_server", env_nntp, NULL);
729  }
730  if (!C_NewsServer)
731  {
732  char buf[1024];
733  char *server = mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buf, sizeof(buf));
734  cs_str_string_set(Config, "news_server", server, NULL);
735  }
736  if (C_NewsServer)
737  cs_str_initial_set(Config, "news_server", C_NewsServer, NULL);
738 #endif
739 
740  /* Initialize crypto backends. */
741  crypt_init();
742 
743  if (new_magic)
744  {
745  struct Buffer err = mutt_buffer_make(0);
746  int r = cs_str_initial_set(Config, "mbox_type", new_magic, &err);
747  if (CSR_RESULT(r) != CSR_SUCCESS)
748  {
749  mutt_error(err.data);
750  mutt_buffer_dealloc(&err);
751  goto main_curses;
752  }
753  cs_str_reset(Config, "mbox_type", NULL);
754  }
755 
756  if (!STAILQ_EMPTY(&queries))
757  {
758  rc = mutt_query_variables(&queries);
759  goto main_curses;
760  }
761 
762  if (dump_variables)
763  {
764  dump_config(Config, hide_sensitive ? CS_DUMP_HIDE_SENSITIVE : CS_DUMP_NO_FLAGS, stdout);
765  goto main_ok; // TEST18: neomutt -D
766  }
767 
768  if (!STAILQ_EMPTY(&alias_queries))
769  {
770  rc = 0;
771  for (; optind < argc; optind++)
772  mutt_list_insert_tail(&alias_queries, mutt_str_strdup(argv[optind]));
773  struct ListNode *np = NULL;
774  STAILQ_FOREACH(np, &alias_queries, entries)
775  {
776  struct AddressList *al = mutt_alias_lookup(np->data);
777  if (al)
778  {
779  /* output in machine-readable form */
780  mutt_addrlist_to_intl(al, NULL);
781  mutt_write_addrlist(al, stdout, 0, 0);
782  }
783  else
784  {
785  rc = 1;
786  printf("%s\n", np->data); // TEST19: neomutt -A unknown
787  }
788  }
789  mutt_list_free(&alias_queries);
790  goto main_curses; // TEST20: neomutt -A alias
791  }
792 
793  if (!OptNoCurses)
794  {
796  clear();
800  }
801 
802  /* Initialize autocrypt after curses messages are working,
803  * because of the initial account setup screens. */
804 #ifdef USE_AUTOCRYPT
805  if (C_Autocrypt)
806  mutt_autocrypt_init(!(sendflags & SEND_BATCH));
807 #endif
808 
809  /* Create the C_Folder directory if it doesn't exist. */
810  if (!OptNoCurses && C_Folder)
811  {
812  struct stat sb;
813  struct Buffer *fpath = mutt_buffer_pool_get();
814 
817  bool skip = false;
818 #ifdef USE_IMAP
819  /* we're not connected yet - skip mail folder creation */
820  skip |= (imap_path_probe(mutt_b2s(fpath), NULL) == MUTT_IMAP);
821 #endif
822 #ifdef USE_NNTP
823  skip |= (nntp_path_probe(mutt_b2s(fpath), NULL) == MUTT_NNTP);
824 #endif
825  if (!skip && (stat(mutt_b2s(fpath), &sb) == -1) && (errno == ENOENT))
826  {
827  char msg2[256];
828  snprintf(msg2, sizeof(msg2), _("%s does not exist. Create it?"), C_Folder);
829  if (mutt_yesorno(msg2, MUTT_YES) == MUTT_YES)
830  {
831  if ((mkdir(mutt_b2s(fpath), 0700) == -1) && (errno != EEXIST))
832  mutt_error(_("Can't create %s: %s"), C_Folder, strerror(errno)); // TEST21: neomutt -n -F /dev/null (and ~/Mail doesn't exist)
833  }
834  }
835  mutt_buffer_pool_release(&fpath);
836  }
837 
838  if (batch_mode)
839  {
840  goto main_ok; // TEST22: neomutt -B
841  }
842 
847  if (Colors)
849 
850  if (sendflags & SEND_POSTPONED)
851  {
852  if (!OptNoCurses)
853  mutt_flushinp();
854  if (ci_send_message(SEND_POSTPONED, NULL, NULL, NULL, NULL) == 0)
855  rc = 0;
856  // TEST23: neomutt -p (postponed message, cancel)
857  // TEST24: neomutt -p (no postponed message)
858  log_queue_empty();
859  repeat_error = true;
860  goto main_curses;
861  }
862  else if (subject || e || sendflags || draft_file || include_file ||
863  !STAILQ_EMPTY(&attach) || (optind < argc))
864  {
865  FILE *fp_in = NULL;
866  FILE *fp_out = NULL;
867  char *infile = NULL;
868  char *bodytext = NULL;
869  const char *bodyfile = NULL;
870  int rv = 0;
871 
872  if (!OptNoCurses)
873  mutt_flushinp();
874 
875  if (!e)
876  e = email_new();
877  if (!e->env)
878  e->env = mutt_env_new();
879 
880  for (i = optind; i < argc; i++)
881  {
882  if (url_check_scheme(argv[i]) == U_MAILTO)
883  {
884  if (mutt_parse_mailto(e->env, &bodytext, argv[i]) < 0)
885  {
886  mutt_error(_("Failed to parse mailto: link"));
887  email_free(&e);
888  goto main_curses; // TEST25: neomutt mailto:
889  }
890  }
891  else
892  mutt_addrlist_parse(&e->env->to, argv[i]);
893  }
894 
895  if (!draft_file && C_Autoedit && TAILQ_EMPTY(&e->env->to) &&
896  TAILQ_EMPTY(&e->env->cc))
897  {
898  mutt_error(_("No recipients specified"));
899  email_free(&e);
900  goto main_curses; // TEST26: neomutt -s test (with autoedit=yes)
901  }
902 
903  if (subject)
904  e->env->subject = mutt_str_strdup(subject);
905 
906  if (draft_file)
907  {
908  infile = draft_file;
909  include_file = NULL;
910  }
911  else if (include_file)
912  infile = include_file;
913  else
914  edit_infile = false;
915 
916  if (infile || bodytext)
917  {
918  /* Prepare fp_in and expanded_infile. */
919  if (infile)
920  {
921  if (mutt_str_strcmp("-", infile) == 0)
922  {
923  if (edit_infile)
924  {
925  mutt_error(_("Can't use -E flag with stdin"));
926  email_free(&e);
927  goto main_curses; // TEST27: neomutt -E -H -
928  }
929  fp_in = stdin;
930  }
931  else
932  {
933  mutt_buffer_strcpy(&expanded_infile, infile);
934  mutt_buffer_expand_path(&expanded_infile);
935  fp_in = fopen(mutt_b2s(&expanded_infile), "r");
936  if (!fp_in)
937  {
938  mutt_perror(mutt_b2s(&expanded_infile));
939  email_free(&e);
940  goto main_curses; // TEST28: neomutt -E -H missing
941  }
942  }
943  }
944 
945  /* Copy input to a tempfile, and re-point fp_in to the tempfile.
946  * Note: stdin is always copied to a tempfile, ensuring draft_file
947  * can stat and get the correct st_size below. */
948  if (!edit_infile)
949  {
950  mutt_buffer_mktemp(&tempfile);
951 
952  fp_out = mutt_file_fopen(mutt_b2s(&tempfile), "w");
953  if (!fp_out)
954  {
955  mutt_file_fclose(&fp_in);
956  mutt_perror(mutt_b2s(&tempfile));
957  email_free(&e);
958  goto main_curses; // TEST29: neomutt -H existing-file (where tmpdir=/path/to/FILE blocking tmpdir)
959  }
960  if (fp_in)
961  {
962  mutt_file_copy_stream(fp_in, fp_out);
963  if (fp_in != stdin)
964  mutt_file_fclose(&fp_in);
965  }
966  else if (bodytext)
967  fputs(bodytext, fp_out);
968  mutt_file_fclose(&fp_out);
969 
970  fp_in = fopen(mutt_b2s(&tempfile), "r");
971  if (!fp_in)
972  {
973  mutt_perror(mutt_b2s(&tempfile));
974  email_free(&e);
975  goto main_curses; // TEST30: can't test
976  }
977  }
978  /* If editing the infile, keep it around afterwards so
979  * it doesn't get unlinked, and we can rebuild the draft_file */
980  else
981  sendflags |= SEND_NO_FREE_HEADER;
982 
983  /* Parse the draft_file into the full Email/Body structure.
984  * Set SEND_DRAFT_FILE so ci_send_message doesn't overwrite
985  * our e->content. */
986  if (draft_file)
987  {
988  struct Envelope *opts_env = e->env;
989  struct stat st;
990 
991  sendflags |= SEND_DRAFT_FILE;
992 
993  /* Set up a tmp Email with just enough information so that
994  * mutt_prepare_template() can parse the message in fp_in. */
995  struct Email *e_tmp = email_new();
996  e_tmp->offset = 0;
997  e_tmp->content = mutt_body_new();
998  if (fstat(fileno(fp_in), &st) != 0)
999  {
1000  mutt_perror(draft_file);
1001  email_free(&e);
1002  email_free(&e_tmp);
1003  goto main_curses; // TEST31: can't test
1004  }
1005  e_tmp->content->length = st.st_size;
1006 
1007  if (mutt_prepare_template(fp_in, NULL, e, e_tmp, false) < 0)
1008  {
1009  mutt_error(_("Can't parse message template: %s"), draft_file);
1010  email_free(&e);
1011  email_free(&e_tmp);
1012  goto main_curses;
1013  }
1014 
1015  /* Scan for neomutt header to set C_ResumeDraftFiles */
1016  struct ListNode *np = NULL, *tmp = NULL;
1017  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
1018  {
1019  if (mutt_str_startswith(np->data, "X-Mutt-Resume-Draft:", CASE_IGNORE))
1020  {
1022  cs_str_native_set(Config, "resume_draft_files", true, NULL);
1023 
1024  STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
1025  FREE(&np->data);
1026  FREE(&np);
1027  }
1028  }
1029 
1030  mutt_addrlist_copy(&e->env->to, &opts_env->to, false);
1031  mutt_addrlist_copy(&e->env->cc, &opts_env->cc, false);
1032  mutt_addrlist_copy(&e->env->bcc, &opts_env->bcc, false);
1033  if (opts_env->subject)
1034  mutt_str_replace(&e->env->subject, opts_env->subject);
1035 
1036  mutt_env_free(&opts_env);
1037  email_free(&e_tmp);
1038  }
1039  /* Editing the include_file: pass it directly in.
1040  * Note that SEND_NO_FREE_HEADER is set above so it isn't unlinked. */
1041  else if (edit_infile)
1042  bodyfile = mutt_b2s(&expanded_infile);
1043  /* For bodytext and unedited include_file: use the tempfile.
1044  */
1045  else
1046  bodyfile = mutt_b2s(&tempfile);
1047 
1048  mutt_file_fclose(&fp_in);
1049  }
1050 
1051  FREE(&bodytext);
1052 
1053  if (!STAILQ_EMPTY(&attach))
1054  {
1055  struct Body *b = e->content;
1056 
1057  while (b && b->next)
1058  b = b->next;
1059 
1060  struct ListNode *np = NULL;
1061  STAILQ_FOREACH(np, &attach, entries)
1062  {
1063  if (b)
1064  {
1065  b->next = mutt_make_file_attach(np->data);
1066  b = b->next;
1067  }
1068  else
1069  {
1070  b = mutt_make_file_attach(np->data);
1071  e->content = b;
1072  }
1073  if (!b)
1074  {
1075  mutt_error(_("%s: unable to attach file"), np->data);
1076  mutt_list_free(&attach);
1077  email_free(&e);
1078  goto main_curses; // TEST32: neomutt john@example.com -a missing
1079  }
1080  }
1081  mutt_list_free(&attach);
1082  }
1083 
1084  rv = ci_send_message(sendflags, e, bodyfile, NULL, NULL);
1085  /* We WANT the "Mail sent." and any possible, later error */
1086  log_queue_empty();
1087  if (ErrorBufMessage)
1088  mutt_message("%s", ErrorBuf);
1089 
1090  if (edit_infile)
1091  {
1092  if (include_file)
1093  e->content->unlink = false;
1094  else if (draft_file)
1095  {
1096  if (truncate(mutt_b2s(&expanded_infile), 0) == -1)
1097  {
1098  mutt_perror(mutt_b2s(&expanded_infile));
1099  email_free(&e);
1100  goto main_curses; // TEST33: neomutt -H read-only -s test john@example.com -E
1101  }
1102  fp_out = mutt_file_fopen(mutt_b2s(&expanded_infile), "a");
1103  if (!fp_out)
1104  {
1105  mutt_perror(mutt_b2s(&expanded_infile));
1106  email_free(&e);
1107  goto main_curses; // TEST34: can't test
1108  }
1109 
1110  /* If the message was sent or postponed, these will already
1111  * have been done. */
1112  if (rv < 0)
1113  {
1114  if (e->content->next)
1117  mutt_prepare_envelope(e->env, false);
1118  mutt_env_to_intl(e->env, NULL, NULL);
1119  }
1120 
1122  fp_out, e->env, e->content, MUTT_WRITE_HEADER_POSTPONE, false,
1125  fprintf(fp_out, "X-Mutt-Resume-Draft: 1\n");
1126  fputc('\n', fp_out);
1127  if ((mutt_write_mime_body(e->content, fp_out) == -1))
1128  {
1129  mutt_file_fclose(&fp_out);
1130  email_free(&e);
1131  goto main_curses; // TEST35: can't test
1132  }
1133  mutt_file_fclose(&fp_out);
1134  }
1135 
1136  email_free(&e);
1137  }
1138 
1139  /* !edit_infile && draft_file will leave the tempfile around */
1140  if (!mutt_buffer_is_empty(&tempfile))
1141  unlink(mutt_b2s(&tempfile));
1142 
1144 
1145  if (rv != 0)
1146  goto main_curses; // TEST36: neomutt -H existing -s test john@example.com -E (cancel sending)
1147  }
1148  else
1149  {
1150  if (flags & MUTT_CLI_MAILBOX)
1151  {
1152 #ifdef USE_IMAP
1153  bool passive = C_ImapPassive;
1154  C_ImapPassive = false;
1155 #endif
1156  if (mutt_mailbox_check(Context ? Context->mailbox : NULL, 0) == 0)
1157  {
1158  mutt_message(_("No mailbox with new mail"));
1159  goto main_curses; // TEST37: neomutt -Z (no new mail)
1160  }
1161  mutt_buffer_reset(&folder);
1162  mutt_mailbox_next_buffer(Context ? Context->mailbox : NULL, &folder);
1163 #ifdef USE_IMAP
1164  C_ImapPassive = passive;
1165 #endif
1166  }
1167  else if (flags & MUTT_CLI_SELECT)
1168  {
1169 #ifdef USE_NNTP
1170  if (flags & MUTT_CLI_NEWS)
1171  {
1172  OptNews = true;
1173  CurrentNewsSrv =
1175  if (!CurrentNewsSrv)
1176  goto main_curses; // TEST38: neomutt -G (unset news_server)
1177  }
1178  else
1179 #endif
1180  if (TAILQ_EMPTY(&NeoMutt->accounts))
1181  {
1182  mutt_error(_("No incoming mailboxes defined"));
1183  goto main_curses; // TEST39: neomutt -n -F /dev/null -y
1184  }
1185  mutt_buffer_reset(&folder);
1187  if (mutt_buffer_is_empty(&folder))
1188  {
1189  goto main_ok; // TEST40: neomutt -y (quit selection)
1190  }
1191  }
1192 
1193  if (mutt_buffer_is_empty(&folder))
1194  {
1195  if (C_Spoolfile)
1196  {
1197  // Check if C_Spoolfile corresponds a mailboxes' description.
1198  struct Mailbox *m_desc = mailbox_find_name(C_Spoolfile);
1199  if (m_desc)
1200  mutt_buffer_strcpy(&folder, m_desc->realpath);
1201  else
1202  mutt_buffer_strcpy(&folder, C_Spoolfile);
1203  }
1204  else if (C_Folder)
1205  mutt_buffer_strcpy(&folder, C_Folder);
1206  /* else no folder */
1207  }
1208 
1209 #ifdef USE_NNTP
1210  if (OptNews)
1211  {
1212  OptNews = false;
1213  mutt_buffer_alloc(&folder, PATH_MAX);
1214  nntp_expand_path(folder.data, folder.dsize, &CurrentNewsSrv->conn->account);
1215  }
1216  else
1217 #endif
1218  mutt_buffer_expand_path(&folder);
1219 
1221  mutt_str_replace(&LastFolder, mutt_b2s(&folder));
1222 
1223  if (flags & MUTT_CLI_IGNORE)
1224  {
1225  /* check to see if there are any messages in the folder */
1226  switch (mx_check_empty(mutt_b2s(&folder)))
1227  {
1228  case -1:
1229  mutt_perror(mutt_b2s(&folder));
1230  goto main_curses; // TEST41: neomutt -z -f missing
1231  case 1:
1232  mutt_error(_("Mailbox is empty"));
1233  goto main_curses; // TEST42: neomutt -z -f /dev/null
1234  }
1235  }
1236 
1237  mutt_folder_hook(mutt_b2s(&folder), NULL);
1240 
1241  repeat_error = true;
1242  struct Mailbox *m = mx_path_resolve(mutt_b2s(&folder));
1244  if (!Context)
1245  {
1246  if (m->account)
1247  {
1249  mailbox_free(&m);
1250  m = NULL;
1251  }
1252  else
1253  mailbox_free(&m);
1254  }
1255  if (Context || !explicit_folder)
1256  {
1257 #ifdef USE_SIDEBAR
1259 #endif
1260  mutt_index_menu();
1261  ctx_free(&Context);
1262  }
1263 #ifdef USE_IMAP
1264  imap_logout_all();
1265 #endif
1266 #ifdef USE_SASL
1267  mutt_sasl_done();
1268 #endif
1269 #ifdef USE_AUTOCRYPT
1271 #endif
1272  // TEST43: neomutt (no change to mailbox)
1273  // TEST44: neomutt (change mailbox)
1276  }
1277 
1278 main_ok:
1279  rc = 0;
1280 main_curses:
1281  clear();
1282  refresh();
1283  mutt_endwin();
1286  /* Repeat the last message to the user */
1287  if (repeat_error && ErrorBufMessage)
1288  puts(ErrorBuf);
1289 main_exit:
1290  mutt_buffer_dealloc(&folder);
1291  mutt_buffer_dealloc(&expanded_infile);
1292  mutt_buffer_dealloc(&tempfile);
1293  mutt_list_free(&queries);
1299  mutt_opts_free();
1300  mutt_keys_free();
1303  cs_free(&Config);
1304  log_queue_empty();
1305  mutt_log_stop();
1306  return rc;
1307 }
void mutt_mailbox_next_buffer(struct Mailbox *m_cur, struct Buffer *s)
incoming folders completion routine
Definition: mutt_mailbox.c:290
#define MUTT_OPEN_NO_FLAGS
No flags are set.
Definition: mx.h:50
WHERE char * Username
User&#39;s login name.
Definition: globals.h:54
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:94
The "current" mailbox.
Definition: context.h:36
struct ConfigSet * init_config(size_t size)
Initialise the config system.
Definition: init.c:3778
uint8_t CliFlags
Flags for command line options, e.g. MUTT_CLI_IGNORE.
Definition: main.c:102
struct NntpAccountData * nntp_select_server(struct Mailbox *m, char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:982
#define MUTT_CLI_NOSYSRC
-n Do not read the system-wide config file
Definition: main.c:106
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
Container for lots of config items.
Definition: set.h:187
Manage keymappings.
WHERE bool C_Autocrypt
Config: Enables the Autocrypt feature.
Definition: globals.h:203
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:400
Define wrapper functions around Curses/Slang.
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct AddressList * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:285
int mutt_randbuf(void *buf, size_t buflen)
Fill a buffer with randomness.
Definition: muttlib.c:486
bool C_ResumeEditedDraftFiles
Config: Resume editing previously saved draft files.
Definition: main.c:99
The envelope/body of an email.
Definition: email.h:37
int mutt_log_start(void)
Enable file logging.
Definition: mutt_logging.c:284
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
#define mutt_perror(...)
Definition: logging.h:85
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:33
struct Notify * notify
Notifications system.
Definition: color.h:150
#define CSR_RESULT(x)
Definition: set.h:62
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2430
struct ConnAccount account
Definition: connection.h:36
void mutt_window_init(void)
Create the default Windows.
Definition: mutt_window.c:179
Window management.
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: browser.c:123
GUI miscellaneous curses (window drawing) routines.
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:51
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:1148
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:457
int cs_str_string_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: set.c:627
GUI manage the main index (list of emails)
#define mutt_message(...)
Definition: logging.h:83
int mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1593
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:39
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
#define SEND_DRAFT_FILE
Used by the -H flag.
Definition: send.h:99
static const struct TestValue tests[]
Definition: mutt_str_atoi.c:36
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:49
void mutt_window_free_all(void)
Free all the default Windows.
Definition: mutt_window.c:142
bool mutt_ts_capability(void)
Check terminal capabilities.
Definition: terminal.c:54
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:848
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1082
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:95
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:727
struct Body * content
List of MIME parts.
Definition: email.h:90
void mutt_envlist_init(char *envp[])
Create a copy of the environment.
Definition: envlist.c:55
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
void print_version(FILE *fp)
Print system and compile info to a file.
Definition: version.c:381
void neomutt_free(struct NeoMutt **ptr)
Free a NeoMutt.
Definition: neomutt.c:63
A postponed Email, just the envelope info.
Definition: sendlib.h:61
String manipulation buffer.
Definition: buffer.h:33
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
#define _(a)
Definition: message.h:28
WHERE struct ConfigSet * Config
Wrapper around the user&#39;s config settings.
Definition: globals.h:41
void km_init(void)
Initialise all the menu keybindings.
Definition: keymap.c:927
struct Body * next
next attachment in the list
Definition: body.h:53
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:253
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:46
WHERE char * LastFolder
Previously selected mailbox.
Definition: globals.h:57
Definition: logging.h:63
Log informational message.
Definition: logging.h:55
#define MUTT_READONLY
Open in read-only mode.
Definition: mx.h:53
void mutt_unlink_temp_attachments(void)
Delete all temporary attachments.
Definition: mutt_attach.c:1197
void log_queue_flush(log_dispatcher_t disp)
Replay the log queue.
Definition: logging.c:357
uint16_t SendFlags
Flags for ci_send_message(), e.g. SEND_REPLY.
Definition: send.h:86
log_dispatcher_t MuttLogger
The log dispatcher.
Definition: logging.c:52
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope&#39;s Address fields to Punycode format.
Definition: envelope.c:309
int mutt_str_atos(const char *str, short *dst)
Convert ASCII string to a short.
Definition: string.c:232
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:92
Container for Accounts, Notifications.
Definition: neomutt.h:35
enum UrlScheme url_check_scheme(const char *s)
Check the protocol of a URL.
Definition: url.c:132
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:89
Set the terminal title/icon.
Representation of a single alias to an email address.
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
The body of an email.
Definition: body.h:34
void mutt_prepare_envelope(struct Envelope *env, bool final)
Prepare an email header.
Definition: sendlib.c:3007
#define CS_DUMP_HIDE_SENSITIVE
Obscure sensitive information like passwords.
Definition: dump.h:37
Convenience wrapper for the config headers.
GUI component for displaying/selecting items from a list.
Prepare and send an email.
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: browser.h:47
Hundreds of global variables to back the user variables.
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject)
Write out one RFC822 header line.
Definition: sendlib.c:2334
void imap_logout_all(void)
close all open connections
Definition: imap.c:687
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:1048
Email Address Handling.
#define SEND_NO_FLAGS
No flags are set.
Definition: send.h:87
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition: main.c:182
Some miscellaneous functions.
int cs_str_initial_set(const struct ConfigSet *cs, const char *name, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:487
void init_extended_keys(void)
Initialise map of ncurses extended keys.
Definition: keymap.c:897
#define mutt_array_size(x)
Definition: memory.h:33
int mutt_query_variables(struct ListHead *queries)
Implement the -Q command line flag.
Definition: init.c:3289
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:502
size_t dsize
Length of data.
Definition: buffer.h:37
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:134
bool notify_observer_add(struct Notify *notify, enum NotifyType type, int subtype, observer_t callback, intptr_t data)
Add an observer to an object.
Definition: notify.c:159
void mutt_startup_shutdown_hook(HookFlags type)
Execute any startup/shutdown hooks.
Definition: hook.c:846
#define SEND_MAILX
Send email in Mailx compatibility mode.
Definition: send.h:94
void mutt_signal_init(void)
Initialise the signal handling.
Definition: mutt_signal.c:130
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:375
int mx_check_empty(const char *path)
Is the mailbox empty.
Definition: mx.c:1162
struct Mailbox * mailbox
Definition: context.h:50
Parse and execute user-defined hooks.
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
API for mailboxes.
struct Body * mutt_make_file_attach(const char *path)
Create a file attachment.
Definition: sendlib.c:1651
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:55
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
IMAP network mailbox.
struct Envelope * env
Envelope information.
Definition: email.h:89
Convenience wrapper for the core headers.
struct MyVarList MyVars
List of all the user&#39;s custom config variables.
Definition: myvar.c:34
WHERE char * HomeDir
User&#39;s home directory.
Definition: globals.h:51
int cs_he_reset(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *err)
Reset a config item to its initial value.
Definition: set.c:375
#define MUTT_CLI_RO
-R Open mailbox in read-only mode
Definition: main.c:107
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
WHERE bool C_Autoedit
Config: Skip the initial compose menu and edit the email.
Definition: globals.h:206
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
WHERE char * CurrentFolder
Currently selected mailbox.
Definition: globals.h:56
bool get_user_info(struct ConfigSet *cs)
Find the user&#39;s name, home and shell.
Definition: main.c:367
int log_disp_queue(time_t stamp, const char *file, int line, const char *function, int level,...)
Save a log line to an internal queue - Implements log_dispatcher_t.
Definition: logging.c:409
WHERE bool C_ReadOnly
Config: Open folders in read-only mode.
Definition: globals.h:250
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition: set.c:216
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:360
static int start_curses(void)
Start the curses or slang UI.
Definition: main.c:294
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:46
void mutt_window_reflow(void)
Resize the Windows to fit the screen.
Definition: mutt_window.c:264
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: sendlib.c:1747
Plain text.
Definition: color.h:78
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
#define MUTT_CLI_SELECT
-y Start with a list of all mailboxes
Definition: main.c:108
void myvar_set(const char *var, const char *val)
Set the value of a "my_" variable.
Definition: myvar.c:91
void mutt_autocrypt_cleanup(void)
Shutdown Autocrypt.
Definition: autocrypt.c:127
#define mutt_b2s(buf)
Definition: buffer.h:41
WHERE char * C_NewsServer
Config: (nntp) Url of the news server.
Definition: globals.h:131
int mutt_reply_observer(struct NotifyCallback *nc)
Listen for config changes to "reply_regex" - Implements observer_t()
Definition: index.c:3732
void log_queue_set_max_size(int size)
Set a upper limit for the queue length.
Definition: logging.c:323
Colour has changed.
Definition: notify_type.h:39
Prototypes for many functions.
const char * line
Definition: common.c:36
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:544
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: globals.h:121
struct Mailbox * mailbox_find_name(const char *name)
Find the mailbox with a given name.
Definition: mailbox.c:115
int log_disp_curses(time_t stamp, const char *file, int line, const char *function, int level,...)
Display a log line in the message line - Implements log_dispatcher_t.
Definition: mutt_logging.c:129
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void mutt_keys_free(void)
Free the key maps.
Definition: keymap.c:1601
A mailbox.
Definition: mailbox.h:92
#define PATH_MAX
Definition: mutt.h:50
int mutt_mailbox_check(struct Mailbox *m_cur, int force)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:127
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
WHERE char ErrorBuf[256]
Copy of the last error message.
Definition: globals.h:47
void mutt_encode_descriptions(struct Body *b, bool recurse)
rfc2047 encode the content-descriptions
Definition: send.c:1436
void myvarlist_free(struct MyVarList *list)
Free a List of MyVars.
Definition: myvar.c:131
#define MUTT_CLI_MAILBOX
-Z Open first mailbox if is has new mail
Definition: main.c:105
int mutt_write_mime_body(struct Body *a, FILE *fp)
Write a MIME part.
Definition: sendlib.c:556
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
void log_queue_empty(void)
Free the contents of the queue.
Definition: logging.c:335
char * data
Pointer to data.
Definition: buffer.h:35
WHERE bool ErrorBufMessage
true if the last message was an error
Definition: globals.h:46
Not object-related.
Definition: notify_type.h:32
Mapping from user command name to function.
GUI present the user with a selectable list.
static void test_parse_set(void)
Test the config parsing.
Definition: main.c:117
Ignore case when comparing strings.
Definition: string2.h:68
void mutt_log_stop(void)
Close the log file.
Definition: mutt_logging.c:225
int ci_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el)
Send an email.
Definition: send.c:1868
Handling of email attachments.
API for encryption/signing of emails.
void crypt_init(void)
Initialise the crypto backends.
Definition: cryptglue.c:93
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
int cs_he_initial_get(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *result)
Get the initial, or parent, value of a config item.
Definition: set.c:513
struct Colors * mutt_colors_new(void)
Create new colours.
Definition: color.c:372
struct Notify * notify
Notifications handler.
Definition: neomutt.h:37
Display version and copyright about NeoMutt.
bool TsSupported
Terminal Setting is supported.
Definition: terminal.c:42
int cs_he_initial_set(const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err)
Set the initial value of a config item.
Definition: set.c:446
bool dump_config(struct ConfigSet *cs, ConfigDumpFlags flags, FILE *fp)
Write all the config to a file.
Definition: dump.c:198
WHERE bool C_CryptProtectedHeadersRead
Config: Display protected headers (Memory Hole) in the pager.
Definition: globals.h:279
Definition: color.h:130
Color and attribute parsing.
void mutt_opts_free(void)
clean up before quitting
Definition: init.c:2890
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
void mutt_envlist_free(void)
Free the private copy of the environment.
Definition: envlist.c:40
void mutt_write_addrlist(struct AddressList *al, FILE *fp, int linelen, bool display)
wrapper around mutt_write_address()
Definition: sendlib.c:1797
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
Definition: file.c:1369
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:551
void cs_free(struct ConfigSet **ptr)
Free a Config Set.
Definition: set.c:198
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:98
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
Read/write command history from/to a file.
int cs_str_reset(const struct ConfigSet *cs, const char *name, struct Buffer *err)
Reset a config item to its initial value.
Definition: set.c:423
Config has changed.
Definition: notify_type.h:33
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:45
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:210
#define MUTT_CLI_NO_FLAGS
No flags are set.
Definition: main.c:103
struct Connection * conn
Definition: nntp.h:102
char * data
String.
Definition: list.h:35
char * subject
Email&#39;s subject.
Definition: envelope.h:66
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:343
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:142
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1216
NeoMutt is initialised.
Definition: neomutt.h:49
WHERE char * C_Spoolfile
Config: Inbox.
Definition: globals.h:146
static void usage(void)
Display NeoMutt command line.
Definition: main.c:222
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
Autocrypt end-to-end encryption.
struct Notify * notify
Notifications system.
Definition: set.h:191
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:84
void mutt_sasl_done(void)
Invoke when processing is complete.
Definition: sasl.c:723
#define mutt_error(...)
Definition: logging.h:84
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
static void init_locale(void)
Initialise the Locale/NLS settings.
Definition: main.c:339
WHERE bool C_ImapPassive
Config: (imap) Reuse an existing IMAP connection to check for new mail.
Definition: globals.h:230
Connection Library.
#define MUTT_CLI_NEWS
-g/-G Start with a list of all newsgroups
Definition: main.c:110
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1552
Url is mailto://.
Definition: url.h:44
#define STAILQ_EMPTY(head)
Definition: queue.h:346
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:322
void crypto_module_free(void)
Clean up the crypto modules.
Definition: crypt_mod.c:81
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
int mutt_hist_observer(struct NotifyCallback *nc)
Listen for config changes affecting the history - Implements observer_t()
Definition: mutt_history.c:151
The item stored in a Hash Table.
Definition: hash.h:42
struct Email * email_new(void)
Create a new Email.
Definition: email.c:68
void mutt_log_prep(void)
Prepare to log.
Definition: mutt_logging.c:215
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:49
Handling of global boolean variables.
Miscellaneous functions for sending an email.
#define TAILQ_EMPTY(head)
Definition: queue.h:715
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe()
Definition: nntp.c:2824
void mutt_buffer_pool_free(void)
Release the Buffer pool.
Definition: pool.c:86
int mutt_init(bool skip_sys_rc, struct ListHead *commands)
Initialise NeoMutt.
Definition: init.c:2977
bool OptLocales
(pseudo) set if user has valid locale definition
Definition: mbyte.c:44
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
int main(int argc, char *argv[], char *envp[])
Start NeoMutt.
Definition: main.c:412
int mutt_index_menu(void)
Display a list of emails.
Definition: index.c:1067
A List node for strings.
Definition: list.h:33
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Handling of personal config (&#39;my&#39; variables)
int mutt_log_observer(struct NotifyCallback *nc)
Listen for config changes affecting the log file - Implements observer_t()
Definition: mutt_logging.c:325
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:52
bool notify_send(struct Notify *notify, int type, int subtype, intptr_t data)
Send out a notification message.
Definition: notify.c:145
struct NeoMutt * neomutt_new(struct ConfigSet *cs)
Create the master NeoMutt object.
Definition: neomutt.c:44
Convenience wrapper for the library headers.
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:43
#define MUTT_CLI_IGNORE
-z Open first mailbox if it has mail
Definition: main.c:104
int log_disp_terminal(time_t stamp, const char *file, int line, const char *function, int level,...)
Save a log line to the terminal - Implements log_dispatcher_t.
Definition: logging.c:450
#define MUTT_STARTUP_HOOK
startup-hook: run when starting NeoMutt
Definition: hook.h:64
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
static const char clear[]
int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new, struct Email *e, bool resend)
Prepare a message template.
Definition: postpone.c:599
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:93
enum CommandResult mutt_parse_rc_line(char *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:3232
Usenet network mailbox type; talk to an NNTP server.
The header of an Email.
Definition: envelope.h:54
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:75
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition: muttlib.c:1560
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
int cs_str_native_set(const struct ConfigSet *cs, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: set.c:772
void print_copyright(void)
Print copyright message.
Definition: version.c:463