2 * Copyright notice from original mutt:
3 * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org>
5 * Parts were written/modified by:
6 * Rocco Rutte <pdmef@cs.tu-berlin.de>
8 * This file is part of mutt-ng, see http://www.muttng.org/.
9 * It's licensed under the GNU General Public License,
10 * please see the file GPL in the top level source directory.
13 #include <lib-lib/lib-lib.h>
15 #include <lib-lua/lib-lua.h>
16 #include <lib-sys/unix.h>
17 #include <lib-sys/mutt_ssl.h>
18 #include <lib-ui/curses.h>
19 #include <lib-ui/history.h>
20 #include <lib-mx/mx.h>
21 #include <lib-crypt/crypt.h>
27 #include "mutt_idna.h"
29 #if defined (USE_LIBESMTP) && (defined (USE_SSL) || defined (USE_GNUTLS))
30 #include "mutt_libesmtp.h"
39 static const struct mapping_t* get_sortmap (struct option_t* option);
40 static int parse_sort (struct option_t* dst, const char *s,
41 const struct mapping_t *map,
42 char* errbuf, ssize_t errlen);
44 static hash_t *ConfigOptions = NULL;
46 /* for synonym warning reports: synonym found during parsing */
47 typedef struct syn_t {
51 struct option_t* n; /* new */
52 struct option_t* o; /* old */
56 static void syn_wipe(syn_t *syn) {
60 DO_DELETE(syn_t, syn);
61 DO_SLIST(syn_t, syn, syn_delete);
63 /* for synonym warning reports: list of synonyms found */
64 static syn_t *Synonyms = NULL;
65 /* for synonym warning reports: current rc file */
66 static const char* CurRCFile = NULL;
67 /* for synonym warning reports: current rc line */
68 static int CurRCLine = 0;
70 /* prototypes for checking for special vars */
71 static int check_history (const char* option, unsigned long val,
72 char* errbuf, ssize_t errlen);
73 /* this checks that numbers are >= 0 */
74 static int check_num (const char* option, unsigned long val,
75 char* errbuf, ssize_t errlen);
77 /* use this to check only */
78 static int check_special (const char* option, unsigned long val,
79 char* errbuf, ssize_t errlen);
81 /* variable <-> sanity check function mappings
82 * when changing these, make sure the proper _from_string handler
87 int (*check) (const char* option, unsigned long val,
88 char* errbuf, ssize_t errlen);
90 #if defined (USE_LIBESMTP) && (defined (USE_SSL) || defined (USE_GNUTLS))
91 { "smtp_use_tls", mutt_libesmtp_check_usetls },
93 { "history", check_history },
94 { "pager_index_lines", check_num },
99 static void bool_to_string (char* dst, ssize_t dstlen,
100 struct option_t* option) {
101 snprintf (dst, dstlen, "%s=%s", option->option,
102 option (option->data) ? "yes" : "no");
105 static int bool_from_string (struct option_t* dst, const char* val,
106 char* errbuf __attribute__ ((unused)),
107 ssize_t errlen __attribute__ ((unused))) {
112 if (ascii_strncasecmp (val, "yes", 3) == 0)
114 else if (ascii_strncasecmp (val, "no", 2) == 0)
120 set_option (dst->data);
122 unset_option (dst->data);
126 static void num_to_string (char* dst, ssize_t dstlen,
127 struct option_t* option) {
129 const char* fmt = (m_strcmp(option->option, "umask") == 0) ?
131 snprintf (dst, dstlen, fmt, option->option,
132 *((short*) option->data));
135 static int num_from_string (struct option_t* dst, const char* val,
136 char* errbuf, ssize_t errlen) {
137 int num = 0, old = 0;
143 num = strtol (val, &t, 0);
145 if (m_strisempty(val) || *t || (short) num != num) {
147 snprintf (errbuf, errlen, _("'%s' is invalid for $%s"),
153 /* just temporarily accept new val so that check_special for
154 * $history already has it when doing history's init() */
155 old = *((short*) dst->data);
156 *((short*) dst->data) = (short) num;
158 if (!check_special (dst->option, (unsigned long) num, errbuf, errlen)) {
159 *((short*) dst->data) = old;
166 static void str_to_string (char* dst, ssize_t dstlen,
167 struct option_t* option) {
168 snprintf (dst, dstlen, "%s=\"%s\"", option->option,
169 NONULL (*((char**) option->data)));
172 static int path_from_string (struct option_t* dst, const char* val,
173 char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
174 char path[_POSIX_PATH_MAX];
179 if (m_strisempty(val)) {
180 p_delete((char**) dst->data);
185 m_strcpy(path, sizeof(path), val);
186 mutt_expand_path (path, sizeof(path));
187 m_strreplace((char **) dst->data, path);
191 static int str_from_string (struct option_t* dst, const char* val,
192 char* errbuf, ssize_t errlen) {
196 if (!check_special (dst->option, (unsigned long) val, errbuf, errlen))
199 m_strreplace((char**) dst->data, val);
203 static void quad_to_string (char* dst, ssize_t dstlen,
204 struct option_t* option) {
205 const char *vals[] = { "no", "yes", "ask-no", "ask-yes" };
206 snprintf (dst, dstlen, "%s=%s", option->option,
207 vals[quadoption (option->data)]);
210 static int quad_from_string (struct option_t* dst, const char* val,
211 char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
216 if (ascii_strncasecmp (val, "yes", 3) == 0)
218 else if (ascii_strncasecmp (val, "no", 2) == 0)
220 else if (ascii_strncasecmp (val, "ask-yes", 7) == 0)
222 else if (ascii_strncasecmp (val, "ask-no", 6) == 0)
228 set_quadoption (dst->data, flag);
232 static void sort_to_string (char* dst, ssize_t dstlen,
233 struct option_t* option) {
234 const struct mapping_t *map = get_sortmap (option);
235 const char *p = NULL;
238 snprintf (dst, sizeof(dst), "%s=unknown", option->option);
242 p = mutt_getnamebyvalue(*((short *)option->data) & SORT_MASK, map);
244 snprintf (dst, dstlen, "%s=%s%s%s", option->option,
245 (*((short *) option->data) & SORT_REVERSE) ?
247 (*((short *) option->data) & SORT_LAST) ? "last-" :
251 static int sort_from_string (struct option_t* dst, const char* val,
252 char* errbuf, ssize_t errlen) {
253 const struct mapping_t *map = NULL;
254 if (!(map = get_sortmap (dst))) {
256 snprintf (errbuf, errlen, _("%s: Unknown type."),
260 if (parse_sort (dst, val, map, errbuf, errlen) == -1)
265 static void rx_to_string (char* dst, ssize_t dstlen,
266 struct option_t* option) {
267 rx_t* p = (rx_t*) option->data;
268 snprintf (dst, dstlen, "%s=\"%s\"", option->option,
269 NONULL (p->pattern));
272 static int rx_from_string (struct option_t* dst, const char* val,
273 char* errbuf, ssize_t errlen) {
276 int flags = 0, e = 0, neg = 0;
282 if (option (OPTATTACHMSG) && !m_strcmp(dst->option, "reply_regexp")) {
284 snprintf (errbuf, errlen,
285 "Operation not permitted when in attach-message mode.");
289 if (!((rx_t*) dst->data))
290 *((rx_t**) dst->data) = p_new(rx_t, 1);
292 p = (rx_t*) dst->data;
294 /* something to do? */
295 if (m_strisempty(val) || (p->pattern && m_strcmp(p->pattern, val) == 0))
298 if (m_strcmp(dst->option, "mask") != 0)
299 flags |= mutt_which_case (val);
302 if (m_strcmp(dst->option, "mask") == 0 && *s == '!') {
307 rx = p_new(regex_t, 1);
309 if ((e = REGCOMP (rx, s, flags)) != 0) {
310 regerror (e, rx, errbuf, errlen);
321 m_strreplace(&p->pattern, val);
325 if (m_strcmp(dst->option, "reply_regexp") == 0)
326 mutt_adjust_all_subjects ();
331 static void magic_to_string (char* dst, ssize_t dstlen,
332 struct option_t* option) {
333 const char* s = NULL;
334 switch (option->data) {
335 case M_MBOX: s = "mbox"; break;
336 case M_MMDF: s = "MMDF"; break;
337 case M_MH: s = "MH"; break;
338 case M_MAILDIR: s = "Maildir"; break;
339 default: s = "unknown"; break;
341 snprintf (dst, dstlen, "%s=%s", option->option, s);
344 static int magic_from_string (struct option_t* dst, const char* val,
345 char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
348 if (!dst || m_strisempty(val))
350 if (ascii_strncasecmp (val, "mbox", 4) == 0)
352 else if (ascii_strncasecmp (val, "mmdf", 4) == 0)
354 else if (ascii_strncasecmp (val, "mh", 2) == 0)
356 else if (ascii_strncasecmp (val, "maildir", 7) == 0)
362 *((short*) dst->data) = flag;
367 static void addr_to_string (char* dst, ssize_t dstlen,
368 struct option_t* option) {
371 rfc822_addrcat(s, sizeof(s), *((address_t**) option->data), 0);
372 snprintf (dst, dstlen, "%s=\"%s\"", option->option, NONULL (s));
375 static int addr_from_string (struct option_t* dst, const char* val,
376 char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
379 address_list_wipe((address_t**) dst->data);
381 *((address_t**) dst->data) = rfc822_parse_adrlist (NULL, val);
387 void (*opt_tostr) (char* dst, ssize_t dstlen, struct option_t* option);
388 int (*opt_fromstr) (struct option_t* dst, const char* val,
389 char* errbuf, ssize_t errlen);
391 { 0, NULL, NULL }, /* there's no DT_ type with 0 */
392 { DT_BOOL, bool_to_string, bool_from_string },
393 { DT_NUM, num_to_string, num_from_string },
394 { DT_STR, str_to_string, str_from_string },
395 { DT_PATH, str_to_string, path_from_string },
396 { DT_QUAD, quad_to_string, quad_from_string },
397 { DT_SORT, sort_to_string, sort_from_string },
398 { DT_RX, rx_to_string, rx_from_string },
399 { DT_MAGIC, magic_to_string, magic_from_string },
400 /* synonyms should be resolved already so we don't need this
401 * but must define it as DT_ is used for indexing */
402 { DT_SYN, NULL, NULL },
403 { DT_ADDR, addr_to_string, addr_from_string },
407 int mutt_option_value (const char* val, char* dst, ssize_t dstlen) {
408 struct option_t* option = NULL;
409 char* tmp = NULL, *t = NULL;
412 if (!(option = hash_find (ConfigOptions, val))) {
416 tmp = p_new(char, dstlen+1);
417 FuncTable[DTYPE(option->type)].opt_tostr (tmp, dstlen, option);
419 /* as we get things of type $var=value and don't want to bloat the
420 * above "just" for expansion, we do the stripping here */
421 t = strchr (tmp, '=');
425 if (t[l-1] == '"' && *t == '"') {
430 memcpy (dst, t, l+1);
436 static void toggle_quadoption (int opt)
439 int b = (opt % 4) * 2;
441 QuadOptions[n] ^= (1 << b);
444 void set_quadoption (int opt, int flag)
447 int b = (opt % 4) * 2;
449 QuadOptions[n] &= ~(0x3 << b);
450 QuadOptions[n] |= (flag & 0x3) << b;
453 int quadoption (int opt)
456 int b = (opt % 4) * 2;
458 return (QuadOptions[n] >> b) & 0x3;
461 int query_quadoption2(int v, const char *prompt)
469 v = mutt_yesorno(prompt, (v == M_ASKYES));
470 CLEARLINE (LINES - 1);
475 int query_quadoption (int opt, const char *prompt)
477 int v = quadoption (opt);
485 v = mutt_yesorno (prompt, (v == M_ASKYES));
486 CLEARLINE (LINES - 1);
493 /* always wise to do what someone else did before */
494 static void _attachments_clean (void) {
496 if (Context && Context->msgcount) {
497 for (i = 0; i < Context->msgcount; i++)
498 Context->hdrs[i]->attach_valid = 0;
502 static int parse_attach_list (BUFFER *buf, BUFFER *s, string_list_t **ldata,
503 BUFFER *err __attribute__ ((unused))) {
505 string_list_t *listp, *lastp;
510 /* Find the last item in the list that data points to. */
512 for (listp = *ldata; listp; listp = listp->next) {
513 a = (ATTACH_MATCH *)listp->data;
518 mutt_extract_token (buf, s, 0);
520 if (!buf->data || *buf->data == '\0')
523 a = p_new(ATTACH_MATCH, 1);
525 /* some cheap hacks that I expect to remove */
526 if (!m_strcasecmp(buf->data, "any"))
527 a->major = m_strdup("*/.*");
528 else if (!m_strcasecmp(buf->data, "none"))
529 a->major = m_strdup("cheap_hack/this_should_never_match");
531 a->major = m_strdup(buf->data);
533 if ((p = strchr(a->major, '/'))) {
538 a->minor = "unknown";
541 len = m_strlen(a->minor);
542 tmpminor = p_new(char, len + 3);
543 m_strcpy(&tmpminor[1], len + 3, a->minor);
545 tmpminor[len+1] = '$';
546 tmpminor[len+2] = '\0';
548 a->major_int = mutt_check_mime_type(a->major);
549 regcomp(&a->minor_rx, tmpminor, REG_ICASE|REG_EXTENDED);
553 listp = p_new(string_list_t, 1);
554 listp->data = (char *)a;
563 while (MoreArgs (s));
565 _attachments_clean();
569 static int parse_unattach_list (BUFFER *buf, BUFFER *s, string_list_t **ldata,
570 BUFFER *err __attribute__ ((unused))) {
572 string_list_t *lp, *lastp, *newlp;
578 mutt_extract_token (buf, s, 0);
580 if (!m_strcasecmp(buf->data, "any"))
581 tmp = m_strdup("*/.*");
582 else if (!m_strcasecmp(buf->data, "none"))
583 tmp = m_strdup("cheap_hack/this_should_never_match");
585 tmp = m_strdup(buf->data);
587 if ((minor = strchr(tmp, '/'))) {
591 minor = m_strdup("unknown");
593 major = mutt_check_mime_type(tmp);
595 /* We must do our own walk here because string_list_remove() will only
596 * remove the string_list_t->data, not anything pointed to by the string_list_t->data. */
598 for(lp = *ldata; lp; ) {
599 a = (ATTACH_MATCH *)lp->data;
600 if (a->major_int == major && !m_strcasecmp(minor, a->minor)) {
601 regfree(&a->minor_rx);
604 /* Relink backward */
606 lastp->next = lp->next;
611 p_delete(&lp->data); /* same as a */
621 while (MoreArgs (s));
624 _attachments_clean();
628 static int print_attach_list (string_list_t *lp, char op, const char *name) {
630 printf("attachments %c%s %s/%s\n", op, name,
631 ((ATTACH_MATCH *)lp->data)->major,
632 ((ATTACH_MATCH *)lp->data)->minor);
639 static int parse_attachments (BUFFER *buf, BUFFER *s,
640 unsigned long data __attribute__ ((unused)),
643 string_list_t **listp;
645 mutt_extract_token(buf, s, 0);
646 if (!buf->data || *buf->data == '\0') {
647 m_strcpy(err->data, err->dsize, _("attachments: no disposition"));
651 category = buf->data;
657 printf("\nCurrent attachments settings:\n\n");
658 print_attach_list(AttachAllow, '+', "A");
659 print_attach_list(AttachExclude, '-', "A");
660 print_attach_list(InlineAllow, '+', "I");
661 print_attach_list(InlineExclude, '-', "I");
662 set_option (OPTFORCEREDRAWINDEX);
663 set_option (OPTFORCEREDRAWPAGER);
664 mutt_any_key_to_continue (NULL);
668 if (op != '+' && op != '-') {
672 if (!m_strncasecmp(category, "attachment", strlen(category))) {
674 listp = &AttachAllow;
676 listp = &AttachExclude;
678 else if (!m_strncasecmp(category, "inline", strlen(category))) {
680 listp = &InlineAllow;
682 listp = &InlineExclude;
684 m_strcpy(err->data, err->dsize, _("attachments: invalid disposition"));
688 return parse_attach_list(buf, s, listp, err);
691 static int parse_unattachments (BUFFER *buf, BUFFER *s, unsigned long data __attribute__ ((unused)), BUFFER *err) {
693 string_list_t **listp;
695 mutt_extract_token(buf, s, 0);
696 if (!buf->data || *buf->data == '\0') {
697 m_strcpy(err->data, err->dsize, _("unattachments: no disposition"));
703 if (op != '+' && op != '-') {
707 if (!m_strncasecmp(p, "attachment", strlen(p))) {
709 listp = &AttachAllow;
711 listp = &AttachExclude;
713 else if (!m_strncasecmp(p, "inline", strlen(p))) {
715 listp = &InlineAllow;
717 listp = &InlineExclude;
720 m_strcpy(err->data, err->dsize, _("unattachments: invalid disposition"));
724 return parse_unattach_list(buf, s, listp, err);
727 static int parse_unalias (BUFFER * buf, BUFFER * s,
728 unsigned long data __attribute__ ((unused)),
729 BUFFER * err __attribute__ ((unused)))
731 alias_t *tmp, **last;
734 mutt_extract_token (buf, s, 0);
736 if (!m_strcmp("*", buf->data) == 0) {
737 if (CurrentMenu == MENU_ALIAS) {
738 for (tmp = Aliases; tmp; tmp = tmp->next)
740 set_option(OPTFORCEREDRAWINDEX);
742 alias_list_wipe(&Aliases);
748 for (last = &Aliases; *last; last = &(*last)->next) {
749 if (!m_strcasecmp(buf->data, (*last)->name)) {
750 if (CurrentMenu == MENU_ALIAS) {
752 set_option (OPTFORCEREDRAWINDEX);
754 tmp = alias_list_pop(last);
760 } while (MoreArgs(s));
765 static int parse_alias (BUFFER * buf, BUFFER * s,
766 unsigned long data __attribute__ ((unused)),
773 m_strcpy(err->data, err->dsize, _("alias: no address"));
777 mutt_extract_token (buf, s, 0);
779 /* check to see if an alias with this name already exists */
780 for (last = &Aliases; *last; last = &(*last)->next) {
781 if (!m_strcasecmp((*last)->name, buf->data))
786 /* create a new alias */
788 (*last)->name = m_strdup(buf->data);
789 /* give the main addressbook code a chance */
790 if (CurrentMenu == MENU_ALIAS)
791 set_option (OPTMENUCALLER);
793 /* override the previous value */
794 address_list_wipe(&(*last)->addr);
795 if (CurrentMenu == MENU_ALIAS)
796 set_option (OPTFORCEREDRAWINDEX);
799 mutt_extract_token(buf, s, M_TOKEN_QUOTE | M_TOKEN_SPACE);
800 (*last)->addr = mutt_parse_adrlist((*last)->addr, buf->data);
801 if (mutt_addrlist_to_idna((*last)->addr, &estr)) {
802 snprintf (err->data, err->dsize,
803 _("Warning: Bad IDN '%s' in alias '%s'.\n"), estr, (*last)->name);
812 parse_unmy_hdr(BUFFER * buf, BUFFER * s,
813 unsigned long data __attribute__ ((unused)),
814 BUFFER * err __attribute__ ((unused)))
817 mutt_extract_token (buf, s, 0);
819 if (!m_strcmp("*", buf->data)) {
820 string_list_wipe(&UserHeader);
822 string_list_t **last = &UserHeader;
823 ssize_t l = m_strlen(buf->data);
825 if (buf->data[l - 1] == ':')
829 if (!ascii_strncasecmp(buf->data, (*last)->data, l)
830 && (*last)->data[l] == ':')
832 string_list_t *tmp = string_list_pop(last);
833 string_item_delete(&tmp);
835 last = &(*last)->next;
839 } while (MoreArgs(s));
844 static int parse_my_hdr (BUFFER * buf, BUFFER * s, unsigned long data __attribute__ ((unused)),
851 mutt_extract_token (buf, s, M_TOKEN_SPACE | M_TOKEN_QUOTE);
852 if ((p = strpbrk (buf->data, ": \t")) == NULL || *p != ':') {
853 m_strcpy(err->data, err->dsize, _("invalid header field"));
856 keylen = p - buf->data + 1;
859 for (tmp = UserHeader;; tmp = tmp->next) {
860 /* see if there is already a field by this name */
861 if (ascii_strncasecmp (buf->data, tmp->data, keylen) == 0) {
862 /* replace the old value */
863 p_delete(&tmp->data);
864 tmp->data = buf->data;
871 tmp->next = string_item_new();
875 tmp = string_item_new();
878 tmp->data = buf->data;
884 parse_sort (struct option_t* dst, const char *s, const struct mapping_t *map,
885 char* errbuf, ssize_t errlen) {
888 if (m_strncmp("reverse-", s, 8) == 0) {
890 flags = SORT_REVERSE;
893 if (m_strncmp("last-", s, 5) == 0) {
898 if ((i = mutt_getvaluebyname (s, map)) == -1) {
900 snprintf (errbuf, errlen, _("'%s' is invalid for $%s"), s, dst->option);
904 *((short*) dst->data) = i | flags;
908 /* if additional data more == 1, we want to resolve synonyms */
909 static void mutt_set_default(const char *name __attribute__ ((unused)), void* p, unsigned long more)
911 char buf[LONG_STRING];
912 struct option_t *ptr = p;
914 if (DTYPE(ptr->type) == DT_SYN) {
917 ptr = hash_find(ConfigOptions, (const char *)ptr->data);
919 if (!ptr || *ptr->init || !FuncTable[DTYPE (ptr->type)].opt_fromstr)
922 mutt_option_value(ptr->option, buf, sizeof(buf));
923 if (m_strlen(ptr->init) == 0 && buf && *buf)
924 ptr->init = m_strdup(buf);
927 static int init_expand (char** dst, struct option_t* src) {
933 if (DTYPE(src->type) == DT_STR ||
934 DTYPE(src->type) == DT_PATH) {
935 /* only expand for string as it's the only place where
936 * we want to expand vars right now */
937 if (src->init && *src->init) {
940 len = m_strlen(src->init) + 2;
941 in.data = p_new(char, len + 1);
942 snprintf (in.data, len, "\"%s\"", src->init);
945 mutt_extract_token (&token, &in, 0);
946 if (token.data && *token.data)
947 *dst = m_strdup(token.data);
951 p_delete(&token.data);
955 /* for non-string: take value as is */
956 *dst = m_strdup(src->init);
960 /* if additional data more == 1, we want to resolve synonyms */
961 static void mutt_restore_default (const char* name __attribute__ ((unused)),
962 void* p, unsigned long more) {
964 struct option_t* ptr = (struct option_t*) p;
967 if (DTYPE (ptr->type) == DT_SYN) {
970 ptr = hash_find (ConfigOptions, (char*) ptr->data);
974 if (FuncTable[DTYPE (ptr->type)].opt_fromstr) {
975 init_expand (&init, ptr);
976 if (!FuncTable[DTYPE (ptr->type)].opt_fromstr (ptr, init, errbuf,
978 if (!option (OPTNOCURSES))
980 fprintf (stderr, _("Invalid default setting for $%s found: \"%s\".\n"
981 "Please report this error: \"%s\"\n"),
982 ptr->option, NONULL (init), errbuf);
988 if (ptr->flags & R_INDEX)
989 set_option (OPTFORCEREDRAWINDEX);
990 if (ptr->flags & R_PAGER)
991 set_option (OPTFORCEREDRAWPAGER);
992 if (ptr->flags & R_RESORT_SUB)
993 set_option (OPTSORTSUBTHREADS);
994 if (ptr->flags & R_RESORT)
995 set_option (OPTNEEDRESORT);
996 if (ptr->flags & R_RESORT_INIT)
997 set_option (OPTRESORTINIT);
998 if (ptr->flags & R_TREE)
999 set_option (OPTREDRAWTREE);
1002 static int check_num (const char* option, unsigned long p,
1003 char* errbuf, ssize_t errlen) {
1006 snprintf (errbuf, errlen, _("'%d' is invalid for $%s"), (int) p, option);
1012 static int check_history (const char* option __attribute__ ((unused)), unsigned long p,
1013 char* errbuf, ssize_t errlen) {
1014 if (!check_num ("history", p, errbuf, errlen))
1016 mutt_init_history ();
1020 static int check_special (const char* name, unsigned long val,
1021 char* errbuf, ssize_t errlen) {
1024 for (i = 0; SpecialVars[i].name; i++) {
1025 if (m_strcmp(SpecialVars[i].name, name) == 0) {
1026 return (SpecialVars[i].check (SpecialVars[i].name,
1027 val, errbuf, errlen));
1033 static const struct mapping_t* get_sortmap (struct option_t* option) {
1034 const struct mapping_t* map = NULL;
1036 switch (option->type & DT_SUBTYPE_MASK) {
1038 map = SortAliasMethods;
1040 case DT_SORT_BROWSER:
1041 map = SortBrowserMethods;
1044 map = SortKeyMethods;
1047 map = SortAuxMethods;
1056 #define CHECK_PAGER \
1057 if ((CurrentMenu == MENU_PAGER) && \
1058 (!option || (option->flags & R_RESORT))) \
1060 snprintf (err->data, err->dsize, \
1061 _("Not available in this menu.")); \
1065 static int parse_set (BUFFER * tmp, BUFFER * s, unsigned long data,
1068 int query, unset, inv, reset, r = 0;
1069 struct option_t* option = NULL;
1071 while (MoreArgs (s)) {
1072 /* reset state variables */
1074 unset = data & M_SET_UNSET;
1075 inv = data & M_SET_INV;
1076 reset = data & M_SET_RESET;
1078 if (*s->dptr == '?') {
1082 else if (m_strncmp("no", s->dptr, 2) == 0) {
1086 else if (m_strncmp("inv", s->dptr, 3) == 0) {
1090 else if (*s->dptr == '&') {
1095 /* get the variable name */
1096 mutt_extract_token (tmp, s, M_TOKEN_EQUAL);
1098 /* resolve synonyms */
1099 if ((option = hash_find (ConfigOptions, tmp->data)) != NULL &&
1100 DTYPE (option->type == DT_SYN))
1102 struct option_t* newopt = hash_find (ConfigOptions, (char*) option->data);
1103 syn_t* syn = syn_new();
1104 syn->f = m_strdup(CurRCFile);
1108 syn_list_push(&Synonyms, syn);
1112 if (!option && !(reset && m_strcmp("all", tmp->data) == 0)) {
1113 snprintf (err->data, err->dsize, _("%s: unknown variable"), tmp->data);
1116 s->dptr = vskipspaces(s->dptr);
1119 if (query || unset || inv) {
1120 snprintf (err->data, err->dsize, _("prefix is illegal with reset"));
1124 if (s && *s->dptr == '=') {
1125 snprintf (err->data, err->dsize, _("value is illegal with reset"));
1129 if (!m_strcmp("all", tmp->data)) {
1130 if (CurrentMenu == MENU_PAGER) {
1131 snprintf (err->data, err->dsize, _("Not available in this menu."));
1134 hash_map (ConfigOptions, mutt_restore_default, 1);
1135 set_option (OPTFORCEREDRAWINDEX);
1136 set_option (OPTFORCEREDRAWPAGER);
1137 set_option (OPTSORTSUBTHREADS);
1138 set_option (OPTNEEDRESORT);
1139 set_option (OPTRESORTINIT);
1140 set_option (OPTREDRAWTREE);
1144 mutt_restore_default (NULL, option, 1);
1147 else if (DTYPE (option->type) == DT_BOOL) {
1148 /* XXX this currently ignores the function table
1149 * as we don't get invert and stuff into it */
1150 if (s && *s->dptr == '=') {
1151 if (unset || inv || query) {
1152 snprintf (err->data, err->dsize, "Usage: set variable=yes|no");
1157 mutt_extract_token (tmp, s, 0);
1158 if (ascii_strcasecmp ("yes", tmp->data) == 0)
1160 else if (ascii_strcasecmp ("no", tmp->data) == 0)
1163 snprintf (err->data, err->dsize, "Usage: set variable=yes|no");
1169 bool_to_string (err->data, err->dsize, option);
1175 unset_option (option->data);
1177 toggle_option (option->data);
1179 set_option (option->data);
1181 else if (DTYPE (option->type) == DT_STR ||
1182 DTYPE (option->type) == DT_PATH ||
1183 DTYPE (option->type) == DT_ADDR ||
1184 DTYPE (option->type) == DT_MAGIC ||
1185 DTYPE (option->type) == DT_NUM ||
1186 DTYPE (option->type) == DT_SORT ||
1187 DTYPE (option->type) == DT_RX)
1189 /* XXX maybe we need to get unset into handlers? */
1190 if (DTYPE (option->type) == DT_STR ||
1191 DTYPE (option->type) == DT_PATH ||
1192 DTYPE (option->type) == DT_ADDR)
1196 if (DTYPE (option->type) == DT_ADDR)
1197 address_list_wipe((address_t **) option->data);
1199 p_delete((void **)(void *)&option->data);
1204 if (query || *s->dptr != '=') {
1205 FuncTable[DTYPE (option->type)].opt_tostr
1206 (err->data, err->dsize, option);
1212 mutt_extract_token (tmp, s, 0);
1213 if (!FuncTable[DTYPE (option->type)].opt_fromstr
1214 (option, tmp->data, err->data, err->dsize))
1217 else if (DTYPE (option->type) == DT_QUAD) {
1220 quad_to_string (err->data, err->dsize, option);
1224 if (*s->dptr == '=') {
1227 mutt_extract_token (tmp, s, 0);
1228 if (ascii_strcasecmp ("yes", tmp->data) == 0)
1229 set_quadoption (option->data, M_YES);
1230 else if (ascii_strcasecmp ("no", tmp->data) == 0)
1231 set_quadoption (option->data, M_NO);
1232 else if (ascii_strcasecmp ("ask-yes", tmp->data) == 0)
1233 set_quadoption (option->data, M_ASKYES);
1234 else if (ascii_strcasecmp ("ask-no", tmp->data) == 0)
1235 set_quadoption (option->data, M_ASKNO);
1237 snprintf (err->data, err->dsize, _("'%s' is invalid for $%s\n"),
1238 tmp->data, option->option);
1245 toggle_quadoption (option->data);
1247 set_quadoption (option->data, M_NO);
1249 set_quadoption (option->data, M_YES);
1253 snprintf (err->data, err->dsize, _("%s: unknown type"),
1259 if (option->flags & R_INDEX)
1260 set_option (OPTFORCEREDRAWINDEX);
1261 if (option->flags & R_PAGER)
1262 set_option (OPTFORCEREDRAWPAGER);
1263 if (option->flags & R_RESORT_SUB)
1264 set_option (OPTSORTSUBTHREADS);
1265 if (option->flags & R_RESORT)
1266 set_option (OPTNEEDRESORT);
1267 if (option->flags & R_RESORT_INIT)
1268 set_option (OPTRESORTINIT);
1269 if (option->flags & R_TREE)
1270 set_option (OPTREDRAWTREE);
1277 /* reads the specified initialization file. returns -1 if errors were found
1278 so that we can pause to let the user know... */
1279 static int source_rc (const char *rcfile, BUFFER * err)
1282 int line = 0, rc = 0, conv = 0;
1284 char *linebuf = NULL;
1285 char *currentline = NULL;
1289 if ((f = mutt_open_read (rcfile, &pid)) == NULL) {
1290 snprintf (err->data, err->dsize, "%s: %s", rcfile, strerror (errno));
1295 while ((linebuf = mutt_read_line(linebuf, &buflen, f, &line)) != NULL) {
1296 conv = ConfigCharset && (*ConfigCharset) && MCharset.charset;
1298 currentline = m_strdup(linebuf);
1301 mutt_convert_string (¤tline, ConfigCharset, MCharset.charset, 0);
1304 currentline = linebuf;
1309 if (mutt_parse_rc_line (currentline, &token, err) == -1) {
1310 mutt_error (_("Error in %s, line %d: %s"), rcfile, line, err->data);
1311 if (--rc < -MAXERRS) {
1313 p_delete(¤tline);
1322 p_delete(¤tline);
1324 p_delete(&token.data);
1328 mutt_wait_filter (pid);
1330 /* the muttrc source keyword */
1331 snprintf (err->data, err->dsize,
1332 rc >= -MAXERRS ? _("source: errors in %s")
1333 : _("source: reading aborted due too many errors in %s"),
1342 static int parse_source (BUFFER * tmp, BUFFER * s,
1343 unsigned long data __attribute__ ((unused)),
1346 char path[_POSIX_PATH_MAX];
1350 if (mutt_extract_token (tmp, s, 0) != 0) {
1351 snprintf (err->data, err->dsize, _("source: error at %s"), s->dptr);
1355 m_strcpy(path, sizeof(path), tmp->data);
1356 mutt_expand_path (path, sizeof(path));
1358 rc += source_rc (path, err);
1360 while (MoreArgs (s));
1362 return ((rc < 0) ? -1 : 0);
1365 /* line command to execute
1367 token scratch buffer to be used by parser. caller should free
1368 token->data when finished. the reason for this variable is
1369 to avoid having to allocate and deallocate a lot of memory
1370 if we are parsing many lines. the caller can pass in the
1371 memory to use, which avoids having to create new space for
1372 every call to this function.
1374 err where to write error messages */
1375 int mutt_parse_rc_line (const char *line, BUFFER * token, BUFFER * err)
1381 expn.data = expn.dptr = line;
1382 expn.dsize = m_strlen(line);
1386 expn.dptr = vskipspaces(expn.dptr);
1387 while (*expn.dptr) {
1388 if (*expn.dptr == '#')
1389 break; /* rest of line is a comment */
1390 if (*expn.dptr == ';') {
1394 mutt_extract_token (token, &expn, 0);
1395 for (i = 0; Commands[i].name; i++) {
1396 if (!m_strcmp(token->data, Commands[i].name)) {
1397 if (Commands[i].func (token, &expn, Commands[i].data, err) != 0)
1402 if (!Commands[i].name) {
1403 snprintf (err->data, err->dsize, _("%s: unknown command"),
1404 NONULL (token->data));
1411 p_delete(&expn.data);
1416 #define NUMVARS (sizeof(MuttVars)/sizeof(MuttVars[0]))
1417 #define NUMCOMMANDS (sizeof(Commands)/sizeof(Commands[0]))
1418 /* initial string that starts completion. No telling how much crap
1419 * the user has typed so far. Allocate LONG_STRING just to be sure! */
1420 char User_typed[LONG_STRING] = { 0 };
1422 int Num_matched = 0; /* Number of matches for completion */
1423 char Completed[STRING] = { 0 }; /* completed string (command or variable) */
1424 const char *Matches[MAX (NUMVARS, NUMCOMMANDS) + 1]; /* all the matches + User_typed */
1426 /* helper function for completion. Changes the dest buffer if
1427 necessary/possible to aid completion.
1428 dest == completion result gets here.
1429 src == candidate for completion.
1430 try == user entered data for completion.
1431 len == length of dest buffer.
1433 static void candidate (char *dest, char *try, const char *src, int len)
1437 if (strstr (src, try) == src) {
1438 Matches[Num_matched++] = src;
1440 m_strcpy(dest, len, src);
1442 for (l = 0; src[l] && src[l] == dest[l]; l++);
1448 int mutt_command_complete (char *buffer, ssize_t len, int pos, int numtabs)
1452 int spaces; /* keep track of the number of leading spaces on the line */
1454 buffer = vskipspaces(buffer);
1455 spaces = buffer - pt;
1457 pt = buffer + pos - spaces;
1458 while ((pt > buffer) && !isspace ((unsigned char) *pt))
1461 if (pt == buffer) { /* complete cmd */
1462 /* first TAB. Collect all the matches */
1465 m_strcpy(User_typed, sizeof(User_typed), pt);
1466 p_clear(Matches, countof(Matches));
1467 p_clear(Completed, countof(Completed));
1468 for (num = 0; Commands[num].name; num++)
1469 candidate (Completed, User_typed, Commands[num].name,
1471 Matches[Num_matched++] = User_typed;
1473 /* All matches are stored. Longest non-ambiguous string is ""
1474 * i.e. dont change 'buffer'. Fake successful return this time */
1475 if (User_typed[0] == 0)
1479 if (Completed[0] == 0 && User_typed[0])
1482 /* Num_matched will _always_ be atleast 1 since the initial
1483 * user-typed string is always stored */
1484 if (numtabs == 1 && Num_matched == 2)
1485 snprintf (Completed, sizeof(Completed), "%s", Matches[0]);
1486 else if (numtabs > 1 && Num_matched > 2)
1487 /* cycle thru all the matches */
1488 snprintf (Completed, sizeof(Completed), "%s",
1489 Matches[(numtabs - 2) % Num_matched]);
1491 /* return the completed command */
1492 m_strcpy(buffer, len - spaces, Completed);
1494 else if (!m_strncmp(buffer, "set", 3)
1495 || !m_strncmp(buffer, "unset", 5)
1496 || !m_strncmp(buffer, "reset", 5)
1497 || !m_strncmp(buffer, "toggle", 6)) { /* complete variables */
1498 const char *prefixes[] = { "no", "inv", "?", "&", NULL };
1501 /* loop through all the possible prefixes (no, inv, ...) */
1502 if (!m_strncmp(buffer, "set", 3)) {
1503 for (num = 0; prefixes[num]; num++) {
1504 if (!m_strncmp(pt, prefixes[num], m_strlen(prefixes[num]))) {
1505 pt += m_strlen(prefixes[num]);
1511 /* first TAB. Collect all the matches */
1514 m_strcpy(User_typed, sizeof(User_typed), pt);
1515 p_clear(Matches, countof(Matches));
1516 p_clear(Completed, countof(Completed));
1517 for (num = 0; MuttVars[num].option; num++)
1518 candidate(Completed, User_typed, MuttVars[num].option,
1520 Matches[Num_matched++] = User_typed;
1522 /* All matches are stored. Longest non-ambiguous string is ""
1523 * i.e. dont change 'buffer'. Fake successful return this time */
1524 if (User_typed[0] == 0)
1528 if (Completed[0] == 0 && User_typed[0])
1531 /* Num_matched will _always_ be atleast 1 since the initial
1532 * user-typed string is always stored */
1533 if (numtabs == 1 && Num_matched == 2)
1534 snprintf (Completed, sizeof(Completed), "%s", Matches[0]);
1535 else if (numtabs > 1 && Num_matched > 2)
1536 /* cycle thru all the matches */
1537 snprintf (Completed, sizeof(Completed), "%s",
1538 Matches[(numtabs - 2) % Num_matched]);
1540 m_strcpy(pt, buffer + len - pt - spaces, Completed);
1542 else if (!m_strncmp(buffer, "exec", 4)) {
1543 struct binding_t *menu = km_get_table (CurrentMenu);
1545 if (!menu && CurrentMenu != MENU_PAGER)
1549 /* first TAB. Collect all the matches */
1552 m_strcpy(User_typed, sizeof(User_typed), pt);
1553 p_clear(Matches, countof(Matches));
1554 p_clear(Completed, countof(Completed));
1555 for (num = 0; menu[num].name; num++)
1556 candidate (Completed, User_typed, menu[num].name, sizeof(Completed));
1557 /* try the generic menu */
1558 if (Completed[0] == 0 && CurrentMenu != MENU_PAGER) {
1560 for (num = 0; menu[num].name; num++)
1561 candidate (Completed, User_typed, menu[num].name,
1564 Matches[Num_matched++] = User_typed;
1566 /* All matches are stored. Longest non-ambiguous string is ""
1567 * i.e. dont change 'buffer'. Fake successful return this time */
1568 if (User_typed[0] == 0)
1572 if (Completed[0] == 0 && User_typed[0])
1575 /* Num_matched will _always_ be atleast 1 since the initial
1576 * user-typed string is always stored */
1577 if (numtabs == 1 && Num_matched == 2)
1578 snprintf (Completed, sizeof(Completed), "%s", Matches[0]);
1579 else if (numtabs > 1 && Num_matched > 2)
1580 /* cycle thru all the matches */
1581 snprintf (Completed, sizeof(Completed), "%s",
1582 Matches[(numtabs - 2) % Num_matched]);
1584 m_strcpy(pt, buffer + len - pt - spaces, Completed);
1592 int mutt_var_value_complete (char *buffer, ssize_t len, int pos)
1594 char var[STRING], *pt = buffer;
1596 struct option_t* option = NULL;
1601 buffer = vskipspaces(buffer);
1602 spaces = buffer - pt;
1604 pt = buffer + pos - spaces;
1605 while ((pt > buffer) && !isspace ((unsigned char) *pt))
1607 pt++; /* move past the space */
1608 if (*pt == '=') /* abort if no var before the '=' */
1611 if (m_strncmp(buffer, "set", 3) == 0) {
1612 m_strcpy(var, sizeof(var), pt);
1613 /* ignore the trailing '=' when comparing */
1614 var[m_strlen(var) - 1] = 0;
1615 if (!(option = hash_find (ConfigOptions, var)))
1616 return 0; /* no such variable. */
1618 char tmp[LONG_STRING], tmp2[LONG_STRING];
1620 ssize_t dlen = buffer + len - pt - spaces;
1621 const char *vals[] = { "no", "yes", "ask-no", "ask-yes" };
1625 if ((DTYPE (option->type) == DT_STR) ||
1626 (DTYPE (option->type) == DT_PATH) ||
1627 (DTYPE (option->type) == DT_RX)) {
1628 m_strcpy(tmp, sizeof(tmp), NONULL(*((char **)option->data)));
1629 if (DTYPE (option->type) == DT_PATH)
1630 mutt_pretty_mailbox (tmp);
1632 else if (DTYPE (option->type) == DT_ADDR) {
1633 rfc822_addrcat(tmp, sizeof(tmp), *((address_t **) option->data), 0);
1635 else if (DTYPE (option->type) == DT_QUAD)
1636 m_strcpy(tmp, sizeof(tmp), vals[quadoption(option->data)]);
1637 else if (DTYPE (option->type) == DT_NUM)
1638 snprintf (tmp, sizeof(tmp), "%d", (*((short *) option->data)));
1639 else if (DTYPE (option->type) == DT_SORT) {
1640 const struct mapping_t *map;
1643 switch (option->type & DT_SUBTYPE_MASK) {
1645 map = SortAliasMethods;
1647 case DT_SORT_BROWSER:
1648 map = SortBrowserMethods;
1651 map = SortKeyMethods;
1657 p = mutt_getnamebyvalue(*((short *) option->data) & SORT_MASK, map);
1658 snprintf(tmp, sizeof(tmp), "%s%s%s",
1659 (*((short *)option->data) & SORT_REVERSE) ? "reverse-" : "",
1660 (*((short *)option->data) & SORT_LAST) ? "last-" : "", p);
1662 else if (DTYPE (option->type) == DT_MAGIC) {
1664 switch (DefaultMagic) {
1680 m_strcpy(tmp, sizeof(tmp), p);
1682 else if (DTYPE (option->type) == DT_BOOL)
1683 m_strcpy(tmp, sizeof(tmp), option(option->data) ? "yes" : "no");
1687 for (s = tmp, d = tmp2; *s && (d - tmp2) < ssizeof(tmp2) - 2;) {
1688 if (*s == '\\' || *s == '"')
1694 m_strcpy(tmp, sizeof(tmp), pt);
1695 snprintf (pt, dlen, "%s\"%s\"", tmp, tmp2);
1703 /* Implement the -Q command line flag */
1704 int mutt_query_variables (string_list_t * queries)
1708 char errbuff[STRING];
1709 char command[STRING];
1717 err.dsize = sizeof(errbuff);
1719 for (p = queries; p; p = p->next) {
1720 snprintf (command, sizeof(command), "set ?%s\n", p->data);
1721 if (mutt_parse_rc_line (command, &token, &err) == -1) {
1722 fprintf (stderr, "%s\n", err.data);
1723 p_delete(&token.data);
1726 printf ("%s\n", err.data);
1729 p_delete(&token.data);
1733 static int mutt_execute_commands (string_list_t * p)
1736 char errstr[STRING];
1740 err.dsize = sizeof(errstr);
1742 for (; p; p = p->next) {
1743 if (mutt_parse_rc_line (p->data, &token, &err) != 0) {
1744 fprintf (stderr, _("Error in command line: %s\n"), err.data);
1745 p_delete(&token.data);
1749 p_delete(&token.data);
1753 void mutt_init (int skip_sys_rc, string_list_t * commands)
1757 char buffer[STRING], error[STRING];
1758 int default_rc = 0, need_pause = 0;
1764 err.dsize = sizeof(error);
1766 ConfigOptions = hash_new (sizeof(MuttVars) * 2, 0);
1767 for (i = 0; MuttVars[i].option; i++) {
1768 hash_insert (ConfigOptions, MuttVars[i].option, &MuttVars[i]);
1772 * XXX - use something even more difficult to predict?
1774 snprintf (AttachmentMarker, sizeof(AttachmentMarker),
1775 "\033]9;%ld\a", (long) time (NULL));
1778 /* Get some information about the user */
1779 if ((pw = getpwuid (getuid ()))) {
1781 mutt_gecos_name(rnbuf, sizeof(rnbuf), pw, MCore.gecos_mask);
1782 Realname = m_strdup(rnbuf);
1790 if ((f = safe_fopen (SYSCONFDIR "/nntpserver", "r"))) {
1792 fgets (buffer, sizeof(buffer), f);
1793 p = vskipspaces(buffer);
1795 while (*q && !isspace(*q))
1798 NewsServer = m_strdup(p);
1802 if ((p = getenv ("NNTPSERVER")))
1803 NewsServer = m_strdup(p);
1806 if ((p = getenv("MAIL") ?: getenv("MAILDIR"))) {
1807 Spoolfile = m_strdup(p);
1810 mutt_concat_path(buffer, sizeof(buffer), NONULL(MCore.homedir), MAILPATH);
1812 mutt_concat_path(buffer, sizeof(buffer), MAILPATH, NONULL(MCore.username));
1814 Spoolfile = m_strdup(buffer);
1817 if ((p = getenv ("REPLYTO")) != NULL) {
1820 snprintf (buffer, sizeof(buffer), "Reply-To: %s", p);
1823 buf.data = buf.dptr = buffer;
1824 buf.dsize = m_strlen(buffer);
1827 parse_my_hdr (&token, &buf, 0, &err);
1828 p_delete(&token.data);
1831 if ((p = getenv ("EMAIL")) != NULL)
1832 From = rfc822_parse_adrlist (NULL, p);
1834 /* Set standard defaults */
1835 hash_map (ConfigOptions, mutt_set_default, 0);
1836 hash_map (ConfigOptions, mutt_restore_default, 0);
1838 CurrentMenu = MENU_MAIN;
1841 /* Unset suspend by default if we're the session leader */
1842 if (getsid (0) == getpid ())
1843 unset_option (OPTSUSPEND);
1846 mutt_init_history ();
1849 snprintf (buffer, sizeof(buffer), "%s/.madmuttrc", NONULL(MCore.homedir));
1850 if (access (buffer, F_OK) == -1)
1851 snprintf (buffer, sizeof(buffer), "%s/.madmutt/madmuttrc",
1852 NONULL(MCore.homedir));
1855 Muttrc = m_strdup(buffer);
1858 m_strcpy(buffer, sizeof(buffer), Muttrc);
1860 mutt_expand_path (buffer, sizeof(buffer));
1861 Muttrc = m_strdup(buffer);
1864 /* Process the global rc file if it exists and the user hasn't explicity
1865 requested not to via "-n". */
1867 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc-%s", SYSCONFDIR,
1869 if (access (buffer, F_OK) == -1)
1870 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc", SYSCONFDIR);
1871 if (access (buffer, F_OK) == -1)
1872 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc-%s", PKGDATADIR,
1874 if (access (buffer, F_OK) == -1)
1875 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc", PKGDATADIR);
1876 if (access (buffer, F_OK) != -1) {
1877 if (source_rc (buffer, &err) != 0) {
1878 fputs (err.data, stderr);
1879 fputc ('\n', stderr);
1885 /* Read the user's initialization file. */
1886 if (access (Muttrc, F_OK) != -1) {
1887 if (!option (OPTNOCURSES))
1889 if (source_rc (Muttrc, &err) != 0) {
1890 fputs (err.data, stderr);
1891 fputc ('\n', stderr);
1895 else if (!default_rc) {
1896 /* file specified by -F does not exist */
1897 snprintf (buffer, sizeof(buffer), "%s: %s", Muttrc, strerror (errno));
1898 mutt_endwin (buffer);
1903 snprintf(buffer, sizeof(buffer), "%s/.madmutt.lua", NONULL(MCore.homedir));
1904 if (access(buffer, F_OK) < 0)
1905 snprintf(buffer, sizeof(buffer), "%s/.madmutt/cfg.lua", NONULL(MCore.homedir));
1906 if (!access(buffer, F_OK)) {
1907 need_pause = luaM_wrap(mutt_error, luaM_dofile(buffer));
1911 if (mutt_execute_commands (commands) != 0)
1914 /* warn about synonym variables */
1918 fprintf (stderr, _("Warning: the following synonym variables were found:\n"));
1920 for (syn = Synonyms; syn; syn = syn->next) {
1921 fprintf(stderr, "$%s ($%s should be used) (%s:%d)\n",
1922 syn->o ? NONULL(syn->o->option) : "",
1923 syn->n ? NONULL(syn->n->option) : "",
1924 NONULL(syn->f), syn->l);
1926 fprintf (stderr, _("Warning: synonym variables are scheduled"
1927 " for removal.\n"));
1928 syn_list_wipe(&Synonyms);
1932 if (need_pause && !option (OPTNOCURSES)) {
1933 if (mutt_any_key_to_continue (NULL) == -1)
1938 int mutt_get_hook_type (const char *name)
1940 struct command_t *c;
1942 for (c = Commands; c->name; c++)
1943 if (c->func == mutt_parse_hook && ascii_strcasecmp (c->name, name) == 0)
1948 /* dump out the value of all the variables we have */
1949 int mutt_dump_variables (int full) {
1952 /* get all non-synonyms into list... */
1953 for (i = 0; MuttVars[i].option; i++) {
1954 struct option_t *option = MuttVars + i;
1955 char buf[LONG_STRING];
1957 if (DTYPE(option->type) == DT_SYN)
1961 mutt_option_value(option->option, buf, sizeof(buf));
1962 if (!m_strcmp(buf, option->init))
1967 FuncTable[DTYPE(option->type)].opt_tostr(buf, sizeof(buf), option);
1968 printf ("%s\n", buf);
1971 printf ("\n# vi""m:set ft=muttrc:\n");