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 void add_to_list(string_list_t **list, const char *str)
524 /* don't add a NULL or empty string to the list */
525 if (m_strisempty(str))
528 /* check to make sure the item is not already on this list */
530 if (!ascii_strcasecmp(str, (*list)->data))
532 list = &(*list)->next;
535 *list = p_new(string_list_t, 1);
536 (*list)->data = m_strdup(str);
539 static void remove_from_list(string_list_t **l, const char *str)
541 if (!m_strcmp("*", str)) {
542 string_list_wipe(l); /* ``unCMD *'' means delete all current entries */
547 if (!ascii_strcasecmp(str, (*l)->data)) {
548 string_list_t *it = string_list_pop(l);
549 string_item_delete(&it);
556 static int parse_unignore (BUFFER * buf, BUFFER * s,
557 unsigned long data __attribute__ ((unused)),
558 BUFFER * err __attribute__ ((unused)))
561 mutt_extract_token (buf, s, 0);
563 /* don't add "*" to the unignore list */
564 if (m_strcmp (buf->data, "*"))
565 add_to_list (&UnIgnore, buf->data);
567 remove_from_list (&Ignore, buf->data);
568 } while (MoreArgs (s));
573 static int parse_ignore (BUFFER * buf, BUFFER * s,
574 unsigned long data __attribute__ ((unused)),
575 BUFFER * err __attribute__ ((unused)))
578 mutt_extract_token (buf, s, 0);
579 remove_from_list (&UnIgnore, buf->data);
580 add_to_list (&Ignore, buf->data);
581 } while (MoreArgs(s));
585 static int parse_list(BUFFER * buf, BUFFER * s, unsigned long data,
586 BUFFER * err __attribute__ ((unused)))
589 mutt_extract_token (buf, s, 0);
590 add_to_list ((string_list_t **) data, buf->data);
591 } while (MoreArgs(s));
595 static int parse_unlist (BUFFER * buf, BUFFER * s, unsigned long data,
596 BUFFER * err __attribute__ ((unused)))
599 mutt_extract_token (buf, s, 0);
601 * Check for deletion of entire list
603 if (m_strcmp(buf->data, "*") == 0) {
604 string_list_wipe((string_list_t **) data);
607 remove_from_list ((string_list_t **) data, buf->data);
609 while (MoreArgs (s));
614 /* always wise to do what someone else did before */
615 static void _attachments_clean (void) {
617 if (Context && Context->msgcount) {
618 for (i = 0; i < Context->msgcount; i++)
619 Context->hdrs[i]->attach_valid = 0;
623 static int parse_attach_list (BUFFER *buf, BUFFER *s, string_list_t **ldata,
624 BUFFER *err __attribute__ ((unused))) {
626 string_list_t *listp, *lastp;
631 /* Find the last item in the list that data points to. */
633 for (listp = *ldata; listp; listp = listp->next) {
634 a = (ATTACH_MATCH *)listp->data;
639 mutt_extract_token (buf, s, 0);
641 if (!buf->data || *buf->data == '\0')
644 a = p_new(ATTACH_MATCH, 1);
646 /* some cheap hacks that I expect to remove */
647 if (!m_strcasecmp(buf->data, "any"))
648 a->major = m_strdup("*/.*");
649 else if (!m_strcasecmp(buf->data, "none"))
650 a->major = m_strdup("cheap_hack/this_should_never_match");
652 a->major = m_strdup(buf->data);
654 if ((p = strchr(a->major, '/'))) {
659 a->minor = "unknown";
662 len = m_strlen(a->minor);
663 tmpminor = p_new(char, len + 3);
664 m_strcpy(&tmpminor[1], len + 3, a->minor);
666 tmpminor[len+1] = '$';
667 tmpminor[len+2] = '\0';
669 a->major_int = mutt_check_mime_type(a->major);
670 regcomp(&a->minor_rx, tmpminor, REG_ICASE|REG_EXTENDED);
674 listp = p_new(string_list_t, 1);
675 listp->data = (char *)a;
684 while (MoreArgs (s));
686 _attachments_clean();
690 static int parse_unattach_list (BUFFER *buf, BUFFER *s, string_list_t **ldata,
691 BUFFER *err __attribute__ ((unused))) {
693 string_list_t *lp, *lastp, *newlp;
699 mutt_extract_token (buf, s, 0);
701 if (!m_strcasecmp(buf->data, "any"))
702 tmp = m_strdup("*/.*");
703 else if (!m_strcasecmp(buf->data, "none"))
704 tmp = m_strdup("cheap_hack/this_should_never_match");
706 tmp = m_strdup(buf->data);
708 if ((minor = strchr(tmp, '/'))) {
712 minor = m_strdup("unknown");
714 major = mutt_check_mime_type(tmp);
716 /* We must do our own walk here because remove_from_list() will only
717 * remove the string_list_t->data, not anything pointed to by the string_list_t->data. */
719 for(lp = *ldata; lp; ) {
720 a = (ATTACH_MATCH *)lp->data;
721 if (a->major_int == major && !m_strcasecmp(minor, a->minor)) {
722 regfree(&a->minor_rx);
725 /* Relink backward */
727 lastp->next = lp->next;
732 p_delete(&lp->data); /* same as a */
742 while (MoreArgs (s));
745 _attachments_clean();
749 static int print_attach_list (string_list_t *lp, char op, const char *name) {
751 printf("attachments %c%s %s/%s\n", op, name,
752 ((ATTACH_MATCH *)lp->data)->major,
753 ((ATTACH_MATCH *)lp->data)->minor);
760 static int parse_attachments (BUFFER *buf, BUFFER *s,
761 unsigned long data __attribute__ ((unused)),
764 string_list_t **listp;
766 mutt_extract_token(buf, s, 0);
767 if (!buf->data || *buf->data == '\0') {
768 m_strcpy(err->data, err->dsize, _("attachments: no disposition"));
772 category = buf->data;
778 printf("\nCurrent attachments settings:\n\n");
779 print_attach_list(AttachAllow, '+', "A");
780 print_attach_list(AttachExclude, '-', "A");
781 print_attach_list(InlineAllow, '+', "I");
782 print_attach_list(InlineExclude, '-', "I");
783 set_option (OPTFORCEREDRAWINDEX);
784 set_option (OPTFORCEREDRAWPAGER);
785 mutt_any_key_to_continue (NULL);
789 if (op != '+' && op != '-') {
793 if (!m_strncasecmp(category, "attachment", strlen(category))) {
795 listp = &AttachAllow;
797 listp = &AttachExclude;
799 else if (!m_strncasecmp(category, "inline", strlen(category))) {
801 listp = &InlineAllow;
803 listp = &InlineExclude;
805 m_strcpy(err->data, err->dsize, _("attachments: invalid disposition"));
809 return parse_attach_list(buf, s, listp, err);
812 static int parse_unattachments (BUFFER *buf, BUFFER *s, unsigned long data __attribute__ ((unused)), BUFFER *err) {
814 string_list_t **listp;
816 mutt_extract_token(buf, s, 0);
817 if (!buf->data || *buf->data == '\0') {
818 m_strcpy(err->data, err->dsize, _("unattachments: no disposition"));
824 if (op != '+' && op != '-') {
828 if (!m_strncasecmp(p, "attachment", strlen(p))) {
830 listp = &AttachAllow;
832 listp = &AttachExclude;
834 else if (!m_strncasecmp(p, "inline", strlen(p))) {
836 listp = &InlineAllow;
838 listp = &InlineExclude;
841 m_strcpy(err->data, err->dsize, _("unattachments: invalid disposition"));
845 return parse_unattach_list(buf, s, listp, err);
848 static int parse_unalias (BUFFER * buf, BUFFER * s,
849 unsigned long data __attribute__ ((unused)),
850 BUFFER * err __attribute__ ((unused)))
852 alias_t *tmp, **last;
855 mutt_extract_token (buf, s, 0);
857 if (!m_strcmp("*", buf->data) == 0) {
858 if (CurrentMenu == MENU_ALIAS) {
859 for (tmp = Aliases; tmp; tmp = tmp->next)
861 set_option(OPTFORCEREDRAWINDEX);
863 alias_list_wipe(&Aliases);
869 for (last = &Aliases; *last; last = &(*last)->next) {
870 if (!m_strcasecmp(buf->data, (*last)->name)) {
871 if (CurrentMenu == MENU_ALIAS) {
873 set_option (OPTFORCEREDRAWINDEX);
875 tmp = alias_list_pop(last);
881 } while (MoreArgs(s));
886 static int parse_alias (BUFFER * buf, BUFFER * s,
887 unsigned long data __attribute__ ((unused)),
894 m_strcpy(err->data, err->dsize, _("alias: no address"));
898 mutt_extract_token (buf, s, 0);
900 /* check to see if an alias with this name already exists */
901 for (last = &Aliases; *last; last = &(*last)->next) {
902 if (!m_strcasecmp((*last)->name, buf->data))
907 /* create a new alias */
909 (*last)->name = m_strdup(buf->data);
910 /* give the main addressbook code a chance */
911 if (CurrentMenu == MENU_ALIAS)
912 set_option (OPTMENUCALLER);
914 /* override the previous value */
915 address_list_wipe(&(*last)->addr);
916 if (CurrentMenu == MENU_ALIAS)
917 set_option (OPTFORCEREDRAWINDEX);
920 mutt_extract_token(buf, s, M_TOKEN_QUOTE | M_TOKEN_SPACE);
921 (*last)->addr = mutt_parse_adrlist((*last)->addr, buf->data);
922 if (mutt_addrlist_to_idna((*last)->addr, &estr)) {
923 snprintf (err->data, err->dsize,
924 _("Warning: Bad IDN '%s' in alias '%s'.\n"), estr, (*last)->name);
933 parse_unmy_hdr(BUFFER * buf, BUFFER * s,
934 unsigned long data __attribute__ ((unused)),
935 BUFFER * err __attribute__ ((unused)))
938 mutt_extract_token (buf, s, 0);
940 if (!m_strcmp("*", buf->data)) {
941 string_list_wipe(&UserHeader);
943 string_list_t **last = &UserHeader;
944 ssize_t l = m_strlen(buf->data);
946 if (buf->data[l - 1] == ':')
950 if (!ascii_strncasecmp(buf->data, (*last)->data, l)
951 && (*last)->data[l] == ':')
953 string_list_t *tmp = string_list_pop(last);
954 string_item_delete(&tmp);
956 last = &(*last)->next;
960 } while (MoreArgs(s));
965 static int parse_my_hdr (BUFFER * buf, BUFFER * s, unsigned long data __attribute__ ((unused)),
972 mutt_extract_token (buf, s, M_TOKEN_SPACE | M_TOKEN_QUOTE);
973 if ((p = strpbrk (buf->data, ": \t")) == NULL || *p != ':') {
974 m_strcpy(err->data, err->dsize, _("invalid header field"));
977 keylen = p - buf->data + 1;
980 for (tmp = UserHeader;; tmp = tmp->next) {
981 /* see if there is already a field by this name */
982 if (ascii_strncasecmp (buf->data, tmp->data, keylen) == 0) {
983 /* replace the old value */
984 p_delete(&tmp->data);
985 tmp->data = buf->data;
992 tmp->next = string_item_new();
996 tmp = string_item_new();
999 tmp->data = buf->data;
1005 parse_sort (struct option_t* dst, const char *s, const struct mapping_t *map,
1006 char* errbuf, ssize_t errlen) {
1009 if (m_strncmp("reverse-", s, 8) == 0) {
1011 flags = SORT_REVERSE;
1014 if (m_strncmp("last-", s, 5) == 0) {
1019 if ((i = mutt_getvaluebyname (s, map)) == -1) {
1021 snprintf (errbuf, errlen, _("'%s' is invalid for $%s"), s, dst->option);
1025 *((short*) dst->data) = i | flags;
1029 /* if additional data more == 1, we want to resolve synonyms */
1030 static void mutt_set_default(const char *name __attribute__ ((unused)), void* p, unsigned long more)
1032 char buf[LONG_STRING];
1033 struct option_t *ptr = p;
1035 if (DTYPE(ptr->type) == DT_SYN) {
1038 ptr = hash_find(ConfigOptions, (const char *)ptr->data);
1040 if (!ptr || *ptr->init || !FuncTable[DTYPE (ptr->type)].opt_fromstr)
1043 mutt_option_value(ptr->option, buf, sizeof(buf));
1044 if (m_strlen(ptr->init) == 0 && buf && *buf)
1045 ptr->init = m_strdup(buf);
1048 static int init_expand (char** dst, struct option_t* src) {
1054 if (DTYPE(src->type) == DT_STR ||
1055 DTYPE(src->type) == DT_PATH) {
1056 /* only expand for string as it's the only place where
1057 * we want to expand vars right now */
1058 if (src->init && *src->init) {
1061 len = m_strlen(src->init) + 2;
1062 in.data = p_new(char, len + 1);
1063 snprintf (in.data, len, "\"%s\"", src->init);
1066 mutt_extract_token (&token, &in, 0);
1067 if (token.data && *token.data)
1068 *dst = m_strdup(token.data);
1070 *dst = m_strdup("");
1072 p_delete(&token.data);
1074 *dst = m_strdup("");
1076 /* for non-string: take value as is */
1077 *dst = m_strdup(src->init);
1081 /* if additional data more == 1, we want to resolve synonyms */
1082 static void mutt_restore_default (const char* name __attribute__ ((unused)),
1083 void* p, unsigned long more) {
1084 char errbuf[STRING];
1085 struct option_t* ptr = (struct option_t*) p;
1088 if (DTYPE (ptr->type) == DT_SYN) {
1091 ptr = hash_find (ConfigOptions, (char*) ptr->data);
1095 if (FuncTable[DTYPE (ptr->type)].opt_fromstr) {
1096 init_expand (&init, ptr);
1097 if (!FuncTable[DTYPE (ptr->type)].opt_fromstr (ptr, init, errbuf,
1099 if (!option (OPTNOCURSES))
1101 fprintf (stderr, _("Invalid default setting for $%s found: \"%s\".\n"
1102 "Please report this error: \"%s\"\n"),
1103 ptr->option, NONULL (init), errbuf);
1109 if (ptr->flags & R_INDEX)
1110 set_option (OPTFORCEREDRAWINDEX);
1111 if (ptr->flags & R_PAGER)
1112 set_option (OPTFORCEREDRAWPAGER);
1113 if (ptr->flags & R_RESORT_SUB)
1114 set_option (OPTSORTSUBTHREADS);
1115 if (ptr->flags & R_RESORT)
1116 set_option (OPTNEEDRESORT);
1117 if (ptr->flags & R_RESORT_INIT)
1118 set_option (OPTRESORTINIT);
1119 if (ptr->flags & R_TREE)
1120 set_option (OPTREDRAWTREE);
1123 static int check_num (const char* option, unsigned long p,
1124 char* errbuf, ssize_t errlen) {
1127 snprintf (errbuf, errlen, _("'%d' is invalid for $%s"), (int) p, option);
1133 static int check_history (const char* option __attribute__ ((unused)), unsigned long p,
1134 char* errbuf, ssize_t errlen) {
1135 if (!check_num ("history", p, errbuf, errlen))
1137 mutt_init_history ();
1141 static int check_special (const char* name, unsigned long val,
1142 char* errbuf, ssize_t errlen) {
1145 for (i = 0; SpecialVars[i].name; i++) {
1146 if (m_strcmp(SpecialVars[i].name, name) == 0) {
1147 return (SpecialVars[i].check (SpecialVars[i].name,
1148 val, errbuf, errlen));
1154 static const struct mapping_t* get_sortmap (struct option_t* option) {
1155 const struct mapping_t* map = NULL;
1157 switch (option->type & DT_SUBTYPE_MASK) {
1159 map = SortAliasMethods;
1161 case DT_SORT_BROWSER:
1162 map = SortBrowserMethods;
1165 map = SortKeyMethods;
1168 map = SortAuxMethods;
1177 #define CHECK_PAGER \
1178 if ((CurrentMenu == MENU_PAGER) && \
1179 (!option || (option->flags & R_RESORT))) \
1181 snprintf (err->data, err->dsize, \
1182 _("Not available in this menu.")); \
1186 static int parse_set (BUFFER * tmp, BUFFER * s, unsigned long data,
1189 int query, unset, inv, reset, r = 0;
1190 struct option_t* option = NULL;
1192 while (MoreArgs (s)) {
1193 /* reset state variables */
1195 unset = data & M_SET_UNSET;
1196 inv = data & M_SET_INV;
1197 reset = data & M_SET_RESET;
1199 if (*s->dptr == '?') {
1203 else if (m_strncmp("no", s->dptr, 2) == 0) {
1207 else if (m_strncmp("inv", s->dptr, 3) == 0) {
1211 else if (*s->dptr == '&') {
1216 /* get the variable name */
1217 mutt_extract_token (tmp, s, M_TOKEN_EQUAL);
1219 /* resolve synonyms */
1220 if ((option = hash_find (ConfigOptions, tmp->data)) != NULL &&
1221 DTYPE (option->type == DT_SYN))
1223 struct option_t* newopt = hash_find (ConfigOptions, (char*) option->data);
1224 syn_t* syn = syn_new();
1225 syn->f = m_strdup(CurRCFile);
1229 syn_list_push(&Synonyms, syn);
1233 if (!option && !(reset && m_strcmp("all", tmp->data) == 0)) {
1234 snprintf (err->data, err->dsize, _("%s: unknown variable"), tmp->data);
1237 s->dptr = vskipspaces(s->dptr);
1240 if (query || unset || inv) {
1241 snprintf (err->data, err->dsize, _("prefix is illegal with reset"));
1245 if (s && *s->dptr == '=') {
1246 snprintf (err->data, err->dsize, _("value is illegal with reset"));
1250 if (!m_strcmp("all", tmp->data)) {
1251 if (CurrentMenu == MENU_PAGER) {
1252 snprintf (err->data, err->dsize, _("Not available in this menu."));
1255 hash_map (ConfigOptions, mutt_restore_default, 1);
1256 set_option (OPTFORCEREDRAWINDEX);
1257 set_option (OPTFORCEREDRAWPAGER);
1258 set_option (OPTSORTSUBTHREADS);
1259 set_option (OPTNEEDRESORT);
1260 set_option (OPTRESORTINIT);
1261 set_option (OPTREDRAWTREE);
1265 mutt_restore_default (NULL, option, 1);
1268 else if (DTYPE (option->type) == DT_BOOL) {
1269 /* XXX this currently ignores the function table
1270 * as we don't get invert and stuff into it */
1271 if (s && *s->dptr == '=') {
1272 if (unset || inv || query) {
1273 snprintf (err->data, err->dsize, "Usage: set variable=yes|no");
1278 mutt_extract_token (tmp, s, 0);
1279 if (ascii_strcasecmp ("yes", tmp->data) == 0)
1281 else if (ascii_strcasecmp ("no", tmp->data) == 0)
1284 snprintf (err->data, err->dsize, "Usage: set variable=yes|no");
1290 bool_to_string (err->data, err->dsize, option);
1296 unset_option (option->data);
1298 toggle_option (option->data);
1300 set_option (option->data);
1302 else if (DTYPE (option->type) == DT_STR ||
1303 DTYPE (option->type) == DT_PATH ||
1304 DTYPE (option->type) == DT_ADDR ||
1305 DTYPE (option->type) == DT_MAGIC ||
1306 DTYPE (option->type) == DT_NUM ||
1307 DTYPE (option->type) == DT_SORT ||
1308 DTYPE (option->type) == DT_RX)
1310 /* XXX maybe we need to get unset into handlers? */
1311 if (DTYPE (option->type) == DT_STR ||
1312 DTYPE (option->type) == DT_PATH ||
1313 DTYPE (option->type) == DT_ADDR)
1317 if (DTYPE (option->type) == DT_ADDR)
1318 address_list_wipe((address_t **) option->data);
1320 p_delete((void **)(void *)&option->data);
1325 if (query || *s->dptr != '=') {
1326 FuncTable[DTYPE (option->type)].opt_tostr
1327 (err->data, err->dsize, option);
1333 mutt_extract_token (tmp, s, 0);
1334 if (!FuncTable[DTYPE (option->type)].opt_fromstr
1335 (option, tmp->data, err->data, err->dsize))
1338 else if (DTYPE (option->type) == DT_QUAD) {
1341 quad_to_string (err->data, err->dsize, option);
1345 if (*s->dptr == '=') {
1348 mutt_extract_token (tmp, s, 0);
1349 if (ascii_strcasecmp ("yes", tmp->data) == 0)
1350 set_quadoption (option->data, M_YES);
1351 else if (ascii_strcasecmp ("no", tmp->data) == 0)
1352 set_quadoption (option->data, M_NO);
1353 else if (ascii_strcasecmp ("ask-yes", tmp->data) == 0)
1354 set_quadoption (option->data, M_ASKYES);
1355 else if (ascii_strcasecmp ("ask-no", tmp->data) == 0)
1356 set_quadoption (option->data, M_ASKNO);
1358 snprintf (err->data, err->dsize, _("'%s' is invalid for $%s\n"),
1359 tmp->data, option->option);
1366 toggle_quadoption (option->data);
1368 set_quadoption (option->data, M_NO);
1370 set_quadoption (option->data, M_YES);
1374 snprintf (err->data, err->dsize, _("%s: unknown type"),
1380 if (option->flags & R_INDEX)
1381 set_option (OPTFORCEREDRAWINDEX);
1382 if (option->flags & R_PAGER)
1383 set_option (OPTFORCEREDRAWPAGER);
1384 if (option->flags & R_RESORT_SUB)
1385 set_option (OPTSORTSUBTHREADS);
1386 if (option->flags & R_RESORT)
1387 set_option (OPTNEEDRESORT);
1388 if (option->flags & R_RESORT_INIT)
1389 set_option (OPTRESORTINIT);
1390 if (option->flags & R_TREE)
1391 set_option (OPTREDRAWTREE);
1398 /* reads the specified initialization file. returns -1 if errors were found
1399 so that we can pause to let the user know... */
1400 static int source_rc (const char *rcfile, BUFFER * err)
1403 int line = 0, rc = 0, conv = 0;
1405 char *linebuf = NULL;
1406 char *currentline = NULL;
1410 if ((f = mutt_open_read (rcfile, &pid)) == NULL) {
1411 snprintf (err->data, err->dsize, "%s: %s", rcfile, strerror (errno));
1416 while ((linebuf = mutt_read_line(linebuf, &buflen, f, &line)) != NULL) {
1417 conv = ConfigCharset && (*ConfigCharset) && MCharset.charset;
1419 currentline = m_strdup(linebuf);
1422 mutt_convert_string (¤tline, ConfigCharset, MCharset.charset, 0);
1425 currentline = linebuf;
1430 if (mutt_parse_rc_line (currentline, &token, err) == -1) {
1431 mutt_error (_("Error in %s, line %d: %s"), rcfile, line, err->data);
1432 if (--rc < -MAXERRS) {
1434 p_delete(¤tline);
1443 p_delete(¤tline);
1445 p_delete(&token.data);
1449 mutt_wait_filter (pid);
1451 /* the muttrc source keyword */
1452 snprintf (err->data, err->dsize,
1453 rc >= -MAXERRS ? _("source: errors in %s")
1454 : _("source: reading aborted due too many errors in %s"),
1463 static int parse_source (BUFFER * tmp, BUFFER * s,
1464 unsigned long data __attribute__ ((unused)),
1467 char path[_POSIX_PATH_MAX];
1471 if (mutt_extract_token (tmp, s, 0) != 0) {
1472 snprintf (err->data, err->dsize, _("source: error at %s"), s->dptr);
1476 m_strcpy(path, sizeof(path), tmp->data);
1477 mutt_expand_path (path, sizeof(path));
1479 rc += source_rc (path, err);
1481 while (MoreArgs (s));
1483 return ((rc < 0) ? -1 : 0);
1486 /* line command to execute
1488 token scratch buffer to be used by parser. caller should free
1489 token->data when finished. the reason for this variable is
1490 to avoid having to allocate and deallocate a lot of memory
1491 if we are parsing many lines. the caller can pass in the
1492 memory to use, which avoids having to create new space for
1493 every call to this function.
1495 err where to write error messages */
1496 int mutt_parse_rc_line (const char *line, BUFFER * token, BUFFER * err)
1502 expn.data = expn.dptr = line;
1503 expn.dsize = m_strlen(line);
1507 expn.dptr = vskipspaces(expn.dptr);
1508 while (*expn.dptr) {
1509 if (*expn.dptr == '#')
1510 break; /* rest of line is a comment */
1511 if (*expn.dptr == ';') {
1515 mutt_extract_token (token, &expn, 0);
1516 for (i = 0; Commands[i].name; i++) {
1517 if (!m_strcmp(token->data, Commands[i].name)) {
1518 if (Commands[i].func (token, &expn, Commands[i].data, err) != 0)
1523 if (!Commands[i].name) {
1524 snprintf (err->data, err->dsize, _("%s: unknown command"),
1525 NONULL (token->data));
1532 p_delete(&expn.data);
1537 #define NUMVARS (sizeof(MuttVars)/sizeof(MuttVars[0]))
1538 #define NUMCOMMANDS (sizeof(Commands)/sizeof(Commands[0]))
1539 /* initial string that starts completion. No telling how much crap
1540 * the user has typed so far. Allocate LONG_STRING just to be sure! */
1541 char User_typed[LONG_STRING] = { 0 };
1543 int Num_matched = 0; /* Number of matches for completion */
1544 char Completed[STRING] = { 0 }; /* completed string (command or variable) */
1545 const char *Matches[MAX (NUMVARS, NUMCOMMANDS) + 1]; /* all the matches + User_typed */
1547 /* helper function for completion. Changes the dest buffer if
1548 necessary/possible to aid completion.
1549 dest == completion result gets here.
1550 src == candidate for completion.
1551 try == user entered data for completion.
1552 len == length of dest buffer.
1554 static void candidate (char *dest, char *try, const char *src, int len)
1558 if (strstr (src, try) == src) {
1559 Matches[Num_matched++] = src;
1561 m_strcpy(dest, len, src);
1563 for (l = 0; src[l] && src[l] == dest[l]; l++);
1569 int mutt_command_complete (char *buffer, ssize_t len, int pos, int numtabs)
1573 int spaces; /* keep track of the number of leading spaces on the line */
1575 buffer = vskipspaces(buffer);
1576 spaces = buffer - pt;
1578 pt = buffer + pos - spaces;
1579 while ((pt > buffer) && !isspace ((unsigned char) *pt))
1582 if (pt == buffer) { /* complete cmd */
1583 /* first TAB. Collect all the matches */
1586 m_strcpy(User_typed, sizeof(User_typed), pt);
1587 p_clear(Matches, countof(Matches));
1588 p_clear(Completed, countof(Completed));
1589 for (num = 0; Commands[num].name; num++)
1590 candidate (Completed, User_typed, Commands[num].name,
1592 Matches[Num_matched++] = User_typed;
1594 /* All matches are stored. Longest non-ambiguous string is ""
1595 * i.e. dont change 'buffer'. Fake successful return this time */
1596 if (User_typed[0] == 0)
1600 if (Completed[0] == 0 && User_typed[0])
1603 /* Num_matched will _always_ be atleast 1 since the initial
1604 * user-typed string is always stored */
1605 if (numtabs == 1 && Num_matched == 2)
1606 snprintf (Completed, sizeof(Completed), "%s", Matches[0]);
1607 else if (numtabs > 1 && Num_matched > 2)
1608 /* cycle thru all the matches */
1609 snprintf (Completed, sizeof(Completed), "%s",
1610 Matches[(numtabs - 2) % Num_matched]);
1612 /* return the completed command */
1613 m_strcpy(buffer, len - spaces, Completed);
1615 else if (!m_strncmp(buffer, "set", 3)
1616 || !m_strncmp(buffer, "unset", 5)
1617 || !m_strncmp(buffer, "reset", 5)
1618 || !m_strncmp(buffer, "toggle", 6)) { /* complete variables */
1619 const char *prefixes[] = { "no", "inv", "?", "&", NULL };
1622 /* loop through all the possible prefixes (no, inv, ...) */
1623 if (!m_strncmp(buffer, "set", 3)) {
1624 for (num = 0; prefixes[num]; num++) {
1625 if (!m_strncmp(pt, prefixes[num], m_strlen(prefixes[num]))) {
1626 pt += m_strlen(prefixes[num]);
1632 /* first TAB. Collect all the matches */
1635 m_strcpy(User_typed, sizeof(User_typed), pt);
1636 p_clear(Matches, countof(Matches));
1637 p_clear(Completed, countof(Completed));
1638 for (num = 0; MuttVars[num].option; num++)
1639 candidate(Completed, User_typed, MuttVars[num].option,
1641 Matches[Num_matched++] = User_typed;
1643 /* All matches are stored. Longest non-ambiguous string is ""
1644 * i.e. dont change 'buffer'. Fake successful return this time */
1645 if (User_typed[0] == 0)
1649 if (Completed[0] == 0 && User_typed[0])
1652 /* Num_matched will _always_ be atleast 1 since the initial
1653 * user-typed string is always stored */
1654 if (numtabs == 1 && Num_matched == 2)
1655 snprintf (Completed, sizeof(Completed), "%s", Matches[0]);
1656 else if (numtabs > 1 && Num_matched > 2)
1657 /* cycle thru all the matches */
1658 snprintf (Completed, sizeof(Completed), "%s",
1659 Matches[(numtabs - 2) % Num_matched]);
1661 m_strcpy(pt, buffer + len - pt - spaces, Completed);
1663 else if (!m_strncmp(buffer, "exec", 4)) {
1664 struct binding_t *menu = km_get_table (CurrentMenu);
1666 if (!menu && CurrentMenu != MENU_PAGER)
1670 /* first TAB. Collect all the matches */
1673 m_strcpy(User_typed, sizeof(User_typed), pt);
1674 p_clear(Matches, countof(Matches));
1675 p_clear(Completed, countof(Completed));
1676 for (num = 0; menu[num].name; num++)
1677 candidate (Completed, User_typed, menu[num].name, sizeof(Completed));
1678 /* try the generic menu */
1679 if (Completed[0] == 0 && CurrentMenu != MENU_PAGER) {
1681 for (num = 0; menu[num].name; num++)
1682 candidate (Completed, User_typed, menu[num].name,
1685 Matches[Num_matched++] = User_typed;
1687 /* All matches are stored. Longest non-ambiguous string is ""
1688 * i.e. dont change 'buffer'. Fake successful return this time */
1689 if (User_typed[0] == 0)
1693 if (Completed[0] == 0 && User_typed[0])
1696 /* Num_matched will _always_ be atleast 1 since the initial
1697 * user-typed string is always stored */
1698 if (numtabs == 1 && Num_matched == 2)
1699 snprintf (Completed, sizeof(Completed), "%s", Matches[0]);
1700 else if (numtabs > 1 && Num_matched > 2)
1701 /* cycle thru all the matches */
1702 snprintf (Completed, sizeof(Completed), "%s",
1703 Matches[(numtabs - 2) % Num_matched]);
1705 m_strcpy(pt, buffer + len - pt - spaces, Completed);
1713 int mutt_var_value_complete (char *buffer, ssize_t len, int pos)
1715 char var[STRING], *pt = buffer;
1717 struct option_t* option = NULL;
1722 buffer = vskipspaces(buffer);
1723 spaces = buffer - pt;
1725 pt = buffer + pos - spaces;
1726 while ((pt > buffer) && !isspace ((unsigned char) *pt))
1728 pt++; /* move past the space */
1729 if (*pt == '=') /* abort if no var before the '=' */
1732 if (m_strncmp(buffer, "set", 3) == 0) {
1733 m_strcpy(var, sizeof(var), pt);
1734 /* ignore the trailing '=' when comparing */
1735 var[m_strlen(var) - 1] = 0;
1736 if (!(option = hash_find (ConfigOptions, var)))
1737 return 0; /* no such variable. */
1739 char tmp[LONG_STRING], tmp2[LONG_STRING];
1741 ssize_t dlen = buffer + len - pt - spaces;
1742 const char *vals[] = { "no", "yes", "ask-no", "ask-yes" };
1746 if ((DTYPE (option->type) == DT_STR) ||
1747 (DTYPE (option->type) == DT_PATH) ||
1748 (DTYPE (option->type) == DT_RX)) {
1749 m_strcpy(tmp, sizeof(tmp), NONULL(*((char **)option->data)));
1750 if (DTYPE (option->type) == DT_PATH)
1751 mutt_pretty_mailbox (tmp);
1753 else if (DTYPE (option->type) == DT_ADDR) {
1754 rfc822_addrcat(tmp, sizeof(tmp), *((address_t **) option->data), 0);
1756 else if (DTYPE (option->type) == DT_QUAD)
1757 m_strcpy(tmp, sizeof(tmp), vals[quadoption(option->data)]);
1758 else if (DTYPE (option->type) == DT_NUM)
1759 snprintf (tmp, sizeof(tmp), "%d", (*((short *) option->data)));
1760 else if (DTYPE (option->type) == DT_SORT) {
1761 const struct mapping_t *map;
1764 switch (option->type & DT_SUBTYPE_MASK) {
1766 map = SortAliasMethods;
1768 case DT_SORT_BROWSER:
1769 map = SortBrowserMethods;
1772 map = SortKeyMethods;
1778 p = mutt_getnamebyvalue(*((short *) option->data) & SORT_MASK, map);
1779 snprintf(tmp, sizeof(tmp), "%s%s%s",
1780 (*((short *)option->data) & SORT_REVERSE) ? "reverse-" : "",
1781 (*((short *)option->data) & SORT_LAST) ? "last-" : "", p);
1783 else if (DTYPE (option->type) == DT_MAGIC) {
1785 switch (DefaultMagic) {
1801 m_strcpy(tmp, sizeof(tmp), p);
1803 else if (DTYPE (option->type) == DT_BOOL)
1804 m_strcpy(tmp, sizeof(tmp), option(option->data) ? "yes" : "no");
1808 for (s = tmp, d = tmp2; *s && (d - tmp2) < ssizeof(tmp2) - 2;) {
1809 if (*s == '\\' || *s == '"')
1815 m_strcpy(tmp, sizeof(tmp), pt);
1816 snprintf (pt, dlen, "%s\"%s\"", tmp, tmp2);
1824 /* Implement the -Q command line flag */
1825 int mutt_query_variables (string_list_t * queries)
1829 char errbuff[STRING];
1830 char command[STRING];
1838 err.dsize = sizeof(errbuff);
1840 for (p = queries; p; p = p->next) {
1841 snprintf (command, sizeof(command), "set ?%s\n", p->data);
1842 if (mutt_parse_rc_line (command, &token, &err) == -1) {
1843 fprintf (stderr, "%s\n", err.data);
1844 p_delete(&token.data);
1847 printf ("%s\n", err.data);
1850 p_delete(&token.data);
1854 static int mutt_execute_commands (string_list_t * p)
1857 char errstr[STRING];
1861 err.dsize = sizeof(errstr);
1863 for (; p; p = p->next) {
1864 if (mutt_parse_rc_line (p->data, &token, &err) != 0) {
1865 fprintf (stderr, _("Error in command line: %s\n"), err.data);
1866 p_delete(&token.data);
1870 p_delete(&token.data);
1874 void mutt_init (int skip_sys_rc, string_list_t * commands)
1878 char buffer[STRING], error[STRING];
1879 int default_rc = 0, need_pause = 0;
1885 err.dsize = sizeof(error);
1887 ConfigOptions = hash_new (sizeof(MuttVars) * 2, 0);
1888 for (i = 0; MuttVars[i].option; i++) {
1889 hash_insert (ConfigOptions, MuttVars[i].option, &MuttVars[i]);
1893 * XXX - use something even more difficult to predict?
1895 snprintf (AttachmentMarker, sizeof(AttachmentMarker),
1896 "\033]9;%ld\a", (long) time (NULL));
1899 /* Get some information about the user */
1900 if ((pw = getpwuid (getuid ()))) {
1902 mutt_gecos_name(rnbuf, sizeof(rnbuf), pw, MCore.gecos_mask);
1903 Realname = m_strdup(rnbuf);
1911 if ((f = safe_fopen (SYSCONFDIR "/nntpserver", "r"))) {
1913 fgets (buffer, sizeof(buffer), f);
1914 p = vskipspaces(buffer);
1916 while (*q && !isspace(*q))
1919 NewsServer = m_strdup(p);
1923 if ((p = getenv ("NNTPSERVER")))
1924 NewsServer = m_strdup(p);
1927 if ((p = getenv("MAIL") ?: getenv("MAILDIR"))) {
1928 Spoolfile = m_strdup(p);
1931 mutt_concat_path(buffer, sizeof(buffer), NONULL(MCore.homedir), MAILPATH);
1933 mutt_concat_path(buffer, sizeof(buffer), MAILPATH, NONULL(MCore.username));
1935 Spoolfile = m_strdup(buffer);
1938 if ((p = getenv ("REPLYTO")) != NULL) {
1941 snprintf (buffer, sizeof(buffer), "Reply-To: %s", p);
1944 buf.data = buf.dptr = buffer;
1945 buf.dsize = m_strlen(buffer);
1948 parse_my_hdr (&token, &buf, 0, &err);
1949 p_delete(&token.data);
1952 if ((p = getenv ("EMAIL")) != NULL)
1953 From = rfc822_parse_adrlist (NULL, p);
1955 /* Set standard defaults */
1956 hash_map (ConfigOptions, mutt_set_default, 0);
1957 hash_map (ConfigOptions, mutt_restore_default, 0);
1959 CurrentMenu = MENU_MAIN;
1962 /* Unset suspend by default if we're the session leader */
1963 if (getsid (0) == getpid ())
1964 unset_option (OPTSUSPEND);
1967 mutt_init_history ();
1970 snprintf (buffer, sizeof(buffer), "%s/.madmuttrc", NONULL(MCore.homedir));
1971 if (access (buffer, F_OK) == -1)
1972 snprintf (buffer, sizeof(buffer), "%s/.madmutt/madmuttrc",
1973 NONULL(MCore.homedir));
1976 Muttrc = m_strdup(buffer);
1979 m_strcpy(buffer, sizeof(buffer), Muttrc);
1981 mutt_expand_path (buffer, sizeof(buffer));
1982 Muttrc = m_strdup(buffer);
1985 /* Process the global rc file if it exists and the user hasn't explicity
1986 requested not to via "-n". */
1988 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc-%s", SYSCONFDIR,
1990 if (access (buffer, F_OK) == -1)
1991 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc", SYSCONFDIR);
1992 if (access (buffer, F_OK) == -1)
1993 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc-%s", PKGDATADIR,
1995 if (access (buffer, F_OK) == -1)
1996 snprintf (buffer, sizeof(buffer), "%s/Madmuttrc", PKGDATADIR);
1997 if (access (buffer, F_OK) != -1) {
1998 if (source_rc (buffer, &err) != 0) {
1999 fputs (err.data, stderr);
2000 fputc ('\n', stderr);
2006 /* Read the user's initialization file. */
2007 if (access (Muttrc, F_OK) != -1) {
2008 if (!option (OPTNOCURSES))
2010 if (source_rc (Muttrc, &err) != 0) {
2011 fputs (err.data, stderr);
2012 fputc ('\n', stderr);
2016 else if (!default_rc) {
2017 /* file specified by -F does not exist */
2018 snprintf (buffer, sizeof(buffer), "%s: %s", Muttrc, strerror (errno));
2019 mutt_endwin (buffer);
2024 snprintf(buffer, sizeof(buffer), "%s/.madmutt.lua", NONULL(MCore.homedir));
2025 if (access(buffer, F_OK) < 0)
2026 snprintf(buffer, sizeof(buffer), "%s/.madmutt/cfg.lua", NONULL(MCore.homedir));
2027 if (!access(buffer, F_OK)) {
2028 need_pause = luaM_wrap(mutt_error, luaM_dofile(buffer));
2032 if (mutt_execute_commands (commands) != 0)
2035 /* warn about synonym variables */
2039 fprintf (stderr, _("Warning: the following synonym variables were found:\n"));
2041 for (syn = Synonyms; syn; syn = syn->next) {
2042 fprintf(stderr, "$%s ($%s should be used) (%s:%d)\n",
2043 syn->o ? NONULL(syn->o->option) : "",
2044 syn->n ? NONULL(syn->n->option) : "",
2045 NONULL(syn->f), syn->l);
2047 fprintf (stderr, _("Warning: synonym variables are scheduled"
2048 " for removal.\n"));
2049 syn_list_wipe(&Synonyms);
2053 if (need_pause && !option (OPTNOCURSES)) {
2054 if (mutt_any_key_to_continue (NULL) == -1)
2059 int mutt_get_hook_type (const char *name)
2061 struct command_t *c;
2063 for (c = Commands; c->name; c++)
2064 if (c->func == mutt_parse_hook && ascii_strcasecmp (c->name, name) == 0)
2069 /* dump out the value of all the variables we have */
2070 int mutt_dump_variables (int full) {
2073 /* get all non-synonyms into list... */
2074 for (i = 0; MuttVars[i].option; i++) {
2075 struct option_t *option = MuttVars + i;
2076 char buf[LONG_STRING];
2078 if (DTYPE(option->type) == DT_SYN)
2082 mutt_option_value(option->option, buf, sizeof(buf));
2083 if (!m_strcmp(buf, option->init))
2088 FuncTable[DTYPE(option->type)].opt_tostr(buf, sizeof(buf), option);
2089 printf ("%s\n", buf);
2092 printf ("\n# vi""m:set ft=muttrc:\n");