diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c new file mode 100644 index 0000000..2645669 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c @@ -0,0 +1,251 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" + +#include "sieve-code.h" +#include "sieve-stringlist.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "ext-imap4flags-common.h" + +/* + * Commands + */ + +/* Forward declarations */ + +static bool cmd_flag_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx); + +/* Setflag command + * + * Syntax: + * setflag [<variablename: string>] <list-of-flags: string-list> + */ + +const struct sieve_command_def cmd_setflag = { + .identifier = "setflag", + .type = SCT_COMMAND, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = ext_imap4flags_command_validate, + .generate = cmd_flag_generate +}; + +/* Addflag command + * + * Syntax: + * addflag [<variablename: string>] <list-of-flags: string-list> + */ + +const struct sieve_command_def cmd_addflag = { + .identifier = "addflag", + .type = SCT_COMMAND, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = ext_imap4flags_command_validate, + .generate = cmd_flag_generate +}; + + +/* Removeflag command + * + * Syntax: + * removeflag [<variablename: string>] <list-of-flags: string-list> + */ + +const struct sieve_command_def cmd_removeflag = { + .identifier = "removeflag", + .type = SCT_COMMAND, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = ext_imap4flags_command_validate, + .generate = cmd_flag_generate +}; + +/* + * Operations + */ + +/* Forward declarations */ + +bool cmd_flag_operation_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int cmd_flag_operation_execute + (const struct sieve_runtime_env *renv, sieve_size_t *address); + +/* Setflag operation */ + +const struct sieve_operation_def setflag_operation = { + .mnemonic = "SETFLAG", + .ext_def = &imap4flags_extension, + .code = EXT_IMAP4FLAGS_OPERATION_SETFLAG, + .dump = cmd_flag_operation_dump, + .execute = cmd_flag_operation_execute +}; + +/* Addflag operation */ + +const struct sieve_operation_def addflag_operation = { + .mnemonic = "ADDFLAG", + .ext_def = &imap4flags_extension, + .code = EXT_IMAP4FLAGS_OPERATION_ADDFLAG, + .dump = cmd_flag_operation_dump, + .execute = cmd_flag_operation_execute +}; + +/* Removeflag operation */ + +const struct sieve_operation_def removeflag_operation = { + .mnemonic = "REMOVEFLAG", + .ext_def = &imap4flags_extension, + .code = EXT_IMAP4FLAGS_OPERATION_REMOVEFLAG, + .dump = cmd_flag_operation_dump, + .execute = cmd_flag_operation_execute +}; + +/* + * Code generation + */ + +static bool cmd_flag_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) +{ + struct sieve_ast_argument *arg1, *arg2; + + /* Emit operation */ + if ( sieve_command_is(cmd, cmd_setflag) ) + sieve_operation_emit(cgenv->sblock, cmd->ext, &setflag_operation); + else if ( sieve_command_is(cmd, cmd_addflag) ) + sieve_operation_emit(cgenv->sblock, cmd->ext, &addflag_operation); + else if ( sieve_command_is(cmd, cmd_removeflag) ) + sieve_operation_emit(cgenv->sblock, cmd->ext, &removeflag_operation); + + arg1 = cmd->first_positional; + arg2 = sieve_ast_argument_next(arg1); + + if ( arg2 == NULL ) { + /* No variable */ + sieve_opr_omitted_emit(cgenv->sblock); + if ( !sieve_generate_argument(cgenv, arg1, cmd) ) + return FALSE; + } else { + /* Full command */ + if ( !sieve_generate_argument(cgenv, arg1, cmd) ) + return FALSE; + if ( !sieve_generate_argument(cgenv, arg2, cmd) ) + return FALSE; + } + return TRUE; +} + +/* + * Code dump + */ + +bool cmd_flag_operation_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + struct sieve_operand oprnd; + + sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(denv->oprtn)); + sieve_code_descend(denv); + + sieve_code_mark(denv); + if ( !sieve_operand_read(denv->sblock, address, NULL, &oprnd) ) { + sieve_code_dumpf(denv, "ERROR: INVALID OPERAND"); + return FALSE; + } + + if ( !sieve_operand_is_omitted(&oprnd) ) { + return + sieve_opr_string_dump_data(denv, &oprnd, address, "variable name") && + sieve_opr_stringlist_dump(denv, address, "list of flags"); + } + + return + sieve_opr_stringlist_dump(denv, address, "list of flags"); +} + +/* + * Code execution + */ + +static int cmd_flag_operation_execute +(const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + const struct sieve_operation *op = renv->oprtn; + struct sieve_operand oprnd; + struct sieve_stringlist *flag_list; + struct sieve_variable_storage *storage; + unsigned int var_index; + ext_imapflag_flag_operation_t flag_op; + int ret; + + /* + * Read operands + */ + + /* Read bare operand (two types possible) */ + if ( (ret=sieve_operand_runtime_read + (renv, address, NULL, &oprnd)) <= 0 ) + return ret; + + /* Variable operand (optional) */ + if ( !sieve_operand_is_omitted(&oprnd) ) { + /* Read the variable operand */ + if ( (ret=sieve_variable_operand_read_data + (renv, &oprnd, address, "variable", &storage, &var_index)) <= 0 ) + return ret; + + /* Read flag list */ + if ( (ret=sieve_opr_stringlist_read(renv, address, "flag-list", &flag_list)) + <= 0 ) + return ret; + + /* Flag-list operand */ + } else { + storage = NULL; + var_index = 0; + + /* Read flag list */ + if ( (ret=sieve_opr_stringlist_read(renv, address, + "flag-list", &flag_list)) <= 0 ) + return ret; + } + + /* + * Perform operation + */ + + /* Determine what to do */ + + if ( sieve_operation_is(op, setflag_operation) ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "setflag command"); + flag_op = sieve_ext_imap4flags_set_flags; + } else if ( sieve_operation_is(op, addflag_operation) ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "addflag command"); + flag_op = sieve_ext_imap4flags_add_flags; + } else if ( sieve_operation_is(op, removeflag_operation) ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "removeflag command"); + flag_op = sieve_ext_imap4flags_remove_flags; + } else { + i_unreached(); + } + + sieve_runtime_trace_descend(renv); + + /* Perform requested operation */ + return flag_op(renv, op->ext, storage, var_index, flag_list); +} |