package com.planet_ink.coffee_mud.core.intermud.i3.packets;
import com.planet_ink.coffee_mud.core.intermud.imc2.*;
import com.planet_ink.coffee_mud.core.intermud.i3.packets.*;
import com.planet_ink.coffee_mud.core.intermud.i3.persist.*;
import com.planet_ink.coffee_mud.core.intermud.i3.server.*;
import com.planet_ink.coffee_mud.core.intermud.i3.net.*;
import com.planet_ink.coffee_mud.core.intermud.*;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.core.CMSecurity.DbgFlag;
import com.planet_ink.coffee_mud.core.collections.*;
import com.planet_ink.coffee_mud.Abilities.interfaces.*;
import com.planet_ink.coffee_mud.Areas.interfaces.*;
import com.planet_ink.coffee_mud.Behaviors.interfaces.*;
import com.planet_ink.coffee_mud.CharClasses.interfaces.*;
import com.planet_ink.coffee_mud.Commands.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.*;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.ChannelsLibrary;
import com.planet_ink.coffee_mud.Libraries.interfaces.ChannelsLibrary.CMChannel;
import com.planet_ink.coffee_mud.Libraries.interfaces.ChannelsLibrary.ChannelFlag;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;
import java.io.*;
import java.net.Socket;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
/**
* The Intermud class is the central focus of incoming
* and outgoing Intermud 3 packets. It creates the link
* to the I3 router, handles reconnection, and routing
* of packets to the mudlib. The mudlib is responsible
* for providing two specific objects to interface with
* this object:
* an implementation of com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices
* an implementation of com.planet_ink.coffee_mud.core.intermud.i3.persist.PersistentPeer
* To start up the Intermud connection, call the class
* method setup().
* The class itself creates an instance of itself and
* serves as a way to interface to the rest of the mudlib.
* When the mudlib needs to send a packet, it sends it
* through a class method which then routes it to the
* proper instance of Intermud.
* @author George Reese
* @version 1.0
* @see com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices
* @see com.planet_ink.coffee_mud.core.intermud.i3.persist.PersistentPeer
*/
@SuppressWarnings({"unchecked","rawtypes"})
public class Intermud implements Runnable, Persistent, Serializable
{
public static final long serialVersionUID=0;
static private Intermud thread = null;
/**
* Sends a packet to the router. The packet must
* be a valid subclass of com.planet_ink.coffee_mud.core.intermud.i3.packets.Packet.
* This method will then route the packet to the
* currently running Intermud instance.
* @param p an instance of a subclass of com.planet_ink.coffee_mud.core.intermud.i3.packets.Packet
* @see com.planet_ink.coffee_mud.core.intermud.i3.packets.Packet
*/
static public void sendPacket(Packet p)
{
if(!isConnected())
return;
thread.send(p);
}
/**
* Creates the initial link to an I3 router.
* It will handle subsequent reconnections as needed
* for as long as the mud process is running.
* @param imud an instance of the mudlib implementation of com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices
* @param peer and instance of the mudlib implementation of com.planet_ink.coffee_mud.core.intermud.i3.packets.IntermudPeer
* @see com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices
* @see com.planet_ink.coffee_mud.core.intermud.i3.persist.PersistentPeer
*/
static public void setup(ImudServices imud, PersistentPeer peer)
{
if( thread != null )
{
return;
}
thread = new Intermud(imud, peer);
}
/**
* Translates a user entered mud name into the mud's
* canonical name.
* @param mud the user entered mud name
* @return the specified mud's canonical name
*/
static public String translateName(String mud)
{
if(!isConnected())
return "";
final String s=thread.getMudNameFor(mud);
if(s!=null)
return s;
mud = mud.toLowerCase().replace('.', ' ');
return mud;
}
/**
* Translates a user entered mud name into the mud's
* canonical name.
* @param mud the user entered mud name
* @return the specified mud's canonical name
*/
static public boolean isAPossibleMUDName(String mud)
{
if(!isConnected())
return false;
return thread.getMudNameFor(mud) != null;
}
/**
* Register a fake channel
* @param c the remote channel name
* @return the local channel name for the specified new local channel name
* @see com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices#getLocalChannel
*/
static public String registerFakeChannel(String c)
{
if((!isConnected())||(thread.intermud.getLocalChannel(c).length()>0))
return "";
String name=c.toUpperCase();
final int x=1;
while(thread.intermud.getRemoteChannel(name).length()>0)
name=c.toUpperCase()+x;
final CMChannel chan=CMLib.channels().createNewChannel(name, c, "", "+FAKE", new HashSet<ChannelFlag>(), "","");
if(thread.intermud.addChannel(chan))
return chan.name();
return "";
}
/**
* Register a fake channel
* @param c the remote channel name
* @return the local channel name for the specified new local channel name
* @see com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices#getLocalChannel
*/
static public String removeFakeChannel(String c)
{
if((!isConnected())||(thread.intermud.getLocalChannel(c).length()==0))
return "";
final String mask=thread.intermud.getRemoteMask(c);
final String name=thread.intermud.getLocalChannel(c);
if((mask.equalsIgnoreCase("+FAKE"))
&&(thread.intermud.delChannel(c)))
return name;
return "";
}
/**
* Returns a String representing the local channel
* name for the specified remote channel by
* calling the ImudServices implementation of
* getLocalChannel().
* @param c the remote channel name
* @return the local channel name for the specified remote channel name
* @see com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices#getLocalChannel
*/
static public String getLocalChannel(String c )
{
if(!isConnected())
return "";
return thread.intermud.getLocalChannel(c);
}
/**
* Returns a String representing the remote channel
* name for the specified local channel by
* calling the ImudServices implementation of
* getRemoteChannel().
* @param c the local channel name
* @return the remote channel name for the specified local channel name
* @see com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices#getRemoteChannel
*/
static public String getRemoteChannel(String c)
{
if(!isConnected())
return "";
return thread.intermud.getRemoteChannel(c);
}
/**
* Determines whether or not the specified mud is up.
* You may pass user entered mud names, as this method
* will take the time to convert to a canonical name.
* @param mud the name of the mud being checked
* @return true if the mud is currently up, false otherwise
*/
static public boolean isUp(String mud)
{
if(!isConnected())
return false;
final I3Mud m = thread.getMud(mud);
if( m == null )
return false;
return (m.state == -1);
}
private volatile long lastPingSentTime;
private boolean connected;
private Socket connection;
private Thread input_thread;
private ImudServices intermud;
private int modified;
private DataOutputStream output;
private PersistentPeer peer;
private Tickable save_thread;
public boolean shutdown=false;
public DataInputStream input;
public int attempts;
public Hashtable banned;
public ChannelList channels;
public MudList muds;
public List<NameServer> name_servers;
public int password;
public NameServer currentRouter;
private Intermud(final ImudServices imud, PersistentPeer p)
{
super();
intermud = imud;
peer = p;
peer.setPersistent(this);
connected = false;
password = -1;
attempts = 0;
input_thread = null;
channels = new ChannelList(-1);
muds = new MudList(-1);
banned = new Hashtable();
name_servers = new Vector();
String s=CMProps.getVar(CMProps.Str.I3ROUTERS);
final List<String> V=CMParms.parseCommas(s,true);
for(int v=0;v<V.size();v++)
{
s=V.get(v);
final List<String> V2=CMParms.parseAny(s,':',true);
if(V2.size()>=3)
name_servers.add(new NameServer(V2.get(0),CMath.s_int(V2.get(1)), V2.get(2)));
}
modified = Persistent.UNMODIFIED;
try
{
restore();
}
catch( final PersistenceException e )
{
password = -1;
Log.errOut("Intermud",e);
}
channels = new ChannelList(-1);
muds = new MudList(-1);
if((save_thread==null)||(!CMLib.threads().isTicking(save_thread, Tickable.TICKID_SUPPORT)))
{
save_thread=CMLib.threads().startTickDown(new Tickable()
{
private final int tickStatus=Tickable.STATUS_NOT;
@Override public String ID() { return "I3SaveTick"+Thread.currentThread().getThreadGroup().getName().charAt(0); }
@Override public CMObject newInstance() { return this; }
@Override public CMObject copyOf() { return this; }
@Override public void initializeClass() { }
@Override public int compareTo(CMObject o) { return (o==this)?0:1; }
@Override public String name() { return ID(); }
@Override public int getTickStatus() { return tickStatus; }
@Override public boolean tick(Tickable ticking, int tickID)
{
try
{
if(CMSecurity.isDisabled(CMSecurity.DisFlag.I3))
{
lastPingSentTime=System.currentTimeMillis();
return !shutdown;
}
else
{
final long ellapsedTime = System.currentTimeMillis()-imud.getLastPacketReceivedTime();
if(ellapsedTime>(60 * 60 * 1000)) // one hour
{
Log.errOut("I3SaveTick","No I3 response received in "+CMLib.time().date2EllapsedTime(ellapsedTime, TimeUnit.MILLISECONDS, false)+". Connected="+Intermud.isConnected());
CMLib.threads().executeRunnable(new Runnable()
{
@Override
public void run()
{
try
{
imud.resetLastPacketReceivedTime();
I3Server.shutdown();
CMLib.hosts().get(0).executeCommand("START I3");
Log.errOut("I3SaveTick","Restarted your Intermud system. To stop receiving these messages, DISABLE the I3 system.");
}
catch(final Exception e){}
}
});
}
}
save();
}
catch( final PersistenceException e )
{
}
return !shutdown;
}
}, Tickable.TICKID_SUPPORT, 30).getClientObject();
}
connect();
}
// Handles an incoming channel list packet
private synchronized void channelList(Vector packet)
{
final Hashtable list = (Hashtable)packet.elementAt(7);
final Enumeration keys = list.keys();
synchronized( channels )
{
channels.setChannelListId(((Integer)packet.elementAt(6)).intValue());
while( keys.hasMoreElements() )
{
final Channel c = new Channel();
Object ob;
c.channel = (String)keys.nextElement();
ob = list.get(c.channel);
if( ob instanceof Integer )
{
removeChannel(c);
}
else
{
final Vector info = (Vector)ob;
c.owner = (String)info.elementAt(0);
if(info.elementAt(1) instanceof Integer)
c.type = ((Integer)info.elementAt(1)).intValue();
else
if(info.elementAt(1) instanceof List)
Log.errOut("InterMud","Received unexpected channel-reply: " + CMParms.toListString((List)info.elementAt(1)));
addChannel(c);
}
}
}
modified = Persistent.MODIFIED;
}
public static NameServer getNameServer()
{
if(thread==null)
return null;
if(thread.currentRouter!=null)
return thread.currentRouter;
if(thread.name_servers==null)
return null;
if(thread.name_servers.size()==0)
return null;
return thread.name_servers.get(0);
}
private synchronized void connect()
{
if(shutdown)
return;
attempts++;
try
{
if(name_servers.size()==0)
Log.sysOut("Intermud3","No I3 routers defined in coffeemud.ini file.");
else
{
if(CMProps.getVar(CMProps.Str.ADMINEMAIL).indexOf('@')<0)
Log.errOut("Intermud","Please set ADMINEMAIL in your coffeemud.ini file.");
final Vector connectionStatuses=new Vector(name_servers.size());
for(int i=0;i<name_servers.size();i++)
{
currentRouter = name_servers.get(i);
try
{
connection = new Socket(currentRouter.ip, currentRouter.port);
output = new DataOutputStream(connection.getOutputStream());
send("({\"startup-req-3\",5,\"" + intermud.getMudName() + "\",0,\"" +
currentRouter.name + "\",0," + password +
"," + muds.getMudListId() + "," + channels.getChannelListId() + "," + intermud.getMudPort() +
",0,0,\""+intermud.getMudVersion()+"\",\""+intermud.getMudVersion()+"\",\""+intermud.getMudVersion()+"\",\"CoffeeMud\"," +
"\""+intermud.getMudState()+"\",\""+CMProps.getVar(CMProps.Str.ADMINEMAIL).toLowerCase()+"\",([" +
"\"who\":1,\"finger\":1,\"channel\":1,\"tell\":1,\"locate\":1,\"auth\":1,]),([]),})");
}
catch(final java.io.IOException e)
{
connectionStatuses.addElement(currentRouter.ip+": "+currentRouter.port+": "+e.getMessage());
continue;
}
connected = true;
input_thread = new Thread(Thread.currentThread().getThreadGroup(),this);
input_thread.setDaemon(true);
input_thread.setName(("I3Client:"+currentRouter.ip+"@"+currentRouter.port));
input_thread.start();
final Enumeration e = intermud.getChannels();
while( e.hasMoreElements() )
{
final String chan = (String)e.nextElement();
send("({\"channel-listen\",5,\"" + intermud.getMudName() + "\",0,\"" +
currentRouter.name + "\",0,\"" + chan + "\",1,})");
}
Log.sysOut("Intermud3","I3 client connection: "+currentRouter.ip+"@"+currentRouter.port);
break;
}
if(!connected)
for(int e=0;e<connectionStatuses.size();e++)
Log.errOut("Intermud",(String)connectionStatuses.elementAt(e));
}
}
catch( final Exception e )
{
try { Thread.sleep((attempts) * 100l); }
catch( final InterruptedException ignore )
{
if(shutdown)
{
Log.sysOut("Intermud","Shutdown!");
return;
}
}
connect();
}
}
// Handles an incoming error packet
private synchronized void error(Vector packet)
{
final Object target = packet.elementAt(5);
final String msg = (String)packet.elementAt(7);
if( target instanceof Integer )
{
I3Exception e;
e = new I3Exception(msg);
final String cmd=e.getMessage();
if(cmd!=null)
{
Log.errOut("InterMud","276-"+cmd);
}
}
else
{
}
}
private synchronized void mudlist(Vector packet)
{
Hashtable list;
Enumeration keys;
synchronized( muds )
{
muds.setMudListId(((Integer)packet.elementAt(6)).intValue());
list = (Hashtable)packet.elementAt(7);
keys = list.keys();
while( keys.hasMoreElements() )
{
final I3Mud mud = new I3Mud();
Object info;
mud.mud_name = (String)keys.nextElement();
info = list.get(mud.mud_name);
if( info instanceof Integer )
{
removeMud(mud);
}
else
{
final Vector v = (Vector)info;
int total=0;
for(int vi=0;vi<v.size();vi++)
if(v.elementAt(vi) instanceof String)
total+=((String)v.elementAt(vi)).length();
if(total<1024)
{
mud.state = ((Integer)v.elementAt(0)).intValue();
mud.address = (String)v.elementAt(1);
mud.player_port = ((Integer)v.elementAt(2)).intValue();
mud.tcp_port = ((Integer)v.elementAt(3)).intValue();
mud.udp_port = ((Integer)v.elementAt(4)).intValue();
mud.mudlib = (String)v.elementAt(5);
mud.base_mudlib = (String)v.elementAt(6);
mud.driver = (String)v.elementAt(7);
mud.mud_type = (String)v.elementAt(8);
mud.status = (String)v.elementAt(9);
mud.admin_email = (String)v.elementAt(10);
addMud(mud);
}
}
}
}
}
// Hashtable services = (Hashtable)v.elementAt(11);
// Hashtable other_info = (Hashtable)v.elementAt(12);
@Override
public void restore() throws PersistenceException {
if( modified != Persistent.UNMODIFIED )
{
throw new PersistenceException("Restoring over changed data.");
}
peer.restore();
modified = Persistent.UNMODIFIED;
}
public static boolean isConnected()
{
if(thread==null)
return false;
return thread.connected;
}
public void logMemory()
{
try
{
System.gc();
Thread.sleep(1500);
}catch(final Exception e){}
final long free=Runtime.getRuntime().freeMemory()/1024;
final long total=Runtime.getRuntime().totalMemory()/1024;
Log.errOut("Intermud", "Memory usage: "+(total-free)+"kb");
}
@Override
public void run()
{
try
{
connection.setSoTimeout(60000);
input = new DataInputStream(connection.getInputStream());
}
catch( final java.io.IOException e )
{
input = null;
connected = false;
}
lastPingSentTime = System.currentTimeMillis();
while( connected && (!shutdown))
{
Vector data;
try { Thread.sleep(100); }
catch( final InterruptedException e )
{
if(shutdown)
{
Log.sysOut("Intermud","Shutdown!!");
return;
}
}
if(CMSecurity.isDisabled(CMSecurity.DisFlag.I3))
{
continue;
}
else
if((!shutdown) && (System.currentTimeMillis()-lastPingSentTime)>( 30 * 60 * 1000))
{
lastPingSentTime=System.currentTimeMillis();
try { new MudAuthRequest(I3Server.getMudName()).send(); } catch(final Exception e) { }
final long ellapsedTime = System.currentTimeMillis() - intermud.getLastPacketReceivedTime();
if(ellapsedTime>(60 * 60 * 1000)) // one hour
{
Log.errOut("Intermud","No I3 Ping received in "+CMLib.time().date2EllapsedTime(ellapsedTime, TimeUnit.SECONDS, false)+". Connected="+Intermud.isConnected());
CMLib.threads().executeRunnable(new Runnable()
{
@Override
public void run()
{
try
{
//logMemory();
I3Server.shutdown();
CMLib.hosts().get(0).executeCommand("START I3");
Log.errOut("Intermud","Restarted your Intermud system. To stop receiving these messages, DISABLE the I3 system.");
}
catch(final Exception e){}
}
});
}
}
String cmd;
try
{
int len=0;
while(!shutdown)
{
try
{ // please don't compress this again
len = input.readInt();
break;
}
catch(final java.io.IOException e)
{
if((e.getMessage()==null)||(e.getMessage().toUpperCase().indexOf("TIMED OUT")<0))
throw e;
CMLib.s_sleep(1000);
continue;
}
}
if(len>65536)
{
int skipped=0;
try
{ // please don't compress this again
while(skipped<len)
skipped+=input.skipBytes(len);
}
catch( final java.io.IOException e ) {}
Log.errOut("Intermud","Got illegal packet: "+skipped+"/"+len+" bytes.");
continue;
}
final byte[] tmp = new byte[len];
final long startTime=System.currentTimeMillis();
while(!shutdown)
{
try
{ // please don't compress this again
input.readFully(tmp);
break;
}
catch(final java.io.IOException e)
{
if((e.getMessage()==null)||(e.getMessage().toUpperCase().indexOf("TIMED OUT")<0))
throw e;
CMLib.s_sleep(1000);
if((System.currentTimeMillis()-startTime)>(10 * 60 * 1000))
throw e;
Log.errOut("Intermud","Timeout receiving packet sized "+len);
continue;
}
}
cmd=new String(tmp);
}
catch( final java.io.IOException e )
{
data = null;
cmd = null;
connected = false;
try { Thread.sleep(1200); }
catch (final InterruptedException ee)
{
if(shutdown)
{
Log.sysOut("Intermud","Shutdown!!!");
return;
}
}
connect();
final String errMsg=e.getMessage()==null?e.toString():e.getMessage();
if(errMsg!=null)
Log.errOut("InterMud","384-"+errMsg);
return;
}
try
{
if(CMSecurity.isDebugging(CMSecurity.DbgFlag.I3))
Log.sysOut("Intermud","Receiving: "+cmd);
final Object o=LPCData.getLPCData(cmd);
if(o instanceof Vector)
data=(Vector)o;
else
{
Log.errOut("InterMud","390-"+o);
continue;
}
}
catch( final I3Exception e )
{
final String errMsg=e.getMessage()==null?e.toString():e.getMessage();
if(errMsg!=null)
Log.errOut("InterMud","389-"+errMsg);
continue;
}
// Figure out the packet type and send it to the mudlib
final String type = (String)data.elementAt(0);
if( type.equals("channel-m") || type.equals("channel-e") || type.equals("channel-t") )
{
try
{
final ChannelPacket p = new ChannelPacket(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud","0-"+e.getMessage());
}
}
else if( type.equals("chan-who-req") )
{
try
{
final ChannelWhoRequest p = new ChannelWhoRequest(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("chan-user-req") )
{
try
{
final ChannelUserRequest p = new ChannelUserRequest(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("channel-add") )
{
try
{
final ChannelAdd p = new ChannelAdd(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("channel-remove") )
{
try
{
final ChannelDelete p = new ChannelDelete(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("channel-listen") )
{
try
{
final ChannelListen p = new ChannelListen(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("chan-who-reply") )
{
try
{
final ChannelWhoReply p = new ChannelWhoReply(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("chan-user-reply") )
{
try
{
final ChannelUserReply p = new ChannelUserReply(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("chanlist-reply") )
{
channelList(data);
}
else if( type.equals("locate-reply") )
{
try
{
final LocateReplyPacket p = new LocateReplyPacket(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("finger-reply") )
{
try
{
final FingerReply p = new FingerReply(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("finger-req") )
{
try
{
final FingerRequest p = new FingerRequest(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("locate-req") )
{
try
{
final LocateQueryPacket p = new LocateQueryPacket(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("mudlist") )
{
mudlist(data);
}
else if( type.equals("startup-reply") )
{
startupReply(data);
}
else if( type.equals("tell") )
{
try
{
final TellPacket p = new TellPacket(data);
intermud.receive(p);
}
catch( final InvalidPacketException e )
{
Log.errOut("Intermud",type+"-"+e.getMessage());
}
}
else if( type.equals("who-req") )
{
final WhoPacket p = new WhoPacket(data);
intermud.receive(p);
}
else if( type.equals("who-reply") )
{
final WhoPacket p = new WhoPacket(data);
intermud.receive(p);
}
else if( type.equals("auth-mud-req") )
{
final MudAuthRequest p = new MudAuthRequest(data);
intermud.receive(p);
}
else if( type.equals("auth-mud-reply") )
{
final MudAuthReply p = new MudAuthReply(data);
intermud.receive(p);
}
else if( type.equals("error") )
{
error(data);
}
else if( type.equals("ucache-update") )
{
// i have NO idea what to do here
}
else
{
Log.errOut("Intermud","Other packet: " + type);
}
}
}
@Override
public void save() throws PersistenceException {
if( modified == Persistent.UNMODIFIED )
{
return;
}
peer.save();
modified = Persistent.UNMODIFIED;
}
/**
* Sends any valid subclass of Packet to the router.
* @param p the packet to send
*/
public void send(Packet p)
{
send(p.toString());
}
// Send a formatted mud mode packet to the router
private void send(String cmd)
{
if(CMSecurity.isDebugging(CMSecurity.DbgFlag.I3))
Log.sysOut("Intermud","Sending: "+cmd);
try
{
// Remove non-printables, as required by the I3 specification
// (Contributed by David Green <green@couchpotato.net>)
final byte[] packet = cmd.getBytes("ISO-8859-1");
for (int i = 0; i < packet.length; i++)
{
// 160 is a non-breaking space. We'll consider that "printable".
if ( (packet[i]&0xFF) < 32 || ((packet[i]&0xFF) >= 127 && (packet[i]&0xFF) <= 159))
{
// Java uses it as a replacement character,
// so it's probably ok for us too.
packet[i] = '?';
}
}
output.writeInt(packet.length);
output.write(packet);
}
catch( final java.io.IOException e )
{
final String errMsg=e.getMessage()==null?e.toString():e.getMessage();
if(errMsg!=null)
{
Log.errOut("InterMud","557-"+errMsg);
}
}
}
// Handle a startup reply packet
private synchronized void startupReply(Vector packet)
{
final Vector router_list = (Vector)packet.elementAt(6);
if( router_list != null )
{
final Vector router = (Vector)router_list.elementAt(0);
final NameServer name_server = name_servers.get(0);
if( !name_server.name.equals(router.elementAt(0)) )
{
// create new name server and connect
return;
}
}
password = ((Integer)packet.elementAt(7)).intValue();
modified = Persistent.MODIFIED;
}
/**
* Shuts down the connection to the router without
* reconnecting.
* @see java.lang.Runnable#run()
*/
public void stop()
{
connected = false;
shutdown=true;
try { if(input!=null) input.close();}catch(final Exception e){}
try { if(connection!=null) connection.close();}catch(final Exception e){}
if(save_thread!=null)
{
CMLib.threads().deleteTick(save_thread, -1);
save_thread=null;
}
try { save(); }
catch( final PersistenceException e ) { }
try { if(input_thread!=null) CMLib.killThread(input_thread,100,1); }catch(final Exception e){}
input_thread=null;
shutdown=false;
}
/**
* Adds a channel to the channel list.
* This does not subscribe the mud to that channel.
* In order to subscribe, the channel needs to be
* added to the ImudServices implementation's getChannels()
* method.
* @param c the channel to add to the list of known channels
* @see com.planet_ink.coffee_mud.core.intermud.i3.packets.ImudServices#getChannels
*/
public void addChannel(Channel c)
{
channels.addChannel(c);
}
/**
* Removes a channel from the channel list.
* @param c the channel to remove
*/
public void removeChannel(Channel c)
{
channels.removeChannel(c);
}
/**
* @return the list of currently known channels
*/
public ChannelList getChannelList()
{
return channels;
}
/**
* Sets the channel list to a new channel list.
* @param list the new channel list
*/
public void setChannelList(ChannelList list)
{
channels = list;
}
/**
* Adds a mud to the list of known muds.
* @param m the mud to add
*/
public void addMud(I3Mud m)
{
muds.addMud(m);
modified = Persistent.MODIFIED;
}
private I3Mud getMud(String mud_name)
{
return muds.getMud(getMudNameFor(mud_name));
}
/**
* Removed a mud from the list of known muds.
* @param m the mud to remove
*/
public void removeMud(I3Mud m)
{
muds.removeMud(m);
modified = Persistent.MODIFIED;
}
/**
* @return the list of known muds
*/
public MudList getMudList()
{
return muds;
}
/**
* @return the list of known muds
*/
public static MudList getAllMudsList()
{
if(!isConnected())
return new MudList(-1);
return thread.muds;
}
/**
* @return the list of known muds
*/
public static ChannelList getAllChannelList()
{
if(!isConnected())
return new ChannelList();
return thread.channels;
}
/**
* Sets the list of known muds to the specified list.
* @param list the new list of muds
*/
public void setMudList(MudList list)
{
muds = list;
}
private String getMudNameFor(String mud)
{
mud = mud.toLowerCase().replace('.', ' ');
for(final String cmd : muds.getMuds().keySet())
{
if( mud.equalsIgnoreCase(cmd) )
{
return cmd;
}
}
for(final String cmd : muds.getMuds().keySet())
{
if( CMLib.english().containsString(cmd,mud) )
{
return cmd;
}
}
return null;
}
/**
* @return the I3 password for this mud
*/
public int getPassword()
{
return password;
}
/**
* Sets the Intermud 3 password.
* @param pass the new password
*/
public void setPassword(int pass)
{
password = pass;
}
public static void shutdown()
{
if(thread!=null)
thread.stop();
thread=null;
}
}