// process the incomming connection and send the message to all interested plugins package net.reliableresponse.notification.smtp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Vector; import net.reliableresponse.notification.broker.BrokerFactory; interface commands { int none = 0; int helo = 1; int quit = 2; int mailfrom = 3; int rcptto = 4; int data = 5; int datafinished = 6; }; public class Process extends Thread { Socket clientSocket; // someone just tried to make a connection store the socket and wait for the // thread to handle it public Process(Socket PassedclientSocket) { clientSocket = PassedclientSocket; } // process the commands in a separete thread public void run() { int intLastCommand; // last command issued String strTo; Vector vPlugIns; // all known plugins Vector vActivePlugIns; // a plugin used to send this message int i; Vector vStarted; boolean bCleanExit; // did the client disconnect cleanly? - if not then the message is discarded String strFrom; // initilize variables intLastCommand = commands.none; vPlugIns = null; strTo = null; vStarted = null; vActivePlugIns = new Vector(); strFrom = null; // who the mail is from BrokerFactory.getLoggingBroker().logWarn("smtp - connection started"); bCleanExit = true; // assume a clean exit try { PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader( clientSocket.getInputStream())); String strIn; // make an instance of all the plugins vPlugIns = new Vector(); for (i = 0; i < SMTP.vNamesOfPlugIns.length; i++) { vPlugIns.addElement((Class.forName(SMTP.vNamesOfPlugIns[i])) .newInstance()); BrokerFactory.getLoggingBroker() .logWarn( "+++load " + SMTP.vNamesOfPlugIns[i]); } // i'm ready... intLastCommand = commands.none; out.println("220 - Reliable Response Notification mail server"); out.flush(); // proccess commands till a quit is issued while (intLastCommand != commands.quit) { try { // read the next command strIn = MyTimeout.TimedReadLine(in, 1000 * 60 * 3); // strIn = in.readLine(); BrokerFactory.getLoggingBroker().logWarn("----" + strIn); } catch (Exception e) { // if can't read then the client dropped so assume a quit strIn = "QUIT"; } // if read a null then drop the connecion since the client does not know what he's doing if (strIn == null) { strIn = "QUIT"; } // interpret the command if (strIn.toUpperCase().startsWith("HELO")) { // must start with hello - if not then the other guy is not talking to who he thinks he's talking to // now i'm ready for commands out.println("250 - calvin's mail server"); out.flush(); intLastCommand = commands.helo; } else if (strIn.toUpperCase().startsWith("RSET")) { if (intLastCommand != commands.none) { // start over vActivePlugIns = new Vector(); // reset the list of people to send mail to // back to the hello command intLastCommand = commands.helo; // ready to go out.println("250 - reliable response mail server"); out.flush(); } else { out.println("503 - rset not allowed here"); out.flush(); } } else if (strIn.toUpperCase().startsWith("MAIL FROM")) { // anyone can send us mail - should do a check somewhere that only allows non-local mail // to come from a valid user if (intLastCommand == commands.helo) { out.println("250 - ok"); out.flush(); // store who the mail is from strFrom = GrabAddress(strIn.substring(10, strIn .length())); intLastCommand = commands.mailfrom; BrokerFactory.getLoggingBroker().logWarn( "smtp.process.-- MailFrom: " + strFrom); } else { out.println("503 - mail from not allowed here"); out.flush(); } } else if (strIn.toUpperCase().startsWith("RCPT TO")) { if ((intLastCommand == commands.mailfrom) || (intLastCommand == commands.rcptto)) { strTo = GrabAddress(strIn.substring(8, strIn.length())); BrokerFactory.getLoggingBroker().logWarn( "+++plugin.size: " + vPlugIns.size()); // check if mail can be sent to the person, strip off the command first for (i = 0; i < vPlugIns.size(); i++) { BrokerFactory.getLoggingBroker().logWarn( "+++i: " + i); // check if mail can be sent from the user if (((MailHandler) vPlugIns.elementAt(i)) .CheckFromUser(strFrom) == true) if (((MailHandler) vPlugIns.elementAt(i)) .CheckToUser(strTo) == true) { MailHandler mh = (MailHandler) vPlugIns .elementAt(i).getClass() .newInstance(); // add this plugin to the active plug-in list vActivePlugIns.addElement(mh); // since a new plugin was created let it also do a check mh.CheckFromUser(strFrom); mh.CheckToUser(strTo); } } // check if any plugin wants the mail if (vActivePlugIns.size() != 0) { out.println("250 - ok"); intLastCommand = commands.rcptto; BrokerFactory.getLoggingBroker().logWarn( "mail can be sent"); } else { // user is unknown - since not plugin could handle it out.println("550 - no such user"); BrokerFactory.getLoggingBroker().logWarn( "no such user"); } out.flush(); } else { out.println("503 - rcpt to not allowed here"); out.flush(); } } else if (strIn.toUpperCase().startsWith("DATA")) { if (intLastCommand == commands.rcptto) { vStarted = new Vector(); for (i = 0; i < vActivePlugIns.size(); i++) { if (((MailHandler) vActivePlugIns.elementAt(i)) .Start()) { vStarted.addElement(new Integer(i)); } } if (vStarted.size() > 0) { out.println("354 - send the mail"); out.flush(); intLastCommand = commands.data; strIn = MyTimeout.TimedReadLine(in, 1000 * 60 * 3); // strIn = in.readLine(); // while(!strIn.startsWith(".")) while (!strIn.equals(".")) { for (i = 0; i < vStarted.size(); i++) ((MailHandler) vActivePlugIns .elementAt(((Integer) vStarted .elementAt(i)).intValue())) .Line(strIn); strIn = MyTimeout.TimedReadLine(in, 1000 * 60 * 3); // strIn = in.readLine(); } for (i = 0; i < vStarted.size(); i++) try { ((MailHandler) vActivePlugIns .elementAt(((Integer) vStarted .elementAt(i)).intValue())) .End(); } catch (Exception e) { BrokerFactory.getLoggingBroker().logError(e); } out.println("250 - ok"); out.flush(); intLastCommand = commands.datafinished; } else { out.println("550 - no plug in could start"); out.flush(); } } else { out.println("503 - data not allowed here"); out.flush(); } } else if (strIn.startsWith("NOOP")) { // just a check to see if were still here - which we are // outlook does not use this but this spec says it's a // requirment for a simple smpt server - so it's here // however this is untested if (intLastCommand != commands.none) { out.println("250 - ok"); out.flush(); } else { out.println("503 - noop not allowed here"); out.flush(); } } else if (strIn.toUpperCase().startsWith("QUIT")) { intLastCommand = commands.quit; } // left as comment so other commands can be added later // else if(strIn.startsWith("")) // { // } else { out.println("502 - unknown command"); out.flush(); } } } catch (Exception e) { e.printStackTrace(); // on any exception the message is over // if the last command is not datafinished then the message is thrown away // this is since some programs don't send the quit command instead they // just quit ex. qsmtp.java if (intLastCommand == commands.datafinished) { BrokerFactory.getLoggingBroker() .logWarn("error - message kept"); } else { BrokerFactory.getLoggingBroker().logWarn( "error - message deleted"); bCleanExit = false; // something went wrong } } finally { // always close the socket try { clientSocket.close(); // tell everyone the connection was closed for (i = 0; i < vActivePlugIns.size(); i++) ((MailHandler) vActivePlugIns.elementAt(i)) .ConnectionClosed(bCleanExit); } catch (IOException e) { // ignore it since can't do anything about it } } BrokerFactory.getLoggingBroker().logWarn( "smtp - connection finished - awaiting next"); } // // private internal stuff // // parse the to command and strip out the user name private String GrabAddress(String strToCmd) { String strAddress; strAddress = strToCmd; if (strAddress == null) strAddress = ""; int intFoundStart; int intFoundEnd; // kill white space strToCmd = strToCmd.trim(); // check if the address contains a < if so then just use whats inside // otherwise use the address given intFoundStart = strToCmd.indexOf('<'); if (intFoundStart != -1) { // found it strip everything from inside intFoundEnd = strToCmd.indexOf('>'); if (intFoundEnd != -1) { strAddress = strToCmd.substring(intFoundStart + 1, intFoundEnd); } else { strAddress = strToCmd.substring(intFoundStart + 1, strToCmd .length()); } } else { // not found - use as is strAddress = strToCmd; } return strAddress; } }