1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.mercury.smtp.command;
14
15 import java.io.IOException;
16 import java.io.InterruptedIOException;
17 import java.io.OutputStream;
18 import java.io.PrintStream;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.Map.Entry;
22
23 import org.abstracthorizon.danube.connection.Connection;
24 import org.abstracthorizon.danube.service.server.ServerConnectionHandler;
25 import org.abstracthorizon.mercury.common.command.CommandException;
26 import org.abstracthorizon.mercury.smtp.SMTPResponses;
27 import org.abstracthorizon.mercury.smtp.SMTPScanner;
28 import org.abstracthorizon.mercury.smtp.SMTPSession;
29 import org.abstracthorizon.mercury.smtp.exception.ParserException;
30 import org.abstracthorizon.mercury.smtp.filter.MailSessionData;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
35
36
37
38
39
40 public class SMTPCommandFactory extends ServerConnectionHandler {
41
42
43 public static String HELO = "HELO";
44
45
46 public static String EHLO = "EHLO";
47
48
49 public static String MAIL = "MAIL";
50
51
52 public static String RCPT = "RCPT";
53
54
55 public static String DATA = "DATA";
56
57
58 public static String NOOP = "NOOP";
59
60
61 public static String RSET = "RSET";
62
63
64 public static String QUIT = "QUIT";
65
66
67 public static String VRFY = "VRFY";
68
69
70 public static String EXPN = "EXPN";
71
72
73 protected static final Logger logger = LoggerFactory.getLogger(SMTPCommandFactory.class);
74
75
76 protected Map<String, SMTPCommand> commands = new HashMap<String, SMTPCommand>();
77
78
79 protected int inactivityTimeout = 120000;
80
81
82
83
84 public SMTPCommandFactory() {
85
86 commands.put(EHLO, new EhloCommand());
87 commands.put(HELO, new EhloCommand());
88 commands.put(MAIL, new MailCommand());
89 commands.put(RCPT, new RcptCommand());
90 commands.put(DATA, new DataCommand());
91
92 commands.put(NOOP, new NoopCommand());
93 commands.put(RSET, new ResetCommand());
94 commands.put(QUIT, new QuitCommand());
95 commands.put(VRFY, new NotImplementedCommand());
96 commands.put(EXPN, new NotImplementedCommand());
97 }
98
99
100
101
102
103 public Map<String, SMTPCommand> getCommands() {
104 return commands;
105 }
106
107
108
109
110
111 public void setCommands(Map<String, SMTPCommand> commands) {
112 this.commands = commands;
113 }
114
115
116
117
118
119 public void setInactivityTimeout(int timeout) {
120 this.inactivityTimeout = timeout;
121 }
122
123
124
125
126
127 public int getInactivityTimeout() {
128 return inactivityTimeout;
129 }
130
131
132
133
134
135 protected void processConnection(Connection connection) {
136 SMTPSession smtpConnection = (SMTPSession)connection.adapt(SMTPSession.class);
137 try {
138 processKeywords(smtpConnection);
139 } catch (IOException e) {
140 throw new RuntimeException(e);
141 }
142 }
143
144
145
146
147
148
149 protected Connection decorateConnection(Connection connection) {
150 SMTPSession smtpConnection = (SMTPSession)connection.adapt(SMTPSession.class);
151 smtpConnection.setCommandFactory(this);
152 smtpConnection.setState(SMTPSession.STATE_READY);
153 return smtpConnection;
154 }
155
156
157
158
159
160 protected boolean postProcessing(Connection connection) {
161 boolean persistConnection = super.postProcessing(connection);
162 SMTPSession session = (SMTPSession)connection.adapt(SMTPSession.class);
163 if ((System.currentTimeMillis() - session.getSessionAccessed()) > getInactivityTimeout()) {
164 return false;
165 }
166
167
168
169
170
171 MailSessionData data = session.getMailSessionData();
172 boolean dropConnection = "true".equals(data.getAttribute("dropconnection"));
173 persistConnection = !dropConnection && persistConnection && (session.getState() != SMTPSession.STATE_READY);
174
175 return persistConnection;
176 }
177
178
179
180
181
182
183 protected void finishProcessingConnection(Connection connection, boolean closedConnection) {
184
185 }
186
187
188
189
190
191
192
193 public SMTPCommand getCommand(String mnemonic) throws CommandException {
194 SMTPCommand command = commands.get(mnemonic);
195 return command;
196 }
197
198
199
200
201
202
203
204
205 public void processKeywords(SMTPSession smtpConnection) throws IOException {
206 SMTPScanner scanner = smtpConnection.getScanner();
207 for (Entry<String, SMTPCommand> entry : commands.entrySet()) {
208 if (scanner.keyword(entry.getKey())) {
209 invokeCommand(smtpConnection, entry.getKey(), entry.getValue());
210 return;
211 }
212 }
213
214 scanner.skip_line();
215 scanner.resetEOL();
216 smtpConnection.sendResponse(SMTPResponses.COMMAND_NOT_RECOGNISED_RESPONSE);
217 }
218
219
220
221
222
223
224
225
226
227 public void invokeCommand(SMTPSession smtpConnection, String commandName, SMTPCommand command) throws IOException {
228 SMTPScanner scanner = smtpConnection.getScanner();
229 if (scanner.peek_char(' ') || scanner.peek_char('\r')) {
230 try {
231 long started = System.currentTimeMillis();
232 try {
233 if (command != null) {
234 command.handleConnection(smtpConnection);
235 } else {
236 smtpConnection.sendResponse(SMTPResponses.SYNTAX_ERROR_RESPONSE);
237 }
238 } finally {
239 if (logger.isDebugEnabled()) {
240 logger.debug("Command " + commandName + " completed in " + (System.currentTimeMillis() - started) + "ms");
241 }
242 }
243 } catch (InterruptedIOException e) {
244 throw e;
245 } catch (ParserException e) {
246 smtpConnection.setKeepLog(true);
247 if (logger.isDebugEnabled()) {
248 logger.debug("Problem", e);
249 }
250 OutputStream debugStream = smtpConnection.getDebugStream();
251 if (debugStream != null) {
252 e.printStackTrace(new PrintStream(debugStream));
253 }
254 smtpConnection.sendResponse(SMTPResponses.SYNTAX_ERROR_RESPONSE);
255 } catch (CommandException e) {
256 smtpConnection.setKeepLog(true);
257 logger.error("Problem", e);
258 OutputStream debugStream = smtpConnection.getDebugStream();
259 if (debugStream != null) {
260 e.printStackTrace(new PrintStream(debugStream));
261 }
262 smtpConnection.sendResponse(SMTPResponses.GENERIC_ERROR_RESPONSE);
263 } catch (Throwable e) {
264 smtpConnection.setKeepLog(true);
265 logger.error("Problem", e);
266 OutputStream debugStream = smtpConnection.getDebugStream();
267 if (debugStream != null) {
268 e.printStackTrace(new PrintStream(debugStream));
269 }
270 smtpConnection.sendResponse(SMTPResponses.GENERIC_ERROR_RESPONSE);
271 }
272 } else {
273 smtpConnection.sendResponse(SMTPResponses.SYNTAX_ERROR_RESPONSE);
274 }
275 scanner.skip_line();
276 scanner.resetEOL();
277 }
278 }