/*
* (c) 2000-2009 Carlos G�mez Rodr�guez, todos los derechos reservados / all rights reserved.
* Licencia en license/bsd.txt / License in license/bsd.txt
*/
package eu.irreality.age.telnet;
import java.util.*;
import java.net.*;
import java.io.*;
import eu.irreality.age.StringMethods;
import eu.irreality.age.World;
import eu.irreality.age.i18n.UIMessages;
import eu.irreality.age.server.PartidaEnCurso;
public class SimpleTelnetClientHandler extends Thread {
private static Vector activeClients;
private int maxClients;
//private World mundo;
private List /*of PartidaEnCurso*/ partidas;
int clientCount;
private short thePort;
public SimpleTelnetClientHandler( short port )
{
System.out.println("SimpleTelnetClientHandler started.");
partidas = new Vector();
thePort = port;
setPriority(Thread.MIN_PRIORITY);
start();
}
public SimpleTelnetClientHandler ( World w , int maxPlayers , short port ) //this seems to never be called as of 2011-11-10.
{
System.out.println("SimpleTelnetClientHandler started.");
thePort = port;
//mundo = w;
partidas = new Vector();
addPartida ( new PartidaEnCurso ( w , maxPlayers , "Nombre de Partida" , null ) );
maxClients = maxPlayers;
setPriority(Thread.MIN_PRIORITY);
start();
}
public synchronized void addPartida ( PartidaEnCurso pec )
{
System.out.println("ADDDDDDDDDDDDING GAME");
partidas.add ( pec );
}
public synchronized int getClientCount()
{
return clientCount;
}
public synchronized void incClientCount()
{
clientCount++;
}
public synchronized int getAndIncClientCount()
{
clientCount++;
return ( clientCount-1 );
}
//coge las partidas en curso, protegida de accesos concurrentes
public synchronized List getPartidasEnCurso()
{
Vector result = new Vector();
for ( int i = 0 ; i < partidas.size() ; i++ )
{
result.add ( partidas.get(i) );
}
return result;
}
public void run()
{
activeClients = new Vector();
clientCount = 1;
try
{
ServerSocket s = new ServerSocket ( thePort );
for (;;)
{
final Socket incoming = s.accept();
//hacer un fork, porque la selecci�n de mundo, etc. tiene esperas, y mientras tenemos que poder atender a otros clientes
Thread th = new Thread()
{
public void run()
{
int ccount = getAndIncClientCount(); //synchronized
System.out.println("Spawnin' client proxy " + ccount );
SimpleTelnetClientSelector stcs = new SimpleTelnetClientSelector ( incoming , ccount );
PartidaEnCurso pec = stcs.getPartidaSelection( getPartidasEnCurso() );
World mundo = pec.getMundo();
if ( mundo == null ) return;
SimpleTelnetClientProxy stpc = new SimpleTelnetClientProxy ( incoming , ccount , mundo );
activeClients.addElement ( stpc );
}
};
th.start();
}
}
catch (IOException ioe )
{
System.out.println("Exception on accepting socket.\n");
ioe.printStackTrace();
}
}
}
//obtiene las opciones del cliente.
class SimpleTelnetClientSelector implements TelnetConstants
{
private InputStream is;
private OutputStream os;
private BufferedReader in;
private PrintWriter out;
private Socket incoming;
private int id;
public SimpleTelnetClientSelector ( java.net.Socket s , int id )
{
this.incoming = s;
this.id = id;
try
{
if (incoming != null)
{
in = new BufferedReader(new InputStreamReader((is=incoming.getInputStream())));
out = new PrintWriter(new OutputStreamWriter((os=incoming.getOutputStream())));
}
}
catch (Exception e)
{
System.out.println("Error: " + e);
}
}
public boolean checkForANSISupport ( ) throws IOException //BLOCKING CALL
{
//the telnet negotiations which check for ANSI support!!
boolean terminamos = false;
int tries = 10;
//ask for terminal-type negotiation
os.write ( IAC );
os.write ( DO );
os.write ( TELOPT_TTYPE );
for(;!terminamos;)
{
System.out.println("Iteration.");
int abyte = is.read();
if ( tries == 0 ) terminamos = true;
if ( abyte == -1 ) break;
if ( abyte == IAC )
{
System.out.println("IAC.");
int bbyte = is.read();
switch ( bbyte )
{
case WILL:
System.out.println("WILL.");
int cbyte = is.read();
if ( cbyte == TELOPT_TTYPE )
{
//aceptan negociar terminal type!
//pedimos tipos de terminal...
os.write ( IAC );
os.write ( SB );
os.write ( TELOPT_TTYPE );
os.write ( TEL_QUAL_SEND );
os.write ( IAC );
os.write ( SE );
//otra iteraci�n para SB
}
break;
case WONT:
System.out.println("WONT.");
int cbyte2 = is.read();
if ( cbyte2 == TELOPT_TTYPE )
{
System.out.println("TELOPT_TTYPE.");
escribir("Your telnet client refuses negotiating terminal types.\n");
terminamos = true;
}
break;
case SB: //subnegotiation begin
System.out.println("SB.");
int cbyte3 = is.read();
if ( cbyte3 == TELOPT_TTYPE )
{
byte[] buf = new byte[100];
int i = 0;
int c;
is.skip(1); //IS
while ( (c=is.read()) != IAC && i < 99 )
{
buf[i] = (byte)c;
i++;
}
buf[i] = '\0';
String termTypeString = new String ( buf );
System.out.println("TERMTYPESTRING:"+termTypeString+"\n");
if ( termTypeString.equalsIgnoreCase("ansi") || termTypeString.equalsIgnoreCase("vt100") || termTypeString.equalsIgnoreCase("xterm") || termTypeString.equalsIgnoreCase("vt320") || termTypeString.equalsIgnoreCase("mushclient") || termTypeString.equalsIgnoreCase("zmud") )
{
escribir("ANSI support detected (" + termTypeString + ")\n");
return true;
}
else
{
//pedir otra terminal
os.write ( IAC );
os.write ( SB );
os.write ( TELOPT_TTYPE );
os.write ( TEL_QUAL_SEND );
os.write ( IAC );
os.write ( SE );
//otra iteraci�n para SB y procesar subnegotiation
tries--;
}
}
default: break;
}
}
}
return false;
}
//do
public void escribir ( String s )
{
if ( out != null )
{
System.out.print("Systemoutprinting:"+s);
//print with LF -> CRLF substitution!
out.print( StringMethods.textualSubstitution ( s , "\n" , "\n\r" ) );
out.flush();
}
}
//selector input is always synchronous.
public String getInput ( )
{
try
{
//escribir("> ");
String str = in.readLine();
System.out.println("INPUT GOTTEN: " + str );
return str;
}
catch ( IOException ioe )
{
System.out.println("Oh yeppie, en �i Ou Excepxen.\n");
return null;
}
}
public PartidaEnCurso getPartidaSelection( List partidas )
{
//aqu� parafernalia del men�
if ( partidas.size() < 1 )
{
escribir(UIMessages.getInstance().getMessage("server.no.games")+"\n");
return null;
}
if ( partidas.size() == 1 )
{
//autoseleccionar la �nica que hay
PartidaEnCurso pec = (PartidaEnCurso) partidas.get(0);
if ( pec.getPlayers() >= pec.getMaxPlayers() )
{
; //como si hubiera varias partidas, mostrar men�
}
else
{
return pec;
}
}
//c�digo para m�s de una partida en curso:
boolean done = false;
while ( !done )
{
escribir(UIMessages.getInstance().getMessage("server.active.games")+"\n");
for ( int i = 0 ; i < partidas.size() ; i++ )
{
PartidaEnCurso pec = (PartidaEnCurso) partidas.get(i);
escribir ( (i+1) + ". " + pec.getNombre() + " " + "(" + pec.getPlayers() + "/" + pec.getMaxPlayers() + ")" );
escribir ( "\n" );
}
escribir(UIMessages.getInstance().getMessage("server.enter.game.number") + " ");
String linea = getInput();
if ( linea == null ) return null; //exc
int part = -1;
try
{
part = Integer.valueOf ( linea ).intValue();
}
catch ( NumberFormatException nfe )
{
;
}
if ( part > 0 && part <= partidas.size() )
{
PartidaEnCurso p = (PartidaEnCurso) partidas.get(part-1);
if ( p.getPlayers() < p.getMaxPlayers() )
return p;
else
escribir(UIMessages.getInstance().getMessage("server.player.limit.hit") + "\n");
}
}
return null;
}
}