This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch 3.9.x
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 2eadff76e645cf1c275adcfc65cf1a2c77bf8513
Author: Rene Cordier <[email protected]>
AuthorDate: Fri Sep 19 16:54:10 2025 +0700

    JAMES-4148 Refactor HeaderExtractor to be able to extract headers on 
MessageResult and Mail
---
 .../james/jmap/mailet/filter/FilteringHeaders.java | 92 ++++++++++++++++++++++
 .../james/jmap/mailet/filter/HeaderExtractor.java  | 23 +++---
 .../james/jmap/mailet/filter/MailMatcher.java      |  7 +-
 .../james/jmap/mailet/filter/RuleMatcher.java      | 13 ++-
 4 files changed, 118 insertions(+), 17 deletions(-)

diff --git 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/FilteringHeaders.java
 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/FilteringHeaders.java
new file mode 100644
index 0000000000..264847e74b
--- /dev/null
+++ 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/FilteringHeaders.java
@@ -0,0 +1,92 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.mailet.filter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import jakarta.mail.MessagingException;
+
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.Header;
+import org.apache.james.mailbox.model.Headers;
+import org.apache.james.mailbox.model.MessageResult;
+import org.apache.mailet.Mail;
+
+public interface FilteringHeaders {
+    class MailFilteringHeaders implements FilteringHeaders {
+        private final Mail mail;
+
+        public MailFilteringHeaders(Mail mail) {
+            this.mail = mail;
+        }
+
+        @Override
+        public String[] getHeader(String name) throws MessagingException {
+            return mail.getMessage().getHeader(name);
+        }
+
+        @Override
+        public String getSubject() throws MessagingException {
+            return mail.getMessage().getSubject();
+        }
+    }
+
+    class MessageResultFilteringHeaders implements FilteringHeaders {
+        private final Headers headers;
+
+        public MessageResultFilteringHeaders(MessageResult messageResult) 
throws MailboxException {
+            this.headers = messageResult.getHeaders();
+        }
+
+        @Override
+        public String[] getHeader(String name) throws MailboxException {
+            return getMatchingHeaders(name);
+        }
+
+        @Override
+        public String getSubject() throws MailboxException {
+            return Arrays.stream(getMatchingHeaders("Subject"))
+                .findFirst()
+                .orElse(null);
+        }
+
+        private String[] getMatchingHeaders(String name) throws 
MailboxException {
+            final List<String> results = new ArrayList<>();
+            if (name != null) {
+                Iterator<Header> iterator = headers.headers();
+                while (iterator.hasNext()) {
+                    Header header = iterator.next();
+                    final String headerName = header.getName();
+                    if (name.equalsIgnoreCase(headerName)) {
+                        results.add(header.getValue());
+                    }
+                }
+            }
+            return results.toArray(new String[0]);
+        }
+    }
+
+    String[] getHeader(String name) throws Exception;
+
+    String getSubject() throws Exception;
+}
diff --git 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/HeaderExtractor.java
 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/HeaderExtractor.java
index 72430ad960..c5a57ffa11 100644
--- 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/HeaderExtractor.java
+++ 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/HeaderExtractor.java
@@ -32,7 +32,6 @@ import org.apache.james.javax.AddressHelper;
 import org.apache.james.jmap.api.filtering.Rule;
 import org.apache.james.mime4j.util.MimeUtil;
 import org.apache.james.util.StreamUtils;
-import org.apache.mailet.Mail;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,15 +40,15 @@ import com.github.fge.lambdas.functions.ThrowingFunction;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 
-public interface HeaderExtractor extends ThrowingFunction<Mail, 
Stream<String>> {
+public interface HeaderExtractor extends ThrowingFunction<FilteringHeaders, 
Stream<String>> {
     Logger LOGGER = LoggerFactory.getLogger(HeaderExtractor.class);
 
-    HeaderExtractor SUBJECT_EXTRACTOR = mail ->
-        StreamUtils.ofNullables(mail.getMessage().getSubject());
+    HeaderExtractor SUBJECT_EXTRACTOR = filteringHeaders ->
+        StreamUtils.ofNullables(filteringHeaders.getSubject());
     HeaderExtractor CC_EXTRACTOR = 
recipientExtractor(Message.RecipientType.CC);
     HeaderExtractor TO_EXTRACTOR = 
recipientExtractor(Message.RecipientType.TO);
     HeaderExtractor RECIPIENT_EXTRACTOR = and(TO_EXTRACTOR, CC_EXTRACTOR);
-    HeaderExtractor FROM_EXTRACTOR = addressExtractor(mail -> 
mail.getMessage().getHeader(FROM), FROM);
+    HeaderExtractor FROM_EXTRACTOR = addressExtractor(filteringHeaders -> 
filteringHeaders.getHeader(FROM), FROM);
 
     Map<Rule.Condition.Field, HeaderExtractor> HEADER_EXTRACTOR_REGISTRY = 
ImmutableMap.<Rule.Condition.Field, HeaderExtractor>builder()
         .put(Rule.Condition.FixedField.SUBJECT, SUBJECT_EXTRACTOR)
@@ -62,23 +61,23 @@ public interface HeaderExtractor extends 
ThrowingFunction<Mail, Stream<String>>
     boolean STRICT_PARSING = true;
 
     static HeaderExtractor and(HeaderExtractor headerExtractor1, 
HeaderExtractor headerExtractor2) {
-        return (Mail mail) -> 
StreamUtils.flatten(headerExtractor1.apply(mail), headerExtractor2.apply(mail));
+        return (FilteringHeaders filteringHeaders) -> 
StreamUtils.flatten(headerExtractor1.apply(filteringHeaders), 
headerExtractor2.apply(filteringHeaders));
     }
 
     static HeaderExtractor recipientExtractor(Message.RecipientType type) {
         String headerName = type.toString();
-        ThrowingFunction<Mail, String[]> addressGetter = mail -> 
mail.getMessage().getHeader(headerName);
+        ThrowingFunction<FilteringHeaders, String[]> addressGetter = 
filteringHeaders -> filteringHeaders.getHeader(headerName);
 
         return addressExtractor(addressGetter, headerName);
     }
 
-    static HeaderExtractor addressExtractor(ThrowingFunction<Mail, String[]> 
addressGetter, String fallbackHeaderName) {
-        return mail -> {
+    static HeaderExtractor addressExtractor(ThrowingFunction<FilteringHeaders, 
String[]> addressGetter, String fallbackHeaderName) {
+        return filteringHeaders -> {
             try {
-                return toAddressContents(addressGetter.apply(mail));
+                return 
toAddressContents(addressGetter.apply(filteringHeaders));
             } catch (Exception e) {
                 LOGGER.info("Failed parsing header. Falling back to unparsed 
header value matching", e);
-                return 
Stream.of(mail.getMessage().getHeader(fallbackHeaderName))
+                return 
Stream.of(filteringHeaders.getHeader(fallbackHeaderName))
                     .map(MimeUtil::unscrambleHeaderValue);
             }
         };
@@ -96,7 +95,7 @@ public interface HeaderExtractor extends 
ThrowingFunction<Mail, Stream<String>>
                 Preconditions.checkArgument(field instanceof 
Rule.Condition.CustomHeaderField);
                 Rule.Condition.CustomHeaderField customHeaderField = 
(Rule.Condition.CustomHeaderField) field;
 
-                return Optional.of(mail -> 
StreamUtils.ofNullables(mail.getMessage().getHeader(customHeaderField.headerName())));
+                return Optional.of(filteringHeaders -> 
StreamUtils.ofNullables(filteringHeaders.getHeader(customHeaderField.headerName())));
             });
     }
 }
diff --git 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java
 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java
index f583561cad..dc433411e8 100644
--- 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java
+++ 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/MailMatcher.java
@@ -23,7 +23,6 @@ import java.util.List;
 import java.util.stream.Stream;
 
 import org.apache.james.jmap.api.filtering.Rule;
-import org.apache.mailet.Mail;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,10 +45,10 @@ public interface MailMatcher {
         }
 
         @Override
-        public boolean match(Mail mail) {
+        public boolean match(FilteringHeaders filteringHeaders) {
             try {
                 Predicate<MailMatchingCondition> predicate = 
(MailMatchingCondition mailMatchingCondition) -> {
-                    Stream<String> headerLines = 
mailMatchingCondition.getHeaderExtractor().apply(mail);
+                    Stream<String> headerLines = 
mailMatchingCondition.getHeaderExtractor().apply(filteringHeaders);
                     return 
mailMatchingCondition.getContentMatcher().match(headerLines, 
mailMatchingCondition.getRuleValue());
                 };
 
@@ -107,5 +106,5 @@ public interface MailMatcher {
             ).collect(ImmutableList.toImmutableList()), 
rule.getConditionGroup().getConditionCombiner());
     }
 
-    boolean match(Mail mail);
+    boolean match(FilteringHeaders filteringHeaders);
 }
diff --git 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/RuleMatcher.java
 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/RuleMatcher.java
index 07f0371182..4e59fb4611 100644
--- 
a/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/RuleMatcher.java
+++ 
b/server/protocols/jmap-rfc-8621/src/main/java/org/apache/james/jmap/mailet/filter/RuleMatcher.java
@@ -23,6 +23,8 @@ import java.util.List;
 import java.util.stream.Stream;
 
 import org.apache.james.jmap.api.filtering.Rule;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MessageResult;
 import org.apache.mailet.Mail;
 
 import com.google.common.base.Preconditions;
@@ -37,7 +39,16 @@ class RuleMatcher {
     }
 
     Stream<Rule> findApplicableRules(Mail mail) {
+        FilteringHeaders filteringHeaders = new 
FilteringHeaders.MailFilteringHeaders(mail);
+
+        return filteringRules.stream()
+            .filter(rule -> MailMatcher.from(rule).match(filteringHeaders));
+    }
+
+    Stream<Rule> findApplicableRules(MessageResult messageResult) throws 
MailboxException {
+        FilteringHeaders filteringHeaders = new 
FilteringHeaders.MessageResultFilteringHeaders(messageResult);
+
         return filteringRules.stream()
-            .filter(rule -> MailMatcher.from(rule).match(mail));
+            .filter(rule -> MailMatcher.from(rule).match(filteringHeaders));
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to