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

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


The following commit(s) were added to refs/heads/master by this push:
     new c80ea10788 [FIX] Attachment filename should be indexed when missing in 
the `Content-Disposition` header but exists in the `Content-Type` header
c80ea10788 is described below

commit c80ea107886e8798f44c7e348e10f66371206b58
Author: Quan Tran <hqt...@linagora.com>
AuthorDate: Tue May 20 16:32:20 2025 +0700

    [FIX] Attachment filename should be indexed when missing in the 
`Content-Disposition` header but exists in the `Content-Type` header
---
 .../opensearch/json/IndexableMessageTest.java      | 35 ++++++++++++++++
 .../src/test/resources/eml/alternative.json        |  4 +-
 .../eml/attachments-filename-in-content-type.eml   | 48 ++++++++++++++++++++++
 .../mailbox/store/search/mime/MimePartParser.java  |  8 +++-
 .../eml/attachment-filename-in-content-type.eml    | 43 +++++++++++++++++++
 .../contract/EmailQueryMethodContract.scala        | 44 ++++++++++++++++++++
 6 files changed, 178 insertions(+), 4 deletions(-)

diff --git 
a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/IndexableMessageTest.java
 
b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/IndexableMessageTest.java
index 04385ae896..3836ae127f 100644
--- 
a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/IndexableMessageTest.java
+++ 
b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/json/IndexableMessageTest.java
@@ -250,6 +250,41 @@ class IndexableMessageTest {
         assertThat(indexableMessage.getAttachments()).isNotEmpty();
     }
 
+    @Test
+    void 
attachmentsFilenameShouldFallbackToContentTypeWhenFilenameIsMissingInContentDisposition()
 throws Exception {
+        //Given
+        MailboxMessage mailboxMessage = mock(MailboxMessage.class);
+        TestId mailboxId = TestId.of(1);
+        when(mailboxMessage.getMailboxId())
+            .thenReturn(mailboxId);
+        when(mailboxMessage.getModSeq())
+            .thenReturn(ModSeq.first());
+        when(mailboxMessage.getMessageId())
+            .thenReturn(InMemoryMessageId.of(42));
+        when(mailboxMessage.getFullContent())
+            
.thenReturn(ClassLoader.getSystemResourceAsStream("eml/attachments-filename-in-content-type.eml"));
+        when(mailboxMessage.createFlags())
+            .thenReturn(new Flags());
+        when(mailboxMessage.getUid())
+            .thenReturn(MESSAGE_UID);
+
+        // When
+        IndexableMessage indexableMessage = IndexableMessage.builder()
+            .message(mailboxMessage)
+            .extractor(new DefaultTextExtractor())
+            .zoneId(ZoneId.of("Europe/Paris"))
+            .indexAttachments(IndexAttachments.YES)
+            .indexHeaders(IndexHeaders.YES)
+            .build()
+            .block();
+
+        // Then
+        
assertThat(indexableMessage.getAttachments().getFirst().fileName()).isEqualTo(Optional.of("1.txt"));
+        
assertThat(indexableMessage.getAttachments().getFirst().fileExtension()).isEqualTo(Optional.of("txt"));
+        
assertThat(indexableMessage.getAttachments().get(1).fileName()).isEqualTo(Optional.of("2.txt"));
+        
assertThat(indexableMessage.getAttachments().get(1).fileExtension()).isEqualTo(Optional.of("txt"));
+    }
+
     @SuppressWarnings("checkstyle:LocalVariableName")
     @Test
     void otherAttachmentsShouldBeenIndexedWhenOneOfThemCannotBeParsed() throws 
Exception {
diff --git a/mailbox/opensearch/src/test/resources/eml/alternative.json 
b/mailbox/opensearch/src/test/resources/eml/alternative.json
index 4c08c45d45..86a63fc739 100644
--- a/mailbox/opensearch/src/test/resources/eml/alternative.json
+++ b/mailbox/opensearch/src/test/resources/eml/alternative.json
@@ -3,8 +3,8 @@
     {
       "mediaType":"application",
       "subtype":"json",
-      "fileName":null,
-      "fileExtension":null,
+      "fileName":"id_rsa.txt",
+      "fileExtension":"txt",
       "contentDisposition":"attachment",
       "textContent":null
     }
diff --git 
a/mailbox/opensearch/src/test/resources/eml/attachments-filename-in-content-type.eml
 
b/mailbox/opensearch/src/test/resources/eml/attachments-filename-in-content-type.eml
new file mode 100644
index 0000000000..837b4fc121
--- /dev/null
+++ 
b/mailbox/opensearch/src/test/resources/eml/attachments-filename-in-content-type.eml
@@ -0,0 +1,48 @@
+MIME-Version: 1.0
+Subject: Hello xyz
+From: Bob <b...@linagora.com>
+To: al...@linagora.com
+Message-ID: <mime4j.14.31ce45ac61ec422b.196e75cc...@linagora.com>
+User-Agent: Twake-Mail/0.15.3 Mozilla/5.0 (Macintosh; Intel Mac OS X
+ 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0
+ Safari/537.36
+Content-Type: multipart/mixed;
+ boundary="-=Part.16.2ce5c5497f23d613.196e75cd044.32ca13e0fd5dd663=-"
+
+---=Part.16.2ce5c5497f23d613.196e75cd044.32ca13e0fd5dd663=-
+Content-Type: multipart/alternative;
+ boundary="-=Part.15.4e5239b38c309d78.196e75cd043.9d6830842151817f=-"
+
+---=Part.15.4e5239b38c309d78.196e75cd043.9d6830842151817f=-
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+Accept-Language: fr-FR, en-US, vi-VN, ru-RU, ar-TN, it-IT, de-DE
+Content-Language: vi-VN
+
+body
+
+
+---=Part.15.4e5239b38c309d78.196e75cd043.9d6830842151817f=-
+Content-Type: text/html; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+Accept-Language: fr-FR, en-US, vi-VN, ru-RU, ar-TN, it-IT, de-DE
+Content-Language: vi-VN
+
+<div>body<br><br></div>
+---=Part.15.4e5239b38c309d78.196e75cd043.9d6830842151817f=---
+
+---=Part.16.2ce5c5497f23d613.196e75cd044.32ca13e0fd5dd663=-
+Content-Type: text/plain; name="=?US-ASCII?Q?1.txt?="; charset=windows-1252
+Content-Disposition: attachment
+Content-Transfer-Encoding: base64
+
+d2hhdGV2ZXIK
+
+---=Part.16.2ce5c5497f23d613.196e75cd044.32ca13e0fd5dd663=-
+Content-Type: text/plain; name="=?US-ASCII?Q?2.txt?="; charset=windows-1252
+Content-Disposition: attachment
+Content-Transfer-Encoding: base64
+
+d2hhdGV2ZXIyCg==
+
+---=Part.16.2ce5c5497f23d613.196e75cd044.32ca13e0fd5dd663=---
diff --git 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/mime/MimePartParser.java
 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/mime/MimePartParser.java
index 827a2270c3..3dbd62c917 100644
--- 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/mime/MimePartParser.java
+++ 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/mime/MimePartParser.java
@@ -129,8 +129,12 @@ public class MimePartParser {
             Optional.ofNullable(descriptor.getSubType())
                 .map(SubType::of)
                 .ifPresent(currentlyBuildMimePart::addSubType);
-            
currentlyBuildMimePart.addContentDisposition(descriptor.getContentDispositionType())
-                .addFileName(descriptor.getContentDispositionFilename());
+            
currentlyBuildMimePart.addContentDisposition(descriptor.getContentDispositionType());
+
+            Optional.ofNullable(descriptor.getContentDispositionFilename())
+                .or(() -> 
Optional.ofNullable(descriptor.getContentTypeParameters().get("name")))
+                .ifPresent(currentlyBuildMimePart::addFileName);
+
             extractCharset(descriptor);
         } catch (Exception e) {
             LOGGER.warn("Failed to extract mime body part description", e);
diff --git 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/resources/eml/attachment-filename-in-content-type.eml
 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/resources/eml/attachment-filename-in-content-type.eml
new file mode 100644
index 0000000000..e48ee18253
--- /dev/null
+++ 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/resources/eml/attachment-filename-in-content-type.eml
@@ -0,0 +1,43 @@
+MIME-Version: 1.0
+Subject: test send mail with attachment filename search
+From: Bob <b...@linagora.com>
+To: "al...@gmail.com" <al...@gmail.com>
+Reply-To: b...@linagora.com
+Message-ID: <mime4j.7.2182050b7626964a.196e6b48...@linagora.com>
+User-Agent: Twake-Mail/0.15.3 Mozilla/5.0 (Macintosh; Intel Mac OS X
+ 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0
+ Safari/537.36
+Content-Type: multipart/mixed;
+ boundary="-=Part.9.facdaad4d7d1e26d.196e6b48470.15f465553d6bace6=-"
+
+---=Part.9.facdaad4d7d1e26d.196e6b48470.15f465553d6bace6=-
+Content-Type: multipart/alternative;
+ boundary="-=Part.8.8fd856f88f8fdedd.196e6b48470.d48dd74354571387=-"
+
+---=Part.8.8fd856f88f8fdedd.196e6b48470.d48dd74354571387=-
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+Accept-Language: fr-FR, en-US, vi-VN, ru-RU, ar-TN, it-IT, de-DE
+Content-Language: vi-VN
+
+body
+
+
+---=Part.8.8fd856f88f8fdedd.196e6b48470.d48dd74354571387=-
+Content-Type: text/html; charset=UTF-8
+Content-Transfer-Encoding: quoted-printable
+Accept-Language: fr-FR, en-US, vi-VN, ru-RU, ar-TN, it-IT, de-DE
+Content-Language: vi-VN
+
+<div>body<br><br></div>
+---=Part.8.8fd856f88f8fdedd.196e6b48470.d48dd74354571387=---
+
+---=Part.9.facdaad4d7d1e26d.196e6b48470.15f465553d6bace6=-
+Content-Type: text/plain; name="=?US-ASCII?Q?filename.txt?=";
+ charset=windows-1252
+Content-Disposition: attachment
+Content-Transfer-Encoding: base64
+
+d2hhdGV2ZXIgY29udGVudCA1OTUzNjI0NzY0Cg==
+
+---=Part.9.facdaad4d7d1e26d.196e6b48470.15f465553d6bace6=---
diff --git 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
index ca4c8fec63..eeff40dbdf 100644
--- 
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
+++ 
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala
@@ -6705,6 +6705,50 @@ trait EmailQueryMethodContract {
     }
   }
 
+  @Test
+  def 
attachmentFilenameShouldBeSearchableWhenMissingInContentDispositionAndExistsInContentType(server:
 GuiceJamesServer): Unit = {
+    server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
+    val messageId = server.getProbe(classOf[MailboxProbeImpl])
+      .appendMessage(BOB.asString, MailboxPath.inbox(BOB), AppendCommand.from(
+        
ClassLoaderUtils.getSystemResourceAsSharedStream("eml/attachment-filename-in-content-type.eml")))
+      .getMessageId
+
+    val request =
+      s"""{
+         |  "using": [
+         |    "urn:ietf:params:jmap:core",
+         |    "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Email/query",
+         |    {
+         |      "accountId": 
"29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |      "filter": {
+         |        "text": "filename"
+         |      }
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    awaitAtMostTenSeconds.untilAsserted { () =>
+      val response = `given`
+        .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+        .body(request)
+      .when
+        .post
+      .`then`
+        .statusCode(SC_OK)
+        .contentType(JSON)
+        .extract
+        .body
+        .asString
+
+      assertThatJson(response)
+        .inPath("$.methodResponses[0][1].ids")
+        .isEqualTo(
+          s"""["${messageId.serialize()}"]""".stripMargin)
+    }
+  }
+
   @Test
   def emailQueryShouldSupportAndOperator(server: GuiceJamesServer): Unit = {
     val message: Message = buildTestMessage


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org
For additional commands, e-mail: notifications-h...@james.apache.org

Reply via email to