001 /****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one *
003 * or more contributor license agreements. See the NOTICE file *
004 * distributed with this work for additional information *
005 * regarding copyright ownership. The ASF licenses this file *
006 * to you under the Apache License, Version 2.0 (the *
007 * "License"); you may not use this file except in compliance *
008 * with the License. You may obtain a copy of the License at *
009 * *
010 * http://www.apache.org/licenses/LICENSE-2.0 *
011 * *
012 * Unless required by applicable law or agreed to in writing, *
013 * software distributed under the License is distributed on an *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015 * KIND, either express or implied. See the License for the *
016 * specific language governing permissions and limitations *
017 * under the License. *
018 ****************************************************************/
019 package org.apache.james.protocols.smtp.core;
020
021 import java.util.ArrayList;
022 import java.util.Collection;
023 import java.util.LinkedList;
024 import java.util.List;
025
026 import org.apache.james.protocols.api.Request;
027 import org.apache.james.protocols.api.Response;
028 import org.apache.james.protocols.api.handler.CommandHandler;
029 import org.apache.james.protocols.api.handler.ExtensibleHandler;
030 import org.apache.james.protocols.api.handler.LineHandler;
031 import org.apache.james.protocols.api.handler.WiringException;
032 import org.apache.james.protocols.smtp.MailEnvelope;
033 import org.apache.james.protocols.smtp.MailEnvelopeImpl;
034 import org.apache.james.protocols.smtp.SMTPResponse;
035 import org.apache.james.protocols.smtp.SMTPRetCode;
036 import org.apache.james.protocols.smtp.SMTPSession;
037 import org.apache.james.protocols.smtp.dsn.DSNStatus;
038 import org.apache.mailet.MailAddress;
039
040
041 /**
042 * handles DATA command
043 */
044 public class DataCmdHandler implements CommandHandler<SMTPSession>, ExtensibleHandler {
045
046 public static final class DataConsumerLineHandler implements LineHandler<SMTPSession> {
047
048 /**
049 * @see org.apache.james.protocols.api.handler.LineHandler
050 * #onLine(org.apache.james.protocols.api.ProtocolSession, byte[])
051 */
052 public SMTPResponse onLine(SMTPSession session, byte[] line) {
053
054 // Discard everything until the end of DATA session
055 if (line.length == 3 && line[0] == 46) {
056 session.popLineHandler();
057 }
058 return null;
059 }
060 }
061
062 public static final class DataLineFilterWrapper implements LineHandler<SMTPSession> {
063
064 private DataLineFilter filter;
065 private LineHandler<SMTPSession> next;
066
067 public DataLineFilterWrapper(DataLineFilter filter, LineHandler<SMTPSession> next) {
068 this.filter = filter;
069 this.next = next;
070 }
071
072 /**
073 * @see org.apache.james.protocols.api.handler.LineHandler
074 * #onLine(org.apache.james.protocols.api.ProtocolSession, byte[])
075 */
076 public Response onLine(SMTPSession session, byte[] line) {
077 return filter.onLine(session, line, next);
078 }
079
080 }
081
082 public final static String MAILENV = "MAILENV";
083
084 private LineHandler<SMTPSession> lineHandler;
085
086 /**
087 * process DATA command
088 *
089 */
090 public Response onCommand(SMTPSession session, Request request) {
091 String parameters = request.getArgument();
092 SMTPResponse response = doDATAFilter(session,parameters);
093
094 if (response == null) {
095 return doDATA(session, parameters);
096 } else {
097 return response;
098 }
099 }
100
101
102 /**
103 * Handler method called upon receipt of a DATA command.
104 * Reads in message data, creates header, and delivers to
105 * mail server service for delivery.
106 *
107 * @param session SMTP session object
108 * @param argument the argument passed in with the command by the SMTP client
109 */
110 @SuppressWarnings("unchecked")
111 protected SMTPResponse doDATA(SMTPSession session, String argument) {
112 MailEnvelope env = createEnvelope(session, (MailAddress) session.getState().get(SMTPSession.SENDER), new ArrayList<MailAddress>((Collection)session.getState().get(SMTPSession.RCPT_LIST)));
113 session.getState().put(MAILENV, env);
114 session.pushLineHandler(lineHandler);
115
116 return new SMTPResponse(SMTPRetCode.DATA_READY, "Ok Send data ending with <CRLF>.<CRLF>");
117 }
118
119 protected MailEnvelope createEnvelope(SMTPSession session, MailAddress sender, List<MailAddress> recipients) {
120 MailEnvelopeImpl env = new MailEnvelopeImpl();
121 env.setRecipients(recipients);
122 env.setSender(sender);
123 return env;
124 }
125
126
127 /**
128 * @see org.apache.james.protocols.api.handler.CommandHandler#getImplCommands()
129 */
130 public Collection<String> getImplCommands() {
131 Collection<String> implCommands = new ArrayList<String>();
132 implCommands.add("DATA");
133
134 return implCommands;
135 }
136
137
138 /**
139 * @see org.apache.james.protocols.api.handler.ExtensibleHandler#getMarkerInterfaces()
140 */
141 @SuppressWarnings("unchecked")
142 public List getMarkerInterfaces() {
143 List classes = new LinkedList();
144 classes.add(DataLineFilter.class);
145 return classes;
146 }
147
148
149 /**
150 * @see org.apache.james.protocols.api.handler.ExtensibleHandler#wireExtensions(java.lang.Class, java.util.List)
151 */
152 @SuppressWarnings("unchecked")
153 public void wireExtensions(Class interfaceName, List extension) throws WiringException {
154 if (DataLineFilter.class.equals(interfaceName)) {
155
156 LineHandler<SMTPSession> lineHandler = new DataConsumerLineHandler();
157 for (int i = extension.size() - 1; i >= 0; i--) {
158 lineHandler = new DataLineFilterWrapper((DataLineFilter) extension.get(i), lineHandler);
159 }
160
161 this.lineHandler = lineHandler;
162 }
163 }
164
165 protected SMTPResponse doDATAFilter(SMTPSession session, String argument) {
166 if ((argument != null) && (argument.length() > 0)) {
167 return new SMTPResponse(SMTPRetCode.SYNTAX_ERROR_COMMAND_UNRECOGNIZED, DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Unexpected argument provided with DATA command");
168 }
169 if (!session.getState().containsKey(SMTPSession.SENDER)) {
170 return new SMTPResponse(SMTPRetCode.BAD_SEQUENCE, DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" No sender specified");
171 } else if (!session.getState().containsKey(SMTPSession.RCPT_LIST)) {
172 return new SMTPResponse(SMTPRetCode.BAD_SEQUENCE, DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" No recipients specified");
173 }
174 return null;
175 }
176
177 protected LineHandler<SMTPSession> getLineHandler() {
178 return lineHandler;
179 }
180
181 }