summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/lib-sieve/sieve-match.c
diff options
context:
space:
mode:
Diffstat (limited to 'pigeonhole/src/lib-sieve/sieve-match.c')
-rw-r--r--pigeonhole/src/lib-sieve/sieve-match.c293
1 files changed, 293 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/sieve-match.c b/pigeonhole/src/lib-sieve/sieve-match.c
new file mode 100644
index 0000000..37d37fe
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/sieve-match.c
@@ -0,0 +1,293 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "mempool.h"
+#include "hash.h"
+#include "array.h"
+#include "str-sanitize.h"
+
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-stringlist.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-dump.h"
+#include "sieve-comparators.h"
+#include "sieve-match-types.h"
+#include "sieve-runtime-trace.h"
+
+#include "sieve-match.h"
+
+/*
+ * Matching implementation
+ */
+
+struct sieve_match_context *sieve_match_begin
+(const struct sieve_runtime_env *renv,
+ const struct sieve_match_type *mcht,
+ const struct sieve_comparator *cmp)
+{
+ struct sieve_match_context *mctx;
+ pool_t pool;
+
+ /* Reject unimplemented match-type */
+ if ( mcht->def == NULL || (mcht->def->match == NULL &&
+ mcht->def->match_keys == NULL && mcht->def->match_key == NULL) )
+ return NULL;
+
+ /* Create match context */
+ pool = pool_alloconly_create("sieve_match_context", 1024);
+ mctx = p_new(pool, struct sieve_match_context, 1);
+ mctx->pool = pool;
+ mctx->runenv = renv;
+ mctx->match_type = mcht;
+ mctx->comparator = cmp;
+ mctx->exec_status = SIEVE_EXEC_OK;
+ mctx->trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
+
+ /* Trace */
+ if ( mctx->trace ) {
+ sieve_runtime_trace_descend(renv);
+ sieve_runtime_trace(renv, 0,
+ "starting `:%s' match with `%s' comparator:",
+ sieve_match_type_name(mcht), sieve_comparator_name(cmp));
+ }
+
+ /* Initialize match type */
+ if ( mcht->def != NULL && mcht->def->match_init != NULL ) {
+ mcht->def->match_init(mctx);
+ }
+
+ return mctx;
+}
+
+int sieve_match_value
+(struct sieve_match_context *mctx, const char *value, size_t value_size,
+ struct sieve_stringlist *key_list)
+{
+ const struct sieve_match_type *mcht = mctx->match_type;
+ const struct sieve_runtime_env *renv = mctx->runenv;
+ int match, ret;
+
+ if ( mctx->trace ) {
+ sieve_runtime_trace(renv, 0,
+ "matching value `%s'", str_sanitize(value, 80));
+ }
+
+ /* Match to key values */
+
+ sieve_stringlist_reset(key_list);
+
+ if ( mctx->trace )
+ sieve_stringlist_set_trace(key_list, TRUE);
+
+ sieve_runtime_trace_descend(renv);
+
+ if ( mcht->def->match_keys != NULL ) {
+ /* Call match-type's own key match handler */
+ match = mcht->def->match_keys(mctx, value, value_size, key_list);
+ } else {
+ string_t *key_item = NULL;
+
+ /* Default key match loop */
+ match = 0;
+ while ( match == 0 &&
+ (ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 ) {
+ T_BEGIN {
+ match = mcht->def->match_key
+ (mctx, value, value_size, str_c(key_item), str_len(key_item));
+
+ if ( mctx->trace ) {
+ sieve_runtime_trace(renv, 0,
+ "with key `%s' => %d", str_sanitize(str_c(key_item), 80),
+ match);
+ }
+ } T_END;
+ }
+
+ if ( ret < 0 ) {
+ mctx->exec_status = key_list->exec_status;
+ match = -1;
+ }
+ }
+
+ sieve_runtime_trace_ascend(renv);
+
+ if ( mctx->match_status < 0 || match < 0 )
+ mctx->match_status = -1;
+ else
+ mctx->match_status =
+ ( mctx->match_status > match ? mctx->match_status : match );
+ return match;
+}
+
+int sieve_match_end(struct sieve_match_context **mctx, int *exec_status)
+{
+ const struct sieve_match_type *mcht = (*mctx)->match_type;
+ const struct sieve_runtime_env *renv = (*mctx)->runenv;
+ int match = (*mctx)->match_status;
+
+ if ( mcht->def != NULL && mcht->def->match_deinit != NULL )
+ mcht->def->match_deinit(*mctx);
+
+ if ( exec_status != NULL )
+ *exec_status = (*mctx)->exec_status;
+
+ pool_unref(&(*mctx)->pool);
+
+ sieve_runtime_trace(renv, SIEVE_TRLVL_MATCHING,
+ "finishing match with result: %s",
+ ( match > 0 ? "matched" : ( match < 0 ? "error" : "not matched" ) ));
+ sieve_runtime_trace_ascend(renv);
+
+ return match;
+}
+
+int sieve_match
+(const struct sieve_runtime_env *renv,
+ const struct sieve_match_type *mcht,
+ const struct sieve_comparator *cmp,
+ struct sieve_stringlist *value_list,
+ struct sieve_stringlist *key_list,
+ int *exec_status)
+{
+ struct sieve_match_context *mctx;
+ string_t *value_item = NULL;
+ int match, ret;
+
+ if ( (mctx=sieve_match_begin(renv, mcht, cmp)) == NULL )
+ return 0;
+
+ /* Match value to keys */
+
+ sieve_stringlist_reset(value_list);
+
+ if ( mctx->trace )
+ sieve_stringlist_set_trace(value_list, TRUE);
+
+ if ( mcht->def->match != NULL ) {
+ /* Call match-type's match handler */
+ match = mctx->match_status =
+ mcht->def->match(mctx, value_list, key_list);
+
+ } else {
+ /* Default value match loop */
+
+ match = 0;
+ while ( match == 0 &&
+ (ret=sieve_stringlist_next_item(value_list, &value_item)) > 0 ) {
+
+ match = sieve_match_value
+ (mctx, str_c(value_item), str_len(value_item), key_list);
+ }
+
+ if ( ret < 0 ) {
+ mctx->exec_status = value_list->exec_status;
+ match = -1;
+ }
+ }
+
+ (void)sieve_match_end(&mctx, exec_status);
+ return match;
+}
+
+/*
+ * Reading match operands
+ */
+
+int sieve_match_opr_optional_dump
+(const struct sieve_dumptime_env *denv, sieve_size_t *address, int *opt_code)
+{
+ int _opt_code = 0;
+ bool final = FALSE, opok = TRUE;
+
+ if ( opt_code == NULL ) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ while ( opok ) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_dump(denv, address, opt_code)) <= 0 )
+ return opt;
+
+ switch ( *opt_code ) {
+ case SIEVE_MATCH_OPT_COMPARATOR:
+ opok = sieve_opr_comparator_dump(denv, address);
+ break;
+ case SIEVE_MATCH_OPT_MATCH_TYPE:
+ opok = sieve_opr_match_type_dump(denv, address);
+ break;
+ default:
+ return ( final ? -1 : 1 );
+ }
+ }
+
+ return -1;
+}
+
+int sieve_match_opr_optional_read
+(const struct sieve_runtime_env *renv, sieve_size_t *address, int *opt_code,
+ int *exec_status, struct sieve_comparator *cmp, struct sieve_match_type *mcht)
+{
+ int _opt_code = 0;
+ bool final = FALSE;
+ int status = SIEVE_EXEC_OK;
+
+ if ( opt_code == NULL ) {
+ opt_code = &_opt_code;
+ final = TRUE;
+ }
+
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_OK;
+
+ while ( status == SIEVE_EXEC_OK ) {
+ int opt;
+
+ if ( (opt=sieve_opr_optional_read(renv, address, opt_code)) <= 0 ){
+ if ( opt < 0 && exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return opt;
+ }
+
+ switch ( *opt_code ) {
+ case SIEVE_MATCH_OPT_COMPARATOR:
+ if (cmp == NULL) {
+ sieve_runtime_trace_error(renv, "unexpected comparator operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ status = sieve_opr_comparator_read(renv, address, cmp);
+ break;
+ case SIEVE_MATCH_OPT_MATCH_TYPE:
+ if (mcht == NULL) {
+ sieve_runtime_trace_error(renv, "unexpected match-type operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ status = sieve_opr_match_type_read(renv, address, mcht);
+ break;
+ default:
+ if ( final ) {
+ sieve_runtime_trace_error(renv, "invalid optional operand");
+ if ( exec_status != NULL )
+ *exec_status = SIEVE_EXEC_BIN_CORRUPT;
+ return -1;
+ }
+ return 1;
+ }
+ }
+
+ if ( exec_status != NULL )
+ *exec_status = status;
+ return -1;
+}
+