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.nio.charset.Charset;
022 import java.util.Collection;
023 import java.util.Date;
024 import java.util.List;
025
026 import org.apache.james.protocols.api.Response;
027 import org.apache.james.protocols.api.handler.LineHandler;
028 import org.apache.james.protocols.smtp.SMTPSession;
029 import org.apache.mailet.base.RFC2822Headers;
030 import org.apache.mailet.base.RFC822DateFormat;
031
032 public class ReceivedDataLineFilter implements DataLineFilter {
033
034 private final static Charset CHARSET = Charset.forName("US-ASCII");
035
036 private final static String SOFTWARE_TYPE = "JAMES SMTP Server ";
037
038 // Replace this with something usefull
039 // + Constants.SOFTWARE_VERSION;
040
041 /**
042 * Static RFC822DateFormat used to generate date headers
043 */
044 private final static RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
045 private final static String HEADERS_WRITTEN = "HEADERS_WRITTEN";
046
047
048 /**
049 * @see org.apache.james.protocols.smtp.core.DataLineFilter#onLine(SMTPSession, byte[], LineHandler)
050 */
051 public Response onLine(SMTPSession session, byte[] line, LineHandler<SMTPSession> next) {
052 if (session.getState().containsKey(HEADERS_WRITTEN) == false) {
053 Response response = addNewReceivedMailHeaders(session, next);
054
055 session.getState().put(HEADERS_WRITTEN, true);
056
057 if (response != null) {
058 return response;
059 }
060 }
061 Response resp = next.onLine(session, line);
062 return resp;
063 }
064
065 private Response addNewReceivedMailHeaders(SMTPSession session, LineHandler<SMTPSession> next) {
066 StringBuilder headerLineBuffer = new StringBuilder();
067
068 String heloMode = (String) session.getConnectionState().get(
069 SMTPSession.CURRENT_HELO_MODE);
070 String heloName = (String) session.getConnectionState().get(
071 SMTPSession.CURRENT_HELO_NAME);
072
073 // Put our Received header first
074 headerLineBuffer.append(RFC2822Headers.RECEIVED + ": from ").append(
075 session.getRemoteHost());
076
077 if (heloName != null) {
078 headerLineBuffer.append(" (").append(heloMode).append(" ").append(
079 heloName).append(") ");
080 }
081
082 headerLineBuffer.append(" ([").append(session.getRemoteIPAddress())
083 .append("])").append("\r\n");
084
085 Response response = next.onLine(session, headerLineBuffer.toString().getBytes(CHARSET));
086 if (response != null) {
087 return response;
088 }
089 headerLineBuffer.delete(0, headerLineBuffer.length());
090
091 headerLineBuffer.append(" by ").append(session.getHelloName())
092 .append(" (").append(SOFTWARE_TYPE).append(") with ");
093
094 // Check if EHLO was used
095 if ("EHLO".equals(heloMode)) {
096 // Not successful auth
097 if (session.getUser() == null) {
098 headerLineBuffer.append("ESMTP");
099 } else {
100 // See RFC3848
101 // The new keyword "ESMTPA" indicates the use of ESMTP when the
102 // SMTP
103 // AUTH [3] extension is also used and authentication is
104 // successfully
105 // achieved.
106 headerLineBuffer.append("ESMTPA");
107 }
108 } else {
109 headerLineBuffer.append("SMTP");
110 }
111
112 headerLineBuffer.append(" ID ").append(session.getSessionID());
113
114 if (((Collection) session.getState().get(SMTPSession.RCPT_LIST)).size() == 1) {
115 // Only indicate a recipient if they're the only recipient
116 // (prevents email address harvesting and large headers in
117 // bulk email)
118 headerLineBuffer.append("\r\n");
119 next.onLine(session, headerLineBuffer.toString().getBytes(CHARSET));
120 headerLineBuffer.delete(0, headerLineBuffer.length());
121
122 headerLineBuffer.delete(0, headerLineBuffer.length());
123 headerLineBuffer.append(" for <").append(((List) session.getState().get(SMTPSession.RCPT_LIST)).get(0).toString()).append(">;").append("\r\n");
124 response = next.onLine(session, headerLineBuffer.toString().getBytes(CHARSET));
125
126 if (response != null) {
127 return response;
128 }
129 headerLineBuffer.delete(0, headerLineBuffer.length());
130 headerLineBuffer.delete(0, headerLineBuffer.length());
131
132 } else {
133 // Put the ; on the end of the 'by' line
134 headerLineBuffer.append(";");
135 headerLineBuffer.append("\r\n");
136
137 response = next.onLine(session, headerLineBuffer.toString().getBytes(CHARSET));
138 if (response != null) {
139 return response;
140 }
141 headerLineBuffer.delete(0, headerLineBuffer.length());
142 }
143 headerLineBuffer = null;
144 return next.onLine(session, (" " + rfc822DateFormat.format(new Date()) + "\r\n").getBytes(CHARSET));
145
146 }
147 }