static int cmd_test_config_unset_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { string_t *setting; int ret; /* * Read operands */ /* Setting */ if ( (ret=sieve_opr_string_read(renv, address, "setting", &setting)) <= 0 ) return ret; /* * Perform operation */ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { sieve_runtime_trace(renv, 0, "testsuite: test_config_unset command"); sieve_runtime_trace_descend(renv); sieve_runtime_trace(renv, 0, "unset config `%s'", str_c(setting)); } testsuite_setting_unset(str_c(setting)); return SIEVE_EXEC_OK; }
static int cmd_test_set_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { struct testsuite_object tobj; string_t *value; int member_id; int ret; if ( !testsuite_object_read_member (renv->sblock, address, &tobj, &member_id) ) { sieve_runtime_trace_error(renv, "invalid testsuite object member"); return SIEVE_EXEC_BIN_CORRUPT; } if ( (ret=sieve_opr_string_read(renv, address, "string", &value)) <= 0 ) return ret; if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { sieve_runtime_trace(renv, 0, "testsuite: test_set command"); sieve_runtime_trace_descend(renv); sieve_runtime_trace(renv, 0, "set test parameter '%s' = \"%s\"", testsuite_object_member_name(&tobj, member_id), str_c(value)); } if ( tobj.def == NULL || tobj.def->set_member == NULL ) { sieve_runtime_trace_error(renv, "unimplemented testsuite object"); return SIEVE_EXEC_FAILURE; } tobj.def->set_member(renv, member_id, value); return SIEVE_EXEC_OK; }
int sieve_match_value (struct sieve_match_context *mctx, const char *value, size_t value_size, struct sieve_stringlist *key_list) { const struct sieve_match_type *mcht = mctx->match_type; const struct sieve_runtime_env *renv = mctx->runenv; int match, ret; if ( mctx->trace ) { sieve_runtime_trace(renv, 0, "matching value `%s'", str_sanitize(value, 80)); } /* Match to key values */ sieve_stringlist_reset(key_list); if ( mctx->trace ) sieve_stringlist_set_trace(key_list, TRUE); sieve_runtime_trace_descend(renv); if ( mcht->def->match_keys != NULL ) { /* Call match-type's own key match handler */ match = mcht->def->match_keys(mctx, value, value_size, key_list); } else { string_t *key_item = NULL; /* Default key match loop */ match = 0; while ( match == 0 && (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 ) { T_BEGIN { match = mcht->def->match_key (mctx, value, value_size, str_c(key_item), str_len(key_item)); if ( mctx->trace ) { sieve_runtime_trace(renv, 0, "with key `%s' => %d", str_sanitize(str_c(key_item), 80), match); } } T_END; } if ( ret < 0 ) { mctx->exec_status = key_list->exec_status; match = -1; } } sieve_runtime_trace_ascend(renv); if ( mctx->match_status < 0 || match < 0 ) mctx->match_status = -1; else mctx->match_status = ( mctx->match_status > match ? mctx->match_status : match ); return match; }
static int tst_exists_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { struct sieve_stringlist *hdr_list; struct mail *mail = sieve_message_get_mail(renv->msgctx); string_t *hdr_item; bool matched; int ret; /* * Read operands */ /* Read header-list */ if ( (ret=sieve_opr_stringlist_read(renv, address, "header-list", &hdr_list)) <= 0 ) return ret; /* * Perfrom test */ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "exists test"); sieve_runtime_trace_descend(renv); /* Iterate through all requested headers to match (must find all specified) */ hdr_item = NULL; matched = TRUE; while ( matched && (ret=sieve_stringlist_next_item(hdr_list, &hdr_item)) > 0 ) { const char *const *headers; if ( mail_get_headers(mail, str_c(hdr_item), &headers) < 0 || headers[0] == NULL ) { matched = FALSE; } sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, "header `%s' %s", str_sanitize(str_c(hdr_item), 80), ( matched ? "exists" : "is missing" )); } if ( matched ) sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, "all headers exist"); else sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING, "headers are missing"); /* Set test result for subsequent conditional jump */ if ( ret >= 0 ) { sieve_interpreter_set_test_result(renv->interp, matched); return SIEVE_EXEC_OK; } sieve_runtime_trace_error(renv, "invalid header-list item"); return SIEVE_EXEC_BIN_CORRUPT; }
static int ext_fileinto_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { struct sieve_side_effects_list *slist = NULL; string_t *folder; bool folder_literal; bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS); int ret = 0; /* * Read operands */ /* Optional operands (side effects only) */ if ( sieve_action_opr_optional_read(renv, address, NULL, &ret, &slist) != 0 ) return ret; /* Folder operand */ if ( (ret=sieve_opr_string_read_ex (renv, address, "folder", FALSE, &folder, &folder_literal)) <= 0 ) return ret; /* * Perform operation */ if ( trace ) { sieve_runtime_trace(renv, 0, "fileinto action"); sieve_runtime_trace_descend(renv); } if ( !folder_literal && !uni_utf8_str_is_valid(str_c(folder)) ) { sieve_runtime_error(renv, NULL, "folder name specified for fileinto command is not utf-8: %s", str_c(folder)); return SIEVE_EXEC_FAILURE; } if ( trace ) { sieve_runtime_trace(renv, 0, "store message in mailbox `%s'", str_sanitize(str_c(folder), 80)); } /* Add action to result */ if ( sieve_act_store_add_to_result (renv, slist, str_c(folder)) < 0 ) return SIEVE_EXEC_FAILURE; sieve_message_snapshot(renv->msgctx); return SIEVE_EXEC_OK; }
static int mcht_count_match (struct sieve_match_context *mctx, struct sieve_stringlist *value_list, struct sieve_stringlist *key_list) { const struct sieve_runtime_env *renv = mctx->runenv; bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING); int count; string_t *key_item; int match, ret; if ( (count=sieve_stringlist_get_length(value_list)) < 0 ) { mctx->exec_status = value_list->exec_status; return -1; } sieve_stringlist_reset(key_list); string_t *value = t_str_new(20); str_printfa(value, "%d", count); if ( trace ) { sieve_runtime_trace(renv, 0, "matching count value `%s'", str_sanitize(str_c(value), 80)); } sieve_runtime_trace_descend(renv); /* Match to all key values */ key_item = NULL; match = 0; while ( match == 0 && (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 ) { match = mcht_value_match_key (mctx, str_c(value), str_len(value), str_c(key_item), str_len(key_item)); if ( trace ) { sieve_runtime_trace(renv, 0, "with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret); } } sieve_runtime_trace_ascend(renv); if ( ret < 0 ) { mctx->exec_status = key_list->exec_status; match = -1; } return match; }
static int tst_test_multiscript_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { struct sieve_stringlist *scripts_list; string_t *script_name; ARRAY_TYPE (const_string) scriptfiles; bool result = TRUE; int ret; /* * Read operands */ if ( (ret=sieve_opr_stringlist_read(renv, address, "scripts", &scripts_list)) <= 0 ) return ret; /* * Perform operation */ sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "testsuite: test_multiscript test"); sieve_runtime_trace_descend(renv); t_array_init(&scriptfiles, 16); script_name = NULL; while ( result && (ret=sieve_stringlist_next_item(scripts_list, &script_name)) > 0 ) { const char *script = t_strdup(str_c(script_name)); array_append(&scriptfiles, &script, 1); } result = result && (ret >= 0) && testsuite_script_multiscript(renv, &scriptfiles); /* Set result */ sieve_interpreter_set_test_result(renv->interp, result); return SIEVE_EXEC_OK; }
struct sieve_match_context *sieve_match_begin (const struct sieve_runtime_env *renv, const struct sieve_match_type *mcht, const struct sieve_comparator *cmp) { struct sieve_match_context *mctx; pool_t pool; /* Reject unimplemented match-type */ if ( mcht->def == NULL || (mcht->def->match == NULL && mcht->def->match_keys == NULL && mcht->def->match_key == NULL) ) return NULL; /* Create match context */ pool = pool_alloconly_create("sieve_match_context", 1024); mctx = p_new(pool, struct sieve_match_context, 1); mctx->pool = pool; mctx->runenv = renv; mctx->match_type = mcht; mctx->comparator = cmp; mctx->exec_status = SIEVE_EXEC_OK; mctx->trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING); /* Trace */ if ( mctx->trace ) { sieve_runtime_trace_descend(renv); sieve_runtime_trace(renv, 0, "starting `:%s' match with `%s' comparator:", sieve_match_type_name(mcht), sieve_comparator_name(cmp)); } /* Initialize match type */ if ( mcht->def != NULL && mcht->def->match_init != NULL ) { mcht->def->match_init(mctx); } return mctx; }
static int cmd_test_imap_metadata_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { const struct sieve_operation *oprtn = renv->oprtn; int opt_code = 0; string_t *mailbox = NULL, *annotation = NULL, *value = NULL; int ret; /* * Read 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 OPT_MAILBOX: ret = sieve_opr_string_read(renv, address, "mailbox", &mailbox); break; default: sieve_runtime_trace_error(renv, "unknown optional operand"); ret = SIEVE_EXEC_BIN_CORRUPT; } if ( ret <= 0 ) return ret; } /* Fixed operands */ if ( (ret=sieve_opr_string_read (renv, address, "annotation", &annotation)) <= 0 ) return ret; if ( (ret=sieve_opr_string_read (renv, address, "value", &value)) <= 0 ) return ret; /* * Perform operation */ if ( sieve_operation_is(oprtn, test_imap_metadata_set_operation) ) { if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { sieve_runtime_trace(renv, 0, "testsuite/test_imap_metadata_set command"); sieve_runtime_trace_descend(renv); if (mailbox == NULL) { sieve_runtime_trace(renv, 0, "set server annotation `%s'", str_c(annotation)); } else { sieve_runtime_trace(renv, 0, "set annotation `%s' for mailbox `%s'", str_c(annotation), str_c(mailbox)); } } if (testsuite_mailstore_set_imap_metadata (( mailbox == NULL ? NULL : str_c(mailbox) ), str_c(annotation), str_c(value)) < 0) return SIEVE_EXEC_FAILURE; } return SIEVE_EXEC_OK; }
static int cmd_test_binary_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { const struct sieve_operation *oprtn = renv->oprtn; string_t *binary_name = NULL; int ret; /* * Read operands */ /* Binary Name */ if ( (ret=sieve_opr_string_read(renv, address, "binary-name", &binary_name)) <= 0 ) return ret; /* * Perform operation */ if ( sieve_operation_is(oprtn, test_binary_load_operation) ) { struct sieve_binary *sbin = testsuite_binary_load(str_c(binary_name)); if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { sieve_runtime_trace(renv, 0, "testsuite: test_binary_load command"); sieve_runtime_trace_descend(renv); sieve_runtime_trace(renv, 0, "load binary `%s'", str_c(binary_name)); } if ( sbin != NULL ) { testsuite_script_set_binary(sbin); sieve_binary_unref(&sbin); } else { sieve_sys_error(testsuite_sieve_instance, "failed to load binary %s", str_c(binary_name)); return SIEVE_EXEC_FAILURE; } } else if ( sieve_operation_is(oprtn, test_binary_save_operation) ) { struct sieve_binary *sbin = testsuite_script_get_binary(); if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { sieve_runtime_trace(renv, 0, "testsuite: test_binary_save command"); sieve_runtime_trace_descend(renv); sieve_runtime_trace(renv, 0, "save binary `%s'", str_c(binary_name)); } if ( sbin != NULL ) testsuite_binary_save(sbin, str_c(binary_name)); else { sieve_sys_error(testsuite_sieve_instance, "no compiled binary to save as %s", str_c(binary_name)); return SIEVE_EXEC_FAILURE; } } else { i_unreached(); } return SIEVE_EXEC_OK; }
static int tst_mailboxexists_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { struct sieve_stringlist *mailbox_names; string_t *mailbox_item; bool trace = FALSE; bool all_exist = TRUE; int ret; /* * Read operands */ /* Read notify uris */ if ( (ret=sieve_opr_stringlist_read (renv, address, "mailbox-names", &mailbox_names)) <= 0 ) return ret; /* * Perform operation */ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_TESTS) ) { sieve_runtime_trace(renv, 0, "mailboxexists test"); sieve_runtime_trace_descend(renv); trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING); } if ( renv->scriptenv->user != NULL ) { int ret; mailbox_item = NULL; while ( (ret=sieve_stringlist_next_item(mailbox_names, &mailbox_item)) > 0 ) { struct mail_namespace *ns; const char *mailbox = str_c(mailbox_item); struct mailbox *box; /* Find the namespace */ ns = mail_namespace_find(renv->scriptenv->user->namespaces, mailbox); if ( ns == NULL) { if ( trace ) { sieve_runtime_trace(renv, 0, "mailbox `%s' not found", str_sanitize(mailbox, 80)); } all_exist = FALSE; break; } /* Open the box */ box = mailbox_alloc(ns->list, mailbox, 0); if ( mailbox_open(box) < 0 ) { if ( trace ) { sieve_runtime_trace(renv, 0, "mailbox `%s' cannot be opened", str_sanitize(mailbox, 80)); } all_exist = FALSE; mailbox_free(&box); break; } /* Also fail when it is readonly */ if ( mailbox_is_readonly(box) ) { if ( trace ) { sieve_runtime_trace(renv, 0, "mailbox `%s' is read-only", str_sanitize(mailbox, 80)); } all_exist = FALSE; mailbox_free(&box); break; } /* FIXME: check acl for 'p' or 'i' ACL permissions as required by RFC */ if ( trace ) { sieve_runtime_trace(renv, 0, "mailbox `%s' exists", str_sanitize(mailbox, 80)); } /* Close mailbox */ mailbox_free(&box); } if ( ret < 0 ) { sieve_runtime_trace_error(renv, "invalid mailbox name item"); return SIEVE_EXEC_BIN_CORRUPT; } } if ( trace ) { if ( all_exist ) sieve_runtime_trace(renv, 0, "all mailboxes are available"); else sieve_runtime_trace(renv, 0, "some mailboxes are unavailable"); } sieve_interpreter_set_test_result(renv->interp, all_exist); return SIEVE_EXEC_OK; }
static int cmd_test_config_reload_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { const struct sieve_extension *ext; int opt_code = 0; string_t *extension = NULL; int ret; /* * Read 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 OPT_EXTENSION: ret = sieve_opr_string_read(renv, address, "extension", &extension); break; default: sieve_runtime_trace_error(renv, "unknown optional operand"); ret = SIEVE_EXEC_BIN_CORRUPT; } if ( ret <= 0 ) return ret; } /* * Perform operation */ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { sieve_runtime_trace(renv, 0, "testsuite: test_config_reload command"); sieve_runtime_trace_descend(renv); } if ( extension == NULL ) { if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { sieve_runtime_trace(renv, 0, "reload configuration for sieve engine"); } sieve_settings_load(renv->svinst); } else { if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { sieve_runtime_trace(renv, 0, "reload configuration for extension `%s'", str_c(extension)); } ext = sieve_extension_get_by_name(renv->svinst, str_c(extension)); if ( ext == NULL ) { testsuite_test_failf("test_config_reload: " "unknown extension '%s'", str_c(extension)); return SIEVE_EXEC_OK; } sieve_extension_reload(ext); } return SIEVE_EXEC_OK; }
static int cmd_filter_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { const struct sieve_extension *this_ext = renv->oprtn->ext; unsigned int is_test = 0; struct sieve_stringlist *args_list = NULL; enum sieve_error error = SIEVE_ERROR_NONE; string_t *pname = NULL; const char *program_name = NULL; const char *const *args = NULL; struct istream *newmsg = NULL; struct sieve_extprogram *sprog; int ret; /* * Read operands */ /* The is_test flag */ if ( !sieve_binary_read_byte(renv->sblock, address, &is_test) ) { sieve_runtime_trace_error(renv, "invalid is_test flag"); return SIEVE_EXEC_BIN_CORRUPT; } /* Optional operands */ if ( sieve_action_opr_optional_read(renv, address, NULL, &ret, NULL) != 0 ) return ret; /* Fixed operands */ if ( (ret=sieve_extprogram_command_read_operands (renv, address, &pname, &args_list)) <= 0 ) return ret; program_name = str_c(pname); if ( args_list != NULL && sieve_stringlist_read_all(args_list, pool_datastack_create(), &args) < 0 ) { sieve_runtime_trace_error(renv, "failed to read args operand"); return args_list->exec_status; } /* * Perform operation */ /* Trace */ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "filter action"); sieve_runtime_trace_descend(renv); sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "execute program `%s'", str_sanitize(program_name, 128)); sprog = sieve_extprogram_create (this_ext, renv->scriptenv, renv->msgdata, "filter", program_name, args, &error); if ( sprog != NULL ) { struct mail *mail = sieve_message_get_mail(renv->msgctx); if ( sieve_extprogram_set_input_mail(sprog, mail) < 0 ) { sieve_extprogram_destroy(&sprog); return sieve_runtime_mail_error(renv, mail, "filter action: failed to read input message"); } sieve_extprogram_set_output_seekable(sprog); ret = sieve_extprogram_run(sprog); } else { ret = -1; } if ( ret > 0 ) newmsg = sieve_extprogram_get_output_seekable(sprog); if ( sprog != NULL ) sieve_extprogram_destroy(&sprog); if ( ret > 0 && newmsg != NULL ) { sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "executed program successfully"); i_stream_set_name(newmsg, t_strdup_printf("filter %s output", program_name)); newmsg->blocking = TRUE; if ( (ret=sieve_message_substitute(renv->msgctx, newmsg)) >= 0 ) { sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "changed message"); } else { sieve_runtime_critical(renv, NULL, "filter action", "filter action: failed to substitute message"); } i_stream_unref(&newmsg); } else if ( ret < 0 ) { if ( error == SIEVE_ERROR_NOT_FOUND ) { sieve_runtime_error(renv, NULL, "filter action: program `%s' not found", str_sanitize(program_name, 80)); } else { sieve_extprogram_exec_error(renv->ehandler, sieve_runtime_get_full_command_location(renv), "filter action: failed to execute to program `%s'", str_sanitize(program_name, 80)); } } else { sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "filter action: program indicated false result"); } if ( is_test > 0 ) { sieve_interpreter_set_test_result(renv->interp, ( ret > 0 )); return SIEVE_EXEC_OK; } return ( ret >= 0 ? SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE ); }
static int cmd_report_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { struct act_report_data *act; string_t *fbtype, *message, *to_address; const char *norm_address, *feedback_type, *error; int opt_code = 0, ret = 0; bool headers_only = FALSE; pool_t pool; /* * Read 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 OPT_HEADERS_ONLY: headers_only = TRUE; break; default: sieve_runtime_trace_error(renv, "unknown optional operand"); return SIEVE_EXEC_BIN_CORRUPT; } } /* Fixed operands */ if ( (ret=sieve_opr_string_read (renv, address, "feedback-type", &fbtype)) <= 0 ) return ret; if ( (ret=sieve_opr_string_read (renv, address, "message", &message)) <= 0 ) return ret; if ( (ret=sieve_opr_string_read (renv, address, "address", &to_address)) <= 0 ) return ret; /* * Perform operation */ /* Verify and trim feedback type */ feedback_type = ext_vnd_report_parse_feedback_type(str_c(fbtype)); if ( feedback_type == NULL ) { sieve_runtime_error(renv, NULL, "specified report feedback type `%s' is invalid", str_sanitize(str_c(fbtype), 256)); return SIEVE_EXEC_FAILURE; } /* Verify and normalize the address to 'local_part@domain' */ norm_address = sieve_address_normalize(to_address, &error); if ( norm_address == NULL ) { sieve_runtime_error(renv, NULL, "specified report address `%s' is invalid: %s", str_sanitize(str_c(to_address), 256), error); return SIEVE_EXEC_FAILURE; } /* Trace */ if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS) ) { sieve_runtime_trace(renv, 0, "report action"); sieve_runtime_trace_descend(renv); sieve_runtime_trace(renv, 0, "report incoming message as `%s' to address `%s'", str_sanitize(str_c(fbtype), 32), str_sanitize(norm_address, 80)); } /* Add report action to the result */ pool = sieve_result_pool(renv->result); act = p_new(pool, struct act_report_data, 1); act->headers_only = headers_only; act->feedback_type = p_strdup(pool, feedback_type); act->message = p_strdup(pool, str_c(message)); act->to_address = p_strdup(pool, norm_address); if ( sieve_result_add_action(renv, NULL, &act_report, NULL, (void *) act, 0, TRUE) < 0 ) return SIEVE_EXEC_FAILURE; return SIEVE_EXEC_OK; }
static int tst_spamvirustest_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { const struct sieve_operation *op = renv->oprtn; const struct sieve_extension *this_ext = op->ext; int opt_code = 0; struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type); struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); bool percent = FALSE; struct sieve_stringlist *value_list, *key_list; const char *score_value; int match, ret; /* Read optional operands */ for (;;) { int opt; if ( (opt=sieve_match_opr_optional_read (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 ) return ret; if ( opt == 0 ) break; switch ( opt_code ) { case OPT_SPAMTEST_PERCENT: percent = TRUE; break; default: sieve_runtime_trace_error(renv, "unknown optional operand"); return SIEVE_EXEC_BIN_CORRUPT; } } /* Read value part */ if ( (ret=sieve_opr_stringlist_read(renv, address, "value", &key_list)) <= 0 ) return ret; /* Perform test */ if ( sieve_operation_is(op, spamtest_operation) ) { sieve_runtime_trace (renv, SIEVE_TRLVL_TESTS, "spamtest test [percent=%s]", ( percent ? "true" : "false" )); } else { sieve_runtime_trace (renv, SIEVE_TRLVL_TESTS, "virustest test"); } /* Get score value */ sieve_runtime_trace_descend(renv); if ( (ret=ext_spamvirustest_get_value (renv, this_ext, percent, &score_value)) <= 0 ) return ret; sieve_runtime_trace_ascend(renv); /* Construct value list */ value_list = sieve_single_stringlist_create_cstr(renv, score_value, TRUE); /* Perform match */ if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 ) return ret; /* Set test result for subsequent conditional jump */ sieve_interpreter_set_test_result(renv->interp, match > 0); return SIEVE_EXEC_OK; }
static int cmd_execute_operation_execute (const struct sieve_runtime_env *renv, sieve_size_t *address) { const struct sieve_extension *this_ext = renv->oprtn->ext; struct sieve_side_effects_list *slist = NULL; int opt_code = 0; unsigned int is_test = 0; struct sieve_stringlist *args_list = NULL; string_t *pname = NULL, *input = NULL; struct sieve_variable_storage *var_storage = NULL; unsigned int var_index; bool have_input = FALSE; const char *program_name = NULL; const char *const *args = NULL; enum sieve_error error = SIEVE_ERROR_NONE; buffer_t *outbuf = NULL; struct sieve_extprogram *sprog = NULL; int ret; /* * Read operands */ /* The is_test flag */ if ( !sieve_binary_read_byte(renv->sblock, address, &is_test) ) { sieve_runtime_trace_error(renv, "invalid is_test flag"); return SIEVE_EXEC_BIN_CORRUPT; } /* Optional operands */ for (;;) { int opt; if ( (opt=sieve_action_opr_optional_read (renv, address, &opt_code, &ret, &slist)) < 0 ) return ret; if ( opt == 0 ) break; switch ( opt_code ) { case OPT_INPUT: ret = sieve_opr_string_read_ex (renv, address, "input", TRUE, &input, NULL); have_input = TRUE; break; case OPT_OUTPUT: ret = sieve_variable_operand_read (renv, address, "output", &var_storage, &var_index); break; default: sieve_runtime_trace_error(renv, "unknown optional operand"); return SIEVE_EXEC_BIN_CORRUPT; } if ( ret <= 0 ) return ret; } /* Fixed operands */ if ( (ret=sieve_extprogram_command_read_operands (renv, address, &pname, &args_list)) <= 0 ) return ret; program_name = str_c(pname); if ( args_list != NULL && sieve_stringlist_read_all(args_list, pool_datastack_create(), &args) < 0 ) { sieve_runtime_trace_error(renv, "failed to read args operand"); return args_list->exec_status; } /* * Perform operation */ /* Trace */ sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "execute action"); sieve_runtime_trace_descend(renv); sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "execute program `%s'", str_sanitize(program_name, 128)); sprog = sieve_extprogram_create (this_ext, renv->scriptenv, renv->msgdata, "execute", program_name, args, &error); if ( sprog != NULL ) { if ( var_storage != NULL ) { // FIXME: limit output size struct ostream *outdata; outbuf = buffer_create_dynamic(pool_datastack_create(), 1024); outdata = o_stream_create_buffer(outbuf); sieve_extprogram_set_output(sprog, outdata); o_stream_unref(&outdata); } if ( input == NULL && have_input ) { struct mail *mail = sieve_message_get_mail(renv->msgctx); if ( sieve_extprogram_set_input_mail(sprog, mail) < 0 ) { sieve_extprogram_destroy(&sprog); return sieve_runtime_mail_error(renv, mail, "execute action: failed to read input message"); } ret = 1; } else if ( input != NULL ) { struct istream *indata = i_stream_create_from_data(str_data(input), str_len(input)); sieve_extprogram_set_input(sprog, indata); i_stream_unref(&indata); ret = 1; } if ( ret >= 0 ) ret = sieve_extprogram_run(sprog); sieve_extprogram_destroy(&sprog); } else { ret = -1; } if ( ret > 0 ) { sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "executed program successfully"); if ( var_storage != NULL ) { string_t *var; if ( sieve_variable_get_modifiable(var_storage, var_index, &var) ) { str_truncate(var, 0); str_append_str(var, outbuf); sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "assigned output variable"); } // FIXME: handle failure } } else if ( ret < 0 ) { if ( error == SIEVE_ERROR_NOT_FOUND ) { sieve_runtime_error(renv, NULL, "execute action: program `%s' not found", str_sanitize(program_name, 80)); } else { sieve_extprogram_exec_error(renv->ehandler, sieve_runtime_get_full_command_location(renv), "execute action: failed to execute to program `%s'", str_sanitize(program_name, 80)); } } else { sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "execute action: program indicated false result"); } if ( outbuf != NULL ) buffer_free(&outbuf); if ( is_test ) sieve_interpreter_set_test_result(renv->interp, ( ret > 0 )); return SIEVE_EXEC_OK; }