1 package org.paneris.messageboard.receivemail;
2
3 import java.io.BufferedInputStream;
4 import java.io.BufferedReader;
5 import java.io.IOException;
6 import java.io.InputStreamReader;
7 import java.io.OutputStreamWriter;
8 import java.io.PrintWriter;
9 import java.io.PushbackInputStream;
10 import java.net.Socket;
11 import java.sql.SQLException;
12 import java.util.Properties;
13
14 import javax.mail.MessagingException;
15 import javax.mail.internet.InternetAddress;
16
17 import org.paneris.jal.model.DBConnectionManager;
18 import org.paneris.jal.model.Log;
19 import org.paneris.util.ExceptionUtils;
20 import org.paneris.util.StringUtils;
21
22
23
24
25
26
27
28
29
30 class SMTPSession extends Thread {
31
32 private String smtpIdentifier;
33 private Socket withClient;
34 private PushbackInputStream fromClientPushBack;
35 private BufferedReader fromClient;
36 private DBConnectionManager connMgr;
37 private Properties databaseNameOfDomain;
38 private int bufSize;
39 private PrintWriter toClient;
40 private Log log;
41
42 private String sender = null;
43 private MessageBoardStore store = null;
44 private MessageBoardStore.SenderID senderID = null;
45 private MessageBoardStore.RecipientID recipientID = null;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 SMTPSession(String smtpIdentifier, Socket withClient,
73 DBConnectionManager connMgr, Properties databaseNameOfDomain,
74 int bufSize, Log log)
75 throws IOException {
76 this.smtpIdentifier = smtpIdentifier;
77 this.withClient = withClient;
78 this.connMgr = connMgr;
79 this.databaseNameOfDomain = databaseNameOfDomain;
80 this.bufSize = bufSize;
81 bufSize = this.bufSize;
82 this.log = log;
83
84 fromClientPushBack =
85 new PushbackInputStream(new BufferedInputStream(
86 withClient.getInputStream(),
87 bufSize));
88
89 fromClient = new BufferedReader(new InputStreamReader(fromClientPushBack));
90
91 toClient =
92 new PrintWriter(new OutputStreamWriter(withClient.getOutputStream(),
93 "8859_1"),
94 true);
95 }
96
97
98
99
100
101 private void reset() {
102 sender = null;
103 senderID = null;
104 recipientID = null;
105 if (store != null) {
106 try {
107 store.close();
108 } catch (Exception e) {
109 ;
110 }
111 store = null;
112 }
113 }
114
115
116
117
118
119
120 private void mailFrom(String address) {
121 if (address.charAt(0) == '<') {
122
123 address = address.substring(1, address.length() - 1);
124 }
125
126
127
128 sender = address;
129 toClient.println("250 " + address + "... Sender provisionally OK");
130 }
131
132
133
134
135
136
137
138
139
140
141 private MessageBoardStore storeForAddress(String address)
142 throws MessagingException, IOException {
143 int atIndex = address.indexOf('@');
144 if (atIndex == -1)
145 throw new MessagingException("`" + address + "': missing domain, " +
146 "so can't determine which database to use");
147
148 String domain = address.substring(atIndex + 1);
149 String propertyName =
150 "org.paneris.messageboard.receivemail.database." + domain;
151
152 String databaseName = databaseNameOfDomain.getProperty(propertyName);
153
154 if (databaseName == null)
155 throw new MessagingException(
156 "`" + domain + "' is not a messageboard mail domain " +
157 "(no entry `" + propertyName + "' in properties)");
158
159 try {
160 return new MessageBoardStore(connMgr, databaseName, log);
161 }
162 catch (IOException e) {
163 throw new IOException(
164 "failed to open message store `" + domain + "' -> `" + databaseName +
165 "': " + e);
166 }
167 }
168
169
170
171
172
173
174
175 private void rcptTo(String address) throws Exception {
176 if (sender == null)
177 toClient.println("503 Need MAIL before RCPT");
178
179 else if (store != null) {
180
181
182 toClient.println("553 a message can only appear on one board, " +
183 "but this one was copied to several");
184 }
185
186 else {
187 if (address.charAt(0) == '<') {
188
189 address = address.substring(1, address.length() - 1);
190 }
191 try {
192 store = storeForAddress(address);
193
194
195
196
197 senderID = store.senderIDOfAddress(new InternetAddress(sender));
198 recipientID =
199 store.recipientIDOfAddress(new InternetAddress(address));
200
201 toClient.println("250 Recipient OK");
202 }
203 catch (MessagingException e) {
204 toClient.println("550 " +
205 StringUtils.tr(e.getMessage(), "\n\r", " "));
206 log.warning("board address `" + address + "' rejected: " + e);
207 }
208 }
209 }
210
211
212
213
214
215 private void data() throws Exception {
216 if (senderID == null || recipientID == null)
217 toClient.println("503 Need MAIL command");
218 else {
219 toClient.println("354 Enter mail, end with \".\" on a line by itself");
220
221 try {
222 Object messageID = store.messageAccept(senderID, recipientID,
223 new DotTerminatedInputStream(fromClientPushBack));
224
225 toClient.println("250 "+messageID+" Message accepted for delivery");
226 }
227 catch (SQLException e) {
228 if (e.getMessage().startsWith("SQL Statement too long")) {
229 toClient.println("552 Your message message is too long---" +
230 "can you split it up?");
231 reset();
232 }
233 else { throw e; }
234 }
235
236 reset();
237 }
238 }
239
240
241
242
243 public void run () {
244 try {
245 toClient.println("220 " + smtpIdentifier + " SMTP");
246 for (;;) {
247 String command = fromClient.readLine().trim();
248
249 if (command.regionMatches(true, 0, "HELO", 0, 4))
250 toClient.println("250 " + smtpIdentifier);
251
252 else if (command.regionMatches(true, 0, "MAIL FROM:", 0, 10))
253 mailFrom(command.substring(10).trim());
254
255 else if (command.regionMatches(true, 0, "RCPT TO:", 0, 8))
256 rcptTo(command.substring(8).trim());
257
258 else if (command.regionMatches(true, 0, "DATA", 0, 4))
259 data();
260
261 else if (command.regionMatches(true, 0, "RSET", 0, 4)) {
262 reset();
263 toClient.println("250 Reset state");
264 }
265
266 else if (command.regionMatches(true, 0, "QUIT", 0, 4)) {
267 toClient.println("221 " + smtpIdentifier + " closing connection");
268 break;
269 }
270
271 else
272 toClient.println("500 Command unrecognized: \"" + command + "\"");
273 }
274 }
275 catch (Exception e) {
276 toClient.println("554 Sorry: something is wrong with this server---" +
277 StringUtils.tr(e.toString(), "\n\r", " "));
278 log.error("post of message from `" + sender + "' failed:\n" +
279 ExceptionUtils.stackTrace(e));
280 }
281 finally {
282 try {
283 reset();
284 withClient.close();
285 }
286 catch (Exception e) {
287 ;
288 }
289 }
290 }
291 }