+/*
+ * prototypes
+ */
+static int mutt_option_index (char*);
+static const struct mapping_t* get_sortmap (int idx);
+
+/* for synonym warning reports: synonym found during parsing */
+typedef struct {
+ char* f; /* file */
+ int l; /* line */
+ int n; /* new name (index) */
+ int o; /* old name (index) */
+} syn_t;
+
+/* for synonym warning reports: list of synonyms found */
+static list2_t* Synonyms;
+/* for synonym warning reports: current rc file */
+static const char* CurRCFile = NULL;
+/* for synonym warning reports: current rc line */
+static int CurRCLine = 0;
+
+/* prototypes for checking for special vars */
+static int check_dsn_return (const char*);
+static int check_dsn_notify (const char*);
+
+/* variable <-> sanity check function mappings */
+static struct {
+ const char* name;
+ int (*check) (const char*);
+} SpecialVars[] = {
+ { "dsn_notify", check_dsn_notify },
+ { "dsn_return", check_dsn_return },
+#if defined (USE_LIBESMTP) && (defined (USE_SSL) || defined (USE_GNUTLS))
+ { "smtp_use_tls", mutt_libesmtp_check_usetls },
+#endif
+ /* last */
+ { NULL, NULL }
+};
+
+/* protos for config type handles */
+static void bool_to_string (char* dst, size_t dstlen, int idx);
+static void num_to_string (char* dst, size_t dstlen, int idx);
+static void str_to_string (char* dst, size_t dstlen, int idx);
+static void quad_to_string (char* dst, size_t dstlen, int idx);
+static void sort_to_string (char* dst, size_t dstlen, int idx);
+static void rx_to_string (char* dst, size_t dstlen, int idx);
+static void magic_to_string (char* dst, size_t dstlen, int idx);
+static void syn_to_string (char* dst, size_t dstlen, int idx);
+static void addr_to_string (char* dst, size_t dstlen, int idx);
+
+static struct {
+ unsigned short type;
+ void (*opt_to_string) (char* dst, size_t dstlen, int idx);
+} FuncTable[] = {
+ { 0, NULL }, /* there's no DT_ type with 0 */
+ { DT_BOOL, bool_to_string },
+ { DT_NUM, num_to_string },
+ { DT_STR, str_to_string },
+ { DT_PATH, str_to_string },
+ { DT_QUAD, quad_to_string },
+ { DT_SORT, sort_to_string },
+ { DT_RX, rx_to_string },
+ { DT_MAGIC, magic_to_string },
+ { DT_SYN, syn_to_string },
+ { DT_ADDR, addr_to_string }
+};
+
+static void bool_to_string (char* dst, size_t dstlen, int idx) {
+ snprintf (dst, dstlen, "%s=%s", MuttVars[idx].option,
+ MuttVars[idx].data ? "yes" : "no");
+}
+
+static void num_to_string (char* dst, size_t dstlen, int idx) {
+ /* XXX puke */
+ const char* fmt = (idx == mutt_option_index ("umask")) ? "%s=%04o" : "%s=%d";
+ snprintf (dst, dstlen, fmt, MuttVars[idx].option,
+ *((short*) MuttVars[idx].data));
+}
+
+static void str_to_string (char* dst, size_t dstlen, int idx) {
+ snprintf (dst, dstlen, "%s=\"%s\"", MuttVars[idx].option,
+ NONULL (*((char**) MuttVars[idx].data)));
+}
+
+static void quad_to_string (char* dst, size_t dstlen, int idx) {
+ char *vals[] = { "no", "yes", "ask-no", "ask-yes" };
+ snprintf (dst, dstlen, "%s=%s", MuttVars[idx].option,
+ vals[quadoption (MuttVars[idx].data)]);
+}
+
+static void sort_to_string (char* dst, size_t dstlen, int idx) {
+ const struct mapping_t *map = get_sortmap (idx);
+ char* p = NULL;
+
+ if (!map) {
+ snprintf (dst, sizeof (dst), "%s=unknown", MuttVars[idx].option);
+ return;
+ }
+
+ p = mutt_getnamebyvalue (*((short *) MuttVars[idx].data) & SORT_MASK,
+ map);
+
+ snprintf (dst, dstlen, "%s=%s%s%s", MuttVars[idx].option,
+ (*((short *) MuttVars[idx].data) & SORT_REVERSE) ?
+ "reverse-" : "",
+ (*((short *) MuttVars[idx].data) & SORT_LAST) ? "last-" :
+ "", NONULL (p));
+}
+
+static void rx_to_string (char* dst, size_t dstlen, int idx) {
+ rx_t* p = (rx_t*) MuttVars[idx].data;
+ snprintf (dst, dstlen, "%s=\"%s\"", MuttVars[idx].option,
+ NONULL (p->pattern));
+}
+
+static void magic_to_string (char* dst, size_t dstlen, int idx) {
+ const char* s = NULL;
+ switch (MuttVars[idx].data) {
+ case M_MBOX: s = "mbox"; break;
+ case M_MMDF: s = "MMDF"; break;
+ case M_MH: s = "MH"; break;
+ case M_MAILDIR: s = "Maildir"; break;
+ default: s = "unknown"; break;
+ }
+ snprintf (dst, dstlen, "%s=%s", MuttVars[idx].option, s);
+}
+
+static void syn_to_string (char* dst, size_t dstlen, int idx) {
+ int i = mutt_option_index ((char*) MuttVars[idx].data);
+ FuncTable[MuttVars[i].type].opt_to_string (dst, dstlen, i);
+}
+
+static void addr_to_string (char* dst, size_t dstlen, int idx) {
+ char s[STRING];
+ s[0] = '\0';
+ rfc822_write_address (s, sizeof (s), *((ADDRESS**) MuttVars[idx].data), 0);
+ snprintf (dst, dstlen, "%s=\"%s\"", MuttVars[idx].option, NONULL (s));
+}
+
+int mutt_option_value (const char* val, char* dst, size_t dstlen) {
+ int i = mutt_option_index ((char*) val);
+ char* tmp = NULL, *t = NULL;
+ size_t l = 0;
+
+ if (i < 0) {
+ debug_print (1, ("var '%s' not found, i = %d\n", val, i));
+ *dst = '\0';
+ return (0);
+ }
+ tmp = mem_malloc (dstlen+1);
+ FuncTable[DTYPE (MuttVars[i].type)].opt_to_string (tmp, dstlen, i);
+
+ /* as we get things of type $var=value and don't want to bloat the
+ * above "just" for expansion, we do the stripping here */
+ debug_print (1, ("orig == '%s'\n", tmp));
+ t = strchr (tmp, '=');
+ t++;
+ l = str_len (t);
+ if (l >= 2) {
+ if (t[l-1] == '"' && *t == '"') {
+ t[l-1] = '\0';
+ t++;
+ }
+ }
+ memcpy (dst, t, l+1);
+ mem_free (&tmp);
+ debug_print (1, ("stripped == '%s'\n", dst));
+
+ return (1);
+}
+
+/* for synonym warning reports: adds synonym to end of list */
+static void syn_add (int n, int o) {
+ syn_t* tmp = mem_malloc (sizeof (syn_t));
+ tmp->f = str_dup (CurRCFile);
+ tmp->l = CurRCLine;
+ tmp->n = n;
+ tmp->o = o;
+ list_push_back (&Synonyms, tmp);
+}
+
+/* for synonym warning reports: free single item (for list_del()) */
+static void syn_del (void** p) {
+ mem_free(&(*(syn_t**) p)->f);
+ mem_free(p);
+}
+