Package com.adito.agent.client

Source Code of com.adito.agent.client.Agent$KeepAliveThread

/*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
     
package com.adito.agent.client;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import com.maverick.http.AuthenticationCancelledException;
import com.maverick.http.AuthenticationPrompt;
import com.maverick.http.GetMethod;
import com.maverick.http.HttpAuthenticator;
import com.maverick.http.HttpAuthenticatorFactory;
import com.maverick.http.HttpClient;
import com.maverick.http.HttpConnection;
import com.maverick.http.HttpException;
import com.maverick.http.HttpResponse;
import com.maverick.http.PasswordCredentials;
import com.maverick.http.URLDecoder;
import com.maverick.http.UnsupportedAuthenticationException;
import com.maverick.multiplex.MultiplexedConnection;
import com.maverick.multiplex.MultiplexedConnectionListener;
import com.maverick.multiplex.Request;
import com.maverick.multiplex.RequestHandler;
import com.maverick.ssl.SSLIOException;
import com.maverick.ssl.SSLTransportFactory;
import com.maverick.ssl.SSLTransportImpl;
import com.maverick.ssl.https.HttpsURLStreamHandlerFactory;
import com.maverick.util.ByteArrayReader;
import com.maverick.util.ByteArrayWriter;
import com.adito.agent.client.applications.ApplicationManager;
import com.adito.agent.client.networkplaces.NetworkPlaceManager;
import com.adito.agent.client.tunneling.DefaultTunnel;
import com.adito.agent.client.tunneling.LocalTunnelServer;
import com.adito.agent.client.tunneling.TunnelInactivityMonitor;
import com.adito.agent.client.tunneling.TunnelManager;
import com.adito.agent.client.util.BrowserLauncher;
import com.adito.agent.client.util.FileCleaner;
import com.adito.agent.client.util.IOStreamConnectorListener;
import com.adito.agent.client.util.TunnelConfiguration;
import com.adito.agent.client.util.URI;
import com.adito.agent.client.util.Utils;
import com.adito.agent.client.util.URI.MalformedURIException;
import com.adito.agent.client.webforwards.WebForwardManager;

/**
* Concrete implementation of an {@link AbstractVPNClient} that runs as
* standalone applicaiton launched from the Adito web interface (via the
* <i>Laumcher</i> applet.
* <p>
* See package description for more information.
*/
public class Agent implements RequestHandler, MultiplexedConnectionListener {
 
  /*
   * Replaced by build
   */
  public final static String AGENT_VERSION = "999.999.999";

  /** The hostname of the Adito proxy * */
  protected String aditoHostname;

  /** The port of the Adito proxy * */
  protected int aditoPort;
 
  /** Are we using a secure port? **/
  protected boolean isSecure = true;

  /** The username for this session * */
  protected String username;

  /** The VPN client ticket for an authenticated session * */
  protected String ticket;

  /** The hostname of the local HTTPS proxy server * */
  protected URI localProxyURL;

  /** We store all the available proxy information here * */
  protected static Hashtable proxiesIE = new Hashtable();

  /** We store all the local bypass addresses here * */
  protected static Vector proxyBypassIE = new Vector();

  protected static Hashtable proxiesFF = new Hashtable();

  protected static Vector proxyBypassFF = new Vector();

  /** HttpClient instances are cached * */

  protected AgentConfiguration agentConfiguration;

  protected String serverVersion;

  protected HttpClient client;

  protected String defaultProxyHost;

  protected int defaultProxyPort = 80;

  protected PasswordCredentials defaultProxyCredentials;

  protected String defaultProxyPreferredAuthentication;

  protected boolean autoDetectProxies = true;

  protected AuthenticationPrompt defaultProxyAuthenticationPrompt;

    protected AuthenticationPrompt defaultAuthenticationPrompt;

  protected int defaultProxyType = HttpClient.PROXY_HTTP;

  protected ApplicationManager applicationManager;

  protected TunnelManager tunnelManager;

  protected WebForwardManager webForwardManager;

  protected NetworkPlaceManager networkPlaceManager;

  boolean ticketIsPassword;
 
  // Public statics

  /**
   * Client is connected
   */
  public final static int STATE_CONNECTED = 1;

  /**
   * Client is disconnected
   */
  public final static int STATE_DISCONNECTED = 2;

  // Private instance variables

  private int currentState = STATE_DISCONNECTED;

  private TXRXMonitor txm;

  private AgentClientGUI gui;

  private Vector extensions = new Vector();

  private TunnelInactivityMonitor inactivityMonitor;

  private KeepAliveThread keepAlive;

  // Statics

  MultiplexedConnection con = null;

  HttpConnection httpConnection = null;

  public static final String SHUTDOWN_REQUEST = "shutdown";

  public static final String OPEN_URL_REQUEST = "openURL";

  public static final String MESSAGE_REQUEST = "agentMessage";

  public static final String UPDATE_RESOURCES_REQUEST = "updateResources";

  public static final String SYNCHRONIZED_REQUEST = "synchronized";
   
    // #ifdef DEBUG
  static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
      .getLog(Agent.class);
  // #endif

  static {
    HttpClient.setUserAgent("Agent"); //$NON-NLS-1$
  }

  /**
   * Set the URL of the HTTPS proxy server to use for all outgoing connections
   *
   * @param localProxyURL
   *            local proxy URL
   * @throws URI.MalformedURIException
   */
  public void setLocalProxyURL(String localProxyURL)
      throws URI.MalformedURIException {
    this.localProxyURL = new URI(localProxyURL);

    // FIXME What about HttpsURLConnection?
  }

  /**
   * Get the application manager for this agent.
   *
   * @return application manager
   */
  public ApplicationManager getApplicationManager() {
    return applicationManager;
  }

  /**
   * Get the tunnel manager for this agent
   *
   * @return tunnel mananger
   */
  public TunnelManager getTunnelManager() {
    return tunnelManager;
  }

  /**
   * Get the network place manager for this agent
   *
   * @return network place manager
   */
  public NetworkPlaceManager getNetworkPlaceManager() {
    return networkPlaceManager;
  }

  /**
   * Get the version of the server this agent is connected to. Will be
   * <code>null</code> until connected.
   *
   * @return server version
   */
  public String getServerVersion() {
    return serverVersion;
  }

  /**
   * Get the client version. This will be 999.999.999 when running
   * directly from classes or the agent extension version when
   * running from deployed version.
   *
   * @return client version
   */
  public String getClientVersion() {
    return AGENT_VERSION;
  }

  public MultiplexedConnection getConnection() {
    return con;
  }

  /**
   * Get the hostname of the Adito proxy
   *
   * @return hostname
   */
  public String getAditoHost() {
    return aditoHostname;
  }

  public String getTicket() {
    return ticket;
  }

  /**
   * Get the port of the Adito proxy
   *
   * @return port
   */
  public int getAditoPort() {
    return aditoPort;
  }
 
  public boolean isSecure() {
    return isSecure;
  }

  /**
   * Get the username for this session
   *
   * @return username
   */
  public String getUsername() {
    return username;
  }

  public void onConnectionClose() {
    currentState = STATE_DISCONNECTED;
    if (getConfiguration().isSystemExitOnDisconnect()) {
      startShutdownProcedure();
    } else {
      getGUI().showDisconnected();
    }
  }

  public void onConnectionOpen() {
    currentState = STATE_CONNECTED;
  }

  /**
   * Configure the proxy server using the currently set <i>Local Proxy URL</i>
   * (set by {@link #setLocalProxyURL(String)}.
   */
  public void configureProxy() {

    // Configure local proxy support
    if (localProxyURL != null && !localProxyURL.equals("")) { //$NON-NLS-1$
      // #ifdef DEBUG
      log.info("Configuring HTTP proxy to "
          + obfuscateURL(localProxyURL.toString()));
      // #endif
      String userInfo = localProxyURL.getUserinfo();
      String user = ""; //$NON-NLS-1$
      String password = ""; //$NON-NLS-1$
      if (userInfo != null && !userInfo.equals("")) { //$NON-NLS-1$
        int idx = userInfo.indexOf(':');
        user = URLDecoder.decode(userInfo);
        if (idx != -1) {
          password = URLDecoder.decode(userInfo.substring(idx + 1));
          user = URLDecoder.decode(userInfo.substring(0, idx));
        }
      }
      int port = localProxyURL.getPort();
      setDefaultProxyType(localProxyURL.getScheme().equals("https") ? HttpClient.PROXY_HTTPS : HttpClient.PROXY_HTTP); //$NON-NLS-1$
      setDefaultProxyHost(localProxyURL.getHost());
      setDefaultProxyPort(port == -1 ? 80 : port);
      if (!user.equals("")) { //$NON-NLS-1$
        setDefaultProxyCredentials(new PasswordCredentials(user,
            password));
      }
      if (localProxyURL.getQueryString() != null) {
        setDefaultProxyPreferredAuthentication(localProxyURL
            .getQueryString());
      }
    }
    if (localProxyURL != null && !localProxyURL.equals("")) { //$NON-NLS-1$
      setDefaultProxyAuthenticationPrompt(gui);
    }

  }

  /**
   * Get the {@link HttpClient} that is being used by this VPN client for
   * communication with Adito.
   *
   * @return http client
   */
  private synchronized HttpClient getHttpClient() {
    if (client == null) {
      // #ifdef DEBUG
      log.info("Creating HttpClient instance"); //$NON-NLS-1$
      // #endif
      client = new HttpClient(aditoHostname, aditoPort, isSecure);
      client.setAuthenticationPrompt(defaultAuthenticationPrompt != null ? defaultAuthenticationPrompt : getGUI());
      if (defaultProxyHost != null && !defaultProxyHost.equals("")) { //$NON-NLS-1$
        // #ifdef DEBUG
        log.info("Configuring proxies for HttpClient instance"); //$NON-NLS-1$
        // #endif
        client
            .setProxyAuthenticationPrompt(defaultProxyAuthenticationPrompt);
        client.setProxyHost(defaultProxyHost);
        client.setProxyPort(defaultProxyPort);
        client.setProxyType(defaultProxyType);

        if (defaultProxyCredentials != null
            && defaultProxyCredentials.getUsername() != null
            && !defaultProxyCredentials.getUsername().equals("")) { //$NON-NLS-1$
          /**
           * LDP - This used to set preemptive authentication but its
           * causing problems with NTLM
           */
          client.setProxyCredentials(defaultProxyCredentials);

          /**
           * LDP - It seems preemptive might be needed for Basic
           * authentication. There are lots of users seeing
           * EOFExceptions after 407 proxy authentication required.
           */
          if ("BASIC"
              .equalsIgnoreCase(defaultProxyPreferredAuthentication)) {
            client.setProxyPreemptiveAuthentication(true);
          }
        }
        client
            .setProxyPreferedAuthentication("AUTO".equalsIgnoreCase(defaultProxyPreferredAuthentication) ? null //$NON-NLS-1$
                : defaultProxyPreferredAuthentication);
      }
    }

    return client;
  }

  /**
   * Constructor preventing direct instantiation.
   */
  public Agent(AgentConfiguration agentConfiguration) {
    this.agentConfiguration = agentConfiguration;

    // Forced
    if (getConfiguration().getGUIClass() != null) {
      try {
        gui = (AgentClientGUI) Class.forName(
            getConfiguration().getGUIClass()).newInstance();
      } catch (Exception e) {
        //#ifdef DEBUG
        log.error("Failed to create GUI", e);
        //#endif
      }
    }

    //
    if (gui == null) {

      // SWT
      try {
        Class.forName("org.eclipse.swt.widgets.Display");
        gui = (AgentClientGUI) Class
            .forName(
                "com.adito.agent.client.gui.swt.SWTSystemTrayGUI")
            .newInstance();
      } catch (Exception e) {
        //#ifdef DEBUG
        log.debug("Failed to create SWT GUI", e);
        //#endif
      }

      //
      if (gui == null) {

        // JDK6
        if (Utils.checkVersion("1.6")) { //$NON-NLS-1$
          try {
            // yay, finally agent tray icon for linux
            gui = (AgentClientGUI) Class
                .forName(
                    "com.adito.agent.client.gui.awt.JDK6SystemTrayGUI")
                .newInstance();
          } catch (Exception e) {
            //#ifdef DEBUG
            log.debug("Failed to create JDK6 GUI", e);
            //#endif
          }
        }

        // Systray4j
        if (gui == null
            && Utils.checkVersion("1.2") && System.getProperty("os.name").startsWith("Windows") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            && !System
                .getProperty("os.name").startsWith("Windows 98") //$NON-NLS-1$ //$NON-NLS-2$
            && !System
                .getProperty("os.name").startsWith("Windows 95") //$NON-NLS-1$ //$NON-NLS-2$
            && !System
                .getProperty("os.name").startsWith("Windows ME")) { //$NON-NLS-1$ //$NON-NLS-2$
          try {
            gui = (AgentClientGUI) Class
                .forName(
                    "com.adito.agent.client.gui.awt.SystemTrayGUI")
                .newInstance();
          } catch (Exception e) {
            //#ifdef DEBUG
            log.debug("Failed to create JDIC GUI", e);
            //#endif
          }
        }

        // Fallback to basic frame GUI
        if (gui == null) {
          try {
            gui = (AgentClientGUI) Class
                .forName(
                    "com.adito.agent.client.gui.awt.BasicFrameGUI")
                .newInstance();
          } catch (Exception e) {
            //#ifdef DEBUG
            log.debug("Failed to create basic GUI", e);
            //#endif
          }

          // No GUI? Probably embedded so use a dummy GUI
          if (gui == null) {
            gui = new DummyGUI();
          }
        }
      }
    }
  }

  // /**
  // * Get the static instance of the {@link Agent}.
  // *
  // * @return instance
  // */
  // public static Agent getVPN() {
  // if (vpn == null) {
  // vpn = new Agent();
  // }
  // return vpn;
  // }

  /**
   * Get the current state. Will be one of {@link #STATE_DISCONNECTED} or
   * {@link #STATE_CONNECTED}.
   *
   * @return state
   */
  public int getState() {
    return currentState;
  }

  /**
   * Get the object the stores various configuration options
   *
   * @return configuration
   */
  public AgentConfiguration getConfiguration() {
    return agentConfiguration;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.adito.vpn.base.AbstractVPNClient#init(java.lang.String,
   *      int, java.lang.String, java.lang.String)
   */
  public void init() throws SecurityException, IOException {

        // Create connection object now so users of API can add connection listeners before connecting
      con = new MultiplexedConnection(new AgentChannelFactory(
                this));
       
    // #ifdef DEBUG
    log.info("Allow untrusted hosts is set to " + System.getProperty("com.maverick.ssl.allowUntrustedCertificates", "false")); //$NON-NLS-1$ //$NON-NLS-2$
    log.info("Cache directory is " + getConfiguration().getCacheDir());
    // #endif

    // #ifdef DEBUG
    log.info("Initialising GUI"); //$NON-NLS-1$
    // #endif
    gui.init(this);
    disconnected();

    // Install and configure HTTP / HTTPS support
    // #ifdef DEBUG
    log.info("Installing Maverick SSL support for HTTPSURLStreamHandler"); //$NON-NLS-1$
    // #endif

    try {
      HttpsURLStreamHandlerFactory.addHTTPSSupport();
      configureProxy();
    } catch (SecurityException se) {
      disconnected();
      throw se;
    } catch (IOException ioe) {
      disconnected();
      throw ioe;
    }
  }

  public void connect(String aditoHostname, int aditoPort,
      boolean isSecure, String username, String ticket, boolean ticketIsPassword)
      throws IOException, HttpException,
      UnsupportedAuthenticationException,
      AuthenticationCancelledException {

    this.aditoHostname = aditoHostname;
    this.aditoPort = aditoPort;
    this.username = username;
    this.ticket = ticket;
    this.ticketIsPassword = ticketIsPassword;
    this.isSecure = isSecure;

    inactivityMonitor = new TunnelInactivityMonitor(this);
    keepAlive = new KeepAliveThread();

    gui.showTxRx();

    connectAgent();

    // Start the Tx/Rx monitor so we have some animated icons
    txm = new TXRXMonitor(this);
    txm.start();

    gui.showIdle();
    updateInformation();

    inactivityMonitor.start();

    if (getConfiguration().getKeepAlivePeriod() > 0)
      keepAlive.start();

    if (getConfiguration().isDisplayInformationPopups()) {
      getGUI().popup(null, Messages.getString("VPNClient.nowRunning"), //$NON-NLS-1$  
          Messages.getString("VPNClient.title"), "popup-agent", 5000); //$NON-NLS-1$
    }
   
    try {
      // Give the popup message some breathing space
      // otherwise in SWT we loose it :(
      Thread.sleep(3000);
    } catch(InterruptedException ex) { }

  }

  public boolean processRequest(Request request, MultiplexedConnection con) {

    if (request.getRequestName().equals(SHUTDOWN_REQUEST)) {
      disconnectAgent();
      return true;
    } else if (request.getRequestName().equals(MESSAGE_REQUEST)) {
      displayMessage(request);
      return true;
    } else if (request.getRequestName().equals(UPDATE_RESOURCES_REQUEST)) {
      final ByteArrayReader bar = new ByteArrayReader(request.getRequestData());
      Thread t = new Thread() {
        public void run() {
          try {
            updateResources((int)bar.readInt());
          }
          catch(IOException e) {       
          }
        }
      };
      t.start();
      return true;
    } else if (request.getRequestName().equals(OPEN_URL_REQUEST)
        && request.getRequestData() != null) {
      try {
        ByteArrayReader msg = new ByteArrayReader(request
            .getRequestData());
        openURL(msg.readString(), msg.readString(), request);
        return true;
      } catch (IOException e) {
        // #ifdef DEBUG
        log.error("Failed to process openURL request", e);
        // #endif
        return false;
      }
    } else
      return false;
  }

  public void postReply(MultiplexedConnection connection) {
  }

  private void displayMessage(Request request) {

    try {
      if (request.getRequestData() != null) {
        ByteArrayReader msg = new ByteArrayReader(request
            .getRequestData());
        String title = msg.readString();
        msg.readInt(); // type
        String message = msg.readString();

        getGUI().popup(
            null,
            MessageFormat.format(Messages
                .getString("Agent.received"), new Object[] {
                SimpleDateFormat.getDateTimeInstance().format(
                    new Date()), message }),
            title.equals("") ? Messages
                .getString("Agent.promptTitle") : title,
            "popup-mail", 0);
      }
    } catch (IOException e) {
      // #ifdef DEBUG
      log.error("Failed to read message data from popup message request",
          e);
      // #endif
    }

  }

  private boolean openURL(String link, String launchId, Request request) {

    // #ifdef DEBUG
    log.info("Request to open " + link + " via a temporary tunnel"); //$NON-NLS-1$ //$NON-NLS-2$
    // #endif

    // Parse the link address and create a new address for the browser
    // to use
    try {
      URI url = new URI(link);
      String linkHost = url.getHost();
      int linkPort = url.getPort() == -1 ? (url.getScheme()
          .equalsIgnoreCase("https") ? 443 : 80) : url.getPort(); //$NON-NLS-1$

      // Start a tunnel

      DefaultTunnel t = new DefaultTunnel(-1,
          TunnelConfiguration.LOCAL_TUNNEL,
          TunnelConfiguration.TCP_TUNNEL, null, 0, linkPort,
          linkHost, false, false, linkHost + ":" + linkPort, launchId);

      LocalTunnelServer listener = getTunnelManager().startLocalTunnel(t);

      // #ifdef DEBUG
      log.info("Tunneled web forward listener started on port "
          + listener.getLocalPort());
      // #endif

      ByteArrayWriter w = new ByteArrayWriter();
      w.writeInt(listener.getLocalPort());
      request.setRequestData(w.toByteArray());
      return true;
    } catch (Exception e) {
      // #ifdef DEBUG
      log.error("Failed to process openURL request", e);
      // #endif
    }
    return false;
  }

  /**
   * Get the current GUI.
   *
   * @return gui
   */
  public AgentClientGUI getGUI() {
    return gui;
  }

  public void updateInformation() {

    // String msg = ""; //$NON-NLS-1$
    // int count = getActiveDirectTunnels().size()
    // + activeForwardingTunnels.size();
    //
    // for (Enumeration e = remoteListeners.elements();
    // e.hasMoreElements();) {
    // MultiplexedConnection con = (MultiplexedConnection) e.nextElement();
    // count += con.getActiveChannels().length;
    // }
    // int ports = activeListeners.size() + remoteListeners.size();
    // if (ports > 0) {
    // if (count > 0) {
    // msg = MessageFormat
    // .format(
    // Messages
    // .getString("VPNClient.information.active"), new Object[] { new
    // Integer(ports), new Integer(count) }); //$NON-NLS-1$
    // } else {
    // msg = MessageFormat
    // .format(
    // Messages
    // .getString("VPNClient.information.notActive"), new Object[] { new
    // Integer(ports) }); //$NON-NLS-1$
    // }
    // } else if (count > 0) {
    // msg = MessageFormat
    // .format(
    // Messages
    // .getString("VPNClient.information.remainingConnections"), new
    // Object[] { new Integer(count) }); //$NON-NLS-1$
    //
    // }
    //
    // if (msg.equals("")) { //$NON-NLS-1$
    // msg = Messages.getString("VPNClient.information.idle"); //$NON-NLS-1$
    // }
    //
    // gui.setInfo(msg);
  }

  /*
   * (non-Javadoc)
   *
   * @see com.adito.vpn.base.AbstractVPNClient#getTXIOListener()
   */
  public IOStreamConnectorListener getTXIOListener() {
    return txm != null ? txm.getTxListener() : null;
  }

  public IOStreamConnectorListener getRXIOListener() {
    return txm != null ? txm.getRxListener() : null;
  }

  /**
   * Get the full URL to use for a redirect given the path. The appropriate
   * hostname and port will automatically be added.
   *
   * @param path
   *            path
   * @return full URL including appropriate host and port
   */
  protected String getRedirectUrl(String path) {
    try {
      new URL(path);
      return path;
    } catch (Exception e) {
      return "https://" + getAditoHost() + ":" + getAditoPort() + path; //$NON-NLS-1$  //$NON-NLS-2$
    }
  }

  protected void startExtensions(String extensionClasses) {
    StringTokenizer classes = new StringTokenizer(extensionClasses, ","); //$NON-NLS-1$
    while (classes.hasMoreTokens()) {
      String cls = classes.nextToken();
      try {
        Class agent = Class.forName(cls);
        AgentExtension ext = (AgentExtension) agent.newInstance();
        // #ifdef DEBUG
        log.info("Starting " + ext.getName());
        // #endif
        ext.init(this);
        extensions.addElement(ext);
      } catch (Exception e1) {
        // #ifdef DEBUG
        log.info("Unable to start extension " + cls, e1);
        // #endif
        continue;
      }
    }
  }

  private void connectAgent() throws IOException, HttpException,
      UnsupportedAuthenticationException,
      AuthenticationCancelledException {

    HttpResponse response = null;
    HttpAuthenticator authenticator = null;
    String ticketToSend = ticket;
   
    boolean doPreemptive = ticketIsPassword;

    try {
           
      for (int i = 0; i < 3; i++) {

              HttpClient client = getHttpClient();
              if (doPreemptive) {
                  client.setCredentials(new PasswordCredentials(username,
                          ticket));
                  client.setPreferredAuthentication("Basic");
              }
              else {
                  client.setCredentials(null);
              }

        // #ifdef DEBUG
        log.info("Registering with the server"); //$NON-NLS-1$
        log.info("Server is " + (isSecure ? "https://" : "http://") + getAditoHost() //$NON-NLS-1$
            + ":" + getAditoPort()); //$NON-NLS-1$
        // #endif
        GetMethod post = new GetMethod("/agent"); //$NON-NLS-1$

              client.setPreemtiveAuthentication(doPreemptive);
        if (!doPreemptive && ticket != null) {
          post.setParameter("ticket", ticket); //$NON-NLS-1$
        }

        post.setParameter(
            "agentType", getConfiguration().getAgentType()); //$NON-NLS-1$ //$NON-NLS-2$
        post.setParameter("locale", Locale.getDefault().toString()); //$NON-NLS-1$

        response = client.execute(post);

        if (response.getStatus() == 302) {
          // Reset the client
          this.client = null;

          URL url = new URL(response.getHeaderField("Location")); //$NON-NLS-1$
          aditoHostname = url.getHost();
          if (url.getPort() > 0)
            aditoPort = url.getPort();
          continue;
        } else if (response.getStatus() == 200) {
          con.addListener(this);
          httpConnection = response.getConnection(); // Preserve the
          // connection
          con.registerRequestHandler(MESSAGE_REQUEST, this);
          con.registerRequestHandler(SHUTDOWN_REQUEST, this);
          con.registerRequestHandler(OPEN_URL_REQUEST, this);
          con.registerRequestHandler(UPDATE_RESOURCES_REQUEST, this);

          // Start the protocol

          con.startProtocol(
              response.getConnection().getInputStream(), response
                  .getConnection().getOutputStream(), true);

          // Synchronize and read back server information
          Request syncRequest = new Request(SYNCHRONIZED_REQUEST);
          con.sendRequest(syncRequest, true);
          if (syncRequest.getRequestData() == null)
            throw new IOException(
                "Server failed to return version data");

          ByteArrayReader reader = new ByteArrayReader(syncRequest
              .getRequestData());
          serverVersion = reader.readString();

          /**
           * Initialize the managers. Tunnels are no longer recorded
           * here unless they are active. This simplifies the agent by
           * making it respond to start and stop requests from the new
           * persistent connection with Adito.
           */
          tunnelManager = new TunnelManager(this);
          applicationManager = new ApplicationManager(this);
          webForwardManager = new WebForwardManager(this);
          networkPlaceManager = new NetworkPlaceManager(this);
          updateResources(-1);
          return;
        } else if (response.getStatus() == 401) {
          authenticator = HttpAuthenticatorFactory
              .createAuthenticator(
                  response.getConnection(),
                  response
                      .getHeaderFields("WWW-Authenticate"),
                  "WWW-Authenticate", "Authorization",
                  HttpAuthenticatorFactory.BASIC, post
                      .getURI());
          if (authenticator.wantsPrompt()) {
            if ( !( defaultAuthenticationPrompt != null ? defaultAuthenticationPrompt.promptForCredentials(false, authenticator) :
                getGUI().promptForCredentials(false, authenticator) ) ) {
              throw new AuthenticationCancelledException();
            }
          }
        } else if(response.getStatus() == 403) {
            if(doPreemptive || ticket != null) {
                doPreemptive = false;
                ticket = null;
            }
            else {
              throw new IOException(MessageFormat.format(Messages
                  .getString("VPNClient.register.failed"),
                  new Object[] {
                      String.valueOf(response.getStatus()),
                      response.getReason() }));
            }
        }
      }

      throw new IOException(Messages
          .getString("VPNClient.register.tooManyRedirects")); //$NON-NLS-1$
    } catch (IOException ioe) {
      disconnected();
      throw ioe;
    } catch (HttpException httpe) {
      disconnected();
      throw httpe;
    } catch (UnsupportedAuthenticationException uae) {
      disconnected();
      throw uae;
    } catch (AuthenticationCancelledException ace) {
      disconnected();
      throw ace;
    }

  }
   
    public boolean isConnected() {
        return con != null && con.isRunning();
    }

  public void disconnect() {
    if (isConnected()) {
      disconnectAgent();
    }
  }

  /**
   * Shutdown the Agent.
   *
   * @param deregister
   *            deregister the agent
   * @param threadDeRegister
   *            deregister in a thread
   */
  public void startShutdownProcedure() {
    // #ifdef DEBUG
    log.info("Starting agent shutdown procedure."); //$NON-NLS-1$
    // #endif

    if (getConfiguration().isDisplayInformationPopups()) {
      getGUI()
          .popup(
              null,
              Messages.getString("VPNClient.shutdown.popupText"), Messages.getString("VPNClient.title"), "popup-agent", -1); //$NON-NLS-1$  //$NON-NLS-2$
    }

    AgentExtension ext;
    for (Enumeration e = extensions.elements(); e.hasMoreElements();) {
      ext = (AgentExtension) e.nextElement();

      // #ifdef DEBUG
      log.info("Stopping extension " + ext.getName()); //$NON-NLS-1$
      // #endif
      ext.exit();
    }

    getGUI().showDisconnected();

    FileCleaner.deleteAllFiles();
   
    if (getConfiguration().isCleanOnExit()) {
      if (Utils.isSupportedPlatform("Windows")) {
        cleanupWindowsAgent();
      } else if (Utils.isSupportedPlatform("Linux")) {
        cleanupLinuxAgent();
      } else {
        // #ifdef DEBUG
        log
            .info("Agent cleanOnExit is not supported on this platform."); //$NON-NLS-1$
        // #endif

      }
    }

    if (getConfiguration().isSystemExitOnDisconnect()) {
      scheduleExit();
    } else {
      gui.dispose();
    }
  }

  /**
   * Get the default credentials used for proxy server authentication. By
   * default this will be <code>null</code>
   *
   * @return default credentials used for proxy server authentication.
   */
  public PasswordCredentials getDefaultProxyCredentials() {
    return defaultProxyCredentials;
  }

  /**
   * Set the default credentials used for proxy server authentication.
   *
   * @param defaultProxyCredentials
   *            default credentials used for proxy server authentication.
   */
  public void setDefaultProxyCredentials(
      PasswordCredentials defaultProxyCredentials) {
    this.defaultProxyCredentials = defaultProxyCredentials;
  }

  /**
   * Get the default hostname for the proxy server to use. Use
   * <code>null</code> for no proxy server (the default).
   *
   * @return proxy hostname or <code>null</code> for no proxy
   */
  public String getDefaultProxyHost() {
    return defaultProxyHost;
  }

  /**
   * Set the default hostname for the proxy server to use. Use
   * <code>null</code> for no proxy server (the default).
   *
   * @param defaultProxyHost
   *            proxy hostname or <code>null</code> for no proxy
   */
  public void setDefaultProxyHost(String defaultProxyHost) {
    this.defaultProxyHost = defaultProxyHost;
  }

  /**
   * Set the default proxy port. By default this is <i>80</i>.
   *
   * CHECK Why 80? IIS?
   *
   * @return default proxy port number
   */
  public int getDefaultProxyPort() {
    return defaultProxyPort;
  }

  /**
   * Set the default proxy port. By default this is <i>80</i>.
   *
   * CHECK Why 80? IIS?
   *
   * @param defaultProxyPort
   *            default proxy port number
   */
  public void setDefaultProxyPort(int defaultProxyPort) {
    this.defaultProxyPort = defaultProxyPort;
  }

  /**
   * Get the default proxy type. This may be one of
   * {@link HttpClient#PROXY_HTTP}, {@link HttpClient#PROXY_HTTPS} or
   * {@link HttpClient#PROXY_NONE}. By default this is
   * {@link HttpClient#PROXY_HTTP}.
   *
   * @return default proxy type
   */
  public int getDefaultProxyType() {
    return defaultProxyType;
  }

  /**
   * Set the default proxy type. This may be one of
   * {@link HttpClient#PROXY_HTTP}, {@link HttpClient#PROXY_HTTPS} or
   * {@link HttpClient#PROXY_NONE}. By default this is
   * {@link HttpClient#PROXY_HTTP}.
   *
   * @param defaultProxyType
   *            default proxy type
   */
  public void setDefaultProxyType(int defaultProxyType) {
    this.defaultProxyType = defaultProxyType;
  }

  /**
   * Get the default preferred authentication type to use for proxy servers.
   * This may be one of {@link HttpAuthenticatorFactory#BASIC},
   * {@link HttpAuthenticatorFactory#NTLM},
   * {@link HttpAuthenticatorFactory#DIGEST},
   * {@link HttpAuthenticatorFactory#NONE} or <code>null</code> (Automatic).
   * The string value <i>"AUTO"</i> may be used instead of <code>null</code>.
   *
   * @return default proxy authentication type
   */
  public String getDefaultProxyPreferredAuthentication() {
    return defaultProxyPreferredAuthentication;
  }

  /**
   * Set the default preferred authentication type to use for proxy servers.
   * This may be one of {@link HttpAuthenticatorFactory#BASIC},
   * {@link HttpAuthenticatorFactory#NTLM},
   * {@link HttpAuthenticatorFactory#DIGEST},
   * {@link HttpAuthenticatorFactory#NONE} or <code>null</code> (Automatic).
   * The string value <i>"AUTO"</i> may be used instead of <code>null</code>.
   *
   * @param defaultProxyPreferredAuthentication
   *            default proxy authentication type
   */
  public void setDefaultProxyPreferredAuthentication(
      String defaultProxyPreferredAuthentication) {
    this.defaultProxyPreferredAuthentication = defaultProxyPreferredAuthentication;
  }

  /**
   * Get the {@link AuthenticationPrompt} that will be used if the proxy
   * server requires authentication. This may happen if the default
   * authentication details have not been set using the methods in the class
   * or if those details are incorrect and the proxy server is requesting
   * again.
   * <p>
   * The prompt may for example display a GUI dialog box that will ask the
   * user for details or it may retrieve them from somewhere else such as a
   * password database.
   * <p>
   * If <code>null</code> is returned then no authenitcation prompt is set.
   *
   * @return authentication prompt
   */
  public AuthenticationPrompt getDefaultProxyAuthenticationPrompt() {
    return defaultProxyAuthenticationPrompt;
  }

  /**
   * Set the {@link AuthenticationPrompt} that will be used if the proxy
   * server requires authentication. This may happen if the default
   * authentication details have not been set using the methods in the class
   * or if those details are incorrect and the proxy server is requesting
   * again.
   * <p>
   * The prompt may for example display a GUI dialog box that will ask the
   * user for details or it may retrieve them from somewhere else such as a
   * password database.
   * <p>
   * If <code>null</code> is returned then no authenitcation prompt is set.
   *
   * @param defaultProxyAuthenticationPrompt
   *            authentication prompt
   */
  public void setDefaultProxyAuthenticationPrompt(
      AuthenticationPrompt defaultProxyAuthenticationPrompt) {
    this.defaultProxyAuthenticationPrompt = defaultProxyAuthenticationPrompt;
  }

    /**
     * Set the {@link AuthenticationPrompt} that will be used if the Adito
     * server requires authentication. This may happen if the default
     * authentication details have not been set using the methods in the class
     * or if those details are incorrect and the server is requesting
     * again.
     * <p>
     * The prompt may for example display a GUI dialog box that will ask the
     * user for details or it may retrieve them from somewhere else such as a
     * password database.
     *
     * @param defaultAuthenticationPrompt
     *            authentication prompt
     */
    public void setDefaultAuthenticationPrompt(
            AuthenticationPrompt defaultAuthenticationPrompt) {
        this.defaultAuthenticationPrompt = defaultAuthenticationPrompt;
    }

  /**
   * Utility method to hide any passwords that may be present in the userinfo
   * portion of a URL.
   *
   * @param originalUrl
   *            original url
   * @return obfuscated url
   */
  public static String obfuscateURL(String originalUrl) {
    try {
      URI url = new URI(originalUrl);
      String userInfo = url.getUserinfo();
      String user = ""; //$NON-NLS-1$
      if (userInfo != null && !userInfo.equals("")) { //$NON-NLS-1$
        int idx = userInfo.indexOf(':');
        user = userInfo;
        if (idx != -1) {
          user = userInfo.substring(0, idx);
        }
        return url.getScheme()
            + "://" + user + ":***@" + url.getHost() + ":" + url.getPort() //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            + (url.getQueryString() != null ? ("?" + url.getQueryString()) : ""); //$NON-NLS-1$ //$NON-NLS-2$
      } else {
        return originalUrl;
      }

    } catch (URI.MalformedURIException e) {
      return originalUrl;
    }
  }

  /**
   * Get a <code>Properties</code> that may be sent back to the server so it
   * can check if the client is in a supported environment. For example, the
   * sun.os.patch.level property may be used to deny clients that are running
   * Windows SP1.
   *
   * @return system properties
   */
  public static Properties getSystemPropertiesToSend() {
    Properties p = new Properties();
    setIfNotEmpty("java.version", p); //$NON-NLS-1$
    setIfNotEmpty("java.vendor", p); //$NON-NLS-1$
    setIfNotEmpty("sun.os.patch.level", p); //$NON-NLS-1$
    setIfNotEmpty("os.name", p); //$NON-NLS-1$
    setIfNotEmpty("os.version", p); //$NON-NLS-1$
    setIfNotEmpty("os.arch", p); //$NON-NLS-1$
    return p;
  }

  protected static void setIfNotEmpty(String name, Properties p) {
    String v = System.getProperty(name);
    if (v != null && !v.equals("")) { //$NON-NLS-1$
      p.put(name, v);
    }
  }

  private static String getCommandLineValue(String arg) {
    int idx = arg.indexOf('=');
    if (idx > -1)
      return arg.substring(idx + 1);
    else
      return arg;
  }

  /**
   * Entry point.
   *
   * @param args arguments
   */
  public static void main(String[] args) throws Throwable {
    try {
      // #ifdef DEBUG
      org.apache.log4j.BasicConfigurator.configure();
      // #endif

            AgentArgs agentArgs = Agent.initArgs(args);
           
            Agent agent = Agent.initAgent(agentArgs);
           
            if (agentArgs.isDisableNewSSLEngine())
                SSLTransportFactory.setTransportImpl(SSLTransportImpl.class);

      agent.initMain(agentArgs.getHostname(), agentArgs.getPort(), agentArgs.isSecure(), agentArgs.getUsername(), agentArgs.getPassword(), agentArgs.getTicket());

      if (agentArgs.getExtensionClasses() != null)
        agent.startExtensions(agentArgs.getExtensionClasses());
    } catch (Throwable t) {
      // Catch any nasties to make sure we exit
      // #ifdef DEBUG
      if (log != null) {
        log.error("Critical error, shutting down.", t); //$NON-NLS-1$
      } else {
        System.err.println("Critical error, shutting down.");
        t.printStackTrace();
      }
      // #endif
      throw t;
    }
  }
   
    protected static AgentArgs initArgs(String[] args) throws Throwable {
        int shutdown = -1;
        int webforwardInactivity = 300000;
        int tunnelInactivity = 600000;

        AgentArgs agentArgs = new AgentArgs();
        AgentConfiguration configuration = new AgentConfiguration();

        String hostHeader = null;
        String protocol = null;
        for (int i = 0; i < args.length; i++) {
            if (args[i].startsWith("host")) { //$NON-NLS-1$
                hostHeader = getCommandLineValue(args[i]);
            } else if (args[i].startsWith("protocol")) { //$NON-NLS-1$
                protocol = getCommandLineValue(args[i]);
            } else if (args[i].startsWith("username")) { //$NON-NLS-1$
                agentArgs.setUsername(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("password")) { //$NON-NLS-1$
                agentArgs.setPassword(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("localProxyURL")) { //$NON-NLS-1$
                agentArgs.setLocalProxyURL(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("pluginProxyURL")) { //$NON-NLS-1$
                agentArgs.setPluginProxyURL(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("ticket")) { //$NON-NLS-1$
                agentArgs.setTicket(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("browserCommand")) { //$NON-NLS-1$
                agentArgs.setBrowserCommand(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("userAgent")) { //$NON-NLS-1$
                String userAgent = getCommandLineValue(args[i]);
                agentArgs.setUserAgent(userAgent);
                HttpClient.setUserAgent(userAgent);
            } else if (args[i].startsWith("locale")) { //$NON-NLS-1$
                agentArgs.setLocaleName(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("disableNewSSLEngine")) { //$NON-NLS-1$
                agentArgs.setDisableNewSSLEngine(Boolean.valueOf(getCommandLineValue(args[i])).booleanValue());
            } else if (args[i].startsWith("webforward.inactivity")) { //$NON-NLS-1$
                try {
                    webforwardInactivity = Integer
                            .parseInt(getCommandLineValue(args[i]));
                } catch (NumberFormatException ex) {
                }
            } else if (args[i].startsWith("tunnel.inactivity")) { //$NON-NLS-1$
                try {
                    tunnelInactivity = Integer
                            .parseInt(getCommandLineValue(args[i]));
                } catch (NumberFormatException ex) {
                }
            } else if (args[i].startsWith("shutdown")) { //$NON-NLS-1$
                try {
                    shutdown = Integer
                            .parseInt(getCommandLineValue(args[i]));
                } catch (NumberFormatException ex) {
                }
            } else if (args[i].startsWith("log4j")) { //$NON-NLS-1$
                agentArgs.setLogProperties(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("extensionClasses")) { //$NON-NLS-1$
                agentArgs.setExtensionClasses(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("ignoreCertWarnings")) {
                System.getProperties().put(
                        "com.maverick.ssl.allowUntrustedCertificates",
                        "true");
                System.getProperties()
                        .put("com.maverick.ssl.allowInvalidCertificates",
                                "true");
            } else if (args[i].startsWith("forceBasicUI")) {
                configuration
                        .setGUIClass("com.adito.agent.client.gui.BasicFrameGUI");
            } else if (args[i].startsWith("displayInformationPopups")) {
                configuration
                        .setDisplayInformationPopups(getCommandLineValue(
                                args[i]).equalsIgnoreCase("true"));
            } else if (args[i]
                    .startsWith("remoteTunnelsRequireConfirmation")) {
                configuration
                        .setRemoteTunnelsRequireConfirmation(getCommandLineValue(
                                args[i]).equalsIgnoreCase("true"));
            } else if (args[i].startsWith("cleanOnExit")) {
                configuration.setCleanOnExit(getCommandLineValue(args[i])
                        .equalsIgnoreCase("true"));
            } else if (args[i].startsWith("localhostAddress")) {
                configuration.setLocalhostAddress(getCommandLineValue(args[i]));
            } else if (args[i].startsWith("dir")) {
                configuration.setCacheDir(new File(
                        Utils.getHomeDirectory(),
                        getCommandLineValue(args[i])));
            } else if (args[i].startsWith("removeFiles")) {
                StringTokenizer files = new StringTokenizer(
                        getCommandLineValue(args[i]), File.pathSeparator);
                while (files.hasMoreTokens()) {
                    configuration.removeFileOnExit(new File(files
                            .nextToken()));
                }
            } else if (args[i].startsWith("keepAlivePeriod")) {
                configuration.setKeepAlivePeriod(Integer
                        .parseInt(getCommandLineValue(args[i])));
            } else if (args[i].startsWith("extensionId")) {
              agentArgs.setExtensionId(getCommandLineValue(args[i]));
            }
        }
       
        if(hostHeader == null || protocol == null) {
          throw new IOException("");
        } else {
          int idx = hostHeader.indexOf(':');
          if(idx > -1) {
            String port = hostHeader.substring(idx+1);
            agentArgs.setHostname(hostHeader.substring(0,idx));
                try {
                    agentArgs.setPort(Integer.parseInt(port));
                } catch (NumberFormatException ex) {
                }
                agentArgs.setSecure(protocol.equalsIgnoreCase("https"));
          } else {
            agentArgs.setHostname(hostHeader);
            agentArgs.setPort(protocol.equalsIgnoreCase("http") ? 80 : 443);
            agentArgs.setSecure(protocol.equalsIgnoreCase("https"));
          }
        }

        if(isWindows64()) {
            configuration.setGUIClass("com.adito.agent.client.gui.BasicFrameGUI");
        }
       
        WinRegistry.setLocation(new File(configuration.getCacheDir(), "applications" + File.separator + agentArgs.getExtensionId()));
       
        /*
         * Load the message resources.
         */
        Locale.setDefault(Utils.createLocale(agentArgs.getLocaleName()));

        if (agentArgs.getLogProperties() == null) {
            System.out.println(Messages
                    .getString("VPNClient.main.debugModeWarning")); //$NON-NLS-1$
        }

        if (agentArgs.getPort() == -1 || agentArgs.getHostname() == null || agentArgs.getUsername() == null
                || (agentArgs.getTicket() == null && agentArgs.getPassword() == null))
            throw new IOException(
                    Messages
                            .getString("VPNClient.main.missingCommandLineArguments")); //$NON-NLS-1$

        if (shutdown > -1)
            configuration.setShutdownPeriod(shutdown);
        configuration.setSystemExitOnDisconnect(true);
        configuration.setWebForwardInactivity(webforwardInactivity);
        configuration.setTunnelInactivity(tunnelInactivity);

        agentArgs.setAgentConfiguration(configuration);
        return agentArgs;
    }
   
    protected static Agent initAgent(AgentArgs agentArgs) throws Throwable {
        Agent agent = new Agent(agentArgs.getAgentConfiguration());

        // Setup the output stream
        PrintStream consolePrintStream = new PrintStream(agent.getGUI()
                .getConsole());
        System.setErr(consolePrintStream);
        System.setOut(consolePrintStream);

        System.out.println("Java version "
                + System.getProperty("java.version"));
        System.out.println("OS version " + System.getProperty("os.name"));

        // #ifdef DEBUG
        if (agentArgs.getLogProperties() != null) {
            File f = new File(agentArgs.getLogProperties());
            InputStream in = new FileInputStream(f);
            try {
                Properties props = new Properties();
                props.load(in);
                File logfile = new File(f.getParent(), "agent.log"); //$NON-NLS-1$
                props
                        .put(
                                "log4j.appender.logfile.File", logfile.getAbsolutePath()); //$NON-NLS-1$
                org.apache.log4j.PropertyConfigurator.configure(props);
                log = org.apache.commons.logging.LogFactory
                        .getLog(Agent.class);
                log.info("Configured logging"); //$NON-NLS-1$
            } finally {
                in.close();
            }
        }
       
        Properties systemProperties = System.getProperties();
        String key;
        log.info("System properties:");
        for(Enumeration e = systemProperties.keys(); e.hasMoreElements();) {
            key = (String)e.nextElement();
            log.info("   " + key + ": " + systemProperties.getProperty(key));
        }
        // #endif

        agent.setupProxy(agentArgs.getLocalProxyURL(), agentArgs.getUserAgent(), agentArgs.getPluginProxyURL());

        if (agentArgs.getBrowserCommand() != null && !agentArgs.getBrowserCommand().equals("")) { //$NON-NLS-1$

            // #ifdef DEBUG
            log.info("Setting browser to " + agentArgs.getBrowserCommand()); //$NON-NLS-1$
            // #endif
            BrowserLauncher.setBrowserCommand(agentArgs.getBrowserCommand());
        }
       
        return agent;
    }
 
  private static boolean isWindows64() {

      String prop = System.getProperty("os.name");
      if (prop == null || prop.startsWith("Windows") == false)
        return false;

      prop = System.getProperty("os.arch");
      if (prop != null && prop.equalsIgnoreCase("amd64"))
        return true;

      prop = System.getProperty("java.vm.name");
      if (prop != null && prop.indexOf("64-Bit") != -1)
        return true;

      prop = System.getProperty("sun.arch.data.model");
      if (prop != null && prop.equals("64"))
        return true;

      return false;   
  }
 
  private static boolean isWindowsVista() {
    return System.getProperty("os.name").startsWith("Windows Vista");
  }
   
    public static void initMain(Agent agent, AgentArgs agentArgs) {
        if (null != agent && null != agentArgs) {
          agent.initMain(agentArgs.getHostname(), agentArgs.getPort(), agentArgs.isSecure(), agentArgs.getUsername(), agentArgs.getPassword(), agentArgs.getTicket());
            if (agentArgs.getExtensionClasses() != null)
                agent.startExtensions(agentArgs.getExtensionClasses());
        }
    }

  protected void initMain(String hostname, int port, boolean isSecure, String username, String password,
      String ticket) {
    try {
      init();
      connect(hostname, port, isSecure, username, ticket == null ? password
          : ticket, ticket == null);
    } catch (SSLIOException ex) {
      // #ifdef DEBUG
      log.info("An unexpected error has occured.", ex.getRealException()); //$NON-NLS-1$
      log.info("Agent must now exit"); //$NON-NLS-1$
      // #endif
      gui.showDisconnected();
      gui.error(Messages.getString("VPNClient.close"), null, //$NON-NLS-1$ 
          Messages.getString("VPNClient.error"), //$NON-NLS-1$
          Messages.getString("VPNClient.failedToConnect"), ex); //$NON-NLS-1$
      System.exit(4);
    } catch (IOException ex) {
      // #ifdef DEBUG
      log.info("An unexpected error has occured.", ex); //$NON-NLS-1$
      log.info("Agent must now exit"); //$NON-NLS-1$
      // #endif
      gui.error(Messages.getString("VPNClient.close"), null, //$NON-NLS-1$
          Messages.getString("VPNClient.error"), //$NON-NLS-1$
          Messages.getString("VPNClient.failedToConnect"), ex); //$NON-NLS-1$
      gui.showDisconnected();
      System.exit(4);
    } catch (Throwable t) {
      gui.error(Messages.getString("VPNClient.close"), null, //$NON-NLS-1$
          Messages.getString("VPNClient.error"), //$NON-NLS-1$
          Messages.getString("VPNClient.failedToConnect"), t); //$NON-NLS-1$
      // #ifdef DEBUG
      log.info("Critical failure", t); //$NON-NLS-1$
      // #endif
      gui.showDisconnected();
      System.exit(4);
    }
  }

  public void setupProxy(String localProxyURL, String userAgent,
      String pluginProxyURL) throws MalformedURIException {
    if (localProxyURL != null
        && !localProxyURL.equals("") && !localProxyURL.startsWith("browser://")) { //$NON-NLS-1$ //$NON-NLS-2$
      // Use the user supplied proxy settings

      // #ifdef DEBUG
      log.info("Setting user specified local proxy URL to " + obfuscateURL(localProxyURL)); //$NON-NLS-1$
      // #endif
      setLocalProxyURL(localProxyURL);
    } else {
      // #ifdef DEBUG
      log.info("Attempting to detect proxy settings using platform specific methods"); //$NON-NLS-1$
      // #endif

      if (localProxyURL != null && localProxyURL.startsWith("browser://")) { //$NON-NLS-1$
              
        URI uri = new URI(localProxyURL);

        /*
         * Try to determine the proxy settings by first usng platform /
         * browser specific method, then the proxy supplied by the Java
         * plugin.
         *
         * TODO be more intelligent about which browse to try first -
         * use the userAgent parameter passed from the JSP
         */
        String proxyURL = null;
        if (userAgent != null) {

          // TODO support more browsers

          BrowserProxySettings proxySettings = null;
          if (userAgent.indexOf("MSIE") != -1) { //$NON-NLS-1$
            try {
              // #ifdef DEBUG
              log.info("Looking for IE"); //$NON-NLS-1$
              // #endif
              proxySettings = ProxyUtil.lookupIEProxySettings();
            } catch (Throwable t) {
              // #ifdef DEBUG
              log
                  .error(
                      "Failed to get IE proxy settings, trying Firefox.", t); //$NON-NLS-1$
              // #endif
            }
          }

          if (proxySettings == null
              && userAgent.indexOf("Firefox") != -1) { //$NON-NLS-1$
            try {
              // #ifdef DEBUG
              log.info("Looking for Firefox"); //$NON-NLS-1$
              // #endif
              proxySettings = ProxyUtil
                  .lookupFirefoxProxySettings();
            } catch (Throwable t) {
              // #ifdef DEBUG
              log.error(
                  "Failed to get Firefox proxy settings.", t); //$NON-NLS-1$
              // #endif
            }
          }
          if (proxySettings != null) {
            // #ifdef DEBUG
            log.info("Found some proxy settings."); //$NON-NLS-1$
            // #endif
            ProxyInfo[] proxyInfo = proxySettings.getProxies();
            for (int i = 0; proxyInfo != null
                && i < proxyInfo.length; i++) {
              // #ifdef DEBUG
              log
                  .info("Checking if " + obfuscateURL(proxyInfo[i].toUri()) + " is suitable."); //$NON-NLS-1$
              // #endif
              if (proxyInfo[i].getProtocol().equals("ssl") || proxyInfo[i].getProtocol().equals("https") //$NON-NLS-1$ //$NON-NLS-2$
                  || proxyInfo[i].getProtocol().equals("all")) { //$NON-NLS-1$
                StringBuffer buf = new StringBuffer("http://"); //$NON-NLS-1$
                if (proxyInfo[i].getUsername() != null
                    && !proxyInfo[i].getUsername().equals(
                        "")) { //$NON-NLS-1$
                  buf.append(proxyInfo[i].getUsername());
                  if (proxyInfo[i].getPassword() != null
                      && !proxyInfo[i].getPassword()
                          .equals("")) { //$NON-NLS-1$
                    buf.append(":"); //$NON-NLS-1$
                    buf.append(proxyInfo[i].getPassword());
                  }
                  buf.append("@"); //$NON-NLS-1$
                }
                buf.append(proxyInfo[i].getHostname());
                if (proxyInfo[i].getPort() != 0) {
                  buf.append(":"); //$NON-NLS-1$
                  buf.append(proxyInfo[i].getPort());
                }
                if (uri.getHost() != null) {
                  buf.append("?"); //$NON-NLS-1$
                  buf.append(uri.getHost());
                }
                proxyURL = buf.toString();
                break;
              }
            }
          } else {
            // #ifdef DEBUG
            log
                .warn("No useragent supplied, automatic proxy could not check for browse type."); //$NON-NLS-1$
            // #endif
          }

          // Use the proxy supplied by the plugin if it is
          // available
          if (proxyURL == null && pluginProxyURL != null
              && !pluginProxyURL.equals("")) { //$NON-NLS-1$
            // #ifdef DEBUG
            log.info("Using plugin supplied proxy settings."); //$NON-NLS-1$
            // #endif
            proxyURL = pluginProxyURL;
          }
        }

        if (proxyURL != null) {
          // #ifdef DEBUG
          log
              .info("Setting local proxy URL to " + obfuscateURL(proxyURL) + "."); //$NON-NLS-1$
          // #endif
          setLocalProxyURL(proxyURL);
        }
      }
    }
  }
 


  private void cleanupWindowsAgent() {

    // #ifdef DEBUG
    log.info("Clearing Windows agent cache"); //$NON-NLS-1$
    // #endif

    try {
      String[] cmds = null;

      String homeDir = Utils.getHomeDirectory();

      File cwd = getConfiguration().getCacheDir();
      // #ifdef DEBUG
      log.info("Will remove " + cwd.getAbsolutePath()); //$NON-NLS-1$
      // #endif
      File scriptFile = new File(homeDir, "agent-cleanup.bat");
      File launchFile = new File(homeDir,
          "agent-cleanup-launch.bat");
      String scriptContents = "@echo off\r\n"
          + "echo Agent is removing all downloaded files\r\n"
          + ":Repeat\r\n" + "rd /S /Q \"" + cwd.getAbsolutePath()
          + "\" > NUL 2>&1\r\n" + "if exist \""
          + cwd.getAbsolutePath() + "\" > NUL 2>&1 goto Repeat\r\n";

      File toRemove;
      for (Enumeration e = getConfiguration().getFilesToRemove(); e
          .hasMoreElements();) {
        toRemove = (File) e.nextElement();
        if (toRemove.exists()) {
          if (toRemove.isDirectory()) {
            scriptContents += "rd /S /Q \""
                + toRemove.getAbsolutePath()
                + "\" > NUL 2>&1\r\n";
          } else {
            scriptContents += "del \"" + toRemove.getAbsolutePath()
                + "\" > NUL 2>&1\r\n";
          }
        }
      }
      scriptContents += "del \"" + scriptFile.getAbsolutePath()
          + "\" > NUL 2>&1 && exit\r\n";

      String launchScript = "start \"Agent Cleanup\" /MIN \""
          + scriptFile.getAbsolutePath()
          + "\"\r\n"
          + "del \""
          + launchFile.getAbsolutePath() + "\" > NUL 2>&1\r\n";

      cmds = new String[3];
      cmds[0] = "cmd.exe";
      cmds[1] = "/C";
      cmds[2] = "\"" + launchFile.getAbsolutePath() + "\"";

      FileOutputStream out = new FileOutputStream(scriptFile);
      out.write(scriptContents.getBytes());
      out.close();

      out = new FileOutputStream(launchFile);
      out.write(launchScript.getBytes());
      out.close();

      final Process proc = Runtime.getRuntime().exec(cmds);

      Thread t1 = new Thread(new Runnable() {
        public void run() {
          try {
            InputStream in = proc.getInputStream();
            while (in.read() > -1)
              ;
          } catch (IOException e) {
          }
        }
      }, "CleanupAgentInput");
      Thread t2 = new Thread(new Runnable() {
        public void run() {
          try {
            InputStream in = proc.getErrorStream();
            while (in.read() > -1)
              ;
          } catch (IOException e) {
          }
        }
      }, "CleanupAgentOutput");

      t1.start();
      t2.start();

    } catch (Exception e) {

    }
  }

  /**
   * Schedule a System.exit() in a thread. After the configured shutdown
   * period has elapsed the JVM will terminate.
   */
  public void scheduleExit() {
    Thread t = new Thread("ScheduledExit") {
      public void run() {
        try {
          Thread.sleep(getConfiguration().getShutdownPeriod());
        } catch (InterruptedException ex) {
        }
        gui.dispose();
        // #ifdef DEBUG
        log.info("Exiting JVM."); //$NON-NLS-1$
        // #endif
        System.exit(0);
      }
    };
    t.start();
  }

  private void disconnected() {
    currentState = STATE_DISCONNECTED;
    getGUI().showDisconnected();
  }

  private void disconnectAgent() {

    // #ifdef DEBUG
    log.info("Disconnecting Agent"); //$NON-NLS-1$
    // #endif
    // Disconnect the multiplexed protocol
        keepAlive.stopThread();
    con.disconnect("The agent is shutting down");
    // This is a backup to ensure that the socket is released.
    httpConnection.close();
  }

  private void cleanupLinuxAgent() {

    // #ifdef DEBUG
    log.info("Clearing Linux agent cache"); //$NON-NLS-1$
    // #endif

    try {
      String[] cmds = null;
      String homeDir = Utils.getHomeDirectory();
      File cacheDir = getConfiguration().getCacheDir();
      // #ifdef DEBUG
      log.info("Will remove " + cacheDir.getAbsolutePath()); //$NON-NLS-1$
      // #endif
      File scriptFile = new File(homeDir, "agent-cleanup.sh");
      File launchFile = new File(homeDir,
          "agent-cleanup-launch.sh");

      // clean up script
      StringBuffer scriptContents = new StringBuffer();
      scriptContents.append("#!/bin/sh\n");
      scriptContents.append("sleep 3\n");
      scriptContents.append("rm -fr \"");
      scriptContents.append(cacheDir.getAbsolutePath());
      scriptContents.append("\" \"");

      File toRemove;
      for (Enumeration e = getConfiguration().getFilesToRemove(); e
          .hasMoreElements();) {
        toRemove = (File) e.nextElement();
        scriptContents.append(toRemove.getAbsolutePath());
        scriptContents.append("\" \"");
      }

      scriptContents.append(scriptFile.getAbsolutePath());
      scriptContents.append("\" \"");
      scriptContents.append(launchFile.getAbsolutePath());
      scriptContents.append("\"\n");

      // launch script
      StringBuffer launchScript = new StringBuffer();
      launchScript.append("#!/bin/sh\n");
      launchScript.append("nohup sh \"");
      launchScript.append(scriptFile.getAbsolutePath());
      launchScript.append("\" &\n");

      cmds = new String[2];
      cmds[0] = "sh";
      cmds[1] = launchFile.getAbsolutePath();

      FileOutputStream out = new FileOutputStream(scriptFile);
      out.write(scriptContents.toString().getBytes());
      out.close();

      out = new FileOutputStream(launchFile);
      out.write(launchScript.toString().getBytes());
      out.close();

      final Process proc = Runtime.getRuntime().exec(cmds);

      Thread t1 = new Thread(new Runnable() {
        public void run() {
          try {
            InputStream in = proc.getInputStream();
            while (in.read() > -1)
              ;
          } catch (IOException e) {
          }
        }
      });
      Thread t2 = new Thread(new Runnable() {
        public void run() {
          try {
            InputStream in = proc.getErrorStream();
            while (in.read() > -1)
              ;
          } catch (IOException e) {
          }
        }
      });

      t1.start();
      t2.start();

    } catch (Exception e) {

    }
  }
 
  protected void updateResources(int resourceTypeId) {   
    if (getConfiguration().isGetResources()) {
      /* TODO we should consider moving the services into the appropriate extension instead
       * of all in the agent module. It should now be possible to rewrite them as agent
       * extensions
       */
     
      // Applications
      if(resourceTypeId == -1 || resourceTypeId == ApplicationManager.APPLICATION_SHORTCUT_RESOURCE_TYPE_ID)
        applicationManager.getApplicationResources();
     
      // Tunnels     
      if(resourceTypeId == -1 || resourceTypeId == TunnelManager.TUNNEL_RESOURCE_TYPE_ID)
        tunnelManager.getTunnelResources();
     
      // Web forwards
      if(resourceTypeId == -1 || resourceTypeId == WebForwardManager.WEBFORWARD_RESOURCE_TYPE_ID)
        webForwardManager.getWebForwardResources();
     
      // Network places
      if(resourceTypeId == -1 || resourceTypeId == NetworkPlaceManager.NETWORK_PLACE_RESOURCE_TYPE_ID)
        networkPlaceManager.getNetworkPlaceResources();
    }
  }

  class KeepAliveThread extends Thread {

    boolean running = true;

    Request keepAlive = new Request("keepAlive");

    public void run() {

      long period = getConfiguration().getKeepAlivePeriod();

      if(period > 0) {
        while (running && con.isRunning()) {
          try {
            Thread.sleep(period);
          } catch (InterruptedException e) {
          }
 
          if (!running || !con.isRunning()) {
            break;
          }
 
          try {
            con.sendRequest(keepAlive, true, getConfiguration()
                .getKeepAliveTimeout());
          } catch (InterruptedIOException ex) {
            //#ifdef DEBUG
            log.error("Keepalive packet timed out!! Agent connection is no longer operational", ex);
            //#endif
            if (getConfiguration().isDisplayInformationPopups()) {
              getGUI().popup(
                null,
                Messages.getString("VPNClient.keepalive.timeout"), Messages.getString("VPNClient.title"), "popup-error", -1); //$NON-NLS-1$  //$NON-NLS-2$
            }
            try {
              Thread.sleep(10000);
            } catch (InterruptedException e) {
            }
            Agent.this.startShutdownProcedure();
          } catch (IOException e) {
            //#ifdef DEBUG
            log.error("Keepalive IO error!! Agent connection is no longer operational", e);
            //#endif
            if (getConfiguration().isDisplayInformationPopups()) {
              getGUI().popup(
                null,
                Messages.getString("VPNClient.keepalive.error"), Messages.getString("VPNClient.title"), "popup-error", -1); //$NON-NLS-1$  //$NON-NLS-2$
            }
            try {
              Thread.sleep(10000);
            } catch (InterruptedException e2) {
            }
            Agent.this.startShutdownProcedure();
          }
        }
      }

    }

    public void stopThread() {
      running = false;
      interrupt();
    }
  }
}
TOP

Related Classes of com.adito.agent.client.Agent$KeepAliveThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.