package com.jscape.inet.smtpssh;

import com.jscape.inet.ipclientssh.IpClientSsh;
import com.jscape.inet.smtp.Smtp;
import com.jscape.inet.smtp.SmtpException;
import com.jscape.inet.ssh.util.SshParameters;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * Implements the basic functionality of a SMTP client tunnelling all data through a secure SSH connection. <P>
 * Example Usage:
 * <p/>
 * <P>
 * <pre>
 * // connection parameters for SSH server
 * String sshHostname = "smtp.myserver.com";
 * String sshUsername = "jsmith";
 * String sshPassword = "secret";
 *
 * // create new SshParameters instance
 * SshParameters sshParams = new SshParameters(sshHostname,sshUsername,sshPassword);
 *
 * // create new instance
 * SmtpSsh smtp = new SmtpSsh(sshParams, "smtp.myserver.com");
 *  // address the message
 * EmailMessage message = new EmailMessage();
 * message.setTo("mjones@myserver.com");
 * message.setFrom("jsmith@myserver.com");
 * message.setSubject("Meeting today at 8");
 * message setBody("see you then");
 *  // connect, send the message, disconnect
 * try
 * {
 *   smtp.connect();
 *   smtp.send(message);
 *   smtp.disconnect();
 * }
 * catch(Exception e)
 * {
 *   System.out.println(e);
 * }
 * </pre>
 * </p>
 */
public class SmtpSsh
        extends Smtp {

    private SshParameters sshParameters;
    private IpClientSsh sshClient;

    /**
     * Creates a new SmtpSsh instance.
     *
     * @param hostname the SMTP server hostname
     */
    public SmtpSsh(String hostname) {
        super(hostname);
    }

    /**
     * Creates a new SmtpSsh instance.
     *
     * @param hostname      the SMTP server hostname
     * @param sshParameters the SSH parameters used in establishing secure connection
     */
    public SmtpSsh(SshParameters sshParameters, String hostname) {
        super(hostname);
        this.sshParameters = sshParameters;
    }

    /**
     * Creates a new SmtpSsh instance.
     */
    public SmtpSsh() {
        super();
    }

    /**
     * Connects to SMTP server tunnelling data through SSH server.
     *
     * @throws SmtpException thrown for I/O or SMTP related error
     */
    public SmtpSsh connect()
            throws SmtpException {
        try {
            sshClient = new IpClientSsh(sshParameters, hostname, port, timeout);
            sshClient.connect();

            in =
                    new BufferedReader(
                            new InputStreamReader(sshClient.getInputStream(), "8859_1"));
            out = new BufferedOutputStream(sshClient.getOutputStream());
            fireSmtpConnected(hostname);

            // read SMTP banner
            readResponse();

            // issue HELO command
            String ip = null;
            if ((heloAddress != null) && (heloAddress.trim().length() > 0)) {
                ip = heloAddress;
            } else {
                try {
                    ip = InetAddress.getLocalHost().getHostName();
                } catch (UnknownHostException uh) {
                    ip = "localhost";
                }
            }

            try {
                writeCommand(out, "EHLO " + ip);
                readResponse();
            } catch (Exception ez) {
                writeCommand(out, "HELO " + ip);
                readResponse();
            }

            return this;
        } catch (Exception e) {
            e.printStackTrace();
            throw new SmtpException(e.getMessage(), e);
        }
    }

    /**
     * Disconnects from SMTP and SSH servers.
     *
     * @throws SmtpException thrown to handle SMTP and I/O related errors
     * @see SmtpException
     */
    public void disconnect()
            throws SmtpException {
        synchronized (this) {
            try {
                if (out != null) {
                    writeCommand(out, "QUIT");
                    readResponse();
                    sshClient.disconnect();
                    out = null;
                    in = null;
                    connection = null;
                }
            } catch (Exception ioe) {
                throw new SmtpException(ioe.getMessage(), ioe);
            }
        }
        fireSmtpDisconnected(hostname);
    }

    /**
     * Gets SSH parameters used in establishing connection with SSH server.
     *
     * @return the SSH parameters
     *
     * @see com.jscape.inet.ssh.util.SshParameters
     */
    public SshParameters getSshParameters() {
        return sshParameters;
    }

    /**
     * Sets SSH parameters used in establishing connection with SSH server.
     *
     * @param parameters the SSH parameters
     *
     * @see com.jscape.inet.ssh.util.SshParameters
     */
    public void setSshParameters(SshParameters parameters) {
        sshParameters = parameters;
    }

}