1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
6
#include "str-sanitize.h"
8
#include "sieve-common.h"
9
#include "sieve-commands.h"
10
#include "sieve-code.h"
11
#include "sieve-actions.h"
12
#include "sieve-validator.h"
13
#include "sieve-generator.h"
14
#include "sieve-interpreter.h"
15
#include "sieve-result.h"
16
#include "sieve-dump.h"
18
#include "sieve-ext-variables.h"
20
#include "ext-imap4flags-common.h"
23
* Forward declarations
26
static bool flag_is_valid(const char *flag);
32
extern const struct sieve_argument tag_flags;
33
extern const struct sieve_argument tag_flags_implicit;
36
* Common command functions
39
bool ext_imap4flags_command_validate
40
(struct sieve_validator *validator, struct sieve_command_context *cmd)
42
struct sieve_ast_argument *arg = cmd->first_positional;
43
struct sieve_ast_argument *arg2;
48
sieve_command_validate_error(validator, cmd,
49
"the %s %s expects at least one argument, but none was found",
50
cmd->command->identifier, sieve_command_type_name(cmd->command));
54
if ( sieve_ast_argument_type(arg) != SAAT_STRING &&
55
sieve_ast_argument_type(arg) != SAAT_STRING_LIST )
57
sieve_argument_validate_error(validator, arg,
58
"the %s %s expects either a string (variable name) or "
59
"a string-list (list of flags) as first argument, but %s was found",
60
cmd->command->identifier, sieve_command_type_name(cmd->command),
61
sieve_ast_argument_name(arg));
65
arg2 = sieve_ast_argument_next(arg);
67
/* First, check syntax sanity */
69
if ( sieve_ast_argument_type(arg) != SAAT_STRING )
71
if ( cmd->command == &tst_hasflag ) {
72
if ( sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) {
73
sieve_argument_validate_error(validator, arg,
74
"if a second argument is specified for the hasflag, the first "
75
"must be a string-list (variable-list), but %s was found",
76
sieve_ast_argument_name(arg));
80
sieve_argument_validate_error(validator, arg,
81
"if a second argument is specified for the %s %s, the first "
82
"must be a string (variable name), but %s was found",
83
cmd->command->identifier, sieve_command_type_name(cmd->command),
84
sieve_ast_argument_name(arg));
89
/* Then, check whether the second argument is permitted */
91
if ( !sieve_ext_variables_is_active(validator) ) {
92
sieve_argument_validate_error(validator,arg,
93
"the %s %s only allows for the specification of a "
94
"variable name when the variables extension is active",
95
cmd->command->identifier, sieve_command_type_name(cmd->command));
99
if ( !sieve_variable_argument_activate(validator, cmd, arg,
100
cmd->command != &tst_hasflag ) )
103
if ( sieve_ast_argument_type(arg2) != SAAT_STRING &&
104
sieve_ast_argument_type(arg2) != SAAT_STRING_LIST )
106
sieve_argument_validate_error(validator, arg2,
107
"the %s %s expects a string list (list of flags) as "
108
"second argument when two arguments are specified, "
110
cmd->command->identifier, sieve_command_type_name(cmd->command),
111
sieve_ast_argument_name(arg2));
117
if ( !sieve_validator_argument_activate(validator, cmd, arg2, FALSE) )
120
if ( cmd->command != &tst_hasflag && sieve_argument_is_string_literal(arg2) ) {
121
struct ext_imap4flags_iter fiter;
124
/* Warn the user about validity of verifiable flags */
125
ext_imap4flags_iter_init(&fiter, sieve_ast_argument_str(arg));
127
while ( (flag=ext_imap4flags_iter_get_flag(&fiter)) != NULL ) {
128
if ( !flag_is_valid(flag) ) {
129
sieve_argument_validate_warning(validator, arg,
130
"IMAP flag '%s' specified for the %s command is invalid "
131
"and will be ignored (only first invalid is reported)",
132
str_sanitize(flag, 64), cmd->command->identifier);
142
* Flags tag registration
145
void ext_imap4flags_attach_flags_tag
146
(struct sieve_validator *valdtr, const char *command)
148
/* Register :flags tag with the command and we don't care whether it is
149
* registered or even whether it will be registered at all. The validator
150
* handles either situation gracefully
153
/* Tag specified by user */
154
sieve_validator_register_external_tag
155
(valdtr, &tag_flags, command, SIEVE_OPT_SIDE_EFFECT);
157
/* Implicit tag if none is specified */
158
sieve_validator_register_persistent_tag
159
(valdtr, &tag_flags_implicit, command);
166
struct ext_imap4flags_result_context {
167
string_t *internal_flags;
170
static void _get_initial_flags
171
(struct sieve_result *result, string_t *flags)
173
const struct sieve_message_data *msgdata =
174
sieve_result_get_message_data(result);
175
enum mail_flags mail_flags;
176
const char *const *mail_keywords;
178
mail_flags = mail_get_flags(msgdata->mail);
179
mail_keywords = mail_get_keywords(msgdata->mail);
181
if ( (mail_flags & MAIL_FLAGGED) > 0 )
182
str_printfa(flags, " \\flagged");
184
if ( (mail_flags & MAIL_ANSWERED) > 0 )
185
str_printfa(flags, " \\answered");
187
if ( (mail_flags & MAIL_DELETED) > 0 )
188
str_printfa(flags, " \\deleted");
190
if ( (mail_flags & MAIL_SEEN) > 0 )
191
str_printfa(flags, " \\seen");
193
if ( (mail_flags & MAIL_DRAFT) > 0 )
194
str_printfa(flags, " \\draft");
196
while ( *mail_keywords != NULL ) {
197
str_printfa(flags, " %s", *mail_keywords);
202
static inline struct ext_imap4flags_result_context *_get_result_context
203
(struct sieve_result *result)
205
struct ext_imap4flags_result_context *rctx =
206
(struct ext_imap4flags_result_context *)
207
sieve_result_extension_get_context(result, &imap4flags_extension);
209
if ( rctx == NULL ) {
210
pool_t pool = sieve_result_pool(result);
212
rctx =p_new(pool, struct ext_imap4flags_result_context, 1);
213
rctx->internal_flags = str_new(pool, 32);
214
_get_initial_flags(result, rctx->internal_flags);
216
sieve_result_extension_set_context
217
(result, &imap4flags_extension, rctx);
223
static string_t *_get_flags_string
224
(struct sieve_result *result)
226
struct ext_imap4flags_result_context *ctx =
227
_get_result_context(result);
229
return ctx->internal_flags;
233
* Runtime initialization
236
static void ext_imap4flags_runtime_init
237
(const struct sieve_runtime_env *renv, void *context ATTR_UNUSED)
239
sieve_result_add_implicit_side_effect
240
(renv->result, NULL, TRUE, &flags_side_effect, NULL);
243
const struct sieve_interpreter_extension imap4flags_interpreter_extension = {
244
&imap4flags_extension,
245
ext_imap4flags_runtime_init,
253
/* FIXME: This currently accepts a potentially unlimited number of
254
* flags, making the internal or variable flag list indefinitely long
256
static bool flag_is_valid(const char *flag)
260
const char *atom = t_str_ucase(flag);
263
(strcmp(atom, "\\ANSWERED") != 0) &&
264
(strcmp(atom, "\\FLAGGED") != 0) &&
265
(strcmp(atom, "\\DELETED") != 0) &&
266
(strcmp(atom, "\\SEEN") != 0) &&
267
(strcmp(atom, "\\DRAFT") != 0) )
274
* The validity of the keyword cannot be validated until the
275
* target mailbox for the message is known. Meaning that the
276
* verfication of keyword can only be performed when the
277
* action side effect is about to be executed.
279
* FIXME: technically this is nonsense, since we can simply parse
280
* using the flag-keyword grammar provided by imap.
287
void ext_imap4flags_iter_init
288
(struct ext_imap4flags_iter *iter, string_t *flags_list)
290
iter->flags_list = flags_list;
295
const char *ext_imap4flags_iter_get_flag
296
(struct ext_imap4flags_iter *iter)
298
unsigned int len = str_len(iter->flags_list);
299
const unsigned char *fp;
300
const unsigned char *fbegin;
301
const unsigned char *fstart;
302
const unsigned char *fend;
304
if ( iter->offset >= len ) return NULL;
306
fbegin = str_data(iter->flags_list);
307
fp = fbegin + iter->offset;
311
if ( fp >= fend || *fp == ' ' ) {
313
const char *flag = t_strdup_until(fstart, fp);
315
iter->last = fstart - fbegin;
316
iter->offset = fp - fbegin;
323
if ( fp >= fend ) break;
328
iter->last = fstart - fbegin;
329
iter->offset = fp - fbegin;
333
static void ext_imap4flags_iter_delete_last
334
(struct ext_imap4flags_iter *iter)
337
if ( iter->offset > str_len(iter->flags_list) )
338
iter->offset = str_len(iter->flags_list);
339
if ( iter->offset == str_len(iter->flags_list) )
342
str_delete(iter->flags_list, iter->last, iter->offset - iter->last);
344
iter->offset = iter->last;
347
static bool flags_list_flag_exists
348
(string_t *flags_list, const char *flag)
351
struct ext_imap4flags_iter flit;
353
ext_imap4flags_iter_init(&flit, flags_list);
355
while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) {
356
if ( strcasecmp(flg, flag) == 0 )
363
static void flags_list_flag_delete
364
(string_t *flags_list, const char *flag)
367
struct ext_imap4flags_iter flit;
369
ext_imap4flags_iter_init(&flit, flags_list);
371
while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) {
372
if ( strcasecmp(flg, flag) == 0 ) {
373
ext_imap4flags_iter_delete_last(&flit);
378
static void flags_list_add_flags
379
(string_t *flags_list, string_t *flags)
382
struct ext_imap4flags_iter flit;
384
ext_imap4flags_iter_init(&flit, flags);
386
while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) {
387
if ( flag_is_valid(flg) && !flags_list_flag_exists(flags_list, flg) ) {
388
if ( str_len(flags_list) != 0 )
389
str_append_c(flags_list, ' ');
390
str_append(flags_list, flg);
395
static void flags_list_remove_flags
396
(string_t *flags_list, string_t *flags)
399
struct ext_imap4flags_iter flit;
401
ext_imap4flags_iter_init(&flit, flags);
403
while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) {
404
flags_list_flag_delete(flags_list, flg);
408
static void flags_list_set_flags
409
(string_t *flags_list, string_t *flags)
411
str_truncate(flags_list, 0);
412
flags_list_add_flags(flags_list, flags);
419
int ext_imap4flags_set_flags
420
(const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage,
421
unsigned int var_index, string_t *flags)
425
if ( storage != NULL ) {
426
if ( !sieve_variable_get_modifiable(storage, var_index, &cur_flags) )
427
return SIEVE_EXEC_BIN_CORRUPT;
429
cur_flags = _get_flags_string(renv->result);
431
if ( cur_flags != NULL )
432
flags_list_set_flags(cur_flags, flags);
434
return SIEVE_EXEC_OK;
437
int ext_imap4flags_add_flags
438
(const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage,
439
unsigned int var_index, string_t *flags)
443
if ( storage != NULL ) {
444
if ( !sieve_variable_get_modifiable(storage, var_index, &cur_flags) )
445
return SIEVE_EXEC_BIN_CORRUPT;
447
cur_flags = _get_flags_string(renv->result);
449
if ( cur_flags != NULL )
450
flags_list_add_flags(cur_flags, flags);
452
return SIEVE_EXEC_OK;
455
int ext_imap4flags_remove_flags
456
(const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage,
457
unsigned int var_index, string_t *flags)
461
if ( storage != NULL ) {
462
if ( !sieve_variable_get_modifiable(storage, var_index, &cur_flags) )
463
return SIEVE_EXEC_BIN_CORRUPT;
465
cur_flags = _get_flags_string(renv->result);
467
if ( cur_flags != NULL )
468
flags_list_remove_flags(cur_flags, flags);
470
return SIEVE_EXEC_OK;
473
int ext_imap4flags_get_flags_string
474
(const struct sieve_runtime_env *renv, struct sieve_variable_storage *storage,
475
unsigned int var_index, const char **flags)
479
if ( storage != NULL ) {
480
if ( !sieve_variable_get_modifiable(storage, var_index, &cur_flags) )
481
return SIEVE_EXEC_BIN_CORRUPT;
483
cur_flags = _get_flags_string(renv->result);
485
if ( cur_flags == NULL )
488
*flags = str_c(cur_flags);
490
return SIEVE_EXEC_OK;
493
void ext_imap4flags_get_flags_init
494
(struct ext_imap4flags_iter *iter, const struct sieve_runtime_env *renv,
495
string_t *flags_list)
499
if ( flags_list != NULL ) {
500
cur_flags = t_str_new(256);
502
flags_list_set_flags(cur_flags, flags_list);
505
cur_flags = _get_flags_string(renv->result);
507
ext_imap4flags_iter_init(iter, cur_flags);
510
void ext_imap4flags_get_implicit_flags_init
511
(struct ext_imap4flags_iter *iter, struct sieve_result *result)
513
string_t *cur_flags = _get_flags_string(result);
515
ext_imap4flags_iter_init(iter, cur_flags);