All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nightcode.milter.AbstractMilterHandler Maven / Gradle / Ivy

There is a newer version: 0.8
Show newest version
/*
 * Licensed 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.nightcode.milter;

import org.nightcode.common.util.logging.LogManager;
import org.nightcode.common.util.logging.Logger;
import org.nightcode.milter.command.CommandProcessor;
import org.nightcode.milter.net.MilterPacket;
import org.nightcode.milter.net.MilterPacketSender;
import org.nightcode.milter.util.Actions;
import org.nightcode.milter.util.ByteArrays;
import org.nightcode.milter.util.MilterPacketUtil;
import org.nightcode.milter.util.ProtocolSteps;

import java.net.InetAddress;
import java.util.List;

import javax.annotation.Nullable;

public abstract class AbstractMilterHandler implements MilterHandler {

  private final Actions milterActions;
  private final ProtocolSteps milterProtocolSteps;

  protected final MessageModificationService messageModificationService;

  protected final Logger logger = LogManager.getLogger(this);

  protected AbstractMilterHandler(Actions milterActions, ProtocolSteps milterProtocolSteps) {
    this(milterActions, milterProtocolSteps, new MessageModificationServiceImpl());
  }

  protected AbstractMilterHandler(Actions milterActions, ProtocolSteps milterProtocolSteps,
      MessageModificationService messageModificationService) {
    this.milterActions = milterActions;
    this.milterProtocolSteps = milterProtocolSteps;
    this.messageModificationService = messageModificationService;
  }

  @Override public void connect(MilterContext context, String hostname, @Nullable InetAddress address)
      throws MilterException {
    context.sendContinue();
  }

  @Override public void helo(MilterContext context, String helohost) throws MilterException {
    context.sendContinue();
  }

  @Override public void envfrom(MilterContext context, List from) throws MilterException {
    context.sendContinue();
  }

  @Override public void envrcpt(MilterContext context, List recipients) throws MilterException {
    context.sendContinue();
  }

  @Override public void header(MilterContext context, String headerName, String headerValue) throws MilterException {
    context.sendContinue();
  }

  @Override public void eoh(MilterContext context) throws MilterException {
    context.sendContinue();
  }

  @Override public void body(MilterContext context, String bodyChunk) throws MilterException {
    context.sendContinue();
  }

  @Override public void eom(MilterContext context, @Nullable String bodyChunk) throws MilterException {
    context.sendContinue();
  }

  @Override public void abort(MilterContext context, @Nullable MilterPacket packet) throws MilterException {
    // do nothing
  }

  @Override public void data(MilterContext context, byte[] payload) throws MilterException {
    context.sendContinue();
  }

  @Override public void negotiate(MilterContext context, int mtaProtocolVersion, Actions mtaActions,
      ProtocolSteps mtaProtocolSteps) throws MilterException {
    logger.debug("\t\tMTA { Version: %s %s %s }\n"
                + "\t\tMilter { Version: %s %s %s}"
            , mtaProtocolVersion
            , mtaActions
            , mtaProtocolSteps
            , context.milterProtocolVersion()
            , context.milterActions()
            , context.milterProtocolSteps()
    );

    context.setMtaProtocolVersion(mtaProtocolVersion);

    int sessionProtocolVersion = Math.min(context.milterProtocolVersion(), mtaProtocolVersion);
    context.setSessionProtocolVersion(sessionProtocolVersion);

    if (mtaActions.bitmap() == 0) {
      mtaActions = Actions.DEF_ACTIONS;
    }
    context.setMtaActions(mtaActions);

    if ((context.getMtaActions().bitmap() & context.milterActions().bitmap()) != context.milterActions().bitmap()) {
      logger.warn("MTA %s doesn't fulfill Milter requirements %s", context.getMtaActions(), context.milterActions());
      abortSession(context, null);
      return;
    }

    if (mtaProtocolSteps.bitmap() == 0) {
      mtaProtocolSteps = ProtocolSteps.DEF_PROTOCOL_STEPS;
    }
    context.setMtaProtocolSteps(mtaProtocolSteps);

    byte[] buffer = new byte[4];
    for (int i = 0; i < buffer.length; i++) {
      buffer[i] = (byte) (mtaProtocolSteps.array()[i] & context.milterProtocolSteps().array()[i]);
    }
    context.setSessionProtocolSteps(new ProtocolSteps(buffer, 0));

    byte[] version = ByteArrays.intToByteArray(context.getSessionProtocolVersion());
    byte[] actions = context.milterActions().array();
    byte[] protocolSteps = context.getSessionProtocolSteps().array();

    byte[] payload = new byte[version.length + actions.length + protocolSteps.length];

    System.arraycopy(version, 0, payload, 0, version.length);
    System.arraycopy(actions, 0, payload, version.length, actions.length);
    System.arraycopy(protocolSteps, 0, payload, version.length + actions.length, protocolSteps.length);

    MilterPacket response = MilterPacket.builder()
        .command(CommandProcessor.SMFIC_OPTNEG)
        .payload(payload)
        .build();
    context.sendPacket(response);
  }

  @Override public void unknown(MilterContext context, byte[] payload) throws MilterException {
    context.sendContinue();
  }

  @Override public void abortSession(MilterContext context, MilterPacket packet) {
    if (MilterPacketUtil.isMessageState(context.getSessionState())) {
      try {
        abort(context, packet);
      } catch (MilterException ex) {
        logger.info(ex, "[%s] can't execute abort command", context.id());
      }
    }
    closeSession(context);
  }

  @Override public void closeSession(MilterContext context) {
    try {
      close(context);
    } finally {
      context.destroy();
    }
  }

  @Override public MilterContext createSession(MilterPacketSender sender) {
    return new MilterContextImpl(milterActions, milterProtocolSteps, sender);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy