1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.james.smtpserver.core;
23
24 import org.apache.avalon.framework.logger.AbstractLogEnabled;
25 import org.apache.james.Constants;
26 import org.apache.james.core.MailHeaders;
27 import org.apache.james.core.MailImpl;
28 import org.apache.james.dsn.DSNStatus;
29 import org.apache.james.smtpserver.ReaderInputStream;
30 import org.apache.james.smtpserver.CommandHandler;
31 import org.apache.james.smtpserver.MessageSizeException;
32 import org.apache.james.smtpserver.SMTPSession;
33 import org.apache.james.smtpserver.SizeLimitedInputStream;
34 import org.apache.james.util.stream.CharTerminatedInputStream;
35 import org.apache.james.util.stream.DotStuffingInputStream;
36 import org.apache.james.util.watchdog.BytesReadResetInputStream;
37 import org.apache.mailet.MailAddress;
38 import org.apache.mailet.base.RFC2822Headers;
39 import org.apache.mailet.base.RFC822DateFormat;
40
41 import javax.mail.MessagingException;
42
43 import java.io.ByteArrayInputStream;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.io.SequenceInputStream;
47 import java.io.StringReader;
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import java.util.Date;
51 import java.util.Enumeration;
52 import java.util.List;
53
54
55
56
57
58 public class DataCmdHandler
59 extends AbstractLogEnabled
60 implements CommandHandler {
61
62 private final static String SOFTWARE_TYPE = "JAMES SMTP Server "
63 + Constants.SOFTWARE_VERSION;
64
65
66
67
68 private final static RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
69
70
71
72
73
74
75 private final static String SMTP_AUTH_USER_ATTRIBUTE_NAME = "org.apache.james.SMTPAuthUser";
76
77
78
79
80 private final static String SMTP_AUTH_NETWORK_NAME = "org.apache.james.SMTPIsAuthNetwork";
81
82
83
84
85 private final static char[] SMTPTerminator = { '\r', '\n', '.', '\r', '\n' };
86
87
88
89
90
91
92 public void onCommand(SMTPSession session) {
93 doDATA(session, session.getCommandArgument());
94 }
95
96
97
98
99
100
101
102
103
104
105 private void doDATA(SMTPSession session, String argument) {
106
107 String responseString = null;
108 responseString = "354 Ok Send data ending with <CRLF>.<CRLF>";
109 session.writeResponse(responseString);
110 InputStream msgIn = new CharTerminatedInputStream(session
111 .getInputStream(), SMTPTerminator);
112 try {
113 msgIn = new BytesReadResetInputStream(msgIn, session.getWatchdog(),
114 session.getConfigurationData().getResetLength());
115
116
117
118 long maxMessageSize = session.getConfigurationData()
119 .getMaxMessageSize();
120 if (maxMessageSize > 0) {
121 if (getLogger().isDebugEnabled()) {
122 StringBuffer logBuffer = new StringBuffer(128).append(
123 "Using SizeLimitedInputStream ").append(
124 " with max message size: ").append(maxMessageSize);
125 getLogger().debug(logBuffer.toString());
126 }
127 msgIn = new SizeLimitedInputStream(msgIn, maxMessageSize);
128 }
129
130 msgIn = new DotStuffingInputStream(msgIn);
131
132 MailHeaders headers = new MailHeaders(msgIn);
133 headers = processMailHeaders(session, headers);
134 processMail(session, headers, msgIn);
135 headers = null;
136 } catch (MessagingException me) {
137
138 Exception e = me.getNextException();
139
140
141 if (e != null && e instanceof MessageSizeException) {
142
143
144
145
146 session.getState().put(SMTPSession.MESG_FAILED, Boolean.TRUE);
147
148
149 responseString = "552 "
150 + DSNStatus.getStatus(DSNStatus.PERMANENT,
151 DSNStatus.SYSTEM_MSG_TOO_BIG)
152 + " Error processing message: " + e.getMessage();
153 StringBuffer errorBuffer = new StringBuffer(256).append(
154 "Rejected message from ").append(
155 session.getState().get(SMTPSession.SENDER).toString())
156 .append(" from host ").append(session.getRemoteHost())
157 .append(" (").append(session.getRemoteIPAddress())
158 .append(") exceeding system maximum message size of ")
159 .append(
160 session.getConfigurationData()
161 .getMaxMessageSize());
162 getLogger().error(errorBuffer.toString());
163 } else {
164 responseString = "451 "
165 + DSNStatus.getStatus(DSNStatus.TRANSIENT,
166 DSNStatus.UNDEFINED_STATUS)
167 + " Error processing message: " + me.getMessage();
168 getLogger().error(
169 "Unknown error occurred while processing DATA.", me);
170 }
171 session.writeResponse(responseString);
172 return;
173 } finally {
174 if (msgIn != null) {
175 try {
176 msgIn.close();
177 } catch (Exception e) {
178
179 }
180 msgIn = null;
181 }
182 }
183
184 }
185
186
187
188
189
190
191
192 private MailHeaders processMailHeaders(SMTPSession session, MailHeaders headers)
193 throws MessagingException {
194
195
196 if (!headers.isSet(RFC2822Headers.DATE)) {
197 headers.setHeader(RFC2822Headers.DATE, rfc822DateFormat.format(new Date()));
198 }
199 if (!headers.isSet(RFC2822Headers.FROM) && session.getState().get(SMTPSession.SENDER) != null) {
200 headers.setHeader(RFC2822Headers.FROM, session.getState().get(SMTPSession.SENDER).toString());
201 }
202
203
204
205
206
207 StringBuffer headerLineBuffer = new StringBuffer(512);
208
209 Enumeration headerLines = headers.getAllHeaderLines();
210 MailHeaders newHeaders = new MailHeaders();
211
212 String heloMode = (String) session.getConnectionState().get(SMTPSession.CURRENT_HELO_MODE);
213 String heloName = (String) session.getConnectionState().get(SMTPSession.CURRENT_HELO_NAME);
214
215
216 headerLineBuffer.append(RFC2822Headers.RECEIVED + ": from ")
217 .append(session.getRemoteHost());
218
219 if (heloName != null) {
220 headerLineBuffer.append(" (")
221 .append(heloMode)
222 .append(" ")
223 .append(heloName)
224 .append(") ");
225 }
226
227 headerLineBuffer.append(" ([")
228 .append(session.getRemoteIPAddress())
229 .append("])");
230
231 newHeaders.addHeaderLine(headerLineBuffer.toString());
232 headerLineBuffer.delete(0, headerLineBuffer.length());
233
234 headerLineBuffer.append(" by ")
235 .append(session.getConfigurationData().getHelloName())
236 .append(" (")
237 .append(SOFTWARE_TYPE)
238 .append(") with ");
239
240
241 if ("EHLO".equals(heloMode)) {
242
243
244 if (session.getUser() == null) {
245 headerLineBuffer.append("ESMTP");
246 } else {
247
248
249
250
251 headerLineBuffer.append("ESMTPA");
252 }
253 } else {
254 headerLineBuffer.append("SMTP");
255 }
256
257 headerLineBuffer.append(" ID ")
258 .append(session.getSessionID());
259
260 if (((Collection) session.getState().get(SMTPSession.RCPT_LIST)).size() == 1) {
261
262
263
264 newHeaders.addHeaderLine(headerLineBuffer.toString());
265 headerLineBuffer.delete(0, headerLineBuffer.length());
266 headerLineBuffer.append(" for <")
267 .append(((List) session.getState().get(SMTPSession.RCPT_LIST)).get(0).toString())
268 .append(">;");
269 newHeaders.addHeaderLine(headerLineBuffer.toString());
270 headerLineBuffer.delete(0, headerLineBuffer.length());
271 } else {
272
273 headerLineBuffer.append(";");
274 newHeaders.addHeaderLine(headerLineBuffer.toString());
275 headerLineBuffer.delete(0, headerLineBuffer.length());
276 }
277 headerLineBuffer = null;
278 newHeaders.addHeaderLine(" " + rfc822DateFormat.format(new Date()));
279
280
281 while (headerLines.hasMoreElements()) {
282 newHeaders.addHeaderLine((String) headerLines.nextElement());
283 }
284 return newHeaders;
285 }
286
287
288
289
290
291
292
293
294
295 private void processMail(SMTPSession session, MailHeaders headers, InputStream msgIn)
296 throws MessagingException {
297 ByteArrayInputStream headersIn = null;
298 MailImpl mail = null;
299 List recipientCollection = null;
300 try {
301 headersIn = new ByteArrayInputStream(headers.toByteArray());
302 recipientCollection = (List) session.getState().get(SMTPSession.RCPT_LIST);
303 mail =
304 new MailImpl(session.getConfigurationData().getMailServer().getId(),
305 (MailAddress) session.getState().get(SMTPSession.SENDER),
306 recipientCollection,
307 new SequenceInputStream(new SequenceInputStream(headersIn, msgIn),
308 new ReaderInputStream(new StringReader("\r\n"))));
309
310
311 if (session.getConfigurationData().getMaxMessageSize() > 0) {
312 mail.getMessageSize();
313 }
314 mail.setRemoteHost(session.getRemoteHost());
315 mail.setRemoteAddr(session.getRemoteIPAddress());
316 if (session.getUser() != null) {
317 mail.setAttribute(SMTP_AUTH_USER_ATTRIBUTE_NAME, session.getUser());
318 }
319
320 if (session.isRelayingAllowed()) {
321 mail.setAttribute(SMTP_AUTH_NETWORK_NAME,"true");
322 }
323
324 session.setMail(mail);
325 } catch (MessagingException me) {
326
327
328
329
330
331
332
333
334
335
336
337
338 if (mail != null) {
339 mail.dispose();
340 }
341 throw me;
342 } finally {
343 if (recipientCollection != null) {
344 recipientCollection.clear();
345 }
346 recipientCollection = null;
347 if (headersIn != null) {
348 try {
349 headersIn.close();
350 } catch (IOException ioe) {
351
352 }
353 }
354 headersIn = null;
355 }
356
357 }
358
359
360
361
362 public Collection getImplCommands() {
363 Collection implCommands = new ArrayList();
364 implCommands.add("DATA");
365
366 return implCommands;
367 }
368
369 }