NeoMutt  2021-10-29-220-g2b1eec
Teaching an old dog new tricks
DOXYGEN
command_parse.c
Go to the documentation of this file.
1 
31 #include "config.h"
32 #include <assert.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include "mutt/lib.h"
40 #include "address/lib.h"
41 #include "config/lib.h"
42 #include "email/lib.h"
43 #include "core/lib.h"
44 #include "gui/lib.h"
45 #include "mutt.h"
46 #include "command_parse.h"
47 #include "imap/lib.h"
48 #include "menu/lib.h"
49 #include "init.h"
50 #include "keymap.h"
51 #include "monitor.h"
52 #include "mutt_commands.h"
53 #include "mutt_globals.h"
54 #include "muttlib.h"
55 #include "mx.h"
56 #include "myvar.h"
57 #include "options.h"
58 #include "version.h"
59 #ifdef ENABLE_NLS
60 #include <libintl.h>
61 #endif
62 
63 /* LIFO designed to contain the list of config files that have been sourced and
64  * avoid cyclic sourcing */
65 static struct ListHead MuttrcStack = STAILQ_HEAD_INITIALIZER(MuttrcStack);
66 
67 #define MAX_ERRS 128
68 
73 {
77 };
78 
85 static bool is_function(const char *name)
86 {
87  for (size_t i = 0; MenuNames[i].name; i++)
88  {
89  const struct Binding *b = km_get_table(MenuNames[i].value);
90  if (!b)
91  continue;
92 
93  for (int j = 0; b[j].name; j++)
94  if (mutt_str_equal(name, b[j].name))
95  return true;
96  }
97  return false;
98 }
99 
109 int parse_grouplist(struct GroupList *gl, struct Buffer *buf, struct Buffer *s,
110  struct Buffer *err)
111 {
112  while (mutt_istr_equal(buf->data, "-group"))
113  {
114  if (!MoreArgs(s))
115  {
116  mutt_buffer_strcpy(err, _("-group: no group name"));
117  return -1;
118  }
119 
121 
123 
124  if (!MoreArgs(s))
125  {
126  mutt_buffer_strcpy(err, _("out of arguments"));
127  return -1;
128  }
129 
131  }
132 
133  return 0;
134 }
135 
142 int source_rc(const char *rcfile_path, struct Buffer *err)
143 {
144  int lineno = 0, rc = 0, warnings = 0;
145  enum CommandResult line_rc;
146  struct Buffer *token = NULL, *linebuf = NULL;
147  char *line = NULL;
148  char *currentline = NULL;
149  char rcfile[PATH_MAX];
150  size_t linelen = 0;
151  pid_t pid;
152 
153  mutt_str_copy(rcfile, rcfile_path, sizeof(rcfile));
154 
155  size_t rcfilelen = mutt_str_len(rcfile);
156  if (rcfilelen == 0)
157  return -1;
158 
159  bool ispipe = rcfile[rcfilelen - 1] == '|';
160 
161  if (!ispipe)
162  {
163  struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
164  if (!mutt_path_to_absolute(rcfile, np ? NONULL(np->data) : ""))
165  {
166  mutt_error(_("Error: Can't build path of '%s'"), rcfile_path);
167  return -1;
168  }
169 
170  STAILQ_FOREACH(np, &MuttrcStack, entries)
171  {
172  if (mutt_str_equal(np->data, rcfile))
173  {
174  break;
175  }
176  }
177  if (np)
178  {
179  mutt_error(_("Error: Cyclic sourcing of configuration file '%s'"), rcfile);
180  return -1;
181  }
182 
184  }
185 
186  mutt_debug(LL_DEBUG2, "Reading configuration file '%s'\n", rcfile);
187 
188  FILE *fp = mutt_open_read(rcfile, &pid);
189  if (!fp)
190  {
191  mutt_buffer_printf(err, "%s: %s", rcfile, strerror(errno));
192  return -1;
193  }
194 
195  token = mutt_buffer_pool_get();
196  linebuf = mutt_buffer_pool_get();
197 
198  while ((line = mutt_file_read_line(line, &linelen, fp, &lineno, MUTT_RL_CONT)) != NULL)
199  {
200  const char *const c_config_charset =
201  cs_subset_string(NeoMutt->sub, "config_charset");
202  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
203  const bool conv = c_config_charset && c_charset;
204  if (conv)
205  {
206  currentline = mutt_str_dup(line);
207  if (!currentline)
208  continue;
209  mutt_ch_convert_string(&currentline, c_config_charset, c_charset, MUTT_ICONV_NO_FLAGS);
210  }
211  else
212  currentline = line;
213 
214  mutt_buffer_strcpy(linebuf, currentline);
215 
216  mutt_buffer_reset(err);
217  line_rc = mutt_parse_rc_buffer(linebuf, token, err);
218  if (line_rc == MUTT_CMD_ERROR)
219  {
220  mutt_error(_("Error in %s, line %d: %s"), rcfile, lineno, err->data);
221  if (--rc < -MAX_ERRS)
222  {
223  if (conv)
224  FREE(&currentline);
225  break;
226  }
227  }
228  else if (line_rc == MUTT_CMD_WARNING)
229  {
230  /* Warning */
231  mutt_warning(_("Warning in %s, line %d: %s"), rcfile, lineno, err->data);
232  warnings++;
233  }
234  else if (line_rc == MUTT_CMD_FINISH)
235  {
236  if (conv)
237  FREE(&currentline);
238  break; /* Found "finish" command */
239  }
240  else
241  {
242  if (rc < 0)
243  rc = -1;
244  }
245  if (conv)
246  FREE(&currentline);
247  }
248 
249  FREE(&line);
250  mutt_file_fclose(&fp);
251  if (pid != -1)
252  filter_wait(pid);
253 
254  if (rc)
255  {
256  /* the neomuttrc source keyword */
257  mutt_buffer_reset(err);
258  mutt_buffer_printf(err, (rc >= -MAX_ERRS) ? _("source: errors in %s") : _("source: reading aborted due to too many errors in %s"),
259  rcfile);
260  rc = -1;
261  }
262  else
263  {
264  /* Don't alias errors with warnings */
265  if (warnings > 0)
266  {
267  mutt_buffer_printf(err, ngettext("source: %d warning in %s", "source: %d warnings in %s", warnings),
268  warnings, rcfile);
269  rc = -2;
270  }
271  }
272 
273  if (!ispipe && !STAILQ_EMPTY(&MuttrcStack))
274  {
275  struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
276  STAILQ_REMOVE_HEAD(&MuttrcStack, entries);
277  FREE(&np->data);
278  FREE(&np);
279  }
280 
281  mutt_buffer_pool_release(&token);
282  mutt_buffer_pool_release(&linebuf);
283  return rc;
284 }
285 
289 enum CommandResult parse_cd(struct Buffer *buf, struct Buffer *s, intptr_t data,
290  struct Buffer *err)
291 {
294  if (mutt_buffer_len(buf) == 0)
295  {
296  if (HomeDir)
298  else
299  {
300  mutt_buffer_printf(err, _("%s: too few arguments"), "cd");
301  return MUTT_CMD_ERROR;
302  }
303  }
304 
305  if (chdir(mutt_buffer_string(buf)) != 0)
306  {
307  mutt_buffer_printf(err, "cd: %s", strerror(errno));
308  return MUTT_CMD_ERROR;
309  }
310 
311  return MUTT_CMD_SUCCESS;
312 }
313 
317 enum CommandResult parse_echo(struct Buffer *buf, struct Buffer *s,
318  intptr_t data, struct Buffer *err)
319 {
320  if (!MoreArgs(s))
321  {
322  mutt_buffer_printf(err, _("%s: too few arguments"), "echo");
323  return MUTT_CMD_WARNING;
324  }
326  OptForceRefresh = true;
327  mutt_message("%s", buf->data);
328  OptForceRefresh = false;
329  mutt_sleep(0);
330 
331  return MUTT_CMD_SUCCESS;
332 }
333 
341 enum CommandResult parse_finish(struct Buffer *buf, struct Buffer *s,
342  intptr_t data, struct Buffer *err)
343 {
344  if (MoreArgs(s))
345  {
346  mutt_buffer_printf(err, _("%s: too many arguments"), "finish");
347  return MUTT_CMD_WARNING;
348  }
349 
350  return MUTT_CMD_FINISH;
351 }
352 
356 enum CommandResult parse_group(struct Buffer *buf, struct Buffer *s,
357  intptr_t data, struct Buffer *err)
358 {
359  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
360  enum GroupState state = GS_NONE;
361 
362  do
363  {
365  if (parse_grouplist(&gl, buf, s, err) == -1)
366  goto bail;
367 
368  if ((data == MUTT_UNGROUP) && mutt_istr_equal(buf->data, "*"))
369  {
371  goto out;
372  }
373 
374  if (mutt_istr_equal(buf->data, "-rx"))
375  state = GS_RX;
376  else if (mutt_istr_equal(buf->data, "-addr"))
377  state = GS_ADDR;
378  else
379  {
380  switch (state)
381  {
382  case GS_NONE:
383  mutt_buffer_printf(err, _("%sgroup: missing -rx or -addr"),
384  (data == MUTT_UNGROUP) ? "un" : "");
385  goto warn;
386 
387  case GS_RX:
388  if ((data == MUTT_GROUP) &&
389  (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0))
390  {
391  goto bail;
392  }
393  else if ((data == MUTT_UNGROUP) &&
394  (mutt_grouplist_remove_regex(&gl, buf->data) < 0))
395  {
396  goto bail;
397  }
398  break;
399 
400  case GS_ADDR:
401  {
402  char *estr = NULL;
403  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
404  mutt_addrlist_parse2(&al, buf->data);
405  if (TAILQ_EMPTY(&al))
406  goto bail;
407  if (mutt_addrlist_to_intl(&al, &estr))
408  {
409  mutt_buffer_printf(err, _("%sgroup: warning: bad IDN '%s'"),
410  (data == 1) ? "un" : "", estr);
411  mutt_addrlist_clear(&al);
412  FREE(&estr);
413  goto bail;
414  }
415  if (data == MUTT_GROUP)
416  mutt_grouplist_add_addrlist(&gl, &al);
417  else if (data == MUTT_UNGROUP)
419  mutt_addrlist_clear(&al);
420  break;
421  }
422  }
423  }
424  } while (MoreArgs(s));
425 
426 out:
428  return MUTT_CMD_SUCCESS;
429 
430 bail:
432  return MUTT_CMD_ERROR;
433 
434 warn:
436  return MUTT_CMD_WARNING;
437 }
438 
452 enum CommandResult parse_ifdef(struct Buffer *buf, struct Buffer *s,
453  intptr_t data, struct Buffer *err)
454 {
456 
457  // is the item defined as:
458  bool res = cs_subset_lookup(NeoMutt->sub, buf->data) // a variable?
459  || feature_enabled(buf->data) // a compiled-in feature?
460  || is_function(buf->data) // a function?
461  || mutt_command_get(buf->data) // a command?
462  || myvar_get(buf->data) // a my_ variable?
463  || mutt_str_getenv(buf->data); // an environment variable?
464 
465  if (!MoreArgs(s))
466  {
467  mutt_buffer_printf(err, _("%s: too few arguments"), (data ? "ifndef" : "ifdef"));
468  return MUTT_CMD_WARNING;
469  }
471 
472  /* ifdef KNOWN_SYMBOL or ifndef UNKNOWN_SYMBOL */
473  if ((res && (data == 0)) || (!res && (data == 1)))
474  {
475  enum CommandResult rc = mutt_parse_rc_line(buf->data, err);
476  if (rc == MUTT_CMD_ERROR)
477  {
478  mutt_error(_("Error: %s"), err->data);
479  return MUTT_CMD_ERROR;
480  }
481  return rc;
482  }
483  return MUTT_CMD_SUCCESS;
484 }
485 
489 enum CommandResult parse_ignore(struct Buffer *buf, struct Buffer *s,
490  intptr_t data, struct Buffer *err)
491 {
492  do
493  {
496  add_to_stailq(&Ignore, buf->data);
497  } while (MoreArgs(s));
498 
499  return MUTT_CMD_SUCCESS;
500 }
501 
505 enum CommandResult parse_lists(struct Buffer *buf, struct Buffer *s,
506  intptr_t data, struct Buffer *err)
507 {
508  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
509 
510  do
511  {
513 
514  if (parse_grouplist(&gl, buf, s, err) == -1)
515  goto bail;
516 
518 
519  if (mutt_regexlist_add(&MailLists, buf->data, REG_ICASE, err) != 0)
520  goto bail;
521 
522  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
523  goto bail;
524  } while (MoreArgs(s));
525 
527  return MUTT_CMD_SUCCESS;
528 
529 bail:
531  return MUTT_CMD_ERROR;
532 }
533 
539 enum CommandResult parse_mailboxes(struct Buffer *buf, struct Buffer *s,
540  intptr_t data, struct Buffer *err)
541 {
542  while (MoreArgs(s))
543  {
544  struct Mailbox *m = mailbox_new();
545 
546  if (data & MUTT_NAMED)
547  {
548  // This may be empty, e.g. `named-mailboxes "" +inbox`
550  m->name = mutt_buffer_strdup(buf);
551  }
552 
554  if (mutt_buffer_is_empty(buf))
555  {
556  /* Skip empty tokens. */
557  mailbox_free(&m);
558  continue;
559  }
560 
561  mutt_buffer_strcpy(&m->pathbuf, buf->data);
562  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
563  /* int rc = */ mx_path_canon2(m, c_folder);
564 
565  if (m->type <= MUTT_UNKNOWN)
566  {
567  mutt_error("Unknown Mailbox: %s", m->realpath);
568  mailbox_free(&m);
569  return MUTT_CMD_ERROR;
570  }
571 
572  bool new_account = false;
573  struct Account *a = mx_ac_find(m);
574  if (!a)
575  {
576  a = account_new(NULL, NeoMutt->sub);
577  a->type = m->type;
578  new_account = true;
579  }
580 
581  if (!new_account)
582  {
583  struct Mailbox *m_old = mx_mbox_find(a, m->realpath);
584  if (m_old)
585  {
586  const bool show = (m_old->flags == MB_HIDDEN);
587  if (show)
588  {
589  m_old->flags = MB_NORMAL;
590  m_old->gen = mailbox_gen();
591  }
592 
593  const bool rename = (data & MUTT_NAMED) && !mutt_str_equal(m_old->name, m->name);
594  if (rename)
595  {
596  mutt_str_replace(&m_old->name, m->name);
597  }
598 
599  mailbox_free(&m);
600  continue;
601  }
602  }
603 
604  if (!mx_ac_add(a, m))
605  {
606  //error
607  mailbox_free(&m);
608  if (new_account)
609  {
610  cs_subset_free(&a->sub);
611  FREE(&a->name);
612  notify_free(&a->notify);
613  FREE(&a);
614  }
615  continue;
616  }
617  if (new_account)
618  {
620  }
621 
622 #ifdef USE_INOTIFY
623  mutt_monitor_add(m);
624 #endif
625  }
626  return MUTT_CMD_SUCCESS;
627 }
628 
632 enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s,
633  intptr_t data, struct Buffer *err)
634 {
636  char *p = strpbrk(buf->data, ": \t");
637  if (!p || (*p != ':'))
638  {
639  mutt_buffer_strcpy(err, _("invalid header field"));
640  return MUTT_CMD_WARNING;
641  }
642 
643  struct EventHeader ev_h = { buf->data };
644  struct ListNode *n = header_find(&UserHeader, buf->data);
645 
646  if (n)
647  {
648  header_update(n, buf->data);
649  mutt_debug(LL_NOTIFY, "NT_HEADER_CHANGE: %s\n", buf->data);
651  }
652  else
653  {
654  header_add(&UserHeader, buf->data);
655  mutt_debug(LL_NOTIFY, "NT_HEADER_ADD: %s\n", buf->data);
657  }
658 
659  return MUTT_CMD_SUCCESS;
660 }
661 
667 enum CommandResult parse_set(struct Buffer *buf, struct Buffer *s,
668  intptr_t data, struct Buffer *err)
669 {
670  /* The order must match `enum MuttSetCommand` */
671  static const char *set_commands[] = { "set", "toggle", "unset", "reset" };
672 
673  int rc = 0;
674 
675  while (MoreArgs(s))
676  {
677  bool prefix = false;
678  bool query = false;
679  bool inv = (data == MUTT_SET_INV);
680  bool reset = (data == MUTT_SET_RESET);
681  bool unset = (data == MUTT_SET_UNSET);
682 
683  if (*s->dptr == '?')
684  {
685  prefix = true;
686  query = true;
687  s->dptr++;
688  }
689  else if (mutt_str_startswith(s->dptr, "no"))
690  {
691  prefix = true;
692  unset = !unset;
693  s->dptr += 2;
694  }
695  else if (mutt_str_startswith(s->dptr, "inv"))
696  {
697  prefix = true;
698  inv = !inv;
699  s->dptr += 3;
700  }
701  else if (*s->dptr == '&')
702  {
703  prefix = true;
704  reset = true;
705  s->dptr++;
706  }
707 
708  if (prefix && (data != MUTT_SET_SET))
709  {
710  mutt_buffer_printf(err, _("Can't use 'inv', 'no', '&' or '?' with the '%s' command"),
711  set_commands[data]);
712  return MUTT_CMD_WARNING;
713  }
714 
715  /* get the variable name */
717 
718  bool bq = false;
719  bool equals = false;
720  bool increment = false;
721  bool decrement = false;
722 
723  struct HashElem *he = NULL;
724  bool my = mutt_str_startswith(buf->data, "my_");
725  if (!my)
726  {
727  he = cs_subset_lookup(NeoMutt->sub, buf->data);
728  if (!he)
729  {
730  if (reset && mutt_str_equal(buf->data, "all"))
731  {
732  struct HashElem **list = get_elem_list(NeoMutt->sub->cs);
733  if (!list)
734  return MUTT_CMD_ERROR;
735 
736  for (size_t i = 0; list[i]; i++)
737  cs_subset_he_reset(NeoMutt->sub, list[i], NULL);
738 
739  FREE(&list);
740  break;
741  }
742  else
743  {
744  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
745  return MUTT_CMD_ERROR;
746  }
747  }
748 
749  // Use the correct name if a synonym is used
750  mutt_buffer_strcpy(buf, he->key.strkey);
751 
752  bq = ((DTYPE(he->type) == DT_BOOL) || (DTYPE(he->type) == DT_QUAD));
753  }
754 
755  if (*s->dptr == '?')
756  {
757  if (prefix)
758  {
759  mutt_buffer_printf(err,
760  _("Can't use a prefix when querying a variable"));
761  return MUTT_CMD_WARNING;
762  }
763 
764  if (reset || unset || inv)
765  {
766  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"),
767  set_commands[data]);
768  return MUTT_CMD_WARNING;
769  }
770 
771  query = true;
772  s->dptr++;
773  }
774  else if (*s->dptr == '+' || *s->dptr == '-')
775  {
776  if (prefix)
777  {
779  err,
780  _("Can't use prefix when incrementing or decrementing a variable"));
781  return MUTT_CMD_WARNING;
782  }
783 
784  if (reset || unset || inv)
785  {
786  mutt_buffer_printf(err, _("Can't set a variable with the '%s' command"),
787  set_commands[data]);
788  return MUTT_CMD_WARNING;
789  }
790  if (*s->dptr == '+')
791  increment = true;
792  else
793  decrement = true;
794 
795  if (my && decrement)
796  {
797  mutt_buffer_printf(err, _("Can't decrement a my_ variable"), set_commands[data]);
798  return MUTT_CMD_WARNING;
799  }
800  s->dptr++;
801  if (*s->dptr == '=')
802  {
803  equals = true;
804  s->dptr++;
805  }
806  }
807  else if (*s->dptr == '=')
808  {
809  if (prefix)
810  {
811  mutt_buffer_printf(err, _("Can't use prefix when setting a variable"));
812  return MUTT_CMD_WARNING;
813  }
814 
815  if (reset || unset || inv)
816  {
817  mutt_buffer_printf(err, _("Can't set a variable with the '%s' command"),
818  set_commands[data]);
819  return MUTT_CMD_WARNING;
820  }
821 
822  equals = true;
823  s->dptr++;
824  }
825 
826  if (!bq && (inv || (unset && prefix)))
827  {
828  if (data == MUTT_SET_SET)
829  {
830  mutt_buffer_printf(err, _("Prefixes 'no' and 'inv' may only be used "
831  "with bool/quad variables"));
832  }
833  else
834  {
835  mutt_buffer_printf(err, _("Command '%s' can only be used with bool/quad variables"),
836  set_commands[data]);
837  }
838  return MUTT_CMD_WARNING;
839  }
840 
841  if (reset)
842  {
843  // mutt_buffer_printf(err, "ACT24 reset variable %s", buf->data);
844  if (he)
845  {
846  rc = cs_subset_he_reset(NeoMutt->sub, he, err);
847  if (CSR_RESULT(rc) != CSR_SUCCESS)
848  return MUTT_CMD_ERROR;
849  }
850  else
851  {
852  myvar_del(buf->data);
853  }
854  continue;
855  }
856 
857  if ((data == MUTT_SET_SET) && !inv && !unset)
858  {
859  if (query)
860  {
861  // mutt_buffer_printf(err, "ACT08 query variable %s", buf->data);
862  if (he)
863  {
864  mutt_buffer_addstr(err, buf->data);
865  mutt_buffer_addch(err, '=');
866  mutt_buffer_reset(buf);
867  rc = cs_subset_he_string_get(NeoMutt->sub, he, buf);
868  if (CSR_RESULT(rc) != CSR_SUCCESS)
869  {
870  mutt_buffer_addstr(err, buf->data);
871  return MUTT_CMD_ERROR;
872  }
873  if (DTYPE(he->type) == DT_PATH)
874  mutt_pretty_mailbox(buf->data, buf->dsize);
875  pretty_var(buf->data, err);
876  }
877  else
878  {
879  const char *val = myvar_get(buf->data);
880  if (val)
881  {
882  mutt_buffer_addstr(err, buf->data);
883  mutt_buffer_addch(err, '=');
884  pretty_var(val, err);
885  }
886  else
887  {
888  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
889  return MUTT_CMD_ERROR;
890  }
891  }
892  break;
893  }
894  else if (equals)
895  {
896  // mutt_buffer_printf(err, "ACT11 set variable %s to ", buf->data);
897  const char *name = NULL;
898  if (my)
899  {
900  name = mutt_str_dup(buf->data);
901  }
903  if (my)
904  {
905  assert(!decrement);
906  if (increment)
907  {
908  myvar_append(name, buf->data);
909  }
910  else
911  {
912  myvar_set(name, buf->data);
913  }
914  FREE(&name);
915  }
916  else
917  {
918  if (DTYPE(he->type) == DT_PATH)
919  {
920  if (he->type & (DT_PATH_DIR | DT_PATH_FILE))
922  else
923  mutt_path_tilde(buf->data, buf->dsize, HomeDir);
924  }
925  else if (IS_MAILBOX(he))
926  {
928  }
929  else if (IS_COMMAND(he))
930  {
931  struct Buffer scratch = mutt_buffer_make(1024);
932  mutt_buffer_copy(&scratch, buf);
933 
934  if (!mutt_str_equal(buf->data, "builtin"))
935  {
936  mutt_buffer_expand_path(&scratch);
937  }
938  mutt_buffer_reset(buf);
939  mutt_buffer_addstr(buf, mutt_buffer_string(&scratch));
940  mutt_buffer_dealloc(&scratch);
941  }
942  if (increment)
943  {
944  rc = cs_subset_he_string_plus_equals(NeoMutt->sub, he, buf->data, err);
945  }
946  else if (decrement)
947  {
948  rc = cs_subset_he_string_minus_equals(NeoMutt->sub, he, buf->data, err);
949  }
950  else
951  {
952  rc = cs_subset_he_string_set(NeoMutt->sub, he, buf->data, err);
953  }
954  if (CSR_RESULT(rc) != CSR_SUCCESS)
955  return MUTT_CMD_ERROR;
956  }
957  continue;
958  }
959  else
960  {
961  if (bq)
962  {
963  // mutt_buffer_printf(err, "ACT23 set variable %s to 'yes'", buf->data);
964  rc = cs_subset_he_native_set(NeoMutt->sub, he, true, err);
965  if (CSR_RESULT(rc) != CSR_SUCCESS)
966  return MUTT_CMD_ERROR;
967  continue;
968  }
969  else
970  {
971  // mutt_buffer_printf(err, "ACT10 query variable %s", buf->data);
972  if (he)
973  {
974  mutt_buffer_addstr(err, buf->data);
975  mutt_buffer_addch(err, '=');
976  mutt_buffer_reset(buf);
977  rc = cs_subset_he_string_get(NeoMutt->sub, he, buf);
978  if (CSR_RESULT(rc) != CSR_SUCCESS)
979  {
980  mutt_buffer_addstr(err, buf->data);
981  return MUTT_CMD_ERROR;
982  }
983  if (DTYPE(he->type) == DT_PATH)
984  mutt_pretty_mailbox(buf->data, buf->dsize);
985  pretty_var(buf->data, err);
986  }
987  else
988  {
989  const char *val = myvar_get(buf->data);
990  if (val)
991  {
992  mutt_buffer_addstr(err, buf->data);
993  mutt_buffer_addch(err, '=');
994  pretty_var(val, err);
995  }
996  else
997  {
998  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
999  return MUTT_CMD_ERROR;
1000  }
1001  }
1002  break;
1003  }
1004  }
1005  }
1006 
1007  if (my)
1008  {
1009  myvar_del(buf->data);
1010  }
1011  else if (bq)
1012  {
1013  if (inv)
1014  {
1015  // mutt_buffer_printf(err, "ACT25 TOGGLE bool/quad variable %s", buf->data);
1016  if (DTYPE(he->type) == DT_BOOL)
1017  bool_he_toggle(NeoMutt->sub, he, err);
1018  else
1019  quad_he_toggle(NeoMutt->sub, he, err);
1020  }
1021  else
1022  {
1023  // mutt_buffer_printf(err, "ACT26 UNSET bool/quad variable %s", buf->data);
1024  rc = cs_subset_he_native_set(NeoMutt->sub, he, false, err);
1025  if (CSR_RESULT(rc) != CSR_SUCCESS)
1026  return MUTT_CMD_ERROR;
1027  }
1028  continue;
1029  }
1030  else
1031  {
1032  rc = cs_subset_he_string_set(NeoMutt->sub, he, NULL, err);
1033  if (CSR_RESULT(rc) != CSR_SUCCESS)
1034  return MUTT_CMD_ERROR;
1035  }
1036  }
1037 
1038  return MUTT_CMD_SUCCESS;
1039 }
1040 
1044 enum CommandResult parse_setenv(struct Buffer *buf, struct Buffer *s,
1045  intptr_t data, struct Buffer *err)
1046 {
1047  char **envp = mutt_envlist_getlist();
1048 
1049  bool query = false;
1050  bool prefix = false;
1051  bool unset = (data == MUTT_SET_UNSET);
1052 
1053  if (!MoreArgs(s))
1054  {
1055  mutt_buffer_printf(err, _("%s: too few arguments"), "setenv");
1056  return MUTT_CMD_WARNING;
1057  }
1058 
1059  if (*s->dptr == '?')
1060  {
1061  query = true;
1062  prefix = true;
1063 
1064  if (unset)
1065  {
1066  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"), "unsetenv");
1067  return MUTT_CMD_WARNING;
1068  }
1069 
1070  s->dptr++;
1071  }
1072 
1073  /* get variable name */
1075 
1076  if (*s->dptr == '?')
1077  {
1078  if (unset)
1079  {
1080  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"), "unsetenv");
1081  return MUTT_CMD_WARNING;
1082  }
1083 
1084  if (prefix)
1085  {
1086  mutt_buffer_printf(err, _("Can't use a prefix when querying a variable"));
1087  return MUTT_CMD_WARNING;
1088  }
1089 
1090  query = true;
1091  s->dptr++;
1092  }
1093 
1094  if (query)
1095  {
1096  bool found = false;
1097  while (envp && *envp)
1098  {
1099  /* This will display all matches for "^QUERY" */
1100  if (mutt_str_startswith(*envp, buf->data))
1101  {
1102  if (!found)
1103  {
1104  mutt_endwin();
1105  found = true;
1106  }
1107  puts(*envp);
1108  }
1109  envp++;
1110  }
1111 
1112  if (found)
1113  {
1115  return MUTT_CMD_SUCCESS;
1116  }
1117 
1118  mutt_buffer_printf(err, _("%s is unset"), buf->data);
1119  return MUTT_CMD_WARNING;
1120  }
1121 
1122  if (unset)
1123  {
1124  if (!mutt_envlist_unset(buf->data))
1125  {
1126  mutt_buffer_printf(err, _("%s is unset"), buf->data);
1127  return MUTT_CMD_WARNING;
1128  }
1129  return MUTT_CMD_SUCCESS;
1130  }
1131 
1132  /* set variable */
1133 
1134  if (*s->dptr == '=')
1135  {
1136  s->dptr++;
1137  SKIPWS(s->dptr);
1138  }
1139 
1140  if (!MoreArgs(s))
1141  {
1142  mutt_buffer_printf(err, _("%s: too few arguments"), "setenv");
1143  return MUTT_CMD_WARNING;
1144  }
1145 
1146  char *name = mutt_str_dup(buf->data);
1148  mutt_envlist_set(name, buf->data, true);
1149  FREE(&name);
1150 
1151  return MUTT_CMD_SUCCESS;
1152 }
1153 
1157 enum CommandResult parse_source(struct Buffer *buf, struct Buffer *s,
1158  intptr_t data, struct Buffer *err)
1159 {
1160  char path[PATH_MAX];
1161 
1162  do
1163  {
1164  if (mutt_extract_token(buf, s, MUTT_TOKEN_NO_FLAGS) != 0)
1165  {
1166  mutt_buffer_printf(err, _("source: error at %s"), s->dptr);
1167  return MUTT_CMD_ERROR;
1168  }
1169  mutt_str_copy(path, buf->data, sizeof(path));
1170  mutt_expand_path(path, sizeof(path));
1171 
1172  if (source_rc(path, err) < 0)
1173  {
1174  mutt_buffer_printf(err, _("source: file %s could not be sourced"), path);
1175  return MUTT_CMD_ERROR;
1176  }
1177 
1178  } while (MoreArgs(s));
1179 
1180  return MUTT_CMD_SUCCESS;
1181 }
1182 
1186 enum CommandResult parse_spam_list(struct Buffer *buf, struct Buffer *s,
1187  intptr_t data, struct Buffer *err)
1188 {
1189  struct Buffer templ;
1190 
1191  mutt_buffer_init(&templ);
1192 
1193  /* Insist on at least one parameter */
1194  if (!MoreArgs(s))
1195  {
1196  if (data == MUTT_SPAM)
1197  mutt_buffer_strcpy(err, _("spam: no matching pattern"));
1198  else
1199  mutt_buffer_strcpy(err, _("nospam: no matching pattern"));
1200  return MUTT_CMD_ERROR;
1201  }
1202 
1203  /* Extract the first token, a regex */
1205 
1206  /* data should be either MUTT_SPAM or MUTT_NOSPAM. MUTT_SPAM is for spam commands. */
1207  if (data == MUTT_SPAM)
1208  {
1209  /* If there's a second parameter, it's a template for the spam tag. */
1210  if (MoreArgs(s))
1211  {
1213 
1214  /* Add to the spam list. */
1215  if (mutt_replacelist_add(&SpamList, buf->data, templ.data, err) != 0)
1216  {
1217  FREE(&templ.data);
1218  return MUTT_CMD_ERROR;
1219  }
1220  FREE(&templ.data);
1221  }
1222  /* If not, try to remove from the nospam list. */
1223  else
1224  {
1226  }
1227 
1228  return MUTT_CMD_SUCCESS;
1229  }
1230  /* MUTT_NOSPAM is for nospam commands. */
1231  else if (data == MUTT_NOSPAM)
1232  {
1233  /* nospam only ever has one parameter. */
1234 
1235  /* "*" is a special case. */
1236  if (mutt_str_equal(buf->data, "*"))
1237  {
1240  return MUTT_CMD_SUCCESS;
1241  }
1242 
1243  /* If it's on the spam list, just remove it. */
1244  if (mutt_replacelist_remove(&SpamList, buf->data) != 0)
1245  return MUTT_CMD_SUCCESS;
1246 
1247  /* Otherwise, add it to the nospam list. */
1248  if (mutt_regexlist_add(&NoSpamList, buf->data, REG_ICASE, err) != 0)
1249  return MUTT_CMD_ERROR;
1250 
1251  return MUTT_CMD_SUCCESS;
1252  }
1253 
1254  /* This should not happen. */
1255  mutt_buffer_strcpy(err, "This is no good at all.");
1256  return MUTT_CMD_ERROR;
1257 }
1258 
1264 enum CommandResult parse_stailq(struct Buffer *buf, struct Buffer *s,
1265  intptr_t data, struct Buffer *err)
1266 {
1267  do
1268  {
1270  add_to_stailq((struct ListHead *) data, buf->data);
1271  } while (MoreArgs(s));
1272 
1273  return MUTT_CMD_SUCCESS;
1274 }
1275 
1279 enum CommandResult parse_subscribe(struct Buffer *buf, struct Buffer *s,
1280  intptr_t data, struct Buffer *err)
1281 {
1282  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
1283 
1284  do
1285  {
1287 
1288  if (parse_grouplist(&gl, buf, s, err) == -1)
1289  goto bail;
1290 
1293 
1294  if (mutt_regexlist_add(&MailLists, buf->data, REG_ICASE, err) != 0)
1295  goto bail;
1296  if (mutt_regexlist_add(&SubscribedLists, buf->data, REG_ICASE, err) != 0)
1297  goto bail;
1298  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
1299  goto bail;
1300  } while (MoreArgs(s));
1301 
1303  return MUTT_CMD_SUCCESS;
1304 
1305 bail:
1307  return MUTT_CMD_ERROR;
1308 }
1309 
1310 #ifdef USE_IMAP
1318 enum CommandResult parse_subscribe_to(struct Buffer *buf, struct Buffer *s,
1319  intptr_t data, struct Buffer *err)
1320 {
1321  if (!buf || !s || !err)
1322  return MUTT_CMD_ERROR;
1323 
1324  mutt_buffer_reset(err);
1325 
1326  if (MoreArgs(s))
1327  {
1329 
1330  if (MoreArgs(s))
1331  {
1332  mutt_buffer_printf(err, _("%s: too many arguments"), "subscribe-to");
1333  return MUTT_CMD_WARNING;
1334  }
1335 
1336  if (buf->data && (*buf->data != '\0'))
1337  {
1338  /* Expand and subscribe */
1339  if (imap_subscribe(mutt_expand_path(buf->data, buf->dsize), true) == 0)
1340  {
1341  mutt_message(_("Subscribed to %s"), buf->data);
1342  return MUTT_CMD_SUCCESS;
1343  }
1344 
1345  mutt_buffer_printf(err, _("Could not subscribe to %s"), buf->data);
1346  return MUTT_CMD_ERROR;
1347  }
1348 
1349  mutt_debug(LL_DEBUG1, "Corrupted buffer");
1350  return MUTT_CMD_ERROR;
1351  }
1352 
1353  mutt_buffer_addstr(err, _("No folder specified"));
1354  return MUTT_CMD_WARNING;
1355 }
1356 #endif
1357 
1361 enum CommandResult parse_tag_formats(struct Buffer *buf, struct Buffer *s,
1362  intptr_t data, struct Buffer *err)
1363 {
1364  if (!buf || !s)
1365  return MUTT_CMD_ERROR;
1366 
1367  char *tmp = NULL;
1368 
1369  while (MoreArgs(s))
1370  {
1371  char *tag = NULL, *format = NULL;
1372 
1374  if (buf->data && (*buf->data != '\0'))
1375  tag = mutt_str_dup(buf->data);
1376  else
1377  continue;
1378 
1380  format = mutt_str_dup(buf->data);
1381 
1382  /* avoid duplicates */
1383  tmp = mutt_hash_find(TagFormats, format);
1384  if (tmp)
1385  {
1386  mutt_debug(LL_DEBUG3, "tag format '%s' already registered as '%s'\n", format, tmp);
1387  FREE(&tag);
1388  FREE(&format);
1389  continue;
1390  }
1391 
1392  mutt_hash_insert(TagFormats, format, tag);
1393  }
1394  return MUTT_CMD_SUCCESS;
1395 }
1396 
1400 enum CommandResult parse_tag_transforms(struct Buffer *buf, struct Buffer *s,
1401  intptr_t data, struct Buffer *err)
1402 {
1403  if (!buf || !s)
1404  return MUTT_CMD_ERROR;
1405 
1406  char *tmp = NULL;
1407 
1408  while (MoreArgs(s))
1409  {
1410  char *tag = NULL, *transform = NULL;
1411 
1413  if (buf->data && (*buf->data != '\0'))
1414  tag = mutt_str_dup(buf->data);
1415  else
1416  continue;
1417 
1419  transform = mutt_str_dup(buf->data);
1420 
1421  /* avoid duplicates */
1422  tmp = mutt_hash_find(TagTransforms, tag);
1423  if (tmp)
1424  {
1425  mutt_debug(LL_DEBUG3, "tag transform '%s' already registered as '%s'\n", tag, tmp);
1426  FREE(&tag);
1427  FREE(&transform);
1428  continue;
1429  }
1430 
1431  mutt_hash_insert(TagTransforms, tag, transform);
1432  }
1433  return MUTT_CMD_SUCCESS;
1434 }
1435 
1439 enum CommandResult parse_unignore(struct Buffer *buf, struct Buffer *s,
1440  intptr_t data, struct Buffer *err)
1441 {
1442  do
1443  {
1445 
1446  /* don't add "*" to the unignore list */
1447  if (strcmp(buf->data, "*") != 0)
1448  add_to_stailq(&UnIgnore, buf->data);
1449 
1450  remove_from_stailq(&Ignore, buf->data);
1451  } while (MoreArgs(s));
1452 
1453  return MUTT_CMD_SUCCESS;
1454 }
1455 
1459 enum CommandResult parse_unlists(struct Buffer *buf, struct Buffer *s,
1460  intptr_t data, struct Buffer *err)
1461 {
1463  do
1464  {
1468 
1469  if (!mutt_str_equal(buf->data, "*") &&
1470  (mutt_regexlist_add(&UnMailLists, buf->data, REG_ICASE, err) != 0))
1471  {
1472  return MUTT_CMD_ERROR;
1473  }
1474  } while (MoreArgs(s));
1475 
1476  return MUTT_CMD_SUCCESS;
1477 }
1478 
1483 static void do_unmailboxes(struct Mailbox *m)
1484 {
1485 #ifdef USE_INOTIFY
1487 #endif
1488  m->flags = MB_HIDDEN;
1489  m->gen = -1;
1490  if (m->opened)
1491  {
1492  struct EventMailbox ev_m = { NULL };
1493  mutt_debug(LL_NOTIFY, "NT_MAILBOX_SWITCH: NULL\n");
1495  }
1496  else
1497  {
1499  mailbox_free(&m);
1500  }
1501 }
1502 
1506 static void do_unmailboxes_star(void)
1507 {
1508  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
1510  struct MailboxNode *np = NULL;
1511  struct MailboxNode *nptmp = NULL;
1512  STAILQ_FOREACH_SAFE(np, &ml, entries, nptmp)
1513  {
1514  do_unmailboxes(np->mailbox);
1515  }
1517 }
1518 
1524 enum CommandResult parse_unmailboxes(struct Buffer *buf, struct Buffer *s,
1525  intptr_t data, struct Buffer *err)
1526 {
1527  while (MoreArgs(s))
1528  {
1530 
1531  if (mutt_str_equal(buf->data, "*"))
1532  {
1534  return MUTT_CMD_SUCCESS;
1535  }
1536 
1538 
1539  struct Account *a = NULL;
1540  TAILQ_FOREACH(a, &NeoMutt->accounts, entries)
1541  {
1542  struct Mailbox *m = mx_mbox_find(a, mutt_buffer_string(buf));
1543  if (m)
1544  {
1545  do_unmailboxes(m);
1546  break;
1547  }
1548  }
1549  }
1550  return MUTT_CMD_SUCCESS;
1551 }
1552 
1556 enum CommandResult parse_unmy_hdr(struct Buffer *buf, struct Buffer *s,
1557  intptr_t data, struct Buffer *err)
1558 {
1559  struct ListNode *np = NULL, *tmp = NULL;
1560  size_t l;
1561 
1562  do
1563  {
1565  if (mutt_str_equal("*", buf->data))
1566  {
1567  /* Clear all headers, send a notification for each header */
1568  STAILQ_FOREACH(np, &UserHeader, entries)
1569  {
1570  mutt_debug(LL_NOTIFY, "NT_HEADER_DELETE: %s\n", np->data);
1571  struct EventHeader ev_h = { np->data };
1573  }
1575  continue;
1576  }
1577 
1578  l = mutt_str_len(buf->data);
1579  if (buf->data[l - 1] == ':')
1580  l--;
1581 
1582  STAILQ_FOREACH_SAFE(np, &UserHeader, entries, tmp)
1583  {
1584  if (mutt_istrn_equal(buf->data, np->data, l) && (np->data[l] == ':'))
1585  {
1586  mutt_debug(LL_NOTIFY, "NT_HEADER_DELETE: %s\n", np->data);
1587  struct EventHeader ev_h = { np->data };
1589 
1590  header_free(&UserHeader, np);
1591  }
1592  }
1593  } while (MoreArgs(s));
1594  return MUTT_CMD_SUCCESS;
1595 }
1596 
1602 enum CommandResult parse_unstailq(struct Buffer *buf, struct Buffer *s,
1603  intptr_t data, struct Buffer *err)
1604 {
1605  do
1606  {
1608  /* Check for deletion of entire list */
1609  if (mutt_str_equal(buf->data, "*"))
1610  {
1611  mutt_list_free((struct ListHead *) data);
1612  break;
1613  }
1614  remove_from_stailq((struct ListHead *) data, buf->data);
1615  } while (MoreArgs(s));
1616 
1617  return MUTT_CMD_SUCCESS;
1618 }
1619 
1623 enum CommandResult parse_unsubscribe(struct Buffer *buf, struct Buffer *s,
1624  intptr_t data, struct Buffer *err)
1625 {
1627  do
1628  {
1631 
1632  if (!mutt_str_equal(buf->data, "*") &&
1633  (mutt_regexlist_add(&UnSubscribedLists, buf->data, REG_ICASE, err) != 0))
1634  {
1635  return MUTT_CMD_ERROR;
1636  }
1637  } while (MoreArgs(s));
1638 
1639  return MUTT_CMD_SUCCESS;
1640 }
1641 
1642 #ifdef USE_IMAP
1650 enum CommandResult parse_unsubscribe_from(struct Buffer *buf, struct Buffer *s,
1651  intptr_t data, struct Buffer *err)
1652 {
1653  if (!buf || !s || !err)
1654  return MUTT_CMD_ERROR;
1655 
1656  if (MoreArgs(s))
1657  {
1659 
1660  if (MoreArgs(s))
1661  {
1662  mutt_buffer_printf(err, _("%s: too many arguments"), "unsubscribe-from");
1663  return MUTT_CMD_WARNING;
1664  }
1665 
1666  if (buf->data && (*buf->data != '\0'))
1667  {
1668  /* Expand and subscribe */
1669  if (imap_subscribe(mutt_expand_path(buf->data, buf->dsize), false) == 0)
1670  {
1671  mutt_message(_("Unsubscribed from %s"), buf->data);
1672  return MUTT_CMD_SUCCESS;
1673  }
1674 
1675  mutt_buffer_printf(err, _("Could not unsubscribe from %s"), buf->data);
1676  return MUTT_CMD_ERROR;
1677  }
1678 
1679  mutt_debug(LL_DEBUG1, "Corrupted buffer");
1680  return MUTT_CMD_ERROR;
1681  }
1682 
1683  mutt_buffer_addstr(err, _("No folder specified"));
1684  return MUTT_CMD_WARNING;
1685 }
1686 #endif
1687 
1692 {
1694 }
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:96
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:43
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:616
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
Email Address Handling.
int bool_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:186
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:432
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:447
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define MoreArgs(buf)
Definition: buffer.h:40
CommandResult
Error codes for command_t parse functions.
Definition: command.h:34
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:37
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:35
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition: command.h:36
@ MUTT_CMD_FINISH
Finish: Stop processing this file.
Definition: command.h:38
GroupState
Type of email address group.
Definition: command_parse.c:73
@ GS_RX
Entry is a regular expression.
Definition: command_parse.c:75
@ GS_NONE
Group is missing an argument.
Definition: command_parse.c:74
@ GS_ADDR
Entry is an address.
Definition: command_parse.c:76
#define MAX_ERRS
Definition: command_parse.c:67
int parse_grouplist(struct GroupList *gl, struct Buffer *buf, struct Buffer *s, struct Buffer *err)
Parse a group context.
static void do_unmailboxes_star(void)
Remove all Mailboxes from the Sidebar/notifications.
void clear_source_stack(void)
Free memory from the stack used for the source command.
static struct ListHead MuttrcStack
Definition: command_parse.c:65
static void do_unmailboxes(struct Mailbox *m)
Remove a Mailbox from the Sidebar/notifications.
int source_rc(const char *rcfile_path, struct Buffer *err)
Read an initialization file.
static bool is_function(const char *name)
Is the argument a neomutt function?
Definition: command_parse.c:85
Functions to parse commands in a config file.
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
Convenience wrapper for the core headers.
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:427
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:394
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition: dump.c:83
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:526
struct ListNode * header_add(struct ListHead *hdrlist, const char *header)
Add a header to a list.
Definition: email.c:203
struct ListNode * header_update(struct ListNode *hdr, const char *header)
Update an existing header.
Definition: email.c:217
void header_free(struct ListHead *hdrlist, struct ListNode *target)
Free and remove a header from a header list.
Definition: email.c:245
struct ListNode * header_find(const struct ListHead *hdrlist, const char *header)
Find a header, matching on its field, in a list of headers.
Definition: email.c:180
Structs that make up an email.
@ NT_HEADER_CHANGE
An existing header has been changed.
Definition: email.h:171
@ NT_HEADER_ADD
Header has been added.
Definition: email.h:169
@ NT_HEADER_DELETE
Header has been removed.
Definition: email.h:170
bool mutt_envlist_unset(const char *name)
Unset an environment variable.
Definition: envlist.c:132
bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:85
char ** mutt_envlist_getlist(void)
Get the private environment.
Definition: envlist.c:169
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:695
#define MUTT_RL_CONT
-continuation
Definition: file.h:39
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:34
struct RegexList SubscribedLists
List of regexes to match subscribed mailing lists.
Definition: globals.c:43
struct HashTable * AutoSubscribeCache
Hash Table of auto-subscribed mailing lists.
Definition: globals.c:38
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: globals.c:40
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: globals.c:42
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: globals.c:41
struct ListHead Ignore
List of header patterns to ignore.
Definition: globals.c:35
struct RegexList NoSpamList
List of regexes to whitelist non-spam emails.
Definition: globals.c:33
struct ListHead UnIgnore
List of header patterns to unignore (see)
Definition: globals.c:36
int mutt_grouplist_remove_addrlist(struct GroupList *gl, struct AddressList *al)
Remove an AddressList from a GroupList.
Definition: group.c:289
void mutt_grouplist_add(struct GroupList *gl, struct Group *group)
Add a Group to a GroupList.
Definition: group.c:181
struct Group * mutt_pattern_group(const char *pat)
Match a pattern to a Group.
Definition: group.c:112
int mutt_grouplist_add_regex(struct GroupList *gl, const char *s, uint16_t flags, struct Buffer *err)
Add matching Addresses to a GroupList.
Definition: group.c:320
int mutt_grouplist_remove_regex(struct GroupList *gl, const char *s)
Remove matching addresses from a GroupList.
Definition: group.c:345
void mutt_grouplist_destroy(struct GroupList *gl)
Free a GroupList.
Definition: group.c:201
void mutt_grouplist_clear(struct GroupList *gl)
Clear a GroupList.
Definition: group.c:147
void mutt_grouplist_add_addrlist(struct GroupList *gl, struct AddressList *al)
Add Address list to a GroupList.
Definition: group.c:270
#define MUTT_GROUP
'group' config command
Definition: group.h:33
#define MUTT_UNGROUP
'ungroup' config command
Definition: group.h:34
enum CommandResult parse_unmy_hdr(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unmy_hdr' command - Implements Command::parse() -.
enum CommandResult parse_tag_formats(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'tag-formats' command - Implements Command::parse() -.
enum CommandResult parse_tag_transforms(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'tag-transforms' command - Implements Command::parse() -.
enum CommandResult parse_unstailq(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse an unlist command - Implements Command::parse() -.
enum CommandResult parse_set(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'set' family of commands - Implements Command::parse() -.
enum CommandResult parse_ifdef(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'ifdef' and 'ifndef' commands - Implements Command::parse() -.
enum CommandResult parse_echo(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'echo' command - Implements Command::parse() -.
enum CommandResult parse_unsubscribe_from(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unsubscribe-from' command - Implements Command::parse() -.
enum CommandResult parse_unmailboxes(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unmailboxes' command - Implements Command::parse() -.
enum CommandResult parse_unsubscribe(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unsubscribe' command - Implements Command::parse() -.
enum CommandResult parse_unignore(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unignore' command - Implements Command::parse() -.
enum CommandResult parse_finish(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'finish' command - Implements Command::parse() -.
enum CommandResult parse_unlists(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unlists' command - Implements Command::parse() -.
enum CommandResult parse_subscribe_to(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'subscribe-to' command - Implements Command::parse() -.
enum CommandResult parse_group(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'group' and 'ungroup' commands - Implements Command::parse() -.
enum CommandResult parse_source(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'source' command - Implements Command::parse() -.
enum CommandResult parse_mailboxes(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'mailboxes' command - Implements Command::parse() -.
enum CommandResult parse_lists(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'lists' command - Implements Command::parse() -.
enum CommandResult parse_cd(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'cd' command - Implements Command::parse() -.
enum CommandResult parse_spam_list(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'spam' and 'nospam' commands - Implements Command::parse() -.
enum CommandResult parse_setenv(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'setenv' and 'unsetenv' commands - Implements Command::parse() -.
enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'my_hdr' command - Implements Command::parse() -.
enum CommandResult parse_subscribe(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'subscribe' command - Implements Command::parse() -.
enum CommandResult parse_stailq(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse a list command - Implements Command::parse() -.
enum CommandResult parse_ignore(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'ignore' command - Implements Command::parse() -.
#define mutt_warning(...)
Definition: logging.h:85
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
Convenience wrapper for the gui headers.
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition: hash.c:335
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:457
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
IMAP network mailbox.
int imap_subscribe(char *path, bool subscribe)
Subscribe to a mailbox.
Definition: imap.c:1289
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:399
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:1044
enum CommandResult mutt_parse_rc_buffer(struct Buffer *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:986
Config/command parsing.
const struct Binding * km_get_table(enum MenuType mtype)
Lookup a menu's keybindings.
Definition: keymap.c:1301
Manage keymappings.
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:68
int mailbox_gen(void)
Get the next generation number.
Definition: mailbox.c:58
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
@ NT_MAILBOX_SWITCH
Current Mailbox has changed.
Definition: mailbox.h:182
#define MB_HIDDEN
Definition: mailbox.h:38
@ MUTT_MAILBOX_ANY
Match any Mailbox type.
Definition: mailbox.h:45
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:47
#define MB_NORMAL
Definition: mailbox.h:37
#define FREE(x)
Definition: memory.h:40
GUI present the user with a selectable list.
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:483
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:528
Monitor files for changes.
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:764
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
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 notify_free(struct Notify **ptr)
Free a notification handler.
Definition: notify.c:73
bool mutt_path_tilde(char *buf, size_t buflen, const char *homedir)
Expand '~' in a path.
Definition: path.c:223
bool mutt_path_to_absolute(char *path, const char *reference)
Convert relative filepath to an absolute path.
Definition: path.c:397
int mutt_replacelist_remove(struct ReplaceList *rl, const char *pat)
Remove a pattern from a list.
Definition: regex.c:581
void mutt_regexlist_free(struct RegexList *rl)
Free a RegexList object.
Definition: regex.c:173
int mutt_regexlist_add(struct RegexList *rl, const char *str, uint16_t flags, struct Buffer *err)
Compile a regex string and add it to a list.
Definition: regex.c:134
void mutt_replacelist_free(struct ReplaceList *rl)
Free a ReplaceList object.
Definition: regex.c:465
int mutt_regexlist_remove(struct RegexList *rl, const char *str)
Remove a Regex from a list.
Definition: regex.c:229
int mutt_replacelist_add(struct ReplaceList *rl, const char *pat, const char *templ, struct Buffer *err)
Add a pattern and a template to a list.
Definition: regex.c:265
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:727
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:181
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:715
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:158
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:475
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:835
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:560
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:257
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:432
Many unsorted constants and some structs.
#define MUTT_TOKEN_BACKTICK_VARS
Expand variables within backticks.
Definition: mutt.h:74
#define MUTT_TOKEN_MINUS
Treat '-' as a special.
Definition: mutt.h:78
#define MUTT_TOKEN_PLUS
Treat '+' as a special.
Definition: mutt.h:77
#define MUTT_TOKEN_QUOTE
Don't interpret quotes.
Definition: mutt.h:70
#define MUTT_NOSPAM
Definition: mutt.h:111
#define MUTT_TOKEN_SPACE
Don't treat whitespace as a term.
Definition: mutt.h:69
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:66
#define MUTT_TOKEN_EQUAL
Treat '=' as a special.
Definition: mutt.h:67
#define MUTT_TOKEN_QUESTION
Treat '?' as a special.
Definition: mutt.h:76
#define MUTT_SPAM
Definition: mutt.h:110
#define PATH_MAX
Definition: mutt.h:40
struct Command * mutt_command_get(const char *s)
Get a Command by its name.
Definitions of NeoMutt commands.
#define MUTT_NAMED
Definition: mutt_commands.h:44
@ MUTT_SET_INV
default is to invert all vars
Definition: mutt_commands.h:38
@ MUTT_SET_SET
default is to set all vars
Definition: mutt_commands.h:37
@ MUTT_SET_RESET
default is to reset all vars to default
Definition: mutt_commands.h:40
@ MUTT_SET_UNSET
default is to unset all vars
Definition: mutt_commands.h:39
Hundreds of global variables to back the user variables.
struct HashTable * TagFormats
Hash Table of tag-formats (tag -> format string)
Definition: mutt_globals.h:59
struct ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition: mutt_globals.h:68
void remove_from_stailq(struct ListHead *head, const char *str)
Remove an item, matching a string, from a List.
Definition: muttlib.c:1753
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
void add_to_stailq(struct ListHead *head, const char *str)
Add a string to a list.
Definition: muttlib.c:1728
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:122
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1461
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:1315
Some miscellaneous functions.
bool mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1765
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1587
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1563
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1477
API for mailboxes.
void myvar_del(const char *var)
Unset the value of a "my_" variable.
Definition: myvar.c:146
const char * myvar_get(const char *var)
Get the value of a "my_" variable.
Definition: myvar.c:92
void myvar_set(const char *var, const char *val)
Set the value of a "my_" variable.
Definition: myvar.c:109
void myvar_append(const char *var, const char *val)
Append to the value of a "my_" variable.
Definition: myvar.c:128
Handling of personal config ('my' variables)
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:141
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:84
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:164
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:48
@ NT_HEADER
A header has changed, NotifyHeader EventHeader.
Definition: notify_type.h:46
Handling of global boolean variables.
bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:42
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
int quad_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a quad.
Definition: quad.c:204
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define STAILQ_REMOVE_HEAD(head, field)
Definition: queue.h:422
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
#define TAILQ_EMPTY(head)
Definition: queue.h:721
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
#define NONULL(x)
Definition: string2.h:37
#define SKIPWS(ch)
Definition: string2.h:46
A group of associated Mailboxes.
Definition: account.h:37
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
char * name
Name of Account.
Definition: account.h:39
struct Notify * notify
Notifications: NotifyAccount, EventAccount.
Definition: account.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: account.h:40
Mapping between a user key and a function.
Definition: keymap.h:92
const char * name
name of the function
Definition: keymap.h:93
String manipulation buffer.
Definition: buffer.h:34
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
An event that happened to a header.
Definition: email.h:178
An Event that happened to a Mailbox.
Definition: mailbox.h:191
The item stored in a Hash Table.
Definition: hash.h:44
union HashKey key
Key representing the data.
Definition: hash.h:46
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:45
void * data
User-supplied data.
Definition: hash.h:47
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
List of Mailboxes.
Definition: mailbox.h:157
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:158
A mailbox.
Definition: mailbox.h:82
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:83
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:131
int opened
Number of times mailbox is opened.
Definition: mailbox.h:132
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
int gen
Generation number, for sorting.
Definition: mailbox.h:150
const char * name
String value.
Definition: mapping.h:33
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
int cs_subset_he_string_minus_equals(const struct ConfigSubset *sub, struct HashElem *he, const char *value, struct Buffer *err)
Remove from a config item by string.
Definition: subset.c:462
int cs_subset_he_string_get(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:354
int cs_subset_he_native_set(const struct ConfigSubset *sub, struct HashElem *he, intptr_t value, struct Buffer *err)
Natively set the value of a HashElem config item.
Definition: subset.c:283
int cs_subset_he_reset(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Reset a config item to its initial value.
Definition: subset.c:320
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:179
int cs_subset_he_string_set(const struct ConfigSubset *sub, struct HashElem *he, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:386
struct HashElem ** get_elem_list(struct ConfigSet *cs)
Create a sorted list of all config items.
Definition: subset.c:75
void cs_subset_free(struct ConfigSubset **ptr)
Free a Config Subset.
Definition: subset.c:104
int cs_subset_he_string_plus_equals(const struct ConfigSubset *sub, struct HashElem *he, const char *value, struct Buffer *err)
Add to a config item by string.
Definition: subset.c:424
struct HashTable * TagTransforms
Lookup table of alternative tag names.
Definition: tags.c:37
const struct Mapping MenuNames[]
Menu name lookup table.
Definition: type.c:31
#define DTYPE(x)
Mask for the Data Type.
Definition: types.h:44
#define IS_MAILBOX(x)
Definition: types.h:57
#define DT_QUAD
quad-option (no/yes/ask-no/ask-yes)
Definition: types.h:37
#define DT_BOOL
boolean option
Definition: types.h:30
#define DT_PATH_DIR
Path is a directory.
Definition: types.h:53
#define DT_PATH_FILE
Path is a file.
Definition: types.h:54
#define DT_PATH
a path to a file/directory
Definition: types.h:36
#define IS_COMMAND(x)
Definition: types.h:58
const char * strkey
String key.
Definition: hash.h:36
bool feature_enabled(const char *name)
Test if a compile-time feature is enabled.
Definition: version.c:560
Display version and copyright about NeoMutt.