From 8e9c7953aa13a8b24c0833e04823f92af0d12cfc Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Sat, 17 Dec 2011 15:04:59 +0100 Subject: [PATCH] Fixed interaction of Sieve include extension with ManageSieve. Upon upload, the include extension is more lenient towards circular includes and missing scripts as required by RFC. The script is now also verified upon SETACTIVE when it was not active before. However, this new SETACTIVE behavior is not optimal for the situation where the active script was updated with PUTSCRIPT and contains an nonexistent include (ignored during upload). This can still cause runtime errors, since an already active script is not verified again during SETACTIVE. --- TODO | 7 +- src/lib-sieve/plugins/include/cmd-include.c | 64 +++++++++++----- .../plugins/include/ext-include-common.c | 39 ++++++---- .../plugins/include/ext-include-common.h | 2 +- src/lib-sieve/sieve-commands.h | 2 + src/lib-sieve/sieve-generator.c | 4 +- src/lib-sieve/sieve-generator.h | 5 +- src/lib-sieve/sieve-types.h | 12 ++- src/lib-sieve/sieve.c | 7 +- src/lib-sievestorage/sieve-storage-save.c | 18 +++++ src/lib-sievestorage/sieve-storage-save.h | 3 + src/lib-sievestorage/sieve-storage-script.c | 32 +++++++- src/lib-sievestorage/sieve-storage-script.h | 2 + src/managesieve/cmd-putscript.c | 11 ++- src/managesieve/cmd-setactive.c | 73 ++++++++++++++++--- 15 files changed, 218 insertions(+), 63 deletions(-) diff --git a/TODO b/TODO index 721b96a58..59b845084 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ Current activities: -* Build a sieve tool to filter an entire existing mailbox through a Sieve - script. +* Update include extension to latest draft (v13 currently): + - Implement :optional tag. Parallel plugin-based efforts: @@ -15,9 +15,6 @@ Parallel plugin-based efforts: Next (mostly in order of descending priority/precedence): * Implement index extension -* Update include extension to latest draft (v10 currently): - - Implement :optional tag. - - Implement required ManageSieve behavior * Add normalize() method to comparators to normalize the string before matching (for efficiency). * Improve error handling. diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c index 1ad1d1621..8c6a8ae61 100644 --- a/src/lib-sieve/plugins/include/cmd-include.c +++ b/src/lib-sieve/plugins/include/cmd-include.c @@ -203,7 +203,8 @@ static bool cmd_include_validate (struct cmd_include_context_data *) cmd->data; struct sieve_script *script; const char *script_path, *script_name; - enum sieve_error error = TRUE; + enum sieve_error error = SIEVE_ERROR_NONE; + bool include = TRUE; /* Check argument */ if ( !sieve_validate_positional_argument @@ -251,18 +252,33 @@ static bool cmd_include_validate sieve_validator_error_handler(valdtr), &error); if ( script == NULL ) { - if ( error == SIEVE_ERROR_NOT_FOUND ) { - sieve_argument_validate_error(valdtr, arg, - "included %s script '%s' does not exist", - ext_include_script_location_name(ctx_data->location), - str_sanitize(script_name, 80)); + if ( error != SIEVE_ERROR_NOT_FOUND ) { + return FALSE; + } else { + enum sieve_compile_flags cpflags = + sieve_validator_compile_flags(valdtr); + + if ( (cpflags & SIEVE_COMPILE_FLAG_UPLOADED) != 0 ) { + sieve_argument_validate_warning(valdtr, arg, + "included %s script '%s' does not exist (ignored during upload)", + ext_include_script_location_name(ctx_data->location), + str_sanitize(script_name, 80)); + include = FALSE; + } else { + sieve_argument_validate_error(valdtr, arg, + "included %s script '%s' does not exist", + ext_include_script_location_name(ctx_data->location), + str_sanitize(script_name, 80)); + return FALSE; + } } - return FALSE; } - ext_include_ast_link_included_script(cmd->ext, cmd->ast_node->ast, script); - ctx_data->script = script; - + if ( include ) { + ext_include_ast_link_included_script(cmd->ext, cmd->ast_node->ast, script); + ctx_data->script = script; + } + arg = sieve_ast_arguments_detach(arg, 1); return TRUE; @@ -279,18 +295,26 @@ static bool cmd_include_generate (struct cmd_include_context_data *) cmd->data; const struct ext_include_script_info *included; unsigned int flags = ctx_data->include_once; + int ret; - /* Compile (if necessary) and include the script into the binary. - * This yields the id of the binary block containing the compiled byte code. + /* Upon upload ctx_data->script may be NULL if the script was not found. We + * don't emit any code for this include command in that case. */ - if ( !ext_include_generate_include - (cgenv, cmd, ctx_data->location, ctx_data->script, &included, - ctx_data->include_once) ) - return FALSE; - - (void)sieve_operation_emit(cgenv->sblock, cmd->ext, &include_operation); - (void)sieve_binary_emit_unsigned(cgenv->sblock, included->id); - (void)sieve_binary_emit_byte(cgenv->sblock, flags); + if ( ctx_data->script != NULL ) { + /* Compile (if necessary) and include the script into the binary. + * This yields the id of the binary block containing the compiled byte code. + */ + if ( (ret=ext_include_generate_include + (cgenv, cmd, ctx_data->location, ctx_data->script, &included, + ctx_data->include_once)) < 0 ) + return FALSE; + + if ( ret > 0 ) { + (void)sieve_operation_emit(cgenv->sblock, cmd->ext, &include_operation); + (void)sieve_binary_emit_unsigned(cgenv->sblock, included->id); + (void)sieve_binary_emit_byte(cgenv->sblock, flags); + } + } return TRUE; } diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c index c47dcc21b..a5f4c983e 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.c +++ b/src/lib-sieve/plugins/include/ext-include-common.c @@ -462,7 +462,7 @@ struct sieve_variable_storage *ext_include_interpreter_get_global_variables * Including a script during code generation */ -bool ext_include_generate_include +int ext_include_generate_include (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd, enum ext_include_script_location location, struct sieve_script *script, const struct ext_include_script_info **included_r, bool once) @@ -470,7 +470,7 @@ bool ext_include_generate_include const struct sieve_extension *this_ext = cmd->ext; struct ext_include_context *ext_ctx = (struct ext_include_context *)this_ext->context; - bool result = TRUE; + int result = 1; struct sieve_ast *ast; struct sieve_binary *sbin = cgenv->sbin; struct sieve_generator *gentr = cgenv->gentr; @@ -488,14 +488,14 @@ bool ext_include_generate_include * already. */ if ( sieve_get_errors(ehandler) > 0 ) - return FALSE; + return -1; /* Limit nesting level */ if ( ctx->nesting_depth >= ext_ctx->max_nesting_depth ) { sieve_command_generate_error (gentr, cmd, "cannot nest includes deeper than %d levels", ext_ctx->max_nesting_depth); - return FALSE; + return -1; } /* Check for circular include */ @@ -503,9 +503,18 @@ bool ext_include_generate_include pctx = ctx; while ( pctx != NULL ) { if ( sieve_script_equals(pctx->script, script) ) { + /* Just drop circular include when uploading inactive script; + * not an error + */ + if ( (cgenv->flags & SIEVE_COMPILE_FLAG_UPLOADED) != 0 && + (cgenv->flags & SIEVE_COMPILE_FLAG_ACTIVATED) == 0 ) { + sieve_command_generate_warning + (gentr, cmd, "circular include (ignored during upload)"); + return 0; + } + sieve_command_generate_error(gentr, cmd, "circular include"); - - return FALSE; + return -1; } pctx = pctx->parent; @@ -520,7 +529,7 @@ bool ext_include_generate_include { struct sieve_binary_block *inc_block; const char *script_name = sieve_script_name(script); - enum sieve_compile_flags cpflags = 0; + enum sieve_compile_flags cpflags = cgenv->flags; /* Check whether include limit is exceeded */ if ( ext_include_binary_script_get_count(binctx) >= @@ -528,7 +537,7 @@ bool ext_include_generate_include sieve_command_generate_error(gentr, cmd, "failed to include script '%s': no more than %u includes allowed", str_sanitize(script_name, 80), ext_ctx->max_includes); - return FALSE; + return -1; } /* No, allocate a new block in the binary and mark the script as included. @@ -541,13 +550,15 @@ bool ext_include_generate_include if ( (ast = sieve_parse(script, ehandler, NULL)) == NULL ) { sieve_command_generate_error(gentr, cmd, "failed to parse included script '%s'", str_sanitize(script_name, 80)); - return FALSE; + return -1; } /* Included scripts inherit global variable scope */ (void)ext_include_create_ast_context(this_ext, ast, cmd->ast_node->ast); - if ( location != EXT_INCLUDE_LOCATION_GLOBAL ) + if ( location == EXT_INCLUDE_LOCATION_GLOBAL ) + cpflags &= ~SIEVE_RUNTIME_FLAG_NOGLOBAL; + else cpflags |= SIEVE_RUNTIME_FLAG_NOGLOBAL; /* Validate */ @@ -556,7 +567,7 @@ bool ext_include_generate_include "failed to validate included script '%s'", str_sanitize(script_name, 80)); sieve_ast_unref(&ast); - return FALSE; + return -1; } /* Generate @@ -564,14 +575,14 @@ bool ext_include_generate_include * FIXME: It might not be a good idea to recurse code generation for * included scripts. */ - subgentr = sieve_generator_create(ast, ehandler); + subgentr = sieve_generator_create(ast, ehandler, cpflags); ext_include_initialize_generator_context(cmd->ext, subgentr, ctx, script); if ( sieve_generator_run(subgentr, &inc_block) == NULL ) { sieve_command_generate_error(gentr, cmd, "failed to generate code for included script '%s'", str_sanitize(script_name, 80)); - result = FALSE; + result = -1; } sieve_generator_free(&subgentr); @@ -580,7 +591,7 @@ bool ext_include_generate_include sieve_ast_unref(&ast); } - if ( result ) *included_r = included; + if ( result > 0 ) *included_r = included; return result; } diff --git a/src/lib-sieve/plugins/include/ext-include-common.h b/src/lib-sieve/plugins/include/ext-include-common.h index 4d27e80f0..c55617ecf 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.h +++ b/src/lib-sieve/plugins/include/ext-include-common.h @@ -142,7 +142,7 @@ void ext_include_register_generator_context (const struct sieve_extension *this_ext, const struct sieve_codegen_env *cgenv); -bool ext_include_generate_include +int ext_include_generate_include (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd, enum ext_include_script_location location, struct sieve_script *script, const struct ext_include_script_info **included_r, bool once); diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h index feaf9899c..49d872f3c 100644 --- a/src/lib-sieve/sieve-commands.h +++ b/src/lib-sieve/sieve-commands.h @@ -200,6 +200,8 @@ bool sieve_command_block_exits_unconditionally #define sieve_command_generate_error(gentr, context, ...) \ sieve_generator_error(gentr, (context)->ast_node->source_line, __VA_ARGS__) +#define sieve_command_generate_warning(gentr, context, ...) \ + sieve_generator_warning(gentr, (context)->ast_node->source_line, __VA_ARGS__) /* Utility macros */ diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c index 637a75c84..d32245073 100644 --- a/src/lib-sieve/sieve-generator.c +++ b/src/lib-sieve/sieve-generator.c @@ -76,7 +76,8 @@ struct sieve_generator { }; struct sieve_generator *sieve_generator_create -(struct sieve_ast *ast, struct sieve_error_handler *ehandler) +(struct sieve_ast *ast, struct sieve_error_handler *ehandler, + enum sieve_compile_flags flags) { pool_t pool; struct sieve_generator *gentr; @@ -91,6 +92,7 @@ struct sieve_generator *sieve_generator_create sieve_error_handler_ref(ehandler); gentr->genenv.gentr = gentr; + gentr->genenv.flags = flags; gentr->genenv.ast = ast; sieve_ast_ref(ast); diff --git a/src/lib-sieve/sieve-generator.h b/src/lib-sieve/sieve-generator.h index 34a2c2aa3..654fdd43c 100644 --- a/src/lib-sieve/sieve-generator.h +++ b/src/lib-sieve/sieve-generator.h @@ -16,6 +16,8 @@ struct sieve_codegen_env { struct sieve_generator *gentr; struct sieve_instance *svinst; + enum sieve_compile_flags flags; + struct sieve_script *script; struct sieve_ast *ast; @@ -24,7 +26,8 @@ struct sieve_codegen_env { }; struct sieve_generator *sieve_generator_create - (struct sieve_ast *ast, struct sieve_error_handler *ehandler); + (struct sieve_ast *ast, struct sieve_error_handler *ehandler,\ + enum sieve_compile_flags flags); void sieve_generator_free(struct sieve_generator **generator); /* diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h index 5a3223bd0..3da2192ce 100644 --- a/src/lib-sieve/sieve-types.h +++ b/src/lib-sieve/sieve-types.h @@ -65,7 +65,14 @@ enum sieve_error { */ enum sieve_compile_flags { - SIEVE_COMPILE_FLAG_NOGLOBAL = (1<<0) + /* No global extensions are allowed + * (as marked by sieve_global_extensions setting) + */ + SIEVE_COMPILE_FLAG_NOGLOBAL = (1<<0), + /* Script is being uploaded (usually through ManageSieve) */ + SIEVE_COMPILE_FLAG_UPLOADED = (1<<1), + /* Script is being activated (usually through ManageSieve) */ + SIEVE_COMPILE_FLAG_ACTIVATED = (1<<2), }; /* @@ -88,6 +95,9 @@ struct sieve_message_data { */ enum sieve_runtime_flags { + /* No global extensions are allowed + * (as marked by sieve_global_extensions setting) + */ SIEVE_RUNTIME_FLAG_NOGLOBAL = (1<<0) }; diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 5e2a85263..bdd1dba04 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -177,9 +177,10 @@ bool sieve_validate static struct sieve_binary *sieve_generate (struct sieve_ast *ast, struct sieve_error_handler *ehandler, - enum sieve_error *error_r) + enum sieve_compile_flags flags, enum sieve_error *error_r) { - struct sieve_generator *generator = sieve_generator_create(ast, ehandler); + struct sieve_generator *generator = + sieve_generator_create(ast, ehandler, flags); struct sieve_binary *sbin = NULL; sbin = sieve_generator_run(generator, NULL); @@ -222,7 +223,7 @@ struct sieve_binary *sieve_compile_script } /* Generate */ - if ( (sbin=sieve_generate(ast, ehandler, error_r)) == NULL ) { + if ( (sbin=sieve_generate(ast, ehandler, flags, error_r)) == NULL ) { sieve_error(ehandler, sieve_script_name(script), "code generation failed"); sieve_ast_unref(&ast); diff --git a/src/lib-sievestorage/sieve-storage-save.c b/src/lib-sievestorage/sieve-storage-save.c index 60ed394fb..9fa2ee507 100644 --- a/src/lib-sievestorage/sieve-storage-save.c +++ b/src/lib-sievestorage/sieve-storage-save.c @@ -316,6 +316,24 @@ struct sieve_script *sieve_storage_save_get_tempscript return ctx->scriptobject; } +bool sieve_storage_save_will_activate +(struct sieve_save_context *ctx) +{ + const char *scriptname; + int ret = 0; + + T_BEGIN { + ret = sieve_storage_get_active_scriptfile(ctx->storage, &scriptname); + + if ( ret > 0 ) { + /* Is the requested script active? */ + ret = ( strcmp(ctx->scriptname, scriptname) == 0 ? 1 : 0 ); + } + } T_END; + + return ret; +} + int sieve_storage_save_commit(struct sieve_save_context **ctx) { const char *dest_path; diff --git a/src/lib-sievestorage/sieve-storage-save.h b/src/lib-sievestorage/sieve-storage-save.h index 819b4cb16..3e861d580 100644 --- a/src/lib-sievestorage/sieve-storage-save.h +++ b/src/lib-sievestorage/sieve-storage-save.h @@ -19,6 +19,9 @@ int sieve_storage_save_finish(struct sieve_save_context *ctx); struct sieve_script *sieve_storage_save_get_tempscript (struct sieve_save_context *ctx); +bool sieve_storage_save_will_activate + (struct sieve_save_context *ctx); + void sieve_storage_save_cancel(struct sieve_save_context **ctx); int sieve_storage_save_commit(struct sieve_save_context **ctx); diff --git a/src/lib-sievestorage/sieve-storage-script.c b/src/lib-sievestorage/sieve-storage-script.c index 58567d6b3..a57784c93 100644 --- a/src/lib-sievestorage/sieve-storage-script.c +++ b/src/lib-sievestorage/sieve-storage-script.c @@ -164,7 +164,7 @@ static int sieve_storage_read_active_link } static const char *sieve_storage_parse_link -(struct sieve_storage *storage, const char *link) +(struct sieve_storage *storage, const char *link, const char **scriptname_r) { const char *fname, *scriptname, *scriptpath; @@ -200,6 +200,9 @@ static const char *sieve_storage_parse_link return NULL; } + if ( scriptname_r != NULL ) + *scriptname_r = scriptname; + return fname; } @@ -216,7 +219,7 @@ int sieve_storage_get_active_scriptfile return ret; /* Parse the link */ - scriptfile = sieve_storage_parse_link(storage, link); + scriptfile = sieve_storage_parse_link(storage, link, NULL); if (scriptfile == NULL) { /* Obviously someone has been playing with our symlink, @@ -230,6 +233,29 @@ int sieve_storage_get_active_scriptfile return 1; } +int sieve_storage_get_active_scriptname +(struct sieve_storage *storage, const char **name_r) +{ + const char *link; + int ret; + + *name_r = NULL; + + /* Read the active link */ + if ( (ret=sieve_storage_read_active_link(storage, &link)) <= 0 ) + return ret; + + if ( sieve_storage_parse_link(storage, link, name_r) == NULL ) { + /* Obviously someone has been playing with our symlink, + * ignore this situation and report 'no active script'. + * Activation should fix this situation. + */ + return 0; + } + + return 1; +} + struct sieve_script *sieve_storage_get_active_script (struct sieve_storage *storage) { @@ -251,7 +277,7 @@ struct sieve_script *sieve_storage_get_active_script } /* Parse the link */ - scriptfile = sieve_storage_parse_link(storage, link); + scriptfile = sieve_storage_parse_link(storage, link, NULL); if (scriptfile == NULL) { /* Obviously someone has been playing with our symlink, diff --git a/src/lib-sievestorage/sieve-storage-script.h b/src/lib-sievestorage/sieve-storage-script.h index c440086ac..d446b0ecf 100644 --- a/src/lib-sievestorage/sieve-storage-script.h +++ b/src/lib-sievestorage/sieve-storage-script.h @@ -16,6 +16,8 @@ const char *sieve_storage_file_get_scriptname int sieve_storage_get_active_scriptfile (struct sieve_storage *storage, const char **file_r); +int sieve_storage_get_active_scriptname + (struct sieve_storage *storage, const char **name_r); struct sieve_script *sieve_storage_get_active_script (struct sieve_storage *storage); diff --git a/src/managesieve/cmd-putscript.c b/src/managesieve/cmd-putscript.c index 1165e6fa5..1fe8c0792 100644 --- a/src/managesieve/cmd-putscript.c +++ b/src/managesieve/cmd-putscript.c @@ -174,8 +174,6 @@ static bool cmd_putscript_finish_parsing(struct client_command_context *cmd) if (args[0].type == MANAGESIEVE_ARG_EOL) { struct sieve_script *script; - - /* Last (and only) script */ bool success = TRUE; /* Eat away the trailing CRLF */ @@ -194,9 +192,16 @@ static bool cmd_putscript_finish_parsing(struct client_command_context *cmd) /* Try to compile script */ T_BEGIN { struct sieve_error_handler *ehandler; + enum sieve_compile_flags cpflags = + SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_UPLOADED; struct sieve_binary *sbin; string_t *errors; + /* Mark this as an activation when we are replacing the active script */ + if ( sieve_storage_save_will_activate(ctx->save_ctx) ) { + cpflags |= SIEVE_COMPILE_FLAG_ACTIVATED; + } + /* Prepare error handler */ errors = str_new(default_pool, 1024); ehandler = sieve_strbuf_ehandler_create(client->svinst, errors, TRUE, @@ -204,7 +209,7 @@ static bool cmd_putscript_finish_parsing(struct client_command_context *cmd) /* Compile */ if ( (sbin=sieve_compile_script - (script, ehandler, SIEVE_COMPILE_FLAG_NOGLOBAL, NULL)) == NULL ) { + (script, ehandler, cpflags, NULL)) == NULL ) { client_send_no(client, str_c(errors)); success = FALSE; } else { diff --git a/src/managesieve/cmd-setactive.c b/src/managesieve/cmd-setactive.c index 3e566cd79..0cf518f60 100644 --- a/src/managesieve/cmd-setactive.c +++ b/src/managesieve/cmd-setactive.c @@ -2,7 +2,9 @@ */ #include "lib.h" +#include "str.h" +#include "sieve.h" #include "sieve-storage.h" #include "sieve-storage-script.h" @@ -14,39 +16,88 @@ bool cmd_setactive(struct client_command_context *cmd) struct client *client = cmd->client; struct sieve_storage *storage = client->storage; const char *scriptname; - struct sieve_script *script;; + struct sieve_script *script; int ret; /* <scriptname> */ if ( !client_read_string_args(cmd, 1, TRUE, &scriptname) ) return FALSE; + /* Activate, or .. */ if ( *scriptname != '\0' ) { - script = sieve_storage_script_init(storage, scriptname); + string_t *errors = NULL; + bool warnings = FALSE; + bool success = TRUE; + script = sieve_storage_script_init(storage, scriptname); if ( script == NULL ) { client_send_storage_error(client, storage); return TRUE; } + + if ( sieve_storage_script_is_active(script) <= 0 ) { + /* Script is first being activated; compile it again without the UPLOAD + * flag. + */ + T_BEGIN { + struct sieve_error_handler *ehandler; + enum sieve_compile_flags cpflags = + SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_ACTIVATED; + struct sieve_binary *sbin; + + /* Prepare error handler */ + errors = str_new(default_pool, 1024); + ehandler = sieve_strbuf_ehandler_create(client->svinst, errors, TRUE, + client->set->managesieve_max_compile_errors); + + /* Compile */ + if ( (sbin=sieve_compile_script + (script, ehandler, cpflags, NULL)) == NULL ) { + success = FALSE; + } else { + sieve_close(&sbin); + } + + warnings = ( sieve_get_warnings(ehandler) > 0 ); + sieve_error_handler_unref(&ehandler); + } T_END; + } - ret = sieve_storage_script_activate(script); - if ( ret < 0 ) - client_send_storage_error(client, storage); - else - client_send_ok(client, ret ? - "Setactive completed." : - "Script is already active."); + /* Activate only when script is valid (or already active) */ + if ( success ) { + /* Refresh activation no matter what; this can also resolve some erroneous + * situations. + */ + ret = sieve_storage_script_activate(script); + if ( ret < 0 ) { + client_send_storage_error(client, storage); + } else { + if ( warnings ) { + client_send_okresp(client, "WARNINGS", str_c(errors)); + } else { + client_send_ok(client, ( ret > 0 ? + "Setactive completed." : + "Script is already active." )); + } + } + } else { + client_send_no(client, str_c(errors)); + } + if ( errors != NULL ) + str_free(&errors); sieve_script_unref(&script); + + /* ... deactivate */ } else { ret = sieve_storage_deactivate(storage); if ( ret < 0 ) client_send_storage_error(client, storage); else - client_send_ok(client, ret ? + client_send_ok(client, ( ret > 0 ? "Active script is now deactivated." : - "No scripts currently active."); + "No scripts currently active." )); } return TRUE; -- GitLab