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 /* protos for config type handles: convert value to string */
100 static void bool_to_string (char* dst, ssize_t dstlen, struct option_t* option);
101 static void num_to_string (char* dst, ssize_t dstlen, struct option_t* option);
102 static void str_to_string (char* dst, ssize_t dstlen, struct option_t* option);
103 static void quad_to_string (char* dst, ssize_t dstlen, struct option_t* option);
104 static void sort_to_string (char* dst, ssize_t dstlen, struct option_t* option);
105 static void rx_to_string (char* dst, ssize_t dstlen, struct option_t* option);
106 static void magic_to_string (char* dst, ssize_t dstlen, struct option_t* option);
107 static void addr_to_string (char* dst, ssize_t dstlen, struct option_t* option);
109 /* protos for config type handles: convert to value from string */
110 static int bool_from_string (struct option_t* dst, const char* val,
111 char* errbuf, ssize_t errlen);
112 static int num_from_string (struct option_t* dst, const char* val,
113 char* errbuf, ssize_t errlen);
114 static int str_from_string (struct option_t* dst, const char* val,
115 char* errbuf, ssize_t errlen);
116 static int path_from_string (struct option_t* dst, const char* val,
117 char* errbuf, ssize_t errlen);
118 static int quad_from_string (struct option_t* dst, const char* val,
119 char* errbuf, ssize_t errlen);
120 static int sort_from_string (struct option_t* dst, const char* val,
121 char* errbuf, ssize_t errlen);
122 static int rx_from_string (struct option_t* dst, const char* val,
123 char* errbuf, ssize_t errlen);
124 static int magic_from_string (struct option_t* dst, const char* val,
125 char* errbuf, ssize_t errlen);
126 static int addr_from_string (struct option_t* dst, const char* val,
127 char* errbuf, ssize_t errlen);
131 void (*opt_tostr) (char* dst, ssize_t dstlen, struct option_t* option);
132 int (*opt_fromstr) (struct option_t* dst, const char* val,
133 char* errbuf, ssize_t errlen);
135 { 0, NULL, NULL }, /* there's no DT_ type with 0 */
136 { DT_BOOL, bool_to_string, bool_from_string },
137 { DT_NUM, num_to_string, num_from_string },
138 { DT_STR, str_to_string, str_from_string },
139 { DT_PATH, str_to_string, path_from_string },
140 { DT_QUAD, quad_to_string, quad_from_string },
141 { DT_SORT, sort_to_string, sort_from_string },
142 { DT_RX, rx_to_string, rx_from_string },
143 { DT_MAGIC, magic_to_string, magic_from_string },
144 /* synonyms should be resolved already so we don't need this
145 * but must define it as DT_ is used for indexing */
146 { DT_SYN, NULL, NULL },
147 { DT_ADDR, addr_to_string, addr_from_string },
150 static void bool_to_string (char* dst, ssize_t dstlen,
151 struct option_t* option) {
152 snprintf (dst, dstlen, "%s=%s", option->option,
153 option (option->data) ? "yes" : "no");
156 static int bool_from_string (struct option_t* dst, const char* val,
157 char* errbuf __attribute__ ((unused)),
158 ssize_t errlen __attribute__ ((unused))) {
163 if (ascii_strncasecmp (val, "yes", 3) == 0)
165 else if (ascii_strncasecmp (val, "no", 2) == 0)
171 set_option (dst->data);
173 unset_option (dst->data);
177 static void num_to_string (char* dst, ssize_t dstlen,
178 struct option_t* option) {
180 const char* fmt = (m_strcmp(option->option, "umask") == 0) ?
182 snprintf (dst, dstlen, fmt, option->option,
183 *((short*) option->data));
186 static int num_from_string (struct option_t* dst, const char* val,
187 char* errbuf, ssize_t errlen) {
188 int num = 0, old = 0;
194 num = strtol (val, &t, 0);
196 if (m_strisempty(val) || *t || (short) num != num) {
198 snprintf (errbuf, errlen, _("'%s' is invalid for $%s"),
204 /* just temporarily accept new val so that check_special for
205 * $history already has it when doing history's init() */
206 old = *((short*) dst->data);
207 *((short*) dst->data) = (short) num;
209 if (!check_special (dst->option, (unsigned long) num, errbuf, errlen)) {
210 *((short*) dst->data) = old;
217 static void str_to_string (char* dst, ssize_t dstlen,
218 struct option_t* option) {
219 snprintf (dst, dstlen, "%s=\"%s\"", option->option,
220 NONULL (*((char**) option->data)));
223 static int path_from_string (struct option_t* dst, const char* val,
224 char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
225 char path[_POSIX_PATH_MAX];
230 if (m_strisempty(val)) {
231 p_delete((char**) dst->data);
236 m_strcpy(path, sizeof(path), val);
237 mutt_expand_path (path, sizeof(path));
238 m_strreplace((char **) dst->data, path);
242 static int str_from_string (struct option_t* dst, const char* val,
243 char* errbuf, ssize_t errlen) {
247 if (!check_special (dst->option, (unsigned long) val, errbuf, errlen))
250 m_strreplace((char**) dst->data, val);
254 static void quad_to_string (char* dst, ssize_t dstlen,
255 struct option_t* option) {
256 const char *vals[] = { "no", "yes", "ask-no", "ask-yes" };
257 snprintf (dst, dstlen, "%s=%s", option->option,
258 vals[quadoption (option->data)]);
261 static int quad_from_string (struct option_t* dst, const char* val,
262 char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
267 if (ascii_strncasecmp (val, "yes", 3) == 0)
269 else if (ascii_strncasecmp (val, "no", 2) == 0)
271 else if (ascii_strncasecmp (val, "ask-yes", 7) == 0)
273 else if (ascii_strncasecmp (val, "ask-no", 6) == 0)
279 set_quadoption (dst->data, flag);
283 static void sort_to_string (char* dst, ssize_t dstlen,
284 struct option_t* option) {
285 const struct mapping_t *map = get_sortmap (option);
286 const char *p = NULL;
289 snprintf (dst, sizeof(dst), "%s=unknown", option->option);
293 p = mutt_getnamebyvalue(*((short *)option->data) & SORT_MASK, map);
295 snprintf (dst, dstlen, "%s=%s%s%s", option->option,
296 (*((short *) option->data) & SORT_REVERSE) ?
298 (*((short *) option->data) & SORT_LAST) ? "last-" :
302 static int sort_from_string (struct option_t* dst, const char* val,
303 char* errbuf, ssize_t errlen) {
304 const struct mapping_t *map = NULL;
305 if (!(map = get_sortmap (dst))) {
307 snprintf (errbuf, errlen, _("%s: Unknown type."),
311 if (parse_sort (dst, val, map, errbuf, errlen) == -1)
316 static void rx_to_string (char* dst, ssize_t dstlen,
317 struct option_t* option) {
318 rx_t* p = (rx_t*) option->data;
319 snprintf (dst, dstlen, "%s=\"%s\"", option->option,
320 NONULL (p->pattern));
323 static int rx_from_string (struct option_t* dst, const char* val,
324 char* errbuf, ssize_t errlen) {
327 int flags = 0, e = 0, neg = 0;
333 if (option (OPTATTACHMSG) && !m_strcmp(dst->option, "reply_regexp")) {
335 snprintf (errbuf, errlen,
336 "Operation not permitted when in attach-message mode.");
340 if (!((rx_t*) dst->data))
341 *((rx_t**) dst->data) = p_new(rx_t, 1);
343 p = (rx_t*) dst->data;
345 /* something to do? */
346 if (m_strisempty(val) || (p->pattern && m_strcmp(p->pattern, val) == 0))
349 if (m_strcmp(dst->option, "mask") != 0)
350 flags |= mutt_which_case (val);
353 if (m_strcmp(dst->option, "mask") == 0 && *s == '!') {
358 rx = p_new(regex_t, 1);
360 if ((e = REGCOMP (rx, s, flags)) != 0) {
361 regerror (e, rx, errbuf, errlen);
372 m_strreplace(&p->pattern, val);
376 if (m_strcmp(dst->option, "reply_regexp") == 0)
377 mutt_adjust_all_subjects ();
382 static void magic_to_string (char* dst, ssize_t dstlen,
383 struct option_t* option) {
384 const char* s = NULL;
385 switch (option->data) {
386 case M_MBOX: s = "mbox"; break;
387 case M_MMDF: s = "MMDF"; break;
388 case M_MH: s = "MH"; break;
389 case M_MAILDIR: s = "Maildir"; break;
390 default: s = "unknown"; break;
392 snprintf (dst, dstlen, "%s=%s", option->option, s);
395 static int magic_from_string (struct option_t* dst, const char* val,
396 char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
399 if (!dst || m_strisempty(val))
401 if (ascii_strncasecmp (val, "mbox", 4) == 0)
403 else if (ascii_strncasecmp (val, "mmdf", 4) == 0)
405 else if (ascii_strncasecmp (val, "mh", 2) == 0)
407 else if (ascii_strncasecmp (val, "maildir", 7) == 0)
413 *((short*) dst->data) = flag;
418 static void addr_to_string (char* dst, ssize_t dstlen,
419 struct option_t* option) {
422 rfc822_addrcat(s, sizeof(s), *((address_t**) option->data), 0);
423 snprintf (dst, dstlen, "%s=\"%s\"", option->option, NONULL (s));
426 static int addr_from_string (struct option_t* dst, const char* val,
427 char* errbuf __attribute__ ((unused)), ssize_t errlen __attribute__ ((unused))) {
430 address_list_wipe((address_t**) dst->data);
432 *((address_t**) dst->data) = rfc822_parse_adrlist (NULL, val);
436 int mutt_option_value (const char* val, char* dst, ssize_t dstlen) {
437 struct option_t* option = NULL;
438 char* tmp = NULL, *t = NULL;
441 if (!(option = hash_find (ConfigOptions, val))) {
445 tmp = p_new(char, dstlen+1);
446 FuncTable[DTYPE(option->type)].opt_tostr (tmp, dstlen, option);
448 /* as we get things of type $var=value and don't want to bloat the
449 * above "just" for expansion, we do the stripping here */
450 t = strchr (tmp, '=');
454 if (t[l-1] == '"' && *t == '"') {
459 memcpy (dst, t, l+1);
465 static void toggle_quadoption (int opt)
468 int b = (opt % 4) * 2;
470 QuadOptions[n] ^= (1 << b);
473 void set_quadoption (int opt, int flag)
476 int b = (opt % 4) * 2;
478 QuadOptions[n] &= ~(0x3 << b);
479 QuadOptions[n] |= (flag & 0x3) << b;
482 int quadoption (int opt)
485 int b = (opt % 4) * 2;
487 return (QuadOptions[n] >> b) & 0x3;
490 int query_quadoption2(int v, const char *prompt)
498 v = mutt_yesorno(prompt, (v == M_ASKYES));
499 CLEARLINE (LINES - 1);
504 int query_quadoption (int opt, const char *prompt)
506 int v = quadoption (opt);
514 v = mutt_yesorno (prompt, (v == M_ASKYES));
515 CLEARLINE (LINES - 1);
522 static int parse_unignore (BUFFER * buf, BUFFER * s,
523 unsigned long data __attribute__ ((unused)),
524 BUFFER * err __attribute__ ((unused)))
527 mutt_extract_token (buf, s, 0);
529 /* don't add "*" to the unignore list */
530 if (m_strcmp(buf->data, "*")) {
531 string_list_add(&UnIgnore, buf->data);
532 string_list_remove(&Ignore, buf->data);
534 string_list_wipe(&Ignore);
536 } while (MoreArgs (s));
541 static int parse_ignore (BUFFER * buf, BUFFER * s,
542 unsigned long data __attribute__ ((unused)),
543 BUFFER * err __attribute__ ((unused)))
546 mutt_extract_token (buf, s, 0);
547 if (m_strcmp(buf->data, "*")) {
548 string_list_remove(&UnIgnore, buf->data);
550 string_list_wipe(&UnIgnore);
552 string_list_add(&Ignore, buf->data);
553 } while (MoreArgs(s));
557 static int parse_list(BUFFER * buf, BUFFER * s, unsigned long data,
558 BUFFER * err __attribute__ ((unused)))
561 mutt_extract_token (buf, s, 0);
562 string_list_add ((string_list_t **) data, buf->data);
563 } while (MoreArgs(s));
567 static int parse_unlist (BUFFER * buf, BUFFER * s, unsigned long data,
568 BUFFER * err __attribute__ ((unused)))
571 mutt_extract_token (buf, s, 0);
573 * Check for deletion of entire list
575 if (!m_strcmp(buf->data, "*")) {
576 string_list_wipe((string_list_t **) data);
579 string_list_remove((string_list_t **) data, buf->data);
581 while (MoreArgs (s));
586 /* always wise to do what someone else did before */
587 static void _attachments_clean (void) {
589 if (Context && Context->msgcount) {
590 for (i = 0; i < Context->msgcount; i++)
591 Context->hdrs[i]->attach_valid = 0;
595 static int parse_attach_list (BUFFER *buf, BUFFER *s, string_list_t **ldata,
596 BUFFER *err __attribute__ ((unused))) {
598 string_list_t *listp, *lastp;
603 /* Find the last item in the list that data points to. */
605 for (listp = *ldata; listp; listp = listp->next) {
606 a = (ATTACH_MATCH *)listp->data;
611 mutt_extract_token (buf, s, 0);
613 if (!buf->data || *buf->data == '\0')
616 a = p_new(ATTACH_MATCH, 1);
618 /* some cheap hacks that I expect to remove */
619 if (!m_strcasecmp(buf->data, "any"))
620 a->major = m_strdup("*/.*");
621 else if (!m_strcasecmp(buf->data, "none"))
622 a->major = m_strdup("cheap_hack/this_should_never_match");
624 a->major = m_strdup(buf->data);
626 if ((p = strchr(a->major, '/'))) {
631 a->minor = "unknown";
634 len = m_strlen(a->minor);
635 tmpminor = p_new(char, len + 3);
636 m_strcpy(&tmpminor[1], len + 3, a->minor);
638 tmpminor[len+1] = '$';
639 tmpminor[len+2] = '\0';
641 a->major_int = mutt_check_mime_type(a->major);
642 regcomp(&a->minor_rx, tmpminor, REG_ICASE|REG_EXTENDED);
646 listp = p_new(string_list_t, 1);
647 listp->data = (char *)a;
656 while (MoreArgs (s));
658 _attachments_clean();
662 static int parse_unattach_list (BUFFER *buf, BUFFER *s, string_list_t **ldata,
663 BUFFER *err __attribute__ ((unused))) {
665 string_list_t *lp, *lastp, *newlp;
671 mutt_extract_token (buf, s, 0);
673 if (!m_strcasecmp(buf->data, "any"))
674 tmp = m_strdup("*/.*");
675 else if (!m_strcasecmp(buf->data, "none"))
676 tmp = m_strdup("cheap_hack/this_should_never_match");
678 tmp = m_strdup(buf->data);
680 if ((minor = strchr(tmp, '/'))) {
684 minor = m_strdup("unknown");
686 major = mutt_check_mime_type(tmp);
688 /* We must do our own walk here because string_list_remove() will only
689 * remove the string_list_t->data, not anything pointed to by the string_list_t->data. */
691 for(lp = *ldata; lp; ) {
692 a = (ATTACH_MATCH *)lp->data;
693 if (a->major_int == major && !m_strcasecmp(minor, a->minor)) {
694 regfree(&a->minor_rx);
697 /* Relink backward */
699 lastp->next = lp->next;
704 p_delete(&lp->data); /* same as a */
714 while (MoreArgs (s));
717 _attachments_clean();
721 static int print_attach_list (string_list_t *lp, char op, const char *name) {
723 printf("attachments %c%s %s/%s\n", op, name,
724 ((ATTACH_MATCH *)lp->data)->major,
725 ((ATTACH_MATCH *)lp->data)->minor);
732 static int parse_attachments (BUFFER *buf, BUFFER *s,
733 unsigned long data __attribute__ ((unused)),
736 string_list_t **listp;
738 mutt_extract_token(buf, s, 0);
739 if (!buf->data || *buf->data == '\0') {
740 m_strcpy(err->data, err->dsize, _("attachments: no disposition"));
744 category = buf->data;
750 printf("\nCurrent attachments settings:\n\n");
751 print_attach_list(AttachAllow, '+', "A");
752 print_attach_list(AttachExclude, '-', "A");
753 print_attach_list(InlineAllow, '+', "I");
754 print_attach_list(InlineExclude, '-', "I");
755 set_option (OPTFORCEREDRAWINDEX);
756 set_option (OPTFORCEREDRAWPAGER);
757 mutt_any_key_to_continue (NULL);
761 if (op != '+' && op != '-') {
765 if (!m_strncasecmp(category, "attachment", strlen(category))) {
767 listp = &AttachAllow;
769 listp = &AttachExclude;
771 else if (!m_strncasecmp(category, "inline", strlen(category))) {
773 listp = &InlineAllow;
775 listp = &InlineExclude;
777 m_strcpy(err->data, err->dsize, _("attachments: invalid disposition"));
781 return parse_attach_list(buf, s, listp, err);
784 static int parse_unattachments (BUFFER *buf, BUFFER *s, unsigned long data __attribute__ ((unused)), BUFFER *err) {
786 string_list_t **listp;
788 mutt_extract_token(buf, s, 0);
789 if (!buf->data || *buf->data == '\0') {
790 m_strcpy(err->data, err->dsize, _("unattachments: no disposition"));
796 if (op != '+' && op != '-') {
800 if (!m_strncasecmp(p, "attachment", strlen(p))) {
802 listp = &AttachAllow;
804 listp = &AttachExclude;
806 else if (!m_strncasecmp(p, "inline", strlen(p))) {
808 listp = &InlineAllow;
810 listp = &InlineExclude;
813 m_strcpy(err->data, err->dsize, _("unattachments: invalid disposition"));
817 return parse_unattach_list(buf, s, listp, err);
820 static int parse_unalias (BUFFER * buf, BUFFER * s,
821 unsigned long data __attribute__ ((unused)),
822 BUFFER * err __attribute__ ((unused)))
824 alias_t *tmp, **last;
827 mutt_extract_token (buf, s, 0);
829 if (!m_strcmp("*", buf->data) == 0) {
830 if (CurrentMenu == MENU_ALIAS) {
831 for (tmp = Aliases; tmp; tmp = tmp->next)
833 set_option(OPTFORCEREDRAWINDEX);
835 alias_list_wipe(&Aliases);
841 for (last = &Aliases; *last; last = &(*last)->next) {
842 if (!m_strcasecmp(buf->data, (*last)->name)) {
843 if (CurrentMenu == MENU_ALIAS) {
845 set_option (OPTFORCEREDRAWINDEX);
847 tmp = alias_list_pop(last);
853 } while (MoreArgs(s));
858 static int parse_alias (BUFFER * buf, BUFFER * s,
859 unsigned long data __attribute__ ((unused)),
866 m_strcpy(err->data, err->dsize, _("alias: no address"));
870 mutt_extract_token (buf, s, 0);
872 /* check to see if an alias with this name already exists */
873 for (last = &Aliases; *last; last = &(*last)->next) {
874 if (!m_strcasecmp((*last)->name, buf->data))
879 /* create a new alias */
881 (*last)->name = m_strdup(buf->data);
882 /* give the main addressbook code a chance */
883 if (CurrentMenu == MENU_ALIAS)
884 set_option (OPTMENUCALLER);
886 /* override the previous value */
887 address_list_wipe(&(*last)->addr);
888 if (CurrentMenu == MENU_ALIAS)
889 set_option (OPTFORCEREDRAWINDEX);
892 mutt_extract_token(buf, s, M_TOKEN_QUOTE | M_TOKEN_SPACE);
893 (*last)->addr = mutt_parse_adrlist((*last)->addr, buf->data);
894 if (mutt_addrlist_to_idna((*last)->addr, &estr)) {
895 snprintf (err->data, err->dsize,
896 _("Warning: Bad IDN '%s' in alias '%s'.\n"), estr, (*last)->name);
905 parse_unmy_hdr(BUFFER * buf, BUFFER * s,
906 unsigned long data __attribute__ ((unused)),
907 BUFFER * err __attribute__ ((unused)))
910 mutt_extract_token (buf, s, 0);
912 if (!m_strcmp("*", buf->data)) {
913 string_list_wipe(&UserHeader);
915 string_list_t **last = &UserHeader;
916 ssize_t l = m_strlen(buf->data);
918 if (buf->data[l - 1] == ':')
922 if (!ascii_strncasecmp(buf->data, (*last)->data, l)
923 && (*last)->data[l] == ':')
925 string_list_t *tmp = string_list_pop(last);
926 string_item_delete(&tmp);
928 last = &(*last)->next;
932 } while (MoreArgs(s));
937 static int parse_my_hdr (BUFFER * buf, BUFFER * s, unsigned long data __attribute__ ((unused)),
944 mutt_extract_token (buf, s, M_TOKEN_SPACE | M_TOKEN_QUOTE);
945 if ((p = strpbrk (buf->data, ": \t")) == NULL || *p != ':') {
946 m_strcpy(err->data, err->dsize, _("invalid header field"));
949 keylen = p - buf->data + 1;
952 for (tmp = UserHeader;; tmp = tmp->next) {
953 /* see if there is already a field by this name */
954 if (ascii_strncasecmp (buf->data, tmp->data, keylen) == 0) {
955 /* replace the old value */
956 p_delete(&tmp->data);
957 tmp->data = buf->data;
964 tmp->next = string_item_new();
968 tmp = string_item_new();
971 tmp->data = buf->data;
977 parse_sort (struct option_t* dst, const char *s, const struct mapping_t *map,
978 char* errbuf, ssize_t errlen) {
981 if (m_strncmp("reverse-", s, 8) == 0) {
983 flags = SORT_REVERSE;
986 if (m_strncmp("last-", s, 5) == 0) {
991 if ((i = mutt_getvaluebyname (s, map)) == -1) {
993 snprintf (errbuf, errlen, _("'%s' is invalid for $%s"), s, dst->option);
997 *((short*) dst->data) = i | flags;
1001 /* if additional data more == 1, we want to resolve synonyms */
1002 static void mutt_set_default(const char *name __attribute__ ((unused)), void* p, unsigned long more)
1004 char buf[LONG_STRING];
1005 struct option_t *ptr = p;
1007 if (DTYPE(ptr->type) == DT_SYN) {
1010 ptr = hash_find(ConfigOptions, (const char *)ptr->data);
1012 if (!ptr || *ptr->init || !FuncTable[DTYPE (ptr->type)].opt_fromstr)
1015 mutt_option_value(ptr->option, buf, sizeof(buf));
1016 if (m_strlen(ptr->init) == 0 && buf && *buf)
1017 ptr->init = m_strdup(buf);
1020 static int init_expand (char** dst, struct option_t* src) {
1026 if (DTYPE(src->type) == DT_STR ||
1027 DTYPE(src->type) == DT_PATH) {
1028 /* only expand for string as it's the only place where
1029 * we want to expand vars right now */
1030 if (src->init && *src->init) {
1033 len = m_strlen(src->init) + 2;
1034 in.data = p_new(char, len + 1);
1035 snprintf (in.data, len, "\"%s\"", src->init);
1038 mutt_extract_token (&token, &in, 0);
1039 if (token.data && *token.data)
1040 *dst = m_strdup(token.data);
1042 *dst = m_strdup("");
1044 p_delete(&token.data);
1046 *dst = m_strdup("");
1048 /* for non-string: take value as is */
1049 *dst = m_strdup(src->init);
1053 /* if additional data more == 1, we want to resolve synonyms */
1054 static void mutt_restore_default (const char* name __attribute__ ((unused)),
1055 void* p, unsigned long more) {
1056 char errbuf[STRING];
1057 struct option_t* ptr = (struct option_t*) p;
1060 if (DTYPE (ptr->type) == DT_SYN) {
1063 ptr = hash_find (ConfigOptions, (char*) ptr->data);
1067 if (FuncTable[DTYPE (ptr->type)].opt_fromstr) {
1068 init_expand (&init, ptr);
1069 if (!FuncTable[DTYPE (ptr->type)].opt_fromstr (ptr, init, errbuf,
1071 if (!option (OPTNOCURSES))
1073 fprintf (stderr, _("Invalid default setting for $%s found: \"%s\".\n"
1074 "Please report this error: \"%s\"\n"),
1075 ptr->option, NONULL (init), errbuf);
1081 if (ptr->flags & R_INDEX)
1082 set_option (OPTFORCEREDRAWINDEX);
1083 if (ptr->flags & R_PAGER)
1084 set_option (OPTFORCEREDRAWPAGER);
1085 if (ptr->flags & R_RESORT_SUB)
1086 set_option (OPTSORTSUBTHREADS);
1087 if (ptr->flags & R_RESORT)
1088 set_option (OPTNEEDRESORT);
1089 if (ptr->flags & R_RESORT_INIT)
1090 set_option (OPTRESORTINIT);
1091 if (ptr->flags & R_TREE)
1092 set_option (OPTREDRAWTREE);
1095 static int check_num (const char* option, unsigned long p,
1096 char* errbuf, ssize_t errlen) {
1099 snprintf (errbuf, errlen, _("'%d' is invalid for $%s"), (int) p, option);
1105 static int check_history (const char* option __attribute__ ((unused)), unsigned long p,
1106 char* errbuf, ssize_t errlen) {
1107 if (!check_num ("history", p, errbuf, errlen))
1109 mutt_init_history ();
1113 static int check_special (const char* name, unsigned long val,
1114 char* errbuf, ssize_t errlen) {
1117 for (i = 0; SpecialVars[i].name; i++) {
1118 if (m_strcmp(SpecialVars[i].name, name) == 0) {
1119 return (SpecialVars[i].check (SpecialVars[i].name,
1120 val, errbuf, errlen));
1126 static const struct mapping_t* get_sortmap (struct option_t* option) {
1127 const struct mapping_t* map = NULL;
1129 switch (option->type & DT_SUBTYPE_MASK) {
1131 map = SortAliasMethods;
1133 case DT_SORT_BROWSER:
1134 map = SortBrowserMethods;
1137 map = SortKeyMethods;
1140 map = SortAuxMethods;
1149 #define CHECK_PAGER \
1150 if ((CurrentMenu == MENU_PAGER) && \
1151 (!option || (option->flags & R_RESORT))) \
1153 snprintf (err->data, err->dsize, \
1154 _("Not available in this menu.")); \
1158 static int parse_set (BUFFER * tmp, BUFFER * s, unsigned long data,
1161 int query, unset, inv, reset, r = 0;
1162 struct option_t* option = NULL;
1164 while (MoreArgs (s)) {
1165 /* reset state variables */
1167 unset = data & M_SET_UNSET;
1168 inv = data & M_SET_INV;
1169 reset = data & M_SET_RESET;
1171 if (*s->dptr == '?') {
1175 else if (m_strncmp("no", s->dptr, 2) == 0) {
1179 else if (m_strncmp("inv", s->dptr, 3) == 0) {
1183 else if (*s->dptr == '&') {
1188 /* get the variable name */
1189 mutt_extract_token (tmp, s, M_TOKEN_EQUAL);
1191 /* resolve synonyms */
1192 if ((option = hash_find (ConfigOptions, tmp->data)) != NULL &&
1193 DTYPE (option->type == DT_SYN))
1195 struct option_t* newopt = hash_find (ConfigOptions, (char*) option->data);
1196 syn_t* syn = syn_new();
1197 syn->f = m_strdup(CurRCFile);
1201 syn_list_push(&Synonyms, syn);
1205 if (!option && !(reset && m_strcmp("all", tmp->data) == 0)) {
1206 snprintf (err->data, err->dsize, _("%s: unknown variable"), tmp->data);
1209 s->dptr = vskipspaces(s->dptr);
1212 if (query || unset || inv) {
1213 snprintf (err->data, err->dsize, _("prefix is illegal with reset"));
1217 if (s && *s->dptr == '=') {
1218 snprintf (err->data, err->dsize, _("value is illegal with reset"));
1222 if (!m_strcmp("all", tmp->data)) {
1223 if (CurrentMenu == MENU_PAGER) {
1224 snprintf (err->data, err->dsize, _("Not available in this menu."));
1227 hash_map (ConfigOptions, mutt_restore_default, 1);
1228 set_option (OPTFORCEREDRAWINDEX);
1229 set_option (OPTFORCEREDRAWPAGER);
1230 set_option (OPTSORTSUBTHREADS);
1231 set_option (OPTNEEDRESORT);
1232 set_option (OPTRESORTINIT);
1233 set_option (OPTREDRAWTREE);
1237 mutt_restore_default (NULL, option, 1);
1240 else if (DTYPE (option->type) == DT_BOOL) {
1241 /* XXX this currently ignores the function table
1242 * as we don't get invert and stuff into it */
1243 if (s && *s->dptr == '=') {
1244 if (unset || inv || query) {
1245 snprintf (err->data, err->dsize, "Usage: set variable=yes|no");
1250 mutt_extract_token (tmp, s, 0);
1251 if (ascii_strcasecmp ("yes", tmp->data) == 0)
1253 else if (ascii_strcasecmp ("no", tmp->data) == 0)
1256 snprintf (err->data, err->dsize, "Usage: set variable=yes|no");
1262 bool_to_string (err->data, err->dsize, option);
1268 unset_option (option->data);
1270 toggle_option (option->data);
1272 set_option (option->data);
1274 else if (DTYPE (option->type) == DT_STR ||
1275 DTYPE (option->type) == DT_PATH ||
1276 DTYPE (option->type) == DT_ADDR ||
1277 DTYPE (option->type) == DT_MAGIC ||
1278 DTYPE (option->type) == DT_NUM ||
1279 DTYPE (option->type) == DT_SORT ||
1280 DTYPE (option->type) == DT_RX)
1282 /* XXX maybe we need to get unset into handlers? */
1283 if (DTYPE (option->type) == DT_STR ||
1284 DTYPE (option->type) == DT_PATH ||
1285 DTYPE (option->type) == DT_ADDR)
1289 if (DTYPE (option->type) == DT_ADDR)
1290 address_list_wipe((address_t **) option->data);
1292 p_delete((void **)(void *)&option->data);
1297 if (query || *s->dptr != '=') {
1298 FuncTable[DTYPE (option->type)].opt_tostr
1299 (err->data, err->dsize, option);
1305 mutt_extract_token (tmp, s, 0);
1306 if (!FuncTable[DTYPE (option->type)].opt_fromstr
1307 (option, tmp->data, err->data, err->dsize))
1310 else if (DTYPE (option->type) == DT_QUAD) {
1313 quad_to_string (err->data, err->dsize, option);
1317 if (*s->dptr == '=') {
1320 mutt_extract_token (tmp, s, 0);
1321 if (ascii_strcasecmp ("yes", tmp->data) == 0)
1322 set_quadoption (option->data, M_YES);
1323 else if (ascii_strcasecmp ("no", tmp->data) == 0)
1324 set_quadoption (option->data, M_NO);
1325 else if (ascii_strcasecmp ("ask-yes", tmp->data) == 0)
1326 set_quadoption (option->data, M_ASKYES);
1327 else if (ascii_strcasecmp ("ask-no", tmp->data) == 0)
1328 set_quadoption (option->data, M_ASKNO);
1330 snprintf (err->data, err->dsize, _("'%s' is invalid for $%s\n"),
1331 tmp->data, option->option);
1338 toggle_quadoption (option->data);
1340 set_quadoption (option->data, M_NO);
1342 set_quadoption (option->data, M_YES);
1346 snprintf (err->data, err->dsize, _("%s: unknown type"),
1352 if (option->flags & R_INDEX)
1353 set_option (OPTFORCEREDRAWINDEX);
1354 if (option->flags & R_PAGER)
1355 set_option (OPTFORCEREDRAWPAGER);
1356 if (option->flags & R_RESORT_SUB)
1357 set_option (OPTSORTSUBTHREADS);
1358 if (option->flags & R_RESORT)
1359 set_option (OPTNEEDRESORT);
1360 if (option->flags & R_RESORT_INIT)
1361 set_option (OPTRESORTINIT);
1362 if (option->flags & R_TREE)
1363 set_option (OPTREDRAWTREE);
1370 /* reads the specified initialization file. returns -1 if errors were found
1371 so that we can pause to let the user know... */
1372 static int source_rc (const char *rcfile, BUFFER * err)
1375 int line = 0, rc = 0, conv = 0;
1377 char *linebuf = NULL;
1378 char *currentline = NULL;
1382 if ((f = mutt_open_read (rcfile, &pid)) == NULL) {
1383 snprintf (err->data, err->dsize, "%s: %s", rcfile, strerror (errno));
1388 while ((linebuf = mutt_read_line(linebuf, &buflen, f, &line)) != NULL) {
1389 conv = ConfigCharset && (*ConfigCharset) && MCharset.charset;
1391 currentline = m_strdup(linebuf);
1394 mutt_convert_string (¤tline, ConfigCharset, MCharset.charset, 0);
1397 currentline = linebuf;
1402 if (mutt_parse_rc_line (currentline, &token, err) == -1) {
1403 mutt_error (_("Error in %s, line %d: %s"), rcfile, line, err->data);
1404 if (--rc < -MAXERRS) {
1406 p_delete(¤tline);
1415 p_delete(¤tline);
1417 p_delete(&token.data);
1421 mutt_wait_filter (pid);
1423 /* the muttrc source keyword */
1424 snprintf (err->data, err->dsize,
1425 rc >= -MAXERRS ? _("source: errors in %s")
1426 : _("source: reading aborted due too many errors in %s"),
1435 static int parse_source (BUFFER * tmp, BUFFER * s,
1436 unsigned long data __attribute__ ((unused)),
1439 char path[_POSIX_PATH_MAX];
1443 if (mutt_extract_token (tmp, s, 0) != 0) {
1444 snprintf (err->data, err->dsize, _("source: error at %s"), s->dptr);
1448 m_strcpy(path, sizeof(path), tmp->data);
1449 mutt_expand_path (path, sizeof(path));
1451 rc += source_rc (path, err);
1453 while (MoreArgs (s));
1455 return ((rc < 0) ? -1 : 0);
1458 /* line command to execute
1460 token scratch buffer to be used by parser. caller should free
1461 token->data when finished. the reason for this variable is
1462 to avoid having to allocate and deallocate a lot of memory
1463 if we are parsing many lines. the caller can pass in the
1464 memory to use, which avoids having to create new space for
1465 every call to this function.
1467 err where to write error messages */
1468 int mutt_parse_rc_line (const char *line, BUFFER * token, BUFFER * err)
1474 expn.data = expn.dptr = line;
1475 expn.dsize = m_strlen(line);
1479 expn.dptr = vskipspaces(expn.dptr);
1480 while (*expn.dptr) {
1481 if (*expn.dptr == '#')
1482 break; /* rest of line is a comment */
1483 if (*expn.dptr == ';') {
1487 mutt_extract_token (token, &expn, 0);
1488 for (i = 0; Commands[i].name; i++) {
1489 if (!m_strcmp(token->data, Commands[i].name)) {
1490 if (Commands[i].func (token, &expn, Commands[i].data, err) != 0)
1495 if (!Commands[i].name) {
1496 snprintf (err->data, err->dsize, _("%s: unknown command"),
1497 NONULL (token->data));
1504 p_delete(&expn.data);
1509 #define NUMVARS (sizeof(MuttVars)/sizeof(MuttVars[0]))
1510 #define NUMCOMMANDS (sizeof(Commands)/sizeof(Commands[0]))
1511 /* initial string that starts completion. No telling how much crap
1512 * the user has typed so far. Allocate LONG_STRING just to be sure! */
1513 char User_typed[LONG_STRING] = { 0 };
1515 int Num_matched = 0; /* Number of matches for completion */
1516 char Completed[STRING] = { 0 }; /* completed string (command or variable) */
1517 const char *Matches[MAX (NUMVARS, NUMCOMMANDS) + 1]; /* all the matches + User_typed */
1519 /* helper function for completion. Changes the dest buffer if
1520 necessary/possible to aid completion.
1521 dest == completion result gets here.
1522 src == candidate for completion.
1523 try == user entered data for completion.
1524 len == length of dest buffer.
1526 static void candidate (char *dest, char *try, const char *src, int len)
1530 if (strstr (src, try) == src) {
1531 Matches[Num_matched++] = src;
1533 m_strcpy(dest, len, src);
1535 for (l = 0; src[l] && src[l] == dest[l]; l++);
1541 int mutt_command_complete (char *buffer, ssize_t len, int pos, int numtabs)
1545 int spaces; /* keep track of the number of leading spaces on the line */
1547 buffer = vskipspaces(buffer);
1548 spaces = buffer - pt;
1550 pt = buffer + pos - spaces;
1551 while ((pt > buffer) && !isspace ((unsigned char) *pt))
1554 if (pt == buffer) { /* complete cmd */
1555 /* first TAB. Collect all the matches */
1558 m_strcpy(User_typed, sizeof(User_typed), pt);
1559 p_clear(Matches, countof(Matches));
1560 p_clear(Completed, countof(Completed));
1561 for (num = 0; Commands[num].name; num++)
1562 candidate (Completed, User_typed, Commands[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 /* return the completed command */
1585 m_strcpy(buffer, len - spaces, Completed);
1587 else if (!m_strncmp(buffer, "set", 3)
1588 || !m_strncmp(buffer, "unset", 5)
1589 || !m_strncmp(buffer, "reset", 5)
1590 || !m_strncmp(buffer, "toggle", 6)) { /* complete variables */
1591 const char *prefixes[] = { "no", "inv", "?", "&", NULL };
1594 /* loop through all the possible prefixes (no, inv, ...) */
1595 if (!m_strncmp(buffer, "set", 3)) {
1596 for (num = 0; prefixes[num]; num++) {
1597 if (!m_strncmp(pt, prefixes[num], m_strlen(prefixes[num]))) {
1598 pt += m_strlen(prefixes[num]);
1604 /* first TAB. Collect all the matches */
1607 m_strcpy(User_typed, sizeof(User_typed), pt);
1608 p_clear(Matches, countof(Matches));
1609 p_clear(Completed, countof(Completed));
1610 for (num = 0; MuttVars[num].option; num++)
1611 candidate(Completed, User_typed, MuttVars[num].option,
1613 Matches[Num_matched++] = User_typed;
1615 /* All matches are stored. Longest non-ambiguous string is ""
1616 * i.e. dont change 'buffer'. Fake successful return this time */
1617 if (User_typed[0] == 0)
1621 if (Completed[0] == 0 && User_typed[0])
1624 /* Num_matched will _always_ be atleast 1 since the initial
1625 * user-typed string is always stored */
1626 if (numtabs == 1 && Num_matched == 2)
1627 snprintf (Completed, sizeof(Completed), "%s", Matches[0]);
1628 else if (numtabs > 1 && Num_matched > 2)
1629 /* cycle thru all the matches */
1630 snprintf (Completed, sizeof(Completed), "%s",
1631 Matches[(numtabs - 2) % Num_matched]);
1633 m_strcpy(pt, buffer + len - pt - spaces, Completed);
1635 else if (!m_strncmp(buffer, "exec", 4)) {
1636 struct binding_t *menu = km_get_table (CurrentMenu);
1638 if (!menu && CurrentMenu != MENU_PAGER)
1642 /* first TAB. Collect all the matches */
1645 m_strcpy(User_typed, sizeof(User_typed), pt);
1646 p_clear(Matches, countof(Matches));
1647 p_clear(Completed, countof(Completed));
1648 for (num = 0; menu[num].name; num++)
1649 candidate (Completed, User_typed, menu[num].name, sizeof(Completed));
1650 /* try the generic menu */
1651 if (Completed[0] == 0 && CurrentMenu != MENU_PAGER) {
1653 for (num = 0; menu[num].name; num++)
1654 candidate (Completed, User_typed, menu[num].name,
1657 Matches[Num_matched++] = User_typed;
1659 /* All matches are stored. Longest non-ambiguous string is ""
1660 * i.e. dont change 'buffer'. Fake successful return this time */
1661 if (User_typed[0] == 0)
1665 if (Completed[0] == 0 && User_typed[0])
1668 /* Num_matched will _always_ be atleast 1 since the initial
1669 * user-typed string is always stored */
1670 if (numtabs == 1 && Num_matched == 2)
1671 snprintf (Completed, sizeof(Completed), "%s", Matches[0]);
1672 else if (numtabs > 1 && Num_matched > 2)
1673 /* cycle thru all the matches */
1674 snprintf (Completed, sizeof(Completed), "%s",
1675 Matches[(numtabs - 2) % Num_matched]);
1677 m_strcpy(pt, buffer + len - pt - spaces, Completed);
1685 int mutt_var_value_complete (char *buffer, ssize_t len, int pos)
1687 char var[STRING], *pt = buffer;
1689 struct option_t* option = NULL;
1694 buffer = vskipspaces(buffer);
1695 spaces = buffer - pt;
1697 pt = buffer + pos - spaces;
1698 while ((pt > buffer) && !isspace ((unsigned char) *pt))
1700 pt++; /* move past the space */
1701 if (*pt == '=') /* abort if no var before the '=' */
1704 if (m_strncmp(buffer, "set", 3) == 0) {
1705 m_strcpy(var, sizeof(var), pt);
1706 /* ignore the trailing '=' when comparing */
1707 var[m_strlen(var) - 1] = 0;
1708 if (!(option = hash_find (ConfigOptions, var)))
1709 return 0; /* no such variable. */
1711 char tmp[LONG_STRING], tmp2[LONG_STRING];
1713 ssize_t dlen = buffer + len - pt - spaces;
1714 const char *vals[] = { "no", "yes", "ask-no", "ask-yes" };
1718 if ((DTYPE (option->type) == DT_STR) ||
1719 (DTYPE (option->type) == DT_PATH) ||
1720 (DTYPE (option->type) == DT_RX)) {
1721 m_strcpy(tmp, sizeof(tmp), NONULL(*((char **)option->data)));
1722 if (DTYPE (option->type) == DT_PATH)
1723 mutt_pretty_mailbox (tmp);
1725 else if (DTYPE (option->type) == DT_ADDR) {
1726 rfc822_addrcat(tmp, sizeof(tmp), *((address_t **) option->data), 0);
1728 else if (DTYPE (option->type) == DT_QUAD)
1729 m_strcpy(tmp, sizeof(tmp), vals[quadoption(option->data)]);
1730 else if (DTYPE (option->type) == DT_NUM)
1731 snprintf (tmp, sizeof(tmp), "%d", (*((short *) option->data)));
1732 else if (DTYPE (option->type) == DT_SORT) {
1733 const struct mapping_t *map;
1736 switch (option->type & DT_SUBTYPE_MASK) {
1738 map = SortAliasMethods;
1740 case DT_SORT_BROWSER:
1741 map = SortBrowserMethods;
1744 map = SortKeyMethods;
1750 p = mutt_getnamebyvalue(*((short *) option->data) & SORT_MASK, map);
1751 snprintf(tmp, sizeof(tmp), "%s%s%s",
1752 (*((short *)option->data) & SORT_REVERSE) ? "reverse-" : "",
1753 (*((short *)option->data) & SORT_LAST) ? "last-" : "", p);
1755 else if (DTYPE (option->type) == DT_MAGIC) {
1757 switch (DefaultMagic) {
1773 m_strcpy(tmp, sizeof(tmp), p);
1775 else if (DTYPE (option->type) == DT_BOOL)
1776 m_strcpy(tmp, sizeof(tmp), option(option->data) ? "yes" : "no");
1780 for (s = tmp, d = tmp2; *s && (d - tmp2) < ssizeof(tmp2) - 2;) {
1781 if (*s == '\\' || *s == '"')
1787 m_strcpy(tmp, sizeof(tmp), pt);
1788 snprintf (pt, dlen, "%s\"%s\"", tmp, tmp2);
1796 /* Implement the -Q command line flag */
1797 int mutt_query_variables (string_list_t * queries)
1801 char errbuff[STRING];
1802 char command[STRING];
1810 err.dsize = sizeof(errbuff);
1812 for (p = queries; p; p = p->next) {
1813 snprintf (command, sizeof(command), "set ?%s\n", p->data);
1814 if (mutt_parse_rc_line (command, &token, &err) == -1) {
1815 fprintf (stderr, "%s\n", err.data);
1816 p_delete(&token.data);
1819 printf ("%s\n", err.data);
1822 p_delete(&token.data);
1826 static int mutt_execute_commands (string_list_t * p)
1829 char errstr[STRING];
1833 err.dsize = sizeof(errstr);
1835 for (; p; p = p->next) {
1836 if (mutt_parse_rc_line (p->data, &token, &err) != 0) {
1837 fprintf (stderr, _("Error in command line: %s\n"), err.data);
1838 p_delete(&token.data);
1842 p_delete(&token.data);
1846 void mutt_init (int skip_sys_rc, string_list_t * commands)
1850 char buffer[STRING], error[STRING];
1851 int default_rc = 0, need_pause = 0;
1857 err.dsize = sizeof(error);
1859 ConfigOptions = hash_new (sizeof(MuttVars) * 2, 0);
1860 for (i = 0; MuttVars[i].option; i++) {
1861 hash_insert (ConfigOptions, MuttVars[i].option, &MuttVars[i]);
1865 * XXX - use something even more difficult to predict?
1867 snprintf (AttachmentMarker, sizeof(AttachmentMarker),
1868 "\033]9;%ld\a", (long) time (NULL));
1871 /* Get some information about the user */
1872 if ((pw = getpwuid (getuid ()))) {
1874 mutt_gecos_name(rnbuf, sizeof(rnbuf), pw, MCore.gecos_mask);
1875 Realname = m_strdup(rnbuf);
1883 if ((f = safe_fopen (SYSCONFDIR "/nntpserver", "r"))) {
1885 fgets (buffer, sizeof(buffer), f);
1886 p = vskipspaces(buffer);
1888 while (*q && !isspace(*q))
1891 NewsServer = m_strdup(p);
1895 if ((p = getenv ("NNTPSERVER")))
1896 NewsServer = m_strdup(p);
1899 if ((p = getenv("MAIL") ?: getenv("MAILDIR"))) {
1900 Spoolfile = m_strdup(p);
1903 mutt_concat_path(buffer, sizeof(buffer), NONULL(MCore.homedir), MAILPATH);
1905 mutt_concat_path(buffer, sizeof(buffer), MAILPATH, NONULL(MCore.username));
1907 Spoolfile = m_strdup(buffer);
1910 if ((p = getenv ("REPLYTO")) != NULL) {
1913 snprintf (buffer, sizeof(buffer), "Reply-To: %s", p);
1916 buf.data = buf.dptr = buffer;
1917 buf.dsize = m_strlen(buffer);
1920 parse_my_hdr (&token, &buf, 0, &err);
1921 p_delete(&token.data);
1924 if ((p = getenv ("EMAIL")) != NULL)
1925 From = rfc822_parse_adrlist (NULL, p);
1927 /* Set standard defaults */
1928 hash_map (ConfigOptions, mutt_set_default, 0);
1929 hash_map (ConfigOptions, mutt_restore_default, 0);
1931 CurrentMenu = MENU_MAIN;
1934 /* Unset suspend by default if we're the session leader */
1935 if (getsid (0) == getpid ())
1936 unset_option (OPTSUSPEND);
1939 mutt_init_history ();
1942 snprintf (buffer, sizeof(buffer), "%s/.madmuttrc", NONULL(MCore.homedir));
1943 if (access (buffer, F_OK) == -1)
1944 snprintf (buffer, sizeof(buffer), "%s/.madmutt/madmuttrc",
1945 NONULL(MCore.homedir));
1948 Muttrc = m_strdup(buffer);
1951 m_strcpy(buffer, sizeof(buffer), Muttrc);
1953 mutt_expand_path (buffer, sizeof(buffer));
1954 Muttrc = m_strdup(buffer);
1957 /* Process the global rc file if it exists and the user hasn't explicity
1958 requested not to via "-n". */
1960 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc-%s", SYSCONFDIR,
1962 if (access (buffer, F_OK) == -1)
1963 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc", SYSCONFDIR);
1964 if (access (buffer, F_OK) == -1)
1965 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc-%s", PKGDATADIR,
1967 if (access (buffer, F_OK) == -1)
1968 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc", PKGDATADIR);
1969 if (access (buffer, F_OK) != -1) {
1970 if (source_rc (buffer, &err) != 0) {
1971 fputs (err.data, stderr);
1972 fputc ('\n', stderr);
1978 /* Read the user's initialization file. */
1979 if (access (Muttrc, F_OK) != -1) {
1980 if (!option (OPTNOCURSES))
1982 if (source_rc (Muttrc, &err) != 0) {
1983 fputs (err.data, stderr);
1984 fputc ('\n', stderr);
1988 else if (!default_rc) {
1989 /* file specified by -F does not exist */
1990 snprintf (buffer, sizeof(buffer), "%s: %s", Muttrc, strerror (errno));
1991 mutt_endwin (buffer);
1996 snprintf(buffer, sizeof(buffer), "%s/.madmutt.lua", NONULL(MCore.homedir));
1997 if (access(buffer, F_OK) < 0)
1998 snprintf(buffer, sizeof(buffer), "%s/.madmutt/cfg.lua", NONULL(MCore.homedir));
1999 if (!access(buffer, F_OK)) {
2000 need_pause = luaM_wrap(mutt_error, luaM_dofile(buffer));
2004 if (mutt_execute_commands (commands) != 0)
2007 /* warn about synonym variables */
2011 fprintf (stderr, _("Warning: the following synonym variables were found:\n"));
2013 for (syn = Synonyms; syn; syn = syn->next) {
2014 fprintf(stderr, "$%s ($%s should be used) (%s:%d)\n",
2015 syn->o ? NONULL(syn->o->option) : "",
2016 syn->n ? NONULL(syn->n->option) : "",
2017 NONULL(syn->f), syn->l);
2019 fprintf (stderr, _("Warning: synonym variables are scheduled"
2020 " for removal.\n"));
2021 syn_list_wipe(&Synonyms);
2025 if (need_pause && !option (OPTNOCURSES)) {
2026 if (mutt_any_key_to_continue (NULL) == -1)
2031 int mutt_get_hook_type (const char *name)
2033 struct command_t *c;
2035 for (c = Commands; c->name; c++)
2036 if (c->func == mutt_parse_hook && ascii_strcasecmp (c->name, name) == 0)
2041 /* dump out the value of all the variables we have */
2042 int mutt_dump_variables (int full) {
2045 /* get all non-synonyms into list... */
2046 for (i = 0; MuttVars[i].option; i++) {
2047 struct option_t *option = MuttVars + i;
2048 char buf[LONG_STRING];
2050 if (DTYPE(option->type) == DT_SYN)
2054 mutt_option_value(option->option, buf, sizeof(buf));
2055 if (!m_strcmp(buf, option->init))
2060 FuncTable[DTYPE(option->type)].opt_tostr(buf, sizeof(buf), option);
2061 printf ("%s\n", buf);
2064 printf ("\n# vi""m:set ft=muttrc:\n");