// $Id: ClientStart.java,v 1.31 2001/10/19 12:28:29 ramsdell Exp $
// Copyright (c) 2000. The MITRE Corporation (http://www.mitre.org/).
// All rights reserved.
// The SIMP Service comes with ABSOLUTELY NO WARRANTY.
// See the SIMP Service License Agreement for details.
package org.mitre.sipchat.model;
import java.util.*;
import java.io.*;
import java.net.*;
import javax.swing.SwingUtilities;
import org.mitre.sipchat.util.*;
//import org.mitre.simp.security.SimpSigner;
import org.mitre.sipchat.launcher.RegisterResult;
import org.mitre.sipchat.launcher.SipchatLauncher;
import org.mitre.sipchat.launcher.SipchatProperties;
import org.mitre.jsip.*;
import org.mitre.jsip.event.*;
import org.mitre.sipchat.model.presence.Presentity;
/**
* Implements the login protocol and then starts a client.
* @author John D. Ramsdell
* @author Galen B. Williamson
* @version February 2000
*/
public final class ClientStart
// implements XpListener
{
/**
* The following variable controls whether or not to use the
* workaround for an "incompatibility" with AOL Instant Messenger
* that causes the GUI to "freeze" whenever blocking input is
* performed on standard input while AIM is running on Windows
* NT/2000 machines. Since the Simp client may be running in
* "slave" mode with the Windows helper app, it would be listening
* to standard input, normally using the blocking read operations
* of the BufferedInputStream class. If AIM is running, the
* blocking read operation would lock up the GUI, until standard
* input is closed. The workaround is to extend
* BufferedInputStream, overriding the blocking read methods with
* polling versions. We keep the delay between polls relatively
* long (500ms by default) to keep our CPU usage to a minimum in
* this "busy wait". The new class is
* org.mitre.simp.util.PollingInputStream.
* Set the following variable to false to disable this workaround.
*/
private final static boolean USE_POLLING_INPUT_STREAM_HACK = true;
private final static int CLIENT_MAJOR_VERSION = 1;
private final static int CLIENT_MINOR_VERSION = 2;
private final static String AUTH_MECH_KEY = "simp.auth_mech";
private final static String BASIC_AUTH_MECH = "basic";
private final Presentity me;
// private final XpSocket xps;
// private final SimpSigner signer;
private final RegisterResult result;
private final ClientFactory cf;
// private final XpInputStream xpis;
private final String regarding;
// private ClientStart(IMA me, XpSocket xps,
// SimpSigner signer,
// LoginResult result,
// ClientFactory cf,
// XpInputStream xpis,
// String regarding) {
private ClientStart( Presentity me,
RegisterResult result,
ClientFactory cf,
String regarding ) {
this.me = me;
// this.xps = xps;
// this.signer = signer;
this.result = result;
this.cf = cf;
// this.xpis = xpis;
this.regarding = regarding;
// xps.addXpListener(this);
}
// This method handles the second response of the login protocol.
// public void xpReceived(XpEvent e) {
// xps.removeXpListener(this);
// XmlProperties xp = e.getXp();
// String action = xp.remove(Protocol.ACTION);
// if (Protocol.SELF.equals(action)) {
// result.loginSucceeded(null);
// ClientModel cm = new ClientModel(me, xps, xp, xpis, signer);
// cf.makeClient(cm);
// cm.init();
// if (regarding != null)
// cm.converseWith(regarding);
// }
// else {
// String message = xp.getProperty(Protocol.MESSAGE, "");
// try {
// xps.close();
// if (xpis != null)
// xpis.close();
// }
// catch (IOException ex) { }
// result.loginFailed(message);
// }
// }
public void closed() {
result.registerFailed("Connection closed");
}
/**
* This routine performs the login protocol, creates the client
* given by the client factory, and then runs the communication
* portion of a client.
*/
// public static void login(String user, char[] password,
// String host, SimpSigner signer,
// LoginResult result, ClientFactory cf) {
public static void start( String user, char[] password, String host,
RegisterResult result, ClientFactory cf ) {
// login(user, password, host, signer, result, cf, false);
start( user, password, host, result, cf, false );
}
// public static void start(String user, char[] password,
// String host, SimpSigner signer,
// LoginResult result, ClientFactory cf,
// boolean superUser) {
public static void start( String user, char[] password,
String host, RegisterResult result,
ClientFactory cf, boolean superUser ) {
// attempt to register
try {
register( user, password, host, result, cf );
result.registerSucceeded( "User " + user + " registered on local domain" );
result.showStatus( "You are registered" );
} catch ( Exception e ) {
System.err.println("Error registering: " + e );
e.printStackTrace();
result.registerFailed( "User " + user + " couldn't register on local domain" );
}
// if (user == null || host == null) {
// try { // Read connection info on stdin
// new ClientConnection(signer, result, cf).run();
// }
// catch (IOException iox) {
// result.registerFailed("For standard input: " + iox.getMessage());
// return;
// }
// }
// else { // Login directly to server
// XmlProperties resp;
// try {
// XmlProperties req = Protocol.login(user);
// if (superUser)
// req.setProperty(Protocol.PASSWORD, "true");
// resp = HostPost.post(host, req);
// connect(user, password, host, signer, result, cf, resp, null);
// }
// catch (ConnectException iox) {
// result.loginFailed("Failed to connect to host");
// return;
// }
// catch (NoRouteToHostException iox) {
// result.loginFailed("Failed to find route to host");
// return;
// }
// catch (IOException iox) {
// result.loginFailed(iox.getMessage());
// return;
// }
// catch (Throwable t) {
// result.loginFailed(t.getMessage());
// t.printStackTrace();
// return;
// }
// finally {
// if (password != null)
// for (int i = 0; i < password.length; i++)
// password[i] = 0;
// }
// }
}
private static void register( String user, char[] password,
String host, RegisterResult result,
ClientFactory cf ) {
Presentity me = new Presentity( user );
SipClient client = SipClient.getSipClient();
// set the IM capabilities in the SIP library
client.setContactCapabilities( SipUri.METHOD_SUBSCRIBE |
SipUri.METHOD_MESSAGE );
client.setDefaultUserMode( true );
SipUser myUser = new SipUser( client, me );
// Create the model
ClientModel cm = new ClientModel( me, null );
cf.makeClient( cm );
cm.init();
final SipRegister regServer = myUser.addServer( host );
// set up a listener for call events
CallListener regCallListener = new CallListener() {
public void responseReceived( CallEvent ce) {
System.out.println( "REGCALLLISTENER activated" );
SipResponseMessage respMessage = (SipResponseMessage) ce.getMessage();
if ( respMessage.getStatus().getCode() == 401 ) {
try {
regServer.setAuthentication( respMessage );
} catch ( RegisterException re ) {
System.err.println( re.toString() );
}
try {
regServer.requestRegister( false );
} catch ( RegisterException re ) {
System.err.println("Error registering" );
return;
}
} else if ( respMessage.getStatus().getCode() == 200 ) {
// everything's ok. Remove this listener
SipClient sc = SipClient.getSipClient();
// remove this listener
sc.removeCallListener( this );
}
}
public void requestReceived( CallEvent ce ) {}
};
client.addCallListener( regCallListener );
try {
regServer.requestRegister( new String( password ) );
} catch ( RegisterException re ) {
System.err.println("Error registering with password" );
}
// set this user as the default user
client.setDefaultUser( myUser );
}
// private static void connect(String user, char[] password,
// String host, SimpSigner signer,
// LoginResult result, ClientFactory cf,
// XmlProperties resp, XpInputStream xpis) {
// SimpProperties props = SimpLauncher.getSimpProperties();
// boolean basic = false;
// if (props != null) {
// String authMech = props.getProperty(AUTH_MECH_KEY);
// basic = password != null && BASIC_AUTH_MECH.equals(authMech);
// }
// XpSocket xps;
// try {
// host = resp.getProperty(Protocol.HOST, host);
// IMA ima = new IMA(user, host);
// String action = resp.getProperty(Protocol.ACTION);
// String nonce = resp.getProperty(Protocol.NONCE);
// String opaque = resp.getProperty(Protocol.OPAQUE);
// String auth = resp.getProperty(Protocol.AUTHORIZATION);
// String alg = resp.getProperty(Protocol.ALGORITHM, "MD5");
// String p = resp.getProperty(Protocol.PORT);
// String regarding = resp.remove(Protocol.REGARDING);
// if (!Protocol.CHALLENGE.equals(action)
// || nonce == null
// || opaque == null
// || alg == null
// || p == null) {
// String msg = resp.getProperty(Protocol.MESSAGE,
// "Login protocol error");
// result.loginFailed(msg);
// return;
// }
// int port = 0;
// if (p != null) {
// try {
// port = Integer.parseInt(p);
// }
// catch (NumberFormatException nfe) { }
// }
// if (port <= 0) {
// result.loginFailed("Bad port " + p);
// return;
// }
// Authorization authorization = null;
// try {
// authorization = new Authorization(alg);
// }
// catch (java.security.NoSuchAlgorithmException nsae) {
// result.loginFailed("Digest algorithm " + alg + " missing");
// return;
// }
// try {
// if (!basic && auth == null)
// auth = authorization.getAuthorization(user.toLowerCase(),
// password,
// nonce);
// }
// catch (UnsupportedEncodingException uee) {
// result.loginFailed("Unsupported encoding in login");
// return;
// }
// catch (IOException iox) {
// result.loginFailed("I/O exception in login");
// return;
// }
// Socket s = new Socket(host, port);
// xps = new XpSocket(s);
// // Build and send the second request of the login protocol.
// XmlProperties conn;
// if (basic)
// conn = Protocol.connect(password, opaque,
// CLIENT_MAJOR_VERSION,
// CLIENT_MINOR_VERSION);
// else
// conn = Protocol.connect(auth, opaque,
// CLIENT_MAJOR_VERSION,
// CLIENT_MINOR_VERSION);
// auth = null;
// xps.write(conn);
// conn = null;
// // The second response of the login protocol is handled
// // by this object.
// new ClientStart(ima, xps, signer, result, cf, xpis, regarding);
// }
// catch (UnknownHostException ue) {
// result.loginFailed("Host not known");
// return;
// }
// catch (MalformedURLException ex) {
// result.loginFailed("Address invalid");
// return;
// }
// catch (ConnectException iox) {
// result.loginFailed("Failed to connect to host");
// return;
// }
// catch (NoRouteToHostException iox) {
// result.loginFailed("Failed to find route to host");
// return;
// }
// catch (Throwable t) {
// result.loginFailed(t.getMessage());
// t.printStackTrace();
// return;
// }
// finally {
// if (password != null)
// for (int i = 0; i < password.length; i++)
// password[i] = 0;
// }
// xps.run();
// }
// private static class ClientConnection
// implements XpListener, Runnable
// {
// private final SimpSigner signer;
// private final LoginResult result;
// private final ClientFactory cf;
// private final XpInputStream xpis;
// ClientConnection(SimpSigner signer,
// LoginResult result,
// ClientFactory cf)
// throws IOException
// {
// this.signer = signer;
// this.result = result;
// this.cf = cf;
// if (USE_POLLING_INPUT_STREAM_HACK) {
// xpis = new XpInputStream(new PollingInputStream(System.in, 500));
// }
// else {
// xpis = new XpInputStream(System.in);
// }
// xpis.addXpListener(this);
// }
// // This method starts up the second response of the login protocol.
// public void xpReceived(XpEvent e) {
// xpis.removeXpListener(this);
// final XmlProperties xp = e.getXp();
// final String user = xp.remove(Protocol.USER);
// if (user != null) {
// Thread t = new Thread(new Runnable() {
// public void run() {
// connect(user, null, null, signer,
// result, cf, xp, xpis);
// }
// });
// t.start();
// }
// else {
// String message = xp.getProperty(Protocol.MESSAGE,
// "User name missing");
// result.loginFailed(message);
// try {
// xpis.close();
// }
// catch (IOException iox) { }
// }
// }
// public void closed() {
// result.loginFailed("Standard input closed");
// }
// public void run() {
// xpis.run();
// }
// }
}