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