    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 }