/*
 *  SSHTools - Java SSH2 API
 *
 *  Copyright (C) 2002-2003 Lee David Painter and Contributors.
 *
 *  Contributions made by:
 *
 *  Brett Smith
 *  Richard Pernavas
 *  Erwin Bolwidt
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package com.sshtools.common.hosts;

import com.sshtools.j2ssh.transport.AbstractKnownHostsKeyVerification;
import com.sshtools.j2ssh.transport.InvalidHostFileException;
import com.sshtools.j2ssh.transport.TransportProtocolException;
import com.sshtools.j2ssh.transport.publickey.SshPublicKey;

import java.awt.Component;

import java.io.File;

import java.lang.reflect.InvocationTargetException;

import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;


/**
 *
 *
 * @author $author$
 * @version $Revision: 1.13 $
 */
public class DialogKnownHostsKeyVerification
    extends AbstractKnownHostsKeyVerification {
    Component parent;
    private boolean verificationEnabled = true;

    /**
* Creates a new DialogKnownHostsKeyVerification object.
*
* @param parent
*
* @throws InvalidHostFileException
*/
    public DialogKnownHostsKeyVerification(Component parent)
        throws InvalidHostFileException {
        super(new File(System.getProperty("user.home"),
                ".ssh" + File.separator + "known_hosts").getAbsolutePath());
        this.parent = parent;
    }

    /**
* Creates a new DialogKnownHostsKeyVerification object.
*
* @param parent
* @param hostFileName
*
* @throws InvalidHostFileException
*/
    public DialogKnownHostsKeyVerification(Component parent, String hostFileName)
        throws InvalidHostFileException {
        super(hostFileName);
        this.parent = parent;
    }

    /**
*
*
* @param enabled
*/
    public void setVerificationEnabled(boolean enabled) {
        this.verificationEnabled = verificationEnabled;
    }

    /**
*
*
* @param host
*
* @throws TransportProtocolException
*/
    public void onDeniedHost(final String host)
        throws TransportProtocolException {
        // Show a message to the user to inform them that the host
        // is denied
        try {
            if (verificationEnabled) {
                SwingUtilities.invokeAndWait(new Runnable() {
                        public void run() {
                            JOptionPane.showMessageDialog(parent,
                                "Access to '" + host + "' is denied.\n" +
                                "Verify the access granted/denied in the allowed hosts file.",
                                "Remote Host Authentication",
                                JOptionPane.ERROR_MESSAGE);
                        }
                    });
            }
        } catch (InvocationTargetException ite) {
            throw new TransportProtocolException("Invocation Exception: " +
                ite.getMessage());
        } catch (InterruptedException ie) {
            throw new TransportProtocolException(
                "SwingUtilities thread interrupted!");
        }
    }

    /**
*
*
* @param host
* @param recorded
* @param actual
*
* @throws TransportProtocolException
*/
    public void onHostKeyMismatch(final String host,
        final SshPublicKey recorded, final SshPublicKey actual)
        throws TransportProtocolException {
        try {
            if (verificationEnabled) {
                SwingUtilities.invokeAndWait(new Runnable() {
                        public void run() {
                            Object[] options = getOptions();
                            int res = JOptionPane.showOptionDialog(parent,
                                    "The host '" + host +
                                    "' has provided a different host key.\nThe host key" +
                                    " fingerprint provided is '" +
                                    actual.getFingerprint() + "'.\n" +
                                    "The allowed host key fingerprint is " +
                                    recorded.getFingerprint() +
                                    ".\nDo you want to allow this host?",
                                    "Remote host authentication",
                                    JOptionPane.YES_NO_CANCEL_OPTION,
                                    JOptionPane.QUESTION_MESSAGE, null,
                                    options, options[0]);

                            try {
                                // Handle the reply
                                if ((options.length == 3) && (res == 0)) {
                                    // Always allow the host with the new fingerprint
                                    allowHost(host, actual, true);
                                } else if (((options.length == 2) &&
                                        (res == 0)) ||
                                        ((options.length == 3) && (res == 1))) {
                                    // Only allow the host this once
                                    allowHost(host, actual, false);
                                }
                            } catch (InvalidHostFileException e) {
                                showExceptionMessage(e);
                            }
                        }
                    });
            }
        } catch (InvocationTargetException ite) {
            throw new TransportProtocolException("Invocation Exception: " +
                ite.getMessage());
        } catch (InterruptedException ie) {
            throw new TransportProtocolException(
                "SwingUtilities thread interrupted!");
        }
    }

    /**
*
*
* @param host
* @param key
*
* @throws TransportProtocolException
*/
    public void onUnknownHost(final String host, final SshPublicKey key)
        throws TransportProtocolException {
        // Set up the users options. Only allow always if we can
        // write to the hosts file
        try {
            if (verificationEnabled) {
                SwingUtilities.invokeAndWait(new Runnable() {
                        public void run() {
                            Object[] options = getOptions();
                            int res = JOptionPane.showOptionDialog(parent,
                                    "The host '" + host +
                                    "' is unknown. The host key" +
                                    " fingerprint is\n'" +
                                    key.getFingerprint() +
                                    "'.\nDo you want to allow this host?",
                                    "Remote host authentication",
                                    JOptionPane.YES_NO_CANCEL_OPTION,
                                    JOptionPane.QUESTION_MESSAGE, null,
                                    options, options[0]);

                            try {
                                // Handle the reply
                                if ((options.length == 3) && (res == 0)) {
                                    // Always allow the host with the new fingerprint
                                    allowHost(host, key, true);
                                } else if (((options.length == 2) &&
                                        (res == 0)) ||
                                        ((options.length == 3) && (res == 1))) {
                                    // Only allow the host this once
                                    allowHost(host, key, false);
                                }
                            } catch (InvalidHostFileException e) {
                                showExceptionMessage(e);
                            }
                        }
                    });
            }
        } catch (InvocationTargetException ite) {
            throw new TransportProtocolException("Invocation Exception: " +
                ite.getMessage());
        } catch (InterruptedException ie) {
            throw new TransportProtocolException(
                "SwingUtilities thread interrupted!");
        }
    }

    private String[] getOptions() {
        return isHostFileWriteable() ? new String[] { "Always", "Yes", "No" }
                                     : new String[] { "Yes", "No" };
    }

    private void showExceptionMessage(Exception e) {
        JOptionPane.showMessageDialog(parent,
            "An unexpected error occured!\n\n" + e.getMessage(),
            "Host Verification", JOptionPane.ERROR_MESSAGE);
    }
}
