From 609125fd1271be86cecd66938dbee61fce7ffa64 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Tue, 20 Aug 2024 03:21:39 +0200
Subject: [PATCH] lib-sieve: sieve-extensions - Migrate Sieve extension
 settings to new config structure

---
 src/lib-sieve/sieve-extensions.c | 172 +++++++++++++++++--------------
 src/lib-sieve/sieve-settings.c   |  19 ++++
 src/lib-sieve/sieve-settings.h   |   4 +
 3 files changed, 115 insertions(+), 80 deletions(-)

diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c
index a6400c438..32eddc8c0 100644
--- a/src/lib-sieve/sieve-extensions.c
+++ b/src/lib-sieve/sieve-extensions.c
@@ -9,7 +9,6 @@
 
 #include "sieve-common.h"
 #include "sieve-error.h"
-#include "sieve-settings.old.h"
 #include "sieve-extensions.h"
 
 /*
@@ -28,6 +27,11 @@ _sieve_extension_register(struct sieve_instance *svinst,
 			  bool load, bool required,
 			  struct sieve_extension **ext_r);
 
+static int
+sieve_extensions_set_array(struct sieve_instance *svinst,
+			   const ARRAY_TYPE(const_string) *ext_names,
+			   bool global, bool implicit);
+
 /*
  * Instance global context
  */
@@ -115,7 +119,22 @@ extern const struct sieve_extension_def extracttext_extension;
 extern const struct sieve_extension_def mboxmetadata_extension;
 extern const struct sieve_extension_def servermetadata_extension;
 
-const struct sieve_extension_def *sieve_core_extensions[] = {
+extern const struct sieve_extension_def vacation_seconds_extension;
+extern const struct sieve_extension_def spamtest_extension;
+extern const struct sieve_extension_def spamtestplus_extension;
+extern const struct sieve_extension_def virustest_extension;
+extern const struct sieve_extension_def editheader_extension;
+extern const struct sieve_extension_def special_use_extension;
+
+extern const struct sieve_extension_def vnd_debug_extension;
+extern const struct sieve_extension_def vnd_environment_extension;
+extern const struct sieve_extension_def vnd_report_extension;
+
+#ifdef HAVE_SIEVE_UNFINISHED
+extern const struct sieve_extension_def ereject_extension;
+#endif
+
+const struct sieve_extension_def *sieve_extensions[] = {
 	/* Core extensions */
 	&fileinto_extension, &reject_extension, &envelope_extension,
 	&encoded_character_extension,
@@ -128,29 +147,12 @@ const struct sieve_extension_def *sieve_core_extensions[] = {
 	&variables_extension, &enotify_extension, &environment_extension,
 	&mailbox_extension, &date_extension, &index_extension, &ihave_extension,
 	&duplicate_extension, &mime_extension, &foreverypart_extension,
-	&extracttext_extension
-};
-
-const unsigned int sieve_core_extensions_count =
-	N_ELEMENTS(sieve_core_extensions);
-
-/* Extra;
- *   These are not enabled by default, e.g. because explicit configuration is
- *   necessary to make these useful.
- */
+	&extracttext_extension,
 
-extern const struct sieve_extension_def vacation_seconds_extension;
-extern const struct sieve_extension_def spamtest_extension;
-extern const struct sieve_extension_def spamtestplus_extension;
-extern const struct sieve_extension_def virustest_extension;
-extern const struct sieve_extension_def editheader_extension;
-extern const struct sieve_extension_def special_use_extension;
-
-extern const struct sieve_extension_def vnd_debug_extension;
-extern const struct sieve_extension_def vnd_environment_extension;
-extern const struct sieve_extension_def vnd_report_extension;
-
-const struct sieve_extension_def *sieve_extra_extensions[] = {
+	/* Extra;
+	   These are not enabled by default, e.g. because explicit configuration
+	   is necessary to make these useful.
+	*/
 	&vacation_seconds_extension, &spamtest_extension,
 	&spamtestplus_extension, &virustest_extension, &editheader_extension,
 	&mboxmetadata_extension, &servermetadata_extension,
@@ -158,27 +160,14 @@ const struct sieve_extension_def *sieve_extra_extensions[] = {
 
 	/* vnd.dovecot. */
 	&vnd_debug_extension, &vnd_environment_extension, &vnd_report_extension,
-};
-
-const unsigned int sieve_extra_extensions_count =
-	N_ELEMENTS(sieve_extra_extensions);
-
-/*
- * Unfinished extensions
- */
 
 #ifdef HAVE_SIEVE_UNFINISHED
-
-extern const struct sieve_extension_def ereject_extension;
-
-const struct sieve_extension_def *sieve_unfinished_extensions[] = {
-	&ereject_extension
+	/* Unfinished extensions */
+	&ereject_extension,
+#endif
 };
 
-const unsigned int sieve_unfinished_extensions_count =
-	N_ELEMENTS(sieve_unfinished_extensions);
-
-#endif /* HAVE_SIEVE_UNFINISHED */
+const unsigned int sieve_extensions_count = N_ELEMENTS(sieve_extensions);
 
 /*
  * Extensions init/deinit
@@ -226,60 +215,34 @@ int sieve_extensions_init(struct sieve_instance *svinst)
 	}
 
 	/* Pre-load core extensions */
-	for (i = 0; i < sieve_core_extensions_count; i++) {
-		if (sieve_extension_register(svinst, sieve_core_extensions[i],
-					     TRUE, NULL) < 0)
-			return -1;
-	}
-
-	/* Pre-load extra extensions */
-	for (i = 0; i < sieve_extra_extensions_count; i++) {
-		if (sieve_extension_register(svinst, sieve_extra_extensions[i],
+	for (i = 0; i < sieve_extensions_count; i++) {
+		if (sieve_extension_register(svinst, sieve_extensions[i],
 					     FALSE, NULL) < 0)
 			return -1;
 	}
 
-#ifdef HAVE_SIEVE_UNFINISHED
-	/* Register unfinished extensions */
-	for (i = 0; i < sieve_unfinished_extensions_count; i++) {
-		if (sieve_extension_register(
-			svinst, sieve_unfinished_extensions[i], FALSE,
-			NULL) < 0)
-			return -1;
-	}
-#endif
-
 	/* More extensions can be added through plugins */
 	return 0;
 }
 
 int sieve_extensions_load(struct sieve_instance *svinst)
 {
-	const char *extensions;
-
 	/* Apply sieve_extensions configuration */
-	if ((extensions = sieve_setting_get(
-		svinst, "sieve_extensions")) != NULL) {
-		if (sieve_extensions_set_string(svinst, extensions,
-						FALSE, FALSE) < 0)
-			return -1;
-	}
+	if (sieve_extensions_set_array(svinst, &svinst->set->extensions,
+				       FALSE, FALSE) < 0)
+		return -1;
 
 	/* Apply sieve_global_extensions configuration */
-	if ((extensions = sieve_setting_get(
-		svinst, "sieve_global_extensions")) != NULL) {
-		if (sieve_extensions_set_string(svinst, extensions,
-						TRUE, FALSE) < 0)
-			return -1;
-	}
+	if (sieve_extensions_set_array(svinst, &svinst->set->global_extensions,
+				       TRUE, FALSE) < 0)
+		return -1;
 
 	/* Apply sieve_implicit_extensions configuration */
-	if ((extensions = sieve_setting_get(
-		svinst, "sieve_implicit_extensions")) != NULL) {
-		if (sieve_extensions_set_string(svinst, extensions,
-						FALSE, TRUE) < 0)
-			return -1;
-	}
+	if (sieve_extensions_set_array(svinst,
+				       &svinst->set->implicit_extensions,
+				       FALSE, TRUE) < 0)
+		return -1;
+
 	return 0;
 }
 
@@ -679,6 +642,55 @@ sieve_extension_set_implicit(struct sieve_extension *ext, bool enabled)
 	return ret;
 }
 
+static int
+sieve_extensions_set_array(struct sieve_instance *svinst,
+			   const ARRAY_TYPE(const_string) *ext_names,
+			   bool global, bool implicit)
+{
+	struct sieve_extension_registry *ext_reg = svinst->ext_reg;
+	const char *name;
+
+	if (array_is_empty(ext_names))
+		return 0;
+
+	int ret = 0;
+	array_foreach_elem(ext_names, name) {
+		struct sieve_extension *ext;
+
+		ext = hash_table_lookup(ext_reg->extension_index, name);
+		if (ext == NULL || ext->def == NULL ||
+		    *(ext->def->name) == '@') {
+			e_warning(svinst->event,
+				  "ignored unknown extension '%s' "
+				  "while configuring available extensions",
+				  name);
+			continue;
+		}
+		if (ext->id < 0)
+			continue;
+
+		/* Perform actual activation/deactivation */
+		if (global) {
+			if (sieve_extension_set_global(ext, TRUE) < 0) {
+				ret = -1;
+				break;
+			}
+		} else if (implicit) {
+			if (sieve_extension_set_implicit(ext, TRUE) < 0) {
+				ret = -1;
+				break;
+			}
+		} else {
+			if (sieve_extension_set_enabled(ext, TRUE) < 0) {
+				ret = -1;
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
 int sieve_extensions_set_string(struct sieve_instance *svinst,
 				const char *ext_string, bool global,
 				bool implicit)
diff --git a/src/lib-sieve/sieve-settings.c b/src/lib-sieve/sieve-settings.c
index 8320d35d7..68ce06386 100644
--- a/src/lib-sieve/sieve-settings.c
+++ b/src/lib-sieve/sieve-settings.c
@@ -40,6 +40,10 @@ static const struct setting_define sieve_setting_defines[] = {
 	DEF(BOOLLIST, plugins),
 	DEF(STR, plugin_dir),
 
+	DEF(BOOLLIST, extensions),
+	DEF(BOOLLIST, global_extensions),
+	DEF(BOOLLIST, implicit_extensions),
+
 	SETTING_DEFINE_LIST_END,
 };
 
@@ -66,6 +70,20 @@ const struct sieve_settings sieve_default_settings = {
 
 	.plugins = ARRAY_INIT,
 	.plugin_dir = MODULEDIR"/sieve",
+
+	.extensions = ARRAY_INIT,
+	.global_extensions = ARRAY_INIT,
+	.implicit_extensions = ARRAY_INIT,
+};
+
+static const struct setting_keyvalue sieve_default_settings_keyvalue[] = {
+	{ "sieve_extensions",
+	  "fileinto reject envelope encoded-character vacation subaddress "
+	  "comparator-i;ascii-numeric relational regex imap4flags copy include "
+	  "body variables enotify environment mailbox date index ihave "
+	  "duplicate mime foreverypart extracttext"
+	},
+	{ NULL, NULL }
 };
 
 const struct setting_parser_info sieve_setting_parser_info = {
@@ -73,6 +91,7 @@ const struct setting_parser_info sieve_setting_parser_info = {
 
 	.defines = sieve_setting_defines,
 	.defaults = &sieve_default_settings,
+	.default_settings = sieve_default_settings_keyvalue,
 
 	.struct_size = sizeof(struct sieve_settings),
 
diff --git a/src/lib-sieve/sieve-settings.h b/src/lib-sieve/sieve-settings.h
index dc63b621a..158ce0f59 100644
--- a/src/lib-sieve/sieve-settings.h
+++ b/src/lib-sieve/sieve-settings.h
@@ -35,6 +35,10 @@ struct sieve_settings {
 	ARRAY_TYPE(const_string) plugins;
 	const char *plugin_dir;
 
+	ARRAY_TYPE(const_string) extensions;
+	ARRAY_TYPE(const_string) global_extensions;
+	ARRAY_TYPE(const_string) implicit_extensions;
+
 	struct {
 		struct sieve_address_source redirect_envelope_from;
 		const struct smtp_address *user_email;
-- 
GitLab