[pmg-devel] [PATCH pmg-api 8/8] feature: match groups: implement matching logic

Leo Nunner l.nunner at proxmox.com
Fri Apr 7 15:42:54 CEST 2023


Implements the logic behind match groups; A match group holds
several objects inside it, and only evalutes to true if ALL the
contained objects evaluate to true. Match groups are connected via
logical 'or' to all other objects inside the rule:

- Rule
    - Match Group
	- Object 1
	- Object 2
    - Object 3

This rule will match if either (Object 1 && Object 2), or if Object 3
evaluate to true.

Signed-off-by: Leo Nunner <l.nunner at proxmox.com>
---
RFC: This might be a bit weird for What objects: currently, it checks if
there are matches for each of the objects inside the match groups; if
one exists, *all* marks get pushed to the list. I'm not sure if this is
exactly what we want, but I can't really think of a better way here.

 src/PMG/RuleCache.pm | 50 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 43 insertions(+), 7 deletions(-)

diff --git a/src/PMG/RuleCache.pm b/src/PMG/RuleCache.pm
index 9a531ef..eceffaf 100644
--- a/src/PMG/RuleCache.pm
+++ b/src/PMG/RuleCache.pm
@@ -253,11 +253,19 @@ sub from_match {
 	$ip = $1;
     }
 
+    # don't return true if there are no elements marked with and!
+    my $and = grep { $_->{and} } @$from;
     foreach my $obj (@$from) {
-	return 1 if ($obj->who_match($addr, $ip, $ldap) xor $obj->{negate});
+	my $match = ($obj->who_match($addr, $ip, $ldap) xor $obj->{negate});
+
+	if ($obj->{and}) {
+	    $and &&= $match;
+	} else {
+	    return 1 if $match;
+	}
     }
 
-    return 0;
+    return $and;
 }
 
 sub to_match {
@@ -267,11 +275,18 @@ sub to_match {
 
     return 1 if !defined ($to);
 
+    my $and = grep { $_->{and} } @$to;
     foreach my $obj (@$to) {
-	return 1 if ($obj->who_match($addr, undef, $ldap) xor $obj->{negate});
+	my $match = ($obj->who_match($addr, undef, $ldap) xor $obj->{negate});
+
+	if ($obj->{and}) {
+	    $and &&= $match;
+	} else {
+	    return 1 if $match;
+	}
     }
 
-    return 0;
+    return $and;
 }
 
 sub when_match {
@@ -281,11 +296,18 @@ sub when_match {
 
     return 1 if !defined ($when);
 
+    my $and = grep { $_->{and} } @$when;
     foreach my $obj (@$when) {
-	return 1 if ($obj->when_match($time) xor $obj->{negate});
+	my $match = ($obj->when_match($time) xor $obj->{negate});
+
+	if ($obj->{and}) {
+	    $and &&= $match;
+	} else {
+	    return 1 if $match;
+	}
     }
 
-    return 0;
+    return $and;
 }
 
 sub what_match {
@@ -311,14 +333,28 @@ sub what_match {
 
     my $marks;
 
+    # First, we loop through all objects which are not 'Spam Filter'
+    my $group_valid = 1;
+    my @group_matches = ();
     foreach my $obj (@$what) {
 	if (!$obj->can('what_match_targets')) {
 	    if (my $match = $obj->what_match($queue, $element, $msginfo, $dbh)) {
-		push @$marks, @$match;
+		if ($obj->{and}) {
+		    push @group_matches, $match;
+		} else {
+		    push @$marks, @$match;
+		}
+	    } elsif ($obj->{and}) {
+		$group_valid = 0;
 	    }
 	}
     }
 
+    # If the 'Match All' group matches, push everything into the list
+    if ($group_valid) {
+	push(@$marks, @group_matches);
+    }
+
     foreach my $target (@{$msginfo->{targets}}) {
 	$res->{$target}->{marks} = $marks;
 	$res->{marks} = $marks;
-- 
2.30.2





More information about the pmg-devel mailing list