/**
   * Determines whether a vaild session exists for the contact of remote machine.
   *
   * @param sshContact ID of SSH Contact
   * @return <tt>true</tt> if the session is connected <tt>false</tt> otherwise
   */
  public boolean isSessionValid(ContactSSH sshContact) {
    Session sshSession = sshContact.getSSHSession();
    if (sshSession != null) if (sshSession.isConnected()) return true;

    // remove reference to an unconnected SSH Session, if any
    sshContact.setSSHSession(null);
    return false;
  }
  /**
   * Creates a shell channel to the remote machine a new jsch session is also created if the current
   * one is invalid
   *
   * @param sshContact the contact of the remote machine
   * @param firstMessage the first message
   */
  public void connectShell(final ContactSSH sshContact, final Message firstMessage) {
    sshContact.setConnectionInProgress(true);

    final UIService uiService = this.uiService;

    final Thread newConnection =
        new Thread(
            (new Runnable() {
              public void run() {
                OperationSetPersistentPresenceSSHImpl persistentPresence =
                    (OperationSetPersistentPresenceSSHImpl)
                        sshContact.getParentPresenceOperationSet();

                persistentPresence.changeContactPresenceStatus(
                    sshContact, SSHStatusEnum.CONNECTING);

                try {
                  if (!isSessionValid(sshContact)) createSSHSessionAndLogin(sshContact);

                  createShellChannel(sshContact);

                  // initalizing the reader and writers of ssh contact

                  persistentPresence.changeContactPresenceStatus(
                      sshContact, SSHStatusEnum.CONNECTED);

                  showWelcomeMessage(sshContact);

                  sshContact.setMessageType(sshContact.CONVERSATION_MESSAGE_RECEIVED);

                  sshContact.setConnectionInProgress(false);

                  Thread.sleep(1500);

                  sshContact.setCommandSent(true);

                  basicInstantMessaging.sendInstantMessage(sshContact, firstMessage);
                }
                // rigoruos Exception Checking in future
                catch (Exception ex) {
                  persistentPresence.changeContactPresenceStatus(
                      sshContact, SSHStatusEnum.NOT_AVAILABLE);

                  ex.printStackTrace();
                } finally {
                  sshContact.setConnectionInProgress(false);
                }
              }
            }));

    newConnection.start();
  }
  /**
   * Determines whether the contact is connected to shell of remote machine as a precheck for any
   * further operation
   *
   * @param sshContact ID of SSH Contact
   * @return <tt>true</tt> if the contact is connected <tt>false</tt> if the contact is not
   *     connected
   */
  public boolean isShellConnected(ContactSSH sshContact) {
    // a test command may also be run here

    if (isSessionValid(sshContact)) {
      return (sshContact.getShellChannel() != null);
    }

    /*
     * Above should be return(sshContact.getShellChannel() != null
     *                     && sshContact.getShellChannel().isConnected());
     *
     * but incorrect reply from stack for isConnected()
     */

    return false;
  }
  /**
   * Creates a channel for shell type in the current session channel types = shell, sftp, exec(X
   * forwarding), direct-tcpip(stream forwarding) etc
   *
   * @param sshContact ID of SSH Contact
   */
  public void createShellChannel(ContactSSH sshContact) throws IOException {
    try {
      Channel shellChannel = sshContact.getSSHSession().openChannel("shell");

      // initalizing the reader and writers of ssh contact
      sshContact.initializeShellIO(shellChannel.getInputStream(), shellChannel.getOutputStream());

      ((ChannelShell) shellChannel)
          .setPtyType(sshContact.getSSHConfigurationForm().getTerminalType());

      // initializing the shell
      shellChannel.connect(1000);

      sshContact.setShellChannel(shellChannel);

      sshContact.sendLine("export PS1=");
    } catch (JSchException ex) {
      sshContact.setSSHSession(null);
      throw new IOException("Unable to create shell channel to remote" + " server");
    }
  }
 /**
  * Closes the SSH Session associated with the contact
  *
  * @param sshContact ID of SSH Contact
  */
 void closeSSHSession(ContactSSH sshContact) {
   sshContact.getSSHSession().disconnect();
   sshContact.setSSHSession(null);
 }
  /**
   * Creates a SSH Session with a remote machine and tries to login according to the details
   * specified by Contact An appropriate message is shown to the end user in case the login fails
   *
   * @param sshContact ID of SSH Contact
   * @throws JSchException if a JSch is unable to create a SSH Session with the remote machine
   * @throws InterruptedException if the thread is interrupted before session connected or is timed
   *     out
   * @throws OperationFailedException if not of above reasons :-)
   */
  public void createSSHSessionAndLogin(ContactSSH sshContact)
      throws JSchException, OperationFailedException, InterruptedException {
    logger.info("Creating a new SSH Session to " + sshContact.getHostName());

    // creating a new JSch Stack identifier for contact
    JSch jsch = new JSch();

    String knownHosts = (String) accountID.getAccountProperties().get("KNOWN_HOSTS_FILE");

    if (!knownHosts.equals("Optional")) jsch.setKnownHosts(knownHosts);

    String identitiyKey = (String) accountID.getAccountProperties().get("IDENTITY_FILE");

    String userName = sshContact.getUserName();

    // use the name of system user if the contact has not supplied SSH
    // details
    if (userName.equals("")) userName = System.getProperty("user.name");

    if (!identitiyKey.equals("Optional")) jsch.addIdentity(identitiyKey);

    // creating a new session for the contact
    Session session =
        jsch.getSession(
            userName, sshContact.getHostName(), sshContact.getSSHConfigurationForm().getPort());

    /**
     * Creating and associating User Info with the session User Info passes authentication from
     * sshContact to SSH Stack
     */
    SSHUserInfo sshUserInfo = new SSHUserInfo(sshContact);

    session.setUserInfo(sshUserInfo);

    /** initializing the session */
    session.connect(connectionTimeout);

    int count = 0;

    // wait for session to get connected
    while (!session.isConnected() && count <= 30000) {
      Thread.sleep(1000);
      count += 1000;
      logger.trace("SSH:" + sshContact.getHostName() + ": Sleep zzz .. ");
    }

    // if timeout have exceeded
    if (count > 30000) {
      sshContact.setSSHSession(null);
      JOptionPane.showMessageDialog(
          null, "SSH Connection attempt to " + sshContact.getHostName() + " timed out");

      // error codes are not defined yet
      throw new OperationFailedException(
          "SSH Connection attempt to " + sshContact.getHostName() + " timed out", 2);
    }

    sshContact.setJSch(jsch);
    sshContact.setSSHSession(session);

    logger.info("A new SSH Session to " + sshContact.getHostName() + " Created");
  }
 /**
  * Closes the Shell channel are associated IO Streams
  *
  * @param sshContact ID of SSH Contact
  */
 public void closeShellChannel(ContactSSH sshContact) throws JSchException, IOException {
   sshContact.closeShellIO();
   sshContact.getShellChannel().disconnect();
   sshContact.setShellChannel(null);
 }