Line data Source code
1 : /**
2 : * @file
3 : * Dump all the config
4 : *
5 : * @authors
6 : * Copyright (C) 2017-2018 Richard Russon <rich@flatcap.org>
7 : *
8 : * @copyright
9 : * This program is free software: you can redistribute it and/or modify it under
10 : * the terms of the GNU General Public License as published by the Free Software
11 : * Foundation, either version 2 of the License, or (at your option) any later
12 : * version.
13 : *
14 : * This program is distributed in the hope that it will be useful, but WITHOUT
15 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 : * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 : * details.
18 : *
19 : * You should have received a copy of the GNU General Public License along with
20 : * this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : /**
24 : * @page config_dump Dump all the config
25 : *
26 : * Dump all the config items in various formats.
27 : */
28 :
29 : #include "config.h"
30 : #include <stdbool.h>
31 : #include <stdio.h>
32 : #include "mutt/lib.h"
33 : #include "dump.h"
34 : #include "set.h"
35 : #include "subset.h"
36 : #include "types.h"
37 :
38 : void mutt_pretty_mailbox(char *buf, size_t buflen);
39 :
40 : /**
41 : * escape_string - Write a string to a buffer, escaping special characters
42 : * @param buf Buffer to write to
43 : * @param src String to write
44 : * @retval num Bytes written to buffer
45 : */
46 120 : size_t escape_string(struct Buffer *buf, const char *src)
47 : {
48 120 : if (!buf || !src)
49 4 : return 0;
50 :
51 116 : size_t len = 0;
52 944 : for (; *src; src++)
53 : {
54 828 : switch (*src)
55 : {
56 2 : case '\007':
57 2 : len += mutt_buffer_addstr(buf, "\\g");
58 2 : break;
59 2 : case '\n':
60 2 : len += mutt_buffer_addstr(buf, "\\n");
61 2 : break;
62 2 : case '\r':
63 2 : len += mutt_buffer_addstr(buf, "\\r");
64 2 : break;
65 2 : case '\t':
66 2 : len += mutt_buffer_addstr(buf, "\\t");
67 2 : break;
68 820 : default:
69 820 : if ((*src == '\\') || (*src == '"'))
70 4 : len += mutt_buffer_addch(buf, '\\');
71 820 : len += mutt_buffer_addch(buf, src[0]);
72 : }
73 : }
74 116 : return len;
75 : }
76 :
77 : /**
78 : * pretty_var - Escape and stringify a config item value
79 : * @param str String to escape
80 : * @param buf Buffer to write to
81 : * @retval num Number of bytes written to buffer
82 : */
83 118 : size_t pretty_var(const char *str, struct Buffer *buf)
84 : {
85 118 : if (!buf || !str)
86 4 : return 0;
87 :
88 114 : int len = 0;
89 :
90 114 : len += mutt_buffer_addch(buf, '"');
91 114 : len += escape_string(buf, str);
92 114 : len += mutt_buffer_addch(buf, '"');
93 :
94 114 : return len;
95 : }
96 :
97 : /**
98 : * dump_config_neo - Dump the config in the style of NeoMutt
99 : * @param cs Config items
100 : * @param he HashElem representing config item
101 : * @param value Current value of the config item
102 : * @param initial Initial value of the config item
103 : * @param flags Flags, see #ConfigDumpFlags
104 : * @param fp File pointer to write to
105 : */
106 148 : void dump_config_neo(struct ConfigSet *cs, struct HashElem *he, struct Buffer *value,
107 : struct Buffer *initial, ConfigDumpFlags flags, FILE *fp)
108 : {
109 148 : if (!he || !value || !fp)
110 32 : return;
111 :
112 116 : const char *name = he->key.strkey;
113 :
114 116 : if ((flags & CS_DUMP_ONLY_CHANGED) &&
115 28 : (!initial || mutt_str_equal(value->data, initial->data)))
116 : {
117 26 : return;
118 : }
119 :
120 90 : if (he->type == DT_SYNONYM)
121 : {
122 2 : const struct ConfigDef *cdef = he->data;
123 2 : const char *syn = (const char *) cdef->initial;
124 2 : fprintf(fp, "# synonym: %s -> %s\n", name, syn);
125 2 : return;
126 : }
127 :
128 88 : if (flags & CS_DUMP_SHOW_DOCS)
129 : {
130 26 : const struct ConfigDef *cdef = he->data;
131 26 : fprintf(fp, "# %s\n", cdef->docs);
132 : }
133 :
134 88 : bool show_name = !(flags & CS_DUMP_HIDE_NAME);
135 88 : bool show_value = !(flags & CS_DUMP_HIDE_VALUE);
136 :
137 88 : if (show_name && show_value)
138 62 : fprintf(fp, "set ");
139 88 : if (show_name)
140 88 : fprintf(fp, "%s", name);
141 88 : if (show_name && show_value)
142 62 : fprintf(fp, " = ");
143 88 : if (show_value)
144 62 : fprintf(fp, "%s", value->data);
145 88 : if (show_name || show_value)
146 88 : fprintf(fp, "\n");
147 :
148 88 : if (flags & CS_DUMP_SHOW_DEFAULTS)
149 : {
150 28 : const struct ConfigSetType *cst = cs_get_type_def(cs, he->type);
151 28 : if (cst)
152 28 : fprintf(fp, "# %s %s %s\n", cst->name, name, value->data);
153 : }
154 :
155 88 : if (flags & CS_DUMP_SHOW_DOCS)
156 26 : fprintf(fp, "\n");
157 : }
158 :
159 : /**
160 : * dump_config - Write all the config to a file
161 : * @param cs ConfigSet to dump
162 : * @param flags Flags, see #ConfigDumpFlags
163 : * @param fp File to write config to
164 : */
165 14 : bool dump_config(struct ConfigSet *cs, ConfigDumpFlags flags, FILE *fp)
166 : {
167 14 : if (!cs)
168 2 : return false;
169 :
170 12 : struct HashElem *he = NULL;
171 :
172 12 : struct HashElem **list = get_elem_list(cs);
173 12 : if (!list)
174 : return false; /* LCOV_EXCL_LINE */
175 :
176 12 : bool result = true;
177 :
178 12 : struct Buffer value = mutt_buffer_make(256);
179 12 : struct Buffer initial = mutt_buffer_make(256);
180 12 : struct Buffer tmp = mutt_buffer_make(256);
181 :
182 162 : for (size_t i = 0; list[i]; i++)
183 : {
184 150 : mutt_buffer_reset(&value);
185 150 : mutt_buffer_reset(&initial);
186 150 : he = list[i];
187 150 : const int type = DTYPE(he->type);
188 :
189 150 : if ((type == DT_SYNONYM) && !(flags & CS_DUMP_SHOW_SYNONYMS))
190 10 : continue;
191 :
192 140 : if ((he->type & DT_DEPRECATED) && !(flags & CS_DUMP_SHOW_DEPRECATED))
193 10 : continue;
194 :
195 : // if ((type == DT_DISABLED) && !(flags & CS_DUMP_SHOW_DISABLED))
196 : // continue;
197 :
198 130 : if (type != DT_SYNONYM)
199 : {
200 : /* If necessary, get the current value */
201 130 : if ((flags & CS_DUMP_ONLY_CHANGED) || !(flags & CS_DUMP_HIDE_VALUE) ||
202 26 : (flags & CS_DUMP_SHOW_DEFAULTS))
203 : {
204 130 : int rc = cs_he_string_get(cs, he, &value);
205 130 : if (CSR_RESULT(rc) != CSR_SUCCESS)
206 : {
207 : result = false; /* LCOV_EXCL_LINE */
208 : break; /* LCOV_EXCL_LINE */
209 : }
210 :
211 130 : const struct ConfigDef *cdef = he->data;
212 130 : if ((type == DT_STRING) && IS_SENSITIVE(*cdef) &&
213 10 : (flags & CS_DUMP_HIDE_SENSITIVE) && !mutt_buffer_is_empty(&value))
214 : {
215 2 : mutt_buffer_reset(&value);
216 2 : mutt_buffer_addstr(&value, "***");
217 : }
218 :
219 130 : if (((type == DT_PATH) || IS_MAILBOX(he)) && (value.data[0] == '/'))
220 10 : mutt_pretty_mailbox(value.data, value.dsize);
221 :
222 130 : if ((type != DT_BOOL) && (type != DT_NUMBER) && (type != DT_LONG) &&
223 80 : (type != DT_QUAD) && !(flags & CS_DUMP_NO_ESCAPING))
224 : {
225 80 : mutt_buffer_reset(&tmp);
226 80 : pretty_var(value.data, &tmp);
227 80 : mutt_buffer_strcpy(&value, tmp.data);
228 : }
229 : }
230 :
231 : /* If necessary, get the default value */
232 130 : if (flags & (CS_DUMP_ONLY_CHANGED | CS_DUMP_SHOW_DEFAULTS))
233 : {
234 52 : int rc = cs_he_initial_get(cs, he, &initial);
235 52 : if (CSR_RESULT(rc) != CSR_SUCCESS)
236 : {
237 : result = false; /* LCOV_EXCL_LINE */
238 : break; /* LCOV_EXCL_LINE */
239 : }
240 :
241 52 : if (((type == DT_PATH) || IS_MAILBOX(he)) && !(he->type & DT_MAILBOX))
242 4 : mutt_pretty_mailbox(initial.data, initial.dsize);
243 :
244 52 : if ((type != DT_BOOL) && (type != DT_NUMBER) && (type != DT_LONG) &&
245 32 : (type != DT_QUAD) && !(flags & CS_DUMP_NO_ESCAPING))
246 : {
247 32 : mutt_buffer_reset(&tmp);
248 32 : pretty_var(initial.data, &tmp);
249 32 : mutt_buffer_strcpy(&initial, tmp.data);
250 : }
251 : }
252 : }
253 :
254 130 : dump_config_neo(cs, he, &value, &initial, flags, fp);
255 : }
256 :
257 12 : FREE(&list);
258 12 : mutt_buffer_dealloc(&value);
259 12 : mutt_buffer_dealloc(&initial);
260 12 : mutt_buffer_dealloc(&tmp);
261 :
262 12 : return result;
263 : }
|