// SmtpListener.java - listens for SMTP emails on port 25. // Adapted by Rowland http://home.comcast.net/~rowland3 // Based (a bit loosely) on a sample from http://www.engr.uconn.edu/~jeffm/ by Jeffrey A. Meunier import java.io.*; import java.net.*; import java.text.DateFormat; import java.util.*; class MailMessage { String subject; String date; Vector vbodylines; // message text is a vector of strings public final String sender, recipient; TreeMap header= new TreeMap(); public MailMessage(String _sender, String _recipient) { sender= _sender; recipient= _recipient; vbodylines = new Vector(); } public void addHeaderLine(String line) { try { int ix= line.indexOf(": "); if (ix< 0) return; String key= line.substring(0, ix); String val= line.substring(ix+2); if (val.endsWith("\n")) val= val.substring(val.length()-1); // get rid of trailing LF if (val.endsWith("\r")) val= val.substring(val.length()-1); // get rid of trailing CRLF header.put(key, val); } catch (Exception E) { System.err.println("MailMessage.addheaderLine: "+ line); } } public void addHeaderVal(String key, String val) { header.put(key, val); } public void addMailMessageLine(String _line) { vbodylines.add(_line); } public Enumeration getMailMessageLines() { return vbodylines.elements(); } public Iterator getHeaderFields() { return header.keySet().iterator(); } public String getHeaderVal(String key) { Object O= header.get(key); if (O== null) return null; return (String)O; } public String toString() { String s= "Sender: "+ sender+ "\tRecipient: "+ recipient+ "\n"; Iterator hi= header.keySet().iterator(); while (hi.hasNext()) { String key= (String)hi.next(); String hline= key+ ": "+ header.get(key)+ "\n"; s+= hline; } s+= "\n"; Enumeration e= vbodylines.elements(); while(e.hasMoreElements()) { s+= (String)e.nextElement()+ "\n"; } return s; } } //------------------------------------------------------------------------------ class SmtpConnHandler implements Runnable { public static String serverName = "emailtest"; Socket sclient; SmtpListener parent; Thread thread; BufferedReader in; OutputStreamWriter out; boolean debug= false; public SmtpConnHandler(Socket _sclient, SmtpListener _parent) { parent= _parent; sclient = _sclient; thread = new Thread(this); thread.start(); } public void setDebug(boolean _debug) { debug= _debug; } public void run() { if (debug) System.out.println("SMTP: connection from " + sclient.getInetAddress().getHostAddress()); try { InputStream inpStream = sclient.getInputStream(); out = new OutputStreamWriter(sclient.getOutputStream()); in = new BufferedReader(new InputStreamReader(inpStream)); writeln("220 " + serverName + " Service ready"); String clientcommand; while (true) { clientcommand = readln(); if (clientcommand == null) return; if (clientcommand.startsWith("EHLO")) break; else if (clientcommand.startsWith("HELO")) break; else if (clientcommand.equals("QUIT")) return; } writeln("250 " + serverName); while (true) { clientcommand = readln(); if (clientcommand.startsWith("MAIL")) readMailMessage(clientcommand); else if (clientcommand.equals("QUIT")) break; } writeln("221 " + serverName + " closing connection"); if (debug) System.err.println("SMTP: finished session, closing connection\n"); sclient.close(); } catch(Exception E) { System.err.println("SMTPHandler: "+ E.toString()); } } void readMailMessage(String clientcommand) throws IOException { String sSenderEmailAddr = findEmailAddr(clientcommand); ack(); String sRecptEmailAddr = findEmailAddr(readln()); ack(); String s = readln(); if (!s.equals("DATA")) { nak(); return; } writeln("354 Enter mail, end with \".\" on a line by itself"); MailMessage message = new MailMessage(sSenderEmailAddr, sRecptEmailAddr); while (true) { // get the message header s = readln(); if (s.equals("QUIT")) return; else if (s.equals(".")) // shouldn't actually happen return; else if (s.length()== 0) break; // end of header if (s.startsWith("..")) s= s.substring(1); message.addHeaderLine(s); } while (true) { // get the message body s = readln(); if (s.equals("QUIT")) return; else if (s.equals(".")) break; message.addMailMessageLine(s); } writeln("250 Message accepted"); if (parent!= null) parent.gotMailMessage(message); } protected final void writeln(String s) throws IOException { if (debug) System.err.println("SMTP: server sending (" + s + ")"); out.write(s+ "\r\n"); out.flush(); } protected final String readln() throws IOException { String s = in.readLine(); if (debug) System.err.println("SMTP: client sent [" + s + "]"); return s; } protected final void ack() throws IOException { writeln("250 OK"); } protected final void nak() throws IOException { writeln("451 aborted: local error"); } String findEmailAddr(String s) throws IOException { int ix= s.indexOf('<'); if (ix< 0) return s; String emailaddr= s.substring(ix+1); ix= emailaddr.indexOf('>'); if (ix< 0) return emailaddr; return emailaddr.substring(0, ix); } } //----------------------------------------------------------------------- class SmtpListener implements Runnable { ServerSocket slisten; Thread thread; boolean debug= false; public SmtpListener(boolean _debug) { debug= _debug; thread = new Thread(this); thread.start(); } public void setDebug(boolean _debug) { debug= _debug; } // Callback from SmtpConnHandler public synchronized void gotMailMessage(MailMessage m) { System.out.println(m.toString()); } public void run() { System.err.println("Starting SMTP listener"); try { slisten = new ServerSocket(25); // SMTP port while(true) { Socket sconn = slisten.accept(); SmtpConnHandler smtpHandler = new SmtpConnHandler(sconn, this); // spawns automatically if (debug) smtpHandler.setDebug(true); } } catch (Exception E) { System.err.println("SmtpListener: "+ E.toString()); } } public static void main (String args[]) { new SmtpListener(true); } }