package noriega.expresso.protocols; import java.net.*; import java.util.*; import java.io.*; import java.rmi.*; import noriega.expresso.server.*; import noriega.expresso.structures.*; import noriega.util.*; /* * Copyright (c) 1999 Noriega * * $Author: jew23 $ * $Date: 1999/04/12 00:33:31 $ * $Id: SmtpServiceImpl.java,v 1.13 1999/04/12 00:33:31 jew23 Exp $ */ /** *
* This is an implementation of the * Simple Mail Transfer Protocol as * described by RFC 821. * * @author $Author: jew23 $ * Date: $Date: 1999/04/12 00:33:31 $ */ public class SmtpServiceImpl extends DefaultServiceImpl implements SmtpService { // ------------ FIELDS ------------ static final String EOL = "\r\n"; protected BufferedReader reply = null; protected PrintStream send = null; protected Socket sock = null; // -------- CONSTRUCTOR -------- /** * Create an smtp object. * @exception RemoteException * */ public SmtpServiceImpl() throws RemoteException, ExpressoServerException { super(); } // ------------ METHODS ------------ /** *
* Connect to the specified host to send mail. *
** The default hostname and port for connection * are loaded from ExpressoConstants. *
** Initiate socket connection and check to * make sure that SMTP service is available on specified host * by making sure to receive an SMTP 220 (Service Available). *
** Issue HELO command to let server know we have mail to send. *
* @exception RemoteException * @exception java.net.UnknownHostException * @exception IOException */ public void connect() throws RemoteException, java.net.UnknownHostException, IOException { connect(ExpressoConstants.SMTP_DEFAULT_HOST, ExpressoConstants.SMTP_DEFAULT_PORT); } /** ** Connect to the specified host to send mail. *
** @param host SMTP hostname to connect to *
** Initiate socket connection and check to * make sure that SMTP service is available on specified host * by making sure to receive an SMTP 220 (Service Available). *
** Issue HELO command to let server know we have mail to send. *
* @exception RemoteException * @exception java.net.UnknownHostException * @exception IOException */ public void connect( String host) throws RemoteException, java.net.UnknownHostException, IOException { connect (host, ExpressoConstants.SMTP_DEFAULT_PORT); } /** ** Connect to the specified host to send mail. *
** @param host SMTP hostname to connect to * @param port Port to connect to on host *
** Initiate socket connection and check to * make sure that SMTP service is available on specified host * by making sure to receive an SMTP 220 (Service Available). *
** Issue HELO command to let server know we have mail to send. *
* @exception RemoteException * @exception java.net.UnknownHostException * @exception IOException */ public void connect( String host, int port) throws RemoteException, java.net.UnknownHostException, IOException { sock = new Socket( host, port ); reply= new BufferedReader(new InputStreamReader(sock.getInputStream())); send = new PrintStream( sock.getOutputStream() ); String rstr = reply.readLine(); // On successful connection to server, // 220 Service Available if (!rstr.startsWith("220")) throw new ProtocolException(rstr); while (rstr.indexOf('-') == 3) { rstr = reply.readLine(); if (!rstr.startsWith("220")) throw new ProtocolException(rstr); } // If connection is made, sender identifies itself // HELO localhost InetAddress local; try { local = InetAddress.getLocalHost(); } catch (java.net.UnknownHostException ioe) { System.err.println("No local IP address found - is your network up?"); throw ioe; } String localHost = local.getHostName(); send.print("HELO " + localHost); send.print(EOL); send.flush(); // Server should respond // 250 OK rstr = reply.readLine(); if (!rstr.startsWith("250")) throw new ProtocolException(rstr); } /** ** Connect to the specified host to send mail. *
** @param InetAddress SMTP IP address to connect to * @param port Port to connect to on host *
** Initiate socket connection and check to * make sure that SMTP service is available on specified host * by making sure to receive an SMTP 220 (Service Available). *
** Issue HELO command to let server know we have mail to send. *
* @exception RemoteException * @exception IOException */ public void connect( InetAddress address ) throws RemoteException, IOException { connect (address, ExpressoConstants.SMTP_DEFAULT_PORT); } /** ** Connect to the specified host to send mail. *
** @param InetAddress SMTP hostname to connect to * @param port Port to connect to on host *
** Initiate socket connection and check to * make sure that SMTP service is available on specified host * by making sure to receive an SMTP 220 (Service Available). *
** Issue HELO command to let server know we have mail to send. *
* @exception RemoteException * @exception IOException */ public void connect( InetAddress address, int port ) throws RemoteException, IOException { sock = new Socket( address, port ); reply= new BufferedReader(new InputStreamReader(sock.getInputStream())); send = new PrintStream( sock.getOutputStream() ); String rstr = reply.readLine(); // On successful connection to server, // 220 Service Available if (!rstr.startsWith("220")) throw new ProtocolException(rstr); while (rstr.indexOf('-') == 3) { rstr = reply.readLine(); if (!rstr.startsWith("220")) throw new ProtocolException(rstr); } // If connection is made, sender identifies itself // HELO localhost InetAddress local; try { local = InetAddress.getLocalHost(); } catch (java.net.UnknownHostException ioe) { System.err.println("No local IP address found - is your network up?"); throw ioe; } String host = local.getHostName(); send.print("HELO " + host); send.print(EOL); send.flush(); // Server should respond // 250 OK rstr = reply.readLine(); if (!rstr.startsWith("250")) throw new ProtocolException(rstr); } /** ** Send mail messages. * @param message The email message. * * @exception RemoteException * @exception ProtocolException * @exception IOException *
* Issue standard SMTP commands (see comments below for * outline or RFC821 for details). *
* SMTP server accepts command with 250 reply. *
*/ public void sendmsg(Message message) throws RemoteException, ExpressoServerException { ServerDataLayer smtpSDL = getServerDataLayer(); try { sendmsg(message.getHeader(), message.getBody() ); smtpSDL.addToOutbox(getUsername(), message); } catch( Exception e) { e.printStackTrace(); throw new ExpressoServerException(e.getMessage() ); } } /** ** Send mail messages. * @param header The email header. * @param body The email body. * * @exception RemoteException * @exception ProtocolException * @exception IOException *
* Issue standard SMTP commands (see comments below for * outline or RFC821 for details). *
* SMTP server accepts command with 250 reply. *
*/ public void sendmsg(Header header, String body) throws RemoteException, ProtocolException, IOException { EmailAddress from = header.getFrom(); EmailAddress to = header.getTo(); sendmsg(from.toString(), to.toString(), header.getSubject(), body); } /** ** Send mail messages. * @param from_address The sender's email address. * @param to_address The intended recipient's email address. * @param subject The email subject. * @param message The email body. * * @exception RemoteException * @exception ProtocolException * @exception IOException *
* Issue standard SMTP commands (see comments below for * outline or RFC821 for details). *
* SMTP server accepts command with 250 reply. *
*/ public void sendmsg( String from_address, String to_address, String subject, String message ) throws RemoteException, IOException, ProtocolException { String rstr; String sstr; // ---------------- SMTP NEGOTIATION ------------------- // MAIL command identifies originator, provides reverse path // for error reporting sstr = "MAIL FROM: " + from_address ; send.print(sstr); send.print(EOL); send.flush(); // Receiver accepts rstr = reply.readLine(); if (!rstr.startsWith("250")) throw new ProtocolException(rstr); // RCPT command identifies recipients sstr = "RCPT TO: " + to_address; send.print(sstr); send.print(EOL); send.flush(); //Receiver accepts rstr = reply.readLine(); if (!rstr.startsWith("250")) throw new ProtocolException(rstr); // ---------------- TRANSFER MAIL ------------------- // DATA command transfer message send.print("DATA"); send.print(EOL); send.flush(); // SMTP Server returns 354 - Start mail input rstr = reply.readLine(); if (!rstr.startsWith("354")) throw new ProtocolException(rstr); // Write Header send.print("From: " + from_address); send.print(EOL); send.print("To: " + to_address); send.print(EOL); send.print("Subject: " + subject); send.print(EOL); // Create Date Date today_date = new Date(); send.print("Date: " + msgDateFormat(today_date)); send.print(EOL); send.flush(); // Warn the world that Noriega is on the loose send.print("Comment: Unauthenticated sender"); send.print(EOL); send.print("X-Mailer: Noriega Smtp"); send.print(EOL); // End Header. send.print(EOL); // Now send the message send.print(message); send.print(EOL); // The famous DOT send.print("."); send.print(EOL); send.flush(); // Server accepts. rstr = reply.readLine(); if (!rstr.startsWith("250")) throw new ProtocolException(rstr); } /** ** Close connection to host. *
** Issue standard QUIT command * (See RFC821 for details). *
* SMTP server accepts command with 250 reply. *
*/ public void close() throws RemoteException { try { send.print("QUIT"); send.print(EOL); send.flush(); sock.close(); } catch (IOException ioe) { // Noah, I don't really care what happens here // do you ? We have our 250 :-) } } protected void finalize() throws RemoteException, Throwable { this.close(); super.finalize(); } private String msgDateFormat( Date senddate) { String formatted = "hold"; String Day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; String Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; formatted = Day[senddate.getDay()] + ", "; formatted = formatted + String.valueOf(senddate.getDate()) + " "; formatted = formatted + Month[senddate.getMonth()] + " "; if (senddate.getYear() > 99) formatted = formatted + String.valueOf(senddate.getYear() + 1900) + " "; else formatted = formatted + String.valueOf(senddate.getYear()) + " "; if (senddate.getHours() < 10) formatted = formatted + "0"; formatted = formatted + String.valueOf(senddate.getHours()) + ":"; if (senddate.getMinutes() < 10) formatted = formatted + "0"; formatted = formatted + String.valueOf(senddate.getMinutes()) + ":"; if (senddate.getSeconds() < 10) formatted = formatted + "0"; formatted = formatted + String.valueOf(senddate.getSeconds()) + " "; if (senddate.getTimezoneOffset() < 0) formatted = formatted + "+"; else formatted = formatted + "-"; if (Math.abs(senddate.getTimezoneOffset())/60 < 10) formatted = formatted + "0"; formatted = formatted + String.valueOf(Math.abs(senddate.getTimezoneOffset())/60); if (Math.abs(senddate.getTimezoneOffset())%60 < 10) formatted = formatted + "0"; formatted = formatted + String.valueOf(Math.abs(senddate.getTimezoneOffset())%60); return formatted; } public String getServiceName () throws RemoteException { return (ExpressoConstants.SMTP_SERVICE_NAME); } public String getServiceInfo () throws RemoteException { return ("Send Mail"); } } /* * Version Control Log: * $Log: SmtpServiceImpl.java,v $ * Revision 1.13 1999/04/12 00:33:31 jew23 * Javadoc finished. * * Revision 1.12 1999/04/11 18:51:25 jew23 * Javadoc finished. * * Revision 1.11 1999/04/11 17:57:38 ngreen * added connect() to remote interface also * * Revision 1.10 1999/04/11 17:44:45 jew23 * Using ExpressoConstants only. * * Revision 1.9 1999/04/11 17:42:20 jew23 * Added a no-parameter constructor. Sets default host and port to * ExpressoConstants. * * Revision 1.8 1999/04/11 17:38:47 ngreen * fixed send to outbox * * Revision 1.7 1999/04/07 19:31:35 ngreen * fixed initialization and other bugs * * Revision 1.6 1999/04/07 03:41:16 jew23 * Modified SMTP to append outgoing mail to IMAP Outbox folder. * * Revision 1.5 1999/04/05 22:10:17 ngreen * made service names into constants * * Revision 1.4 1999/04/03 18:18:57 ngreen * all are now with no-arg constructors, because that is what RMI requires. * All implement UsesServerDataLayer in order to set the SDL since it cannot * be set thru constructor. * As subclasses of DefaultServiceImpl (which implements UsesServerDataLayer), * the SDL can be accessed either by the "sdl" instance variable or the * getServerDataLayer() method. * * Revision 1.3 1999/04/03 16:24:05 ngreen * now conforms to new ExpressoService interface, as well as * new UsernameOriented interface * * Revision 1.2 1999/03/30 21:12:51 ngreen * fixed all compilation errors * * Revision 1.1 1999/03/30 15:49:04 jew23 * Added RMI implementation of SMTP. Removed old Smtp. * */