From e8c6d5243a95b4c2429e46b9e4c0dabb56a91009 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Thu, 19 Sep 2024 01:04:59 +0200
Subject: [PATCH] lib-sieve: sieve-script - Split basic storage sequence object
 from script sequence

It just returns the one storage that the provided location points to for now.
---
 src/lib-sieve/sieve-script-private.h  |  1 +
 src/lib-sieve/sieve-script.c          | 88 ++++++++++++++++++++-------
 src/lib-sieve/sieve-storage-private.h | 11 ++++
 src/lib-sieve/sieve-storage.c         | 51 ++++++++++++++++
 src/lib-sieve/sieve-storage.h         | 15 +++++
 5 files changed, 145 insertions(+), 21 deletions(-)

diff --git a/src/lib-sieve/sieve-script-private.h b/src/lib-sieve/sieve-script-private.h
index 475465f13..059233f11 100644
--- a/src/lib-sieve/sieve-script-private.h
+++ b/src/lib-sieve/sieve-script-private.h
@@ -108,6 +108,7 @@ void sieve_script_set_not_found_error(struct sieve_script *script,
  */
 
 struct sieve_script_sequence {
+	struct sieve_storage_sequence *storage_seq;
 	struct sieve_storage *storage;
 	void *storage_data;
 };
diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c
index 7871763e8..48881c0c5 100644
--- a/src/lib-sieve/sieve-script.c
+++ b/src/lib-sieve/sieve-script.c
@@ -950,42 +950,92 @@ int sieve_script_sequence_create(struct sieve_instance *svinst,
 				 struct sieve_script_sequence **sseq_r,
 				 enum sieve_error *error_code_r)
 {
-	struct sieve_storage *storage;
+	struct sieve_storage_sequence *storage_seq;
 	struct sieve_script_sequence *sseq;
-	int ret;
 
 	*sseq_r = NULL;
 	sieve_error_args_init(&error_code_r, NULL);
 
-	if (sieve_storage_create(svinst, location, 0,
-				 &storage, error_code_r) < 0)
+	if (sieve_storage_sequence_create(svinst, location,
+					  &storage_seq, error_code_r) < 0)
 		return -1;
 
 	sseq = i_new(struct sieve_script_sequence, 1);
-	sseq->storage = storage;
-
-	i_assert(storage->v.script_sequence_init != NULL);
-        ret = storage->v.script_sequence_init(sseq);
-	*error_code_r = storage->error_code;
+	sseq->storage_seq = storage_seq;
 
 	*sseq_r = sseq;
-	return ret;
+	return 0;
+}
+
+static int
+sieve_script_sequence_init_storage(struct sieve_script_sequence *sseq,
+				   enum sieve_error *error_code_r)
+{
+	int ret;
+
+	while (sseq->storage == NULL) {
+		ret = sieve_storage_sequence_next(sseq->storage_seq,
+						  &sseq->storage, error_code_r);
+		if (ret == 0)
+			return 0;
+		if (ret < 0) {
+			if (*error_code_r == SIEVE_ERROR_NOT_FOUND)
+				continue;
+			return -1;
+		}
+
+		struct sieve_storage *storage =	sseq->storage;
+
+		i_assert(storage->v.script_sequence_init != NULL);
+		*error_code_r = SIEVE_ERROR_NONE;
+		ret = storage->v.script_sequence_init(sseq);
+		*error_code_r = storage->error_code;
+		sieve_storage_unref(&sseq->storage);
+		if (ret < 0 && *error_code_r != SIEVE_ERROR_NOT_FOUND)
+			return -1;
+	}
+	return 1;
+}
+
+static void
+sieve_script_sequence_deinit_storage(struct sieve_script_sequence *sseq)
+{
+	struct sieve_storage *storage =	sseq->storage;
+
+	if (storage != NULL && storage->v.script_sequence_destroy != NULL)
+		storage->v.script_sequence_destroy(sseq);
+	sseq->storage_data = NULL;
+
+	sieve_storage_unref(&sseq->storage);
 }
 
 int sieve_script_sequence_next(struct sieve_script_sequence *sseq,
 			       struct sieve_script **script_r,
 			       enum sieve_error *error_code_r)
 {
-	struct sieve_storage *storage = sseq->storage;
 	int ret;
 
 	*script_r = NULL;
 	sieve_error_args_init(&error_code_r, NULL);
-	sieve_storage_clear_error(storage);
 
-	i_assert(storage->v.script_sequence_next != NULL);
-	ret = storage->v.script_sequence_next(sseq, script_r);
-	*error_code_r = storage->error_code;
+	while ((ret = sieve_script_sequence_init_storage(sseq, error_code_r)) > 0) {
+		struct sieve_storage *storage =	sseq->storage;
+
+		i_assert(storage->v.script_sequence_next != NULL);
+		sieve_storage_clear_error(storage);
+		ret = storage->v.script_sequence_next(sseq, script_r);
+		*error_code_r = storage->error_code;
+		if (ret > 0)
+			break;
+
+		if (ret < 0 && *error_code_r == SIEVE_ERROR_NOT_FOUND)
+			ret = 0;
+
+		sieve_script_sequence_deinit_storage(sseq);
+		if (ret < 0)
+			break;
+	}
+
 	return ret;
 }
 
@@ -997,11 +1047,7 @@ void sieve_script_sequence_free(struct sieve_script_sequence **_sseq)
 		return;
 	*_sseq = NULL;
 
-	struct sieve_storage *storage = sseq->storage;
-
-	if (storage->v.script_sequence_destroy != NULL)
-		storage->v.script_sequence_destroy(sseq);
-
-	sieve_storage_unref(&storage);
+	sieve_script_sequence_deinit_storage(sseq);
+	sieve_storage_sequence_free(&sseq->storage_seq);
 	i_free(sseq);
 }
diff --git a/src/lib-sieve/sieve-storage-private.h b/src/lib-sieve/sieve-storage-private.h
index 695b0f9bd..70f5fc88d 100644
--- a/src/lib-sieve/sieve-storage-private.h
+++ b/src/lib-sieve/sieve-storage-private.h
@@ -163,6 +163,17 @@ struct sieve_storage_save_context {
 	bool finished:1;
 };
 
+/*
+ * Storage sequence
+ */
+
+struct sieve_storage_sequence {
+	struct sieve_instance *svinst;
+	char *location;
+
+	bool done:1;
+};
+
 /*
  * Storage class
  */
diff --git a/src/lib-sieve/sieve-storage.c b/src/lib-sieve/sieve-storage.c
index dee0b127c..42ef4862a 100644
--- a/src/lib-sieve/sieve-storage.c
+++ b/src/lib-sieve/sieve-storage.c
@@ -1622,3 +1622,54 @@ sieve_storage_get_last_error(struct sieve_storage *storage,
 
 	return storage->error != NULL ? storage->error : "Unknown error";
 }
+
+/*
+ * Storage sequence
+ */
+
+int sieve_storage_sequence_create(struct sieve_instance *svinst,
+				  const char *location,
+				  struct sieve_storage_sequence **sseq_r,
+				  enum sieve_error *error_code_r)
+{
+	*sseq_r = NULL;
+	sieve_error_args_init(&error_code_r, NULL);
+
+	struct sieve_storage_sequence *sseq;
+
+	sseq = i_new(struct sieve_storage_sequence, 1);
+	sseq->svinst = svinst;
+	sseq->location = i_strdup(location);
+
+	*sseq_r = sseq;
+	return 0;
+}
+
+int sieve_storage_sequence_next(struct sieve_storage_sequence *sseq,
+				struct sieve_storage **storage_r,
+				enum sieve_error *error_code_r)
+{
+	*storage_r = NULL;
+	sieve_error_args_init(&error_code_r, NULL);
+
+	if (sseq->done)
+		return 0;
+	sseq->done = TRUE;
+
+	if (sieve_storage_create(sseq->svinst, sseq->location, 0,
+				 storage_r, error_code_r) < 0)
+		return -1;
+	return 1;
+}
+
+void sieve_storage_sequence_free(struct sieve_storage_sequence **_sseq)
+{
+	struct sieve_storage_sequence *sseq = *_sseq;
+
+	if (sseq == NULL)
+		return;
+	*_sseq = NULL;
+
+	i_free(sseq->location);
+	i_free(sseq);
+}
diff --git a/src/lib-sieve/sieve-storage.h b/src/lib-sieve/sieve-storage.h
index 5264dd1b7..61bae1373 100644
--- a/src/lib-sieve/sieve-storage.h
+++ b/src/lib-sieve/sieve-storage.h
@@ -180,4 +180,19 @@ int sieve_storage_get_last_change(struct sieve_storage *storage,
 void sieve_storage_set_modified(struct sieve_storage *storage,
 				time_t mtime);
 
+/*
+ * Storage sequence
+ */
+
+struct sieve_storage_sequence;
+
+int sieve_storage_sequence_create(struct sieve_instance *svinst,
+				  const char *location,
+				  struct sieve_storage_sequence **sseq_r,
+				  enum sieve_error *error_code_r);
+int sieve_storage_sequence_next(struct sieve_storage_sequence *sseq,
+				struct sieve_storage **storage_r,
+				enum sieve_error *error_code_r);
+void sieve_storage_sequence_free(struct sieve_storage_sequence **_sseq);
+
 #endif
-- 
GitLab