Coverage Report

Created: 2026-04-12 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
6
#include "sieve-code.h"
7
#include "sieve-stringlist.h"
8
#include "sieve-commands.h"
9
#include "sieve-validator.h"
10
#include "sieve-generator.h"
11
#include "sieve-interpreter.h"
12
#include "sieve-dump.h"
13
14
#include "ext-imap4flags-common.h"
15
16
/*
17
 * Commands
18
 */
19
20
/* Forward declarations */
21
22
static bool cmd_flag_generate
23
  (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
24
25
/* Setflag command
26
 *
27
 * Syntax:
28
 *   setflag [<variablename: string>] <list-of-flags: string-list>
29
 */
30
31
const struct sieve_command_def cmd_setflag = {
32
  .identifier = "setflag",
33
  .type = SCT_COMMAND,
34
  .positional_args = -1, /* We check positional arguments ourselves */
35
  .subtests = 0,
36
  .block_allowed = FALSE,
37
  .block_required = FALSE,
38
  .validate = ext_imap4flags_command_validate,
39
  .generate = cmd_flag_generate
40
};
41
42
/* Addflag command
43
 *
44
 * Syntax:
45
 *   addflag [<variablename: string>] <list-of-flags: string-list>
46
 */
47
48
const struct sieve_command_def cmd_addflag = {
49
  .identifier = "addflag",
50
  .type = SCT_COMMAND,
51
  .positional_args = -1, /* We check positional arguments ourselves */
52
  .subtests = 0,
53
  .block_allowed = FALSE,
54
  .block_required = FALSE,
55
  .validate = ext_imap4flags_command_validate,
56
  .generate = cmd_flag_generate
57
};
58
59
60
/* Removeflag command
61
 *
62
 * Syntax:
63
 *   removeflag [<variablename: string>] <list-of-flags: string-list>
64
 */
65
66
const struct sieve_command_def cmd_removeflag = {
67
  .identifier = "removeflag",
68
  .type = SCT_COMMAND,
69
  .positional_args = -1, /* We check positional arguments ourselves */
70
  .subtests = 0,
71
  .block_allowed = FALSE,
72
  .block_required = FALSE,
73
  .validate = ext_imap4flags_command_validate,
74
  .generate = cmd_flag_generate
75
};
76
77
/*
78
 * Operations
79
 */
80
81
/* Forward declarations */
82
83
bool cmd_flag_operation_dump
84
  (const struct sieve_dumptime_env *denv, sieve_size_t *address);
85
static int cmd_flag_operation_execute
86
  (const struct sieve_runtime_env *renv, sieve_size_t *address);
87
88
/* Setflag operation */
89
90
const struct sieve_operation_def setflag_operation = {
91
  .mnemonic = "SETFLAG",
92
  .ext_def = &imap4flags_extension,
93
  .code = EXT_IMAP4FLAGS_OPERATION_SETFLAG,
94
  .dump = cmd_flag_operation_dump,
95
  .execute = cmd_flag_operation_execute
96
};
97
98
/* Addflag operation */
99
100
const struct sieve_operation_def addflag_operation = {
101
  .mnemonic = "ADDFLAG",
102
  .ext_def = &imap4flags_extension,
103
  .code = EXT_IMAP4FLAGS_OPERATION_ADDFLAG,
104
  .dump = cmd_flag_operation_dump,
105
  .execute = cmd_flag_operation_execute
106
};
107
108
/* Removeflag operation */
109
110
const struct sieve_operation_def removeflag_operation = {
111
  .mnemonic = "REMOVEFLAG",
112
  .ext_def = &imap4flags_extension,
113
  .code = EXT_IMAP4FLAGS_OPERATION_REMOVEFLAG,
114
  .dump = cmd_flag_operation_dump,
115
  .execute = cmd_flag_operation_execute
116
};
117
118
/*
119
 * Code generation
120
 */
121
122
static bool cmd_flag_generate
123
(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
124
0
{
125
0
  struct sieve_ast_argument *arg1, *arg2;
126
127
  /* Emit operation */
128
0
  if ( sieve_command_is(cmd, cmd_setflag) )
129
0
    sieve_operation_emit(cgenv->sblock, cmd->ext, &setflag_operation);
130
0
  else if ( sieve_command_is(cmd, cmd_addflag) )
131
0
    sieve_operation_emit(cgenv->sblock, cmd->ext, &addflag_operation);
132
0
  else if ( sieve_command_is(cmd, cmd_removeflag) )
133
0
    sieve_operation_emit(cgenv->sblock, cmd->ext, &removeflag_operation);
134
135
0
  arg1 = cmd->first_positional;
136
0
  arg2 = sieve_ast_argument_next(arg1);
137
138
0
  if ( arg2 == NULL ) {
139
    /* No variable */
140
0
    sieve_opr_omitted_emit(cgenv->sblock);
141
0
    if ( !sieve_generate_argument(cgenv, arg1, cmd) )
142
0
      return FALSE;
143
0
  } else {
144
    /* Full command */
145
0
    if ( !sieve_generate_argument(cgenv, arg1, cmd) )
146
0
      return FALSE;
147
0
    if ( !sieve_generate_argument(cgenv, arg2, cmd) )
148
0
      return FALSE;
149
0
  }
150
0
  return TRUE;
151
0
}
152
153
/*
154
 * Code dump
155
 */
156
157
bool cmd_flag_operation_dump
158
(const struct sieve_dumptime_env *denv, sieve_size_t *address)
159
0
{
160
0
  struct sieve_operand oprnd;
161
162
0
  sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(denv->oprtn));
163
0
  sieve_code_descend(denv);
164
165
0
  sieve_code_mark(denv);
166
0
  if ( !sieve_operand_read(denv->sblock, address, NULL, &oprnd) ) {
167
0
    sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
168
0
    return FALSE;
169
0
  }
170
171
0
  if ( !sieve_operand_is_omitted(&oprnd) ) {
172
0
    return
173
0
      sieve_opr_string_dump_data(denv, &oprnd, address, "variable name") &&
174
0
      sieve_opr_stringlist_dump(denv, address, "list of flags");
175
0
  }
176
177
0
  return
178
0
    sieve_opr_stringlist_dump(denv, address, "list of flags");
179
0
}
180
181
/*
182
 * Code execution
183
 */
184
185
static int cmd_flag_operation_execute
186
(const struct sieve_runtime_env *renv, sieve_size_t *address)
187
0
{
188
0
  const struct sieve_operation *op = renv->oprtn;
189
0
  struct sieve_operand oprnd;
190
0
  struct sieve_stringlist *flag_list;
191
0
  struct sieve_variable_storage *storage;
192
0
  unsigned int var_index;
193
0
  ext_imapflag_flag_operation_t flag_op;
194
0
  int ret;
195
196
  /*
197
   * Read operands
198
   */
199
200
  /* Read bare operand (two types possible) */
201
0
  if ( (ret=sieve_operand_runtime_read
202
0
    (renv, address, NULL, &oprnd)) <= 0 )
203
0
    return ret;
204
205
  /* Variable operand (optional) */
206
0
  if ( !sieve_operand_is_omitted(&oprnd) ) {
207
    /* Read the variable operand */
208
0
    if ( (ret=sieve_variable_operand_read_data
209
0
      (renv, &oprnd, address, "variable", &storage, &var_index)) <= 0 )
210
0
      return ret;
211
212
    /* Read flag list */
213
0
    if ( (ret=sieve_opr_stringlist_read(renv, address, "flag-list", &flag_list))
214
0
      <= 0 )
215
0
      return ret;
216
217
  /* Flag-list operand */
218
0
  } else {
219
0
    storage = NULL;
220
0
    var_index = 0;
221
222
    /* Read flag list */
223
0
    if ( (ret=sieve_opr_stringlist_read(renv, address,
224
0
      "flag-list", &flag_list)) <= 0 )
225
0
      return ret;
226
0
  }
227
228
  /*
229
   * Perform operation
230
   */
231
232
  /* Determine what to do */
233
234
0
  if ( sieve_operation_is(op, setflag_operation) ) {
235
0
    sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "setflag command");
236
0
    flag_op = sieve_ext_imap4flags_set_flags;
237
0
  } else if ( sieve_operation_is(op, addflag_operation) ) {
238
0
    sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "addflag command");
239
0
    flag_op = sieve_ext_imap4flags_add_flags;
240
0
  } else if ( sieve_operation_is(op, removeflag_operation) ) {
241
0
    sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "removeflag command");
242
0
    flag_op = sieve_ext_imap4flags_remove_flags;
243
0
  } else {
244
0
    i_unreached();
245
0
  }
246
247
0
  sieve_runtime_trace_descend(renv);
248
249
  /* Perform requested operation */
250
0
  return flag_op(renv, op->ext, storage, var_index, flag_list);
251
0
}