package jetbrains.buildServer.deployer.agent.ssh;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.OpenSSHConfig;
import com.jcraft.jsch.Session;
import jetbrains.buildServer.agent.BuildRunnerContext;
import jetbrains.buildServer.agent.InternalPropertiesHolder;
import jetbrains.buildServer.deployer.common.DeployerRunnerConstants;
import jetbrains.buildServer.deployer.common.SSHRunnerConstants;
import jetbrains.buildServer.util.StringUtil;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;


public class SSHSessionProvider {

    public static final String TEAMCITY_DEPLOYER_SSH_CONFIG_PATH = "teamcity.deployer.ssh.config.path";
    public static final String TEAMCITY_DEPLOYER_SSH_DEFAULT_KEY = "teamcity.deployer.ssh.default.key";

    private Session mySession;
    private String myHost;
    private int myPort;
    private String myRemotePath;


    public SSHSessionProvider(@NotNull final BuildRunnerContext context, @NotNull final InternalPropertiesHolder holder) throws JSchException {

        final String target = context.getRunnerParameters().get(DeployerRunnerConstants.PARAM_TARGET_URL);
        final String portStr = context.getRunnerParameters().get(SSHRunnerConstants.PARAM_PORT);
        try {
            myPort = Integer.parseInt(portStr);
        } catch (NumberFormatException e) {
            myPort = 22;
        }

        final int delimiterIndex = target.indexOf(':');
        if (delimiterIndex > 0) {
            myHost = target.substring(0, delimiterIndex);
            final String remotePath = target.substring(delimiterIndex + 1);

            myRemotePath = remotePath.trim().replaceAll("\\\\", "/");
            if (new File(myRemotePath).isAbsolute() && !myRemotePath.startsWith("/")) {
                myRemotePath = "/" + myRemotePath;
            }
        } else {
            myHost = target;
            myRemotePath = "";
        }

        final String username = context.getRunnerParameters().get(DeployerRunnerConstants.PARAM_USERNAME);
        final String password = context.getRunnerParameters().get(DeployerRunnerConstants.PARAM_PASSWORD);
        final String authMethod = context.getRunnerParameters().get(SSHRunnerConstants.PARAM_AUTH_METHOD);

        JSch jsch=new JSch();
        JSch.setConfig("StrictHostKeyChecking", "no");

        if (SSHRunnerConstants.AUTH_METHOD_DEFAULT_KEY.equals(authMethod)) {
            final String configPath = holder.getInternalProperty(TEAMCITY_DEPLOYER_SSH_CONFIG_PATH, System.getProperty("user.home") + File.separator + ".ssh" + File.separator + "config");
            //noinspection ConstantConditions
            final File config = new File(configPath);
            if (config.exists()) {
                iniSessionSSHConfig(jsch, config);
            } else {
                final String keyPath = holder.getInternalProperty(TEAMCITY_DEPLOYER_SSH_DEFAULT_KEY, System.getProperty("user.home") + File.separator + ".ssh" + File.separator + "id_rsa");
                //noinspection ConstantConditions
                final File keyFile = new File(keyPath);
                initSessionKeyFile(username, password, keyFile, jsch);
            }
        } else if (SSHRunnerConstants.AUTH_METHOD_CUSTOM_KEY.equals(authMethod)) {
            final String keyFilePath = context.getRunnerParameters().get(SSHRunnerConstants.PARAM_KEYFILE);
            final File keyFile = new File(context.getBuild().getCheckoutDirectory(), keyFilePath);
            initSessionKeyFile(username, password, keyFile, jsch);
        } else {
            initSessionUserPassword(username, password, jsch);
        }

        mySession.connect();
    }

    private void iniSessionSSHConfig(JSch jsch, File config) throws JSchException {
        try {
            final OpenSSHConfig sshConfig = OpenSSHConfig.parseFile(config.getCanonicalPath());
            jsch.setConfigRepository(sshConfig);
            mySession = jsch.getSession(myHost);
        } catch (IOException e) {
            throw new JSchException("Error parsing ssh config file", e);
        }
    }

    private void initSessionUserPassword(String username, String password, JSch jsch) throws JSchException {
        mySession = jsch.getSession(username, myHost, myPort);
        mySession.setPassword(password);
    }

    private void initSessionKeyFile(String username, String password, File keyFile, JSch jsch) throws JSchException {
        try {
            if (StringUtil.isNotEmpty(password)) {
                jsch.addIdentity(keyFile.getCanonicalPath(), password);
            } else {
                jsch.addIdentity(keyFile.getCanonicalPath());
            }
            mySession = jsch.getSession(username, myHost, myPort);
        } catch (IOException e) {
            throw new JSchException("Failed to use key file", e);
        }
    }

    public String getRemotePath() {
        return myRemotePath;
    }

    public Session getSession() {
        return mySession;
    }

    public String getSessionString() {
        return  (StringUtil.isNotEmpty(myRemotePath) ? "[" + myRemotePath + "] on " : "") + "host [" + myHost + ":" + myPort + "]";
    }

}

@@ -71,120 +71,9 @@
 sch.
-JSch;%0Aimport com.jcraft.jsch.JSchException;%0Aimport com.jcraft.jsch.OpenSSHConfig;%0Aimport com.jcraft.jsch.Session
+*
 ;%0Aim
@@ -367,16 +367,48 @@
 ngUtil;%0A
+import org.apache.log4j.Logger;%0A
 import o
@@ -737,16 +737,85 @@
 .key%22;%0A%0A
+    private final Logger myLog = Logger.getLogger(this.getClass());%0A%0A
     priv
@@ -2354,24 +2354,74 @@
 g%22, %22no%22);%0A%0A
+        myLog.debug(%22Initializing ssh session.%22);%0A
         if (
@@ -2804,24 +2804,117 @@
 exists()) %7B%0A
+                myLog.debug(%22Found config at %5B%22 + config.getAbsolutePath() + %22%5D, reading.%22);%0A
             
@@ -2916,24 +2916,25 @@
          ini
+t
 SessionSSHCo
@@ -3265,24 +3265,116 @@
 e(keyPath);%0A
+                myLog.debug(%22Using keyfile at %5B%22 + keyFile.getAbsolutePath() + %22%5D, load.%22);%0A
             
@@ -3732,24 +3732,112 @@
 yFilePath);%0A
+            myLog.debug(%22Using keyfile at %5B%22 + keyFile.getAbsolutePath() + %22%5D, load.%22);%0A
             
@@ -3900,32 +3900,93 @@
        %7D else %7B%0A
+            myLog.debug(%22Using provided username/password%22);%0A
             init
@@ -4071,32 +4071,32 @@
 nnect();%0A    %7D%0A%0A
-
     private void
@@ -4099,16 +4099,17 @@
 void ini
+t
 SessionS

improve logging, fix typo