/src/dovecot/src/lib-var-expand/expansion-statement.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2024 Dovecot authors, see the included COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "var-expand-private.h" |
5 | | #include "expansion.h" |
6 | | |
7 | | bool var_expand_execute_stmt(struct var_expand_state *state, |
8 | | const struct var_expand_statement *stmt, |
9 | | bool first, const char **error_r) |
10 | 0 | { |
11 | 0 | const char *error; |
12 | 0 | char *delayed_error = NULL; |
13 | 0 | var_expand_filter_func_t *fn; |
14 | | |
15 | | /* We allow first function to be either variable or function, |
16 | | so that you can do simple lookups, like %{variable}. |
17 | | Also we prefer variables first, to avoid cumbersome things like |
18 | | having to write lookup('domain') every time you wanted domain. |
19 | | */ |
20 | 0 | if (first) { |
21 | 0 | const char *value = NULL; |
22 | 0 | if (var_expand_state_lookup_variable(state, stmt->function, |
23 | 0 | &value, &error) < 0) { |
24 | | /* ignore this error now, but leave transfer unset. */ |
25 | | /* allows default to pick this up */ |
26 | 0 | var_expand_state_unset_transfer(state); |
27 | 0 | i_free(delayed_error); |
28 | 0 | delayed_error = i_strdup(error); |
29 | 0 | } else { |
30 | 0 | i_assert(value != NULL); |
31 | 0 | var_expand_state_set_transfer(state, value); |
32 | 0 | return TRUE; |
33 | 0 | } |
34 | 0 | } |
35 | | |
36 | 0 | if (var_expand_find_filter(stmt->function, &fn) == 0) { |
37 | 0 | int ret; |
38 | 0 | T_BEGIN { |
39 | 0 | ret = (*fn)(stmt, state, &error); |
40 | 0 | } T_END_PASS_STR_IF(ret < 0, &error); |
41 | 0 | i_free(delayed_error); |
42 | | /* this is to allow e.g. default to work correctly */ |
43 | 0 | if (ret < 0) { |
44 | 0 | var_expand_state_unset_transfer(state); |
45 | 0 | if (state->delayed_error != NULL) { |
46 | 0 | *error_r = t_strdup(state->delayed_error); |
47 | 0 | return FALSE; |
48 | 0 | } |
49 | 0 | delayed_error = |
50 | 0 | i_strdup_printf("%s: %s", stmt->function, error); |
51 | 0 | } |
52 | | /* this was already handled in the first branch, so just ignore |
53 | | the error here */ |
54 | 0 | } else if (!first) { |
55 | 0 | i_free(delayed_error); |
56 | 0 | *error_r = t_strdup_printf("No such function '%s'", stmt->function); |
57 | 0 | return FALSE; |
58 | 0 | } |
59 | | |
60 | 0 | i_free(state->delayed_error); |
61 | 0 | state->delayed_error = delayed_error; |
62 | 0 | return TRUE; |
63 | 0 | } |