You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2020/12/16 06:52:07 UTC

[james-project] branch master updated (1c80dcc -> f6d0f9c)

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

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


    from 1c80dcc  JAMES-3468 Update Webadmin-cli user commands following Webadmin API change
     new 66b5e33  JAMES-3431 [REFACTORING] Extract SMTP parameter parsing
     new 8a35e07  JAMES-3431 RcptHook should allow handling of additional parameters
     new cfae8d2  JAMES-3431 Ehlo hooks should allow to advertise implemented ESMTP extensions
     new 737de53  JAMES-3431 Mail hook for handling RET & ENVID parameters
     new 2a2423c  JAMES-3431 RCPT hook for handling ORCPT & NOTIFY parameters
     new 4cc8d7b  JAMES-3431 Message hook for positioning information on outgoing emails
     new 224b94b  JAMES-3431 Provide a Helo hook advertising DSN ESMTP extension
     new f6d0f9c  JAMES-3431 Tests for DSN hooks

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../james/protocols/smtp/core/RcptCmdHandler.java  |  55 ++-
 .../protocols/smtp/core/esmtp/EhloCmdHandler.java  |   8 +-
 .../apache/james/protocols/smtp/hook/HeloHook.java |  10 +
 .../apache/james/protocols/smtp/hook/RcptHook.java |  26 ++
 .../apache/james/smtpserver/dsn/DSNEhloHook.java}  |  13 +-
 .../james/smtpserver/dsn/DSNMailParameterHook.java |  63 ++++
 .../DSNMessageHook.java}                           |  48 ++-
 .../james/smtpserver/dsn/DSNRcptParameterHook.java |  76 +++++
 .../java/org/apache/james/smtpserver/DSNTest.java  | 375 +++++++++++++++++++++
 .../apache/james/smtpserver/SMTPServerTest.java    |   2 +-
 .../src/test/resources/smtpserver-dsn.xml}         |  12 +-
 11 files changed, 639 insertions(+), 49 deletions(-)
 copy server/{mailet/integration-testing/src/test/java/org/apache/james/smtp/extensions/hooks/DeclinedHeloHook.java => protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNEhloHook.java} (84%)
 create mode 100644 server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNMailParameterHook.java
 copy server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/{AddDefaultAttributesMessageHook.java => dsn/DSNMessageHook.java} (54%)
 create mode 100644 server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNRcptParameterHook.java
 create mode 100644 server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/DSNTest.java
 copy server/protocols/{jmap-draft-integration-testing/memory-jmap-draft-integration-testing/src/test/resources/smtpserver.xml => protocols-smtp/src/test/resources/smtpserver-dsn.xml} (78%)


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


[james-project] 04/08: JAMES-3431 Mail hook for handling RET & ENVID parameters

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 737de53c918e578036c5da65944deedde952a9a6
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 10 11:05:09 2020 +0700

    JAMES-3431 Mail hook for handling RET & ENVID parameters
---
 .../james/smtpserver/dsn/DSNMailParameterHook.java | 63 ++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNMailParameterHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNMailParameterHook.java
new file mode 100644
index 0000000..ddac5c5
--- /dev/null
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNMailParameterHook.java
@@ -0,0 +1,63 @@
+/****************************************************************
+ * 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.smtpserver.dsn;
+
+import static org.apache.james.protocols.api.ProtocolSession.State.Transaction;
+import static org.apache.mailet.DsnParameters.ENVID_PARAMETER;
+import static org.apache.mailet.DsnParameters.RET_PARAMETER;
+
+import java.util.Optional;
+
+import org.apache.james.protocols.api.ProtocolSession;
+import org.apache.james.protocols.smtp.SMTPSession;
+import org.apache.james.protocols.smtp.hook.HookResult;
+import org.apache.james.protocols.smtp.hook.MailParametersHook;
+import org.apache.mailet.DsnParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DSNMailParameterHook implements MailParametersHook {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DSNMailParameterHook.class);
+
+    public static final ProtocolSession.AttachmentKey<DsnParameters.Ret> DSN_RET = ProtocolSession.AttachmentKey.of("DSN_RET", DsnParameters.Ret.class);
+    public static final ProtocolSession.AttachmentKey<DsnParameters.EnvId> DSN_ENVID = ProtocolSession.AttachmentKey.of("DSN_ENVID", DsnParameters.EnvId.class);
+
+    @Override
+    public HookResult doMailParameter(SMTPSession session, String paramName, String paramValue) {
+        if (paramName.equals(RET_PARAMETER)) {
+            DsnParameters.Ret.parse(paramValue)
+                .or(() -> {
+                    LOGGER.debug("Invalid DSN RET value: {}", paramValue);
+                    return Optional.empty();
+                })
+                .ifPresent(ret -> session.setAttachment(DSN_RET, ret, Transaction));
+        }
+        if (paramName.equals(ENVID_PARAMETER)) {
+            DsnParameters.EnvId envId = DsnParameters.EnvId.of(paramValue);
+            session.setAttachment(DSN_ENVID, envId, Transaction);
+        }
+        return HookResult.DECLINED;
+    }
+
+    @Override
+    public String[] getMailParamNames() {
+        return new String[] {RET_PARAMETER, ENVID_PARAMETER};
+    }
+}


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


[james-project] 05/08: JAMES-3431 RCPT hook for handling ORCPT & NOTIFY parameters

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 2a2423c3a15a98b142847524527ada8b1ead10bc
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 10 11:28:40 2020 +0700

    JAMES-3431 RCPT hook for handling ORCPT & NOTIFY parameters
---
 .../apache/james/protocols/smtp/hook/RcptHook.java | 11 ++++
 .../james/smtpserver/dsn/DSNRcptParameterHook.java | 76 ++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/RcptHook.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/RcptHook.java
index 510b6ec..e5fc611 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/RcptHook.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/RcptHook.java
@@ -62,6 +62,17 @@ public interface RcptHook extends Hook {
         return doRcpt(session, sender.asOptional().orElse(null), rcpt);
     }
 
+    /**
+     * Return the HookResult after run the hook.
+     *
+     * This variation of doRcpt method allows access to RCPT extra parameters.
+     *
+     * @param session the SMTPSession
+     * @param sender the sender MailAddress
+     * @param rcpt the recipient MailAddress
+     * @param parameters parameters passed to the RCPT commands
+     * @return HookResult
+     */
     default HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt, Map<String, String> parameters) {
         return doRcpt(session, sender, rcpt);
     }
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNRcptParameterHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNRcptParameterHook.java
new file mode 100644
index 0000000..f146fef
--- /dev/null
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNRcptParameterHook.java
@@ -0,0 +1,76 @@
+/****************************************************************
+ * 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.smtpserver.dsn;
+
+import static org.apache.james.protocols.api.ProtocolSession.State.Transaction;
+import static org.apache.mailet.DsnParameters.NOTIFY_PARAMETER;
+import static org.apache.mailet.DsnParameters.ORCPT_PARAMETER;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.MaybeSender;
+import org.apache.james.protocols.api.ProtocolSession;
+import org.apache.james.protocols.smtp.SMTPSession;
+import org.apache.james.protocols.smtp.hook.HookResult;
+import org.apache.james.protocols.smtp.hook.RcptHook;
+import org.apache.mailet.DsnParameters;
+import org.apache.mailet.DsnParameters.RecipientDsnParameters;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class DSNRcptParameterHook implements RcptHook {
+    public static class Builder {
+        private final ImmutableMap.Builder<MailAddress, RecipientDsnParameters> entries;
+
+        public Builder() {
+            entries = ImmutableMap.builder();
+        }
+
+        public Builder add(MailAddress recipient, RecipientDsnParameters parameters) {
+            entries.put(recipient, parameters);
+            return this;
+        }
+
+        public ImmutableMap<MailAddress, RecipientDsnParameters> build() {
+            return entries.build();
+        }
+    }
+
+    public static final ProtocolSession.AttachmentKey<Builder> DSN_RCPT_PARAMETERS =
+        ProtocolSession.AttachmentKey.of("DSN_RCPT_PARAMETERS", Builder.class);
+
+    @Override
+    public Set<String> supportedParameters() {
+        return ImmutableSet.of(ORCPT_PARAMETER, NOTIFY_PARAMETER);
+    }
+
+    @Override
+    public HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt, Map<String, String> parameters) {
+        Builder builder = session.getAttachment(DSN_RCPT_PARAMETERS, Transaction)
+            .orElse(new Builder());
+        DsnParameters.RecipientDsnParameters.fromSMTPArgLine(parameters)
+            .ifPresent(rcptParameters ->
+                session.setAttachment(DSN_RCPT_PARAMETERS, builder.add(rcpt, rcptParameters), Transaction));
+        return HookResult.DECLINED;
+    }
+}


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


[james-project] 08/08: JAMES-3431 Tests for DSN hooks

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f6d0f9cf9ec5ffca9c48369838e40f240560b312
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 10 12:42:27 2020 +0700

    JAMES-3431 Tests for DSN hooks
---
 .../dsn/{DSNHeloHook.java => DSNEhloHook.java}     |   2 +-
 .../java/org/apache/james/smtpserver/DSNTest.java  | 375 +++++++++++++++++++++
 .../apache/james/smtpserver/SMTPServerTest.java    |   2 +-
 .../src/test/resources/smtpserver-dsn.xml          |  50 +++
 4 files changed, 427 insertions(+), 2 deletions(-)

diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNHeloHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNEhloHook.java
similarity index 97%
rename from server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNHeloHook.java
rename to server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNEhloHook.java
index 11f0c26..a10a340 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNHeloHook.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNEhloHook.java
@@ -27,7 +27,7 @@ import org.apache.james.protocols.smtp.hook.HookResult;
 
 import com.google.common.collect.ImmutableSet;
 
-public class DSNHeloHook implements HeloHook {
+public class DSNEhloHook implements HeloHook {
     @Override
     public Set<String> implementedEsmtpFeatures() {
         return ImmutableSet.of("DSN");
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/DSNTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/DSNTest.java
new file mode 100644
index 0000000..3c38d88
--- /dev/null
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/DSNTest.java
@@ -0,0 +1,375 @@
+/****************************************************************
+ * 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.smtpserver;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.mailet.DsnParameters.Notify.DELAY;
+import static org.apache.mailet.DsnParameters.Notify.FAILURE;
+import static org.apache.mailet.DsnParameters.Notify.SUCCESS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Base64;
+import java.util.EnumSet;
+
+import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
+import org.apache.commons.net.smtp.SMTPClient;
+import org.apache.james.core.Domain;
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.Username;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.lib.DomainListConfiguration;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.filesystem.api.FileSystem;
+import org.apache.james.mailrepository.api.MailRepositoryStore;
+import org.apache.james.mailrepository.api.Protocol;
+import org.apache.james.mailrepository.memory.MailRepositoryStoreConfiguration;
+import org.apache.james.mailrepository.memory.MemoryMailRepository;
+import org.apache.james.mailrepository.memory.MemoryMailRepositoryStore;
+import org.apache.james.mailrepository.memory.MemoryMailRepositoryUrlStore;
+import org.apache.james.mailrepository.memory.SimpleMailRepositoryLoader;
+import org.apache.james.metrics.api.Metric;
+import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.protocols.api.utils.ProtocolServerUtils;
+import org.apache.james.protocols.lib.mock.MockProtocolHandlerLoader;
+import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.queue.api.RawMailQueueItemDecoratorFactory;
+import org.apache.james.queue.memory.MemoryMailQueueFactory;
+import org.apache.james.rrt.api.AliasReverseResolver;
+import org.apache.james.rrt.api.CanSendFrom;
+import org.apache.james.rrt.api.RecipientRewriteTable;
+import org.apache.james.rrt.api.RecipientRewriteTableConfiguration;
+import org.apache.james.rrt.lib.AliasReverseResolverImpl;
+import org.apache.james.rrt.lib.CanSendFromImpl;
+import org.apache.james.rrt.memory.MemoryRecipientRewriteTable;
+import org.apache.james.server.core.configuration.Configuration;
+import org.apache.james.server.core.configuration.FileConfigurationProvider;
+import org.apache.james.server.core.filesystem.FileSystemImpl;
+import org.apache.james.smtpserver.netty.SMTPServer;
+import org.apache.james.smtpserver.netty.SmtpMetricsImpl;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.memory.MemoryUsersRepository;
+import org.apache.mailet.DsnParameters;
+import org.apache.mailet.Mail;
+import org.assertj.core.api.SoftAssertions;
+import org.jboss.netty.util.HashedWheelTimer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.inject.TypeLiteral;
+
+public class DSNTest {
+    public static final String LOCAL_DOMAIN = "example.local";
+    public static final Username BOB = Username.of("bob@localhost");
+    public static final String PASSWORD = "bobpwd";
+
+    protected HashedWheelTimer hashedWheelTimer;
+    protected MemoryDomainList domainList;
+    protected MemoryUsersRepository usersRepository;
+    protected SMTPServerTest.AlterableDNSServer dnsServer;
+    protected MemoryMailRepositoryStore mailRepositoryStore;
+    protected FileSystemImpl fileSystem;
+    protected Configuration configuration;
+    protected MockProtocolHandlerLoader chain;
+    protected MemoryMailQueueFactory queueFactory;
+    protected MemoryMailQueueFactory.MemoryCacheableMailQueue queue;
+
+    private SMTPServer smtpServer;
+
+    @Before
+    public void setUp() throws Exception {
+        domainList = new MemoryDomainList(new InMemoryDNSService()
+            .registerMxRecord(Domain.LOCALHOST.asString(), "127.0.0.1")
+            .registerMxRecord(Domain.LOCALHOST.asString(), "127.0.0.1")
+            .registerMxRecord(LOCAL_DOMAIN, "127.0.0.1")
+            .registerMxRecord("examplebis.local", "127.0.0.1")
+            .registerMxRecord("127.0.0.1", "127.0.0.1"));
+        domainList.configure(DomainListConfiguration.DEFAULT);
+
+        domainList.addDomain(Domain.of(LOCAL_DOMAIN));
+        domainList.addDomain(Domain.of("examplebis.local"));
+        usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
+        usersRepository.addUser(BOB, PASSWORD);
+
+        createMailRepositoryStore();
+
+        setUpFakeLoader();
+        hashedWheelTimer = new HashedWheelTimer();
+        setUpSMTPServer();
+    }
+
+    protected void createMailRepositoryStore() throws Exception {
+        configuration = Configuration.builder()
+                .workingDirectory("../")
+                .configurationFromClasspath()
+                .build();
+        fileSystem = new FileSystemImpl(configuration.directories());
+        MemoryMailRepositoryUrlStore urlStore = new MemoryMailRepositoryUrlStore();
+
+        MailRepositoryStoreConfiguration configuration = MailRepositoryStoreConfiguration.forItems(
+            new MailRepositoryStoreConfiguration.Item(
+                ImmutableList.of(new Protocol("memory")),
+                MemoryMailRepository.class.getName(),
+                new BaseHierarchicalConfiguration()));
+
+        mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, new SimpleMailRepositoryLoader(), configuration);
+        mailRepositoryStore.init();
+    }
+
+    protected SMTPServer createSMTPServer(SmtpMetricsImpl smtpMetrics) {
+        return new SMTPServer(smtpMetrics);
+    }
+
+    protected void setUpSMTPServer() {
+        SmtpMetricsImpl smtpMetrics = mock(SmtpMetricsImpl.class);
+        when(smtpMetrics.getCommandsMetric()).thenReturn(mock(Metric.class));
+        when(smtpMetrics.getConnectionMetric()).thenReturn(mock(Metric.class));
+        smtpServer = createSMTPServer(smtpMetrics);
+        smtpServer.setDnsService(dnsServer);
+        smtpServer.setFileSystem(fileSystem);
+        smtpServer.setHashWheelTimer(hashedWheelTimer);
+        smtpServer.setProtocolHandlerLoader(chain);
+    }
+
+    protected void setUpFakeLoader() {
+        dnsServer = new SMTPServerTest.AlterableDNSServer();
+
+        MemoryRecipientRewriteTable rewriteTable = new MemoryRecipientRewriteTable();
+        rewriteTable.setConfiguration(RecipientRewriteTableConfiguration.DEFAULT_ENABLED);
+        AliasReverseResolver aliasReverseResolver = new AliasReverseResolverImpl(rewriteTable);
+        CanSendFrom canSendFrom = new CanSendFromImpl(rewriteTable, aliasReverseResolver);
+        queueFactory = new MemoryMailQueueFactory(new RawMailQueueItemDecoratorFactory());
+        queue = queueFactory.createQueue(MailQueueFactory.SPOOL);
+
+        chain = MockProtocolHandlerLoader.builder()
+            .put(binder -> binder.bind(DomainList.class).toInstance(domainList))
+            .put(binder -> binder.bind(new TypeLiteral<MailQueueFactory<?>>() {}).toInstance(queueFactory))
+            .put(binder -> binder.bind(RecipientRewriteTable.class).toInstance(rewriteTable))
+            .put(binder -> binder.bind(CanSendFrom.class).toInstance(canSendFrom))
+            .put(binder -> binder.bind(FileSystem.class).toInstance(fileSystem))
+            .put(binder -> binder.bind(MailRepositoryStore.class).toInstance(mailRepositoryStore))
+            .put(binder -> binder.bind(DNSService.class).toInstance(dnsServer))
+            .put(binder -> binder.bind(UsersRepository.class).toInstance(usersRepository))
+            .put(binder -> binder.bind(MetricFactory.class).to(RecordingMetricFactory.class))
+            .build();
+    }
+
+    @After
+    public void tearDown() {
+        smtpServer.destroy();
+        hashedWheelTimer.stop();
+    }
+
+    @Test
+    public void ehloShouldAdvertiseDsnExtension() throws Exception {
+        smtpServer.configure(FileConfigurationProvider.getConfig(
+            ClassLoader.getSystemResourceAsStream("smtpserver-dsn.xml")));
+        smtpServer.init();
+
+        SMTPClient smtpProtocol = new SMTPClient();
+        InetSocketAddress bindedAddress = new ProtocolServerUtils(smtpServer).retrieveBindedAddress();
+        smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), bindedAddress.getPort());
+        authenticate(smtpProtocol);
+        smtpProtocol.sendCommand("EHLO localhost");
+
+        SoftAssertions.assertSoftly(softly -> {
+            softly.assertThat(smtpProtocol.getReplyCode()).isEqualTo(250);
+            softly.assertThat(smtpProtocol.getReplyString()).contains("250 DSN");
+        });
+    }
+
+    private void authenticate(SMTPClient smtpProtocol) throws IOException {
+        smtpProtocol.sendCommand("AUTH PLAIN");
+        smtpProtocol.sendCommand(Base64.getEncoder().encodeToString(("\0" + BOB.asString() + "\0" + PASSWORD + "\0").getBytes(UTF_8)));
+        assertThat(smtpProtocol.getReplyCode())
+            .as("authenticated")
+            .isEqualTo(235);
+    }
+
+    @Test
+    public void dsnParametersShouldBeSetOnTheFinalEmail() throws Exception {
+        smtpServer.configure(FileConfigurationProvider.getConfig(
+            ClassLoader.getSystemResourceAsStream("smtpserver-dsn.xml")));
+        smtpServer.init();
+
+        SMTPClient smtpProtocol = new SMTPClient();
+        InetSocketAddress bindedAddress = new ProtocolServerUtils(smtpServer).retrieveBindedAddress();
+        smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), bindedAddress.getPort());
+        authenticate(smtpProtocol);
+
+        smtpProtocol.sendCommand("EHLO localhost");
+        smtpProtocol.sendCommand("MAIL FROM: <bo...@localhost> RET=HDRS ENVID=QQ314159");
+        smtpProtocol.sendCommand("RCPT TO:<rc...@localhost> NOTIFY=SUCCESS,FAILURE,DELAY ORCPT=rfc822;orcpt@localhost");
+        smtpProtocol.sendShortMessageData("Subject: test mail\r\n\r\nTest body testSimpleMailSendWithDSN\r\n.\r\n");
+
+        Mail lastMail = queue.getLastMail();
+        assertThat(lastMail.dsnParameters())
+            .contains(DsnParameters.builder()
+                .envId(DsnParameters.EnvId.of("QQ314159"))
+                .ret(DsnParameters.Ret.HDRS)
+                .addRcptParameter(new MailAddress("rcpt@localhost"), DsnParameters.RecipientDsnParameters.of(
+                    EnumSet.of(SUCCESS, FAILURE, DELAY),
+                    new MailAddress("orcpt@localhost")
+                )).build().get());
+    }
+
+    @Test
+    public void multipleRecipientsShouldBeSupported() throws Exception {
+        smtpServer.configure(FileConfigurationProvider.getConfig(
+            ClassLoader.getSystemResourceAsStream("smtpserver-dsn.xml")));
+        smtpServer.init();
+
+        SMTPClient smtpProtocol = new SMTPClient();
+        InetSocketAddress bindedAddress = new ProtocolServerUtils(smtpServer).retrieveBindedAddress();
+        smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), bindedAddress.getPort());
+        authenticate(smtpProtocol);
+
+        smtpProtocol.sendCommand("EHLO localhost");
+        smtpProtocol.sendCommand("MAIL FROM: <bo...@localhost> RET=HDRS ENVID=QQ314159");
+        smtpProtocol.sendCommand("RCPT TO:<rc...@localhost> NOTIFY=SUCCESS,FAILURE,DELAY ORCPT=rfc822;orcpt1@localhost");
+        smtpProtocol.sendCommand("RCPT TO:<rc...@localhost> NOTIFY=SUCCESS,FAILURE,DELAY ORCPT=rfc822;orcpt2@localhost");
+        smtpProtocol.sendCommand("RCPT TO:<rc...@localhost>");
+        smtpProtocol.sendShortMessageData("Subject: test mail\r\n\r\nTest body testSimpleMailSendWithDSN\r\n.\r\n");
+
+        Mail lastMail = queue.getLastMail();
+        assertThat(lastMail.dsnParameters())
+            .contains(DsnParameters.builder()
+                .envId(DsnParameters.EnvId.of("QQ314159"))
+                .ret(DsnParameters.Ret.HDRS)
+                .addRcptParameter(new MailAddress("rcpt1@localhost"), DsnParameters.RecipientDsnParameters.of(
+                    EnumSet.of(SUCCESS, FAILURE, DELAY),
+                    new MailAddress("orcpt1@localhost")))
+                .addRcptParameter(new MailAddress("rcpt2@localhost"), DsnParameters.RecipientDsnParameters.of(
+                    EnumSet.of(SUCCESS, FAILURE, DELAY),
+                    new MailAddress("orcpt2@localhost")
+                )).build().get());
+    }
+
+    @Test
+    public void notifyCanBeOmitted() throws Exception {
+        smtpServer.configure(FileConfigurationProvider.getConfig(
+            ClassLoader.getSystemResourceAsStream("smtpserver-dsn.xml")));
+        smtpServer.init();
+
+        SMTPClient smtpProtocol = new SMTPClient();
+        InetSocketAddress bindedAddress = new ProtocolServerUtils(smtpServer).retrieveBindedAddress();
+        smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), bindedAddress.getPort());
+        authenticate(smtpProtocol);
+
+        smtpProtocol.sendCommand("EHLO localhost");
+        smtpProtocol.sendCommand("MAIL FROM: <bo...@localhost> RET=HDRS ENVID=QQ314159");
+        smtpProtocol.sendCommand("RCPT TO:<rc...@localhost> ORCPT=rfc822;orcpt@localhost");
+        smtpProtocol.sendShortMessageData("Subject: test mail\r\n\r\nTest body testSimpleMailSendWithDSN\r\n.\r\n");
+
+        Mail lastMail = queue.getLastMail();
+        assertThat(lastMail.dsnParameters())
+            .contains(DsnParameters.builder()
+                .envId(DsnParameters.EnvId.of("QQ314159"))
+                .ret(DsnParameters.Ret.HDRS)
+                .addRcptParameter(new MailAddress("rcpt@localhost"), DsnParameters.RecipientDsnParameters.of(
+                    new MailAddress("orcpt@localhost")))
+                .build().get());
+    }
+
+    @Test
+    public void orcptCanBeOmitted() throws Exception {
+        smtpServer.configure(FileConfigurationProvider.getConfig(
+            ClassLoader.getSystemResourceAsStream("smtpserver-dsn.xml")));
+        smtpServer.init();
+
+        SMTPClient smtpProtocol = new SMTPClient();
+        InetSocketAddress bindedAddress = new ProtocolServerUtils(smtpServer).retrieveBindedAddress();
+        smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), bindedAddress.getPort());
+        authenticate(smtpProtocol);
+
+        smtpProtocol.sendCommand("EHLO localhost");
+        smtpProtocol.sendCommand("MAIL FROM: <bo...@localhost> RET=HDRS ENVID=QQ314159");
+        smtpProtocol.sendCommand("RCPT TO:<rc...@localhost> NOTIFY=SUCCESS,FAILURE,DELAY");
+        smtpProtocol.sendShortMessageData("Subject: test mail\r\n\r\nTest body testSimpleMailSendWithDSN\r\n.\r\n");
+
+        Mail lastMail = queue.getLastMail();
+        assertThat(lastMail.dsnParameters())
+            .contains(DsnParameters.builder()
+                .envId(DsnParameters.EnvId.of("QQ314159"))
+                .ret(DsnParameters.Ret.HDRS)
+                .addRcptParameter(new MailAddress("rcpt@localhost"), DsnParameters.RecipientDsnParameters.of(
+                    EnumSet.of(SUCCESS, FAILURE, DELAY)))
+                .build().get());
+    }
+
+    @Test
+    public void retCanBeOmitted() throws Exception {
+        smtpServer.configure(FileConfigurationProvider.getConfig(
+            ClassLoader.getSystemResourceAsStream("smtpserver-dsn.xml")));
+        smtpServer.init();
+
+        SMTPClient smtpProtocol = new SMTPClient();
+        InetSocketAddress bindedAddress = new ProtocolServerUtils(smtpServer).retrieveBindedAddress();
+        smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), bindedAddress.getPort());
+        authenticate(smtpProtocol);
+
+        smtpProtocol.sendCommand("EHLO localhost");
+        smtpProtocol.sendCommand("MAIL FROM: <bo...@localhost> ENVID=QQ314159");
+        smtpProtocol.sendCommand("RCPT TO:<rc...@localhost> NOTIFY=SUCCESS,FAILURE,DELAY ORCPT=rfc822;orcpt@localhost");
+        smtpProtocol.sendShortMessageData("Subject: test mail\r\n\r\nTest body testSimpleMailSendWithDSN\r\n.\r\n");
+
+        Mail lastMail = queue.getLastMail();
+        assertThat(lastMail.dsnParameters())
+            .contains(DsnParameters.builder()
+                .envId(DsnParameters.EnvId.of("QQ314159"))
+                .addRcptParameter(new MailAddress("rcpt@localhost"), DsnParameters.RecipientDsnParameters.of(
+                    EnumSet.of(SUCCESS, FAILURE, DELAY),
+                    new MailAddress("orcpt@localhost")))
+                .build().get());
+    }
+
+    @Test
+    public void envIdCanBeOmitted() throws Exception {
+        smtpServer.configure(FileConfigurationProvider.getConfig(
+            ClassLoader.getSystemResourceAsStream("smtpserver-dsn.xml")));
+        smtpServer.init();
+
+        SMTPClient smtpProtocol = new SMTPClient();
+        InetSocketAddress bindedAddress = new ProtocolServerUtils(smtpServer).retrieveBindedAddress();
+        smtpProtocol.connect(bindedAddress.getAddress().getHostAddress(), bindedAddress.getPort());
+        authenticate(smtpProtocol);
+
+        smtpProtocol.sendCommand("EHLO localhost");
+        smtpProtocol.sendCommand("MAIL FROM: <bo...@localhost> RET=HDRS");
+        smtpProtocol.sendCommand("RCPT TO:<rc...@localhost> NOTIFY=SUCCESS,FAILURE,DELAY ORCPT=rfc822;orcpt@localhost");
+        smtpProtocol.sendShortMessageData("Subject: test mail\r\n\r\nTest body testSimpleMailSendWithDSN\r\n.\r\n");
+
+        Mail lastMail = queue.getLastMail();
+        assertThat(lastMail.dsnParameters())
+            .contains(DsnParameters.builder()
+                .ret(DsnParameters.Ret.HDRS)
+                .addRcptParameter(new MailAddress("rcpt@localhost"), DsnParameters.RecipientDsnParameters.of(
+                    EnumSet.of(SUCCESS, FAILURE, DELAY),
+                    new MailAddress("orcpt@localhost")
+                )).build().get());
+    }
+}
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
index f327ffe..9d99f15 100644
--- a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
@@ -103,7 +103,7 @@ public class SMTPServerTest {
     public static final String USER_LOCALHOST = "test_user_smtp@localhost";
     public static final String USER_LOCAL_DOMAIN = "test_user_smtp@example.local";
 
-    final class AlterableDNSServer implements DNSService {
+    final static class AlterableDNSServer implements DNSService {
 
         private InetAddress localhostByName = null;
 
diff --git a/server/protocols/protocols-smtp/src/test/resources/smtpserver-dsn.xml b/server/protocols/protocols-smtp/src/test/resources/smtpserver-dsn.xml
new file mode 100644
index 0000000..d6b548e
--- /dev/null
+++ b/server/protocols/protocols-smtp/src/test/resources/smtpserver-dsn.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+
+<!--
+  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.
+ -->
+
+<!-- Read https://james.apache.org/server/config-smtp-lmtp.html#SMTP_Configuration for further details -->
+
+    <smtpserver enabled="true">
+        <bind>0.0.0.0:0</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="false" startTLS="false">
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+            <algorithm>SunX509</algorithm>
+        </tls>
+        <connectiontimeout>360</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <authRequired>true</authRequired>
+        <verifyIdentity>true</verifyIdentity>
+        <maxmessagesize>0</maxmessagesize>
+        <addressBracketsEnforcement>true</addressBracketsEnforcement>
+        <smtpGreeting>Apache JAMES awesome SMTP Server</smtpGreeting>
+        <handlerchain>
+            <handler class="org.apache.james.smtpserver.dsn.DSNEhloHook"/>
+            <handler class="org.apache.james.smtpserver.dsn.DSNMailParameterHook"/>
+            <handler class="org.apache.james.smtpserver.dsn.DSNRcptParameterHook"/>
+            <handler class="org.apache.james.smtpserver.dsn.DSNMessageHook"/>
+            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
+        </handlerchain>
+    </smtpserver>
+
+


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


[james-project] 03/08: JAMES-3431 Ehlo hooks should allow to advertise implemented ESMTP extensions

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit cfae8d285173d4542fa790cb775200233b0b062d
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 10 11:47:09 2020 +0700

    JAMES-3431 Ehlo hooks should allow to advertise implemented ESMTP extensions
---
 .../apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java |  8 +++++++-
 .../java/org/apache/james/protocols/smtp/hook/HeloHook.java    | 10 ++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java
index ecbf0d4..7c794e2 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java
@@ -35,6 +35,7 @@ import org.apache.james.protocols.smtp.dsn.DSNStatus;
 import org.apache.james.protocols.smtp.hook.HeloHook;
 import org.apache.james.protocols.smtp.hook.HookResult;
 
+import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
@@ -159,7 +160,12 @@ public class EhloCmdHandler extends AbstractHookableCmdHandler<HeloHook> impleme
 
     @Override
     public List<String> getImplementedEsmtpFeatures(SMTPSession session) {
-        return ESMTP_FEATURES;
+        return ImmutableList.<String>builder()
+            .addAll(ESMTP_FEATURES)
+            .addAll(getHooks().stream()
+                .flatMap(heloHook -> heloHook.implementedEsmtpFeatures().stream())
+                .collect(Guavate.toImmutableList()))
+            .build();
     }
 
 }
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/HeloHook.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/HeloHook.java
index f792a40..3ca3c59 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/HeloHook.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/HeloHook.java
@@ -19,12 +19,22 @@
 
 package org.apache.james.protocols.smtp.hook;
 
+import java.util.Set;
+
 import org.apache.james.protocols.smtp.SMTPSession;
 
+import com.google.common.collect.ImmutableSet;
+
 /**
  * Implement this interfaces to hook in the HELO Command
  */
 public interface HeloHook extends Hook {
+    /**
+     * @return ESMTP extensions to be advertised as part of EHLO answers
+     */
+    default Set<String> implementedEsmtpFeatures() {
+        return ImmutableSet.of();
+    }
 
     /**
      * Return the HookResult after run the hook


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


[james-project] 01/08: JAMES-3431 [REFACTORING] Extract SMTP parameter parsing

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 66b5e3303726c2c1368e4b5c928af0d625fb4435
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 10 10:55:35 2020 +0700

    JAMES-3431 [REFACTORING] Extract SMTP parameter parsing
---
 .../james/protocols/smtp/core/RcptCmdHandler.java  | 26 +++++++++++++---------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
index 93ce9d6..42769a8 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
@@ -27,6 +27,7 @@ import java.util.StringTokenizer;
 
 import javax.inject.Inject;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
 import org.apache.james.metrics.api.MetricFactory;
@@ -163,21 +164,15 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
                     rcptOptionString, " ");
             while (optionTokenizer.hasMoreElements()) {
                 String rcptOption = optionTokenizer.nextToken();
-                int equalIndex = rcptOption.indexOf('=');
-                String rcptOptionName = rcptOption;
-                String rcptOptionValue = "";
-                if (equalIndex > 0) {
-                    rcptOptionName = rcptOption.substring(0, equalIndex)
-                            .toUpperCase(Locale.US);
-                    rcptOptionValue = rcptOption.substring(equalIndex + 1);
-                }
+                Pair<String, String> parameter = parseParameter(rcptOption);
                 // Unexpected option attached to the RCPT command
-                LOGGER.debug("RCPT command had unrecognized/unexpected option {} with value {}{}", rcptOptionName, rcptOptionValue, getContext(session, recipientAddress, recipient));
+                LOGGER.debug("RCPT command had unrecognized/unexpected option {} with value {}{}",
+                    parameter.getKey(), parameter.getValue(), getContext(session, recipientAddress, recipient));
 
                 return new SMTPResponse(
                         SMTPRetCode.PARAMETER_NOT_IMPLEMENTED,
                         "Unrecognized or unsupported option: "
-                                + rcptOptionName);
+                                + parameter.getKey());
             }
             optionTokenizer = null;
         }
@@ -218,6 +213,17 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
         return rawHook.doRcpt(session, sender, session.getAttachment(CURRENT_RECIPIENT, State.Transaction).orElse(MailAddress.nullSender()));
     }
 
+    private Pair<String, String> parseParameter(String rcptOption) {
+        int equalIndex = rcptOption.indexOf('=');
+        if (equalIndex > 0) {
+            return Pair.of(rcptOption.substring(0, equalIndex)
+                    .toUpperCase(Locale.US),
+                rcptOption.substring(equalIndex + 1));
+        } else {
+            return Pair.of(rcptOption, "");
+        }
+    }
+
     protected String getDefaultDomain() {
         return "localhost";
     }


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


[james-project] 02/08: JAMES-3431 RcptHook should allow handling of additional parameters

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8a35e073136b36eb2dab1a9b5d2b403e5cdf927c
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 10 11:04:20 2020 +0700

    JAMES-3431 RcptHook should allow handling of additional parameters
    
     - Hooks should advertise which parameters they support
     - RcptCmdHandler should not reject supported parameters (that we have a hook handling)
     - Parameters should be passed to the hooks
---
 .../james/protocols/smtp/core/RcptCmdHandler.java  | 35 +++++++++++++++++-----
 .../apache/james/protocols/smtp/hook/RcptHook.java | 15 ++++++++++
 2 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
index 42769a8..6974a3a 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.StringTokenizer;
 
 import javax.inject.Inject;
@@ -44,6 +45,8 @@ import org.apache.james.protocols.smtp.hook.RcptHook;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -165,14 +168,17 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
             while (optionTokenizer.hasMoreElements()) {
                 String rcptOption = optionTokenizer.nextToken();
                 Pair<String, String> parameter = parseParameter(rcptOption);
-                // Unexpected option attached to the RCPT command
-                LOGGER.debug("RCPT command had unrecognized/unexpected option {} with value {}{}",
-                    parameter.getKey(), parameter.getValue(), getContext(session, recipientAddress, recipient));
 
-                return new SMTPResponse(
+                if (!supportedParameter(parameter.getKey())) {
+                    // Unexpected option attached to the RCPT command
+                    LOGGER.debug("RCPT command had unrecognized/unexpected option {} with value {}{}",
+                        parameter.getKey(), parameter.getValue(), getContext(session, recipientAddress, recipient));
+
+                    return new SMTPResponse(
                         SMTPRetCode.PARAMETER_NOT_IMPLEMENTED,
                         "Unrecognized or unsupported option: "
-                                + parameter.getKey());
+                            + parameter.getKey());
+                }
             }
             optionTokenizer = null;
         }
@@ -208,9 +214,19 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
     }
 
     @Override
-    protected HookResult callHook(RcptHook rawHook, SMTPSession session, String parameters) {
+    protected HookResult callHook(RcptHook rawHook, SMTPSession session, String parametersString) {
         MaybeSender sender = session.getAttachment(SMTPSession.SENDER, State.Transaction).orElse(MaybeSender.nullSender());
-        return rawHook.doRcpt(session, sender, session.getAttachment(CURRENT_RECIPIENT, State.Transaction).orElse(MailAddress.nullSender()));
+        Map<String, String> parameters = parseParameters(parametersString);
+        MailAddress rcpt = session.getAttachment(CURRENT_RECIPIENT, State.Transaction).orElse(MailAddress.nullSender());
+
+        return rawHook.doRcpt(session, sender, rcpt, parameters);
+    }
+
+    private Map<String, String> parseParameters(String rcptOptions) {
+        return Splitter.on(' ').splitToList(rcptOptions)
+            .stream()
+            .map(this::parseParameter)
+            .collect(Guavate.toImmutableMap(Pair::getKey, Pair::getValue));
     }
 
     private Pair<String, String> parseParameter(String rcptOption) {
@@ -224,6 +240,11 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
         }
     }
 
+    private boolean supportedParameter(String parameterName) {
+        return getHooks().stream()
+            .anyMatch(rcptHook -> rcptHook.supportedParameters().contains(parameterName));
+    }
+
     protected String getDefaultDomain() {
         return "localhost";
     }
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/RcptHook.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/RcptHook.java
index 7df7408..510b6ec 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/RcptHook.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/RcptHook.java
@@ -18,14 +18,25 @@
  ****************************************************************/
 package org.apache.james.protocols.smtp.hook;
 
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
 import org.apache.james.protocols.smtp.SMTPSession;
 
+import com.google.common.collect.ImmutableSet;
+
 /**
  * Implement this interfaces to hook in the MAIL Command
  */
 public interface RcptHook extends Hook {
+    /**
+     * @return RCPT parameters supported by this hook
+     */
+    default Set<String> supportedParameters() {
+        return ImmutableSet.of();
+    }
     
     /**
      * Return the HookResult after run the hook
@@ -51,4 +62,8 @@ public interface RcptHook extends Hook {
         return doRcpt(session, sender.asOptional().orElse(null), rcpt);
     }
 
+    default HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt, Map<String, String> parameters) {
+        return doRcpt(session, sender, rcpt);
+    }
+
 }


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


[james-project] 07/08: JAMES-3431 Provide a Helo hook advertising DSN ESMTP extension

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 224b94bcdee7e00169c604403099d461eee120c7
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 10 11:49:25 2020 +0700

    JAMES-3431 Provide a Helo hook advertising DSN ESMTP extension
---
 .../apache/james/smtpserver/dsn/DSNHeloHook.java   | 40 ++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNHeloHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNHeloHook.java
new file mode 100644
index 0000000..11f0c26
--- /dev/null
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNHeloHook.java
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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.smtpserver.dsn;
+
+import java.util.Set;
+
+import org.apache.james.protocols.smtp.SMTPSession;
+import org.apache.james.protocols.smtp.hook.HeloHook;
+import org.apache.james.protocols.smtp.hook.HookResult;
+
+import com.google.common.collect.ImmutableSet;
+
+public class DSNHeloHook implements HeloHook {
+    @Override
+    public Set<String> implementedEsmtpFeatures() {
+        return ImmutableSet.of("DSN");
+    }
+
+    @Override
+    public HookResult doHelo(SMTPSession session, String helo) {
+        return HookResult.DECLINED;
+    }
+}


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


[james-project] 06/08: JAMES-3431 Message hook for positioning information on outgoing emails

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 4cc8d7bf6e25b0e30355e3765c65aae80e7e24da
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 10 11:34:35 2020 +0700

    JAMES-3431 Message hook for positioning information on outgoing emails
---
 .../james/smtpserver/dsn/DSNMessageHook.java       | 52 ++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNMessageHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNMessageHook.java
new file mode 100644
index 0000000..b9060a3
--- /dev/null
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/dsn/DSNMessageHook.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * 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.smtpserver.dsn;
+
+import static org.apache.james.smtpserver.dsn.DSNMailParameterHook.DSN_ENVID;
+import static org.apache.james.smtpserver.dsn.DSNMailParameterHook.DSN_RET;
+import static org.apache.james.smtpserver.dsn.DSNRcptParameterHook.DSN_RCPT_PARAMETERS;
+
+import java.util.Optional;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.protocols.api.ProtocolSession;
+import org.apache.james.protocols.smtp.SMTPSession;
+import org.apache.james.protocols.smtp.hook.HookResult;
+import org.apache.james.smtpserver.JamesMessageHook;
+import org.apache.mailet.DsnParameters;
+import org.apache.mailet.Mail;
+
+import com.google.common.collect.ImmutableMap;
+
+public class DSNMessageHook implements JamesMessageHook {
+    @Override
+    public HookResult onMessage(SMTPSession session, Mail mail) {
+        Optional<DsnParameters.Ret> ret = session.getAttachment(DSN_RET, ProtocolSession.State.Transaction);
+        Optional<DsnParameters.EnvId> envId = session.getAttachment(DSN_ENVID, ProtocolSession.State.Transaction);
+        ImmutableMap<MailAddress, DsnParameters.RecipientDsnParameters> rcptParameters =
+            session.getAttachment(DSN_RCPT_PARAMETERS, ProtocolSession.State.Transaction)
+                .map(DSNRcptParameterHook.Builder::build)
+                .orElse(ImmutableMap.of());
+
+        DsnParameters.of(envId, ret, rcptParameters)
+            .ifPresent(mail::setDsnParameters);
+        return HookResult.DECLINED;
+    }
+}


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