NeoMutt  2020-06-26-250-g349c94
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 "context.h"
47 #include "init.h"
48 #include "keymap.h"
49 #include "monitor.h"
50 #include "mutt_commands.h"
51 #include "mutt_globals.h"
52 #include "mutt_logging.h"
53 #include "mutt_menu.h"
54 #include "mutt_parse.h"
55 #include "muttlib.h"
56 #include "mx.h"
57 #include "myvar.h"
58 #include "options.h"
59 #include "version.h"
60 #include "imap/lib.h"
61 #ifdef USE_SIDEBAR
62 #include "sidebar/lib.h"
63 #endif
64 #ifdef ENABLE_NLS
65 #include <libintl.h>
66 #endif
67 
68 /* LIFO designed to contain the list of config files that have been sourced and
69  * avoid cyclic sourcing */
71 
72 #define MAX_ERRS 128
73 
78 {
82 };
83 
87 static enum CommandResult parse_unreplace_list(struct Buffer *buf, struct Buffer *s,
88  struct ReplaceList *list, struct Buffer *err)
89 {
90  /* First token is a regex. */
91  if (!MoreArgs(s))
92  {
93  mutt_buffer_printf(err, _("%s: too few arguments"), "unsubjectrx");
94  return MUTT_CMD_WARNING;
95  }
96 
98 
99  /* "*" is a special case. */
100  if (mutt_str_equal(buf->data, "*"))
101  {
102  mutt_replacelist_free(list);
103  return MUTT_CMD_SUCCESS;
104  }
105 
106  mutt_replacelist_remove(list, buf->data);
107  return MUTT_CMD_SUCCESS;
108 }
109 
113 static void attachments_clean(void)
114 {
115  if (!Context || !Context->mailbox)
116  return;
117 
118  struct Mailbox *m = Context->mailbox;
119  for (int i = 0; i < m->msg_count; i++)
120  {
121  struct Email *e = m->emails[i];
122  if (!e)
123  break;
124  e->attach_valid = false;
125  }
126 }
127 
136 static enum CommandResult parse_unattach_list(struct Buffer *buf, struct Buffer *s,
137  struct ListHead *head, struct Buffer *err)
138 {
139  struct AttachMatch *a = NULL;
140  char *tmp = NULL;
141  char *minor = NULL;
142 
143  do
144  {
146  FREE(&tmp);
147 
148  if (mutt_istr_equal(buf->data, "any"))
149  tmp = mutt_str_dup("*/.*");
150  else if (mutt_istr_equal(buf->data, "none"))
151  tmp = mutt_str_dup("cheap_hack/this_should_never_match");
152  else
153  tmp = mutt_str_dup(buf->data);
154 
155  minor = strchr(tmp, '/');
156  if (minor)
157  {
158  *minor = '\0';
159  minor++;
160  }
161  else
162  {
163  minor = "unknown";
164  }
165  const enum ContentType major = mutt_check_mime_type(tmp);
166 
167  struct ListNode *np = NULL, *tmp2 = NULL;
168  STAILQ_FOREACH_SAFE(np, head, entries, tmp2)
169  {
170  a = (struct AttachMatch *) np->data;
171  mutt_debug(LL_DEBUG3, "check %s/%s [%d] : %s/%s [%d]\n", a->major,
172  a->minor, a->major_int, tmp, minor, major);
173  if ((a->major_int == major) && mutt_istr_equal(minor, a->minor))
174  {
175  mutt_debug(LL_DEBUG3, "removed %s/%s [%d]\n", a->major, a->minor, a->major_int);
176  regfree(&a->minor_regex);
177  FREE(&a->major);
178  STAILQ_REMOVE(head, np, ListNode, entries);
179  FREE(&np->data);
180  FREE(&np);
181  }
182  }
183 
184  } while (MoreArgs(s));
185 
186  FREE(&tmp);
188  return MUTT_CMD_SUCCESS;
189 }
190 
194 static void clear_subject_mods(void)
195 {
196  if (!Context || !Context->mailbox)
197  return;
198 
199  struct Mailbox *m = Context->mailbox;
200  for (int i = 0; i < m->msg_count; i++)
201  {
202  struct Email *e = m->emails[i];
203  if (!e || !e->env)
204  continue;
205  FREE(&e->env->disp_subj);
206  }
207 }
208 
212 static enum CommandResult parse_replace_list(struct Buffer *buf, struct Buffer *s,
213  struct ReplaceList *list, struct Buffer *err)
214 {
215  struct Buffer templ = mutt_buffer_make(0);
216 
217  /* First token is a regex. */
218  if (!MoreArgs(s))
219  {
220  mutt_buffer_printf(err, _("%s: too few arguments"), "subjectrx");
221  return MUTT_CMD_WARNING;
222  }
224 
225  /* Second token is a replacement template */
226  if (!MoreArgs(s))
227  {
228  mutt_buffer_printf(err, _("%s: too few arguments"), "subjectrx");
229  return MUTT_CMD_WARNING;
230  }
232 
233  if (mutt_replacelist_add(list, buf->data, templ.data, err) != 0)
234  {
235  FREE(&templ.data);
236  return MUTT_CMD_ERROR;
237  }
238  FREE(&templ.data);
239 
240  return MUTT_CMD_SUCCESS;
241 }
242 
249 static bool is_function(const char *name)
250 {
251  for (enum MenuType i = 0; i < MENU_MAX; i++)
252  {
253  const struct Binding *b = km_get_table(Menus[i].value);
254  if (!b)
255  continue;
256 
257  for (int j = 0; b[j].name; j++)
258  if (mutt_str_equal(name, b[j].name))
259  return true;
260  }
261  return false;
262 }
263 
268 static struct AttachMatch *mutt_attachmatch_new(void)
269 {
270  return mutt_mem_calloc(1, sizeof(struct AttachMatch));
271 }
272 
281 static enum CommandResult parse_attach_list(struct Buffer *buf, struct Buffer *s,
282  struct ListHead *head, struct Buffer *err)
283 {
284  struct AttachMatch *a = NULL;
285  char *p = NULL;
286  char *tmpminor = NULL;
287  size_t len;
288  int ret;
289 
290  do
291  {
293 
294  if (!buf->data || (*buf->data == '\0'))
295  continue;
296 
297  a = mutt_attachmatch_new();
298 
299  /* some cheap hacks that I expect to remove */
300  if (mutt_istr_equal(buf->data, "any"))
301  a->major = mutt_str_dup("*/.*");
302  else if (mutt_istr_equal(buf->data, "none"))
303  a->major = mutt_str_dup("cheap_hack/this_should_never_match");
304  else
305  a->major = mutt_str_dup(buf->data);
306 
307  p = strchr(a->major, '/');
308  if (p)
309  {
310  *p = '\0';
311  p++;
312  a->minor = p;
313  }
314  else
315  {
316  a->minor = "unknown";
317  }
318 
319  len = strlen(a->minor);
320  tmpminor = mutt_mem_malloc(len + 3);
321  strcpy(&tmpminor[1], a->minor);
322  tmpminor[0] = '^';
323  tmpminor[len + 1] = '$';
324  tmpminor[len + 2] = '\0';
325 
327  ret = REG_COMP(&a->minor_regex, tmpminor, REG_ICASE);
328 
329  FREE(&tmpminor);
330 
331  if (ret != 0)
332  {
333  regerror(ret, &a->minor_regex, err->data, err->dsize);
334  FREE(&a->major);
335  FREE(&a);
336  return MUTT_CMD_ERROR;
337  }
338 
339  mutt_debug(LL_DEBUG3, "added %s/%s [%d]\n", a->major, a->minor, a->major_int);
340 
341  mutt_list_insert_tail(head, (char *) a);
342  } while (MoreArgs(s));
343 
345  return MUTT_CMD_SUCCESS;
346 }
347 
355 static int print_attach_list(struct ListHead *h, const char op, const char *name)
356 {
357  struct ListNode *np = NULL;
358  STAILQ_FOREACH(np, h, entries)
359  {
360  printf("attachments %c%s %s/%s\n", op, name,
361  ((struct AttachMatch *) np->data)->major,
362  ((struct AttachMatch *) np->data)->minor);
363  }
364 
365  return 0;
366 }
367 
371 static void alternates_clean(void)
372 {
373  if (!Context || !Context->mailbox)
374  return;
375 
376  struct Mailbox *m = Context->mailbox;
377  for (int i = 0; i < m->msg_count; i++)
378  {
379  struct Email *e = m->emails[i];
380  if (!e)
381  break;
382  e->recip_valid = false;
383  }
384 }
385 
395 int parse_grouplist(struct GroupList *gl, struct Buffer *buf, struct Buffer *s,
396  struct Buffer *err)
397 {
398  while (mutt_istr_equal(buf->data, "-group"))
399  {
400  if (!MoreArgs(s))
401  {
402  mutt_buffer_strcpy(err, _("-group: no group name"));
403  return -1;
404  }
405 
407 
409 
410  if (!MoreArgs(s))
411  {
412  mutt_buffer_strcpy(err, _("out of arguments"));
413  return -1;
414  }
415 
417  }
418 
419  return 0;
420 }
421 
428 int source_rc(const char *rcfile_path, struct Buffer *err)
429 {
430  int lineno = 0, rc = 0, warnings = 0;
431  enum CommandResult line_rc;
432  struct Buffer *token = NULL, *linebuf = NULL;
433  char *line = NULL;
434  char *currentline = NULL;
435  char rcfile[PATH_MAX];
436  size_t linelen = 0;
437  pid_t pid;
438 
439  mutt_str_copy(rcfile, rcfile_path, sizeof(rcfile));
440 
441  size_t rcfilelen = mutt_str_len(rcfile);
442  if (rcfilelen == 0)
443  return -1;
444 
445  bool ispipe = rcfile[rcfilelen - 1] == '|';
446 
447  if (!ispipe)
448  {
449  struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
450  if (!mutt_path_to_absolute(rcfile, np ? NONULL(np->data) : ""))
451  {
452  mutt_error(_("Error: Can't build path of '%s'"), rcfile_path);
453  return -1;
454  }
455 
456  STAILQ_FOREACH(np, &MuttrcStack, entries)
457  {
458  if (mutt_str_equal(np->data, rcfile))
459  {
460  break;
461  }
462  }
463  if (np)
464  {
465  mutt_error(_("Error: Cyclic sourcing of configuration file '%s'"), rcfile);
466  return -1;
467  }
468 
470  }
471 
472  mutt_debug(LL_DEBUG2, "Reading configuration file '%s'\n", rcfile);
473 
474  FILE *fp = mutt_open_read(rcfile, &pid);
475  if (!fp)
476  {
477  mutt_buffer_printf(err, "%s: %s", rcfile, strerror(errno));
478  return -1;
479  }
480 
481  token = mutt_buffer_pool_get();
482  linebuf = mutt_buffer_pool_get();
483 
484  while ((line = mutt_file_read_line(line, &linelen, fp, &lineno, MUTT_CONT)) != NULL)
485  {
486  const bool conv = C_ConfigCharset && C_Charset;
487  if (conv)
488  {
489  currentline = mutt_str_dup(line);
490  if (!currentline)
491  continue;
492  mutt_ch_convert_string(&currentline, C_ConfigCharset, C_Charset, 0);
493  }
494  else
495  currentline = line;
496 
497  mutt_buffer_strcpy(linebuf, currentline);
498 
499  mutt_buffer_reset(err);
500  line_rc = mutt_parse_rc_buffer(linebuf, token, err);
501  if (line_rc == MUTT_CMD_ERROR)
502  {
503  mutt_error(_("Error in %s, line %d: %s"), rcfile, lineno, err->data);
504  if (--rc < -MAX_ERRS)
505  {
506  if (conv)
507  FREE(&currentline);
508  break;
509  }
510  }
511  else if (line_rc == MUTT_CMD_WARNING)
512  {
513  /* Warning */
514  mutt_warning(_("Warning in %s, line %d: %s"), rcfile, lineno, err->data);
515  warnings++;
516  }
517  else if (line_rc == MUTT_CMD_FINISH)
518  {
519  break; /* Found "finish" command */
520  }
521  else
522  {
523  if (rc < 0)
524  rc = -1;
525  }
526  if (conv)
527  FREE(&currentline);
528  }
529 
530  FREE(&line);
531  mutt_file_fclose(&fp);
532  if (pid != -1)
533  filter_wait(pid);
534 
535  if (rc)
536  {
537  /* the neomuttrc source keyword */
538  mutt_buffer_reset(err);
539  mutt_buffer_printf(err, (rc >= -MAX_ERRS) ? _("source: errors in %s") : _("source: reading aborted due to too many errors in %s"),
540  rcfile);
541  rc = -1;
542  }
543  else
544  {
545  /* Don't alias errors with warnings */
546  if (warnings > 0)
547  {
548  mutt_buffer_printf(err, ngettext("source: %d warning in %s", "source: %d warnings in %s", warnings),
549  warnings, rcfile);
550  rc = -2;
551  }
552  }
553 
554  if (!ispipe && !STAILQ_EMPTY(&MuttrcStack))
555  {
556  struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
557  STAILQ_REMOVE_HEAD(&MuttrcStack, entries);
558  FREE(&np->data);
559  FREE(&np);
560  }
561 
562  mutt_buffer_pool_release(&token);
563  mutt_buffer_pool_release(&linebuf);
564  return rc;
565 }
566 
570 enum CommandResult parse_alternates(struct Buffer *buf, struct Buffer *s,
571  intptr_t data, struct Buffer *err)
572 {
573  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
574 
576 
577  do
578  {
580 
581  if (parse_grouplist(&gl, buf, s, err) == -1)
582  goto bail;
583 
584  mutt_regexlist_remove(&UnAlternates, buf->data);
585 
586  if (mutt_regexlist_add(&Alternates, buf->data, REG_ICASE, err) != 0)
587  goto bail;
588 
589  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
590  goto bail;
591  } while (MoreArgs(s));
592 
594  return MUTT_CMD_SUCCESS;
595 
596 bail:
598  return MUTT_CMD_ERROR;
599 }
600 
604 enum CommandResult parse_attachments(struct Buffer *buf, struct Buffer *s,
605  intptr_t data, struct Buffer *err)
606 {
607  char op;
608  char *category = NULL;
609  struct ListHead *head = NULL;
610 
612  if (!buf->data || (*buf->data == '\0'))
613  {
614  mutt_buffer_strcpy(err, _("attachments: no disposition"));
615  return MUTT_CMD_WARNING;
616  }
617 
618  category = buf->data;
619  op = *category++;
620 
621  if (op == '?')
622  {
623  mutt_endwin();
624  fflush(stdout);
625  printf("\n%s\n\n", _("Current attachments settings:"));
626  print_attach_list(&AttachAllow, '+', "A");
627  print_attach_list(&AttachExclude, '-', "A");
628  print_attach_list(&InlineAllow, '+', "I");
629  print_attach_list(&InlineExclude, '-', "I");
631  return MUTT_CMD_SUCCESS;
632  }
633 
634  if ((op != '+') && (op != '-'))
635  {
636  op = '+';
637  category--;
638  }
639  if (mutt_istr_startswith("attachment", category))
640  {
641  if (op == '+')
642  head = &AttachAllow;
643  else
644  head = &AttachExclude;
645  }
646  else if (mutt_istr_startswith("inline", category))
647  {
648  if (op == '+')
649  head = &InlineAllow;
650  else
651  head = &InlineExclude;
652  }
653  else
654  {
655  mutt_buffer_strcpy(err, _("attachments: invalid disposition"));
656  return MUTT_CMD_ERROR;
657  }
658 
659  return parse_attach_list(buf, s, head, err);
660 }
661 
665 enum CommandResult parse_cd(struct Buffer *buf, struct Buffer *s, intptr_t data,
666  struct Buffer *err)
667 {
670  if (mutt_buffer_len(buf) == 0)
671  {
672  if (HomeDir)
674  else
675  {
676  mutt_buffer_printf(err, _("%s: too few arguments"), "cd");
677  return MUTT_CMD_ERROR;
678  }
679  }
680 
681  if (chdir(mutt_b2s(buf)) != 0)
682  {
683  mutt_buffer_printf(err, "cd: %s", strerror(errno));
684  return MUTT_CMD_ERROR;
685  }
686 
687  return MUTT_CMD_SUCCESS;
688 }
689 
693 enum CommandResult parse_echo(struct Buffer *buf, struct Buffer *s,
694  intptr_t data, struct Buffer *err)
695 {
696  if (!MoreArgs(s))
697  {
698  mutt_buffer_printf(err, _("%s: too few arguments"), "echo");
699  return MUTT_CMD_WARNING;
700  }
702  OptForceRefresh = true;
703  mutt_message("%s", buf->data);
704  OptForceRefresh = false;
705  mutt_sleep(0);
706 
707  return MUTT_CMD_SUCCESS;
708 }
709 
717 enum CommandResult parse_finish(struct Buffer *buf, struct Buffer *s,
718  intptr_t data, struct Buffer *err)
719 {
720  if (MoreArgs(s))
721  {
722  mutt_buffer_printf(err, _("%s: too many arguments"), "finish");
723  return MUTT_CMD_WARNING;
724  }
725 
726  return MUTT_CMD_FINISH;
727 }
728 
732 enum CommandResult parse_group(struct Buffer *buf, struct Buffer *s,
733  intptr_t data, struct Buffer *err)
734 {
735  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
736  enum GroupState state = GS_NONE;
737 
738  do
739  {
741  if (parse_grouplist(&gl, buf, s, err) == -1)
742  goto bail;
743 
744  if ((data == MUTT_UNGROUP) && mutt_istr_equal(buf->data, "*"))
745  {
747  goto out;
748  }
749 
750  if (mutt_istr_equal(buf->data, "-rx"))
751  state = GS_RX;
752  else if (mutt_istr_equal(buf->data, "-addr"))
753  state = GS_ADDR;
754  else
755  {
756  switch (state)
757  {
758  case GS_NONE:
759  mutt_buffer_printf(err, _("%sgroup: missing -rx or -addr"),
760  (data == MUTT_UNGROUP) ? "un" : "");
761  goto warn;
762 
763  case GS_RX:
764  if ((data == MUTT_GROUP) &&
765  (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0))
766  {
767  goto bail;
768  }
769  else if ((data == MUTT_UNGROUP) &&
770  (mutt_grouplist_remove_regex(&gl, buf->data) < 0))
771  {
772  goto bail;
773  }
774  break;
775 
776  case GS_ADDR:
777  {
778  char *estr = NULL;
779  struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
780  mutt_addrlist_parse2(&al, buf->data);
781  if (TAILQ_EMPTY(&al))
782  goto bail;
783  if (mutt_addrlist_to_intl(&al, &estr))
784  {
785  mutt_buffer_printf(err, _("%sgroup: warning: bad IDN '%s'"),
786  (data == 1) ? "un" : "", estr);
787  mutt_addrlist_clear(&al);
788  FREE(&estr);
789  goto bail;
790  }
791  if (data == MUTT_GROUP)
792  mutt_grouplist_add_addrlist(&gl, &al);
793  else if (data == MUTT_UNGROUP)
795  mutt_addrlist_clear(&al);
796  break;
797  }
798  }
799  }
800  } while (MoreArgs(s));
801 
802 out:
804  return MUTT_CMD_SUCCESS;
805 
806 bail:
808  return MUTT_CMD_ERROR;
809 
810 warn:
812  return MUTT_CMD_WARNING;
813 }
814 
828 enum CommandResult parse_ifdef(struct Buffer *buf, struct Buffer *s,
829  intptr_t data, struct Buffer *err)
830 {
832 
833  // is the item defined as:
834  bool res = cs_subset_lookup(NeoMutt->sub, buf->data) // a variable?
835  || feature_enabled(buf->data) // a compiled-in feature?
836  || is_function(buf->data) // a function?
837  || mutt_command_get(buf->data) // a command?
838  || myvar_get(buf->data) // a my_ variable?
839  || mutt_str_getenv(buf->data); // an environment variable?
840 
841  if (!MoreArgs(s))
842  {
843  mutt_buffer_printf(err, _("%s: too few arguments"), (data ? "ifndef" : "ifdef"));
844  return MUTT_CMD_WARNING;
845  }
847 
848  /* ifdef KNOWN_SYMBOL or ifndef UNKNOWN_SYMBOL */
849  if ((res && (data == 0)) || (!res && (data == 1)))
850  {
851  enum CommandResult rc = mutt_parse_rc_line(buf->data, err);
852  if (rc == MUTT_CMD_ERROR)
853  {
854  mutt_error(_("Error: %s"), err->data);
855  return MUTT_CMD_ERROR;
856  }
857  return rc;
858  }
859  return MUTT_CMD_SUCCESS;
860 }
861 
865 enum CommandResult parse_ignore(struct Buffer *buf, struct Buffer *s,
866  intptr_t data, struct Buffer *err)
867 {
868  do
869  {
872  add_to_stailq(&Ignore, buf->data);
873  } while (MoreArgs(s));
874 
875  return MUTT_CMD_SUCCESS;
876 }
877 
881 enum CommandResult parse_lists(struct Buffer *buf, struct Buffer *s,
882  intptr_t data, struct Buffer *err)
883 {
884  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
885 
886  do
887  {
889 
890  if (parse_grouplist(&gl, buf, s, err) == -1)
891  goto bail;
892 
894 
895  if (mutt_regexlist_add(&MailLists, buf->data, REG_ICASE, err) != 0)
896  goto bail;
897 
898  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
899  goto bail;
900  } while (MoreArgs(s));
901 
903  return MUTT_CMD_SUCCESS;
904 
905 bail:
907  return MUTT_CMD_ERROR;
908 }
909 
915 enum CommandResult parse_mailboxes(struct Buffer *buf, struct Buffer *s,
916  intptr_t data, struct Buffer *err)
917 {
918  while (MoreArgs(s))
919  {
920  struct Mailbox *m = mailbox_new();
921 
922  if (data & MUTT_NAMED)
923  {
924  // This may be empty, e.g. `named-mailboxes "" +inbox`
926  m->name = mutt_buffer_strdup(buf);
927  }
928 
930  if (mutt_buffer_is_empty(buf))
931  {
932  /* Skip empty tokens. */
933  mailbox_free(&m);
934  continue;
935  }
936 
937  mutt_buffer_strcpy(&m->pathbuf, buf->data);
938  /* int rc = */ mx_path_canon2(m, C_Folder);
939 
940  if (m->type <= MUTT_UNKNOWN)
941  {
942  mutt_error("Unknown Mailbox: %s", m->realpath);
943  mailbox_free(&m);
944  return MUTT_CMD_ERROR;
945  }
946 
947  bool new_account = false;
948  struct Account *a = mx_ac_find(m);
949  if (!a)
950  {
951  a = account_new(NULL, NeoMutt->sub);
952  a->type = m->type;
953  new_account = true;
954  }
955 
956  if (!new_account)
957  {
958  struct Mailbox *m_old = mx_mbox_find(a, m->realpath);
959  if (m_old)
960  {
961  const bool show = (m_old->flags == MB_HIDDEN);
962  if (show)
963  {
964  m_old->flags = MB_NORMAL;
965  }
966 
967  const bool rename = (data & MUTT_NAMED) && !mutt_str_equal(m_old->name, m->name);
968  if (rename)
969  {
970  mutt_str_replace(&m_old->name, m->name);
971  }
972 
973 #ifdef USE_SIDEBAR
974  if (show || rename)
975  {
976  struct MuttWindow *dlg = TAILQ_LAST(&AllDialogsWindow->children, MuttWindowList);
977  struct MuttWindow *win_sidebar = mutt_window_find(dlg, WT_SIDEBAR);
978  if (win_sidebar)
979  sb_notify_mailbox(win_sidebar, m_old, show ? SBN_CREATED : SBN_RENAMED);
980  }
981 #endif
982  mailbox_free(&m);
983  continue;
984  }
985  }
986 
987  if (mx_ac_add(a, m) < 0)
988  {
989  //error
990  mailbox_free(&m);
991  if (new_account)
992  {
993  cs_subset_free(&a->sub);
994  FREE(&a->name);
995  notify_free(&a->notify);
996  FREE(&a);
997  }
998  continue;
999  }
1000  if (new_account)
1001  {
1003  }
1004 
1005 #ifdef USE_SIDEBAR
1006  struct MuttWindow *dlg = TAILQ_LAST(&AllDialogsWindow->children, MuttWindowList);
1007  struct MuttWindow *win_sidebar = mutt_window_find(dlg, WT_SIDEBAR);
1008  if (win_sidebar)
1009  sb_notify_mailbox(win_sidebar, m, SBN_CREATED);
1010 #endif
1011 #ifdef USE_INOTIFY
1012  mutt_monitor_add(m);
1013 #endif
1014  }
1015  return MUTT_CMD_SUCCESS;
1016 }
1017 
1021 enum CommandResult parse_my_hdr(struct Buffer *buf, struct Buffer *s,
1022  intptr_t data, struct Buffer *err)
1023 {
1024  struct ListNode *n = NULL;
1025  size_t keylen;
1026 
1028  char *p = strpbrk(buf->data, ": \t");
1029  if (!p || (*p != ':'))
1030  {
1031  mutt_buffer_strcpy(err, _("invalid header field"));
1032  return MUTT_CMD_WARNING;
1033  }
1034  keylen = p - buf->data + 1;
1035 
1036  STAILQ_FOREACH(n, &UserHeader, entries)
1037  {
1038  /* see if there is already a field by this name */
1039  if (mutt_istrn_equal(buf->data, n->data, keylen))
1040  {
1041  break;
1042  }
1043  }
1044 
1045  if (!n)
1046  {
1047  /* not found, allocate memory for a new node and add it to the list */
1048  n = mutt_list_insert_tail(&UserHeader, NULL);
1049  }
1050  else
1051  {
1052  /* found, free the existing data */
1053  FREE(&n->data);
1054  }
1055 
1056  n->data = mutt_buffer_strdup(buf);
1057 
1058  return MUTT_CMD_SUCCESS;
1059 }
1060 
1066 enum CommandResult parse_set(struct Buffer *buf, struct Buffer *s,
1067  intptr_t data, struct Buffer *err)
1068 {
1069  /* The order must match `enum MuttSetCommand` */
1070  static const char *set_commands[] = { "set", "toggle", "unset", "reset" };
1071 
1072  int rc = 0;
1073 
1074  while (MoreArgs(s))
1075  {
1076  bool prefix = false;
1077  bool query = false;
1078  bool inv = (data == MUTT_SET_INV);
1079  bool reset = (data == MUTT_SET_RESET);
1080  bool unset = (data == MUTT_SET_UNSET);
1081 
1082  if (*s->dptr == '?')
1083  {
1084  prefix = true;
1085  query = true;
1086  s->dptr++;
1087  }
1088  else if (mutt_str_startswith(s->dptr, "no"))
1089  {
1090  prefix = true;
1091  unset = !unset;
1092  s->dptr += 2;
1093  }
1094  else if (mutt_str_startswith(s->dptr, "inv"))
1095  {
1096  prefix = true;
1097  inv = !inv;
1098  s->dptr += 3;
1099  }
1100  else if (*s->dptr == '&')
1101  {
1102  prefix = true;
1103  reset = true;
1104  s->dptr++;
1105  }
1106 
1107  if (prefix && (data != MUTT_SET_SET))
1108  {
1109  mutt_buffer_printf(err, "ERR22 can't use 'inv', 'no', '&' or '?' with the '%s' command",
1110  set_commands[data]);
1111  return MUTT_CMD_WARNING;
1112  }
1113 
1114  /* get the variable name */
1116 
1117  bool bq = false;
1118  bool equals = false;
1119  bool increment = false;
1120  bool decrement = false;
1121 
1122  struct HashElem *he = NULL;
1123  bool my = mutt_str_startswith(buf->data, "my_");
1124  if (!my)
1125  {
1126  he = cs_subset_lookup(NeoMutt->sub, buf->data);
1127  if (!he)
1128  {
1129  if (reset && mutt_str_equal(buf->data, "all"))
1130  {
1131  struct HashElem **list = get_elem_list(NeoMutt->sub->cs);
1132  if (!list)
1133  return MUTT_CMD_ERROR;
1134 
1135  for (size_t i = 0; list[i]; i++)
1136  cs_subset_he_reset(NeoMutt->sub, list[i], NULL);
1137 
1138  FREE(&list);
1139  break;
1140  }
1141  else
1142  {
1143  mutt_buffer_printf(err, "ERR01 unknown variable: %s", buf->data);
1144  return MUTT_CMD_ERROR;
1145  }
1146  }
1147 
1148  bq = ((DTYPE(he->type) == DT_BOOL) || (DTYPE(he->type) == DT_QUAD));
1149  }
1150 
1151  if (*s->dptr == '?')
1152  {
1153  if (prefix)
1154  {
1155  mutt_buffer_printf(err,
1156  "ERR02 can't use a prefix when querying a variable");
1157  return MUTT_CMD_WARNING;
1158  }
1159 
1160  if (reset || unset || inv)
1161  {
1162  mutt_buffer_printf(err, "ERR03 can't query a variable with the '%s' command",
1163  set_commands[data]);
1164  return MUTT_CMD_WARNING;
1165  }
1166 
1167  query = true;
1168  s->dptr++;
1169  }
1170  else if (*s->dptr == '+' || *s->dptr == '-')
1171  {
1172  if (prefix)
1173  {
1174  mutt_buffer_printf(err, "ERR04 can't use prefix when incrementing or "
1175  "decrementing a variable");
1176  return MUTT_CMD_WARNING;
1177  }
1178 
1179  if (reset || unset || inv)
1180  {
1181  mutt_buffer_printf(err, "ERR05 can't set a variable with the '%s' command",
1182  set_commands[data]);
1183  return MUTT_CMD_WARNING;
1184  }
1185  if (*s->dptr == '+')
1186  increment = true;
1187  else
1188  decrement = true;
1189 
1190  s->dptr++;
1191  if (*s->dptr == '=')
1192  {
1193  equals = true;
1194  s->dptr++;
1195  }
1196  }
1197  else if (*s->dptr == '=')
1198  {
1199  if (prefix)
1200  {
1201  mutt_buffer_printf(err,
1202  "ERR04 can't use prefix when setting a variable");
1203  return MUTT_CMD_WARNING;
1204  }
1205 
1206  if (reset || unset || inv)
1207  {
1208  mutt_buffer_printf(err, "ERR05 can't set a variable with the '%s' command",
1209  set_commands[data]);
1210  return MUTT_CMD_WARNING;
1211  }
1212 
1213  equals = true;
1214  s->dptr++;
1215  }
1216 
1217  if (!bq && (inv || (unset && prefix)))
1218  {
1219  if (data == MUTT_SET_SET)
1220  {
1221  mutt_buffer_printf(err, "ERR06 prefixes 'no' and 'inv' may only be "
1222  "used with bool/quad variables");
1223  }
1224  else
1225  {
1226  mutt_buffer_printf(err, "ERR07 command '%s' can only be used with bool/quad variables",
1227  set_commands[data]);
1228  }
1229  return MUTT_CMD_WARNING;
1230  }
1231 
1232  if (reset)
1233  {
1234  // mutt_buffer_printf(err, "ACT24 reset variable %s", buf->data);
1235  if (he)
1236  {
1237  rc = cs_subset_he_reset(NeoMutt->sub, he, err);
1238  if (CSR_RESULT(rc) != CSR_SUCCESS)
1239  return MUTT_CMD_ERROR;
1240  }
1241  else
1242  {
1243  myvar_del(buf->data);
1244  }
1245  continue;
1246  }
1247 
1248  if ((data == MUTT_SET_SET) && !inv && !unset)
1249  {
1250  if (query)
1251  {
1252  // mutt_buffer_printf(err, "ACT08 query variable %s", buf->data);
1253  if (he)
1254  {
1255  mutt_buffer_addstr(err, buf->data);
1256  mutt_buffer_addch(err, '=');
1257  mutt_buffer_reset(buf);
1258  rc = cs_subset_he_string_get(NeoMutt->sub, he, buf);
1259  if (CSR_RESULT(rc) != CSR_SUCCESS)
1260  {
1261  mutt_buffer_addstr(err, buf->data);
1262  return MUTT_CMD_ERROR;
1263  }
1264  if (DTYPE(he->type) == DT_PATH)
1265  mutt_pretty_mailbox(buf->data, buf->dsize);
1266  pretty_var(buf->data, err);
1267  }
1268  else
1269  {
1270  const char *val = myvar_get(buf->data);
1271  if (val)
1272  {
1273  mutt_buffer_addstr(err, buf->data);
1274  mutt_buffer_addch(err, '=');
1275  pretty_var(val, err);
1276  }
1277  else
1278  {
1279  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
1280  return MUTT_CMD_ERROR;
1281  }
1282  }
1283  break;
1284  }
1285  else if (equals)
1286  {
1287  // mutt_buffer_printf(err, "ACT11 set variable %s to ", buf->data);
1288  const char *name = NULL;
1289  if (my)
1290  {
1291  name = mutt_str_dup(buf->data);
1292  }
1294  if (my)
1295  {
1296  myvar_set(name, buf->data);
1297  FREE(&name);
1298  }
1299  else
1300  {
1301  if (DTYPE(he->type) == DT_PATH)
1302  {
1303  if (he->type & (DT_PATH_DIR | DT_PATH_FILE))
1305  else
1306  mutt_path_tilde(buf->data, buf->dsize, HomeDir);
1307  }
1308  else if (IS_MAILBOX(he))
1309  {
1311  }
1312  else if (IS_COMMAND(he))
1313  {
1314  struct Buffer scratch = mutt_buffer_make(1024);
1315  mutt_buffer_copy(&scratch, buf);
1316 
1317  if (!mutt_str_equal(buf->data, "builtin"))
1318  {
1319  mutt_buffer_expand_path(&scratch);
1320  }
1321  mutt_buffer_reset(buf);
1322  mutt_buffer_addstr(buf, mutt_b2s(&scratch));
1323  mutt_buffer_dealloc(&scratch);
1324  }
1325  if (increment)
1326  {
1327  rc = cs_subset_he_string_plus_equals(NeoMutt->sub, he, buf->data, err);
1328  }
1329  else if (decrement)
1330  {
1331  rc = cs_subset_he_string_minus_equals(NeoMutt->sub, he, buf->data, err);
1332  }
1333  else
1334  {
1335  rc = cs_subset_he_string_set(NeoMutt->sub, he, buf->data, err);
1336  }
1337  if (CSR_RESULT(rc) != CSR_SUCCESS)
1338  return MUTT_CMD_ERROR;
1339  }
1340  continue;
1341  }
1342  else
1343  {
1344  if (bq)
1345  {
1346  // mutt_buffer_printf(err, "ACT23 set variable %s to 'yes'", buf->data);
1347  rc = cs_subset_he_native_set(NeoMutt->sub, he, true, err);
1348  if (CSR_RESULT(rc) != CSR_SUCCESS)
1349  return MUTT_CMD_ERROR;
1350  continue;
1351  }
1352  else
1353  {
1354  // mutt_buffer_printf(err, "ACT10 query variable %s", buf->data);
1355  if (he)
1356  {
1357  mutt_buffer_addstr(err, buf->data);
1358  mutt_buffer_addch(err, '=');
1359  mutt_buffer_reset(buf);
1360  rc = cs_subset_he_string_get(NeoMutt->sub, he, buf);
1361  if (CSR_RESULT(rc) != CSR_SUCCESS)
1362  {
1363  mutt_buffer_addstr(err, buf->data);
1364  return MUTT_CMD_ERROR;
1365  }
1366  if (DTYPE(he->type) == DT_PATH)
1367  mutt_pretty_mailbox(buf->data, buf->dsize);
1368  pretty_var(buf->data, err);
1369  }
1370  else
1371  {
1372  const char *val = myvar_get(buf->data);
1373  if (val)
1374  {
1375  mutt_buffer_addstr(err, buf->data);
1376  mutt_buffer_addch(err, '=');
1377  pretty_var(val, err);
1378  }
1379  else
1380  {
1381  mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
1382  return MUTT_CMD_ERROR;
1383  }
1384  }
1385  break;
1386  }
1387  }
1388  }
1389 
1390  if (my)
1391  {
1392  myvar_del(buf->data);
1393  }
1394  else if (bq)
1395  {
1396  if (inv)
1397  {
1398  // mutt_buffer_printf(err, "ACT25 TOGGLE bool/quad variable %s", buf->data);
1399  if (DTYPE(he->type) == DT_BOOL)
1400  bool_he_toggle(NeoMutt->sub, he, err);
1401  else
1402  quad_he_toggle(NeoMutt->sub, he, err);
1403  }
1404  else
1405  {
1406  // mutt_buffer_printf(err, "ACT26 UNSET bool/quad variable %s", buf->data);
1407  rc = cs_subset_he_native_set(NeoMutt->sub, he, false, err);
1408  if (CSR_RESULT(rc) != CSR_SUCCESS)
1409  return MUTT_CMD_ERROR;
1410  }
1411  continue;
1412  }
1413  else
1414  {
1415  rc = cs_subset_he_string_set(NeoMutt->sub, he, NULL, err);
1416  if (CSR_RESULT(rc) != CSR_SUCCESS)
1417  return MUTT_CMD_ERROR;
1418  }
1419  }
1420 
1421  return MUTT_CMD_SUCCESS;
1422 }
1423 
1427 enum CommandResult parse_setenv(struct Buffer *buf, struct Buffer *s,
1428  intptr_t data, struct Buffer *err)
1429 {
1430  char **envp = mutt_envlist_getlist();
1431 
1432  bool query = false;
1433  bool unset = (data == MUTT_SET_UNSET);
1434 
1435  if (!MoreArgs(s))
1436  {
1437  mutt_buffer_printf(err, _("%s: too few arguments"), "setenv");
1438  return MUTT_CMD_WARNING;
1439  }
1440 
1441  if (*s->dptr == '?')
1442  {
1443  query = true;
1444  s->dptr++;
1445  }
1446 
1447  /* get variable name */
1449 
1450  if (query)
1451  {
1452  bool found = false;
1453  while (envp && *envp)
1454  {
1455  /* This will display all matches for "^QUERY" */
1456  if (mutt_str_startswith(*envp, buf->data))
1457  {
1458  if (!found)
1459  {
1460  mutt_endwin();
1461  found = true;
1462  }
1463  puts(*envp);
1464  }
1465  envp++;
1466  }
1467 
1468  if (found)
1469  {
1471  return MUTT_CMD_SUCCESS;
1472  }
1473 
1474  mutt_buffer_printf(err, _("%s is unset"), buf->data);
1475  return MUTT_CMD_WARNING;
1476  }
1477 
1478  if (unset)
1479  {
1480  if (mutt_envlist_unset(buf->data))
1481  return MUTT_CMD_SUCCESS;
1482  return MUTT_CMD_ERROR;
1483  }
1484 
1485  /* set variable */
1486 
1487  if (*s->dptr == '=')
1488  {
1489  s->dptr++;
1490  SKIPWS(s->dptr);
1491  }
1492 
1493  if (!MoreArgs(s))
1494  {
1495  mutt_buffer_printf(err, _("%s: too few arguments"), "setenv");
1496  return MUTT_CMD_WARNING;
1497  }
1498 
1499  char *name = mutt_str_dup(buf->data);
1501  mutt_envlist_set(name, buf->data, true);
1502  FREE(&name);
1503 
1504  return MUTT_CMD_SUCCESS;
1505 }
1506 
1510 enum CommandResult parse_source(struct Buffer *buf, struct Buffer *s,
1511  intptr_t data, struct Buffer *err)
1512 {
1513  char path[PATH_MAX];
1514 
1515  do
1516  {
1517  if (mutt_extract_token(buf, s, MUTT_TOKEN_NO_FLAGS) != 0)
1518  {
1519  mutt_buffer_printf(err, _("source: error at %s"), s->dptr);
1520  return MUTT_CMD_ERROR;
1521  }
1522  mutt_str_copy(path, buf->data, sizeof(path));
1523  mutt_expand_path(path, sizeof(path));
1524 
1525  if (source_rc(path, err) < 0)
1526  {
1527  mutt_buffer_printf(err, _("source: file %s could not be sourced"), path);
1528  return MUTT_CMD_ERROR;
1529  }
1530 
1531  } while (MoreArgs(s));
1532 
1533  return MUTT_CMD_SUCCESS;
1534 }
1535 
1539 enum CommandResult parse_spam_list(struct Buffer *buf, struct Buffer *s,
1540  intptr_t data, struct Buffer *err)
1541 {
1542  struct Buffer templ;
1543 
1544  mutt_buffer_init(&templ);
1545 
1546  /* Insist on at least one parameter */
1547  if (!MoreArgs(s))
1548  {
1549  if (data == MUTT_SPAM)
1550  mutt_buffer_strcpy(err, _("spam: no matching pattern"));
1551  else
1552  mutt_buffer_strcpy(err, _("nospam: no matching pattern"));
1553  return MUTT_CMD_ERROR;
1554  }
1555 
1556  /* Extract the first token, a regex */
1558 
1559  /* data should be either MUTT_SPAM or MUTT_NOSPAM. MUTT_SPAM is for spam commands. */
1560  if (data == MUTT_SPAM)
1561  {
1562  /* If there's a second parameter, it's a template for the spam tag. */
1563  if (MoreArgs(s))
1564  {
1566 
1567  /* Add to the spam list. */
1568  if (mutt_replacelist_add(&SpamList, buf->data, templ.data, err) != 0)
1569  {
1570  FREE(&templ.data);
1571  return MUTT_CMD_ERROR;
1572  }
1573  FREE(&templ.data);
1574  }
1575  /* If not, try to remove from the nospam list. */
1576  else
1577  {
1579  }
1580 
1581  return MUTT_CMD_SUCCESS;
1582  }
1583  /* MUTT_NOSPAM is for nospam commands. */
1584  else if (data == MUTT_NOSPAM)
1585  {
1586  /* nospam only ever has one parameter. */
1587 
1588  /* "*" is a special case. */
1589  if (mutt_str_equal(buf->data, "*"))
1590  {
1593  return MUTT_CMD_SUCCESS;
1594  }
1595 
1596  /* If it's on the spam list, just remove it. */
1597  if (mutt_replacelist_remove(&SpamList, buf->data) != 0)
1598  return MUTT_CMD_SUCCESS;
1599 
1600  /* Otherwise, add it to the nospam list. */
1601  if (mutt_regexlist_add(&NoSpamList, buf->data, REG_ICASE, err) != 0)
1602  return MUTT_CMD_ERROR;
1603 
1604  return MUTT_CMD_SUCCESS;
1605  }
1606 
1607  /* This should not happen. */
1608  mutt_buffer_strcpy(err, "This is no good at all.");
1609  return MUTT_CMD_ERROR;
1610 }
1611 
1617 enum CommandResult parse_stailq(struct Buffer *buf, struct Buffer *s,
1618  intptr_t data, struct Buffer *err)
1619 {
1620  do
1621  {
1623  add_to_stailq((struct ListHead *) data, buf->data);
1624  } while (MoreArgs(s));
1625 
1626  return MUTT_CMD_SUCCESS;
1627 }
1628 
1632 enum CommandResult parse_subjectrx_list(struct Buffer *buf, struct Buffer *s,
1633  intptr_t data, struct Buffer *err)
1634 {
1635  enum CommandResult rc;
1636 
1637  rc = parse_replace_list(buf, s, &SubjectRegexList, err);
1638  if (rc == MUTT_CMD_SUCCESS)
1640  return rc;
1641 }
1642 
1646 enum CommandResult parse_subscribe(struct Buffer *buf, struct Buffer *s,
1647  intptr_t data, struct Buffer *err)
1648 {
1649  struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
1650 
1651  do
1652  {
1654 
1655  if (parse_grouplist(&gl, buf, s, err) == -1)
1656  goto bail;
1657 
1660 
1661  if (mutt_regexlist_add(&MailLists, buf->data, REG_ICASE, err) != 0)
1662  goto bail;
1663  if (mutt_regexlist_add(&SubscribedLists, buf->data, REG_ICASE, err) != 0)
1664  goto bail;
1665  if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
1666  goto bail;
1667  } while (MoreArgs(s));
1668 
1670  return MUTT_CMD_SUCCESS;
1671 
1672 bail:
1674  return MUTT_CMD_ERROR;
1675 }
1676 
1677 #ifdef USE_IMAP
1678 
1685 enum CommandResult parse_subscribe_to(struct Buffer *buf, struct Buffer *s,
1686  intptr_t data, struct Buffer *err)
1687 {
1688  if (!buf || !s || !err)
1689  return MUTT_CMD_ERROR;
1690 
1691  mutt_buffer_reset(err);
1692 
1693  if (MoreArgs(s))
1694  {
1696 
1697  if (MoreArgs(s))
1698  {
1699  mutt_buffer_printf(err, _("%s: too many arguments"), "subscribe-to");
1700  return MUTT_CMD_WARNING;
1701  }
1702 
1703  if (buf->data && (*buf->data != '\0'))
1704  {
1705  /* Expand and subscribe */
1706  if (imap_subscribe(mutt_expand_path(buf->data, buf->dsize), true) == 0)
1707  {
1708  mutt_message(_("Subscribed to %s"), buf->data);
1709  return MUTT_CMD_SUCCESS;
1710  }
1711 
1712  mutt_buffer_printf(err, _("Could not subscribe to %s"), buf->data);
1713  return MUTT_CMD_ERROR;
1714  }
1715 
1716  mutt_debug(LL_DEBUG1, "Corrupted buffer");
1717  return MUTT_CMD_ERROR;
1718  }
1719 
1720  mutt_buffer_addstr(err, _("No folder specified"));
1721  return MUTT_CMD_WARNING;
1722 }
1723 #endif
1724 
1728 enum CommandResult parse_tag_formats(struct Buffer *buf, struct Buffer *s,
1729  intptr_t data, struct Buffer *err)
1730 {
1731  if (!buf || !s)
1732  return MUTT_CMD_ERROR;
1733 
1734  char *tmp = NULL;
1735 
1736  while (MoreArgs(s))
1737  {
1738  char *tag = NULL, *format = NULL;
1739 
1741  if (buf->data && (*buf->data != '\0'))
1742  tag = mutt_str_dup(buf->data);
1743  else
1744  continue;
1745 
1747  format = mutt_str_dup(buf->data);
1748 
1749  /* avoid duplicates */
1750  tmp = mutt_hash_find(TagFormats, format);
1751  if (tmp)
1752  {
1753  mutt_debug(LL_DEBUG3, "tag format '%s' already registered as '%s'\n", format, tmp);
1754  FREE(&tag);
1755  FREE(&format);
1756  continue;
1757  }
1758 
1759  mutt_hash_insert(TagFormats, format, tag);
1760  }
1761  return MUTT_CMD_SUCCESS;
1762 }
1763 
1767 enum CommandResult parse_tag_transforms(struct Buffer *buf, struct Buffer *s,
1768  intptr_t data, struct Buffer *err)
1769 {
1770  if (!buf || !s)
1771  return MUTT_CMD_ERROR;
1772 
1773  char *tmp = NULL;
1774 
1775  while (MoreArgs(s))
1776  {
1777  char *tag = NULL, *transform = NULL;
1778 
1780  if (buf->data && (*buf->data != '\0'))
1781  tag = mutt_str_dup(buf->data);
1782  else
1783  continue;
1784 
1786  transform = mutt_str_dup(buf->data);
1787 
1788  /* avoid duplicates */
1789  tmp = mutt_hash_find(TagTransforms, tag);
1790  if (tmp)
1791  {
1792  mutt_debug(LL_DEBUG3, "tag transform '%s' already registered as '%s'\n", tag, tmp);
1793  FREE(&tag);
1794  FREE(&transform);
1795  continue;
1796  }
1797 
1798  mutt_hash_insert(TagTransforms, tag, transform);
1799  }
1800  return MUTT_CMD_SUCCESS;
1801 }
1802 
1806 enum CommandResult parse_unalternates(struct Buffer *buf, struct Buffer *s,
1807  intptr_t data, struct Buffer *err)
1808 {
1809  alternates_clean();
1810  do
1811  {
1813  mutt_regexlist_remove(&Alternates, buf->data);
1814 
1815  if (!mutt_str_equal(buf->data, "*") &&
1816  (mutt_regexlist_add(&UnAlternates, buf->data, REG_ICASE, err) != 0))
1817  {
1818  return MUTT_CMD_ERROR;
1819  }
1820 
1821  } while (MoreArgs(s));
1822 
1823  return MUTT_CMD_SUCCESS;
1824 }
1825 
1829 enum CommandResult parse_unattachments(struct Buffer *buf, struct Buffer *s,
1830  intptr_t data, struct Buffer *err)
1831 {
1832  char op;
1833  char *p = NULL;
1834  struct ListHead *head = NULL;
1835 
1837  if (!buf->data || (*buf->data == '\0'))
1838  {
1839  mutt_buffer_strcpy(err, _("unattachments: no disposition"));
1840  return MUTT_CMD_WARNING;
1841  }
1842 
1843  p = buf->data;
1844  op = *p++;
1845 
1846  if (op == '*')
1847  {
1849  mutt_list_free_type(&AttachExclude, (list_free_t) mutt_attachmatch_free);
1850  mutt_list_free_type(&InlineAllow, (list_free_t) mutt_attachmatch_free);
1851  mutt_list_free_type(&InlineExclude, (list_free_t) mutt_attachmatch_free);
1853  return 0;
1854  }
1855 
1856  if ((op != '+') && (op != '-'))
1857  {
1858  op = '+';
1859  p--;
1860  }
1861  if (mutt_istr_startswith("attachment", p))
1862  {
1863  if (op == '+')
1864  head = &AttachAllow;
1865  else
1866  head = &AttachExclude;
1867  }
1868  else if (mutt_istr_startswith("inline", p))
1869  {
1870  if (op == '+')
1871  head = &InlineAllow;
1872  else
1873  head = &InlineExclude;
1874  }
1875  else
1876  {
1877  mutt_buffer_strcpy(err, _("unattachments: invalid disposition"));
1878  return MUTT_CMD_ERROR;
1879  }
1880 
1881  return parse_unattach_list(buf, s, head, err);
1882 }
1883 
1887 enum CommandResult parse_unignore(struct Buffer *buf, struct Buffer *s,
1888  intptr_t data, struct Buffer *err)
1889 {
1890  do
1891  {
1893 
1894  /* don't add "*" to the unignore list */
1895  if (strcmp(buf->data, "*") != 0)
1896  add_to_stailq(&UnIgnore, buf->data);
1897 
1898  remove_from_stailq(&Ignore, buf->data);
1899  } while (MoreArgs(s));
1900 
1901  return MUTT_CMD_SUCCESS;
1902 }
1903 
1907 enum CommandResult parse_unlists(struct Buffer *buf, struct Buffer *s,
1908  intptr_t data, struct Buffer *err)
1909 {
1911  do
1912  {
1916 
1917  if (!mutt_str_equal(buf->data, "*") &&
1918  (mutt_regexlist_add(&UnMailLists, buf->data, REG_ICASE, err) != 0))
1919  {
1920  return MUTT_CMD_ERROR;
1921  }
1922  } while (MoreArgs(s));
1923 
1924  return MUTT_CMD_SUCCESS;
1925 }
1926 
1932 enum CommandResult parse_unmailboxes(struct Buffer *buf, struct Buffer *s,
1933  intptr_t data, struct Buffer *err)
1934 {
1935  bool tmp_valid = false;
1936  bool clear_all = false;
1937 
1938  while (!clear_all && MoreArgs(s))
1939  {
1941 
1942  if (mutt_str_equal(buf->data, "*"))
1943  {
1944  clear_all = true;
1945  tmp_valid = false;
1946  }
1947  else
1948  {
1950  tmp_valid = true;
1951  }
1952 
1953  struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
1955  struct MailboxNode *np = NULL;
1956  struct MailboxNode *nptmp = NULL;
1957  STAILQ_FOREACH_SAFE(np, &ml, entries, nptmp)
1958  {
1959  /* Compare against path or desc? Ensure 'buf' is valid */
1960  if (!clear_all && tmp_valid &&
1962  !mutt_istr_equal(mutt_b2s(buf), np->mailbox->name))
1963  {
1964  continue;
1965  }
1966 
1967 #ifdef USE_SIDEBAR
1968  struct MuttWindow *dlg = TAILQ_LAST(&AllDialogsWindow->children, MuttWindowList);
1969  struct MuttWindow *win_sidebar = mutt_window_find(dlg, WT_SIDEBAR);
1970  if (win_sidebar)
1971  sb_notify_mailbox(win_sidebar, np->mailbox, SBN_DELETED);
1972 #endif
1973 #ifdef USE_INOTIFY
1975 #endif
1976  if (Context && (Context->mailbox == np->mailbox))
1977  {
1978  np->mailbox->flags |= MB_HIDDEN;
1979  }
1980  else
1981  {
1983  mailbox_free(&np->mailbox);
1984  }
1985  }
1987  }
1988  return MUTT_CMD_SUCCESS;
1989 }
1990 
1994 enum CommandResult parse_unmy_hdr(struct Buffer *buf, struct Buffer *s,
1995  intptr_t data, struct Buffer *err)
1996 {
1997  struct ListNode *np = NULL, *tmp = NULL;
1998  size_t l;
1999 
2000  do
2001  {
2003  if (mutt_str_equal("*", buf->data))
2004  {
2005  mutt_list_free(&UserHeader);
2006  continue;
2007  }
2008 
2009  l = mutt_str_len(buf->data);
2010  if (buf->data[l - 1] == ':')
2011  l--;
2012 
2013  STAILQ_FOREACH_SAFE(np, &UserHeader, entries, tmp)
2014  {
2015  if (mutt_istrn_equal(buf->data, np->data, l) && (np->data[l] == ':'))
2016  {
2017  STAILQ_REMOVE(&UserHeader, np, ListNode, entries);
2018  FREE(&np->data);
2019  FREE(&np);
2020  }
2021  }
2022  } while (MoreArgs(s));
2023  return MUTT_CMD_SUCCESS;
2024 }
2025 
2031 enum CommandResult parse_unstailq(struct Buffer *buf, struct Buffer *s,
2032  intptr_t data, struct Buffer *err)
2033 {
2034  do
2035  {
2037  /* Check for deletion of entire list */
2038  if (mutt_str_equal(buf->data, "*"))
2039  {
2040  mutt_list_free((struct ListHead *) data);
2041  break;
2042  }
2043  remove_from_stailq((struct ListHead *) data, buf->data);
2044  } while (MoreArgs(s));
2045 
2046  return MUTT_CMD_SUCCESS;
2047 }
2048 
2053  intptr_t data, struct Buffer *err)
2054 {
2055  enum CommandResult rc;
2056 
2057  rc = parse_unreplace_list(buf, s, &SubjectRegexList, err);
2058  if (rc == MUTT_CMD_SUCCESS)
2060  return rc;
2061 }
2062 
2066 enum CommandResult parse_unsubscribe(struct Buffer *buf, struct Buffer *s,
2067  intptr_t data, struct Buffer *err)
2068 {
2070  do
2071  {
2074 
2075  if (!mutt_str_equal(buf->data, "*") &&
2076  (mutt_regexlist_add(&UnSubscribedLists, buf->data, REG_ICASE, err) != 0))
2077  {
2078  return MUTT_CMD_ERROR;
2079  }
2080  } while (MoreArgs(s));
2081 
2082  return MUTT_CMD_SUCCESS;
2083 }
2084 
2085 #ifdef USE_IMAP
2086 
2094  intptr_t data, struct Buffer *err)
2095 {
2096  if (!buf || !s || !err)
2097  return MUTT_CMD_ERROR;
2098 
2099  if (MoreArgs(s))
2100  {
2102 
2103  if (MoreArgs(s))
2104  {
2105  mutt_buffer_printf(err, _("%s: too many arguments"), "unsubscribe-from");
2106  return MUTT_CMD_WARNING;
2107  }
2108 
2109  if (buf->data && (*buf->data != '\0'))
2110  {
2111  /* Expand and subscribe */
2112  if (imap_subscribe(mutt_expand_path(buf->data, buf->dsize), false) == 0)
2113  {
2114  mutt_message(_("Unsubscribed from %s"), buf->data);
2115  return MUTT_CMD_SUCCESS;
2116  }
2117 
2118  mutt_buffer_printf(err, _("Could not unsubscribe from %s"), buf->data);
2119  return MUTT_CMD_ERROR;
2120  }
2121 
2122  mutt_debug(LL_DEBUG1, "Corrupted buffer");
2123  return MUTT_CMD_ERROR;
2124  }
2125 
2126  mutt_buffer_addstr(err, _("No folder specified"));
2127  return MUTT_CMD_WARNING;
2128 }
2129 #endif
2130 
2135 {
2137 }
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:876
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:37
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:201
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
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
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:754
#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:33
bool feature_enabled(const char *name)
Test if a compile-time feature is enabled.
Definition: version.c:565
#define CSR_RESULT(x)
Definition: set.h:52
struct HashElem ** get_elem_list(struct ConfigSet *cs)
Create a sorted list of all config items.
Definition: subset.c:64
Config/command parsing.
Error: Can&#39;t help the user.
Definition: mutt_commands.h:35
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:1784
int mx_path_canon2(struct Mailbox *m, const char *folder)
Canonicalise the path to realpath.
Definition: mx.c:1501
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.
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()
#define MUTT_NOSPAM
Definition: mutt.h:115
#define TAILQ_LAST(head, headname)
Definition: queue.h:812
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:70
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition: hash.c:447
#define mutt_message(...)
Definition: logging.h:83
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
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
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()
struct MuttWindow * mutt_window_find(struct MuttWindow *root, enum WindowType type)
Find a Window of a given type.
Definition: mutt_window.c:688
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
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
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
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:1041
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
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
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:73
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:1608
static bool is_function(const char *name)
Is the argument a neomutt function?
A division of the screen.
Definition: mutt_window.h:115
#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
void cs_subset_free(struct ConfigSubset **ptr)
Free a Config Subset.
Definition: subset.c:93
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
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:1584
#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
const struct Command * mutt_command_get(const char *s)
Get a Command by its name.
Definition: init.c:383
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()
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
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
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:996
Email Address Handling.
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:626
default is to reset all vars to default
Definition: mutt_commands.h:69
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()
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
struct Envelope * env
Envelope information.
Definition: email.h:90
Convenience wrapper for the core headers.
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
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
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:120
#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:77
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
struct Account * account_new(const char *name, struct ConfigSubset *sub)
Create a new Account.
Definition: account.c:43
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 CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
#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:888
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
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 MUTT_TOKEN_QUOTE
Don&#39;t interpret quotes.
Definition: mutt.h:74
Side panel containing Accounts or groups of data.
Definition: mutt_window.h:99
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:81
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:165
#define DT_PATH
a path to a file/directory
Definition: types.h:36
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:570
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:414
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:89
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:97
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.
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:79
bool mutt_path_to_absolute(char *path, const char *reference)
Convert relative filepath to an absolute path.
Definition: path.c:397
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
#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:986
default is to unset all vars
Definition: mutt_commands.h:68
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:522
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
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
struct MuttWindow * AllDialogsWindow
Parent of all Dialogs.
Definition: mutt_window.c:46
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:603
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition: dump.c:83
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:636
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:87
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:37
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:1297
Log at debug level 1.
Definition: logging.h:40
Warning: Help given to the user.
Definition: mutt_commands.h:36
int n
Definition: acutest.h:492
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()
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:721
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:38
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
int bool_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a bool.
Definition: bool.c:205
#define MAX_ERRS
Definition: command_parse.c:72
bool account_mailbox_remove(struct Account *a, struct Mailbox *m)
Remove a Mailbox from an Account.
Definition: account.c:94
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:1265
#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
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()
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:70
#define STAILQ_EMPTY(head)
Definition: queue.h:345
struct MuttWindowList children
Children Windows.
Definition: mutt_window.h:129
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
bool recip_valid
Is_recipient is valid.
Definition: email.h:58
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:53
int quad_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a quad.
Definition: quad.c:222
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:66
#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:80
int const char int line
Definition: acutest.h:617
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
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
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()
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
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
Mapping between a user key and a function.
Definition: keymap.h:118
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:67
#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:1231
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