/src/dovecot/src/lib-var-expand/var-expand.h
Line | Count | Source |
1 | | #ifndef VAR_EXPAND_NEW_H |
2 | | #define VAR_EXPAND_NEW_H |
3 | | |
4 | | /** Variable expansion programs ** |
5 | | |
6 | | A variable expansion program is a set of filters delineated with %{}, |
7 | | or a literal-only program which expands to the string it contains. |
8 | | See https://doc.dovecot.org/latest/core/settings/syntax.html#variable-expansion. |
9 | | |
10 | | The normal usage is to call t_var_expand() to get rendition of a program from |
11 | | data stack memory, or var_expand() if you want to provide the string yourself. |
12 | | The string is appended to, or truncated to where it was on starting on failure. |
13 | | |
14 | | If you need to expand the program multiple times, you should use |
15 | | var_expand_program_create() to create a reusable program chain and then call |
16 | | var_expand_program_execute() to expand it. Since parameters are given to execute |
17 | | you can get the same program executed with different parameters, so you don't |
18 | | have to rebuild the program if your variables are changed. |
19 | | |
20 | | The function var_expand_program_create() parses a string that can contain |
21 | | one or more programs, and chains them together. This is usually what is wanted. |
22 | | |
23 | | There are some cases though when you need to deal with programs one by one, |
24 | | and this is handled by 'var-expand-split.h', and there are a few functions here |
25 | | that do not seem to make much sense alone: |
26 | | |
27 | | The var_expand_program_execute_one() and var_expand_program_has_variable() are |
28 | | such ones. The execute_one() only makes sense to use with individual programs |
29 | | that can be extracted with var_expand_program_template() or |
30 | | var_expand_program_split(), which are in their own header as they have |
31 | | array.h dependency. |
32 | | |
33 | | The var_expand_program_has_variable() can be used for generic purposes too |
34 | | by leaving the first_program_only as FALSE. |
35 | | */ |
36 | | |
37 | | /* Used for getting either prefix:key values, or dynamic values for keys |
38 | | in value tables. |
39 | | |
40 | | Gets key and context, needs to return -1 on error (with error_r set) |
41 | | or 0 on success. value_r *must* be non-null on success. |
42 | | |
43 | | Prefix is removed before calling the function. |
44 | | */ |
45 | | typedef int value_provider_func_t(const char *key, const char **value_r, |
46 | | void *context, const char **error_r); |
47 | | /* Used for escaping values, gets given string to escape and context, |
48 | | must return escaped string. */ |
49 | | typedef const char *var_expand_escape_func_t(const char *str, void *context); |
50 | | |
51 | | struct var_expand_parser_state; |
52 | | struct var_expand_program; |
53 | | |
54 | | #define VAR_EXPAND_TABLE_END { .key = NULL } |
55 | | #define VAR_EXPAND_CONTEXTS_END (void*)var_expand_contexts_end |
56 | | |
57 | | struct var_expand_table { |
58 | | /* Key name, as in %{key} */ |
59 | | const char *key; |
60 | | /* Value to expand into */ |
61 | | const char *value; |
62 | | /* Or function that provides the value */ |
63 | | value_provider_func_t *func; |
64 | | }; |
65 | | |
66 | | struct var_expand_provider { |
67 | | /* key as in %{key:name} */ |
68 | | const char *key; |
69 | | /* function to call to get value */ |
70 | | value_provider_func_t *func; |
71 | | }; |
72 | | |
73 | | extern const void *const var_expand_contexts_end; |
74 | | |
75 | | struct var_expand_params { |
76 | | /* Variables to use, must end with VAR_EXPAND_TABLE_END, |
77 | | asserts that tables_arr is non-NULL. */ |
78 | | const struct var_expand_table *table; |
79 | | /* Providers to use, must end with VAR_EXPAND_TABLE_END, |
80 | | asserts that providers_arr is non-NULL. */ |
81 | | const struct var_expand_provider *providers; |
82 | | /* Multiple var expand tables, must be NULL terminated */ |
83 | | const struct var_expand_table *const *tables_arr; |
84 | | /* Multiple var expand providers, must be NULL terminated */ |
85 | | const struct var_expand_provider *const *providers_arr; |
86 | | /* Function that gets called to escape values */ |
87 | | var_expand_escape_func_t *escape_func; |
88 | | /* Context for escape function */ |
89 | | void *escape_context; |
90 | | /* Contexts for table functions and providers, can be |
91 | | set to NULL if no multiple contexts are needed, then context |
92 | | is defaulted to. |
93 | | |
94 | | Asserts that contexts ends with VAR_EXPAND_CONTEXTS_END. |
95 | | */ |
96 | | void *const *contexts; |
97 | | /* Context for table functions and providers. */ |
98 | | void *context; |
99 | | /* Event for %{event:} expansion, can be NULL. Global event |
100 | | will be attempted if this is NULL. */ |
101 | | struct event *event; |
102 | | }; |
103 | | |
104 | | /* Creates a new expansion program for reusing */ |
105 | | int var_expand_program_create(const char *str, struct var_expand_program **program_r, |
106 | | const char **error_r); |
107 | | /* Lists all seen variables in a program */ |
108 | | const char *const *var_expand_program_variables(const struct var_expand_program *program); |
109 | | /* Checks if the program has a variable, if first_program_only is set, checks the |
110 | | first program only, otherwise it checks the variables using var_expand_program_variables(). |
111 | | |
112 | | The check is done to all filters and parameters on the first program, so it can detect |
113 | | if the variable is used anywhere in the program. |
114 | | */ |
115 | | bool var_expand_program_has_variable(const struct var_expand_program *program, |
116 | | const char *variable, bool first_program_only); |
117 | | /* Dumps the program into a dest for debugging */ |
118 | | void var_expand_program_dump(const struct var_expand_program *program, string_t *dest); |
119 | | /* Executes the program with given params. Params can be left NULL, in which case |
120 | | empty parameters are used. */ |
121 | | int var_expand_program_execute(string_t *dest, const struct var_expand_program *program, |
122 | | const struct var_expand_params *params, |
123 | | const char **error_r) ATTR_NULL(3); |
124 | | /* Execute the first program only */ |
125 | | int var_expand_program_execute_one(string_t *dest, const struct var_expand_program *program, |
126 | | const struct var_expand_params *params, |
127 | | const char **error_r); |
128 | | /* Free up program */ |
129 | | void var_expand_program_free(struct var_expand_program **_program); |
130 | | |
131 | | /* Creates a new program, executes it and frees it. Params can be left NULL, in which |
132 | | case empty parameters are used. */ |
133 | | int var_expand(string_t *dest, const char *str, const struct var_expand_params *params, |
134 | | const char **error_r) ATTR_NULL(3); |
135 | | |
136 | | /* Wrapper for var_expand(), places the result into result_r. */ |
137 | | int t_var_expand(const char *str, const struct var_expand_params *params, |
138 | | const char **result_r, const char **error_r); |
139 | | |
140 | | /* Merge two tables together, keys in table a will be overwritten with keys |
141 | | * from table b in collision. */ |
142 | | struct var_expand_table * |
143 | | var_expand_merge_tables(pool_t pool, const struct var_expand_table *a, |
144 | | const struct var_expand_table *b); |
145 | | |
146 | | /* Returns true if provider is a built-in provider */ |
147 | | bool var_expand_provider_is_builtin(const char *prefix); |
148 | | |
149 | | /* Provides size of a table */ |
150 | | static inline size_t ATTR_PURE |
151 | | var_expand_table_size(const struct var_expand_table *table) |
152 | 0 | { |
153 | 0 | size_t n = 0; |
154 | 0 | while (table != NULL && table[n].key != NULL) |
155 | 0 | n++; |
156 | 0 | return n; |
157 | 0 | } Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_size Unexecuted instantiation: expansion-program.c:var_expand_table_size Unexecuted instantiation: var-expand.c:var_expand_table_size Unexecuted instantiation: var-expand-parser.c:var_expand_table_size Unexecuted instantiation: var-expand-lexer.c:var_expand_table_size Unexecuted instantiation: expansion-parameter.c:var_expand_table_size Unexecuted instantiation: expansion-statement.c:var_expand_table_size Unexecuted instantiation: expansion-filter.c:var_expand_table_size Unexecuted instantiation: expansion-filter-if.c:var_expand_table_size Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_size |
158 | | |
159 | | /* Get table entry by name. Returns NULL if not found. */ |
160 | | static inline struct var_expand_table * |
161 | | var_expand_table_get(struct var_expand_table *table, const char *key) |
162 | 0 | { |
163 | 0 | for (size_t i = 0; table[i].key != NULL; i++) { |
164 | 0 | if (strcmp(table[i].key, key) == 0) { |
165 | 0 | return &(table[i]); |
166 | 0 | } |
167 | 0 | } |
168 | 0 | return NULL; |
169 | 0 | } Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_get Unexecuted instantiation: expansion-program.c:var_expand_table_get Unexecuted instantiation: var-expand.c:var_expand_table_get Unexecuted instantiation: var-expand-parser.c:var_expand_table_get Unexecuted instantiation: var-expand-lexer.c:var_expand_table_get Unexecuted instantiation: expansion-parameter.c:var_expand_table_get Unexecuted instantiation: expansion-statement.c:var_expand_table_get Unexecuted instantiation: expansion-filter.c:var_expand_table_get Unexecuted instantiation: expansion-filter-if.c:var_expand_table_get Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_get |
170 | | |
171 | | /* Set table variable to value. Asserts that key is found. */ |
172 | | static inline void var_expand_table_set_value(struct var_expand_table *table, |
173 | | const char *key, const char *value, |
174 | | const char *file, unsigned int line) |
175 | 0 | { |
176 | 0 | struct var_expand_table *entry = var_expand_table_get(table, key); |
177 | 0 | if (entry != NULL) { |
178 | 0 | i_assert(entry->func == NULL); |
179 | 0 | entry->value = value; |
180 | 0 | } else |
181 | 0 | i_panic("%s:%u No key '%s' in table", file, line, key); |
182 | 0 | } Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_set_value Unexecuted instantiation: expansion-program.c:var_expand_table_set_value Unexecuted instantiation: var-expand.c:var_expand_table_set_value Unexecuted instantiation: var-expand-parser.c:var_expand_table_set_value Unexecuted instantiation: var-expand-lexer.c:var_expand_table_set_value Unexecuted instantiation: expansion-parameter.c:var_expand_table_set_value Unexecuted instantiation: expansion-statement.c:var_expand_table_set_value Unexecuted instantiation: expansion-filter.c:var_expand_table_set_value Unexecuted instantiation: expansion-filter-if.c:var_expand_table_set_value Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_set_value |
183 | | #define var_expand_table_set_value(table, key, value) \ |
184 | | var_expand_table_set_value((table), (key), (value), __FILE__, __LINE__); |
185 | | |
186 | | /* Set table variable function. Asserts that key is found. */ |
187 | | static inline void var_expand_table_set_func(struct var_expand_table *table, |
188 | | const char *key, |
189 | | value_provider_func_t *func, |
190 | | const char *file, unsigned int line) |
191 | 0 | { |
192 | 0 | struct var_expand_table *entry = var_expand_table_get(table, key); |
193 | 0 | if (entry != NULL) { |
194 | 0 | i_assert(entry->value == NULL); |
195 | 0 | entry->func = func; |
196 | 0 | } else |
197 | 0 | i_panic("%s:%u No key '%s' in table", file, line, key); |
198 | 0 | } Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_set_func Unexecuted instantiation: expansion-program.c:var_expand_table_set_func Unexecuted instantiation: var-expand.c:var_expand_table_set_func Unexecuted instantiation: var-expand-parser.c:var_expand_table_set_func Unexecuted instantiation: var-expand-lexer.c:var_expand_table_set_func Unexecuted instantiation: expansion-parameter.c:var_expand_table_set_func Unexecuted instantiation: expansion-statement.c:var_expand_table_set_func Unexecuted instantiation: expansion-filter.c:var_expand_table_set_func Unexecuted instantiation: expansion-filter-if.c:var_expand_table_set_func Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_set_func |
199 | | #define var_expand_table_set_func(table, key, func) \ |
200 | | var_expand_table_set_func((table), (key), (func), __FILE__, __LINE__); |
201 | | |
202 | | /* Set key_b variable to key_a. Copies func and value. |
203 | | Asserts that both are found. */ |
204 | | static inline void var_expand_table_copy(struct var_expand_table *table, |
205 | | const char *key_b, const char *key_a) |
206 | 0 | { |
207 | 0 | struct var_expand_table *entry_a = var_expand_table_get(table, key_a); |
208 | 0 | struct var_expand_table *entry_b = var_expand_table_get(table, key_b); |
209 | 0 |
|
210 | 0 | i_assert(entry_a != NULL && entry_b != NULL); |
211 | 0 | entry_b->value = entry_a->value; |
212 | 0 | entry_b->func = entry_a->func; |
213 | 0 | } Unexecuted instantiation: fuzz-var-expand-import.c:var_expand_table_copy Unexecuted instantiation: expansion-program.c:var_expand_table_copy Unexecuted instantiation: var-expand.c:var_expand_table_copy Unexecuted instantiation: var-expand-parser.c:var_expand_table_copy Unexecuted instantiation: var-expand-lexer.c:var_expand_table_copy Unexecuted instantiation: expansion-parameter.c:var_expand_table_copy Unexecuted instantiation: expansion-statement.c:var_expand_table_copy Unexecuted instantiation: expansion-filter.c:var_expand_table_copy Unexecuted instantiation: expansion-filter-if.c:var_expand_table_copy Unexecuted instantiation: expansion-filter-crypt.c:var_expand_table_copy |
214 | | |
215 | | /* Export variable expand program to a portable string. |
216 | | |
217 | | Output format is a list of programs. Each program is catenated after |
218 | | the previous program. |
219 | | If there is only literal: \x01 <literal> |
220 | | <literal>: tab-escaped string \r |
221 | | Otherwise: |
222 | | <program>: \x02 <function> \x01 <list-of-parameters> \t <list-of-variables> \t |
223 | | <function>: string |
224 | | <list-of-parameters>: <parameter> \x01 <parameter> \x01 .. |
225 | | Note that last parameter has no \x01 at the end. |
226 | | <parameter>: <key> \x01 <type> <value> |
227 | | <key>: string |
228 | | <type>: s = string, i = intmax, v = variable |
229 | | <value>: <encoded-number> | tab-escaped string \r |
230 | | <encoded-number>: |
231 | | The number is expressed in 7-bit bytes and 8th bit indicates the |
232 | | presence of next byte. The number is in little-endian ordering. |
233 | | <list-of-variables>: <variable-name> \x01 <variable-name> \x01 .. |
234 | | Note that last variable has no \x01 at the end. |
235 | | */ |
236 | | |
237 | | const char *var_expand_program_export(const struct var_expand_program *program); |
238 | | void var_expand_program_export_append(string_t *dest, |
239 | | const struct var_expand_program *program); |
240 | | |
241 | | /* Reconstruct var_expand program */ |
242 | | const char *var_expand_program_to_string_one(const struct var_expand_program *program); |
243 | | const char *var_expand_program_to_string(const struct var_expand_program *program); |
244 | | void var_expand_program_to_string_append_one(string_t *dest, |
245 | | const struct var_expand_program *program); |
246 | | void var_expand_program_to_string_append(string_t *dest, |
247 | | const struct var_expand_program *program); |
248 | | |
249 | | /* Imports a variable expansion program exported by var_expand_program_export(). */ |
250 | | |
251 | | int var_expand_program_import(const char *data, |
252 | | struct var_expand_program **program_r, |
253 | | const char **error_r); |
254 | | int var_expand_program_import_sized(const char *data, size_t size, |
255 | | struct var_expand_program **program_r, |
256 | | const char **error_r); |
257 | | |
258 | | void var_expand_crypt_load(void); |
259 | | |
260 | | #endif |