From 792852f326cc876a8d6477f52eb74db70189b6a1 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sun, 10 Feb 2008 16:41:20 +0100
Subject: [PATCH] Added code support for set modifiers.

---
 src/lib-sieve/plugins/variables/cmd-set.c     | 230 ++++++++++++++++--
 .../plugins/variables/ext-variables-common.c  |  23 +-
 .../plugins/variables/ext-variables-common.h  |   8 +
 .../plugins/variables/ext-variables.c         |  27 +-
 .../plugins/variables/sieve-ext-variables.h   |  18 ++
 5 files changed, 273 insertions(+), 33 deletions(-)

diff --git a/src/lib-sieve/plugins/variables/cmd-set.c b/src/lib-sieve/plugins/variables/cmd-set.c
index f3ae9e567..a5d8ac503 100644
--- a/src/lib-sieve/plugins/variables/cmd-set.c
+++ b/src/lib-sieve/plugins/variables/cmd-set.c
@@ -1,10 +1,15 @@
 #include "lib.h"
+#include "str.h"
+#include "array.h"
 
 #include "sieve-common.h"
+#include "sieve-extensions-private.h"
 
 #include "sieve-code.h"
 #include "sieve-ast.h"
 #include "sieve-commands.h"
+#include "sieve-binary.h"
+
 #include "sieve-validator.h"
 #include "sieve-generator.h"
 #include "sieve-interpreter.h"
@@ -12,6 +17,8 @@
 
 #include "ext-variables-common.h"
 
+#include <ctype.h>
+
 /* Forward declarations */
 
 static bool cmd_set_operation_dump
@@ -23,6 +30,8 @@ static bool cmd_set_operation_execute
 
 static bool cmd_set_registered
 	(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg);
+static bool cmd_set_pre_validate
+	(struct sieve_validator *validator, struct sieve_command_context *cmd);
 static bool cmd_set_validate
 	(struct sieve_validator *validator, struct sieve_command_context *cmd);
 static bool cmd_set_generate
@@ -38,7 +47,7 @@ const struct sieve_command cmd_set = {
 	SCT_COMMAND, 
 	2, 0, FALSE, FALSE, 
 	cmd_set_registered,
-	NULL,  
+	cmd_set_pre_validate,  
 	cmd_set_validate, 
 	cmd_set_generate, 
 	NULL 
@@ -53,6 +62,12 @@ const struct sieve_operation cmd_set_operation = {
 	cmd_set_operation_execute
 };
 
+/* Compiler context */
+struct cmd_set_context {
+	ARRAY_DEFINE(modifiers, struct ext_variables_set_modifier *);
+	
+};
+
 /* Tag validation */
 
 /* [MODIFIER]:
@@ -63,28 +78,28 @@ const struct sieve_operation cmd_set_operation = {
  */
  
 static bool tag_modifier_is_instance_of
-(struct sieve_validator *validator, 
+(struct sieve_validator *validator ATTR_UNUSED, 
 	struct sieve_command_context *cmdctx ATTR_UNUSED,	
 	struct sieve_ast_argument *arg)
 {
-	return ext_variables_set_modifier_find
-		(validator, sieve_ast_argument_tag(arg)) != NULL;
+	arg->context = (void *) ext_variables_set_modifier_find
+		(validator, sieve_ast_argument_tag(arg));
+		
+	return arg->context != NULL;
 }
 
 static bool tag_modifier_validate
 (struct sieve_validator *validator, struct sieve_ast_argument **arg, 
 	struct sieve_command_context *cmd)
 {
-	/* Skip parameter */
-	*arg = sieve_ast_argument_next(*arg);
+	struct ext_variables_set_modifier *smodf = (*arg)->context;
+	struct cmd_set_context *sctx = (struct cmd_set_context *) cmd->data;
+	
+	array_append(&sctx->modifiers, &smodf, 1);
+	
+	/* Added to modifier list; self-destruct to prevent duplicate generation */
+	*arg = sieve_ast_arguments_detach(*arg, 1);
 	
-	return TRUE;
-}
-
-static bool tag_modifier_generate
-(struct sieve_generator *generator, struct sieve_ast_argument *arg, 
-	struct sieve_command_context *cmd ATTR_UNUSED)
-{
 	return TRUE;
 }
 
@@ -92,48 +107,74 @@ const struct sieve_argument modifier_tag = {
 	"MODIFIER",
 	tag_modifier_is_instance_of, 
 	tag_modifier_validate, 
-	NULL,
-	tag_modifier_generate 
+	NULL, NULL
 };
 
 /* Pre-defined modifiers */
 
+bool mod_upperfirst_modify(string_t *in, string_t *result);
+bool mod_lowerfirst_modify(string_t *in, string_t *result);
+bool mod_upper_modify(string_t *in, string_t *result);
+bool mod_lower_modify(string_t *in, string_t *result);
+
 const struct ext_variables_set_modifier lower_modifier = {
 	"lower", 
 	EXT_VARIABLES_SET_MODIFIER_LOWER,
-	40
+	40,
+	NULL
 };
 
 const struct ext_variables_set_modifier upper_modifier = {
 	"upper", 
 	EXT_VARIABLES_SET_MODIFIER_UPPER,
-	40
+	40,
+	NULL
 };
 
 const struct ext_variables_set_modifier lowerfirst_modifier = {
 	"lowerfirst", 
 	EXT_VARIABLES_SET_MODIFIER_LOWERFIRST,
-	30
+	30,
+	NULL
 };
 
 const struct ext_variables_set_modifier upperfirst_modifier = {
 	"upperfirst", 
 	EXT_VARIABLES_SET_MODIFIER_UPPERFIRST,
-	30
+	30,
+	NULL
 };
 
 const struct ext_variables_set_modifier quotewildcard_modifier = {
 	"quotewildcard",
 	EXT_VARIABLES_SET_MODIFIER_QUOTEWILDCARD,
-	20
+	20,
+	NULL
 };
 
 const struct ext_variables_set_modifier length_modifier = {
 	"length", 
 	EXT_VARIABLES_SET_MODIFIER_LENGTH,
-	10
+	10,
+	NULL
+};
+
+const struct ext_variables_set_modifier *core_modifiers[] = {
+	&lower_modifier,
+	&upper_modifier,
+	&lowerfirst_modifier,
+	&upperfirst_modifier,
+	&quotewildcard_modifier,
+	&length_modifier
 };
 
+static struct sieve_extension_obj_registry setmodf_default_reg =
+	SIEVE_EXT_DEFINE_SET_MODIFIERS(core_modifiers);
+
+/* Modifier read */
+
+
+
 /* Command registration */
 
 static bool cmd_set_registered
@@ -146,11 +187,24 @@ static bool cmd_set_registered
 
 /* Command validation */
 
+static bool cmd_set_pre_validate
+	(struct sieve_validator *validator, struct sieve_command_context *cmd)
+{
+	pool_t pool = sieve_command_pool(cmd);
+	struct cmd_set_context *sctx = p_new(pool, struct cmd_set_context, 1);
+	
+	p_array_init(&sctx->modifiers, pool, 2);
+
+	cmd->data = (void *) sctx;
+	
+	return TRUE;
+} 
+
 static bool cmd_set_validate(struct sieve_validator *validator, 
 	struct sieve_command_context *cmd) 
-{ 	
+{ 
 	struct sieve_ast_argument *arg = cmd->first_positional;
-	
+		
 	if ( !sieve_validate_positional_argument
 		(validator, cmd, arg, "name", 1, SAAT_STRING) ) {
 		return FALSE;
@@ -175,9 +229,22 @@ static bool cmd_set_validate(struct sieve_validator *validator,
 static bool cmd_set_generate
 	(struct sieve_generator *generator,	struct sieve_command_context *ctx) 
 {
+	struct sieve_binary *sbin = sieve_generator_get_binary(generator);
+	struct cmd_set_context *sctx = (struct cmd_set_context *) ctx->data;
+	unsigned int i;	
+
 	sieve_generator_emit_operation_ext
 		(generator, &cmd_set_operation, ext_variables_my_id);
 
+	/* Generate modifiers */
+	sieve_binary_emit_byte(sbin, array_count(&sctx->modifiers));
+	for ( i = 0; i < array_count(&sctx->modifiers); i++ ) {
+		struct ext_variables_set_modifier * const * smodf =
+			array_idx(&sctx->modifiers, i);
+			
+		sieve_binary_emit_byte(sbin, (*smodf)->code);
+	} 
+
 	/* Generate arguments */
 	if ( !sieve_generate_arguments(generator, ctx, NULL) )
 		return FALSE;	
@@ -185,6 +252,34 @@ static bool cmd_set_generate
 	return TRUE;
 }
 
+/* 
+ * Modifier access
+ */
+ 
+static const struct sieve_extension_obj_registry *
+	cmd_set_modifier_registry_get
+(struct sieve_binary *sbin, unsigned int ext_index)
+{
+	int ext_id = -1; 
+	const struct sieve_variables_extension *ext;
+	
+	if ( sieve_binary_extension_get_by_index(sbin, ext_index, &ext_id) == NULL )
+		return NULL;
+
+	if ( (ext=sieve_variables_extension_get(sbin, ext_id)) == NULL ) 
+		return NULL;
+		
+	return &(ext->set_modifiers);
+}
+
+static const struct ext_variables_set_modifier *cmd_set_modifier_read
+	(struct sieve_binary *sbin, sieve_size_t *address) 
+{
+	return sieve_extension_read_obj
+		(struct ext_variables_set_modifier, sbin, address, &setmodf_default_reg, 
+			cmd_set_modifier_registry_get);
+}
+
 /* 
  * Code dump
  */
@@ -193,9 +288,24 @@ static bool cmd_set_operation_dump
 (const struct sieve_operation *op ATTR_UNUSED,
 	const struct sieve_dumptime_env *denv, sieve_size_t *address)
 {	
+	unsigned int mdfs, i;
+	
 	sieve_code_dumpf(denv, "SET");
 	sieve_code_descend(denv);
-
+	
+	if ( !sieve_binary_read_byte(denv->sbin, address, &mdfs) ) 
+		return FALSE;
+	
+	for ( i = 0; i < mdfs; i++ ) {
+		const struct ext_variables_set_modifier *modf =
+			cmd_set_modifier_read(denv->sbin, address);
+		
+		if ( modf == NULL )
+			return FALSE;
+			
+		sieve_code_dumpf(denv, "MOD: %s", modf->identifier);
+	}
+	
 	return 
 		sieve_opr_string_dump(denv, address) &&
 		sieve_opr_string_dump(denv, address);
@@ -210,13 +320,24 @@ static bool cmd_set_operation_execute
 	const struct sieve_runtime_env *renv, sieve_size_t *address)
 {	
 	struct sieve_variable_storage *storage;
-	unsigned int var_index;
+	unsigned int var_index, mdfs, i;
 	string_t *value;
 	
 	printf(">> SET\n");
 	
-	if ( !ext_variables_opr_variable_read(renv, address, &storage, &var_index) )
+	if ( !sieve_binary_read_byte(renv->sbin, address, &mdfs) ) 
 		return FALSE;
+	
+	for ( i = 0; i < mdfs; i++ ) {
+		const struct ext_variables_set_modifier *modf =
+			cmd_set_modifier_read(renv->sbin, address);
+			
+		if ( modf == NULL )
+			return FALSE;
+	}
+	
+	if ( !ext_variables_opr_variable_read(renv, address, &storage, &var_index) )
+		return FALSE;	
 		
 	if ( !sieve_opr_string_read(renv, address, &value) )
 		return FALSE;
@@ -226,7 +347,64 @@ static bool cmd_set_operation_execute
 	return TRUE;
 }
 
+/* Pre-defined modifier implementation */
+
+bool mod_upperfirst_modify(string_t *in, string_t *result)
+{
+	char *content;
+	
+	if ( in != NULL )
+		str_append_str(result, in);
+		
+	content = str_c_modifiable(result);
+	content[0] = toupper(content[0]);
+
+	return TRUE;
+}
+
+bool mod_lowerfirst_modify(string_t *in, string_t *result)
+{
+	char *content;
+	
+	if ( in != NULL )
+		str_append_str(result, in);
+		
+	content = str_c_modifiable(result);
+	content[0] = tolower(content[0]);
+	
+	return TRUE;
+}
 
+bool mod_upper_modify(string_t *in, string_t *result)
+{
+	unsigned int i;
+	char *content;
+	
+	if ( in != NULL )
+		str_append_str(result, in);
+		
+	content = str_c_modifiable(result);
+	for ( i = 0; i < str_len(result); i++ ) {
+		content[i] = toupper(content[i]);
+	}
+	
+	return TRUE;
+}
 
+bool mod_lower_modify(string_t *in, string_t *result)
+{
+	unsigned int i;
+	char *content;
+	
+	if ( in != NULL )
+		str_append_str(result, in);
+		
+	content = str_c_modifiable(result);
+	for ( i = 0; i < str_len(result); i++ ) {
+		content[i] = toupper(content[i]);
+	}
+	
+	return TRUE;
+}
 
 
diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.c b/src/lib-sieve/plugins/variables/ext-variables-common.c
index ba39f72a4..99f27becc 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-common.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-common.c
@@ -3,9 +3,11 @@
 #include "str.h"
 
 #include "sieve-common.h"
+
 #include "sieve-ast.h"
 #include "sieve-binary.h"
 #include "sieve-code.h"
+
 #include "sieve-commands.h"
 #include "sieve-validator.h"
 #include "sieve-generator.h"
@@ -32,6 +34,25 @@ const struct ext_variables_set_modifier *default_set_modifiers[] = {
 
 const unsigned int default_set_modifiers_count = 
 	N_ELEMENTS(default_set_modifiers);
+	
+/*
+ * Binary context
+ */
+
+const struct sieve_variables_extension *
+	sieve_variables_extension_get(struct sieve_binary *sbin, int ext_id)
+{
+	return (const struct sieve_variables_extension *)
+		sieve_binary_registry_get_object(sbin, ext_variables_my_id, ext_id);
+}
+
+void sieve_variables_extension_set
+	(struct sieve_binary *sbin, int ext_id,
+		const struct sieve_variables_extension *ext)
+{
+	sieve_binary_registry_set_object
+		(sbin, ext_variables_my_id, ext_id, (const void *) ext);
+}
 
 /* Variable scope */
 
@@ -515,7 +536,7 @@ static bool opr_variable_dump
 	sieve_size_t index = 0;
 	
 	if (sieve_binary_read_integer(denv->sbin, address, &index) ) {
-		sieve_code_dumpf(denv, "VARIABLE: %ld [?]", (long) index);
+		sieve_code_dumpf(denv, "VAR: %ld", (long) index);
 
 		return TRUE;
 	}
diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.h b/src/lib-sieve/plugins/variables/ext-variables-common.h
index 7e9db1f19..aac6dcacf 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-common.h
+++ b/src/lib-sieve/plugins/variables/ext-variables-common.h
@@ -40,11 +40,15 @@ struct ext_variables_set_modifier {
 	int code;
 	
 	unsigned int precedence;
+	
+	bool (*modify)(string_t *in, string_t *result);
 };
 
 const struct ext_variables_set_modifier *ext_variables_set_modifier_find
 	(struct sieve_validator *validator, const char *identifier);
 	
+extern const struct ext_variables_set_modifier *core_modifiers[];
+	
 /* Arguments */
 
 extern const struct sieve_argument variable_string_argument;
@@ -68,6 +72,10 @@ struct sieve_variable *ext_variables_validator_get_variable
 
 struct sieve_variable_storage *ext_variables_interpreter_get_storage
 	(struct sieve_interpreter *interp);
+	
+/* Extensions */
 
+const struct sieve_variables_extension *
+	sieve_variables_extension_get(struct sieve_binary *sbin, int ext_id);
 
 #endif /* __EXT_VARIABLES_COMMON_H */
diff --git a/src/lib-sieve/plugins/variables/ext-variables.c b/src/lib-sieve/plugins/variables/ext-variables.c
index 0b3828892..bb3e793d8 100644
--- a/src/lib-sieve/plugins/variables/ext-variables.c
+++ b/src/lib-sieve/plugins/variables/ext-variables.c
@@ -3,7 +3,7 @@
  *
  * Authors: Stephan Bosch
  * Specification: draft-ietf-sieve-variables-08.txt
- * Implementation: skeleton
+ * Implementation: basic variables support
  * Status: under development
  *
  */
@@ -14,6 +14,8 @@
 
 #include "sieve-extensions.h"
 #include "sieve-commands.h"
+#include "sieve-binary.h"
+
 #include "sieve-validator.h"
 
 #include "ext-variables-common.h"
@@ -24,6 +26,7 @@
 
 static bool ext_variables_load(int ext_id);
 static bool ext_variables_validator_load(struct sieve_validator *validator);
+static bool ext_variables_binary_load(struct sieve_binary *sbin);
 static bool ext_variables_interpreter_load(struct sieve_interpreter *interp);
 
 /* Commands */
@@ -37,7 +40,8 @@ extern const struct sieve_operation cmd_set_operation;
 extern const struct sieve_operation tst_string_operation;
 
 const struct sieve_operation *ext_variables_operations[] = {
-	&cmd_set_operation, &tst_string_operation
+	&cmd_set_operation, 
+	&tst_string_operation
 };
 
 /* Operands */
@@ -45,11 +49,11 @@ const struct sieve_operation *ext_variables_operations[] = {
 extern const struct sieve_operand variable_operand;
 extern const struct sieve_operand variable_string_operand;
 
-const struct sieve_operation *ext_variables_operands[] = {
-	&variable_operand, &variable_string_operand
+const struct sieve_operand *ext_variables_operands[] = {
+	&variable_operand, 
+	&variable_string_operand
 };
 
-
 /* Extension definitions */
 
 int ext_variables_my_id;
@@ -58,7 +62,8 @@ struct sieve_extension variables_extension = {
 	"variables", 
 	ext_variables_load,
 	ext_variables_validator_load, 
-	NULL, NULL,
+	NULL, 
+	ext_variables_binary_load,
 	ext_variables_interpreter_load, 
 	SIEVE_EXT_DEFINE_OPERATIONS(ext_variables_operations), 
 	SIEVE_EXT_DEFINE_OPERANDS(ext_variables_operands)
@@ -86,6 +91,16 @@ static bool ext_variables_validator_load
 	return TRUE;
 }
 
+/* Load extension intro binary */
+
+static bool ext_variables_binary_load
+	(struct sieve_binary *sbin)
+{
+	sieve_binary_registry_init(sbin, ext_variables_my_id);
+
+	return TRUE;
+}
+
 /* Load extension into interpreter */
 
 static bool ext_variables_interpreter_load
diff --git a/src/lib-sieve/plugins/variables/sieve-ext-variables.h b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
index db9903c1a..db95aed75 100644
--- a/src/lib-sieve/plugins/variables/sieve-ext-variables.h
+++ b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
@@ -1,6 +1,9 @@
 #ifndef __SIEVE_EXT_VARIABLES_H
 #define __SIEVE_EXT_VARIABLES_H
 
+#include "sieve-common.h"
+#include "sieve-extensions.h"
+
 /* Public interface for other extensions to use */
 
 struct sieve_variable {
@@ -24,4 +27,19 @@ void sieve_variable_assign
 	(struct sieve_variable_storage *storage, unsigned int index, 
 		const string_t *value);
 
+/* Extensions */
+
+struct sieve_variables_extension {
+	const struct sieve_extension *extension;
+	
+	struct sieve_extension_obj_registry set_modifiers;
+};
+
+#define SIEVE_EXT_DEFINE_SET_MODIFIER(OP) SIEVE_EXT_DEFINE_OBJECT(OP)
+#define SIEVE_EXT_DEFINE_SET_MODIFIERS(OPS) SIEVE_EXT_DEFINE_OBJECTS(OPS)
+
+void sieve_variables_extension_set
+	(struct sieve_binary *sbin, int ext_id,
+		const struct sieve_variables_extension *ext);
+
 #endif /* __SIEVE_EXT_VARIABLES_H */
-- 
GitLab