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_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; }