diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c b/pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c new file mode 100644 index 0000000..d9b31a2 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/mime/cmd-extracttext.c @@ -0,0 +1,370 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "array.h" + +#include "sieve-common.h" +#include "sieve-extensions.h" +#include "sieve-code.h" +#include "sieve-ast.h" +#include "sieve-commands.h" +#include "sieve-binary.h" +#include "sieve-message.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "sieve-ext-variables.h" + +#include "ext-mime-common.h" + +/* + * Extracttext command + * + * Syntax: + * extracttext [MODIFIER] [":first" number] <varname: string> + */ + +static bool cmd_extracttext_registered + (struct sieve_validator *valdtr, const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg); +static bool cmd_extracttext_validate + (struct sieve_validator *valdtr, struct sieve_command *cmd); +static bool cmd_extracttext_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx); + +const struct sieve_command_def cmd_extracttext = { + .identifier = "extracttext", + .type = SCT_COMMAND, + .positional_args = 1, + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .registered = cmd_extracttext_registered, + .validate = cmd_extracttext_validate, + .generate = cmd_extracttext_generate +}; + +/* + * Extracttext command tags + */ + +enum cmd_extracttext_optional { + CMD_EXTRACTTEXT_OPT_END, + CMD_EXTRACTTEXT_OPT_FIRST +}; + +static bool cmd_extracttext_validate_first_tag + (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd); + +static const struct sieve_argument_def extracttext_from_tag = { + .identifier = "first", + .validate = cmd_extracttext_validate_first_tag +}; + +/* + * Extracttext operation + */ + +static bool cmd_extracttext_operation_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int cmd_extracttext_operation_execute + (const struct sieve_runtime_env *renv, sieve_size_t *address); + +const struct sieve_operation_def extracttext_operation = { + .mnemonic = "EXTRACTTEXT", + .ext_def = &extracttext_extension, + .dump = cmd_extracttext_operation_dump, + .execute = cmd_extracttext_operation_execute +}; + +/* + * Compiler context + */ + +struct cmd_extracttext_context { + ARRAY_TYPE(sieve_variables_modifier) modifiers; +}; + +/* + * Tag validation + */ + +static bool cmd_extracttext_validate_first_tag +(struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct sieve_ast_argument *tag = *arg; + + /* Detach the tag itself */ + *arg = sieve_ast_arguments_detach(*arg,1); + + /* Check syntax: + * :first <number> + */ + if ( !sieve_validate_tag_parameter + (valdtr, cmd, tag, *arg, NULL, 0, SAAT_NUMBER, FALSE) ) + return FALSE; + + /* Skip parameter */ + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +/* Command registration */ + +static bool cmd_extracttext_registered +(struct sieve_validator *valdtr, const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg) +{ + struct ext_extracttext_context *ectx = + (struct ext_extracttext_context *)ext->context; + + sieve_validator_register_tag(valdtr, cmd_reg, ext, + &extracttext_from_tag, CMD_EXTRACTTEXT_OPT_FIRST); + sieve_variables_modifiers_link_tag + (valdtr, ectx->var_ext, cmd_reg); + return TRUE; +} + +/* + * Command validation + */ + +static bool cmd_extracttext_validate(struct sieve_validator *valdtr, + struct sieve_command *cmd) +{ + const struct sieve_extension *this_ext = cmd->ext; + struct ext_extracttext_context *ectx = + (struct ext_extracttext_context *)this_ext->context; + struct sieve_ast_node *node = cmd->ast_node; + struct sieve_ast_argument *arg = cmd->first_positional; + pool_t pool = sieve_command_pool(cmd); + struct cmd_extracttext_context *sctx; + + /* Create command context */ + sctx = p_new(pool, struct cmd_extracttext_context, 1); + p_array_init(&sctx->modifiers, pool, 4); + cmd->data = (void *) sctx; + + /* Validate modifiers */ + if ( !sieve_variables_modifiers_validate + (valdtr, cmd, &sctx->modifiers) ) + return FALSE; + + /* Validate varname argument */ + if ( !sieve_validate_positional_argument + (valdtr, cmd, arg, "varname", 1, SAAT_STRING) ) { + return FALSE; + } + if ( !sieve_variable_argument_activate + (ectx->var_ext, ectx->var_ext, valdtr, cmd, arg, TRUE) ) + return FALSE; + + /* Check foreverypart context */ + i_assert(node != NULL); + while ( node != NULL ) { + if ( node->command != NULL && + sieve_command_is(node->command, cmd_foreverypart) ) + break; + node = sieve_ast_node_parent(node); + } + + if ( node == NULL ) { + sieve_command_validate_error(valdtr, cmd, + "the extracttext command is not placed inside " + "a foreverypart loop"); + return FALSE; + } + return TRUE; +} + +/* + * Code generation + */ + +static bool cmd_extracttext_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) +{ + const struct sieve_extension *this_ext = cmd->ext; + struct sieve_binary_block *sblock = cgenv->sblock; + struct cmd_extracttext_context *sctx = + (struct cmd_extracttext_context *) cmd->data; + + sieve_operation_emit(sblock, this_ext, &extracttext_operation); + + /* Generate arguments */ + if ( !sieve_generate_arguments(cgenv, cmd, NULL) ) + return FALSE; + + /* Generate modifiers */ + if ( !sieve_variables_modifiers_generate + (cgenv, &sctx->modifiers) ) + return FALSE; + + return TRUE; +} + +/* + * Code dump + */ + +static bool cmd_extracttext_operation_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + int opt_code = 0; + + sieve_code_dumpf(denv, "EXTRACTTEXT"); + sieve_code_descend(denv); + + /* Dump optional operands */ + + for (;;) { + int opt; + bool opok = TRUE; + + if ( (opt=sieve_opr_optional_dump(denv, address, &opt_code)) < 0 ) + return FALSE; + if ( opt == 0 ) break; + + switch ( opt_code ) { + case CMD_EXTRACTTEXT_OPT_FIRST: + opok = sieve_opr_number_dump(denv, address, "first"); + break; + default: + return FALSE; + } + if ( !opok ) return FALSE; + } + + /* Print both variable name and string value */ + if ( !sieve_opr_string_dump(denv, address, "varname") ) + return FALSE; + + return sieve_variables_modifiers_code_dump(denv, address); +} + +/* + * Code execution + */ + +static int cmd_extracttext_operation_execute +(const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + const struct sieve_extension *this_ext = renv->oprtn->ext; + struct ext_extracttext_context *ectx = + (struct ext_extracttext_context *)this_ext->context; + struct sieve_variable_storage *storage; + ARRAY_TYPE(sieve_variables_modifier) modifiers; + struct ext_foreverypart_runtime_loop *sfploop; + struct sieve_message_part *mpart; + struct sieve_message_part_data mpart_data; + int opt_code = 0; + sieve_number_t first = 0; + string_t *value; + unsigned int var_index; + bool have_first = FALSE; + int ret = SIEVE_EXEC_OK; + + /* + * Read the normal operands + */ + + /* Optional operands */ + + for (;;) { + int opt; + + if ( (opt=sieve_opr_optional_read + (renv, address, &opt_code)) < 0 ) + return SIEVE_EXEC_BIN_CORRUPT; + if ( opt == 0 ) break; + + switch ( opt_code ) { + case CMD_EXTRACTTEXT_OPT_FIRST: + ret = sieve_opr_number_read + (renv, address, "first", &first); + have_first = TRUE; + break; + default: + sieve_runtime_trace_error(renv, "unknown optional operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + if ( ret <= 0 ) return ret; + } + + /* Varname operand */ + + if ( (ret=sieve_variable_operand_read + (renv, address, "varname", &storage, &var_index)) <= 0 ) + return ret; + + /* Modifiers */ + + if ( (ret=sieve_variables_modifiers_code_read + (renv, ectx->var_ext, address, &modifiers)) <= 0 ) + return ret; + + /* + * Determine and assign the value + */ + + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "extracttext command"); + sieve_runtime_trace_descend(renv); + + sfploop = ext_foreverypart_runtime_loop_get_current(renv); + if ( sfploop == NULL ) { + sieve_runtime_trace_error(renv, + "outside foreverypart context"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + /* Get current message part */ + mpart = sieve_message_part_iter_current(&sfploop->part_iter); + i_assert( mpart != NULL ); + + /* Get message part content */ + sieve_message_part_get_data(mpart, &mpart_data, TRUE); + + /* Apply ":first" limit, if any */ + if ( !have_first || (size_t)first > mpart_data.size ) { + value = t_str_new_const(mpart_data.content, mpart_data.size); + } else { + value = t_str_new((size_t)first); + str_append_data(value, mpart_data.content, (size_t)first); + } + + /* Apply modifiers */ + if ( (ret=sieve_variables_modifiers_apply + (renv, ectx->var_ext, &modifiers, &value)) <= 0 ) + return ret; + + /* Actually assign the value if all is well */ + i_assert ( value != NULL ); + if ( !sieve_variable_assign(storage, var_index, value) ) + return SIEVE_EXEC_BIN_CORRUPT; + + /* Trace */ + if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { + const char *var_name, *var_id; + + (void)sieve_variable_get_identifier(storage, var_index, &var_name); + var_id = sieve_variable_get_varid(storage, var_index); + + sieve_runtime_trace_here(renv, 0, "assign `%s' [%s] = \"%s\"", + var_name, var_id, str_c(value)); + } + + return SIEVE_EXEC_OK; +} + + + + + + |