#include "lib.h"
#include "str.h"
#include "str-sanitize.h"
#include "rfc2822.h"
#include "sieve-common.h"
#include "sieve-ast.h"
#include "sieve-validator.h"
#include "sieve-generator.h"
#include "sieve-binary.h"
#include "sieve-commands.h"
#include "sieve-code.h"
#include "sieve-interpreter.h"
static bool arg_number_generate
(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
struct sieve_command *context);
static bool arg_string_generate
(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
struct sieve_command *context);
static bool arg_string_list_validate
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
struct sieve_command *context);
static bool arg_string_list_generate
(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
struct sieve_command *context);
const struct sieve_argument_def number_argument = {
"@number",
NULL, NULL, NULL, NULL,
arg_number_generate
};
const struct sieve_argument_def string_argument = {
"@string",
NULL, NULL, NULL, NULL,
arg_string_generate
};
const struct sieve_argument_def string_list_argument = {
"@string-list",
NULL,
arg_string_list_validate,
NULL, NULL,
arg_string_list_generate
};
static bool arg_number_generate
(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
struct sieve_command *cmd ATTR_UNUSED)
{
sieve_opr_number_emit(cgenv->sblock, sieve_ast_argument_number(arg));
return TRUE;
}
static bool arg_string_generate
(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
struct sieve_command *cmd ATTR_UNUSED)
{
sieve_opr_string_emit(cgenv->sblock, sieve_ast_argument_str(arg));
return TRUE;
}
static bool arg_string_list_validate
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
struct sieve_command *cmd)
{
struct sieve_ast_argument *stritem;
stritem = sieve_ast_strlist_first(*arg);
while ( stritem != NULL ) {
if ( !sieve_validator_argument_activate(valdtr, cmd, stritem, FALSE) )
return FALSE;
stritem = sieve_ast_strlist_next(stritem);
}
return TRUE;
}
static bool emit_string_list_operand
(const struct sieve_codegen_env *cgenv, const struct sieve_ast_argument *strlist,
struct sieve_command *cmd)
{
void *list_context;
struct sieve_ast_argument *stritem;
sieve_opr_stringlist_emit_start
(cgenv->sblock, sieve_ast_strlist_count(strlist), &list_context);
stritem = sieve_ast_strlist_first(strlist);
while ( stritem != NULL ) {
if ( !sieve_generate_argument(cgenv, stritem, cmd) )
return FALSE;
stritem = sieve_ast_strlist_next(stritem);
}
sieve_opr_stringlist_emit_end(cgenv->sblock, list_context);
return TRUE;
}
static bool arg_string_list_generate
(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
struct sieve_command *cmd)
{
if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
return ( sieve_generate_argument(cgenv, arg, cmd) );
} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
bool result = TRUE;
if ( sieve_ast_strlist_count(arg) == 1 )
return ( sieve_generate_argument
(cgenv, sieve_ast_strlist_first(arg), cmd) );
else {
T_BEGIN {
result=emit_string_list_operand(cgenv, arg, cmd);
} T_END;
}
return result;
}
return FALSE;
}
struct sieve_arg_catenated_string {
struct sieve_ast_arg_list *str_parts;
};
struct sieve_arg_catenated_string *sieve_arg_catenated_string_create
(struct sieve_ast_argument *orig_arg)
{
pool_t pool = sieve_ast_pool(orig_arg->ast);
struct sieve_ast_arg_list *arglist;
struct sieve_arg_catenated_string *catstr;
arglist = sieve_ast_arg_list_create(pool);
catstr = p_new(pool, struct sieve_arg_catenated_string, 1);
catstr->str_parts = arglist;
(orig_arg)->argument->data = (void *) catstr;
return catstr;
}
void sieve_arg_catenated_string_add_element
(struct sieve_arg_catenated_string *catstr,
struct sieve_ast_argument *element)
{
sieve_ast_arg_list_add(catstr->str_parts, element);
}
#define _cat_string_first(catstr) __AST_LIST_FIRST((catstr)->str_parts)
#define _cat_string_count(catstr) __AST_LIST_COUNT((catstr)->str_parts)
#define _cat_string_next(item) __AST_LIST_NEXT(item)
bool sieve_arg_catenated_string_generate
(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
struct sieve_command *cmd)
{
struct sieve_arg_catenated_string *catstr =
(struct sieve_arg_catenated_string *) arg->argument->data;
struct sieve_ast_argument *strpart;
if ( _cat_string_count(catstr) == 1 )
sieve_generate_argument(cgenv, _cat_string_first(catstr), cmd);
else {
sieve_opr_catenated_string_emit(cgenv->sblock, _cat_string_count(catstr));
strpart = _cat_string_first(catstr);
while ( strpart != NULL ) {
if ( !sieve_generate_argument(cgenv, strpart, cmd) )
return FALSE;
strpart = _cat_string_next(strpart);
}
}
return TRUE;
}
struct sieve_argument *sieve_argument_create
(struct sieve_ast *ast, const struct sieve_argument_def *def,
const struct sieve_extension *ext, int id_code)
{
struct sieve_argument *arg;
pool_t pool;
pool = sieve_ast_pool(ast);
arg = p_new(pool, struct sieve_argument, 1);
arg->def = def;
arg->ext = ext;
arg->id_code = id_code;
return arg;
}
const struct sieve_command_def *sieve_core_tests[] = {
&tst_false, &tst_true,
&tst_not, &tst_anyof, &tst_allof,
&tst_address, &tst_header, &tst_exists, &tst_size
};
const unsigned int sieve_core_tests_count = N_ELEMENTS(sieve_core_tests);
const struct sieve_command_def *sieve_core_commands[] = {
&cmd_require,
&cmd_stop, &cmd_if, &cmd_elsif, &cmd_else,
&cmd_keep, &cmd_discard, &cmd_redirect
};
const unsigned int sieve_core_commands_count = N_ELEMENTS(sieve_core_commands);
struct sieve_command *sieve_command_prev
(struct sieve_command *cmd)
{
struct sieve_ast_node *node = sieve_ast_node_prev(cmd->ast_node);
if ( node != NULL ) {
return node->command;
}
return NULL;
}
struct sieve_command *sieve_command_parent
(struct sieve_command *cmd)
{
struct sieve_ast_node *node = sieve_ast_node_parent(cmd->ast_node);
return ( node != NULL ? node->command : NULL );
}
struct sieve_command *sieve_command_create
(struct sieve_ast_node *cmd_node, const struct sieve_extension *ext,
const struct sieve_command_def *cmd_def,
struct sieve_command_registration *cmd_reg)
{
struct sieve_command *cmd;
cmd = p_new(sieve_ast_node_pool(cmd_node), struct sieve_command, 1);
cmd->ast_node = cmd_node;
cmd->def = cmd_def;
cmd->ext = ext;
cmd->reg = cmd_reg;
cmd->block_exit_command = NULL;
return cmd;
}
const char *sieve_command_def_type_name
(const struct sieve_command_def *cmd_def)
{
switch ( cmd_def->type ) {
case SCT_NONE: return "command of unspecified type (bug)";
case SCT_TEST: return "test";
case SCT_COMMAND: return "command";
default:
break;
}
return "??COMMAND-TYPE??";
}
struct sieve_ast_argument *sieve_command_add_dynamic_tag
(struct sieve_command *cmd, const struct sieve_extension *ext,
const struct sieve_argument_def *tag, int id_code)
{
struct sieve_ast_argument *arg;
if ( cmd->first_positional != NULL )
arg = sieve_ast_argument_tag_insert
(cmd->first_positional, tag->identifier, cmd->ast_node->source_line);
else
arg = sieve_ast_argument_tag_create
(cmd->ast_node, tag->identifier, cmd->ast_node->source_line);
arg->argument = sieve_argument_create(cmd->ast_node->ast, tag, ext, id_code);
return arg;
}
struct sieve_ast_argument *sieve_command_find_argument
(struct sieve_command *cmd, const struct sieve_argument_def *arg_def)
{
struct sieve_ast_argument *arg = sieve_ast_argument_first(cmd->ast_node);
while ( arg != NULL ) {
if ( arg->argument != NULL && arg->argument->def == arg_def )
return arg;
arg = sieve_ast_argument_next(arg);
}
return arg;
}
void sieve_command_exit_block_unconditionally
(struct sieve_command *cmd)
{
struct sieve_command *parent = sieve_command_parent(cmd);
if ( parent != NULL && parent->block_exit_command == NULL )
parent->block_exit_command = cmd;
}
bool sieve_command_block_exits_unconditionally
(struct sieve_command *cmd)
{
return ( cmd->block_exit_command != NULL );
}
static int _verify_header_name_item
(void *context, struct sieve_ast_argument *header)
{
struct sieve_validator *valdtr = (struct sieve_validator *) context;
string_t *name = sieve_ast_argument_str(header);
if ( sieve_argument_is_string_literal(header) &&
!rfc2822_header_field_name_verify(str_c(name), str_len(name)) ) {
sieve_argument_validate_warning
(valdtr, header, "specified header field name '%s' is invalid",
str_sanitize(str_c(name), 80));
return FALSE;
}
return TRUE;
}
bool sieve_command_verify_headers_argument
(struct sieve_validator *valdtr, struct sieve_ast_argument *headers)
{
return ( sieve_ast_stringlist_map
(&headers, (void *) valdtr, _verify_header_name_item) >= 0 );
}