/*
 * @(#)ImapSsh.java
 *
 * Copyright (c) 2003 JSCAPE
 * 1147 S. 53rd Pl., Mesa, Arizona, 85206, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * JSCAPE. ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with
 * the terms of the license agreement you entered into with JSCAPE.
 */
package com.jscape.inet.imapssh;

import com.jscape.inet.imap.Imap;
import com.jscape.inet.imap.ImapException;
import com.jscape.inet.ipclientssh.IpClientSsh;
import com.jscape.inet.ssh.util.SshParameters;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;

/**
 * Implements the basic functionality of a IMAP client tunnelling data through a secure SSH connection.
 * <p/>
 * Example Usage:
 * <p/>
 * <pre>
 * // connection information for SSH server
 * String sshHostname = "imap4.myserver.com";
 * String sshUsername = "jsmith";
 * String sshPassword = "secret";
 *
 * // create new SshParameters instance
 * SshParameters sshParams = new SshParameters(sshHostname,sshUsername,sshPassword);
 *
 * // new instance with SSH parameters hostname, username and password
 * ImapSsh imap = new ImapSsh(sshParams,"imap4.myserver.com","jsmith","secret");
 * try {
 *   // connect to IMAP4 server
 *   imap.connect();
 *
 *   // get messages
 *   int messageCount = imap.getMessageCount();
 *   for(int i = 1; i <= messageCount(); ++i) {
 *     EmailMessage em = imap.getMessage(i);
 *   }
 *
 *   // disconnect
 *   imap.disconnect();
 * }
 * catch(Exception e) {
 *   System.out.println(e);
 * }
 * </pre>
 */
public class ImapSsh
        extends Imap {

    private SshParameters sshParameters;
    private IpClientSsh sshClient;

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

    /**
     * Creates a new ImapSsh instance.
     *
     * @param hostname the IMAP hostname
     * @param username the IMAP username
     * @param password the IMAP password
     */
    public ImapSsh(String hostname, String username, String password) {
        super(hostname, username, password);
    }

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

    /**
     * Connects to IMAP server tunelling data through SSH server and performs login with IMAP server.
     *
     * @throws ImapException if I/O or IMAP related error occurs
     */
    public ImapSsh connect()
            throws ImapException {
        try {
            sshClient = new IpClientSsh(sshParameters, hostname, port, timeout);
            sshClient.connect();

            in =
                    new BufferedInputStream(sshClient.getInputStream());
            out =
                    new BufferedOutputStream(sshClient.getOutputStream());

            // notify that client has connected
            fireImapConnected(hostname);

            // get IMAP banner
            String banner = readLine(in);
            debug(banner);

            this.authentication.apply(this);

            issueCommand("SELECT INBOX");
            currentMailbox = "INBOX";

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

    /**
     * Disconnects from IMAP server. Issues CLOSE and LOGOUT commands to IMAP server and closes connection with SSH server.
     *
     * @throws ImapException if I/O or IMAP related error occurs
     */
    public void disconnect()
            throws ImapException {
        try {
            synchronized (this) {
                issueCommand("CLOSE");
                issueCommand("LOGOUT");
                sshClient.disconnect();
            }
        } catch (NullPointerException npe) {
            throw new ImapException("IMAP client already disconnected");
        } catch (Exception e) {
            throw new ImapException(e.getMessage(), e);
        } finally {
            out = null;
            in = null;
            this.fireImapDisconnected(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;
    }
}
