NeoMutt  2020-09-25
Teaching an old dog new tricks
DOXYGEN
command_parse.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <errno.h>
32 #include <limits.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include "mutt/lib.h"
38 #include "address/lib.h"
39 #include "config/lib.h"
40 #include "email/lib.h"
41 #include "core/lib.h"
42 #include "alias/lib.h"
43 #include "gui/lib.h"
44 #include "mutt.h"
45 #include "command_parse.h"
46 #include "imap/lib.h"
47 #include "context.h"
48 #include "init.h"
49 #include "keymap.h"
50 #include "monitor.h"
51 #include "mutt_commands.h"
52 #include "mutt_globals.h"
53 #include "mutt_logging.h"
54 #include "mutt_menu.h"
55 #include "mutt_parse.h"
56 #include "muttlib.h"
57 #include "mx.h"
58 #include "myvar.h"
59 #include "options.h"
60 #include "version.h"
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 */
68 
69 #define MAX_ERRS 128
70 
75 {
79 };
80 
84 static enum CommandResult parse_unreplace_list(struct Buffer *buf, struct Buffer *s,
85  struct ReplaceList *list, struct Buffer *err)
86 {
87  /* First token is a regex. */
88  if (!MoreArgs(s))
89  {
90  mutt_buffer_printf(err, _("%s: too few arguments"), "unsubjectrx");
91  return MUTT_CMD_WARNING;
92  }
93 
95 
96  /* "*" is a special case. */
97  if (mutt_str_equal(buf->data, "*"))
98  {
100  return MUTT_CMD_SUCCESS;
101  }
102 
103  mutt_replacelist_remove(list, buf->data);
104  return MUTT_CMD_SUCCESS;
105 }
106 
110 static void attachments_clean(void)
111 {
112  if (!Context || !Context->mailbox)
113  return;
114 
115  struct Mailbox *m = Context->mailbox;
116  for (int i = 0; i < m->msg_count; i++)
117  {
118  struct Email *e = m->emails[i];
119  if (!e)
120  break;
121  e->attach_valid = false;
122  }
123 }
124 
133 static enum CommandResult parse_unattach_list(struct Buffer *buf, struct Buffer *s,
134  struct ListHead *head, struct Buffer *err)
135 {
136  struct AttachMatch *a = NULL;
137  char *tmp = NULL;
138  char *minor = NULL;
139 
140  do
141  {
143  FREE(&tmp);
144 
145  if (mutt_istr_equal(buf->data, "any"))
146  tmp = mutt_str_dup("*/.*");
147  else if (mutt_istr_equal(buf->data, "none"))
148  tmp = mutt_str_dup("cheap_hack/this_should_never_match");
149  else
150  tmp = mutt_str_dup(buf->data);
151 
152  minor = strchr(tmp, '/');
153  if (minor)
154  {
155  *minor = '\0';
156  minor++;
157  }
158  else
159  {
160  minor = "unknown";
161  }
162  const enum ContentType major = mutt_check_mime_type(tmp);
163 
164  struct ListNode *np = NULL, *tmp2 = NULL;
165  STAILQ_FOREACH_SAFE(np, head, entries, tmp2)
166  {
167  a = (struct AttachMatch *) np->data;
168  mutt_debug(LL_DEBUG3, "check %s/%s [%d] : %s/%s [%d]\n", a->major,
169  a->minor, a->major_int, tmp, minor, major);
170  if ((a->major_int == major) && mutt_istr_equal(minor, a->minor))
171  {
172  mutt_debug(LL_DEBUG3, "removed %s/%s [%d]\n", a->major, a->minor, a->major_int);
173  regfree(&a->minor_regex);
174  FREE(&a->major);
175  STAILQ_REMOVE(head, np, ListNode, entries);
176  FREE(&np->data);
177  FREE(&np);
178  }
179  }
180 
181  } while (MoreArgs(s));
182 
183  FREE(&tmp);
185  return MUTT_CMD_SUCCESS;
186 }
187 
191 static void clear_subject_mods(void)
192 {
193  if (!Context || !Context->mailbox)
194  return;
195 
196  struct Mailbox *m = Context->mailbox;
197  for (int i = 0; i < m->msg_count; i++)
198  {
199  struct Email *e = m->emails[i];
200  if (!e || !e->env)
201  continue;
202  FREE(&e->env->disp_subj);
203  }
204 }
205 
209 static enum CommandResult parse_replace_list(struct Buffer *buf, struct Buffer *s,
210  struct ReplaceList *list, struct Buffer *err)
211 {
212  struct Buffer templ = mutt_buffer_make(0);
213 
214  /* First token is a regex. */
215  if (!MoreArgs(s))
216  {
217  mutt_buffer_printf(err, _("%s: too few arguments"), "subjectrx");
218  return MUTT_CMD_WARNING;
219  }
221 
222  /* Second token is a replacement template */
223  if (!MoreArgs(s))
224  {
225  mutt_buffer_printf(err, _("%s: too few arguments"), "subjectrx");
226  return MUTT_CMD_WARNING;
227  }
229 
230  if (mutt_replacelist_add(list, buf->data, templ.data, err) != 0)
231  {
232  FREE(&templ.data);
233  return MUTT_CMD_ERROR;
234  }
235  FREE(&templ.data);
236 
237  return MUTT_CMD_SUCCESS;
238 }
239 
246 static bool is_function(const char *name)
247 {
248  for (enum MenuType i = 0; i < MENU_MAX; i++)
249  {
250  const struct Binding *b = km_get_table(Menus[i].value);
251  if (!b)
252  continue;
253 
254  for (int j = 0; b[j].name; j++)
255  if (mutt_str_equal(name, b[j].name))
256  return true;
257  }
258  return false;
259 }
260 
265 static struct AttachMatch *mutt_attachmatch_new(void)
266 {
267  return mutt_mem_calloc(1, sizeof(struct AttachMatch));
268 }
269 
278 static enum CommandResult parse_attach_list(struct Buffer *buf, struct Buffer *s,
279  struct ListHead *head, struct Buffer *err)
280 {
281  struct AttachMatch *a = NULL;
282  char *p = NULL;
283  char *tmpminor = NULL;
284  size_t len;
285  int ret;
286 
287  do
288  {
290 
291  if (!buf->data || (*buf->data == '\0'))
292  continue;
293 
294  a = mutt_attachmatch_new();
295 
296  /* some cheap hacks that I expect to remove */
297  if (mutt_istr_equal(buf->data, "any"))
298  a->major = mutt_str_dup("*/.*");
299  else if (mutt_istr_equal(buf->data, "none"))
300  a->major = mutt_str_dup("cheap_hack/this_should_never_match");
301  else
302  a->major = mutt_str_dup(buf->data);
303 
304  p = strchr(a->major, '/');
305  if (p)
306  {
307  *p = '\0';
308  p++;
309  a->minor = p;
310  }
311  else
312  {
313  a->minor = "unknown";
314  }
315 
316  len = strlen(a->minor);
317  tmpminor = mutt_mem_malloc(len + 3);
318  strcpy(&tmpminor[1], a->minor);
319  tmpminor[0] = '^';
320  tmpminor[len + 1] = '$';
321  tmpminor[len + 2] = '\0';
322 
324  ret = REG_COMP(&a->minor_regex, tmpminor, REG_ICASE);
325 
326  FREE(&tmpminor);
327 
328  if (ret != 0)
329  {
330  regerror(ret, &a->minor_regex, err->data, err->dsize);
331  FREE(&a->major);
332  FREE(&a);
333  return MUTT_CMD_ERROR;
334  }
335 
336  mutt_debug(LL_DEBUG3, "added %s/%s [%d]\n", a->major, a->minor, a->major_int);
337 
338  mutt_list_insert_tail(head, (char *) a);
339  } while (MoreArgs(s));
340 
342  return MUTT_CMD_SUCCESS;
343 }
344 
352 static int print_attach_list(struct ListHead *h, const char op, const char *name)
353 {
354  struct ListNode *np = NULL;
355  STAILQ_FOREACH(np, h, entries)
356  {
357  printf("attachments %c%s %s/%s\n", op, name,
358  ((struct AttachMatch *) np->data)->major,
359  ((struct AttachMatch *) np->data)->minor);
360  }
361 
362  return 0;
363 }
364 
368 static void alternates_clean(void)
369 {
370  if (!Context || !Context->mailbox)
371  return;
372 
373  struct Mailbox *m = Context->mailbox;
374  for (int i = 0; i < m->msg_count; i++)
375  {
376  struct Email *e = m->emails[i];
377  if (!e)
378  break;
379  e->recip_valid = false;
380  }
381 }
382 
392 int parse_grouplist(struct GroupList *gl, struct Buffer *buf, struct Buffer *s,
393  struct Buffer *err)
394 {
395  while (mutt_istr_equal(buf->data, "-group"))
396  {
397  if (!MoreArgs(s))
398  {
399  mutt_buffer_strcpy(err, _("-group: no group name"));
400  return -1;
401  }
402 
404 
406 
407  if (!MoreArgs(s))
408  {
409  mutt_buffer_strcpy(err, _("out of arguments"));
410  return -1;
411  }
412 
414  }
415 
416  return 0;
417 }
418 
425 int source_rc(const char *rcfile_path, struct Buffer *err)
426 {
427  int lineno = 0, rc = 0, warnings = 0;
428  enum CommandResult line_rc;
429  struct Buffer *token = NULL, *linebuf = NULL;
430  char *line = NULL;
431  char *currentline = NULL;
432  char rcfile[PATH_MAX];
433  size_t linelen = 0;
434  pid_t pid;
435 
436  mutt_str_copy(rcfile, rcfile_path, sizeof(rcfile));
437 
438  size_t rcfilelen = mutt_str_len(rcfile);
439  if (rcfilelen == 0)
440  return -1;
441 
442  bool ispipe = rcfile[rcfilelen - 1] == '|';
443 
444  if (!ispipe)
445  {
446  struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
447  if (!mutt_path_to_absolute(rcfile, np ? NONULL(np->data) : ""))
448  {
449  mutt_error(_("Error: Can't build path of '%s'"), rcfile_path);
450  return -1;
451  }
452 
453  STAILQ_FOREACH(np, &MuttrcStack, entries)
454  {
455  if (mutt_str_equal(np->data, rcfile))
456  {
457  break;
458  }
459  }
460  if (np)
461  {
462  mutt_error(_("Error: Cyclic sourcing of configuration file '%s'"), rcfile);
463  return -1;
464  }
465 
467  }
468 
469  mutt_debug(LL_DEBUG2, "Reading configuration file '%s'\n", rcfile);
470 
471  FILE *fp = mutt_open_read(rcfile, &pid);
472  if (!fp)
473  {
474  mutt_buffer_printf(err, "%s: %s", rcfile, strerror(errno));
475  return -1;
476  }
477 
478  token = mutt_buffer_pool_get();
479  linebuf = mutt_buffer_pool_get();
480 
481  while ((line = mutt_file_read_line(line, &linelen, fp, &lineno, MUTT_CONT)) != NULL)
482  {
483  const bool conv = C_ConfigCharset && C_Charset;
484  if (conv)
485  {
486  currentline = mutt_str_dup(line);
487  if (!currentline)
488  continue;
489  mutt_ch_convert_string(&currentline, C_ConfigCharset, C_Charset, 0);
490  }
491  else
492  currentline = line;
493 
494  mutt_buffer_strcpy(linebuf, currentline);
495 
496  mutt_buffer_reset(err);
497  line_rc = mutt_parse_rc_buffer(linebuf, token, err);
498  if (line_rc == MUTT_CMD_ERROR)
499  {
500  mutt_error(_("Error in %s, line %d: %s"), rcfile, lineno, err->data);
501  if (--rc < -MAX_ERRS)
502  {
503  if (conv)
504  FREE(&currentline);
505  break;
506  }
507  }
508  else if (line_rc == MUTT_CMD_WARNING)
509  {
510  /* Warning */
511  mutt_warning(_("Warning in %s, line %d: %s"), rcfile, lineno, err->data);
512  warnings++;
513  }
514  else if (line_rc == MUTT_CMD_FINISH)
515  {
516  break; /* Found "finish" command */
517  }
518  else
519  {
520  if (rc < 0)
521  rc = -1;
522  }
523  if (conv)
524  FREE(&currentline);
525  }
526 
527  FREE(&line);
528  mutt_file_fclose(&fp);
529  if (pid != -1)
530  filter_wait(pid);
531 
532  if (rc)
533  {
534  /* the neomuttrc source keyword */
535  mutt_buffer_reset(err);
536  mutt_buffer_printf(err, (rc >= -MAX_ERRS) ? _("source: errors in %s") : _("source: reading aborted due to too many errors in %s"),
537  rcfile);
538  rc = -1;
539  }
540  else
541  {
542  /* Don't alias errors with warnings */
543  if (warnings > 0)
544  {
545  mutt_buffer_printf(err, ngettext("source: %d warning in %s", "source: %d warnings in %s", warnings),
546  warnings, rcfile);
547  rc = -2;
548  }
549  }
550 
551  if (!ispipe && !STAILQ_EMPTY(&MuttrcStack))
552  {
553  struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
554  STAILQ_REMOVE_HEAD(&MuttrcStack, entries);
555  FREE(&np->data);
556  FREE(&np);
557  }
558 
559  mutt_buffer_pool_release(&token);
560  mutt_buffer_pool_release(&linebuf);
561  return rc;
562 }
563 
567 enum CommandResult parse_alternates(struct Buffer *buf, struct Buffer *s,
568  intptr_t data, struct Buffer *err)
569 {
570  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
571 
573 
574  do
575  {
577 
578  if (parse_grouplist(&gl, buf, s, err) == -1)
579  goto bail;
580 
581  mutt_regexlist_remove(&UnAlternates, buf->data);
582 
583  if (mutt_regexlist_add(&Alternates, buf->data, REG_ICASE, err) != 0)
584  goto bail;
585 
586  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
587  goto bail;
588  } while (MoreArgs(s));
589 
591  return MUTT_CMD_SUCCESS;
592 
593 bail:
595  return MUTT_CMD_ERROR;
596 }
597 
601 enum CommandResult parse_attachments(struct Buffer *buf, struct Buffer *s,
602  intptr_t data, struct Buffer *err)
603 {
604  char op;
605  char *category = NULL;
606  struct ListHead *head = NULL;
607 
609  if (!buf->data || (*buf->data == '\0'))
610  {
611  mutt_buffer_strcpy(err, _("attachments: no disposition"));
612  return MUTT_CMD_WARNING;
613  }
614 
615  category = buf->data;
616  op = *category++;
617 
618  if (op == '?')
619  {
620  mutt_endwin();
621  fflush(stdout);
622  printf("\n%s\n\n", _("Current attachments settings:"));
623  print_attach_list(&AttachAllow, '+', "A");
624  print_attach_list(&AttachExclude, '-', "A");
625  print_attach_list(&InlineAllow, '+', "I");
626  print_attach_list(&InlineExclude, '-', "I");
628  return MUTT_CMD_SUCCESS;
629  }
630 
631  if ((op != '+') && (op != '-'))
632  {
633  op = '+';
634  category--;
635  }
636  if (mutt_istr_startswith("attachment", category))
637  {
638  if (op == '+')
639  head = &AttachAllow;
640  else
641  head = &AttachExclude;
642  }
643  else if (mutt_istr_startswith("inline", category))
644  {
645  if (op == '+')
646  head = &InlineAllow;
647  else
648  head = &InlineExclude;
649  }
650  else
651  {
652  mutt_buffer_strcpy(err, _("attachments: invalid disposition"));
653  return MUTT_CMD_ERROR;
654  }
655 
656  return parse_attach_list(buf, s, head, err);
657 }
658 
662 enum CommandResult parse_cd(struct Buffer *buf, struct Buffer *s, intptr_t data,
663  struct Buffer *err)
664 {
667  if (mutt_buffer_len(buf) == 0)
668  {
669  if (HomeDir)
671  else
672  {
673  mutt_buffer_printf(err, _("%s: too few arguments"), "cd");
674  return MUTT_CMD_ERROR;
675  }
676  }
677 
678  if (chdir(mutt_b2s(buf)) != 0)
679  {
680  mutt_buffer_printf(err, "cd: %s", strerror(errno));
681  return MUTT_CMD_ERROR;
682  }
683 
684  return MUTT_CMD_SUCCESS;
685 }
686 
690 enum CommandResult parse_echo(struct Buffer *buf, struct Buffer *s,
691  intptr_t data, struct Buffer *err)
692 {
693  if (!MoreArgs(s))
694  {
695  mutt_buffer_printf(err, _("%s: too few arguments"), "echo");
696  return MUTT_CMD_WARNING;
697  }
699  OptForceRefresh = true;
700  mutt_message("%s", buf->data);
701  OptForceRefresh = false;
702  mutt_sleep(0);
703 
704  return MUTT_CMD_SUCCESS;
705 }
706 
714 enum CommandResult parse_finish(struct Buffer *buf, struct Buffer *s,
715  intptr_t data, struct Buffer *err)
716 {
717  if (MoreArgs(s))
718  {
719  mutt_buffer_printf(err, _("%s: too many arguments"), "finish");
720  return MUTT_CMD_WARNING;
721  }
722 
723  return MUTT_CMD_FINISH;
724 }
725 
729 enum CommandResult parse_group(struct Buffer *buf, struct Buffer *s,
730  intptr_t data, struct Buffer *err)
731 {
732  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
733  enum GroupState state = GS_NONE;
734 
735  do
736  {
738  if (parse_grouplist(&gl, buf, s, err) == -1)
739  goto bail;
740 
741  if ((data == MUTT_UNGROUP) && mutt_istr_equal(buf->data, "*"))
742  {
744  goto out;
745  }
746 
747  if (mutt_istr_equal(buf->data, "-rx"))
748  state = GS_RX;
749  else if (mutt_istr_equal(buf->data, "-addr"))
750  state = GS_ADDR;
751  else
752  {
753  switch (state)
754  {
755  case GS_NONE:
756  mutt_buffer_printf(err, _("%sgroup: missing -rx or -addr"),
757  (data == MUTT_UNGROUP) ? "un" : "");
758  goto warn;
759 
760  case GS_RX:
761  if ((data == MUTT_GROUP) &&
762  (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0))
763  {
764  goto bail;
765  }
766  else if ((data == MUTT_UNGROUP) &&
767  (mutt_grouplist_remove_regex(&gl, buf->data) < 0))
768  {
769  goto bail;
770  }
771  break;
772 
773  case GS_ADDR:
774  {
775  char *estr = NULL;
776  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
777  mutt_addrlist_parse2(&al, buf->data);
778  if (TAILQ_EMPTY(&al))
779  goto bail;
780  if (mutt_addrlist_to_intl(&al, &estr))
781  {
782  mutt_buffer_printf(err, _("%sgroup: warning: bad IDN '%s'"),
783  (data == 1) ? "un" : "", estr);
784  mutt_addrlist_clear(&al);
785  FREE(&estr);
786  goto bail;
787  }
788  if (data == MUTT_GROUP)
789  mutt_grouplist_add_addrlist(&gl, &al);
790  else if (data == MUTT_UNGROUP)
792  mutt_addrlist_clear(&al);
793  break;
794  }
795  }
796  }
797  } while (MoreArgs(s));
798 
799 out:
801  return MUTT_CMD_SUCCESS;
802 
803 bail:
805  return MUTT_CMD_ERROR;
806 
807 warn:
809  return MUTT_CMD_WARNING;
810 }
811 
825 enum CommandResult parse_ifdef(struct Buffer *buf, struct Buffer *s,
826  intptr_t data, struct Buffer *err)
827 {
829 
830  // is the item defined as:
831  bool res = cs_subset_lookup(NeoMutt->sub, buf->data) // a variable?
832  || feature_enabled(buf->data) // a compiled-in feature?
833  || is_function(buf->data) // a function?
834  || mutt_command_get(buf->data) // a command?
835  || myvar_get(buf->data) // a my_ variable?
836  || mutt_str_getenv(buf->data); // an environment variable?
837 
838  if (!MoreArgs(s))
839  {
840  mutt_buffer_printf(err, _("%s: too few arguments"), (data ? "ifndef" : "ifdef"));
841  return MUTT_CMD_WARNING;
842  }
844 
845  /* ifdef KNOWN_SYMBOL or ifndef UNKNOWN_SYMBOL */
846  if ((res && (data == 0)) || (!res && (data == 1)))
847  {
848  enum CommandResult rc = mutt_parse_rc_line(buf->data, err);
849  if (rc == MUTT_CMD_ERROR)
850  {
851  mutt_error(_("Error: %s"), err->data);
852  return MUTT_CMD_ERROR;
853  }
854  return rc;
855  }
856  return MUTT_CMD_SUCCESS;
857 }
858 
862 enum CommandResult parse_ignore(struct Buffer *buf, struct Buffer *s,
863  intptr_t data, struct Buffer *err)
864 {
865  do
866  {
869  add_to_stailq(&Ignore, buf->data);
870  } while (MoreArgs(s));
871 
872  return MUTT_CMD_SUCCESS;
873 }
874 
878 enum CommandResult parse_lists(struct Buffer *buf, struct Buffer *s,
879  intptr_t data, struct Buffer *err)
880 {
881  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
882 
883  do
884  {
886 
887  if (parse_grouplist(&gl, buf, s, err) == -1)
888  goto bail;
889 
891 
892  if (mutt_regexlist_add(&MailLists, buf->data, REG_ICASE, err) != 0)
893  goto bail;
894 
895  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
896  goto bail;
897  } while (MoreArgs(s));
898 
900  return MUTT_CMD_SUCCESS;
901 
902 bail:
904  return MUTT_CMD_ERROR;
905 }
906 
912 enum CommandResult parse_mailboxes(struct Buffer *buf, struct Buffer *s,
913  intptr_t data, struct Buffer *err)
914 {
915  while (MoreArgs(s))
916  {
917  struct Mailbox *m = mailbox_new();
918 
919  if (data & MUTT_NAMED)
920  {
921  // This may be empty, e.g. `named-mailboxes "" +inbox`
923  m->name = mutt_buffer_strdup(buf);
924  }
925 
927  if (mutt_buffer_is_empty(buf))
928  {
929  /* Skip empty tokens. */
930  mailbox_free(&m);
931  continue;
932  }
933 
934  mutt_buffer_strcpy(&m->pathbuf, buf->data);
935  /* int rc = */ mx_path_canon2(m, C_Folder);
936 
937  if (m->type <= MUTT_UNKNOWN)
938  {
939  mutt_error("Unknown Mailbox: %s", m->realpath);
940  mailbox_free(&m);
941  return MUTT_CMD_ERROR;
942  }
943 
944  bool new_account = false;
945  struct Account *a = mx_ac_find(m);
946  if (!a)
947  {
948  a = account_new(NULL, NeoMutt->sub);
949  a->type = m->type;
950  new_account = true;
951  }
952 
953  if (!new_account)
954  {
955  struct Mailbox *m_old = mx_mbox_find(a, m->realpath);
956  if (m_old)
957  {
958  const bool show = (m_old->flags == MB_HIDDEN);
959  if (show)
960  {
961  m_old->flags = MB_NORMAL;
962  }
963 
964  const bool rename = (data & MUTT_NAMED) && !mutt_str_equal(m_old->name, m->name);
965  if (rename)
966  {
967  mutt_str_replace(&m_old->name, m->name);
968  }
969 
970  mailbox_free(&m);
971  continue;
972  }
973  }
974 
975  if (mx_ac_add(a, m) < 0)
976  {
977  //error
978  mailbox_free(&m);
979  if (new_account)
980  {
981  cs_subset_free(&a->sub);
982  FREE(&a->name);
983  notify_free(&a->notify);
984  FREE(&a);
985  }
986  continue;
987  }
988  if (new_account)
989  {
991  }
992 
993 #ifdef USE_INOTIFY
994  mutt_monitor_add(m);
995 #endif
996  }
997  return MUTT_CMD_SUCCESS;
998 }
999 
1003 enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s,
1004  intptr_t data, struct Buffer *err)
1005 {
1006  struct ListNode *n = NULL;
1007  size_t keylen;
1008 
1010  char *p = strpbrk(buf->data, ": \t");
1011  if (!p || (*p != ':'))
1012  {
1013  mutt_buffer_strcpy(err, _("invalid header field"));
1014  return MUTT_CMD_WARNING;
1015  }
1016  keylen = p - buf->data + 1;
1017 
1018  STAILQ_FOREACH(n, &UserHeader, entries)
1019  {
1020  /* see if there is already a field by this name */
1021  if (mutt_istrn_equal(buf->data, n->data, keylen))
1022  {
1023  break;
1024  }
1025  }
1026 
1027  if (!n)
1028  {
1029  /* not found, allocate memory for a new node and add it to the list */
1030  n = mutt_list_insert_tail(&UserHeader, NULL);
1031  }
1032  else
1033  {
1034  /* found, free the existing data */
1035  FREE(&n->data);
1036  }
1037 
1038  n->data = mutt_buffer_strdup(buf);
1039 
1040  return MUTT_CMD_SUCCESS;
1041 }
1042 
1048 enum CommandResult parse_set(struct Buffer *buf, struct Buffer *s,
1049  intptr_t data, struct Buffer *err)
1050 {
1051  /* The order must match `enum MuttSetCommand` */
1052  static const char *set_commands[] = { "set", "toggle", "unset", "reset" };
1053 
1054  int rc = 0;
1055 
1056  while (MoreArgs(s))
1057  {
1058  bool prefix = false;
1059  bool query = false;
1060  bool inv = (data == MUTT_SET_INV);
1061  bool reset = (data == MUTT_SET_RESET);
1062  bool unset = (data == MUTT_SET_UNSET);
1063 
1064  if (*s->dptr == '?')
1065  {
1066  prefix = true;
1067  query = true;
1068  s->dptr++;
1069  }
1070  else if (mutt_str_startswith(s->dptr, "no"))
1071  {
1072  prefix = true;
1073  unset = !unset;
1074  s->dptr += 2;
1075  }
1076  else if (mutt_str_startswith(s->dptr, "inv"))
1077  {
1078  prefix = true;
1079  inv = !inv;
1080  s->dptr += 3;
1081  }
1082  else if (*s->dptr == '&')
1083  {
1084  prefix = true;
1085  reset = true;
1086  s->dptr++;
1087  }
1088 
1089  if (prefix && (data != MUTT_SET_SET))
1090  {
1091  mutt_buffer_printf(err, _("Can't use 'inv', 'no', '&' or '?' with the '%s' command"),
1092  set_commands[data]);
1093  return MUTT_CMD_WARNING;
1094  }
1095 
1096  /* get the variable name */
1098 
1099  bool bq = false;
1100  bool equals = false;
1101  bool increment = false;
1102  bool decrement = false;
1103 
1104  struct HashElem *he = NULL;
1105  bool my = mutt_str_startswith(buf->data, "my_");
1106  if (!my)
1107  {
1108  he = cs_subset_lookup(NeoMutt->sub, buf->data);
1109  if (!he)
1110  {
1111  if (reset && mutt_str_equal(buf->data, "all"))
1112  {
1113  struct HashElem **list = get_elem_list(NeoMutt->sub->cs);
1114  if (!list)
1115  return MUTT_CMD_ERROR;
1116 
1117  for (size_t i = 0; list[i]; i++)
1118  cs_subset_he_reset(NeoMutt->sub, list[i], NULL);
1119 
1120  FREE(&list);
1121  break;
1122  }
1123  else
1124  {
1125  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
1126  return MUTT_CMD_ERROR;
1127  }
1128  }
1129 
1130  bq = ((DTYPE(he->type) == DT_BOOL) || (DTYPE(he->type) == DT_QUAD));
1131  }
1132 
1133  if (*s->dptr == '?')
1134  {
1135  if (prefix)
1136  {
1137  mutt_buffer_printf(err,
1138  _("Can't use a prefix when querying a variable"));
1139  return MUTT_CMD_WARNING;
1140  }
1141 
1142  if (reset || unset || inv)
1143  {
1144  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"),
1145  set_commands[data]);
1146  return MUTT_CMD_WARNING;
1147  }
1148 
1149  query = true;
1150  s->dptr++;
1151  }
1152  else if (*s->dptr == '+' || *s->dptr == '-')
1153  {
1154  if (prefix)
1155  {
1157  err,
1158  _("Can't use prefix when incrementing or decrementing a variable"));
1159  return MUTT_CMD_WARNING;
1160  }
1161 
1162  if (reset || unset || inv)
1163  {
1164  mutt_buffer_printf(err, _("Can't set a variable with the '%s' command"),
1165  set_commands[data]);
1166  return MUTT_CMD_WARNING;
1167  }
1168  if (*s->dptr == '+')
1169  increment = true;
1170  else
1171  decrement = true;
1172 
1173  s->dptr++;
1174  if (*s->dptr == '=')
1175  {
1176  equals = true;
1177  s->dptr++;
1178  }
1179  }
1180  else if (*s->dptr == '=')
1181  {
1182  if (prefix)
1183  {
1184  mutt_buffer_printf(err, _("Can't use prefix when setting a variable"));
1185  return MUTT_CMD_WARNING;
1186  }
1187 
1188  if (reset || unset || inv)
1189  {
1190  mutt_buffer_printf(err, _("Can't set a variable with the '%s' command"),
1191  set_commands[data]);
1192  return MUTT_CMD_WARNING;
1193  }
1194 
1195  equals = true;
1196  s->dptr++;
1197  }
1198 
1199  if (!bq && (inv || (unset && prefix)))
1200  {
1201  if (data == MUTT_SET_SET)
1202  {
1203  mutt_buffer_printf(err, _("Prefixes 'no' and 'inv' may only be used "
1204  "with bool/quad variables"));
1205  }
1206  else
1207  {
1208  mutt_buffer_printf(err, _("Command '%s' can only be used with bool/quad variables"),
1209  set_commands[data]);
1210  }
1211  return MUTT_CMD_WARNING;
1212  }
1213 
1214  if (reset)
1215  {
1216  // mutt_buffer_printf(err, "ACT24 reset variable %s", buf->data);
1217  if (he)
1218  {
1219  rc = cs_subset_he_reset(NeoMutt->sub, he, err);
1220  if (CSR_RESULT(rc) != CSR_SUCCESS)
1221  return MUTT_CMD_ERROR;
1222  }
1223  else
1224  {
1225  myvar_del(buf->data);
1226  }
1227  continue;
1228  }
1229 
1230  if ((data == MUTT_SET_SET) && !inv && !unset)
1231  {
1232  if (query)
1233  {
1234  // mutt_buffer_printf(err, "ACT08 query variable %s", buf->data);
1235  if (he)
1236  {
1237  mutt_buffer_addstr(err, buf->data);
1238  mutt_buffer_addch(err, '=');
1239  mutt_buffer_reset(buf);
1240  rc = cs_subset_he_string_get(NeoMutt->sub, he, buf);
1241  if (CSR_RESULT(rc) != CSR_SUCCESS)
1242  {
1243  mutt_buffer_addstr(err, buf->data);
1244  return MUTT_CMD_ERROR;
1245  }
1246  if (DTYPE(he->type) == DT_PATH)
1247  mutt_pretty_mailbox(buf->data, buf->dsize);
1248  pretty_var(buf->data, err);
1249  }
1250  else
1251  {
1252  const char *val = myvar_get(buf->data);
1253  if (val)
1254  {
1255  mutt_buffer_addstr(err, buf->data);
1256  mutt_buffer_addch(err, '=');
1257  pretty_var(val, err);
1258  }
1259  else
1260  {
1261  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
1262  return MUTT_CMD_ERROR;
1263  }
1264  }
1265  break;
1266  }
1267  else if (equals)
1268  {
1269  // mutt_buffer_printf(err, "ACT11 set variable %s to ", buf->data);
1270  const char *name = NULL;
1271  if (my)
1272  {
1273  name = mutt_str_dup(buf->data);
1274  }
1276  if (my)
1277  {
1278  myvar_set(name, buf->data);
1279  FREE(&name);
1280  }
1281  else
1282  {
1283  if (DTYPE(he->type) == DT_PATH)
1284  {
1285  if (he->type & (DT_PATH_DIR | DT_PATH_FILE))
1287  else
1288  mutt_path_tilde(buf->data, buf->dsize, HomeDir);
1289  }
1290  else if (IS_MAILBOX(he))
1291  {
1293  }
1294  else if (IS_COMMAND(he))
1295  {
1296  struct Buffer scratch = mutt_buffer_make(1024);
1297  mutt_buffer_copy(&scratch, buf);
1298 
1299  if (!mutt_str_equal(buf->data, "builtin"))
1300  {
1301  mutt_buffer_expand_path(&scratch);
1302  }
1303  mutt_buffer_reset(buf);
1304  mutt_buffer_addstr(buf, mutt_b2s(&scratch));
1305  mutt_buffer_dealloc(&scratch);
1306  }
1307  if (increment)
1308  {
1309  rc = cs_subset_he_string_plus_equals(NeoMutt->sub, he, buf->data, err);
1310  }
1311  else if (decrement)
1312  {
1313  rc = cs_subset_he_string_minus_equals(NeoMutt->sub, he, buf->data, err);
1314  }
1315  else
1316  {
1317  rc = cs_subset_he_string_set(NeoMutt->sub, he, buf->data, err);
1318  }
1319  if (CSR_RESULT(rc) != CSR_SUCCESS)
1320  return MUTT_CMD_ERROR;
1321  }
1322  continue;
1323  }
1324  else
1325  {
1326  if (bq)
1327  {
1328  // mutt_buffer_printf(err, "ACT23 set variable %s to 'yes'", buf->data);
1329  rc = cs_subset_he_native_set(NeoMutt->sub, he, true, err);
1330  if (CSR_RESULT(rc) != CSR_SUCCESS)
1331  return MUTT_CMD_ERROR;
1332  continue;
1333  }
1334  else
1335  {
1336  // mutt_buffer_printf(err, "ACT10 query variable %s", buf->data);
1337  if (he)
1338  {
1339  mutt_buffer_addstr(err, buf->data);
1340  mutt_buffer_addch(err, '=');
1341  mutt_buffer_reset(buf);
1342  rc = cs_subset_he_string_get(NeoMutt->sub, he, buf);
1343  if (CSR_RESULT(rc) != CSR_SUCCESS)
1344  {
1345  mutt_buffer_addstr(err, buf->data);
1346  return MUTT_CMD_ERROR;
1347  }
1348  if (DTYPE(he->type) == DT_PATH)
1349  mutt_pretty_mailbox(buf->data, buf->dsize);
1350  pretty_var(buf->data, err);
1351  }
1352  else
1353  {
1354  const char *val = myvar_get(buf->data);
1355  if (val)
1356  {
1357  mutt_buffer_addstr(err, buf->data);
1358  mutt_buffer_addch(err, '=');
1359  pretty_var(val, err);
1360  }
1361  else
1362  {
1363  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
1364  return MUTT_CMD_ERROR;
1365  }
1366  }
1367  break;
1368  }
1369  }
1370  }
1371 
1372  if (my)
1373  {
1374  myvar_del(buf->data);
1375  }
1376  else if (bq)
1377  {
1378  if (inv)
1379  {
1380  // mutt_buffer_printf(err, "ACT25 TOGGLE bool/quad variable %s", buf->data);
1381  if (DTYPE(he->type) == DT_BOOL)
1382  bool_he_toggle(NeoMutt->sub, he, err);
1383  else
1384  quad_he_toggle(NeoMutt->sub, he, err);
1385  }
1386  else
1387  {
1388  // mutt_buffer_printf(err, "ACT26 UNSET bool/quad variable %s", buf->data);
1389  rc = cs_subset_he_native_set(NeoMutt->sub, he, false, err);
1390  if (CSR_RESULT(rc) != CSR_SUCCESS)
1391  return MUTT_CMD_ERROR;
1392  }
1393  continue;
1394  }
1395  else
1396  {
1397  rc = cs_subset_he_string_set(NeoMutt->sub, he, NULL, err);
1398  if (CSR_RESULT(rc) != CSR_SUCCESS)
1399  return MUTT_CMD_ERROR;
1400  }
1401  }
1402 
1403  return MUTT_CMD_SUCCESS;
1404 }
1405 
1409 enum CommandResult parse_setenv(struct Buffer *buf, struct Buffer *s,
1410  intptr_t data, struct Buffer *err)
1411 {
1412  char **envp = mutt_envlist_getlist();
1413 
1414  bool query = false;
1415  bool prefix = false;
1416  bool unset = (data == MUTT_SET_UNSET);
1417 
1418  if (!MoreArgs(s))
1419  {
1420  mutt_buffer_printf(err, _("%s: too few arguments"), "setenv");
1421  return MUTT_CMD_WARNING;
1422  }
1423 
1424  if (*s->dptr == '?')
1425  {
1426  query = true;
1427  prefix = true;
1428 
1429  if (unset)
1430  {
1431  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"), "unsetenv");
1432  return MUTT_CMD_WARNING;
1433  }
1434 
1435  s->dptr++;
1436  }
1437 
1438  /* get variable name */
1440 
1441  if (*s->dptr == '?')
1442  {
1443  if (unset)
1444  {
1445  mutt_buffer_printf(err, _("Can't query a variable with the '%s' command"), "unsetenv");
1446  return MUTT_CMD_WARNING;
1447  }
1448 
1449  if (prefix)
1450  {
1451  mutt_buffer_printf(err, _("Can't use a prefix when querying a variable"));
1452  return MUTT_CMD_WARNING;
1453  }
1454 
1455  query = true;
1456  s->dptr++;
1457  }
1458 
1459  if (query)
1460  {
1461  bool found = false;
1462  while (envp && *envp)
1463  {
1464  /* This will display all matches for "^QUERY" */
1465  if (mutt_str_startswith(*envp, buf->data))
1466  {
1467  if (!found)
1468  {
1469  mutt_endwin();
1470  found = true;
1471  }
1472  puts(*envp);
1473  }
1474  envp++;
1475  }
1476 
1477  if (found)
1478  {
1480  return MUTT_CMD_SUCCESS;
1481  }
1482 
1483  mutt_buffer_printf(err, _("%s is unset"), buf->data);
1484  return MUTT_CMD_WARNING;
1485  }
1486 
1487  if (unset)
1488  {
1489  if (mutt_envlist_unset(buf->data))
1490  return MUTT_CMD_SUCCESS;
1491  return MUTT_CMD_ERROR;
1492  }
1493 
1494  /* set variable */
1495 
1496  if (*s->dptr == '=')
1497  {
1498  s->dptr++;
1499  SKIPWS(s->dptr);
1500  }
1501 
1502  if (!MoreArgs(s))
1503  {
1504  mutt_buffer_printf(err, _("%s: too few arguments"), "setenv");
1505  return MUTT_CMD_WARNING;
1506  }
1507 
1508  char *name = mutt_str_dup(buf->data);
1510  mutt_envlist_set(name, buf->data, true);
1511  FREE(&name);
1512 
1513  return MUTT_CMD_SUCCESS;
1514 }
1515 
1519 enum CommandResult parse_source(struct Buffer *buf, struct Buffer *s,
1520  intptr_t data, struct Buffer *err)
1521 {
1522  char path[PATH_MAX];
1523 
1524  do
1525  {
1526  if (mutt_extract_token(buf, s, MUTT_TOKEN_NO_FLAGS) != 0)
1527  {
1528  mutt_buffer_printf(err, _("source: error at %s"), s->dptr);
1529  return MUTT_CMD_ERROR;
1530  }
1531  mutt_str_copy(path, buf->data, sizeof(path));
1532  mutt_expand_path(path, sizeof(path));
1533 
1534  if (source_rc(path, err) < 0)
1535  {
1536  mutt_buffer_printf(err, _("source: file %s could not be sourced"), path);
1537  return MUTT_CMD_ERROR;
1538  }
1539 
1540  } while (MoreArgs(s));
1541 
1542  return MUTT_CMD_SUCCESS;
1543 }
1544 
1548 enum CommandResult parse_spam_list(struct Buffer *buf, struct Buffer *s,
1549  intptr_t data, struct Buffer *err)
1550 {
1551  struct Buffer templ;
1552 
1553  mutt_buffer_init(&templ);
1554 
1555  /* Insist on at least one parameter */
1556  if (!MoreArgs(s))
1557  {
1558  if (data == MUTT_SPAM)
1559  mutt_buffer_strcpy(err, _("spam: no matching pattern"));
1560  else
1561  mutt_buffer_strcpy(err, _("nospam: no matching pattern"));
1562  return MUTT_CMD_ERROR;
1563  }
1564 
1565  /* Extract the first token, a regex */
1567 
1568  /* data should be either MUTT_SPAM or MUTT_NOSPAM. MUTT_SPAM is for spam commands. */
1569  if (data == MUTT_SPAM)
1570  {
1571  /* If there's a second parameter, it's a template for the spam tag. */
1572  if (MoreArgs(s))
1573  {
1575 
1576  /* Add to the spam list. */
1577  if (mutt_replacelist_add(&SpamList, buf->data, templ.data, err) != 0)
1578  {
1579  FREE(&templ.data);
1580  return MUTT_CMD_ERROR;
1581  }
1582  FREE(&templ.data);
1583  }
1584  /* If not, try to remove from the nospam list. */
1585  else
1586  {
1588  }
1589 
1590  return MUTT_CMD_SUCCESS;
1591  }
1592  /* MUTT_NOSPAM is for nospam commands. */
1593  else if (data == MUTT_NOSPAM)
1594  {
1595  /* nospam only ever has one parameter. */
1596 
1597  /* "*" is a special case. */
1598  if (mutt_str_equal(buf->data, "*"))
1599  {
1602  return MUTT_CMD_SUCCESS;
1603  }
1604 
1605  /* If it's on the spam list, just remove it. */
1606  if (mutt_replacelist_remove(&SpamList, buf->data) != 0)
1607  return MUTT_CMD_SUCCESS;
1608 
1609  /* Otherwise, add it to the nospam list. */
1610  if (mutt_regexlist_add(&NoSpamList, buf->data, REG_ICASE, err) != 0)
1611  return MUTT_CMD_ERROR;
1612 
1613  return MUTT_CMD_SUCCESS;
1614  }
1615 
1616  /* This should not happen. */
1617  mutt_buffer_strcpy(err, "This is no good at all.");
1618  return MUTT_CMD_ERROR;
1619 }
1620 
1626 enum CommandResult parse_stailq(struct Buffer *buf, struct Buffer *s,
1627  intptr_t data, struct Buffer *err)
1628 {
1629  do
1630  {
1632  add_to_stailq((struct ListHead *) data, buf->data);
1633  } while (MoreArgs(s));
1634 
1635  return MUTT_CMD_SUCCESS;
1636 }
1637 
1641 enum CommandResult parse_subjectrx_list(struct Buffer *buf, struct Buffer *s,
1642  intptr_t data, struct Buffer *err)
1643 {
1644  enum CommandResult rc;
1645 
1646  rc = parse_replace_list(buf, s, &SubjectRegexList, err);
1647  if (rc == MUTT_CMD_SUCCESS)
1649  return rc;
1650 }
1651 
1655 enum CommandResult parse_subscribe(struct Buffer *buf, struct Buffer *s,
1656  intptr_t data, struct Buffer *err)
1657 {
1658  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
1659 
1660  do
1661  {
1663 
1664  if (parse_grouplist(&gl, buf, s, err) == -1)
1665  goto bail;
1666 
1669 
1670  if (mutt_regexlist_add(&MailLists, buf->data, REG_ICASE, err) != 0)
1671  goto bail;
1672  if (mutt_regexlist_add(&SubscribedLists, buf->data, REG_ICASE, err) != 0)
1673  goto bail;
1674  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
1675  goto bail;
1676  } while (MoreArgs(s));
1677 
1679  return MUTT_CMD_SUCCESS;
1680 
1681 bail:
1683  return MUTT_CMD_ERROR;
1684 }
1685 
1686 #ifdef USE_IMAP
1687 
1694 enum CommandResult parse_subscribe_to(struct Buffer *buf, struct Buffer *s,
1695  intptr_t data, struct Buffer *err)
1696 {
1697  if (!buf || !s || !err)
1698  return MUTT_CMD_ERROR;
1699 
1700  mutt_buffer_reset(err);
1701 
1702  if (MoreArgs(s))
1703  {
1705 
1706  if (MoreArgs(s))
1707  {
1708  mutt_buffer_printf(err, _("%s: too many arguments"), "subscribe-to");
1709  return MUTT_CMD_WARNING;
1710  }
1711 
1712  if (buf->data && (*buf->data != '\0'))
1713  {
1714  /* Expand and subscribe */
1715  if (imap_subscribe(mutt_expand_path(buf->data, buf->dsize), true) == 0)
1716  {
1717  mutt_message(_("Subscribed to %s"), buf->data);
1718  return MUTT_CMD_SUCCESS;
1719  }
1720 
1721  mutt_buffer_printf(err, _("Could not subscribe to %s"), buf->data);
1722  return MUTT_CMD_ERROR;
1723  }
1724 
1725  mutt_debug(LL_DEBUG1, "Corrupted buffer");
1726  return MUTT_CMD_ERROR;
1727  }
1728 
1729  mutt_buffer_addstr(err, _("No folder specified"));
1730  return MUTT_CMD_WARNING;
1731 }
1732 #endif
1733 
1737 enum CommandResult parse_tag_formats(struct Buffer *buf, struct Buffer *s,
1738  intptr_t data, struct Buffer *err)
1739 {
1740  if (!buf || !s)
1741  return MUTT_CMD_ERROR;
1742 
1743  char *tmp = NULL;
1744 
1745  while (MoreArgs(s))
1746  {
1747  char *tag = NULL, *format = NULL;
1748 
1750  if (buf->data && (*buf->data != '\0'))
1751  tag = mutt_str_dup(buf->data);
1752  else
1753  continue;
1754 
1756  format = mutt_str_dup(buf->data);
1757 
1758  /* avoid duplicates */
1759  tmp = mutt_hash_find(TagFormats, format);
1760  if (tmp)
1761  {
1762  mutt_debug(LL_DEBUG3, "tag format '%s' already registered as '%s'\n", format, tmp);
1763  FREE(&tag);
1764  FREE(&format);
1765  continue;
1766  }
1767 
1768  mutt_hash_insert(TagFormats, format, tag);
1769  }
1770  return MUTT_CMD_SUCCESS;
1771 }
1772 
1776 enum CommandResult parse_tag_transforms(struct Buffer *buf, struct Buffer *s,
1777  intptr_t data, struct Buffer *err)
1778 {
1779  if (!buf || !s)
1780  return MUTT_CMD_ERROR;
1781 
1782  char *tmp = NULL;
1783 
1784  while (MoreArgs(s))
1785  {
1786  char *tag = NULL, *transform = NULL;
1787 
1789  if (buf->data && (*buf->data != '\0'))
1790  tag = mutt_str_dup(buf->data);
1791  else
1792  continue;
1793 
1795  transform = mutt_str_dup(buf->data);
1796 
1797  /* avoid duplicates */
1798  tmp = mutt_hash_find(TagTransforms, tag);
1799  if (tmp)
1800  {
1801  mutt_debug(LL_DEBUG3, "tag transform '%s' already registered as '%s'\n", tag, tmp);
1802  FREE(&tag);
1803  FREE(&transform);
1804  continue;
1805  }
1806 
1807  mutt_hash_insert(TagTransforms, tag, transform);
1808  }
1809  return MUTT_CMD_SUCCESS;
1810 }
1811 
1815 enum CommandResult parse_unalternates(struct Buffer *buf, struct Buffer *s,
1816  intptr_t data, struct Buffer *err)
1817 {
1818  alternates_clean();
1819  do
1820  {
1822  mutt_regexlist_remove(&Alternates, buf->data);
1823 
1824  if (!mutt_str_equal(buf->data, "*") &&
1825  (mutt_regexlist_add(&UnAlternates, buf->data, REG_ICASE, err) != 0))
1826  {
1827  return MUTT_CMD_ERROR;
1828  }
1829 
1830  } while (MoreArgs(s));
1831 
1832  return MUTT_CMD_SUCCESS;
1833 }
1834 
1838 enum CommandResult parse_unattachments(struct Buffer *buf, struct Buffer *s,
1839  intptr_t data, struct Buffer *err)
1840 {
1841  char op;
1842  char *p = NULL;
1843  struct ListHead *head = NULL;
1844 
1846  if (!buf->data || (*buf->data == '\0'))
1847  {
1848  mutt_buffer_strcpy(err, _("unattachments: no disposition"));
1849  return MUTT_CMD_WARNING;
1850  }
1851 
1852  p = buf->data;
1853  op = *p++;
1854 
1855  if (op == '*')
1856  {
1858  mutt_list_free_type(&AttachExclude, (list_free_t) mutt_attachmatch_free);
1859  mutt_list_free_type(&InlineAllow, (list_free_t) mutt_attachmatch_free);
1860  mutt_list_free_type(&InlineExclude, (list_free_t) mutt_attachmatch_free);
1862  return 0;
1863  }
1864 
1865  if ((op != '+') && (op != '-'))
1866  {
1867  op = '+';
1868  p--;
1869  }
1870  if (mutt_istr_startswith("attachment", p))
1871  {
1872  if (op == '+')
1873  head = &AttachAllow;
1874  else
1875  head = &AttachExclude;
1876  }
1877  else if (mutt_istr_startswith("inline", p))
1878  {
1879  if (op == '+')
1880  head = &InlineAllow;
1881  else
1882  head = &InlineExclude;
1883  }
1884  else
1885  {
1886  mutt_buffer_strcpy(err, _("unattachments: invalid disposition"));
1887  return MUTT_CMD_ERROR;
1888  }
1889 
1890  return parse_unattach_list(buf, s, head, err);
1891 }
1892 
1896 enum CommandResult parse_unignore(struct Buffer *buf, struct Buffer *s,
1897  intptr_t data, struct Buffer *err)
1898 {
1899  do
1900  {
1902 
1903  /* don't add "*" to the unignore list */
1904  if (strcmp(buf->data, "*") != 0)
1905  add_to_stailq(&UnIgnore, buf->data);
1906 
1907  remove_from_stailq(&Ignore, buf->data);
1908  } while (MoreArgs(s));
1909 
1910  return MUTT_CMD_SUCCESS;
1911 }
1912 
1916 enum CommandResult parse_unlists(struct Buffer *buf, struct Buffer *s,
1917  intptr_t data, struct Buffer *err)
1918 {
1920  do
1921  {
1925 
1926  if (!mutt_str_equal(buf->data, "*") &&
1927  (mutt_regexlist_add(&UnMailLists, buf->data, REG_ICASE, err) != 0))
1928  {
1929  return MUTT_CMD_ERROR;
1930  }
1931  } while (MoreArgs(s));
1932 
1933  return MUTT_CMD_SUCCESS;
1934 }
1935 
1940 static void do_unmailboxes(struct Mailbox *m)
1941 {
1942 #ifdef USE_INOTIFY
1944 #endif
1945  m->flags = MB_HIDDEN;
1946  if (Context && (Context->mailbox == m))
1947  {
1948  struct EventMailbox em = { NULL };
1950  }
1951  else
1952  {
1954  mailbox_free(&m);
1955  }
1956 }
1957 
1961 static void do_unmailboxes_star(void)
1962 {
1963  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
1965  struct MailboxNode *np = NULL;
1966  struct MailboxNode *nptmp = NULL;
1967  STAILQ_FOREACH_SAFE(np, &ml, entries, nptmp)
1968  {
1969  do_unmailboxes(np->mailbox);
1970  }
1972 }
1973 
1979 enum CommandResult parse_unmailboxes(struct Buffer *buf, struct Buffer *s,
1980  intptr_t data, struct Buffer *err)
1981 {
1982  while (MoreArgs(s))
1983  {
1985 
1986  if (mutt_str_equal(buf->data, "*"))
1987  {
1989  return MUTT_CMD_SUCCESS;
1990  }
1991 
1993 
1994  struct Account *a = NULL;
1995  TAILQ_FOREACH(a, &NeoMutt->accounts, entries)
1996  {
1997  struct Mailbox *m = mx_mbox_find(a, mutt_b2s(buf));
1998  if (m)
1999  {
2000  do_unmailboxes(m);
2001  break;
2002  }
2003  }
2004  }
2005  return MUTT_CMD_SUCCESS;
2006 }
2007 
2011 enum CommandResult parse_unmy_hdr(struct Buffer *buf, struct Buffer *s,
2012  intptr_t data, struct Buffer *err)
2013 {
2014  struct ListNode *np = NULL, *tmp = NULL;
2015  size_t l;
2016 
2017  do
2018  {
2020  if (mutt_str_equal("*", buf->data))
2021  {
2022  mutt_list_free(&UserHeader);
2023  continue;
2024  }
2025 
2026  l = mutt_str_len(buf->data);
2027  if (buf->data[l - 1] == ':')
2028  l--;
2029 
2030  STAILQ_FOREACH_SAFE(np, &UserHeader, entries, tmp)
2031  {
2032  if (mutt_istrn_equal(buf->data, np->data, l) && (np->data[l] == ':'))
2033  {
2034  STAILQ_REMOVE(&UserHeader, np, ListNode, entries);
2035  FREE(&np->data);
2036  FREE(&np);
2037  }
2038  }
2039  } while (MoreArgs(s));
2040  return MUTT_CMD_SUCCESS;
2041 }
2042 
2048 enum CommandResult parse_unstailq(struct Buffer *buf, struct Buffer *s,
2049  intptr_t data, struct Buffer *err)
2050 {
2051  do
2052  {
2054  /* Check for deletion of entire list */
2055  if (mutt_str_equal(buf->data, "*"))
2056  {
2057  mutt_list_free((struct ListHead *) data);
2058  break;
2059  }
2060  remove_from_stailq((struct ListHead *) data, buf->data);
2061  } while (MoreArgs(s));
2062 
2063  return MUTT_CMD_SUCCESS;
2064 }
2065 
2070  intptr_t data, struct Buffer *err)
2071 {
2072  enum CommandResult rc;
2073 
2074  rc = parse_unreplace_list(buf, s, &SubjectRegexList, err);
2075  if (rc == MUTT_CMD_SUCCESS)
2077  return rc;
2078 }
2079 
2083 enum CommandResult parse_unsubscribe(struct Buffer *buf, struct Buffer *s,
2084  intptr_t data, struct Buffer *err)
2085 {
2087  do
2088  {
2091 
2092  if (!mutt_str_equal(buf->data, "*") &&
2093  (mutt_regexlist_add(&UnSubscribedLists, buf->data, REG_ICASE, err) != 0))
2094  {
2095  return MUTT_CMD_ERROR;
2096  }
2097  } while (MoreArgs(s));
2098 
2099  return MUTT_CMD_SUCCESS;
2100 }
2101 
2102 #ifdef USE_IMAP
2103 
2111  intptr_t data, struct Buffer *err)
2112 {
2113  if (!buf || !s || !err)
2114  return MUTT_CMD_ERROR;
2115 
2116  if (MoreArgs(s))
2117  {
2119 
2120  if (MoreArgs(s))
2121  {
2122  mutt_buffer_printf(err, _("%s: too many arguments"), "unsubscribe-from");
2123  return MUTT_CMD_WARNING;
2124  }
2125 
2126  if (buf->data && (*buf->data != '\0'))
2127  {
2128  /* Expand and subscribe */
2129  if (imap_subscribe(mutt_expand_path(buf->data, buf->dsize), false) == 0)
2130  {
2131  mutt_message(_("Unsubscribed from %s"), buf->data);
2132  return MUTT_CMD_SUCCESS;
2133  }
2134 
2135  mutt_buffer_printf(err, _("Could not unsubscribe from %s"), buf->data);
2136  return MUTT_CMD_ERROR;
2137  }
2138 
2139  mutt_debug(LL_DEBUG1, "Corrupted buffer");
2140  return MUTT_CMD_ERROR;
2141  }
2142 
2143  mutt_buffer_addstr(err, _("No folder specified"));
2144  return MUTT_CMD_WARNING;
2145 }
2146 #endif
2147 
2152 {
2154 }
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
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:354
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Convenience wrapper for the gui headers.
int parse_grouplist(struct GroupList *gl, struct Buffer *buf, struct Buffer *s, struct Buffer *err)
Parse a group context.
int source_rc(const char *rcfile_path, struct Buffer *err)
Read an initialization file.
#define mutt_warning(...)
Definition: logging.h:82
The "current" mailbox.
Definition: context.h:38
struct RegexList SubscribedLists
List of regexes to match subscribed mailing lists.
Definition: globals.c:52
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:327
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:522
Manage keymappings.
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:399
Miscellaneous email parsing routines.
int msg_count
Total number of messages.
Definition: mailbox.h:91
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
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:261
char * name
Name of Account.
Definition: account.h:39
#define MUTT_UNGROUP
&#39;ungroup&#39; config command
Definition: group.h:33
IMAP network mailbox.
The envelope/body of an email.
Definition: email.h:37
int mutt_regexlist_remove(struct RegexList *rl, const char *str)
Remove a Regex from a list.
Definition: regex.c:225
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:34
bool feature_enabled(const char *name)
Test if a compile-time feature is enabled.
Definition: version.c:565
Config/command parsing.
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
Error: Can&#39;t help the user.
Definition: mutt_commands.h:36
struct ReplaceList SubjectRegexList
List of regexes to tidy the view of the email&#39;s subject.
Definition: globals.c:53
int mx_ac_add(struct Account *a, struct Mailbox *m)
Add a Mailbox to an Account - Wrapper for MxOps::ac_add()
Definition: mx.c:1783
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1500
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:754
Structs that make up an email.
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer&#39;s contents to another Buffer.
Definition: buffer.c:445
The "currently-open" mailbox.
int bool_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:185
enum CommandResult parse_alternates(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;alternates&#39; command - Implements Command::parse()
enum CommandResult parse_lists(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;lists&#39; command - Implements Command::parse()
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
#define MUTT_NOSPAM
Definition: mutt.h:115
enum CommandResult parse_finish(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;finish&#39; command - Implements Command::parse()
void mutt_grouplist_clear(struct GroupList *gl)
Clear a GroupList.
Definition: group.c:103
struct ListHead InlineAllow
List of inline types to counted.
Definition: mutt_parse.c:40
MenuType
Types of GUI selections.
Definition: keymap.h:72
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:447
#define mutt_message(...)
Definition: logging.h:83
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
static void attachments_clean(void)
always wise to do what someone else did before
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:137
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition: dump.c:83
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1468
char * disp_subj
Display subject (modified copy of subject)
Definition: envelope.h:68
void notify_free(struct Notify **ptr)
Free a notification handler.
Definition: notify.c:62
enum CommandResult parse_unsubscribe(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unsubscribe&#39; command - Implements Command::parse()
int mutt_monitor_remove(struct Mailbox *m)
Remove a watch for a mailbox.
Definition: monitor.c:524
struct Notify * notify
Notifications handler.
Definition: account.h:42
enum CommandResult parse_subjectrx_list(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;subjectrx&#39; command - Implements Command::parse()
void mutt_list_free_type(struct ListHead *h, list_free_t fn)
Free a List of type.
Definition: list.c:144
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:84
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
Match any Mailbox type.
Definition: mailbox.h:45
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:160
int quad_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a quad.
Definition: quad.c:202
void mutt_grouplist_add(struct GroupList *gl, struct Group *group)
Add a Group to a GroupList.
Definition: group.c:137
enum CommandResult parse_unattachments(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unattachments&#39; command - Implements Command::parse()
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
A group of associated Mailboxes.
Definition: account.h:36
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: globals.c:49
String manipulation buffer.
Definition: buffer.h:33
enum CommandResult mutt_parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: init.c:1039
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
enum ContentType major_int
Definition: mutt_parse.h:37
static struct AttachMatch * mutt_attachmatch_new(void)
Create a new AttachMatch.
#define _(a)
Definition: message.h:28
Mailbox wasn&#39;t recognised.
Definition: mailbox.h:47
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: globals.c:50
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:667
static enum CommandResult parse_replace_list(struct Buffer *buf, struct Buffer *s, struct ReplaceList *list, struct Buffer *err)
Parse a string replacement rule - Implements Command::parse()
#define MUTT_NAMED
Definition: mutt_commands.h:74
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
static enum CommandResult parse_attach_list(struct Buffer *buf, struct Buffer *s, struct ListHead *head, struct Buffer *err)
Parse the "attachments" command.
struct Mailbox * mx_mbox_find(struct Account *a, const char *path)
Find a Mailbox on an Account.
Definition: mx.c:1607
static bool is_function(const char *name)
Is the argument a neomutt function?
void cs_subset_free(struct ConfigSubset **ptr)
Free a Config Subset.
Definition: subset.c:93
#define STAILQ_REMOVE_HEAD(head, field)
Definition: queue.h:419
enum CommandResult parse_unignore(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unignore&#39; command - Implements Command::parse()
void mutt_grouplist_add_addrlist(struct GroupList *gl, struct AddressList *al)
Add Address list to a GroupList.
Definition: group.c:226
enum MailboxType type
Type of Mailboxes this Account contains.
Definition: account.h:38
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:168
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:616
An Event that happened to a Mailbox.
Definition: mailbox.h:181
int mutt_monitor_add(struct Mailbox *m)
Add a watch for a mailbox.
Definition: monitor.c:479
struct Account * mx_ac_find(struct Mailbox *m)
Find the Account owning a Mailbox.
Definition: mx.c:1583
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:449
#define DT_QUAD
quad-option (no/yes/ask-no/ask-yes)
Definition: types.h:37
#define MUTT_CONT
-continuation
Definition: file.h:37
void mutt_replacelist_free(struct ReplaceList *rl)
Free a ReplaceList object.
Definition: regex.c:446
Container for Accounts, Notifications.
Definition: neomutt.h:36
enum CommandResult parse_unmy_hdr(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unmy_hdr&#39; command - Implements Command::parse()
#define DTYPE(x)
Mask for the Data Type.
Definition: types.h:44
enum CommandResult parse_set(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;set&#39; family of commands - Implements Command::parse()
struct HashElem ** get_elem_list(struct ConfigSet *cs)
Create a sorted list of all config items.
Definition: subset.c:64
enum CommandResult parse_source(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;source&#39; command - Implements Command::parse()
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
enum CommandResult parse_ifdef(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;ifdef&#39; and &#39;ifndef&#39; commands - Implements Command::parse()
Convenience wrapper for the config headers.
#define DT_PATH_DIR
Path is a directory.
Definition: types.h:53
struct HashTable * AutoSubscribeCache
Hash Table of auto-subscribed mailing lists.
Definition: globals.c:48
#define CSR_RESULT(x)
Definition: set.h:52
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:49
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition: string.c:991
Email Address Handling.
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:373
bool mutt_istrn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:621
default is to reset all vars to default
Definition: mutt_commands.h:70
Some miscellaneous functions.
size_t dsize
Length of data.
Definition: buffer.h:37
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
#define MoreArgs(buf)
Definition: buffer.h:43
char * name
A short name for the Mailbox.
Definition: mailbox.h:85
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
enum CommandResult parse_unlists(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unlists&#39; command - Implements Command::parse()
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:307
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1446
int mutt_grouplist_add_regex(struct GroupList *gl, const char *s, int flags, struct Buffer *err)
Add matching Addresses to a GroupList.
Definition: group.c:276
enum CommandResult parse_group(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;group&#39; and &#39;ungroup&#39; commands - Implements Command::parse()
struct Mailbox * mailbox
Definition: context.h:50
Many unsorted constants and some structs.
Log at debug level 2.
Definition: logging.h:41
API for mailboxes.
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:324
void clear_source_stack(void)
Free memory from the stack used for the souce command.
enum CommandResult parse_spam_list(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;spam&#39; and &#39;nospam&#39; commands - Implements Command::parse()
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define MUTT_SPAM
Definition: mutt.h:114
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:341
struct Envelope * env
Envelope information.
Definition: email.h:90
Convenience wrapper for the core headers.
enum CommandResult parse_mailboxes(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;mailboxes&#39; command - Implements Command::parse()
const char * name
name of the function
Definition: keymap.h:122
#define SKIPWS(ch)
Definition: string2.h:46
int mutt_grouplist_remove_regex(struct GroupList *gl, const char *s)
Remove matching addresses from a GroupList.
Definition: group.c:300
int mutt_regexlist_add(struct RegexList *rl, const char *str, int flags, struct Buffer *err)
Compile a regex string and add it to a list.
Definition: regex.c:131
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
enum CommandResult parse_echo(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;echo&#39; command - Implements Command::parse()
const char * major
Definition: mutt_parse.h:36
GroupState
Type of email address group.
Definition: command_parse.c:74
enum CommandResult parse_ignore(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;ignore&#39; command - Implements Command::parse()
bool mutt_path_tilde(char *buf, size_t buflen, const char *homedir)
Expand &#39;~&#39; in a path.
Definition: path.c:223
Email Aliases.
struct ListHead Ignore
List of header patterns to ignore.
Definition: globals.c:45
static int print_attach_list(struct ListHead *h, const char op, const char *name)
Print a list of attachments.
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:359
void myvar_del(const char *var)
Unset the value of a "my_" variable.
Definition: myvar.c:112
int mutt_grouplist_remove_addrlist(struct GroupList *gl, struct AddressList *al)
Remove an AddressList from a GroupList.
Definition: group.c:245
int flags
e.g. MB_NORMAL
Definition: mailbox.h:134
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define DT_PATH_FILE
Path is a file.
Definition: types.h:54
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
enum CommandResult parse_unsubscribe_from(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unsubscribe-from&#39; command - Implements Command::parse()
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define mutt_b2s(buf)
Definition: buffer.h:41
#define MUTT_TOKEN_QUOTE
Don&#39;t interpret quotes.
Definition: mutt.h:74
WHERE bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:37
void add_to_stailq(struct ListHead *head, const char *str)
Add a string to a list.
Definition: muttlib.c:1700
const struct Mapping Menus[]
Menu name lookup table.
Definition: keymap.c:61
#define MB_HIDDEN
Definition: mailbox.h:38
struct ListHead InlineExclude
List of inline types to ignore.
Definition: mutt_parse.c:41
Entry is an address.
Definition: command_parse.c:78
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
#define DT_PATH
a path to a file/directory
Definition: types.h:36
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:571
enum CommandResult parse_cd(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;cd&#39; command - Implements Command::parse()
struct RegexList NoSpamList
List of regexes to whitelist non-spam emails.
Definition: globals.c:43
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:44
Functions to parse commands in a config file.
bool mutt_envlist_unset(const char *name)
Unset an environment variable.
Definition: envlist.c:132
#define IS_MAILBOX(x)
Definition: types.h:57
enum CommandResult parse_unstailq(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse an unlist command - Implements Command::parse()
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:394
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
WHERE char * C_ConfigCharset
Config: Character set that the config files are in.
Definition: mutt_globals.h:88
char * dptr
Current read/write position.
Definition: buffer.h:36
#define MUTT_TOKEN_SPACE
Don&#39;t treat whitespace as a term.
Definition: mutt.h:73
char * data
Pointer to data.
Definition: buffer.h:35
enum CommandResult parse_tag_formats(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;tag-formats&#39; command - Implements Command::parse()
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
bool attach_valid
true when the attachment count is valid
Definition: email.h:70
Definitions of NeoMutt commands.
GUI present the user with a selectable list.
static void do_unmailboxes_star(void)
Remove all Mailboxes from the Sidebar/notifications.
struct HashTable * TagTransforms
Lookup table of alternative tag names.
Definition: tags.c:38
void myvar_set(const char *var, const char *val)
Set the value of a "my_" variable.
Definition: myvar.c:91
Group is missing an argument.
Definition: command_parse.c:76
bool mutt_path_to_absolute(char *path, const char *reference)
Convert relative filepath to an absolute path.
Definition: path.c:397
struct Command * mutt_command_get(const char *s)
Get a Command by its name.
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
#define MUTT_TOKEN_PLUS
Treat &#39;+&#39; as a special.
Definition: mutt.h:81
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
static void alternates_clean(void)
Clear the recipient valid flag of all emails.
enum CommandResult mutt_parse_rc_buffer(struct Buffer *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:981
default is to unset all vars
Definition: mutt_commands.h:69
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:43
static void do_unmailboxes(struct Mailbox *m)
Remove a Mailbox from the Sidebar/notifications.
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
Display version and copyright about NeoMutt.
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_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
const char * myvar_get(const char *var)
Get the value of a "my_" variable.
Definition: myvar.c:73
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:604
struct ReplaceList SpamList
List of regexes and patterns to match spam emails.
Definition: globals.c:44
struct ListHead AttachExclude
List of attachment types to be ignored.
Definition: mutt_parse.c:39
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
static enum CommandResult parse_unreplace_list(struct Buffer *buf, struct Buffer *s, struct ReplaceList *list, struct Buffer *err)
Remove a string replacement rule - Implements Command::parse()
Definition: command_parse.c:84
void remove_from_stailq(struct ListHead *head, const char *str)
Remove an item, matching a string, from a List.
Definition: muttlib.c:1725
struct Mailbox * mailbox_new(void)
Create a new Mailbox.
Definition: mailbox.c:42
Success: Command worked.
Definition: mutt_commands.h:38
char * data
String.
Definition: list.h:36
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
struct Account * account
Account that owns this Mailbox.
Definition: mailbox.h:131
struct ListHead UnIgnore
List of header patterns to unignore (see)
Definition: globals.c:46
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1304
Log at debug level 1.
Definition: logging.h:40
Warning: Help given to the user.
Definition: mutt_commands.h:37
enum CommandResult parse_tag_transforms(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;tag-transforms&#39; command - Implements Command::parse()
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:411
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:716
int mutt_replacelist_remove(struct ReplaceList *rl, const char *pat)
Remove a pattern from a list.
Definition: regex.c:563
Finish: Stop processing this file.
Definition: mutt_commands.h:39
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
#define MAX_ERRS
Definition: command_parse.c:69
Current Mailbox has changed.
Definition: mailbox.h:173
regex_t minor_regex
Definition: mutt_parse.h:39
#define mutt_error(...)
Definition: logging.h:84
#define MUTT_TOKEN_MINUS
Treat &#39;-&#39; as a special.
Definition: mutt.h:82
enum CommandResult parse_subscribe(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;subscribe&#39; command - Implements Command::parse()
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: globals.c:51
const struct Binding * km_get_table(enum MenuType menu)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1306
#define MUTT_TOKEN_BACKTICK_VARS
Expand variables within backticks.
Definition: mutt.h:78
void mutt_grouplist_destroy(struct GroupList *gl)
Free a GroupList.
Definition: group.c:157
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:45
#define FREE(x)
Definition: memory.h:40
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:94
enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;my_hdr&#39; command - Implements Command::parse()
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: account.h:40
enum CommandResult parse_unsubjectrx_list(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unsubjectrx&#39; command - Implements Command::parse()
Monitor files for changes.
static struct ListHead MuttrcStack
Definition: command_parse.c:67
#define STAILQ_EMPTY(head)
Definition: queue.h:345
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
bool recip_valid
Is_recipient is valid.
Definition: email.h:58
bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:85
The item stored in a Hash Table.
Definition: hash.h:43
#define MUTT_TOKEN_EQUAL
Treat &#39;=&#39; as a special.
Definition: mutt.h:71
List of Mailboxes.
Definition: mailbox.h:150
static enum CommandResult parse_unattach_list(struct Buffer *buf, struct Buffer *s, struct ListHead *head, struct Buffer *err)
Parse the "unattachments" command.
static void clear_subject_mods(void)
Clear out all modified email subjects.
Hundreds of global variables to back the user variables.
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
void mutt_attachmatch_free(struct AttachMatch **ptr)
Free an AttachMatch - Implements list_free_t.
Definition: mutt_parse.c:240
#define IS_COMMAND(x)
Definition: types.h:58
default is to set all vars
Definition: mutt_commands.h:67
#define TAILQ_EMPTY(head)
Definition: queue.h:714
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
Entry is a regular expression.
Definition: command_parse.c:77
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition: neomutt.c:84
An attachment matching a regex for attachment counter.
Definition: mutt_parse.h:34
enum CommandResult parse_unmailboxes(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unmailboxes&#39; command - Implements Command::parse()
struct Buffer pathbuf
Definition: mailbox.h:83
Convenience wrapper for the library headers.
WHERE struct HashTable * TagFormats
Hash Table of tag-formats (tag -> format string)
Definition: mutt_globals.h:59
A List node for strings.
Definition: list.h:34
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:1304
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
#define MB_NORMAL
Definition: mailbox.h:37
Handling of personal config (&#39;my&#39; variables)
enum CommandResult parse_subscribe_to(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;subscribe-to&#39; command - Implements Command::parse()
struct ListHead AttachAllow
List of attachment types to be counted.
Definition: mutt_parse.c:38
enum CommandResult parse_attachments(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;attachments&#39; command - Implements Command::parse()
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:53
enum CommandResult parse_unalternates(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;unalternates&#39; command - Implements Command::parse()
const char * minor
Definition: mutt_parse.h:38
#define STAILQ_FIRST(head)
Definition: queue.h:347
Mapping between a user key and a function.
Definition: keymap.h:120
enum CommandResult parse_setenv(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the &#39;setenv&#39; and &#39;unsetenv&#39; commands - Implements Command::parse()
struct Group * mutt_pattern_group(const char *pat)
Match a pattern to a Group.
Definition: group.c:65
#define DT_BOOL
boolean option
Definition: types.h:30
void mutt_regexlist_free(struct RegexList *rl)
Free a RegexList object.
Definition: regex.c:169
enum CommandResult parse_stailq(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse a list command - Implements Command::parse()
Log at debug level 3.
Definition: logging.h:42
default is to invert all vars
Definition: mutt_commands.h:68
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:270
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:70
#define MUTT_TOKEN_QUESTION
Treat &#39;?&#39; as a special.
Definition: mutt.h:80
int imap_subscribe(char *path, bool subscribe)
Subscribe to a mailbox.
Definition: imap.c:1264
ContentType
Content-Type.
Definition: mime.h:29
char ** mutt_envlist_getlist(void)
Get the private environment.
Definition: envlist.c:169
void(* list_free_t)(void **ptr)
Prototype for a function to free List data.
Definition: list.h:45
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:152
#define MUTT_GROUP
&#39;group&#39; config command
Definition: group.h:32
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:152