NeoMutt  2022-04-29-145-g9b6a0e
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 "mutt_commands.h"
52 #include "mutt_globals.h"
53 #include "muttlib.h"
54 #include "mx.h"
55 #include "myvar.h"
56 #include "options.h"
57 #include "version.h"
58 #ifdef USE_INOTIFY
59 #include "monitor.h"
60 #endif
61 #ifdef ENABLE_NLS
62 #include <libintl.h>
63 #endif
64 
65 /* LIFO designed to contain the list of config files that have been sourced and
66  * avoid cyclic sourcing */
67 static struct ListHead MuttrcStack = STAILQ_HEAD_INITIALIZER(MuttrcStack);
68 
69 #define MAX_ERRS 128
70 
75 {
79 };
80 
87 static bool is_function(const char *name)
88 {
89  for (size_t i = 0; MenuNames[i].name; i++)
90  {
91  const struct MenuFuncOp *fns = km_get_table(MenuNames[i].value);
92  if (!fns)
93  continue;
94 
95  for (int j = 0; fns[j].name; j++)
96  if (mutt_str_equal(name, fns[j].name))
97  return true;
98  }
99  return false;
100 }
101 
111 int parse_grouplist(struct GroupList *gl, struct Buffer *buf, struct Buffer *s,
112  struct Buffer *err)
113 {
114  while (mutt_istr_equal(buf->data, "-group"))
115  {
116  if (!MoreArgs(s))
117  {
118  mutt_buffer_strcpy(err, _("-group: no group name"));
119  return -1;
120  }
121 
123 
125 
126  if (!MoreArgs(s))
127  {
128  mutt_buffer_strcpy(err, _("out of arguments"));
129  return -1;
130  }
131 
133  }
134 
135  return 0;
136 }
137 
144 int source_rc(const char *rcfile_path, struct Buffer *err)
145 {
146  int lineno = 0, rc = 0, warnings = 0;
147  enum CommandResult line_rc;
148  struct Buffer *token = NULL, *linebuf = NULL;
149  char *line = NULL;
150  char *currentline = NULL;
151  char rcfile[PATH_MAX];
152  size_t linelen = 0;
153  pid_t pid;
154 
155  mutt_str_copy(rcfile, rcfile_path, sizeof(rcfile));
156 
157  size_t rcfilelen = mutt_str_len(rcfile);
158  if (rcfilelen == 0)
159  return -1;
160 
161  bool ispipe = rcfile[rcfilelen - 1] == '|';
162 
163  if (!ispipe)
164  {
165  struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
166  if (!mutt_path_to_absolute(rcfile, np ? NONULL(np->data) : ""))
167  {
168  mutt_error(_("Error: Can't build path of '%s'"), rcfile_path);
169  return -1;
170  }
171 
172  STAILQ_FOREACH(np, &MuttrcStack, entries)
173  {
174  if (mutt_str_equal(np->data, rcfile))
175  {
176  break;
177  }
178  }
179  if (np)
180  {
181  mutt_error(_("Error: Cyclic sourcing of configuration file '%s'"), rcfile);
182  return -1;
183  }
184 
186  }
187 
188  mutt_debug(LL_DEBUG2, "Reading configuration file '%s'\n", rcfile);
189 
190  FILE *fp = mutt_open_read(rcfile, &pid);
191  if (!fp)
192  {
193  mutt_buffer_printf(err, "%s: %s", rcfile, strerror(errno));
194  return -1;
195  }
196 
197  token = mutt_buffer_pool_get();
198  linebuf = mutt_buffer_pool_get();
199 
200  while ((line = mutt_file_read_line(line, &linelen, fp, &lineno, MUTT_RL_CONT)) != NULL)
201  {
202  const char *const c_config_charset = cs_subset_string(NeoMutt->sub, "config_charset");
203  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
204  const bool conv = c_config_charset && c_charset;
205  if (conv)
206  {
207  currentline = mutt_str_dup(line);
208  if (!currentline)
209  continue;
210  mutt_ch_convert_string(&currentline, c_config_charset, c_charset, MUTT_ICONV_NO_FLAGS);
211  }
212  else
213  currentline = line;
214 
215  mutt_buffer_strcpy(linebuf, currentline);
216 
217  mutt_buffer_reset(err);
218  line_rc = mutt_parse_rc_buffer(linebuf, token, err);
219  if (line_rc == MUTT_CMD_ERROR)
220  {
221  mutt_error(_("Error in %s, line %d: %s"), rcfile, lineno, err->data);
222  if (--rc < -MAX_ERRS)
223  {
224  if (conv)
225  FREE(&currentline);
226  break;
227  }
228  }
229  else if (line_rc == MUTT_CMD_WARNING)
230  {
231  /* Warning */
232  mutt_warning(_("Warning in %s, line %d: %s"), rcfile, lineno, err->data);
233  warnings++;
234  }
235  else if (line_rc == MUTT_CMD_FINISH)
236  {
237  if (conv)
238  FREE(&currentline);
239  break; /* Found "finish" command */
240  }
241  else
242  {
243  if (rc < 0)
244  rc = -1;
245  }
246  if (conv)
247  FREE(&currentline);
248  }
249 
250  FREE(&line);
251  mutt_file_fclose(&fp);
252  if (pid != -1)
253  filter_wait(pid);
254 
255  if (rc)
256  {
257  /* the neomuttrc source keyword */
258  mutt_buffer_reset(err);
259  mutt_buffer_printf(err,
260  (rc >= -MAX_ERRS) ?
261  _("source: errors in %s") :
262  _("source: reading aborted due to too many errors in %s"),
263  rcfile);
264  rc = -1;
265  }
266  else
267  {
268  /* Don't alias errors with warnings */
269  if (warnings > 0)
270  {
271  mutt_buffer_printf(err, ngettext("source: %d warning in %s", "source: %d warnings in %s", warnings),
272  warnings, rcfile);
273  rc = -2;
274  }
275  }
276 
277  if (!ispipe && !STAILQ_EMPTY(&MuttrcStack))
278  {
279  struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
280  STAILQ_REMOVE_HEAD(&MuttrcStack, entries);
281  FREE(&np->data);
282  FREE(&np);
283  }
284 
285  mutt_buffer_pool_release(&token);
286  mutt_buffer_pool_release(&linebuf);
287  return rc;
288 }
289 
293 enum CommandResult parse_cd(struct Buffer *buf, struct Buffer *s, intptr_t data,
294  struct Buffer *err)
295 {
298  if (mutt_buffer_len(buf) == 0)
299  {
300  if (HomeDir)
302  else
303  {
304  mutt_buffer_printf(err, _("%s: too few arguments"), "cd");
305  return MUTT_CMD_ERROR;
306  }
307  }
308 
309  if (chdir(mutt_buffer_string(buf)) != 0)
310  {
311  mutt_buffer_printf(err, "cd: %s", strerror(errno));
312  return MUTT_CMD_ERROR;
313  }
314 
315  return MUTT_CMD_SUCCESS;
316 }
317 
321 enum CommandResult parse_echo(struct Buffer *buf, struct Buffer *s,
322  intptr_t data, struct Buffer *err)
323 {
324  if (!MoreArgs(s))
325  {
326  mutt_buffer_printf(err, _("%s: too few arguments"), "echo");
327  return MUTT_CMD_WARNING;
328  }
330  OptForceRefresh = true;
331  mutt_message("%s", buf->data);
332  OptForceRefresh = false;
333  mutt_sleep(0);
334 
335  return MUTT_CMD_SUCCESS;
336 }
337 
345 enum CommandResult parse_finish(struct Buffer *buf, struct Buffer *s,
346  intptr_t data, struct Buffer *err)
347 {
348  if (MoreArgs(s))
349  {
350  mutt_buffer_printf(err, _("%s: too many arguments"), "finish");
351  return MUTT_CMD_WARNING;
352  }
353 
354  return MUTT_CMD_FINISH;
355 }
356 
360 enum CommandResult parse_group(struct Buffer *buf, struct Buffer *s,
361  intptr_t data, struct Buffer *err)
362 {
363  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
364  enum GroupState state = GS_NONE;
365 
366  do
367  {
369  if (parse_grouplist(&gl, buf, s, err) == -1)
370  goto bail;
371 
372  if ((data == MUTT_UNGROUP) && mutt_istr_equal(buf->data, "*"))
373  {
375  goto out;
376  }
377 
378  if (mutt_istr_equal(buf->data, "-rx"))
379  state = GS_RX;
380  else if (mutt_istr_equal(buf->data, "-addr"))
381  state = GS_ADDR;
382  else
383  {
384  switch (state)
385  {
386  case GS_NONE:
387  mutt_buffer_printf(err, _("%sgroup: missing -rx or -addr"),
388  (data == MUTT_UNGROUP) ? "un" : "");
389  goto warn;
390 
391  case GS_RX:
392  if ((data == MUTT_GROUP) &&
393  (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0))
394  {
395  goto bail;
396  }
397  else if ((data == MUTT_UNGROUP) &&
398  (mutt_grouplist_remove_regex(&gl, buf->data) < 0))
399  {
400  goto bail;
401  }
402  break;
403 
404  case GS_ADDR:
405  {
406  char *estr = NULL;
407  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
408  mutt_addrlist_parse2(&al, buf->data);
409  if (TAILQ_EMPTY(&al))
410  goto bail;
411  if (mutt_addrlist_to_intl(&al, &estr))
412  {
413  mutt_buffer_printf(err, _("%sgroup: warning: bad IDN '%s'"),
414  (data == 1) ? "un" : "", estr);
415  mutt_addrlist_clear(&al);
416  FREE(&estr);
417  goto bail;
418  }
419  if (data == MUTT_GROUP)
420  mutt_grouplist_add_addrlist(&gl, &al);
421  else if (data == MUTT_UNGROUP)
423  mutt_addrlist_clear(&al);
424  break;
425  }
426  }
427  }
428  } while (MoreArgs(s));
429 
430 out:
432  return MUTT_CMD_SUCCESS;
433 
434 bail:
436  return MUTT_CMD_ERROR;
437 
438 warn:
440  return MUTT_CMD_WARNING;
441 }
442 
456 enum CommandResult parse_ifdef(struct Buffer *buf, struct Buffer *s,
457  intptr_t data, struct Buffer *err)
458 {
460 
461  // is the item defined as:
462  bool res = cs_subset_lookup(NeoMutt->sub, buf->data) // a variable?
463  || feature_enabled(buf->data) // a compiled-in feature?
464  || is_function(buf->data) // a function?
465  || mutt_command_get(buf->data) // a command?
466  || myvar_get(buf->data) // a my_ variable?
467  || mutt_str_getenv(buf->data); // an environment variable?
468 
469  if (!MoreArgs(s))
470  {
471  mutt_buffer_printf(err, _("%s: too few arguments"), (data ? "ifndef" : "ifdef"));
472  return MUTT_CMD_WARNING;
473  }
475 
476  /* ifdef KNOWN_SYMBOL or ifndef UNKNOWN_SYMBOL */
477  if ((res && (data == 0)) || (!res && (data == 1)))
478  {
479  enum CommandResult rc = mutt_parse_rc_line(buf->data, err);
480  if (rc == MUTT_CMD_ERROR)
481  {
482  mutt_error(_("Error: %s"), err->data);
483  return MUTT_CMD_ERROR;
484  }
485  return rc;
486  }
487  return MUTT_CMD_SUCCESS;
488 }
489 
493 enum CommandResult parse_ignore(struct Buffer *buf, struct Buffer *s,
494  intptr_t data, struct Buffer *err)
495 {
496  do
497  {
500  add_to_stailq(&Ignore, buf->data);
501  } while (MoreArgs(s));
502 
503  return MUTT_CMD_SUCCESS;
504 }
505 
509 enum CommandResult parse_lists(struct Buffer *buf, struct Buffer *s,
510  intptr_t data, struct Buffer *err)
511 {
512  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
513 
514  do
515  {
517 
518  if (parse_grouplist(&gl, buf, s, err) == -1)
519  goto bail;
520 
522 
523  if (mutt_regexlist_add(&MailLists, buf->data, REG_ICASE, err) != 0)
524  goto bail;
525 
526  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
527  goto bail;
528  } while (MoreArgs(s));
529 
531  return MUTT_CMD_SUCCESS;
532 
533 bail:
535  return MUTT_CMD_ERROR;
536 }
537 
543 enum CommandResult parse_mailboxes(struct Buffer *buf, struct Buffer *s,
544  intptr_t data, struct Buffer *err)
545 {
546  while (MoreArgs(s))
547  {
548  struct Mailbox *m = mailbox_new();
549 
550  if (data & MUTT_NAMED)
551  {
552  // This may be empty, e.g. `named-mailboxes "" +inbox`
554  m->name = mutt_buffer_strdup(buf);
555  }
556 
558  if (mutt_buffer_is_empty(buf))
559  {
560  /* Skip empty tokens. */
561  mailbox_free(&m);
562  continue;
563  }
564 
565  mutt_buffer_strcpy(&m->pathbuf, buf->data);
566  const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
567  /* int rc = */ mx_path_canon2(m, c_folder);
568 
569  if (m->type <= MUTT_UNKNOWN)
570  {
571  mutt_error("Unknown Mailbox: %s", m->realpath);
572  mailbox_free(&m);
573  return MUTT_CMD_ERROR;
574  }
575 
576  bool new_account = false;
577  struct Account *a = mx_ac_find(m);
578  if (!a)
579  {
580  a = account_new(NULL, NeoMutt->sub);
581  a->type = m->type;
582  new_account = true;
583  }
584 
585  if (!new_account)
586  {
587  struct Mailbox *m_old = mx_mbox_find(a, m->realpath);
588  if (m_old)
589  {
590  if (!m_old->visible)
591  {
592  m_old->visible = true;
593  m_old->gen = mailbox_gen();
594  }
595 
596  const bool rename = (data & MUTT_NAMED) && !mutt_str_equal(m_old->name, m->name);
597  if (rename)
598  {
599  mutt_str_replace(&m_old->name, m->name);
600  }
601 
602  mailbox_free(&m);
603  continue;
604  }
605  }
606 
607  if (!mx_ac_add(a, m))
608  {
609  mailbox_free(&m);
610  if (new_account)
611  {
612  cs_subset_free(&a->sub);
613  FREE(&a->name);
614  notify_free(&a->notify);
615  FREE(&a);
616  }
617  continue;
618  }
619  if (new_account)
620  {
622  }
623 
624  // this is finally a visible mailbox in the sidebar and mailboxes list
625  m->visible = true;
626 
627 #ifdef USE_INOTIFY
628  mutt_monitor_add(m);
629 #endif
630  }
631  return MUTT_CMD_SUCCESS;
632 }
633 
637 enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s,
638  intptr_t data, struct Buffer *err)
639 {
641  char *p = strpbrk(buf->data, ": \t");
642  if (!p || (*p != ':'))
643  {
644  mutt_buffer_strcpy(err, _("invalid header field"));
645  return MUTT_CMD_WARNING;
646  }
647 
648  struct EventHeader ev_h = { buf->data };
649  struct ListNode *n = header_find(&UserHeader, buf->data);
650 
651  if (n)
652  {
653  header_update(n, buf->data);
654  mutt_debug(LL_NOTIFY, "NT_HEADER_CHANGE: %s\n", buf->data);
656  }
657  else
658  {
659  header_add(&UserHeader, buf->data);
660  mutt_debug(LL_NOTIFY, "NT_HEADER_ADD: %s\n", buf->data);
662  }
663 
664  return MUTT_CMD_SUCCESS;
665 }
666 
672 enum CommandResult parse_set(struct Buffer *buf, struct Buffer *s,
673  intptr_t data, struct Buffer *err)
674 {
675  /* The order must match `enum MuttSetCommand` */
676  static const char *set_commands[] = { "set", "toggle", "unset", "reset" };
677 
678  int rc = 0;
679 
680  while (MoreArgs(s))
681  {
682  bool prefix = false;
683  bool query = false;
684  bool inv = (data == MUTT_SET_INV);
685  bool reset = (data == MUTT_SET_RESET);
686  bool unset = (data == MUTT_SET_UNSET);
687 
688  if (*s->dptr == '?')
689  {
690  prefix = true;
691  query = true;
692  s->dptr++;
693  }
694  else if (mutt_str_startswith(s->dptr, "no"))
695  {
696  prefix = true;
697  unset = !unset;
698  s->dptr += 2;
699  }
700  else if (mutt_str_startswith(s->dptr, "inv"))
701  {
702  prefix = true;
703  inv = !inv;
704  s->dptr += 3;
705  }
706  else if (*s->dptr == '&')
707  {
708  prefix = true;
709  reset = true;
710  s->dptr++;
711  }
712 
713  if (prefix && (data != MUTT_SET_SET))
714  {
715  mutt_buffer_printf(err, _("Can't use 'inv', 'no', '&' or '?' with the '%s' command"),
716  set_commands[data]);
717  return MUTT_CMD_WARNING;
718  }
719 
720  /* get the variable name */
722 
723  bool bq = false;
724  bool equals = false;
725  bool increment = false;
726  bool decrement = false;
727 
728  struct HashElem *he = NULL;
729  bool my = mutt_str_startswith(buf->data, "my_");
730  if (!my)
731  {
732  he = cs_subset_lookup(NeoMutt->sub, buf->data);
733  if (!he)
734  {
735  if (reset && mutt_str_equal(buf->data, "all"))
736  {
737  struct HashElem **list = get_elem_list(NeoMutt->sub->cs);
738  if (!list)
739  return MUTT_CMD_ERROR;
740 
741  for (size_t i = 0; list[i]; i++)
742  cs_subset_he_reset(NeoMutt->sub, list[i], NULL);
743 
744  FREE(&list);
745  break;
746  }
747  else
748  {
749  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
750  return MUTT_CMD_ERROR;
751  }
752  }
753 
754  // Use the correct name if a synonym is used
755  mutt_buffer_strcpy(buf, he->key.strkey);
756 
757  bq = ((DTYPE(he->type) == DT_BOOL) || (DTYPE(he->type) == DT_QUAD));
758  }
759 
760  if (*s->dptr == '?')
761  {
762  if (prefix)
763  {
764  mutt_buffer_printf(err, _("Can't use a prefix when querying a variable"));
765  return MUTT_CMD_WARNING;
766  }
767 
768  if (reset || unset || inv)
769  {
770  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"),
771  set_commands[data]);
772  return MUTT_CMD_WARNING;
773  }
774 
775  query = true;
776  s->dptr++;
777  }
778  else if (*s->dptr == '+' || *s->dptr == '-')
779  {
780  if (prefix)
781  {
782  mutt_buffer_printf(err, _("Can't use prefix when incrementing or decrementing a variable"));
783  return MUTT_CMD_WARNING;
784  }
785 
786  if (reset || unset || inv)
787  {
788  mutt_buffer_printf(err, _("Can't set a variable with the '%s' command"),
789  set_commands[data]);
790  return MUTT_CMD_WARNING;
791  }
792  if (*s->dptr == '+')
793  increment = true;
794  else
795  decrement = true;
796 
797  if (my && decrement)
798  {
799  mutt_buffer_printf(err, _("Can't decrement a my_ variable"), set_commands[data]);
800  return MUTT_CMD_WARNING;
801  }
802  s->dptr++;
803  if (*s->dptr == '=')
804  {
805  equals = true;
806  s->dptr++;
807  }
808  }
809  else if (*s->dptr == '=')
810  {
811  if (prefix)
812  {
813  mutt_buffer_printf(err, _("Can't use prefix when setting a variable"));
814  return MUTT_CMD_WARNING;
815  }
816 
817  if (reset || unset || inv)
818  {
819  mutt_buffer_printf(err, _("Can't set a variable with the '%s' command"),
820  set_commands[data]);
821  return MUTT_CMD_WARNING;
822  }
823 
824  equals = true;
825  s->dptr++;
826  }
827 
828  if (!bq && (inv || (unset && prefix)))
829  {
830  if (data == MUTT_SET_SET)
831  {
832  mutt_buffer_printf(err, _("Prefixes 'no' and 'inv' may only be used with bool/quad variables"));
833  }
834  else
835  {
836  mutt_buffer_printf(err, _("Command '%s' can only be used with bool/quad variables"),
837  set_commands[data]);
838  }
839  return MUTT_CMD_WARNING;
840  }
841 
842  if (reset)
843  {
844  // mutt_buffer_printf(err, "ACT24 reset variable %s", buf->data);
845  if (he)
846  {
847  rc = cs_subset_he_reset(NeoMutt->sub, he, err);
848  if (CSR_RESULT(rc) != CSR_SUCCESS)
849  return MUTT_CMD_ERROR;
850  }
851  else
852  {
853  myvar_del(buf->data);
854  }
855  continue;
856  }
857 
858  if ((data == MUTT_SET_SET) && !inv && !unset)
859  {
860  if (query)
861  {
862  // mutt_buffer_printf(err, "ACT08 query variable %s", buf->data);
863  if (he)
864  {
865  mutt_buffer_addstr(err, buf->data);
866  mutt_buffer_addch(err, '=');
867  mutt_buffer_reset(buf);
868  rc = cs_subset_he_string_get(NeoMutt->sub, he, buf);
869  if (CSR_RESULT(rc) != CSR_SUCCESS)
870  {
871  mutt_buffer_addstr(err, buf->data);
872  return MUTT_CMD_ERROR;
873  }
874  if (DTYPE(he->type) == DT_PATH)
875  mutt_pretty_mailbox(buf->data, buf->dsize);
876  pretty_var(buf->data, err);
877  }
878  else
879  {
880  const char *val = myvar_get(buf->data);
881  if (val)
882  {
883  mutt_buffer_addstr(err, buf->data);
884  mutt_buffer_addch(err, '=');
885  pretty_var(val, err);
886  }
887  else
888  {
889  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
890  return MUTT_CMD_ERROR;
891  }
892  }
893  break;
894  }
895  else if (equals)
896  {
897  // mutt_buffer_printf(err, "ACT11 set variable %s to ", buf->data);
898  const char *name = NULL;
899  if (my)
900  {
901  name = mutt_str_dup(buf->data);
902  }
904  if (my)
905  {
906  assert(!decrement);
907  if (increment)
908  {
909  myvar_append(name, buf->data);
910  }
911  else
912  {
913  myvar_set(name, buf->data);
914  }
915  FREE(&name);
916  }
917  else
918  {
919  if (DTYPE(he->type) == DT_PATH)
920  {
921  if (he->type & (DT_PATH_DIR | DT_PATH_FILE))
923  else
924  mutt_path_tilde(buf->data, buf->dsize, HomeDir);
925  }
926  else if (IS_MAILBOX(he))
927  {
929  }
930  else if (IS_COMMAND(he))
931  {
932  struct Buffer scratch = mutt_buffer_make(1024);
933  mutt_buffer_copy(&scratch, buf);
934 
935  if (!mutt_str_equal(buf->data, "builtin"))
936  {
937  mutt_buffer_expand_path(&scratch);
938  }
939  mutt_buffer_reset(buf);
940  mutt_buffer_addstr(buf, mutt_buffer_string(&scratch));
941  mutt_buffer_dealloc(&scratch);
942  }
943  if (increment)
944  {
945  rc = cs_subset_he_string_plus_equals(NeoMutt->sub, he, buf->data, err);
946  }
947  else if (decrement)
948  {
949  rc = cs_subset_he_string_minus_equals(NeoMutt->sub, he, buf->data, err);
950  }
951  else
952  {
953  rc = cs_subset_he_string_set(NeoMutt->sub, he, buf->data, err);
954  }
955  if (CSR_RESULT(rc) != CSR_SUCCESS)
956  return MUTT_CMD_ERROR;
957  }
958  continue;
959  }
960  else
961  {
962  if (bq)
963  {
964  // mutt_buffer_printf(err, "ACT23 set variable %s to 'yes'", buf->data);
965  rc = cs_subset_he_native_set(NeoMutt->sub, he, true, err);
966  if (CSR_RESULT(rc) != CSR_SUCCESS)
967  return MUTT_CMD_ERROR;
968  continue;
969  }
970  else
971  {
972  // mutt_buffer_printf(err, "ACT10 query variable %s", buf->data);
973  if (he)
974  {
975  mutt_buffer_addstr(err, buf->data);
976  mutt_buffer_addch(err, '=');
977  mutt_buffer_reset(buf);
978  rc = cs_subset_he_string_get(NeoMutt->sub, he, buf);
979  if (CSR_RESULT(rc) != CSR_SUCCESS)
980  {
981  mutt_buffer_addstr(err, buf->data);
982  return MUTT_CMD_ERROR;
983  }
984  if (DTYPE(he->type) == DT_PATH)
985  mutt_pretty_mailbox(buf->data, buf->dsize);
986  pretty_var(buf->data, err);
987  }
988  else
989  {
990  const char *val = myvar_get(buf->data);
991  if (val)
992  {
993  mutt_buffer_addstr(err, buf->data);
994  mutt_buffer_addch(err, '=');
995  pretty_var(val, err);
996  }
997  else
998  {
999  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
1000  return MUTT_CMD_ERROR;
1001  }
1002  }
1003  break;
1004  }
1005  }
1006  }
1007 
1008  if (my)
1009  {
1010  myvar_del(buf->data);
1011  }
1012  else if (bq)
1013  {
1014  if (inv)
1015  {
1016  // mutt_buffer_printf(err, "ACT25 TOGGLE bool/quad variable %s", buf->data);
1017  if (DTYPE(he->type) == DT_BOOL)
1018  bool_he_toggle(NeoMutt->sub, he, err);
1019  else
1020  quad_he_toggle(NeoMutt->sub, he, err);
1021  }
1022  else
1023  {
1024  // mutt_buffer_printf(err, "ACT26 UNSET bool/quad variable %s", buf->data);
1025  rc = cs_subset_he_native_set(NeoMutt->sub, he, false, err);
1026  if (CSR_RESULT(rc) != CSR_SUCCESS)
1027  return MUTT_CMD_ERROR;
1028  }
1029  continue;
1030  }
1031  else
1032  {
1033  rc = cs_subset_he_string_set(NeoMutt->sub, he, NULL, err);
1034  if (CSR_RESULT(rc) != CSR_SUCCESS)
1035  return MUTT_CMD_ERROR;
1036  }
1037  }
1038 
1039  return MUTT_CMD_SUCCESS;
1040 }
1041 
1045 enum CommandResult parse_setenv(struct Buffer *buf, struct Buffer *s,
1046  intptr_t data, struct Buffer *err)
1047 {
1048  char **envp = mutt_envlist_getlist();
1049 
1050  bool query = false;
1051  bool prefix = false;
1052  bool unset = (data == MUTT_SET_UNSET);
1053 
1054  if (!MoreArgs(s))
1055  {
1056  mutt_buffer_printf(err, _("%s: too few arguments"), "setenv");
1057  return MUTT_CMD_WARNING;
1058  }
1059 
1060  if (*s->dptr == '?')
1061  {
1062  query = true;
1063  prefix = true;
1064 
1065  if (unset)
1066  {
1067  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"), "unsetenv");
1068  return MUTT_CMD_WARNING;
1069  }
1070 
1071  s->dptr++;
1072  }
1073 
1074  /* get variable name */
1076 
1077  if (*s->dptr == '?')
1078  {
1079  if (unset)
1080  {
1081  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"), "unsetenv");
1082  return MUTT_CMD_WARNING;
1083  }
1084 
1085  if (prefix)
1086  {
1087  mutt_buffer_printf(err, _("Can't use a prefix when querying a variable"));
1088  return MUTT_CMD_WARNING;
1089  }
1090 
1091  query = true;
1092  s->dptr++;
1093  }
1094 
1095  if (query)
1096  {
1097  bool found = false;
1098  while (envp && *envp)
1099  {
1100  /* This will display all matches for "^QUERY" */
1101  if (mutt_str_startswith(*envp, buf->data))
1102  {
1103  if (!found)
1104  {
1105  mutt_endwin();
1106  found = true;
1107  }
1108  puts(*envp);
1109  }
1110  envp++;
1111  }
1112 
1113  if (found)
1114  {
1116  return MUTT_CMD_SUCCESS;
1117  }
1118 
1119  mutt_buffer_printf(err, _("%s is unset"), buf->data);
1120  return MUTT_CMD_WARNING;
1121  }
1122 
1123  if (unset)
1124  {
1125  if (!mutt_envlist_unset(buf->data))
1126  {
1127  mutt_buffer_printf(err, _("%s is unset"), buf->data);
1128  return MUTT_CMD_WARNING;
1129  }
1130  return MUTT_CMD_SUCCESS;
1131  }
1132 
1133  /* set variable */
1134 
1135  if (*s->dptr == '=')
1136  {
1137  s->dptr++;
1138  SKIPWS(s->dptr);
1139  }
1140 
1141  if (!MoreArgs(s))
1142  {
1143  mutt_buffer_printf(err, _("%s: too few arguments"), "setenv");
1144  return MUTT_CMD_WARNING;
1145  }
1146 
1147  char *name = mutt_str_dup(buf->data);
1149  mutt_envlist_set(name, buf->data, true);
1150  FREE(&name);
1151 
1152  return MUTT_CMD_SUCCESS;
1153 }
1154 
1158 enum CommandResult parse_source(struct Buffer *buf, struct Buffer *s,
1159  intptr_t data, struct Buffer *err)
1160 {
1161  char path[PATH_MAX];
1162 
1163  do
1164  {
1165  if (mutt_extract_token(buf, s, MUTT_TOKEN_NO_FLAGS) != 0)
1166  {
1167  mutt_buffer_printf(err, _("source: error at %s"), s->dptr);
1168  return MUTT_CMD_ERROR;
1169  }
1170  mutt_str_copy(path, buf->data, sizeof(path));
1171  mutt_expand_path(path, sizeof(path));
1172 
1173  if (source_rc(path, err) < 0)
1174  {
1175  mutt_buffer_printf(err, _("source: file %s could not be sourced"), path);
1176  return MUTT_CMD_ERROR;
1177  }
1178 
1179  } while (MoreArgs(s));
1180 
1181  return MUTT_CMD_SUCCESS;
1182 }
1183 
1187 enum CommandResult parse_spam_list(struct Buffer *buf, struct Buffer *s,
1188  intptr_t data, struct Buffer *err)
1189 {
1190  struct Buffer templ;
1191 
1192  mutt_buffer_init(&templ);
1193 
1194  /* Insist on at least one parameter */
1195  if (!MoreArgs(s))
1196  {
1197  if (data == MUTT_SPAM)
1198  mutt_buffer_strcpy(err, _("spam: no matching pattern"));
1199  else
1200  mutt_buffer_strcpy(err, _("nospam: no matching pattern"));
1201  return MUTT_CMD_ERROR;
1202  }
1203 
1204  /* Extract the first token, a regex */
1206 
1207  /* data should be either MUTT_SPAM or MUTT_NOSPAM. MUTT_SPAM is for spam commands. */
1208  if (data == MUTT_SPAM)
1209  {
1210  /* If there's a second parameter, it's a template for the spam tag. */
1211  if (MoreArgs(s))
1212  {
1214 
1215  /* Add to the spam list. */
1216  if (mutt_replacelist_add(&SpamList, buf->data, templ.data, err) != 0)
1217  {
1218  FREE(&templ.data);
1219  return MUTT_CMD_ERROR;
1220  }
1221  FREE(&templ.data);
1222  }
1223  /* If not, try to remove from the nospam list. */
1224  else
1225  {
1227  }
1228 
1229  return MUTT_CMD_SUCCESS;
1230  }
1231  /* MUTT_NOSPAM is for nospam commands. */
1232  else if (data == MUTT_NOSPAM)
1233  {
1234  /* nospam only ever has one parameter. */
1235 
1236  /* "*" is a special case. */
1237  if (mutt_str_equal(buf->data, "*"))
1238  {
1241  return MUTT_CMD_SUCCESS;
1242  }
1243 
1244  /* If it's on the spam list, just remove it. */
1245  if (mutt_replacelist_remove(&SpamList, buf->data) != 0)
1246  return MUTT_CMD_SUCCESS;
1247 
1248  /* Otherwise, add it to the nospam list. */
1249  if (mutt_regexlist_add(&NoSpamList, buf->data, REG_ICASE, err) != 0)
1250  return MUTT_CMD_ERROR;
1251 
1252  return MUTT_CMD_SUCCESS;
1253  }
1254 
1255  /* This should not happen. */
1256  mutt_buffer_strcpy(err, "This is no good at all.");
1257  return MUTT_CMD_ERROR;
1258 }
1259 
1265 enum CommandResult parse_stailq(struct Buffer *buf, struct Buffer *s,
1266  intptr_t data, struct Buffer *err)
1267 {
1268  do
1269  {
1271  add_to_stailq((struct ListHead *) data, buf->data);
1272  } while (MoreArgs(s));
1273 
1274  return MUTT_CMD_SUCCESS;
1275 }
1276 
1280 enum CommandResult parse_subscribe(struct Buffer *buf, struct Buffer *s,
1281  intptr_t data, struct Buffer *err)
1282 {
1283  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
1284 
1285  do
1286  {
1288 
1289  if (parse_grouplist(&gl, buf, s, err) == -1)
1290  goto bail;
1291 
1294 
1295  if (mutt_regexlist_add(&MailLists, buf->data, REG_ICASE, err) != 0)
1296  goto bail;
1297  if (mutt_regexlist_add(&SubscribedLists, buf->data, REG_ICASE, err) != 0)
1298  goto bail;
1299  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
1300  goto bail;
1301  } while (MoreArgs(s));
1302 
1304  return MUTT_CMD_SUCCESS;
1305 
1306 bail:
1308  return MUTT_CMD_ERROR;
1309 }
1310 
1311 #ifdef USE_IMAP
1319 enum CommandResult parse_subscribe_to(struct Buffer *buf, struct Buffer *s,
1320  intptr_t data, struct Buffer *err)
1321 {
1322  if (!buf || !s || !err)
1323  return MUTT_CMD_ERROR;
1324 
1325  mutt_buffer_reset(err);
1326 
1327  if (MoreArgs(s))
1328  {
1330 
1331  if (MoreArgs(s))
1332  {
1333  mutt_buffer_printf(err, _("%s: too many arguments"), "subscribe-to");
1334  return MUTT_CMD_WARNING;
1335  }
1336 
1337  if (buf->data && (*buf->data != '\0'))
1338  {
1339  /* Expand and subscribe */
1340  if (imap_subscribe(mutt_expand_path(buf->data, buf->dsize), true) == 0)
1341  {
1342  mutt_message(_("Subscribed to %s"), buf->data);
1343  return MUTT_CMD_SUCCESS;
1344  }
1345 
1346  mutt_buffer_printf(err, _("Could not subscribe to %s"), buf->data);
1347  return MUTT_CMD_ERROR;
1348  }
1349 
1350  mutt_debug(LL_DEBUG1, "Corrupted buffer");
1351  return MUTT_CMD_ERROR;
1352  }
1353 
1354  mutt_buffer_addstr(err, _("No folder specified"));
1355  return MUTT_CMD_WARNING;
1356 }
1357 #endif
1358 
1366 enum CommandResult parse_tag_formats(struct Buffer *buf, struct Buffer *s,
1367  intptr_t data, struct Buffer *err)
1368 {
1369  if (!s)
1370  return MUTT_CMD_ERROR;
1371 
1372  struct Buffer *tagbuf = mutt_buffer_pool_get();
1373  struct Buffer *fmtbuf = mutt_buffer_pool_get();
1374 
1375  while (MoreArgs(s))
1376  {
1378  const char *tag = mutt_buffer_string(tagbuf);
1379  if (*tag == '\0')
1380  continue;
1381 
1383  const char *fmt = mutt_buffer_string(fmtbuf);
1384 
1385  /* avoid duplicates */
1386  const char *tmp = mutt_hash_find(TagFormats, fmt);
1387  if (tmp)
1388  {
1389  mutt_warning(_("tag format '%s' already registered as '%s'"), fmt, tmp);
1390  continue;
1391  }
1392 
1394  }
1395 
1396  mutt_buffer_pool_release(&tagbuf);
1397  mutt_buffer_pool_release(&fmtbuf);
1398  return MUTT_CMD_SUCCESS;
1399 }
1400 
1408 enum CommandResult parse_tag_transforms(struct Buffer *buf, struct Buffer *s,
1409  intptr_t data, struct Buffer *err)
1410 {
1411  if (!s)
1412  return MUTT_CMD_ERROR;
1413 
1414  struct Buffer *tagbuf = mutt_buffer_pool_get();
1415  struct Buffer *trnbuf = mutt_buffer_pool_get();
1416 
1417  while (MoreArgs(s))
1418  {
1420  const char *tag = mutt_buffer_string(tagbuf);
1421  if (*tag == '\0')
1422  continue;
1423 
1425  const char *trn = mutt_buffer_string(trnbuf);
1426 
1427  /* avoid duplicates */
1428  const char *tmp = mutt_hash_find(TagTransforms, tag);
1429  if (tmp)
1430  {
1431  mutt_warning(_("tag transform '%s' already registered as '%s'"), tag, tmp);
1432  continue;
1433  }
1434 
1436  }
1437 
1438  mutt_buffer_pool_release(&tagbuf);
1439  mutt_buffer_pool_release(&trnbuf);
1440  return MUTT_CMD_SUCCESS;
1441 }
1442 
1446 enum CommandResult parse_unignore(struct Buffer *buf, struct Buffer *s,
1447  intptr_t data, struct Buffer *err)
1448 {
1449  do
1450  {
1452 
1453  /* don't add "*" to the unignore list */
1454  if (strcmp(buf->data, "*") != 0)
1455  add_to_stailq(&UnIgnore, buf->data);
1456 
1457  remove_from_stailq(&Ignore, buf->data);
1458  } while (MoreArgs(s));
1459 
1460  return MUTT_CMD_SUCCESS;
1461 }
1462 
1466 enum CommandResult parse_unlists(struct Buffer *buf, struct Buffer *s,
1467  intptr_t data, struct Buffer *err)
1468 {
1470  do
1471  {
1475 
1476  if (!mutt_str_equal(buf->data, "*") &&
1477  (mutt_regexlist_add(&UnMailLists, buf->data, REG_ICASE, err) != 0))
1478  {
1479  return MUTT_CMD_ERROR;
1480  }
1481  } while (MoreArgs(s));
1482 
1483  return MUTT_CMD_SUCCESS;
1484 }
1485 
1490 static void do_unmailboxes(struct Mailbox *m)
1491 {
1492 #ifdef USE_INOTIFY
1494 #endif
1495  m->visible = false;
1496  m->gen = -1;
1497  if (m->opened)
1498  {
1499  struct EventMailbox ev_m = { NULL };
1500  mutt_debug(LL_NOTIFY, "NT_MAILBOX_CHANGE: NULL\n");
1502  }
1503  else
1504  {
1506  mailbox_free(&m);
1507  }
1508 }
1509 
1513 static void do_unmailboxes_star(void)
1514 {
1515  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
1517  struct MailboxNode *np = NULL;
1518  struct MailboxNode *nptmp = NULL;
1519  STAILQ_FOREACH_SAFE(np, &ml, entries, nptmp)
1520  {
1521  do_unmailboxes(np->mailbox);
1522  }
1524 }
1525 
1531 enum CommandResult parse_unmailboxes(struct Buffer *buf, struct Buffer *s,
1532  intptr_t data, struct Buffer *err)
1533 {
1534  while (MoreArgs(s))
1535  {
1537 
1538  if (mutt_str_equal(buf->data, "*"))
1539  {
1541  return MUTT_CMD_SUCCESS;
1542  }
1543 
1545 
1546  struct Account *a = NULL;
1547  TAILQ_FOREACH(a, &NeoMutt->accounts, entries)
1548  {
1549  struct Mailbox *m = mx_mbox_find(a, mutt_buffer_string(buf));
1550  if (m)
1551  {
1552  do_unmailboxes(m);
1553  break;
1554  }
1555  }
1556  }
1557  return MUTT_CMD_SUCCESS;
1558 }
1559 
1563 enum CommandResult parse_unmy_hdr(struct Buffer *buf, struct Buffer *s,
1564  intptr_t data, struct Buffer *err)
1565 {
1566  struct ListNode *np = NULL, *tmp = NULL;
1567  size_t l;
1568 
1569  do
1570  {
1572  if (mutt_str_equal("*", buf->data))
1573  {
1574  /* Clear all headers, send a notification for each header */
1575  STAILQ_FOREACH(np, &UserHeader, entries)
1576  {
1577  mutt_debug(LL_NOTIFY, "NT_HEADER_DELETE: %s\n", np->data);
1578  struct EventHeader ev_h = { np->data };
1580  }
1582  continue;
1583  }
1584 
1585  l = mutt_str_len(buf->data);
1586  if (buf->data[l - 1] == ':')
1587  l--;
1588 
1589  STAILQ_FOREACH_SAFE(np, &UserHeader, entries, tmp)
1590  {
1591  if (mutt_istrn_equal(buf->data, np->data, l) && (np->data[l] == ':'))
1592  {
1593  mutt_debug(LL_NOTIFY, "NT_HEADER_DELETE: %s\n", np->data);
1594  struct EventHeader ev_h = { np->data };
1596 
1597  header_free(&UserHeader, np);
1598  }
1599  }
1600  } while (MoreArgs(s));
1601  return MUTT_CMD_SUCCESS;
1602 }
1603 
1609 enum CommandResult parse_unstailq(struct Buffer *buf, struct Buffer *s,
1610  intptr_t data, struct Buffer *err)
1611 {
1612  do
1613  {
1615  /* Check for deletion of entire list */
1616  if (mutt_str_equal(buf->data, "*"))
1617  {
1618  mutt_list_free((struct ListHead *) data);
1619  break;
1620  }
1621  remove_from_stailq((struct ListHead *) data, buf->data);
1622  } while (MoreArgs(s));
1623 
1624  return MUTT_CMD_SUCCESS;
1625 }
1626 
1630 enum CommandResult parse_unsubscribe(struct Buffer *buf, struct Buffer *s,
1631  intptr_t data, struct Buffer *err)
1632 {
1634  do
1635  {
1638 
1639  if (!mutt_str_equal(buf->data, "*") &&
1640  (mutt_regexlist_add(&UnSubscribedLists, buf->data, REG_ICASE, err) != 0))
1641  {
1642  return MUTT_CMD_ERROR;
1643  }
1644  } while (MoreArgs(s));
1645 
1646  return MUTT_CMD_SUCCESS;
1647 }
1648 
1649 #ifdef USE_IMAP
1657 enum CommandResult parse_unsubscribe_from(struct Buffer *buf, struct Buffer *s,
1658  intptr_t data, struct Buffer *err)
1659 {
1660  if (!buf || !s || !err)
1661  return MUTT_CMD_ERROR;
1662 
1663  if (MoreArgs(s))
1664  {
1666 
1667  if (MoreArgs(s))
1668  {
1669  mutt_buffer_printf(err, _("%s: too many arguments"), "unsubscribe-from");
1670  return MUTT_CMD_WARNING;
1671  }
1672 
1673  if (buf->data && (*buf->data != '\0'))
1674  {
1675  /* Expand and subscribe */
1676  if (imap_subscribe(mutt_expand_path(buf->data, buf->dsize), false) == 0)
1677  {
1678  mutt_message(_("Unsubscribed from %s"), buf->data);
1679  return MUTT_CMD_SUCCESS;
1680  }
1681 
1682  mutt_buffer_printf(err, _("Could not unsubscribe from %s"), buf->data);
1683  return MUTT_CMD_ERROR;
1684  }
1685 
1686  mutt_debug(LL_DEBUG1, "Corrupted buffer");
1687  return MUTT_CMD_ERROR;
1688  }
1689 
1690  mutt_buffer_addstr(err, _("No folder specified"));
1691  return MUTT_CMD_WARNING;
1692 }
1693 #endif
1694 
1699 {
1701 }
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:63
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:250
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:292
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:354
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:238
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:223
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:430
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:48
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:158
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:445
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:81
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:75
@ GS_RX
Entry is a regular expression.
Definition: command_parse.c:77
@ GS_NONE
Group is missing an argument.
Definition: command_parse.c:76
@ GS_ADDR
Entry is an address.
Definition: command_parse.c:78
#define MAX_ERRS
Definition: command_parse.c:69
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:67
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:87
Functions to parse commands in a config file.
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
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:388
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:355
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:522
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:174
@ NT_HEADER_ADD
Header has been added.
Definition: email.h:172
@ NT_HEADER_DELETE
Header has been removed.
Definition: email.h:173
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:152
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:720
#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
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:273
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:894
enum CommandResult mutt_parse_rc_buffer(struct Buffer *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:836
Config/command parsing.
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition: keymap.c:1228
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_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_CHANGE
Mailbox has been changed.
Definition: mailbox.h:173
@ MUTT_MAILBOX_ANY
Match any Mailbox type.
Definition: mailbox.h:42
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
#define FREE(x)
Definition: memory.h:43
GUI present the user with a selectable list.
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:481
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:526
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:752
#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:583
void mutt_regexlist_free(struct RegexList *rl)
Free a RegexList object.
Definition: regex.c:174
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:135
void mutt_replacelist_free(struct ReplaceList *rl)
Free a ReplaceList object.
Definition: regex.c:467
int mutt_regexlist_remove(struct RegexList *rl, const char *str)
Remove a Regex from a list.
Definition: regex.c:230
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:266
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:904
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:629
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
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:501
Many unsorted constants and some structs.
#define MUTT_TOKEN_BACKTICK_VARS
Expand variables within backticks.
Definition: mutt.h:75
#define MUTT_TOKEN_MINUS
Treat '-' as a special.
Definition: mutt.h:79
#define MUTT_TOKEN_PLUS
Treat '+' as a special.
Definition: mutt.h:78
#define MUTT_TOKEN_QUOTE
Don't interpret quotes.
Definition: mutt.h:71
#define MUTT_NOSPAM
Definition: mutt.h:112
#define MUTT_TOKEN_SPACE
Don't treat whitespace as a term.
Definition: mutt.h:70
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:67
#define MUTT_TOKEN_EQUAL
Treat '=' as a special.
Definition: mutt.h:68
#define MUTT_TOKEN_QUESTION
Treat '?' as a special.
Definition: mutt.h:77
#define MUTT_SPAM
Definition: mutt.h:111
#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 ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition: mutt_globals.h:66
void remove_from_stailq(struct ListHead *head, const char *str)
Remove an item, matching a string, from a List.
Definition: muttlib.c:1744
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:1719
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:123
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1455
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:1311
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:1764
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:49
@ NT_HEADER
A header has changed, NotifyHeader EventHeader.
Definition: notify_type.h:47
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
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:181
An Event that happened to a Mailbox.
Definition: mailbox.h:187
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:154
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:155
A mailbox.
Definition: mailbox.h:79
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:128
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:131
int opened
Number of times mailbox is opened.
Definition: mailbox.h:129
int gen
Generation number, for sorting.
Definition: mailbox.h:147
const char * name
String value.
Definition: mapping.h:33
Mapping between a function and an operation.
Definition: keymap.h:92
const char * name
Name of the function.
Definition: keymap.h:93
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 * TagFormats
Hash Table of tag-formats (tag -> format string)
Definition: tags.c:39
struct HashTable * TagTransforms
Lookup table of alternative tag names.
Definition: tags.c:38
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:563
Display version and copyright about NeoMutt.