Coverage Report

Created: 2026-08-08 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "str.h"
5
#include "str-sanitize.h"
6
#include "mail-storage.h"
7
#include "imap-arg.h"
8
9
#include "sieve-common.h"
10
#include "sieve-commands.h"
11
#include "sieve-code.h"
12
#include "sieve-stringlist.h"
13
#include "sieve-actions.h"
14
#include "sieve-validator.h"
15
#include "sieve-generator.h"
16
#include "sieve-interpreter.h"
17
#include "sieve-result.h"
18
#include "sieve-dump.h"
19
20
#include "sieve-ext-variables.h"
21
22
#include "ext-imap4flags-common.h"
23
24
/*
25
 * Tagged arguments
26
 */
27
28
extern const struct sieve_argument_def tag_flags;
29
extern const struct sieve_argument_def tag_flags_implicit;
30
31
/*
32
 * Common command functions
33
 */
34
35
bool ext_imap4flags_command_validate(struct sieve_validator *valdtr,
36
             struct sieve_command *cmd)
37
0
{
38
0
  const struct sieve_extension *ext = cmd->ext;
39
0
  struct ext_imap4flags_context *extctx = ext->context;
40
0
  const struct sieve_extension *var_ext = extctx->var_ext;
41
0
  struct sieve_ast_argument *arg = cmd->first_positional;
42
0
  struct sieve_ast_argument *arg2;
43
44
  /* Check arguments */
45
46
0
  if (arg == NULL) {
47
0
    sieve_command_validate_error(
48
0
      valdtr, cmd,
49
0
      "the %s %s expects at least one argument, "
50
0
      "but none was found",
51
0
      sieve_command_identifier(cmd),
52
0
      sieve_command_type_name(cmd));
53
0
    return FALSE;
54
0
  }
55
56
0
  if (sieve_ast_argument_type(arg) != SAAT_STRING &&
57
0
      sieve_ast_argument_type(arg) != SAAT_STRING_LIST) {
58
0
    sieve_argument_validate_error(
59
0
      valdtr, arg,
60
0
      "the %s %s expects either a string (variable name) or "
61
0
      "a string-list (list of flags) as first argument, "
62
0
      "but %s was found",
63
0
      sieve_command_identifier(cmd),
64
0
      sieve_command_type_name(cmd),
65
0
      sieve_ast_argument_name(arg));
66
0
    return FALSE;
67
0
  }
68
69
0
  arg2 = sieve_ast_argument_next(arg);
70
0
  if (arg2 != NULL) {
71
    /* First, check syntax sanity */
72
73
0
    if (sieve_ast_argument_type(arg) != SAAT_STRING) {
74
0
      if (sieve_command_is(cmd, tst_hasflag)) {
75
0
        if (sieve_ast_argument_type(arg) != SAAT_STRING_LIST) {
76
0
          sieve_argument_validate_error(
77
0
            valdtr, arg,
78
0
            "if a second argument is specified for the hasflag, "
79
0
            "the first must be a string-list (variable-list), "
80
0
            "but %s was found",
81
0
            sieve_ast_argument_name(arg));
82
0
          return FALSE;
83
0
        }
84
0
      } else {
85
0
        sieve_argument_validate_error(
86
0
          valdtr, arg,
87
0
          "if a second argument is specified for the %s %s, "
88
0
          "the first must be a string (variable name), "
89
0
          "but %s was found",
90
0
          sieve_command_identifier(cmd),
91
0
          sieve_command_type_name(cmd),
92
0
          sieve_ast_argument_name(arg));
93
0
        return FALSE;
94
0
      }
95
0
    }
96
97
    /* Then, check whether the second argument is permitted */
98
99
0
    if (var_ext == NULL ||
100
0
        !sieve_ext_variables_is_active(var_ext, valdtr)) {
101
0
      sieve_argument_validate_error(
102
0
        valdtr,arg,
103
0
        "the %s %s only allows for the specification of a "
104
0
        "variable name when the variables extension is active",
105
0
        sieve_command_identifier(cmd),
106
0
        sieve_command_type_name(cmd));
107
0
      return FALSE;
108
0
    }
109
110
0
    if (!sieve_variable_argument_activate(
111
0
      var_ext, var_ext, valdtr, cmd, arg,
112
0
      !sieve_command_is(cmd, tst_hasflag)))
113
0
      return FALSE;
114
115
0
    if (sieve_ast_argument_type(arg2) != SAAT_STRING &&
116
0
        sieve_ast_argument_type(arg2) != SAAT_STRING_LIST) {
117
0
      sieve_argument_validate_error(
118
0
        valdtr, arg2,
119
0
        "the %s %s expects a string list (list of flags) as "
120
0
        "second argument when two arguments are specified, "
121
0
        "but %s was found",
122
0
        sieve_command_identifier(cmd),
123
0
        sieve_command_type_name(cmd),
124
0
        sieve_ast_argument_name(arg2));
125
0
      return FALSE;
126
0
    }
127
0
  } else
128
0
    arg2 = arg;
129
130
0
  if (!sieve_validator_argument_activate(valdtr, cmd, arg2, FALSE))
131
0
    return FALSE;
132
133
0
  if (!sieve_command_is(cmd, tst_hasflag) &&
134
0
      sieve_argument_is_string_literal(arg2)) {
135
0
    struct ext_imap4flags_iter fiter;
136
0
    const char *flag;
137
138
    /* Warn the user about validity of verifiable flags */
139
0
    ext_imap4flags_iter_init(&fiter, sieve_ast_argument_str(arg));
140
141
0
    while ((flag = ext_imap4flags_iter_get_flag(&fiter)) != NULL) {
142
0
      if (!sieve_ext_imap4flags_flag_is_valid(flag)) {
143
0
        sieve_argument_validate_warning(
144
0
          valdtr, arg,
145
0
          "IMAP flag '%s' specified for the %s command is invalid "
146
0
          "and will be ignored (only first invalid is reported)",
147
0
          str_sanitize(flag, 64),
148
0
          sieve_command_identifier(cmd));
149
0
        break;
150
0
      }
151
0
    }
152
0
  }
153
154
0
  return TRUE;
155
0
}
156
157
/*
158
 * Flags tag registration
159
 */
160
161
void ext_imap4flags_attach_flags_tag(struct sieve_validator *valdtr,
162
             const struct sieve_extension *ext,
163
             const char *command)
164
0
{
165
  /* Register :flags tag with the command and we don't care whether it is
166
     registered or even whether it will be registered at all. The
167
     validator handles either situation gracefully.
168
   */
169
170
  /* Tag specified by user */
171
0
  sieve_validator_register_external_tag(valdtr, command, ext, &tag_flags,
172
0
                SIEVE_OPT_SIDE_EFFECT);
173
0
}
174
175
void sieve_ext_imap4flags_register_side_effect(
176
  struct sieve_validator *valdtr, const struct sieve_extension *flg_ext,
177
  const char *command)
178
0
{
179
  /* Implicit tag if none is specified */
180
0
  sieve_validator_register_persistent_tag(valdtr, command, flg_ext,
181
0
            &tag_flags_implicit);
182
0
}
183
184
/*
185
 * Result context
186
 */
187
188
struct ext_imap4flags_result_context {
189
    string_t *internal_flags;
190
};
191
192
static void _get_initial_flags(struct sieve_result *result, string_t *flags)
193
0
{
194
0
  const struct sieve_message_data *msgdata =
195
0
    sieve_result_get_message_data(result);
196
0
  enum mail_flags mail_flags;
197
0
  const char *const *mail_keywords;
198
199
0
  mail_flags = mail_get_flags(msgdata->mail);
200
0
  mail_keywords = mail_get_keywords(msgdata->mail);
201
202
0
  if ((mail_flags & MAIL_FLAGGED) > 0)
203
0
    str_printfa(flags, " \\flagged");
204
0
  if ((mail_flags & MAIL_ANSWERED) > 0)
205
0
    str_printfa(flags, " \\answered");
206
0
  if ((mail_flags & MAIL_DELETED) > 0)
207
0
    str_printfa(flags, " \\deleted");
208
0
  if ((mail_flags & MAIL_SEEN) > 0)
209
0
    str_printfa(flags, " \\seen");
210
0
  if ((mail_flags & MAIL_DRAFT) > 0)
211
0
    str_printfa(flags, " \\draft");
212
213
0
  while (*mail_keywords != NULL) {
214
0
    str_printfa(flags, " %s", *mail_keywords);
215
0
    mail_keywords++;
216
0
  }
217
0
}
218
219
static inline struct ext_imap4flags_result_context *
220
_get_result_context(const struct sieve_extension *this_ext,
221
        struct sieve_result *result)
222
0
{
223
0
  struct ext_imap4flags_result_context *rctx =
224
0
    (struct ext_imap4flags_result_context *)
225
0
      sieve_result_extension_get_context(result, this_ext);
226
227
0
  if (rctx == NULL) {
228
0
    pool_t pool = sieve_result_pool(result);
229
230
0
    rctx = p_new(pool, struct ext_imap4flags_result_context, 1);
231
0
    rctx->internal_flags = str_new(pool, 32);
232
0
    _get_initial_flags(result, rctx->internal_flags);
233
234
0
    sieve_result_extension_set_context(result, this_ext, rctx);
235
0
  }
236
0
  return rctx;
237
0
}
238
239
static string_t *
240
_get_flags_string(const struct sieve_extension *this_ext,
241
      struct sieve_result *result)
242
0
{
243
0
  struct ext_imap4flags_result_context *ctx =
244
0
    _get_result_context(this_ext, result);
245
246
0
  return ctx->internal_flags;
247
0
}
248
249
/*
250
 * Runtime initialization
251
 */
252
253
static int
254
ext_imap4flags_runtime_init(const struct sieve_extension *ext,
255
          const struct sieve_runtime_env *renv,
256
          void *context ATTR_UNUSED,
257
          bool deferred ATTR_UNUSED)
258
0
{
259
0
  sieve_result_add_implicit_side_effect(renv->result, NULL, TRUE, ext,
260
0
                &flags_side_effect, NULL);
261
0
  return SIEVE_EXEC_OK;
262
0
}
263
264
const struct sieve_interpreter_extension
265
imap4flags_interpreter_extension = {
266
  .ext_def = &imap4flags_extension,
267
  .run = ext_imap4flags_runtime_init,
268
};
269
270
/*
271
 * Flag handling
272
 */
273
274
/* FIXME: This currently accepts a potentially unlimited number of flags, making
275
          the internal or variable flag list indefinitely long.
276
 */
277
278
bool sieve_ext_imap4flags_flag_is_valid(const char *flag)
279
0
{
280
0
  if (*flag == '\0')
281
0
    return FALSE;
282
283
0
  if (*flag == '\\') {
284
    /* System flag */
285
0
    const char *atom = t_str_ucase(flag);
286
287
0
    if (strcmp(atom, "\\ANSWERED") != 0 &&
288
0
        strcmp(atom, "\\FLAGGED") != 0 &&
289
0
        strcmp(atom, "\\DELETED") != 0 &&
290
0
        strcmp(atom, "\\SEEN") != 0 &&
291
0
        strcmp(atom, "\\DRAFT") != 0)
292
0
    {
293
0
      return FALSE;
294
0
    }
295
0
  } else {
296
0
    const char *p;
297
298
    /* Custom keyword:
299
300
       Syntax (IMAP4rev1, RFC 3501, Section 9. Formal Syntax) :
301
        flag-keyword    = atom
302
        atom            = 1*ATOM-CHAR
303
     */
304
0
    p = flag;
305
0
    while (*p != '\0') {
306
0
      if (!IS_ATOM_CHAR(*p))
307
0
        return FALSE;
308
0
      p++;
309
0
    }
310
0
  }
311
0
  return TRUE;
312
0
}
313
314
/* Flag iterator */
315
316
static void ext_imap4flags_iter_clear(struct ext_imap4flags_iter *iter)
317
0
{
318
0
  i_zero(iter);
319
0
}
320
321
void ext_imap4flags_iter_init(struct ext_imap4flags_iter *iter,
322
            string_t *flags_list)
323
0
{
324
0
  ext_imap4flags_iter_clear(iter);
325
0
  iter->flags_list = flags_list;
326
0
}
327
328
static string_t *
329
ext_imap4flags_iter_get_flag_str(struct ext_imap4flags_iter *iter)
330
0
{
331
0
  unsigned int len;
332
0
  const unsigned char *fp;
333
0
  const unsigned char *fbegin;
334
0
  const unsigned char *fstart;
335
0
  const unsigned char *fend;
336
337
  /* Return if not initialized */
338
0
  if (iter->flags_list == NULL)
339
0
    return NULL;
340
341
  /* Return if no more flags are available */
342
0
  len = str_len(iter->flags_list);
343
0
  if (iter->offset >= len)
344
0
    return NULL;
345
346
  /* Mark string boundries */
347
0
  fbegin = str_data(iter->flags_list);
348
0
  fend = fbegin + len;
349
350
  /* Start of this flag */
351
0
  fstart = fbegin + iter->offset;
352
353
  /* Scan for next flag */
354
0
  fp = fstart;
355
0
  for (;;) {
356
    /* Have we reached the end or a flag boundary? */
357
0
    if (fp >= fend || *fp == ' ') {
358
      /* Did we scan more than nothing ? */
359
0
      if (fp > fstart) {
360
        /* Return flag */
361
0
        string_t *flag = t_str_new(fp-fstart+1);
362
0
        str_append_data(flag, fstart, fp-fstart);
363
364
0
        iter->last = fstart - fbegin;
365
0
        iter->offset = fp - fbegin;
366
367
0
        return flag;
368
0
      }
369
370
0
      fstart = fp + 1;
371
0
    }
372
373
0
    if (fp >= fend)
374
0
      break;
375
376
0
    fp++;
377
0
  }
378
379
0
  iter->last = fstart - fbegin;
380
0
  iter->offset = fp - fbegin;
381
0
  return NULL;
382
0
}
383
384
const char *ext_imap4flags_iter_get_flag(struct ext_imap4flags_iter *iter)
385
0
{
386
0
  string_t *flag = ext_imap4flags_iter_get_flag_str(iter);
387
388
0
  if (flag == NULL)
389
0
    return NULL;
390
391
0
  return str_c(flag);
392
0
}
393
394
static void ext_imap4flags_iter_delete_last(struct ext_imap4flags_iter *iter)
395
0
{
396
0
  iter->offset++;
397
0
  if (iter->offset > str_len(iter->flags_list))
398
0
    iter->offset = str_len(iter->flags_list);
399
0
  if (iter->offset == str_len(iter->flags_list) && iter->last > 0)
400
0
    iter->last--;
401
402
0
  str_delete(iter->flags_list, iter->last, iter->offset - iter->last);
403
404
0
  iter->offset = iter->last;
405
0
}
406
407
/* Flag operations */
408
409
static string_t *
410
ext_imap4flags_get_flag_variable(const struct sieve_runtime_env *renv,
411
         const struct sieve_extension *flg_ext,
412
         struct sieve_variable_storage *storage,
413
         unsigned int var_index) ATTR_NULL(2);
414
415
static bool flags_list_flag_exists(string_t *flags_list, const char *flag)
416
0
{
417
0
  const char *flg;
418
0
  struct ext_imap4flags_iter flit;
419
420
0
  ext_imap4flags_iter_init(&flit, flags_list);
421
0
  while ((flg = ext_imap4flags_iter_get_flag(&flit)) != NULL) {
422
0
    if (strcasecmp(flg, flag) == 0)
423
0
      return TRUE;
424
0
  }
425
0
  return FALSE;
426
0
}
427
428
static void flags_list_flag_delete(string_t *flags_list, const char *flag)
429
0
{
430
0
  const char *flg;
431
0
  struct ext_imap4flags_iter flit;
432
433
0
  ext_imap4flags_iter_init(&flit, flags_list);
434
435
0
  while ((flg = ext_imap4flags_iter_get_flag(&flit)) != NULL) {
436
0
    if (strcasecmp(flg, flag) == 0)
437
0
      ext_imap4flags_iter_delete_last(&flit);
438
0
  }
439
0
}
440
441
static void flags_list_add_flags(string_t *flags_list, string_t *flags)
442
0
{
443
0
  const char *flg;
444
0
  struct ext_imap4flags_iter flit;
445
446
0
  ext_imap4flags_iter_init(&flit, flags);
447
448
0
  while ((flg = ext_imap4flags_iter_get_flag(&flit)) != NULL) {
449
0
    if (sieve_ext_imap4flags_flag_is_valid(flg) &&
450
0
        !flags_list_flag_exists(flags_list, flg)) {
451
0
      if (str_len(flags_list) != 0)
452
0
        str_append_c(flags_list, ' ');
453
0
      str_append(flags_list, flg);
454
0
    }
455
0
  }
456
0
}
457
458
static void flags_list_remove_flags(string_t *flags_list, string_t *flags)
459
0
{
460
0
  const char *flg;
461
0
  struct ext_imap4flags_iter flit;
462
463
0
  ext_imap4flags_iter_init(&flit, flags);
464
465
0
  while ((flg = ext_imap4flags_iter_get_flag(&flit)) != NULL)
466
0
    flags_list_flag_delete(flags_list, flg);
467
0
}
468
469
static void flags_list_set_flags(string_t *flags_list, string_t *flags)
470
0
{
471
0
  str_truncate(flags_list, 0);
472
0
  flags_list_add_flags(flags_list, flags);
473
0
}
474
475
static void flags_list_clear_flags(string_t *flags_list)
476
0
{
477
0
  str_truncate(flags_list, 0);
478
0
}
479
480
static string_t *
481
ext_imap4flags_get_flag_variable(const struct sieve_runtime_env *renv,
482
         const struct sieve_extension *flg_ext,
483
         struct sieve_variable_storage *storage,
484
         unsigned int var_index)
485
0
{
486
0
  string_t *flags;
487
488
0
  if (storage != NULL) {
489
0
    if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS)) {
490
0
      const char *var_name, *var_id;
491
492
0
      (void)sieve_variable_get_identifier(storage, var_index,
493
0
                  &var_name);
494
0
      var_id = sieve_variable_get_varid(storage, var_index);
495
496
0
      sieve_runtime_trace(renv, 0,
497
0
              "update variable '%s' [%s]",
498
0
              var_name, var_id);
499
0
    }
500
501
0
    if (!sieve_variable_get_modifiable(storage, var_index, &flags))
502
0
      return NULL;
503
0
  } else {
504
0
    i_assert(sieve_extension_is(flg_ext, imap4flags_extension));
505
0
    flags = _get_flags_string(flg_ext, renv->result);
506
0
  }
507
0
  return flags;
508
0
}
509
510
int sieve_ext_imap4flags_set_flags(const struct sieve_runtime_env *renv,
511
           const struct sieve_extension *flg_ext,
512
           struct sieve_variable_storage *storage,
513
           unsigned int var_index,
514
           struct sieve_stringlist *flags)
515
0
{
516
0
  string_t *cur_flags = ext_imap4flags_get_flag_variable(
517
0
    renv, flg_ext, storage, var_index);
518
519
0
  if (cur_flags != NULL) {
520
0
    string_t *flags_item;
521
0
    int ret;
522
523
0
    flags_list_clear_flags(cur_flags);
524
0
    while ((ret = sieve_stringlist_next_item(
525
0
      flags, &flags_item)) > 0) {
526
0
      sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
527
0
              "set flags '%s'",
528
0
              str_c(flags_item));
529
530
0
      flags_list_add_flags(cur_flags, flags_item);
531
0
    }
532
533
0
    if (ret < 0)
534
0
      return SIEVE_EXEC_BIN_CORRUPT;
535
0
    return SIEVE_EXEC_OK;
536
0
  }
537
0
  return SIEVE_EXEC_BIN_CORRUPT;
538
0
}
539
540
int sieve_ext_imap4flags_add_flags(const struct sieve_runtime_env *renv,
541
           const struct sieve_extension *flg_ext,
542
           struct sieve_variable_storage *storage,
543
           unsigned int var_index,
544
           struct sieve_stringlist *flags)
545
0
{
546
0
  string_t *cur_flags = ext_imap4flags_get_flag_variable(
547
0
    renv, flg_ext, storage, var_index);
548
549
0
  if (cur_flags != NULL) {
550
0
    string_t *flags_item;
551
0
    int ret;
552
553
0
    while ((ret = sieve_stringlist_next_item(
554
0
      flags, &flags_item)) > 0) {
555
0
      sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
556
0
              "add flags '%s'",
557
0
              str_c(flags_item));
558
559
0
      flags_list_add_flags(cur_flags, flags_item);
560
0
    }
561
562
0
    if (ret < 0)
563
0
      return SIEVE_EXEC_BIN_CORRUPT;
564
0
    return SIEVE_EXEC_OK;
565
0
  }
566
567
0
  return SIEVE_EXEC_BIN_CORRUPT;
568
0
}
569
570
int sieve_ext_imap4flags_remove_flags(const struct sieve_runtime_env *renv,
571
              const struct sieve_extension *flg_ext,
572
              struct sieve_variable_storage *storage,
573
              unsigned int var_index,
574
              struct sieve_stringlist *flags)
575
0
{
576
0
  string_t *cur_flags = ext_imap4flags_get_flag_variable(
577
0
    renv, flg_ext, storage, var_index);
578
579
0
  if (cur_flags != NULL) {
580
0
    string_t *flags_item;
581
0
    int ret;
582
583
0
    while ((ret = sieve_stringlist_next_item(
584
0
      flags, &flags_item)) > 0) {
585
0
      sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS,
586
0
              "remove flags '%s'",
587
0
              str_c(flags_item));
588
589
0
      flags_list_remove_flags(cur_flags, flags_item);
590
0
    }
591
592
0
    if (ret < 0) return
593
0
      SIEVE_EXEC_BIN_CORRUPT;
594
0
    return SIEVE_EXEC_OK;
595
0
  }
596
0
  return SIEVE_EXEC_BIN_CORRUPT;
597
0
}
598
599
/* Flag stringlist */
600
601
static int
602
ext_imap4flags_stringlist_next_item(struct sieve_stringlist *_strlist,
603
            string_t **str_r);
604
static void
605
ext_imap4flags_stringlist_reset(struct sieve_stringlist *_strlist);
606
607
struct ext_imap4flags_stringlist {
608
  struct sieve_stringlist strlist;
609
610
  struct sieve_stringlist *flags_list;
611
  string_t *flags_string;
612
  struct ext_imap4flags_iter flit;
613
614
  bool normalize:1;
615
};
616
617
static struct sieve_stringlist *
618
ext_imap4flags_stringlist_create(const struct sieve_runtime_env *renv,
619
         struct sieve_stringlist *flags_list,
620
         bool normalize)
621
0
{
622
0
  struct ext_imap4flags_stringlist *strlist;
623
624
0
  strlist = t_new(struct ext_imap4flags_stringlist, 1);
625
0
  strlist->strlist.exec_status = SIEVE_EXEC_OK;
626
0
  strlist->strlist.runenv = renv;
627
0
  strlist->strlist.next_item = ext_imap4flags_stringlist_next_item;
628
0
  strlist->strlist.reset = ext_imap4flags_stringlist_reset;
629
0
  strlist->normalize = normalize;
630
631
0
  strlist->flags_list = flags_list;
632
633
0
  return &strlist->strlist;
634
0
}
635
636
static struct sieve_stringlist *
637
ext_imap4flags_stringlist_create_single(const struct sieve_runtime_env *renv,
638
          string_t *flags_string, bool normalize)
639
0
{
640
0
  struct ext_imap4flags_stringlist *strlist;
641
642
0
  strlist = t_new(struct ext_imap4flags_stringlist, 1);
643
0
  strlist->strlist.exec_status = SIEVE_EXEC_OK;
644
0
  strlist->strlist.runenv = renv;
645
0
  strlist->strlist.next_item = ext_imap4flags_stringlist_next_item;
646
0
  strlist->strlist.reset = ext_imap4flags_stringlist_reset;
647
0
  strlist->normalize = normalize;
648
649
0
  if (normalize) {
650
0
    strlist->flags_string = t_str_new(256);
651
0
    flags_list_set_flags(strlist->flags_string, flags_string);
652
0
  } else {
653
0
    strlist->flags_string = flags_string;
654
0
  }
655
656
0
  ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string);
657
0
  return &strlist->strlist;
658
0
}
659
660
static int
661
ext_imap4flags_stringlist_next_item(struct sieve_stringlist *_strlist,
662
            string_t **str_r)
663
0
{
664
0
  struct ext_imap4flags_stringlist *strlist =
665
0
    (struct ext_imap4flags_stringlist *)_strlist;
666
667
0
  while ((*str_r = ext_imap4flags_iter_get_flag_str(
668
0
    &strlist->flit)) == NULL) {
669
0
    int ret;
670
671
0
    if (strlist->flags_list == NULL)
672
0
      return 0;
673
674
0
    ret = sieve_stringlist_next_item(strlist->flags_list,
675
0
             &strlist->flags_string);
676
0
    if (ret <= 0)
677
0
      return ret;
678
0
    if (strlist->flags_string == NULL)
679
0
      return -1;
680
681
0
    if (strlist->normalize) {
682
0
      string_t *flags_string = t_str_new(256);
683
684
0
      flags_list_set_flags(flags_string,
685
0
               strlist->flags_string);
686
0
      strlist->flags_string = flags_string;
687
0
    }
688
689
0
    ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string);
690
0
  }
691
0
  return 1;
692
0
}
693
694
static void ext_imap4flags_stringlist_reset(struct sieve_stringlist *_strlist)
695
0
{
696
0
  struct ext_imap4flags_stringlist *strlist =
697
0
    (struct ext_imap4flags_stringlist *)_strlist;
698
699
0
  if (strlist->flags_list != NULL) {
700
0
    sieve_stringlist_reset(strlist->flags_list);
701
0
    ext_imap4flags_iter_clear(&strlist->flit);
702
0
  } else {
703
0
    ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string);
704
0
  }
705
0
}
706
707
/* Flag access */
708
709
struct sieve_stringlist *
710
sieve_ext_imap4flags_get_flags(const struct sieve_runtime_env *renv,
711
             const struct sieve_extension *flg_ext,
712
             struct sieve_stringlist *flags_list)
713
0
{
714
0
  if (flags_list == NULL) {
715
0
    i_assert(sieve_extension_is(flg_ext, imap4flags_extension));
716
0
    return ext_imap4flags_stringlist_create_single(
717
0
      renv, _get_flags_string(flg_ext, renv->result), FALSE);
718
0
  }
719
0
  return ext_imap4flags_stringlist_create(renv, flags_list, TRUE);
720
0
}
721
722
void ext_imap4flags_get_implicit_flags_init(
723
  struct ext_imap4flags_iter *iter,
724
  const struct sieve_extension *this_ext, struct sieve_result *result)
725
0
{
726
0
  string_t *cur_flags = _get_flags_string(this_ext, result);
727
728
0
  ext_imap4flags_iter_init(iter, cur_flags);
729
0
}