Coverage Report

Created: 2025-07-23 06:46

/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
}