1   /*
2    * Dumbster: a dummy SMTP server.
3    * Copyright (C) 2003, Jason Paul Kitchen
4    * lilnottsman@yahoo.com
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public
8    * License as published by the Free Software Foundation; either
9    * version 2.1 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19   */
20  package com.dumbster.smtp;
21  
22  import java.io.BufferedReader;
23  import java.io.IOException;
24  import java.io.InputStreamReader;
25  import java.io.InterruptedIOException;
26  import java.io.PrintWriter;
27  import java.net.ServerSocket;
28  import java.net.Socket;
29  import java.util.ArrayList;
30  import java.util.Iterator;
31  import java.util.List;
32  
33  /***
34   * Dummy SMTP server for testing purposes.
35   */
36  public class SimpleSmtpServer implements Runnable {
37  
38  	/*** Stores all of the email received since this instance started up. */
39  	private List receivedMail;
40  
41  	/*** Default SMTP port is 25. */
42  	public static final int DEFAULT_SMTP_PORT = 25;
43  
44  	/*** Indicates whether this server is stopped or not. */
45  	private volatile boolean stopped = true;
46  
47  	/*** Indicates if a stop request has been sent to this server. */
48  	private volatile boolean doStop = false;
49  
50  	/*** Port the server listens on - set to the default SMTP port initially. */
51  	private int port = DEFAULT_SMTP_PORT;
52  
53  	/***
54  	 * Constructor.
55  	 */
56  	public SimpleSmtpServer(int port) {
57  		receivedMail = new ArrayList();
58  		this.port = port;
59  	}
60  
61  	/***
62  	 * Main loop of the SMTP server.
63  	 */
64  	public void run() {
65  		stopped = false;
66  		ServerSocket serverSocket = null;
67  		try {
68  			serverSocket = new ServerSocket(port);
69  			serverSocket.setSoTimeout(500); // Block for maximum of 1.5 seconds
70  
71  			// Server: loop until stopped
72  			while (!doStop) {
73  				Socket socket = null;
74  				try {
75  					socket = serverSocket.accept();
76  				} catch (InterruptedIOException iioe) {
77  					if (socket != null) {
78  						socket.close();
79  					}
80  					continue; // Non-blocking socket timeout occurred: try accept() again
81  				}
82  
83  				// Get the input and output streams
84  				BufferedReader input = new BufferedReader(new InputStreamReader(socket
85  						.getInputStream()));
86  				PrintWriter out = new PrintWriter(socket.getOutputStream());
87  
88  				// Initialize the state machine
89  				SmtpState smtpState = SmtpState.CONNECT;
90  				SmtpRequest smtpRequest = new SmtpRequest(SmtpActionType.CONNECT, "", smtpState);
91  
92  				// Execute the connection request
93  				SmtpResponse smtpResponse = smtpRequest.execute();
94  
95  				// Send initial response
96  				sendResponse(out, smtpResponse);
97  				smtpState = smtpResponse.getNextState();
98  
99  				SmtpMessage msg = new SmtpMessage();
100 
101 				while (smtpState != SmtpState.CONNECT) {
102 					String line = input.readLine();
103 
104 					if (line == null) {
105 						break;
106 					}
107 					// Create request from client input and current state
108 					SmtpRequest request = SmtpRequest.createRequest(line, smtpState);
109 					// Execute request and create response object
110 					SmtpResponse response = request.execute();
111 					// Move to next internal state
112 					smtpState = response.getNextState();
113 					// Send reponse to client
114 					sendResponse(out, response);
115 
116 					// Store input in message
117 					msg.store(response, request.getParams());
118 				}
119 
120 				receivedMail.add(msg);
121 				socket.close();
122 			}
123 		} catch (Exception e) {
124 			// e.printStackTrace();
125 		} finally {
126 			if (serverSocket != null) {
127 				try {
128 					serverSocket.close();
129 				} catch (IOException e) {
130 					e.printStackTrace();
131 				}
132 			}
133 		}
134 		stopped = true;
135 	}
136 
137 	/***
138 	 * Send response to client.
139 	 * @param out socket output stream
140 	 * @param smtpResponse response object
141 	 */
142 	private void sendResponse(PrintWriter out, SmtpResponse smtpResponse) {
143 		if (smtpResponse.getCode() > 0) {
144 			out.print(smtpResponse.getCode() + " " + smtpResponse.getMessage() + "\r\n");
145 			out.flush();
146 		}
147 	}
148 
149 	/***
150 	 * Get email received by this instance since start up.
151 	 * @return List of String
152 	 */
153 	public Iterator getReceivedEmail() {
154 		return receivedMail.iterator();
155 	}
156 
157 	/***
158 	 * Get the number of messages received.
159 	 * @return size of received email list
160 	 */
161 	public int getReceievedEmailSize() {
162 		return receivedMail.size();
163 	}
164 
165 	/***
166 	 * Forces the server to stop after processing the current request.
167 	 */
168 	public void stop() {
169 		doStop = true;
170 		while (!isStopped()) {} // Wait for email server to stop
171 	}
172 
173 	/***
174 	 * Indicates whether this server is stopped or not.
175 	 * @return true iff this server is stopped
176 	 */
177 	public boolean isStopped() {
178 		return stopped;
179 	}
180 
181 	/***
182 	 * Creates an instance of SimpleSmtpServer and starts it. Will listen on the default port.
183 	 * @return a reference to the SMTP server
184 	 */
185 	public static SimpleSmtpServer start() {
186 		return start(DEFAULT_SMTP_PORT);
187 	}
188 
189 	/***
190 	 * Creates an instance of SimpleSmtpServer and starts it.
191 	 * @param port port number the server should listen to
192 	 * @return a reference to the SMTP server
193 	 */
194 	public static SimpleSmtpServer start(int port) {
195 		SimpleSmtpServer server = new SimpleSmtpServer(port);
196 		Thread t = new Thread(server);
197 		t.start();
198 		return server;
199 	}
200 
201 }