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