<NME> MUD.java
<BEF> package com.planet_ink.coffee_mud.application;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.core.CMProps.Str;
import com.planet_ink.coffee_mud.core.CMSecurity.DbgFlag;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.collections.*;
import com.planet_ink.coffee_mud.core.exceptions.*;
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.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.*;
	public String execExternalCommand=null;

	public static final float HOST_VERSION_MAJOR=(float)3.0;
	public static final float HOST_VERSION_MINOR=(float)5.5;
	
	private boolean acceptConnections=false;
	private String offlineReason=new String("UNKNOWN");
import com.planet_ink.coffee_mud.core.intermud.cm1.CM1Server;
import com.planet_ink.coffee_mud.core.intermud.i3.IMudInterface;
import com.planet_ink.coffee_mud.core.intermud.imc2.IMC2Driver;
import com.planet_ink.coffee_mud.core.intermud.i3.server.I3Server;
import com.planet_ink.coffee_web.http.MIMEType;
import com.planet_ink.coffee_web.interfaces.FileManager;
import com.planet_ink.coffee_web.server.WebServer;
import com.planet_ink.coffee_web.util.CWConfig;
import com.planet_ink.coffee_web.util.CWThread;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter; // for writing to sockets
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.net.*;
import java.util.*;
import java.sql.*;

/*
   Copyright 2000-2022 Bo Zimmerman

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

	   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
public class MUD extends Thread implements MudHost
{
	private static final String	  HOST_VERSION	= "5.10.0.4";

	private static enum MudState
	{
		STARTING,
		WAITING,
		ACCEPTING,
		STOPPED
	}

	private static enum ConnectState
	{
		NORMAL,
		BANNED,
		BLOCKED
	}

	private volatile MudState state		 = MudState.STOPPED;
	private ServerSocket	  servsock	 = null;
	private boolean			  acceptConns= false;
	private int				  port		 = 5555;
	private final long		  startupTime= System.currentTimeMillis();
	private final ThreadGroup threadGroup;

	private static volatile int	 		grpid				= 0;
	private static boolean				bringDown			= false;
	private static String				execExternalCommand	= null;
	private static I3Server				i3server			= null;
	private static IMC2Driver			imc2server			= null;
	private static List<WebServer>		webServers			= new Vector<WebServer>();
	private static SMTPserver			smtpServerThread	= null;
	private static List<DBConnector>	databases			= new Vector<DBConnector>();
	private static List<CM1Server>		cm1Servers			= new Vector<CM1Server>();
	private static final ServiceEngine	serviceEngine		= new ServiceEngine();
	private static AtomicBoolean 		bootSync			= new AtomicBoolean(false);


	public MUD(final String name)
	{
		super(name);
		threadGroup=Thread.currentThread().getThreadGroup();
	}

	@Override
	public void acceptConnection(final Socket sock) throws SocketException, IOException
	{
		setState(MudState.ACCEPTING);
		serviceEngine.executeRunnable(threadGroup.getName(),new ConnectionAcceptor(sock));
	}

	@Override
	public ThreadGroup threadGroup()
	{
		return threadGroup;
	}

	private static boolean checkedSleep(final long millis)
	{
		try
		{
			Thread.sleep(millis);
		}
		catch(final Exception e)
		{
			return false;
		}
		return true;
	}

	private class ConnectionAcceptor implements CMRunnable
	{
		Socket sock;
		long startTime=0;

		public ConnectionAcceptor(final Socket sock) throws SocketException, IOException
		{
			this.sock=sock;
			sock.setSoLinger(true,3);
		}

		@Override
		public long getStartTime()
		{
			return startTime;
		}

		@Override
		public int getGroupID()
		{
			return Thread.currentThread().getThreadGroup().getName().charAt(0);
		}

		@Override
		public void run()
		{
			startTime=System.currentTimeMillis();
			try
			{
				if (acceptConns)
				{
					String address="unknown";
					try
					{
						address=sock.getInetAddress().getHostAddress().trim();
					}
					catch(final Exception e)
					{
					}
					ConnectState proceed=ConnectState.NORMAL;
					if(CMSecurity.isBanned(address))
						proceed=ConnectState.BANNED;
					int numAtThisAddress=0;
					final long LastConnectionDelay=(5*60*1000);
					boolean anyAtThisAddress=false;
					final int maxAtThisAddress=6;
					if(!CMSecurity.isDisabled(CMSecurity.DisFlag.CONNSPAMBLOCK))
					{
						if(!CMProps.isOnWhiteList(CMProps.WhiteList.IPSCONN, address))
						{
							if(CMSecurity.isIPBlocked(address))
								proceed = ConnectState.BANNED;
							else
							{
								@SuppressWarnings("unchecked")
								List<Triad<String,Long,Integer>> accessed= (LinkedList<Triad<String,Long,Integer>>)Resources.staticInstance()._getResource("SYSTEM_IPACCESS_STATS");
								if(accessed == null)
								{
									accessed= new LinkedList<Triad<String,Long,Integer>>();
									Resources.staticInstance()._submitResource("SYSTEM_IPACCESS_STATS",accessed);
								}
								synchronized(accessed)
								{
									for(final Iterator<Triad<String,Long,Integer>> i=accessed.iterator();i.hasNext();)
									{
										final Triad<String,Long,Integer> triad=i.next();
										if((triad.second.longValue()+LastConnectionDelay)<System.currentTimeMillis())
											i.remove();
										else
										if(triad.first.trim().equalsIgnoreCase(address))
										{
											anyAtThisAddress=true;
											triad.second=Long.valueOf(System.currentTimeMillis());
											numAtThisAddress=triad.third.intValue()+1;
											triad.third=Integer.valueOf(numAtThisAddress);
										}
									}
									if(!anyAtThisAddress)
										accessed.add(new Triad<String,Long,Integer>(address,Long.valueOf(System.currentTimeMillis()),Integer.valueOf(1)));
								}
							}
							@SuppressWarnings("unchecked")
							Set<String> autoblocked= (Set<String>)Resources.staticInstance()._getResource("SYSTEM_IPACCESS_AUTOBLOCK");
							if(autoblocked == null)
							{
								autoblocked= new TreeSet<String>();
								Resources.staticInstance()._submitResource("SYSTEM_IPACCESS_AUTOBLOCK",autoblocked);
							}
							if(autoblocked.contains(address.toUpperCase()))
							{
								if(!anyAtThisAddress)
									autoblocked.remove(address.toUpperCase());
								else
									proceed=ConnectState.BLOCKED;
							}
							else
							if(numAtThisAddress>=maxAtThisAddress)
							{
								autoblocked.add(address.toUpperCase());
								proceed=ConnectState.BLOCKED;
							}
						}
					}

					if(proceed != ConnectState.NORMAL)
					{
						final int abusiveCount=numAtThisAddress-maxAtThisAddress+1;
						final long rounder=Math.round(Math.sqrt(abusiveCount));
						if(abusiveCount == (rounder*rounder))
							Log.sysOut(Thread.currentThread().getName(),"Blocking a connection from "+address +" ("+numAtThisAddress+")");
						try
						{
							final PrintWriter out = new PrintWriter(sock.getOutputStream());
							StringBuffer introText;
							if(proceed==ConnectState.BLOCKED)
							{
								introText=new StringBuffer(Resources.getFileResource(Resources.makeFileResourceName("text/connblocked.txt"),true));
								introText=CMStrings.replaceAll(introText, "@mins@", ""+(LastConnectionDelay/60000));
							}
							else
							{
								introText=Resources.getFileResource(Resources.makeFileResourceName("text/blocked.txt"),true);
							}
							try
							{
								introText = CMLib.webMacroFilter().virtualPageFilter(introText);
							}
							catch (final Exception ex)
							{
							}
							out.print(introText.toString());
							out.flush();
							checkedSleep(250);
							out.close();
						}
						catch(final IOException e)
						{
							// dont say anything, just eat it.
						}
						sock = null;
					}
					else
					{
						Log.sysOut(Thread.currentThread().getName(),"Connection from "+address);
						// also the intro page
						final CMFile introDir=new CMFile(Resources.makeFileResourceName("text"),null,CMFile.FLAG_FORCEALLOW);
						String introFilename="text/intro.txt";
						if(introDir.isDirectory())
						{
							final CMFile[] files=introDir.listFiles();
							final List<String> choices=new ArrayList<String>();
							for (final CMFile file : files)
							{
								if(file.getName().toLowerCase().startsWith("intro")
								&&file.getName().toLowerCase().endsWith(".txt"))
									choices.add("text/"+file.getName());
							}
							if(choices.size()>0)
								introFilename=choices.get(CMLib.dice().roll(1,choices.size(),-1));
						}
						StringBuffer introText=Resources.getFileResource(introFilename,true);
						try
						{
							introText = CMLib.webMacroFilter().virtualPageFilter(introText);
						}
						catch (final Exception ex)
						{
						}
						final Session S=(Session)CMClass.getCommon("DefaultSession");
						S.initializeSession(sock, threadGroup().getName(), introText != null ? introText.toString() : null);
						CMLib.sessions().add(S);
						sock = null;
					}
				}
				else
				if((CMLib.database()!=null)
				&&(CMLib.database().isConnected())
				&&(CMLib.encoder()!=null))
				{
					StringBuffer rejectText;

					try
					{
						rejectText = Resources.getFileResource("text/offline.txt",true);
					}
					catch(final java.lang.NullPointerException npe)
					{
						rejectText=new StringBuffer("");
					}

					try
					{
						final PrintWriter out = new PrintWriter(sock.getOutputStream());
						out.println("\n\rOFFLINE: " + CMProps.getVar(CMProps.Str.MUDSTATUS)+"\n\r");
						out.println(rejectText);
						out.flush();

						checkedSleep(1000);
						out.close();
					}
					catch(final IOException e)
					{
						// dont say anything, just eat it.
					}
					sock = null;
				}
				else
				{
					try
					{
						sock.close();
					}
					catch (final Exception e)
					{
					}
					sock = null;
				}
			}
			finally
			{
				startTime=0;
			}
		}

		@Override
		public long activeTimeMillis()
		{
			return (startTime > 0) ? System.currentTimeMillis() - startTime : 0;
		}
	}

	@Override
	public String getLanguage()
	{
		final String lang = CMProps.instance().getStr("LANGUAGE").toUpperCase().trim();
		if(lang.length()==0)
			return "English";
		for (final String[] element : LanguageLibrary.ISO_LANG_CODES)
		{
			if(lang.equals(element[0]))
				return element[1];
		}
		return "English";
	}

	public void setState(final MudState st)
	{
		if(st!=state)
			state=st;
	}

	@Override
	public void run()
	{
		setState(MudState.STARTING);
		int q_len = 6;
		Socket sock=null;

		InetAddress bindAddr = null;

		if (CMProps.getIntVar(CMProps.Int.MUDBACKLOG) > 0)
			q_len = CMProps.getIntVar(CMProps.Int.MUDBACKLOG);

		if (CMProps.getVar(CMProps.Str.MUDBINDADDRESS).length() > 0)
		{
			try
			{
				bindAddr = InetAddress.getByName(CMProps.getVar(CMProps.Str.MUDBINDADDRESS));
			}
			catch (final UnknownHostException e)
			{
				Log.errOut(Thread.currentThread().getName(),"ERROR: MUD Server could not bind to address " + CMProps.getVar(CMProps.Str.MUDBINDADDRESS));
			}
		}

		try
		{
			servsock=new ServerSocket(port, q_len, bindAddr);

			Log.sysOut(Thread.currentThread().getName(),"MUD Server started on port: "+port);
			if (bindAddr != null)
				Log.sysOut(Thread.currentThread().getName(),"MUD Server bound to: "+bindAddr.toString());
			CMLib.hosts().add(this);
			while(servsock!=null)
			{
				setState(MudState.WAITING);
				sock=servsock.accept();
				acceptConnection(sock);
			}
		}
		catch(final Exception t)
		{
			if((!(t instanceof java.net.SocketException))
			||(t.getMessage()==null)
			||(t.getMessage().toLowerCase().indexOf("socket closed")<0))
			{
				Log.errOut(Thread.currentThread().getName(),t);
			}
		}

		Log.sysOut(Thread.currentThread().getName(),"Server cleaning up.");

		try
		{
			if(servsock!=null)
				servsock.close();
			if(sock!=null)
				sock.close();
		}
		catch(final IOException e)
		{
		}

		Log.sysOut(Thread.currentThread().getName(),"MUD on port "+port+" stopped!");
		setState(MudState.STOPPED);
		CMLib.hosts().remove(this);
	}

	@Override
	public String getStatus()
	{
		if(CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN))
			return CMProps.getVar(CMProps.Str.MUDSTATUS);
		if(!CMProps.getBoolVar(CMProps.Bool.MUDSTARTED))
			return CMProps.getVar(CMProps.Str.MUDSTATUS);
		return state.toString();
	}

	@Override
	public void shutdown(final Session S, final boolean keepItDown, final String externalCommand)
	{
		globalShutdown(S,keepItDown,externalCommand);
		interrupt(); // kill the damn archon thread.
	}

	public static void defaultShutdown()
	{
		globalShutdown(null,true,null);
	}

	private static void shutdownMemReport(final String blockName)
	{
		try
		{
			Object obj = new Object();
			final WeakReference<Object> ref = new WeakReference<Object>(obj);
			obj = null;
			System.gc();
			System.runFinalization();
			while(ref.get() != null)
			{
				System.gc();
			}
			checkedSleep(3000);
		}
		catch (final Exception e)
		{
		}
		final long free=Runtime.getRuntime().freeMemory()/1024;
		final long total=Runtime.getRuntime().totalMemory()/1024;
		Log.debugOut("Memory: "+blockName+": "+(total-free)+"/"+total);
	}

	public static void globalShutdown(final Session S, final boolean keepItDown, final String externalCommand)
	{
		CMProps.setBoolAllVar(CMProps.Bool.MUDSTARTED,false);
		CMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN,true);
		bootSync.set(false);
		final AtomicLong shutdownStateTime = new AtomicLong(System.currentTimeMillis());
		final long shutdownTimeout = 5 * 60 * 1000;
		final Thread currentShutdownThread=Thread.currentThread();
		final Thread shutdownWatchThread = new Thread(new Runnable()
		{
			@Override
			public void run()
			{
				while(shutdownStateTime.get()!=0)
				{
					final long ellapsed=System.currentTimeMillis()-shutdownStateTime.get();
					if(ellapsed > shutdownTimeout)
					{
						if(externalCommand!=null)
							MUD.execExternalRestart(externalCommand);
						Log.errOut("** Shutdown timeout. **");
						final StringBuilder lines=new StringBuilder("");
						lines.append("\n\r^HThread: ^N"+currentShutdownThread.getName()+"\n\r");
						final java.lang.StackTraceElement[] s=currentShutdownThread.getStackTrace();
						for (final StackTraceElement element : s)
							lines.append("\n   "+element.getClassName()+": "+element.getMethodName()+"("+element.getFileName()+": "+element.getLineNumber()+")");
						Log.errOut(lines.toString());
						break;
					}
					CMLib.s_sleep(10 * 1000);
				}
			}
		});
		shutdownWatchThread.start();

		final boolean debugMem = CMSecurity.isDebugging(CMSecurity.DbgFlag.SHUTDOWN);
		if(debugMem) shutdownMemReport("BaseLine");
		serviceEngine.suspendAll(null);
		if(S!=null)
			S.print(CMLib.lang().L("Closing MUD listeners to new connections..."));
		for(int i=0;i<CMLib.hosts().size();i++)
			CMLib.hosts().get(i).setAcceptConnections(false);
		Log.sysOut(Thread.currentThread().getName(),"New Connections are now closed");
		if(S!=null)
			S.println(CMLib.lang().L("Done."));

		if(!CMSecurity.isSaveFlag(CMSecurity.SaveFlag.NOPLAYERS))
		{
			if(S!=null)
				S.print(CMLib.lang().L("Saving players..."));
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Saving players...");
			for(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.SESSIONS);e.hasMoreElements();)
			{
				final SessionsList list=((SessionsList)e.nextElement());
				for(final Session S2 : list.allIterable())
				{
					final MOB M = S2.mob();
					if((M!=null)&&(M.playerStats()!=null))
					{
						shutdownStateTime.set(System.currentTimeMillis());
						M.playerStats().setLastDateTime(System.currentTimeMillis());
						// important! shutdown their affects!
						for(int a=M.numAllEffects()-1;a>=0;a--) // reverse enumeration
						{
							try
							{
								final Ability A=M.fetchEffect(a);
								if((A!=null)&&(A.canBeUninvoked()))
									A.unInvoke();
								if((A!=null)&&(!A.isSavable()))
									M.delEffect(A);
							}
							catch (final Throwable ex)
							{
								Log.errOut(ex);
							}
						}
					}
				}
			}
			try
			{
				for(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.PLAYERS);e.hasMoreElements();)
				{
					try
					{
						final PlayerLibrary lib = (PlayerLibrary)e.nextElement();
						shutdownStateTime.set(System.currentTimeMillis()+(lib.numPlayers()*(60 * 1000)));
						lib.savePlayers();
					}
					catch (final Throwable ex)
					{
						Log.errOut(ex);
					}
				}
			}
			catch (final Throwable ex)
			{
				Log.errOut(ex);
			}
			if(S!=null)
				S.println(CMLib.lang().L("done"));
			Log.sysOut(Thread.currentThread().getName(),"All users saved.");
		}
		shutdownStateTime.set(System.currentTimeMillis());
		if(S!=null)
			S.print(CMLib.lang().L("Saving stats..."));
		try
		{
			for(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.STATS);e.hasMoreElements();)
				((StatisticsLibrary)e.nextElement()).update();
		}
		catch (final Throwable ex)
		{
			Log.errOut(ex);
		}
		if(S!=null)
			S.println(CMLib.lang().L("done"));
		Log.sysOut(Thread.currentThread().getName(),"Stats saved.");
		if(debugMem)
			shutdownMemReport("Saves");

		shutdownStateTime.set(System.currentTimeMillis());
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down" + (keepItDown? "..." : " and restarting..."));
		Log.sysOut(Thread.currentThread().getName(),"Notifying all objects of shutdown...");
		if(S!=null)
			S.print(CMLib.lang().L("Notifying all objects of shutdown..."));
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Notifying Objects");
		final MOB mob=(S!=null)?S.mob():CMClass.getFactoryMOB();
		final CMMsg msg=CMClass.getMsg(mob,null,CMMsg.MSG_SHUTDOWN,null);
		final List<Room> roomSet=new ArrayList<Room>();
		try
		{
			shutdownStateTime.set(System.currentTimeMillis());
			for(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.MAP);e.hasMoreElements();)
			{
				final WorldMap map=((WorldMap)e.nextElement());
				for(final Enumeration<Area> a=map.areas();a.hasMoreElements();)
					a.nextElement().setAreaState(Area.State.STOPPED);
			}
			shutdownStateTime.set(System.currentTimeMillis());
			for(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.MAP);e.hasMoreElements();)
			{
				final WorldMap map=((WorldMap)e.nextElement());
				for(final Enumeration<Room> r=map.rooms();r.hasMoreElements();)
				{
					// single threadding is important here.
					final Room R=r.nextElement();
					try
					{
						R.send(mob,msg);
					}
					catch (final Throwable ex)
					{
						Log.errOut(ex);
					}
					roomSet.add(R);
					shutdownStateTime.set(System.currentTimeMillis());
				}
			}
		}
		catch (final NoSuchElementException e)
		{
		}
		if(S!=null)
			S.println(CMLib.lang().L("done"));
		if(debugMem) shutdownMemReport("Notifications");
		final CMLib.Library[][] libraryShutdownLists=
		{
			{CMLib.Library.QUEST,CMLib.Library.TECH,CMLib.Library.SESSIONS},
			{CMLib.Library.STATS,CMLib.Library.THREADS},
			{CMLib.Library.SOCIALS,CMLib.Library.CLANS,CMLib.Library.CHANNELS,CMLib.Library.JOURNALS,
				CMLib.Library.POLLS,CMLib.Library.HELP,CMLib.Library.CATALOG,CMLib.Library.MAP,
				CMLib.Library.PLAYERS
			}
		};

		shutdownStateTime.set(System.currentTimeMillis());
		for(final CMLib.Library lib : libraryShutdownLists[0])
		{
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down "+CMStrings.capitalizeAndLower(lib.name())+"...");
			for(final Enumeration<CMLibrary> e=CMLib.libraries(lib);e.hasMoreElements();)
			{
				try
				{
					shutdownStateTime.set(System.currentTimeMillis()+(5*shutdownTimeout));
					final CMLibrary library = e.nextElement();
					library.shutdown();
					if(debugMem) shutdownMemReport(library.ID());
					shutdownStateTime.set(System.currentTimeMillis());
				}
				catch(final Throwable t)
				{
					Log.errOut(t);
				}
			}
		}

		if(S!=null)
			S.println(CMLib.lang().L("Save thread stopped"));

		if(CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMMOBS)
		||CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMITEMS)
		||CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMSHOPS))
		{
			if(S!=null)
				S.print(CMLib.lang().L("Saving room data..."));
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Rejuving the dead");
			serviceEngine.tickAllTickers(null);
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Map Update");
			for(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.MAP);e.hasMoreElements();)
			{
				final WorldMap map=((WorldMap)e.nextElement());
				for(final Enumeration<Area> a=map.areas();a.hasMoreElements();)
					a.nextElement().setAreaState(Area.State.STOPPED);
			}
			shutdownStateTime.set(System.currentTimeMillis());
			int roomCounter=0;
			Room R=null;
			for(final Iterator<Room> e=roomSet.iterator();e.hasNext();)
			{
				if(((++roomCounter)%200)==0)
				{
					if(S!=null)
						S.print(".");
					CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Map Update ("+roomCounter+")");
				}
				R=e.next();
				try
				{
					if(R.roomID().length()>0)
						R.executeMsg(mob,CMClass.getMsg(mob,R,null,CMMsg.MSG_EXPIRE,null));
				}
				catch (final Throwable ex)
				{
					Log.errOut(ex);
				}
				shutdownStateTime.set(System.currentTimeMillis());
			}
			if(S!=null)
				S.println(CMLib.lang().L("done"));
			Log.sysOut(Thread.currentThread().getName(),"Map data saved.");
		}

		shutdownStateTime.set(System.currentTimeMillis());
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...CM1Servers");
		for(final CM1Server cm1server : cm1Servers)
		{
			try
			{
				cm1server.shutdown();
			}
			catch (final Throwable ex)
			{
				Log.errOut(ex);
			}
			finally
			{
				if(S!=null)
					S.println(CMLib.lang().L("@x1 stopped",cm1server.getName()));
				Log.sysOut(Thread.currentThread().getName(),cm1server.getName()+" stopped");
				if(debugMem) shutdownMemReport("CM1Server");
			}
		}
		cm1Servers.clear();

		shutdownStateTime.set(System.currentTimeMillis());
		if(i3server!=null)
		{
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...I3Server");
			try
			{
				I3Server.shutdown();
			}
			catch (final Throwable ex)
			{
				Log.errOut(ex);
			}
			i3server=null;
			if(S!=null)
				S.println(CMLib.lang().L("I3Server stopped"));
			Log.sysOut(Thread.currentThread().getName(),"I3Server stopped");
			if(debugMem) shutdownMemReport("I3Server");
		}

		shutdownStateTime.set(System.currentTimeMillis());
		if(imc2server!=null)
		{
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...IMC2Server");
			try
			{
				imc2server.shutdown();
			}
			catch (final Throwable ex)
			{
				Log.errOut(ex);
			}
			imc2server=null;
			if(S!=null)
				S.println(CMLib.lang().L("IMC2Server stopped"));
			Log.sysOut(Thread.currentThread().getName(),"IMC2Server stopped");
			if(debugMem) shutdownMemReport("IMC2Server");
		}

		shutdownStateTime.set(System.currentTimeMillis());
		if(S!=null)
			S.print(CMLib.lang().L("Stopping player Sessions..."));
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Stopping sessions");
		for(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.SESSIONS);e.hasMoreElements();)
		{
			final SessionsList list=((SessionsList)e.nextElement());
			for(final Session S2 : list.allIterable())
			{
				if((S!=null)&&(S2==S))
				{
					if(mob!=null)
						mob.removeFromGame(true, false);
					list.remove(S2);
				}
				else
				{
					shutdownStateTime.set(System.currentTimeMillis());
					S2.stopSession(true,true,false);
				}
				if(S!=null)
					S.print(".");
			}
		}
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Done stopping sessions");
		shutdownStateTime.set(System.currentTimeMillis());
		if(S!=null)
			S.println(CMLib.lang().L("All users logged off"));
		checkedSleep(3000);
		/* give sessions a few seconds to inform the map */
		Log.sysOut(Thread.currentThread().getName(),"All users logged off.");
		if(debugMem) shutdownMemReport("Sessions");

		if(smtpServerThread!=null)
		{
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...smtp server");
			smtpServerThread.shutdown();
			smtpServerThread = null;
			Log.sysOut(Thread.currentThread().getName(),"SMTP Server stopped.");
			if(S!=null)
				S.println(CMLib.lang().L("SMTP Server stopped"));
			if(debugMem) shutdownMemReport("SMTP Server");
		}

		shutdownStateTime.set(System.currentTimeMillis());
		if(S!=null)
			S.print(CMLib.lang().L("Stopping all threads..."));
		for(final CMLib.Library lib : libraryShutdownLists[1])
		{
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down "+CMStrings.capitalizeAndLower(lib.name())+"...");
			for(final Enumeration<CMLibrary> e=CMLib.libraries(lib);e.hasMoreElements();)
			{
				try
				{
					shutdownStateTime.set(System.currentTimeMillis()+(5*shutdownTimeout));
					final CMLibrary library = e.nextElement();
					if(S!=null)
						S.print(library.name()+"...");
					library.shutdown();
					if(S!=null)
						S.println("shut down.");
				}
				catch (final Throwable ex)
				{
					Log.errOut(ex);
				}
			}
		}
		if(S!=null)
			S.println(CMLib.lang().L("done"));
		if(debugMem) shutdownMemReport("Map Threads");
		Log.sysOut(Thread.currentThread().getName(),"Map Threads Stopped.");

		shutdownStateTime.set(System.currentTimeMillis());
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down services...");
		for(final CMLib.Library lib : libraryShutdownLists[2])
		{
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down "+CMStrings.capitalizeAndLower(lib.name())+"...");
			for(final Enumeration<CMLibrary> e=CMLib.libraries(lib);e.hasMoreElements();)
			{
				try
				{
					shutdownStateTime.set(System.currentTimeMillis()+(5*shutdownTimeout));
					final CMLibrary library=e.nextElement();
					if(S!=null)
						S.print(library.name()+"...");
					library.shutdown();
					if(S!=null)
						S.println("shut down.");
					if(debugMem)
						shutdownMemReport(library.ID());
				}
				catch (final Throwable ex)
				{
					Log.errOut(ex);
				}
			}
		}
		shutdownStateTime.set(System.currentTimeMillis());
		for(final CMLib.Library lib : CMLib.Library.values())
		{
			boolean found=false;
			for(final CMLib.Library[] prevSet : libraryShutdownLists)
				found=found||CMParms.contains(prevSet, lib);
			if(!found)
			{
				CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down "+CMStrings.capitalizeAndLower(lib.name())+"...");
				for(final Enumeration<CMLibrary> e=CMLib.libraries(lib);e.hasMoreElements();)
				{
					try
					{
						shutdownStateTime.set(System.currentTimeMillis()+(5*shutdownTimeout));
						final CMLibrary library=e.nextElement();
						if(S!=null)
							S.print(library.name()+"...");
						library.shutdown();
						if(S!=null)
							S.println("shut down.");
						if(debugMem)
							shutdownMemReport(library.ID());
					}
					catch (final Throwable ex)
					{
						Log.errOut(ex);
					}
				}
			}
		}
		shutdownStateTime.set(System.currentTimeMillis());
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...unloading resources");
		Resources.shutdown();

		Log.sysOut(Thread.currentThread().getName(),"Resources Cleared.");
		if(S!=null)
			S.println(CMLib.lang().L("All resources unloaded"));
		if(debugMem) shutdownMemReport("Resources");

		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...closing db connections");
		for(int d=0;d<databases.size();d++)
			databases.get(d).killConnections();
		if(S!=null)
			S.println(CMLib.lang().L("Database connections closed"));
		Log.sysOut(Thread.currentThread().getName(),"Database connections closed.");
		if(debugMem) shutdownMemReport("Database Connections");

		shutdownStateTime.set(System.currentTimeMillis());
		for(int i=0;i<webServers.size();i++)
		{
			final WebServer webServerThread=webServers.get(i);
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down web server "+webServerThread.getName()+"...");
			try
			{
				shutdownStateTime.set(System.currentTimeMillis());
				webServerThread.close();
			}
			catch (final Throwable ex)
			{
				Log.errOut(ex);
			}
			Log.sysOut(Thread.currentThread().getName(),"Web server "+webServerThread.getName()+" stopped.");
			if(S!=null)
				S.println(CMLib.lang().L("Web server @x1 stopped",webServerThread.getName()));
			if(debugMem) shutdownMemReport("Web Server "+webServerThread.getName());
		}
		webServers.clear();

		shutdownStateTime.set(System.currentTimeMillis());
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...unloading macros");
		CMLib.lang().clear();
		if(debugMem) shutdownMemReport("Macros");
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...unloading classes");
		try
		{
			CMClass.shutdown();
		}
		catch (final Throwable ex)
		{
			Log.errOut(ex);
		}
		if(debugMem) shutdownMemReport("Java Classes");
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down" + (keepItDown? "..." : " and restarting..."));

		checkedSleep(500);
		Log.sysOut(Thread.currentThread().getName(),"CoffeeMud shutdown complete.");
		if(S!=null)
			S.println(CMLib.lang().L("CoffeeMud shutdown complete."));
		bringDown=keepItDown;
		serviceEngine.resumeAll();
		if(!keepItDown)
		{
			if(S!=null)
				S.println(CMLib.lang().L("Restarting..."));
		}
		shutdownStateTime.set(0);
		shutdownWatchThread.interrupt();
		checkedSleep(500);
		System.gc();
		System.runFinalization();
		checkedSleep(500);
		if(debugMem) shutdownMemReport("Complete");

		execExternalCommand=externalCommand;
		CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutdown: you are the special lucky chosen one!");
		for(int m=CMLib.hosts().size()-1;m>=0;m--)
		{
			if(CMLib.hosts().get(m) instanceof Thread)
			{
				try
				{
					CMLib.killThread((Thread)CMLib.hosts().get(m),100,30);
				}
				catch (final Throwable t)
				{
				}
			}
		}
		shutdownStateTime.set(0);
		CMLib.hosts().clear();
		CMSecurity.unloadAll();
		if(!keepItDown)
			CMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN,false);
		Log.debugOut("Used memory = "+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));
	}

	private static boolean startWebServer(final CMProps page, final String serverName)
	{
		try
		{
			final StringBuffer commonProps=new CMFile("web/common.ini", null, CMFile.FLAG_LOGERRORS).text();
			final StringBuffer finalProps=new CMFile("web/"+serverName+".ini", null, CMFile.FLAG_LOGERRORS).text();
			commonProps.append("\n").append(finalProps.toString());
			final CWConfig config=new CWConfig();
			config.setFileManager(new CMFile.CMFileManager());
			WebServer.initConfig(config, Log.instance(), new ByteArrayInputStream(commonProps.toString().getBytes()));
			if(CMSecurity.isDebugging(DbgFlag.HTTPREQ))
				config.setDebugFlag(page.getStr("DBGMSGS"));
			if(CMSecurity.isDebugging(DbgFlag.HTTPACCESS))
				config.setAccessLogFlag(page.getStr("ACCMSGS"));
			final WebServer webServer=new WebServer(serverName+Thread.currentThread().getThreadGroup().getName().charAt(0),config);
			config.setCoffeeWebServer(webServer);
			webServer.start();
			webServers.add(webServer);
			return true;
		}
		catch(final Exception e)
		{
			Log.errOut("HTTP server "+serverName+" NOT started: "+e.getMessage());
			return false;
		}
	}

	private static boolean stopWebServer(final String serverName)
	{
		try
		{
			for(int i=0;i<webServers.size();i++)
			{
				final WebServer webServerThread=webServers.get(i);
				if((webServerThread.getName().length() < 1)||(webServerThread.getName().indexOf('-')<0))
					continue;
				final String name = webServerThread.getName().substring(webServerThread.getName().indexOf('-')+1,webServerThread.getName().length()-1);
				if(name.equals(serverName))
				{
					CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down web server "+webServerThread.getName()+"...");
					webServerThread.close();
					Log.sysOut(Thread.currentThread().getName(),"Web server "+webServerThread.getName()+" stopped.");
					webServers.remove(webServerThread);
					CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"OK");
					return true;
				}
			}
		}
		catch(final Exception e)
		{
			Log.errOut("HTTP server "+serverName+" NOT stopped: "+e.getMessage());
		}
		return false;
	}

	private static void startIntermud3()
	{
		final char tCode=Thread.currentThread().getThreadGroup().getName().charAt(0);
		final CMProps page=CMProps.instance();
		try
		{
			if(page.getBoolean("RUNI3SERVER")&&(tCode==MAIN_HOST)&&(!CMSecurity.isDisabled(CMSecurity.DisFlag.I3)))
			{
				if(i3server!=null)
					I3Server.shutdown();
				i3server=null;
				String playstate=page.getStr("MUDSTATE");
				if((playstate==null)||(playstate.length()==0))
					playstate=page.getStr("I3STATE");
				if((playstate==null)||(!CMath.isInteger(playstate)))
					playstate="Development";
				else
				switch(CMath.s_int(playstate.trim()))
				{
				case 0:
					playstate = "MudLib Development";
					break;
				case 1:
					playstate = "Restricted Access";
					break;
				case 2:
					playstate = "Beta Testing";
					break;
				case 3:
					playstate = "Open to the public";
					break;
				default:
					playstate = "MudLib Development";
					break;
				}
				final IMudInterface imud=new IMudInterface(CMProps.getVar(CMProps.Str.MUDNAME),
													 "CoffeeMud v"+CMProps.getVar(CMProps.Str.MUDVER),
													 CMLib.mud(0).getPort(),
													 playstate,
													 CMLib.channels().getI3ChannelsList());
				i3server=new I3Server();
				int i3port=page.getInt("I3PORT");
				if(i3port==0)
					i3port=27766;
				I3Server.start(CMProps.getVar(CMProps.Str.MUDNAME),i3port,imud);
			}
		}
		catch(final Exception e)
		{
			if(i3server!=null)
				I3Server.shutdown();
			i3server=null;
		}
	}

	private static boolean stopCM1()
	{
		try
		{
			for(final CM1Server s : cm1Servers)
			{
				s.shutdown();
				cm1Servers.remove(s);
			}
			return true;
		}
		catch(final Exception e)
		{
			return false;
		}
	}

	private static boolean startCM1()
	{
		final char tCode=Thread.currentThread().getThreadGroup().getName().charAt(0);
		final CMProps page=CMProps.instance();
		CM1Server cm1server = null;
		try
		{
			final String runcm1=page.getPrivateStr("RUNCM1SERVER");
			if((runcm1!=null)&&(runcm1.equalsIgnoreCase("TRUE")))
			{
				final String iniFile = page.getStr("CM1CONFIG");
				for(final CM1Server s : cm1Servers)
				{
					if(s.getINIFilename().equalsIgnoreCase(iniFile))
					{
						s.shutdown();
						cm1Servers.remove(s);
					}
				}
				cm1server=new CM1Server("CM1Server"+tCode,iniFile);
				cm1server.start();
				cm1Servers.add(cm1server);
			}
			return true;
		}
		catch(final Exception e)
		{
			if(cm1server!=null)
			{
				cm1server.shutdown();
				cm1Servers.remove(cm1server);
			}
			return false;
		}
	}

	private static void startIntermud2()
	{
		final char tCode=Thread.currentThread().getThreadGroup().getName().charAt(0);
		final CMProps page=CMProps.instance();
		try
		{
			if(page.getBoolean("RUNIMC2CLIENT")&&(tCode==MAIN_HOST)&&(!CMSecurity.isDisabled(CMSecurity.DisFlag.IMC2)))
			{
				imc2server=new IMC2Driver();
				if(!imc2server.imc_startup(false,
											page.getStr("IMC2LOGIN").trim(),
											CMProps.getVar(CMProps.Str.MUDNAME),
											page.getStr("IMC2MYEMAIL").trim(),
											page.getStr("IMC2MYWEB").trim(),
											page.getStr("IMC2HUBNAME").trim(),
											page.getInt("IMC2HUBPORT"),
											page.getStr("IMC2PASS1").trim(),
											page.getStr("IMC2PASS2").trim(),
											CMLib.channels().getIMC2ChannelsList()))
				{
					Log.errOut(Thread.currentThread().getName(),"IMC2 Failed to start!");
					imc2server=null;
				}
				else
				{
					CMLib.intermud().registerIMC2(imc2server);
					imc2server.start();
				}
			}
		}
		catch(final Exception e)
		{
			Log.errOut(e);
		}
	}

	@Override
	public void interrupt()
	{
		if(servsock!=null)
		{
			try
			{
				servsock.close();
				servsock = null;
			}
			catch(final IOException e)
			{
			}
		}
		super.interrupt();
	}

	public static int activeThreadCount(final ThreadGroup tGroup, final boolean nonDaemonsOnly)
	{
		int realAC=0;
		final int ac = tGroup.activeCount();
		final Thread tArray[] = new Thread [ac+1];
		tGroup.enumerate(tArray);
		for (int i = 0; i<ac; ++i)
		{
			if((tArray[i] != null)
			&& tArray[i].isAlive()
			&&(tArray[i] != Thread.currentThread())
			&&((!nonDaemonsOnly)||(!tArray[i].isDaemon())))
				realAC++;
		}
		return realAC;
	}

	private static int killCount(final ThreadGroup tGroup, final boolean nonDaemonsOnly)
	{
		int killed=0;

		final int ac = tGroup.activeCount();
		final Thread tArray[] = new Thread [ac+1];
		tGroup.enumerate(tArray);
		for (int i = 0; i<ac; ++i)
		{
			if ((tArray[i] != null)
			&& tArray[i].isAlive()
			&&(tArray[i] != Thread.currentThread())
			&&((!nonDaemonsOnly)||(!tArray[i].isDaemon())))
			{
				CMLib.killThread(tArray[i],500,10);
				killed++;
			}
		}
		return killed;
	}

	private static void threadList(final ThreadGroup tGroup, final boolean nonDaemonsOnly)
	{
		if(tGroup==null)
			return;
		final int ac = tGroup.activeCount();
		final Thread tArray[] = new Thread [ac+1];
		tGroup.enumerate(tArray);
		for (int i = 0; i<ac; ++i)
		{
			if (tArray[i] != null && tArray[i].isAlive() && (tArray[i] != Thread.currentThread()) && ((!nonDaemonsOnly)||(!tArray[i].isDaemon())))
			{
				String summary;
				if(tArray[i] instanceof MudHost)
					summary=": "+CMClass.classID(tArray[i])+": "+((MudHost)tArray[i]).getStatus();
				else
				{
					final Runnable R=serviceEngine.findRunnableByThread(tArray[i]);
					if(R instanceof TickableGroup)
						summary=": "+((TickableGroup)R).getName()+": "+((TickableGroup)R).getStatus();
					else
					if(R instanceof Session)
					{
						final Session S=(Session)R;
						final MOB mob=S.mob();
						final String mobName=(mob==null)?"null":mob.Name();
						summary=": session "+mobName+": "+S.getStatus().toString()+": "+CMParms.combineQuoted(S.getPreviousCMD(),0);
					}
					else
					if(R instanceof CMRunnable)
						summary=": "+CMClass.classID(R)+": active for "+((CMRunnable)R).activeTimeMillis()+"ms";
					else
					if(CMClass.classID(R).length()>0)
						summary=": "+CMClass.classID(R);
					else
						summary="";
				}
				Log.sysOut(Thread.currentThread().getName(), "-->Thread: "+tArray[i].getName() + summary+"\n\r");
			}
		}
	}

	@Override
	public String getHost()
	{
		return CMProps.getVar(Str.MUDDOMAIN);
	}

	@Override
	public int getPort()
	{
		return port;
	}

	@Override
	public String geWebHostUrl()
	{
		WebServer server=null;
		for(final WebServer serv : webServers)
		{
			if(!CMath.s_bool(serv.getConfig().getMiscProp("ADMIN")))
			{
				server=serv;
				break;
			}
		}
		if((server == null) && (webServers.size()>0))
			server = webServers.get(0);
		if(server == null)
			return "/";
		final int[] ports = server.getConfig().getHttpListenPorts();
		if((ports == null)||(ports.length==0))
			return "/";
		if(CMParms.contains(ports, 80))
			return "http://" + CMProps.getVar(Str.MUDDOMAIN)+"/";
		return "http://" + CMProps.getVar(Str.MUDDOMAIN)+":"+ports[0]+"/";
	}

	private static class HostGroup extends Thread
	{
		private String	name		= null;
		private String	iniFile		= null;
		private String	logName		= null;
		private char	threadCode	= MAIN_HOST;
		private boolean	hostStarted	= false;
		private boolean	failedStart	= false;
		//protected ThreadGroup threadGroup;

		public HostGroup(final ThreadGroup G, final String mudName, final String iniFileName)
		{
			super(G,"HOST"+grpid);
			//threadGroup=G;
			synchronized(CMClass.getSync("HostGroupInit"))
			{
				logName="mud"+((grpid>0)?("."+grpid):"");
				grpid++;
				iniFile=iniFileName;
				name=mudName;
				setDaemon(true);
				threadCode=G.getName().charAt(0);
			}
		}

		public boolean isStarted()
		{
			return hostStarted;
		}

		public boolean failedToStart()
		{
			return failedStart;
		}

		public void fatalStartupError(final Thread t, final int type)
		{
			String errorInternal=null;
			switch(type)
			{
			case 1:
				errorInternal="ERROR: initHost() will not run without properties. Exiting.";
				break;
			case 2:
				errorInternal="Map is empty?! Exiting.";
				break;
			case 3:
				errorInternal="Database init failed. Exiting.";
				break;
			case 4:
				errorInternal="Fatal exception. Exiting.";
				break;
			case 5:
				errorInternal="MUD Server did not start. Exiting.";
				break;
			default:
				errorInternal="Fatal error loading classes.  Make sure you start up coffeemud from the directory containing the class files.";
				break;
			}
			Log.errOut(Thread.currentThread().getName(),errorInternal);
			bringDown=true;

			CMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN,true);
			//CMLib.killThread(t,100,1);
		}

		protected boolean initHost()
		{
			final Thread t=Thread.currentThread();
			final CMProps page=CMProps.instance();

			if ((page == null) || (!page.isLoaded()))
			{
				fatalStartupError(t,1);
				return false;
			}

			final char tCode=Thread.currentThread().getThreadGroup().getName().charAt(0);
			final boolean checkPrivate=(tCode!=MAIN_HOST);

			final List<String> compress=CMParms.parseCommas(page.getStr("COMPRESS").toUpperCase(),true);
			CMProps.setBoolVar(CMProps.Bool.ITEMDCOMPRESS,compress.contains("ITEMDESC"));
			CMProps.setBoolVar(CMProps.Bool.MOBCOMPRESS,compress.contains("GENMOBS"));
			CMProps.setBoolVar(CMProps.Bool.ROOMDCOMPRESS,compress.contains("ROOMDESC"));
			CMProps.setBoolVar(CMProps.Bool.MOBDCOMPRESS,compress.contains("MOBDESC"));
			Resources.setCompression(compress.contains("RESOURCES"));
			final List<String> nocache=CMParms.parseCommas(page.getStr("NOCACHE").toUpperCase(),true);
			CMProps.setBoolVar(CMProps.Bool.MOBNOCACHE,nocache.contains("GENMOBS"));
			CMProps.setBoolVar(CMProps.Bool.ROOMDNOCACHE,nocache.contains("ROOMDESC"));
			CMProps.setBoolVar(CMProps.Bool.FILERESOURCENOCACHE, nocache.contains("FILERESOURCES"));
			CMProps.setBoolVar(CMProps.Bool.CATALOGNOCACHE, nocache.contains("CATALOG"));
			CMProps.setBoolVar(CMProps.Bool.MAPFINDSNOCACHE,nocache.contains("MAPFINDERS"));
			CMProps.setBoolVar(CMProps.Bool.ACCOUNTSNOCACHE,nocache.contains("ACCOUNTS"));
			CMProps.setBoolVar(CMProps.Bool.PLAYERSNOCACHE,nocache.contains("PLAYERS"));

			DBConnector currentDBconnector=null;
			String dbClass=page.getStr("DBCLASS");
			if(tCode!=MAIN_HOST)
			{
				DatabaseEngine baseEngine=(DatabaseEngine)CMLib.library(MAIN_HOST,CMLib.Library.DATABASE);
				while((!MUD.bringDown)
				&&((baseEngine==null)||(!baseEngine.isConnected())))
				{
					if(!checkedSleep(500))
						break;
					baseEngine=(DatabaseEngine)CMLib.library(MAIN_HOST,CMLib.Library.DATABASE);
				}
				if(MUD.bringDown)
					return false;

				if(page.getPrivateStr("DBCLASS").length()==0)
				{
					CMLib.registerLibrary(baseEngine);
					dbClass="";
				}
			}
			if(dbClass.length()>0)
			{
				final String dbService=page.getStr("DBSERVICE");
				final String dbUser=page.getStr("DBUSER");
				final String dbPass=page.getStr("DBPASS");
				final int dbConns=page.getInt("DBCONNECTIONS");
				final int dbPingIntMins=page.getInt("DBPINGINTERVALMINS");
				final Map<String,String> dbParms=CMParms.parseEQParms(page.getStr("DBPARMS"),CMParms.spaceDelimiter,false);
				if(dbConns == 0)
				{
					Log.errOut(Thread.currentThread().getName(),"Fatal error: DBCONNECTIONS in INI file is "+dbConns);
					System.exit(-1);
				}
				final boolean dbReuse=page.getBoolean("DBREUSE");
				final boolean dbTransact=page.getBoolean("DBTRANSACT");
				final boolean useQue=!CMSecurity.isDisabled(CMSecurity.DisFlag.DBERRORQUE);
				final boolean useQueStart=!CMSecurity.isDisabled(CMSecurity.DisFlag.DBERRORQUESTART);
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: connecting to database");
				currentDBconnector=new DBConnector(dbClass,dbService,dbUser,dbPass,dbParms,dbConns,dbPingIntMins,dbReuse,dbTransact,useQue,useQueStart);
				currentDBconnector.reconnect();
				CMLib.registerLibrary(new DBInterface(currentDBconnector,CMProps.getPrivateSubSet("DB.*")));

				final DBConnection DBTEST=currentDBconnector.DBFetchTest();
				if(DBTEST!=null)
					currentDBconnector.DBDone(DBTEST);
				if((DBTEST!=null)&&(currentDBconnector.amIOk())&&(CMLib.database().isConnected()))
				{
					Log.sysOut(Thread.currentThread().getName(),"Connected to "+currentDBconnector.service());
					databases.add(currentDBconnector);
				}
				else
				{
					final String DBerrors=currentDBconnector.errorStatus().toString();
					Log.errOut(Thread.currentThread().getName(),"Fatal database error: "+DBerrors);
					return false;
				}
			}
			else
			if(CMLib.database()==null)
			{
				Log.errOut(Thread.currentThread().getName(),"No registered database!");
				return false;
			}

			// test the database
			try
			{
				final CMFile F = new CMFile("/test.the.database",null);
				if(F.exists())
					Log.sysOut(Thread.currentThread().getName(),"Test file found .. hmm.. that was unexpected.");

			}
			catch(final Exception e)
			{
				Log.errOut(e);
				Log.errOut("Database error! Panic shutdown!");
				return false;
			}

			String webServersList=page.getPrivateStr("RUNWEBSERVERS");
			if(webServersList.equalsIgnoreCase("true"))
				webServersList="pub,admin";
			if((webServersList.length()>0)&&(!webServersList.equalsIgnoreCase("false")))
			{
				final List<String> serverNames=CMParms.parseCommas(webServersList,true);
				for(int s=0;s<serverNames.size();s++)
				{
					final String serverName=serverNames.get(s);
					startWebServer(page, serverName);
				}
			}

			smtpServerThread = new SMTPserver(CMLib.mud(0)); // initializes variables, even if it's not used
			if(page.getPrivateStr("RUNSMTPSERVER").equalsIgnoreCase("true"))
			{
				smtpServerThread.start();
				serviceEngine.startTickDown(Thread.currentThread().getThreadGroup(),smtpServerThread,Tickable.TICKID_EMAIL,CMProps.getTickMillis(),(int)CMProps.getTicksPerMinute() * 5);
			}
			else
			{
				smtpServerThread = null;
				CMProps.setBoolAllVar(CMProps.Bool.EMAILFORWARDING,false);
			}

			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading base classes");
			// wait for baseC
			while((tCode!=MudHost.MAIN_HOST)
			&&(!bootSync.get())
			&&(CMLib.s_sleep(500)))
			{}
			if(!CMClass.loadAllCoffeeMudClasses(page))
			{
				fatalStartupError(t,0);
				return false;
			}
			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading factions");
			if((tCode==MAIN_HOST)
			||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.FACTIONS.name())))
				CMLib.factions().reloadFactions(CMProps.getVar(CMProps.Str.PREFACTIONS));

			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: initializing classes");
			CMClass.instance().intializeClasses();

			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading expertises");
			if((tCode==MudHost.MAIN_HOST)||(CMProps.isPrivateToMe(CMLib.Library.EXPERTISES.name())))
			{
				CMLib.expertises().recompileExpertises();
				Log.sysOut(Thread.currentThread().getName(),"Expertises defined: "+CMLib.expertises().numExpertises());
			}

			CMLib.lang().setLocale(CMLib.props().getStr("LANGUAGE"),CMLib.props().getStr("COUNTRY"));
			if((threadCode==MudHost.MAIN_HOST)
			||(CMLib.time()!=CMLib.library(MudHost.MAIN_HOST, CMLib.Library.TIME)))
				CMLib.time().globalClock().initializeINIClock(page);
			else
			{
				CMProps.setIntVar(CMProps.Int.TICKSPERMUDDAY,""+((CMProps.getMillisPerMudHour()*CMLib.time().globalClock().getHoursInDay()/CMProps.getTickMillis())));
				CMProps.setIntVar(CMProps.Int.TICKSPERMUDMONTH,""+((CMProps.getMillisPerMudHour()*CMLib.time().globalClock().getHoursInDay()*CMLib.time().globalClock().getDaysInMonth()/CMProps.getTickMillis())));
			}

			if(tCode==MudHost.MAIN_HOST)
				bootSync.set(true);

			if((tCode==MAIN_HOST)
			||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.CHANNELS.name()))
			||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.JOURNALS.name())))
			{
				int numChannelsLoaded=0;
				int numJournalsLoaded=0;
				if((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.CHANNELS.name())))
				{
					final String normalChannels=page.getStr("CHANNELS");
					final String i3Channels=page.getBoolean("RUNI3SERVER") ? page.getStr("ICHANNELS") : "";
					final String imc2Channels=page.getBoolean("RUNIMC2CLIENT") ? page.getStr("IMC2CHANNELS") : "";
					numChannelsLoaded=CMLib.channels().loadChannels(normalChannels, i3Channels, imc2Channels);
				}
				if((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.JOURNALS.name())))
				{
					numJournalsLoaded=CMLib.journals().loadCommandJournals(page.getStr("COMMANDJOURNALS"));
					numJournalsLoaded+=CMLib.journals().loadForumJournals(page.getStr("FORUMJOURNALS"));
				}
				Log.sysOut(Thread.currentThread().getName(),"Channels loaded   : "+(numChannelsLoaded+numJournalsLoaded));
			}

			if((tCode==MAIN_HOST)
			||(page.getRawPrivateStr("SYSOPMASK")!=null)
			||(checkPrivate&&CMProps.isPrivateToMe("SECURITY"))
			) // needs to be after journals, for journal flags
			{
				CMSecurity.setSysOp(page.getStr("SYSOPMASK")); // requires all classes be loaded
				CMSecurity.parseGroups(page);
			}
			else
				CMSecurity.shareWith(MAIN_HOST);

			if((tCode==MAIN_HOST)
			||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.SOCIALS.name())))
			{
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading socials");
				CMLib.socials().unloadSocials();
				final List<String> list = CMLib.socials().getSocialsBaseList();
				if(list.size()==0)
					Log.errOut(Thread.currentThread().getName(),"WARNING: Unable to load socials from socials.txt!");
				else
					Log.sysOut(Thread.currentThread().getName(),"Socials loaded    : "+list.size());
			}

			final Map<String,Clan> clanPostLoads=new TreeMap<String,Clan>();
			if((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.CLANS.name())))
			{
				final List<Clan> clans = CMLib.database().DBReadAllClans();
				for(final Clan C : clans)
				{
					CMLib.clans().addClan(C);
					clanPostLoads.put(C.clanID(), C);
				}
				Log.sysOut(Thread.currentThread().getName(),"Clans loaded      : "+CMLib.clans().numClans());
			}

			if((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.FACTIONS.name())))
				serviceEngine.startTickDown(Thread.currentThread().getThreadGroup(),CMLib.factions(),Tickable.TICKID_MOB,CMProps.getTickMillis(),10);

			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Starting CM1");
			startCM1();

			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Starting I3");
			startIntermud3();

			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Starting IMC2");
			startIntermud2();

			checkedSleep(500);

			if((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.CATALOG.name())))
			{
				Log.sysOut(Thread.currentThread().getName(),"Loading catalog...");
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading catalog....");
				CMLib.database().DBReadCatalogs();
			}

			if((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.MAP.name())))
			{
				Log.sysOut(Thread.currentThread().getName(),"Loading map...");
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading rooms....");
				CMLib.database().DBReadAllRooms(null);
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading space....");
				CMLib.database().DBReadSpace();
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: preparing map....");
				Log.sysOut(Thread.currentThread().getName(),"Preparing map...");
				CMLib.database().DBReadArtifacts();
				for(final Enumeration<Area> a=CMLib.map().areas();a.hasMoreElements();)
				{
					final Area A=a.nextElement();
					CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: filling map ("+A.Name()+")");
					A.fillInAreaRooms();
				}
				{
					final MOB mob=CMClass.getFactoryMOB();
					final CMMsg msg=CMClass.getMsg(mob,null,CMMsg.MSG_STARTUP,null);
					CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Sending room startup.");
					for(final Enumeration<Room> a=CMLib.map().rooms();a.hasMoreElements();)
					{
						final Room R=a.nextElement();
						if(R!=null)
						{
							msg.setTarget(R);
							R.send(mob, msg);
						}
					}
					mob.destroy();
				}

				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Map Load Complete.");
				Log.sysOut(Thread.currentThread().getName(),"Mapped rooms      : "+CMLib.map().numRooms()+" in "+CMLib.map().numAreas()+" areas");
				if(CMLib.space().numSpaceObjects()>0)
					Log.sysOut(Thread.currentThread().getName(),"Space objects     : "+CMLib.space().numSpaceObjects());

				if(!CMLib.map().roomIDs().hasMoreElements())
				{
					Log.sysOut("NO MAPPED ROOM?!  I'll make ya one!");
					final String id="START";//New Area#0";
					final Area newArea=CMClass.getAreaType("StdArea");
					newArea.setName(CMLib.lang().L("New Area"));
					CMLib.map().addArea(newArea);
					CMLib.database().DBCreateArea(newArea);
					final Room room=CMClass.getLocale("StdRoom");
					room.setRoomID(id);
					room.setArea(newArea);
					room.setDisplayText(CMLib.lang().L("New Room"));
					room.setDescription(CMLib.lang().L("Brand new database room! You need to change this text with the MODIFY ROOM command.  If your character is not an Archon, pick up the book you see here and read it immediately!"));
					CMLib.map().registerWorldObjectLoaded(newArea, null, newArea);
					CMLib.database().DBCreateRoom(room);
					final Item I=CMClass.getMiscMagic("ManualArchon");
					room.addItem(I);
					CMLib.database().DBUpdateItems(room);
				}
			}

			if(clanPostLoads.size()>0)
			{
				final int num = CMLib.database().DBReadClanItems(clanPostLoads);
				Log.sysOut(Thread.currentThread().getName(),"Clan owned items  : "+num);
			}

			if((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.QUEST.name())))
			{
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Loading Quests");
				CMLib.quests().shutdown();
				for(final Quest Q : CMLib.database().DBReadQuests())
					CMLib.quests().addQuest(Q);
				if(CMLib.quests().numQuests()>0)
					Log.sysOut(Thread.currentThread().getName(),"Quests loaded     : "+CMLib.quests().numQuests());
			}

			if(tCode!=MAIN_HOST)
			{
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Waiting for HOST0");
				while((!MUD.bringDown)
				&&(!CMProps.getBoolVar(CMProps.Bool.MUDSTARTED))
				&&(!CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN)))
				{
					if(!checkedSleep(500))
						break;
				}
				if((MUD.bringDown)
				||(!CMProps.getBoolVar(CMProps.Bool.MUDSTARTED))
				||(CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN)))
					return false;

			}

			if((tCode==MAIN_HOST)
			||(checkPrivate
				&& CMProps.isPrivateToMe(CMLib.Library.LOGIN.name())))
			{
				CMLib.login().initStartRooms(page);
				CMLib.login().initDeathRooms(page);
				CMLib.login().initBodyRooms(page);
			}

			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: readying for connections.");
			try
			{
				CMLib.activateLibraries();
				Log.sysOut(Thread.currentThread().getName(),"Services and utilities started");
			}
			catch (final Throwable th)
			{
				Log.errOut(Thread.currentThread().getName(),"CoffeeMud Server initHost() failed");
				Log.errOut(Thread.currentThread().getName(),th);
				fatalStartupError(t,4);
				return false;
			}

			final StringBuffer str=new StringBuffer("");
			for(int m=0;m<CMLib.hosts().size();m++)
			{
				final MudHost mud=CMLib.hosts().get(m);
				str.append(" "+mud.getPort());
			}
			CMProps.setVar(CMProps.Str.MUDPORTS,str.toString());
			CMProps.setBoolAllVar(CMProps.Bool.MUDSTARTED,true);
			CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"OK");
			Log.sysOut(Thread.currentThread().getName(),"Host#"+threadCode+" initializated.");
			return true;
		}

		@Override
		public void run()
		{
			CMLib.initialize(); // initialize the lib
			CMClass.initialize(); // initialize the classes
			Log.shareWith(MudHost.MAIN_HOST);
			Resources.shareWith(MudHost.MAIN_HOST);

			// wait for ini to be loaded, and for other matters
			if(threadCode!=MAIN_HOST)
			{
				while((CMLib.library(MAIN_HOST,CMLib.Library.INTERMUD)==null)&&(!MUD.bringDown))
				{
					if(!checkedSleep(500))
						break;
				}
				if(MUD.bringDown)
					return;
			}
			final CMProps page=CMProps.loadPropPage("//"+iniFile);
			if ((page==null)||(!page.isLoaded()))
			{
				Log.errOut(Thread.currentThread().getName(),"ERROR: Unable to read ini file: '"+iniFile+"'.");
				System.err.println("MUD/ERROR: Unable to read ini file: '"+iniFile+"'.");
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"A terminal error has occured!");
				return;
			}
			page.resetSystemVars();
			CMProps.setBoolAllVar(CMProps.Bool.MUDSTARTED,false);
			serviceEngine.activate();

			if(threadCode!=MAIN_HOST)
			{
				if(CMath.isInteger(page.getPrivateStr("NUMLOGS")))
				{
					Log.newInstance();
					Log.instance().configureLogFile(logName,page.getInt("NUMLOGS"));
					Log.instance().configureLog(Log.Type.info, page.getStr("SYSMSGS"));
					Log.instance().configureLog(Log.Type.error, page.getStr("ERRMSGS"));
					Log.instance().configureLog(Log.Type.warning, page.getStr("WRNMSGS"));
					Log.instance().configureLog(Log.Type.debug, page.getStr("DBGMSGS"));
					Log.instance().configureLog(Log.Type.help, page.getStr("HLPMSGS"));
					Log.instance().configureLog(Log.Type.kills, page.getStr("KILMSGS"));
					Log.instance().configureLog(Log.Type.combat, page.getStr("CBTMSGS"));
					Log.instance().configureLog(Log.Type.access, page.getStr("ACCMSGS"));
				}
				if((page.getRawPrivateStr("SYSOPMASK")!=null)
				||(page.getRawPrivateStr("DISABLE")!=null)
				||(page.getRawPrivateStr("ENABLE")!=null)
				||(page.getRawPrivateStr("DEBUG")!=null)
				||(page.getRawPrivateStr("SAVE")!=null))
				{
					//page.resetSecurityVars();
				}
				else
					CMSecurity.instance().markShared();
			}

			if(page.getStr("DISABLE").trim().length()>0)
				Log.sysOut(Thread.currentThread().getName(),"Disabled subsystems: "+page.getStr("DISABLE"));
			if(page.getStr("DEBUG").trim().length()>0)
			{
				Log.sysOut(Thread.currentThread().getName(),"Debugging messages: "+page.getStr("DEBUG"));
				if(!Log.debugChannelOn())
					Log.errOut(Thread.currentThread().getName(),"Debug logging is disabled! Check your DBGMSGS flag!");
			}

			final DBConnector currentDBconnector=new DBConnector();
			CMLib.registerLibrary(new DBInterface(currentDBconnector,CMProps.getPrivateSubSet("DB.*")));
			CMProps.setVar(CMProps.Str.MUDVER, HOST_VERSION);

			// an arbitrary dividing line. After threadCode 0
			if(threadCode==MAIN_HOST)
			{
				CMLib.registerLibrary(serviceEngine);
				CMLib.registerLibrary(new IMudClient());
			}
			else
			{
				CMLib.registerLibrary(CMLib.library(MAIN_HOST,CMLib.Library.THREADS));
				CMLib.registerLibrary(CMLib.library(MAIN_HOST,CMLib.Library.INTERMUD));
			}
			CMProps.setVar(CMProps.Str.INIPATH,iniFile,false);
			CMProps.setUpLowVar(CMProps.Str.MUDNAME,name.replace('\'','`'));
			try
			{
				CMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting");
				CMProps.setVar(CMProps.Str.MUDBINDADDRESS,page.getStr("BIND"));
				CMProps.setIntVar(CMProps.Int.MUDBACKLOG,page.getInt("BACKLOG"));

				final LinkedList<MUD> hostMuds=new LinkedList<MUD>();
				String ports=page.getProperty("PORT");
				if((ports==null)||(ports.length()==0))
				{
					Log.errOut("HOST#"+this.threadCode+" could not start any listeners.");
					failedStart=true;
					return;
				}
				int pdex=ports.indexOf(',');
				while(pdex>0)
				{
					final MUD mud=new MUD("MUD@"+ports.substring(0,pdex));
					mud.setState(MudState.STARTING);
					mud.acceptConns=false;
					mud.port=CMath.s_int(ports.substring(0,pdex));
					ports=ports.substring(pdex+1);
					hostMuds.add(mud);
					mud.start();
					pdex=ports.indexOf(',');
				}
				final MUD mud=new MUD("MUD@"+ports);
				mud.setState(MudState.STARTING);
				mud.acceptConns=false;
				mud.port=CMath.s_int(ports);
				hostMuds.add(mud);
				mud.start();

				if(hostMuds.size()==0)
				{
					Log.errOut("HOST#"+this.threadCode+" could not start any listeners.");
					return;
				}

				boolean oneStarted=false;
				final long timeout=System.currentTimeMillis()+60000;
				while((!oneStarted) && (System.currentTimeMillis()<timeout))
				{
					int numStopped=0;
					for(final MUD m : hostMuds)
					{
						if(m.state==MudState.STOPPED)
							numStopped++;
						else
						if(m.state!=MudState.STARTING)
							oneStarted=true;
					}
					if(numStopped==hostMuds.size())
					{
						Log.errOut("HOST#"+this.threadCode+" could not start any listeners.");
						failedStart=true;
						return;
					}
					checkedSleep(100);
				}
				if(!oneStarted)
				{
					Log.errOut("HOST#"+this.threadCode+" could not start any listeners.");
					failedStart=true;
					return;
				}

				if(initHost())
				{
					Thread joinable=null;
					for(int i=0;i<CMLib.hosts().size();i++)
					{
						if(CMLib.hosts().get(i) instanceof Thread)
						{
							joinable=(Thread)CMLib.hosts().get(i);
							break;
						}
					}
					if(joinable!=null)
					{
						hostStarted=true;
						joinable.join();
					}
					else
						failedStart=true;
				}
				else
				{
					failedStart=true;
				}
			}
			catch(final InterruptedException e)
			{
				Log.errOut(Thread.currentThread().getName(),e);
			}
		}
	}

	@Override
	public List<Runnable> getOverdueThreads()
	{
		final Vector<Runnable> V=new Vector<Runnable>();
		for(int w=0;w<webServers.size();w++)
			V.addAll(webServers.get(w).getOverdueThreads());
		return V;
	}

	public static void main(final String a[])
	{
		String nameID="";
		Thread.currentThread().setName(("MUD"));
		final Vector<String> iniFiles=new Vector<String>();
		if(a.length>0)
		{
			for (final String element : a)
				nameID+=" "+element;
			nameID=nameID.trim();
			final List<String> V=CMParms.cleanParameterList(nameID);
			for(int v=0;v<V.size();v++)
			{
				final String s=V.get(v);
				if(s.toUpperCase().startsWith("BOOT=")&&(s.length()>5))
				{
					iniFiles.addElement(s.substring(5));
					V.remove(v);
					v--;
				}
			}
			nameID=CMParms.combine(V,0);
		}
		CMLib.initialize(); // initialize this threads libs

		if(iniFiles.size()==0)
			iniFiles.addElement("coffeemud.ini");
		if((nameID.length()==0)||(nameID.equalsIgnoreCase( "CoffeeMud" ))||nameID.equalsIgnoreCase("Your Muds Name"))
		{
			nameID="Unnamed_CoffeeMUD#";
			long idNumber=new Random(System.currentTimeMillis()).nextLong();
			try
			{
				idNumber=0;
				for(final Enumeration<NetworkInterface> e=NetworkInterface.getNetworkInterfaces();e.hasMoreElements();)
				{
					final NetworkInterface n=e.nextElement();
					idNumber^=n.getDisplayName().hashCode();
					try
					{
						final Method m=n.getClass().getMethod("getHardwareAddress");
						final Object o=m.invoke(n);
						if(o instanceof byte[])
						{
							for(int i=0;i<((byte[])o).length;i++)
								idNumber^=((byte[])o)[0] << (i*8);
						}
					}
					catch (final Exception e1)
					{
					}
				}
			}
			catch (final Exception e1)
			{
			}
			if(idNumber<0)
				idNumber=idNumber*-1;
			nameID=nameID+idNumber;
			System.err.println("*** Please give your mud a unique name in mud.bat or mudUNIX.sh!! ***");
		}
		else
		if(nameID.equalsIgnoreCase( "TheRealCoffeeMudCopyright2000-2022ByBoZimmerman" ))
			nameID="CoffeeMud";
		String iniFile=iniFiles.firstElement();
		final CMProps page=CMProps.loadPropPage("//"+iniFile);
		if ((page==null)||(!page.isLoaded()))
		{
			Log.instance().configureLogFile("mud",1);
			Log.instance().configureLog(Log.Type.info, "BOTH");
			Log.instance().configureLog(Log.Type.error, "BOTH");
			Log.instance().configureLog(Log.Type.warning, "BOTH");
			Log.instance().configureLog(Log.Type.debug, "BOTH");
			Log.instance().configureLog(Log.Type.help, "BOTH");
			Log.instance().configureLog(Log.Type.kills, "BOTH");
			Log.instance().configureLog(Log.Type.combat, "BOTH");
			Log.instance().configureLog(Log.Type.access, "BOTH");
			Log.errOut(Thread.currentThread().getName(),"ERROR: Unable to read ini file: '"+iniFile+"'.");
			System.err.println("MUD/ERROR: Unable to read ini file: '"+iniFile+"'.");
			CMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"A terminal error has occured!");
			System.exit(-1);
			return;
		}
		Log.shareWith(MudHost.MAIN_HOST);
		Log.instance().configureLogFile("mud",page.getInt("NUMLOGS"));
		Log.instance().configureLog(Log.Type.info, page.getStr("SYSMSGS"));
		Log.instance().configureLog(Log.Type.error, page.getStr("ERRMSGS"));
		Log.instance().configureLog(Log.Type.warning, page.getStr("WRNMSGS"));
		Log.instance().configureLog(Log.Type.debug, page.getStr("DBGMSGS"));
		Log.instance().configureLog(Log.Type.help, page.getStr("HLPMSGS"));
		Log.instance().configureLog(Log.Type.kills, page.getStr("KILMSGS"));
		Log.instance().configureLog(Log.Type.combat, page.getStr("CBTMSGS"));
		Log.instance().configureLog(Log.Type.access, page.getStr("ACCMSGS"));

		final Thread shutdownHook=new Thread("ShutdownHook")
		{
			@Override
			public void run()
			{
				if(!CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN))
				{
					ServiceEngine.panicDumpAllThreads();
					MUD.globalShutdown(null,true,null);
				}
			}
		};

		while(!bringDown)
		{
			final PrintStream eolStream = System.out;
			eolStream.println();
			grpid=0;
			Log.sysOut(Thread.currentThread().getName(),"CoffeeMud v"+HOST_VERSION);
			Log.sysOut(Thread.currentThread().getName(),"(C) 2000-2022 Bo Zimmerman");
			Log.sysOut(Thread.currentThread().getName(),"http://www.coffeemud.org");
			CMLib.hosts().clear();
			final LinkedList<HostGroup> myGroups=new LinkedList<HostGroup>();
			HostGroup mainHostGroup=null;
			ThreadGroup mainThreadGroup = null;
			for(int i=0;i<iniFiles.size();i++)
			{
				iniFile=iniFiles.elementAt(i);
				final ThreadGroup G=new ThreadGroup(i+"-MUD");
				final HostGroup H=new HostGroup(G,nameID,iniFile);
				if((mainHostGroup==null)||(mainThreadGroup == null))
				{
					mainHostGroup=H;
					mainThreadGroup=G;
				}
				myGroups.add(H);
				H.start();
			}
			if(mainHostGroup==null)
			{
				Log.errOut("CoffeeMud failed to start.");
				MUD.bringDown=true;
				CMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN, true);
			}
			else
			{
				final long timeout=System.currentTimeMillis()+1800000; /// 30 mins
				int numPending=1;
				while((numPending>0)&&(System.currentTimeMillis()<timeout))
				{
					numPending=0;
					for(final HostGroup g : myGroups)
					{
						if(!g.failedToStart() && !g.isStarted())
							numPending++;
					}
					if(mainHostGroup.failedToStart())
						break;
					checkedSleep(100);
				}
				if(mainHostGroup.failedToStart())
				{
					Log.errOut("CoffeeMud failed to start.");
					MUD.bringDown=true;
					CMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN, true);
				}
				else
				{
					Runtime.getRuntime().addShutdownHook(shutdownHook);
					for(int i=0;i<CMLib.hosts().size();i++)
						CMLib.hosts().get(i).setAcceptConnections(true);
					Log.sysOut(Thread.currentThread().getName(),"Initialization complete.");
					try
					{
						mainHostGroup.join();
					}
					catch(final Exception e)
					{
						e.printStackTrace(); Log.errOut(Thread.currentThread().getName(),e);
					}
					Runtime.getRuntime().removeShutdownHook(shutdownHook);
				}
			}

			System.gc();
			checkedSleep(1000);
			System.runFinalization();
			checkedSleep(1000);

			if(activeThreadCount(Thread.currentThread().getThreadGroup(),true)>1)
			{
				checkedSleep(1000);
				killCount(Thread.currentThread().getThreadGroup(),true);
				checkedSleep(1000);
				if(activeThreadCount(Thread.currentThread().getThreadGroup(),true)>1)
				{
					Log.sysOut(Thread.currentThread().getName(),"WARNING: "
						+ activeThreadCount(Thread.currentThread().getThreadGroup(),true)
						+" other thread(s) are still active!");
					threadList(Thread.currentThread().getThreadGroup(),true);
				}
			}
			if(!bringDown)
			{
				if(execExternalCommand!=null)
				{
					execExternalRestart(execExternalCommand);
					execExternalCommand=null;
					bringDown=true;
				}
			}
		}
	}

	public static void execExternalRestart(final String command)
	{
		final Runtime r=Runtime.getRuntime();
		try
		{
			if((command==null) || (command.equalsIgnoreCase("hard")))
			{
				if(new File("./restart.sh").exists())
				{
					r.exec("sh restart.sh");
					Log.sysOut("Attempted to execute 'restart.sh' in "+new File(".").getCanonicalPath());
				}
				else
				if(new File(".\\restart.bat").exists())
				{
					r.exec("cmd.exe /c start \"\" restart.bat");
					Log.sysOut("Attempted to execute 'restart.bat' in "+new File(".").getCanonicalPath());
				}
			}
			else
			if(System.getProperty("os.name").toLowerCase().indexOf("windows")>=0)
			{
				r.exec("cmd.exe /c start \"\" "+command);
				Log.sysOut("Attempted to execute '"+command+"' in "+new File(".").getCanonicalPath());
			}
			else
			{
				r.exec("sh "+command);
				Log.sysOut("Attempted to execute '"+command+"' in "+new File(".").getCanonicalPath());
			}
		}
		catch (final IOException e)
		{
			Log.errOut(e);
		}
	}

	@Override
	public void setAcceptConnections(final boolean truefalse)
	{
		acceptConns=truefalse;
	}

	@Override
	public boolean isAcceptingConnections()
	{
		return acceptConns;
	}

	@Override
	public long getUptimeSecs()
	{
		return (System.currentTimeMillis()-startupTime)/1000;
	}

	@Override
	public String executeCommand(final String cmd) throws Exception
	{
		final List<String> V=CMParms.parse(cmd);
		if(V.size()==0)
			throw new CMException("Unknown command!");
		final String word=V.get(0);
		if(word.equalsIgnoreCase("GET")&&(V.size()>1))
		{
			final String what=V.get(1);
			if(what.equalsIgnoreCase("CM1SERVER")&&(V.size()>2))
			{
				final String what2=V.get(2);
				if(cm1Servers.size()==0)
					return "Failure";
				final CM1Server svr=cm1Servers.get(0);
				if(what2.equalsIgnoreCase("PORT"))
					return ""+svr.getPort();
				else
				if(what2.equalsIgnoreCase("NAME"))
					return ""+svr.getName();
				return "Failure";
			}
			else
				return "Failure";
		}
		else
		if(word.equalsIgnoreCase("TICK")&&(V.size()>1))
		{
			final String what=V.get(1);
			if(what.equalsIgnoreCase("SMTP"))
			{
				if((smtpServerThread != null)
				&&(smtpServerThread.tick(smtpServerThread, Tickable.TICKID_EMAIL)))
					return "Done";
				else
					return "Failure";
			}
			else
				return "Failure";
		}
		else
		if(word.equalsIgnoreCase("START")&&(V.size()>1))
		{
			final String what=V.get(1);
			if(what.equalsIgnoreCase("I3"))
			{
				startIntermud3();
				return "Done";
			}
			else
			if(what.equalsIgnoreCase("IMC2"))
			{
				startIntermud2();
				return "Done";
			}
			else
			if(what.equalsIgnoreCase("WEB"))
			{
				if(V.size()<3)
					return "Need Server Name";
				if(startWebServer(CMProps.instance(),V.get(2)))
					return "Done";
				else
					return "Failure";
			}
			else
			if(what.equalsIgnoreCase("CM1"))
			{
				if(V.size()<3)
					return "Need Server Name";
				if(startCM1())
					return "Done";
				else
					return "Failure";
			}
			else
			if(what.equalsIgnoreCase("SMTP"))
			{
				if(smtpServerThread==null)
				{
					smtpServerThread = new SMTPserver(CMLib.mud(0)); // initializes variables, even if it's not used
					smtpServerThread.start();
					serviceEngine.startTickDown(Thread.currentThread().getThreadGroup(),smtpServerThread,Tickable.TICKID_EMAIL,CMProps.getTickMillis(),(int)CMProps.getTicksPerMinute() * 5);
					return "Done";
				}
				return "Failure";
			}
		}
		else
		if(word.equalsIgnoreCase("STOP")&&(V.size()>1))
		{
			final String what=V.get(1);
			if(what.equalsIgnoreCase("WEB"))
			{
				if(V.size()<3)
					return "Need Server Name";
				if(stopWebServer(V.get(2)))
					return "Done";
				else
					return "Failure";
			}
			else
			if(what.equalsIgnoreCase("I3"))
			{
				if(i3server!=null)
					I3Server.shutdown();
				i3server=null;
				return "Done";
			}
			else
			if(what.equalsIgnoreCase("IMC2"))
			{
				if(imc2server!=null)
					imc2server.shutdown();
				return "Done";
			}
			else
			if(what.equalsIgnoreCase("CM1"))
			{
				if(stopCM1())
					return "Done";
				else
					return "Failure";
			}
			else
			if(what.equalsIgnoreCase("SMTP"))
			{
				if(smtpServerThread!=null)
				{
					smtpServerThread.shutdown();
					serviceEngine.deleteAllTicks(smtpServerThread);
					smtpServerThread = null;
					return "Done";
				}
				return "Failure";
			}
		}
		else
		if(word.equalsIgnoreCase("WEBSERVER")&&(V.size()>2))
		{
			final String var = V.get(2);
			WebServer server=null;
			for(final WebServer serv : webServers)
			{
				if(serv.getName().equalsIgnoreCase(V.get(1)))
				{
					server=serv;
					break;
				}
				else
				if(CMath.s_bool(serv.getConfig().getMiscProp("ADMIN")))
				{
					if(V.get(1).equalsIgnoreCase("ADMIN"))
					{
						server=serv;
						break;
					}
				}
				else
				{
					if(V.get(1).equalsIgnoreCase("PUB"))
					{
						server=serv;
						break;
					}
				}
			}
			if(server==null)
				throw new CMException("Unknown server: "+var);
			if(var.equalsIgnoreCase("PORT"))
			{
				final int[] ports = server.getConfig().getHttpListenPorts();
				if(ports.length==0)
					return "";
				return Integer.toString(ports[0]);
			}
			else
			if((V.size()>3)&&(var.equalsIgnoreCase("DEBUG")))
				server.getConfig().setDebugFlag(V.get(3));
			else
			if((V.size()>3)&&(var.equalsIgnoreCase("ACCESS")))
				server.getConfig().setDebugFlag(V.get(3));
			else
				throw new CMException("Unknown variable: "+var);
			return "";
		}
		throw new CMException("Unknown command: "+word);
	}
}

<MSG> 

git-svn-id: svn://192.168.1.10/public/CoffeeMud@1320 0d6f1817-ed0e-0410-87c9-987e46238f29

<DFF> @@ -20,7 +20,7 @@ public class MUD extends Thread implements Host
 	public String execExternalCommand=null;
 
 	public static final float HOST_VERSION_MAJOR=(float)3.0;
-	public static final float HOST_VERSION_MINOR=(float)5.5;
+	public static final float HOST_VERSION_MINOR=(float)5.6;
 	
 	private boolean acceptConnections=false;
 	private String offlineReason=new String("UNKNOWN");

{'commit': 'diff --git a/com/planet_ink/coffee_mud/Commands/base/ItemUsage.java b/com/planet_ink/coffee_mud/Commands/base/ItemUsage.java\nindex 069f8e5676..c25a509e8c 100644\n--- a/com/planet_ink/coffee_mud/Commands/base/ItemUsage.java\n+++ b/com/planet_ink/coffee_mud/Commands/base/ItemUsage.java\n@@ -679,8 +679,7 @@ public class ItemUsage\n \t\tdo\r\n \t\t{\r\n \t\t\tItem thisItem=mob.fetchWornItem(Util.combine(commands,0)+addendumStr);\r\n-\t\t\tif((thisItem==null)\r\n-\t\t\t   ||((thisItem!=null)&&(!Sense.canBeSeenBy(thisItem,mob))))\r\n+\t\t\tif(thisItem==null)\r\n \t\t\t{\r\n \t\t\t\tif(!doneSomething)\r\n \t\t\t\t\tmob.tell("You don\'t seem to be wearing that.");\r\ndiff --git a/com/planet_ink/coffee_mud/Items/LightSource.java b/com/planet_ink/coffee_mud/Items/LightSource.java\nindex c27b3ac474..d986e70c01 100644\n--- a/com/planet_ink/coffee_mud/Items/LightSource.java\n+++ b/com/planet_ink/coffee_mud/Items/LightSource.java\n@@ -110,11 +110,7 @@ public class LightSource extends StdItem implements Light\n \t\t\t\tif(myLight.owner() instanceof Room)\r\n \t\t\t\t{\r\n \t\t\t\t\tif(((Room)myLight.owner()).numInhabitants()>0)\r\n-\t\t\t\t\t{\r\n-\t\t\t\t\t\tMOB mob=((Room)myLight.owner()).fetchInhabitant(0);\r\n-\t\t\t\t\t\tif(mob!=null)\r\n-\t\t\t\t\t\t\t((Room)myLight.owner()).show(mob,null,Affect.MSG_OK_VISUAL,myLight.name()+" flickers and burns out.");\r\n-\t\t\t\t\t}\r\n+\t\t\t\t\t\t((Room)myLight.owner()).showHappens(Affect.MSG_OK_VISUAL,myLight.name()+" flickers and burns out.");\r\n \t\t\t\t\tif(myLight.destroyedWhenBurnedOut())\r\n \t\t\t\t\t\tmyLight.destroyThis();\r\n \t\t\t\t\t((Room)myLight.owner()).recoverRoomStats();\r\n@@ -126,6 +122,10 @@ public class LightSource extends StdItem implements Light\n \t\t\t\t\tmyLight.setDuration(0);\r\n \t\t\t\t\tif(myLight.destroyedWhenBurnedOut())\r\n \t\t\t\t\t\tmyLight.destroyThis();\r\n+\t\t\t\t\t((MOB)myLight.owner()).recoverEnvStats();\r\n+\t\t\t\t\t((MOB)myLight.owner()).recoverCharStats();\r\n+\t\t\t\t\t((MOB)myLight.owner()).recoverMaxState();\r\n+\t\t\t\t\t((MOB)myLight.owner()).recoverEnvStats();\r\n \t\t\t\t\t((MOB)myLight.owner()).location().recoverRoomStats();\r\n \t\t\t\t}\r\n \t\t\t}\r\ndiff --git a/com/planet_ink/coffee_mud/Items/StdItem.java b/com/planet_ink/coffee_mud/Items/StdItem.java\nindex 7b785aa975..40350d8aba 100644\n--- a/com/planet_ink/coffee_mud/Items/StdItem.java\n+++ b/com/planet_ink/coffee_mud/Items/StdItem.java\n@@ -490,11 +490,6 @@ public class StdItem implements Item\n \t\t\t\tmob.tell(msg.toString());\r\n \t\t\t\treturn false;\r\n \t\t\t}\r\n-\t\t\tif(!canWear(mob))\r\n-\t\t\t{\r\n-\t\t\t\tmob.tell("Your hands are full.");\r\n-\t\t\t\treturn false;\r\n-\t\t\t}\r\n \t\t\tif(!mob.charStats().getMyRace().canWear(this))\r\n \t\t\t{\r\n \t\t\t\tmob.tell("You lack the anatomy to hold "+name()+".");\r\n@@ -505,6 +500,23 @@ public class StdItem implements Item\n \t\t\t\tmob.tell("That looks too advanced for you.");\r\n \t\t\t\treturn false;\r\n \t\t\t}\r\n+\t\t\tif(!canWear(mob))\r\n+\t\t\t{\r\n+\t\t\t\tItem alreadyWearing=mob.fetchWornItem(Item.HELD);\r\n+\t\t\t\tif(alreadyWearing!=null)\r\n+\t\t\t\t{\r\n+\t\t\t\t\tif(!ExternalPlay.remove(mob,alreadyWearing))\r\n+\t\t\t\t\t{\r\n+\t\t\t\t\t\tmob.tell("Your hands are full.");\r\n+\t\t\t\t\t\treturn false;\r\n+\t\t\t\t\t}\r\n+\t\t\t\t}\r\n+\t\t\t\telse\r\n+\t\t\t\t{\r\n+\t\t\t\t\tmob.tell("Your hands are full.");\r\n+\t\t\t\t\treturn false;\r\n+\t\t\t\t}\r\n+\t\t\t}\r\n \t\t\treturn true;\r\n \t\tcase Affect.TYP_WEAR:\r\n \t\t\tif(properWornBitmap==0)\r\n@@ -517,16 +529,6 @@ public class StdItem implements Item\n \t\t\t\tmob.tell("You are already wearing "+name()+".");\r\n \t\t\t\treturn false;\r\n \t\t\t}\r\n-\t\t\tif(!canWear(mob))\r\n-\t\t\t{\t\r\n-\t\t\t\tlong cantWearAt=whereCantWear(mob);\r\n-\t\t\t\tItem alreadyWearing=mob.fetchWornItem(cantWearAt);\r\n-\t\t\t\tif(alreadyWearing!=null)\r\n-\t\t\t\t\tmob.tell("You are already wearing "+alreadyWearing.name()+" on your "+Sense.wornLocation(cantWearAt)+".");\r\n-\t\t\t\telse\r\n-\t\t\t\t\tmob.tell("You are already wearing something on your "+Sense.wornLocation(cantWearAt)+".");\r\n-\t\t\t\treturn false;\r\n-\t\t\t}\r\n \t\t\tif(!mob.charStats().getMyRace().canWear(this))\r\n \t\t\t{\r\n \t\t\t\tmob.tell("You lack the anatomy to wear "+name()+".");\r\n@@ -537,6 +539,24 @@ public class StdItem implements Item\n \t\t\t\tmob.tell("That looks too advanced for you.");\r\n \t\t\t\treturn false;\r\n \t\t\t}\r\n+\t\t\tif(!canWear(mob))\r\n+\t\t\t{\t\r\n+\t\t\t\tlong cantWearAt=whereCantWear(mob);\r\n+\t\t\t\tItem alreadyWearing=mob.fetchWornItem(cantWearAt);\r\n+\t\t\t\tif(alreadyWearing!=null)\r\n+\t\t\t\t{\r\n+\t\t\t\t\tif(!ExternalPlay.remove(mob,alreadyWearing))\r\n+\t\t\t\t\t{\r\n+\t\t\t\t\t\tmob.tell("You are already wearing "+alreadyWearing.name()+" on your "+Sense.wornLocation(cantWearAt)+".");\r\n+\t\t\t\t\t\treturn false;\r\n+\t\t\t\t\t}\r\n+\t\t\t\t}\r\n+\t\t\t\telse\r\n+\t\t\t\t{\r\n+\t\t\t\t\tmob.tell("You are already wearing something on your "+Sense.wornLocation(cantWearAt)+".");\r\n+\t\t\t\t\treturn false;\r\n+\t\t\t\t}\r\n+\t\t\t}\r\n \t\t\treturn true;\r\n \t\tcase Affect.TYP_WIELD:\r\n \t\t\tif(!canBeWornAt(Item.WIELD))\r\n@@ -549,35 +569,43 @@ public class StdItem implements Item\n \t\t\t\tmob.tell("That\'s already being wielded.");\r\n \t\t\t\treturn false;\r\n \t\t\t}\r\n+\t\t\tif(!mob.charStats().getMyRace().canWear(this))\r\n+\t\t\t{\r\n+\t\t\t\tmob.tell("You lack the anatomy to wield "+name()+".");\r\n+\t\t\t\treturn false;\r\n+\t\t\t}\r\n+\t\t\tif(envStats().level()>mob.envStats().level())\r\n+\t\t\t{\r\n+\t\t\t\tmob.tell("That looks too advanced for you.");\r\n+\t\t\t\treturn false;\r\n+\t\t\t}\r\n \t\t\tif(mob.amWearingSomethingHere(Item.WIELD))\r\n \t\t\t{\r\n \t\t\t\tItem alreadyWearing=mob.fetchWornItem(Item.WIELD);\r\n \t\t\t\tif(alreadyWearing!=null)\r\n-\t\t\t\t\tmob.tell("You are already wielding "+alreadyWearing.name()+".");\r\n+\t\t\t\t{\r\n+\t\t\t\t\tif(!ExternalPlay.remove(mob,alreadyWearing))\r\n+\t\t\t\t\t{\r\n+\t\t\t\t\t\tmob.tell("You are already wielding "+alreadyWearing.name()+".");\r\n+\t\t\t\t\t\treturn false;\r\n+\t\t\t\t\t}\r\n+\t\t\t\t}\r\n \t\t\t\telse\r\n+\t\t\t\t{\r\n \t\t\t\t\tmob.tell("You are already wielding something.");\r\n-\t\t\t\treturn false;\r\n+\t\t\t\t\treturn false;\r\n+\t\t\t\t}\r\n \t\t\t}\r\n \t\t\tif(!canWear(mob))\r\n \t\t\t{\t\r\n \t\t\t\tmob.tell("You can\'t wield "+name()+", your hands are full.");\r\n \t\t\t\treturn false;\r\n \t\t\t}\r\n-\t\t\tif(!mob.charStats().getMyRace().canWear(this))\r\n-\t\t\t{\r\n-\t\t\t\tmob.tell("You lack the anatomy to wield "+name()+".");\r\n-\t\t\t\treturn false;\r\n-\t\t\t}\r\n-\t\t\tif(envStats().level()>mob.envStats().level())\r\n-\t\t\t{\r\n-\t\t\t\tmob.tell("That looks too advanced for you.");\r\n-\t\t\t\treturn false;\r\n-\t\t\t}\r\n \t\t\treturn true;\r\n \t\tcase Affect.TYP_GET:\r\n \t\t\tif((affect.tool()==null)||(affect.tool() instanceof MOB))\r\n \t\t\t{\r\n-\t\t\t\tif(!Sense.canBeSeenBy(this,mob))\r\n+\t\t\t\tif((!Sense.canBeSeenBy(this,mob))&&(amWearingAt(Item.INVENTORY)))\r\n \t\t\t\t{\r\n \t\t\t\t\tmob.tell("You can\'t see that.");\r\n \t\t\t\t\treturn false;\r\ndiff --git a/com/planet_ink/coffee_mud/application/MUD.java b/com/planet_ink/coffee_mud/application/MUD.java\nindex feeecdfc76..5a356eea3a 100644\n--- a/com/planet_ink/coffee_mud/application/MUD.java\n+++ b/com/planet_ink/coffee_mud/application/MUD.java\n@@ -20,7 +20,7 @@ public class MUD extends Thread implements Host\n \tpublic String execExternalCommand=null;\r\n \r\n \tpublic static final float HOST_VERSION_MAJOR=(float)3.0;\r\n-\tpublic static final float HOST_VERSION_MINOR=(float)5.5;\r\n+\tpublic static final float HOST_VERSION_MINOR=(float)5.6;\r\n \t\r\n \tprivate boolean acceptConnections=false;\r\n \tprivate String offlineReason=new String("UNKNOWN");\r\ndiff --git a/guides/todo.txt b/guides/todo.txt\nindex 164b6b43f1..a829c91a21 100644\n--- a/guides/todo.txt\n+++ b/guides/todo.txt\n@@ -18,6 +18,14 @@ Deadly weak-bridge exit.  If too much weight, you fall and die.\n Deadly rope-bridge or narrow ledge exit.  Balance required not to fall and die.  Dex check\r\n for most, or Balance skill for thieves.  \r\n \r\n+scrimshaw common skill\r\n+property to eliminate save thread clearing of an item\r\n+also, flag itemtransporter to make items not clearable.\r\n+clear out the sky after some delay\r\n+try to attach skys AGAIN\r\n+Mining, Foraging, Etc ought to be able to accept a parameter, so MINE IRON would do mine, but would stop mining if you found something other than IRON, and tell you where you might try looking.\r\n+CONTINUAL LIGHT spell\r\n+\r\n Gap exit.  Jump required not to fall in and die.  Strength check for most, Jump\r\n skill available all for help.\r\n \r\n', 'commit_subject': '', 'repo_name': 'bozimmerman/CoffeeMud', 'committer': {'name': 'bozimmerman', 'email': 'dc45fe023482b3b890b5e574e53c1d051f45b1ef@zimmers.net', 'time_sec': '1041812344', 'tz_offset': '0', 'date': {'seconds': '1041812344'}}, 'commit_tree': '56886f40099b061b980a4e00969367e1e1b568f5', 'commit_message': '\n\ngit-svn-id: svn://192.168.1.10/public/CoffeeMud@1320 0d6f1817-ed0e-0410-87c9-987e46238f29\n', 'language_name': 'JavaScript', 'license': 'apache-2.0', 'hunks': '@@ -20,7 +20,7 @@ public class MUD extends Thread implements Host\n \tpublic String execExternalCommand=null;\r\n \r\n \tpublic static final float HOST_VERSION_MAJOR=(float)3.0;\r\n-\tpublic static final float HOST_VERSION_MINOR=(float)5.5;\r\n+\tpublic static final float HOST_VERSION_MINOR=(float)5.6;\r\n \t\r\n \tprivate boolean acceptConnections=false;\r\n \tprivate String offlineReason=new String("UNKNOWN");\r\n', 'addition_count': 1, 'deletion_count': 1, 'src_file': 'a/com/planet_ink/coffee_mud/application/MUD.java', 'tgt_file': 'b/com/planet_ink/coffee_mud/application/MUD.java', 'file_extension': '.java', 'before_file': 'package com.planet_ink.coffee_mud.application;\nimport com.planet_ink.coffee_mud.core.*;\nimport com.planet_ink.coffee_mud.core.CMProps.Str;\nimport com.planet_ink.coffee_mud.core.CMSecurity.DbgFlag;\nimport com.planet_ink.coffee_mud.core.interfaces.*;\nimport com.planet_ink.coffee_mud.core.collections.*;\nimport com.planet_ink.coffee_mud.core.exceptions.*;\nimport com.planet_ink.coffee_mud.Abilities.interfaces.*;\nimport com.planet_ink.coffee_mud.Areas.interfaces.*;\nimport com.planet_ink.coffee_mud.Behaviors.interfaces.*;\nimport com.planet_ink.coffee_mud.CharClasses.interfaces.*;\nimport com.planet_ink.coffee_mud.Commands.interfaces.*;\nimport com.planet_ink.coffee_mud.Common.interfaces.*;\nimport com.planet_ink.coffee_mud.Exits.interfaces.*;\nimport com.planet_ink.coffee_mud.Items.interfaces.*;\nimport com.planet_ink.coffee_mud.Locales.interfaces.*;\nimport com.planet_ink.coffee_mud.MOBS.interfaces.*;\nimport com.planet_ink.coffee_mud.Races.interfaces.*;\nimport com.planet_ink.coffee_mud.Libraries.interfaces.*;\n\tpublic String execExternalCommand=null;\r\n\r\n\tpublic static final float HOST_VERSION_MAJOR=(float)3.0;\r\n\tpublic static final float HOST_VERSION_MINOR=(float)5.5;\r\n\t\r\n\tprivate boolean acceptConnections=false;\r\n\tprivate String offlineReason=new String("UNKNOWN");\r\nimport com.planet_ink.coffee_mud.core.intermud.cm1.CM1Server;\nimport com.planet_ink.coffee_mud.core.intermud.i3.IMudInterface;\nimport com.planet_ink.coffee_mud.core.intermud.imc2.IMC2Driver;\nimport com.planet_ink.coffee_mud.core.intermud.i3.server.I3Server;\nimport com.planet_ink.coffee_web.http.MIMEType;\nimport com.planet_ink.coffee_web.interfaces.FileManager;\nimport com.planet_ink.coffee_web.server.WebServer;\nimport com.planet_ink.coffee_web.util.CWConfig;\nimport com.planet_ink.coffee_web.util.CWThread;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.InputStream;\nimport java.io.PrintStream;\nimport java.io.PrintWriter; // for writing to sockets\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Method;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.net.*;\nimport java.util.*;\nimport java.sql.*;\n\n/*\n   Copyright 2000-2022 Bo Zimmerman\n\n   Licensed under the Apache License, Version 2.0 (the "License");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n\t   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an "AS IS" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n*/\npublic class MUD extends Thread implements MudHost\n{\n\tprivate static final String\t  HOST_VERSION\t= "5.10.0.4";\n\n\tprivate static enum MudState\n\t{\n\t\tSTARTING,\n\t\tWAITING,\n\t\tACCEPTING,\n\t\tSTOPPED\n\t}\n\n\tprivate static enum ConnectState\n\t{\n\t\tNORMAL,\n\t\tBANNED,\n\t\tBLOCKED\n\t}\n\n\tprivate volatile MudState state\t\t = MudState.STOPPED;\n\tprivate ServerSocket\t  servsock\t = null;\n\tprivate boolean\t\t\t  acceptConns= false;\n\tprivate int\t\t\t\t  port\t\t = 5555;\n\tprivate final long\t\t  startupTime= System.currentTimeMillis();\n\tprivate final ThreadGroup threadGroup;\n\n\tprivate static volatile int\t \t\tgrpid\t\t\t\t= 0;\n\tprivate static boolean\t\t\t\tbringDown\t\t\t= false;\n\tprivate static String\t\t\t\texecExternalCommand\t= null;\n\tprivate static I3Server\t\t\t\ti3server\t\t\t= null;\n\tprivate static IMC2Driver\t\t\timc2server\t\t\t= null;\n\tprivate static List<WebServer>\t\twebServers\t\t\t= new Vector<WebServer>();\n\tprivate static SMTPserver\t\t\tsmtpServerThread\t= null;\n\tprivate static List<DBConnector>\tdatabases\t\t\t= new Vector<DBConnector>();\n\tprivate static List<CM1Server>\t\tcm1Servers\t\t\t= new Vector<CM1Server>();\n\tprivate static final ServiceEngine\tserviceEngine\t\t= new ServiceEngine();\n\tprivate static AtomicBoolean \t\tbootSync\t\t\t= new AtomicBoolean(false);\n\n\n\tpublic MUD(final String name)\n\t{\n\t\tsuper(name);\n\t\tthreadGroup=Thread.currentThread().getThreadGroup();\n\t}\n\n\t@Override\n\tpublic void acceptConnection(final Socket sock) throws SocketException, IOException\n\t{\n\t\tsetState(MudState.ACCEPTING);\n\t\tserviceEngine.executeRunnable(threadGroup.getName(),new ConnectionAcceptor(sock));\n\t}\n\n\t@Override\n\tpublic ThreadGroup threadGroup()\n\t{\n\t\treturn threadGroup;\n\t}\n\n\tprivate static boolean checkedSleep(final long millis)\n\t{\n\t\ttry\n\t\t{\n\t\t\tThread.sleep(millis);\n\t\t}\n\t\tcatch(final Exception e)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate class ConnectionAcceptor implements CMRunnable\n\t{\n\t\tSocket sock;\n\t\tlong startTime=0;\n\n\t\tpublic ConnectionAcceptor(final Socket sock) throws SocketException, IOException\n\t\t{\n\t\t\tthis.sock=sock;\n\t\t\tsock.setSoLinger(true,3);\n\t\t}\n\n\t\t@Override\n\t\tpublic long getStartTime()\n\t\t{\n\t\t\treturn startTime;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getGroupID()\n\t\t{\n\t\t\treturn Thread.currentThread().getThreadGroup().getName().charAt(0);\n\t\t}\n\n\t\t@Override\n\t\tpublic void run()\n\t\t{\n\t\t\tstartTime=System.currentTimeMillis();\n\t\t\ttry\n\t\t\t{\n\t\t\t\tif (acceptConns)\n\t\t\t\t{\n\t\t\t\t\tString address="unknown";\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\taddress=sock.getInetAddress().getHostAddress().trim();\n\t\t\t\t\t}\n\t\t\t\t\tcatch(final Exception e)\n\t\t\t\t\t{\n\t\t\t\t\t}\n\t\t\t\t\tConnectState proceed=ConnectState.NORMAL;\n\t\t\t\t\tif(CMSecurity.isBanned(address))\n\t\t\t\t\t\tproceed=ConnectState.BANNED;\n\t\t\t\t\tint numAtThisAddress=0;\n\t\t\t\t\tfinal long LastConnectionDelay=(5*60*1000);\n\t\t\t\t\tboolean anyAtThisAddress=false;\n\t\t\t\t\tfinal int maxAtThisAddress=6;\n\t\t\t\t\tif(!CMSecurity.isDisabled(CMSecurity.DisFlag.CONNSPAMBLOCK))\n\t\t\t\t\t{\n\t\t\t\t\t\tif(!CMProps.isOnWhiteList(CMProps.WhiteList.IPSCONN, address))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(CMSecurity.isIPBlocked(address))\n\t\t\t\t\t\t\t\tproceed = ConnectState.BANNED;\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t@SuppressWarnings("unchecked")\n\t\t\t\t\t\t\t\tList<Triad<String,Long,Integer>> accessed= (LinkedList<Triad<String,Long,Integer>>)Resources.staticInstance()._getResource("SYSTEM_IPACCESS_STATS");\n\t\t\t\t\t\t\t\tif(accessed == null)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\taccessed= new LinkedList<Triad<String,Long,Integer>>();\n\t\t\t\t\t\t\t\t\tResources.staticInstance()._submitResource("SYSTEM_IPACCESS_STATS",accessed);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tsynchronized(accessed)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfor(final Iterator<Triad<String,Long,Integer>> i=accessed.iterator();i.hasNext();)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tfinal Triad<String,Long,Integer> triad=i.next();\n\t\t\t\t\t\t\t\t\t\tif((triad.second.longValue()+LastConnectionDelay)<System.currentTimeMillis())\n\t\t\t\t\t\t\t\t\t\t\ti.remove();\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tif(triad.first.trim().equalsIgnoreCase(address))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tanyAtThisAddress=true;\n\t\t\t\t\t\t\t\t\t\t\ttriad.second=Long.valueOf(System.currentTimeMillis());\n\t\t\t\t\t\t\t\t\t\t\tnumAtThisAddress=triad.third.intValue()+1;\n\t\t\t\t\t\t\t\t\t\t\ttriad.third=Integer.valueOf(numAtThisAddress);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif(!anyAtThisAddress)\n\t\t\t\t\t\t\t\t\t\taccessed.add(new Triad<String,Long,Integer>(address,Long.valueOf(System.currentTimeMillis()),Integer.valueOf(1)));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t@SuppressWarnings("unchecked")\n\t\t\t\t\t\t\tSet<String> autoblocked= (Set<String>)Resources.staticInstance()._getResource("SYSTEM_IPACCESS_AUTOBLOCK");\n\t\t\t\t\t\t\tif(autoblocked == null)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tautoblocked= new TreeSet<String>();\n\t\t\t\t\t\t\t\tResources.staticInstance()._submitResource("SYSTEM_IPACCESS_AUTOBLOCK",autoblocked);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(autoblocked.contains(address.toUpperCase()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif(!anyAtThisAddress)\n\t\t\t\t\t\t\t\t\tautoblocked.remove(address.toUpperCase());\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tproceed=ConnectState.BLOCKED;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\tif(numAtThisAddress>=maxAtThisAddress)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tautoblocked.add(address.toUpperCase());\n\t\t\t\t\t\t\t\tproceed=ConnectState.BLOCKED;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif(proceed != ConnectState.NORMAL)\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal int abusiveCount=numAtThisAddress-maxAtThisAddress+1;\n\t\t\t\t\t\tfinal long rounder=Math.round(Math.sqrt(abusiveCount));\n\t\t\t\t\t\tif(abusiveCount == (rounder*rounder))\n\t\t\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Blocking a connection from "+address +" ("+numAtThisAddress+")");\n\t\t\t\t\t\ttry\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfinal PrintWriter out = new PrintWriter(sock.getOutputStream());\n\t\t\t\t\t\t\tStringBuffer introText;\n\t\t\t\t\t\t\tif(proceed==ConnectState.BLOCKED)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tintroText=new StringBuffer(Resources.getFileResource(Resources.makeFileResourceName("text/connblocked.txt"),true));\n\t\t\t\t\t\t\t\tintroText=CMStrings.replaceAll(introText, "@mins@", ""+(LastConnectionDelay/60000));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tintroText=Resources.getFileResource(Resources.makeFileResourceName("text/blocked.txt"),true);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttry\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tintroText = CMLib.webMacroFilter().virtualPageFilter(introText);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (final Exception ex)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout.print(introText.toString());\n\t\t\t\t\t\t\tout.flush();\n\t\t\t\t\t\t\tcheckedSleep(250);\n\t\t\t\t\t\t\tout.close();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch(final IOException e)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// dont say anything, just eat it.\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsock = null;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Connection from "+address);\n\t\t\t\t\t\t// also the intro page\n\t\t\t\t\t\tfinal CMFile introDir=new CMFile(Resources.makeFileResourceName("text"),null,CMFile.FLAG_FORCEALLOW);\n\t\t\t\t\t\tString introFilename="text/intro.txt";\n\t\t\t\t\t\tif(introDir.isDirectory())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfinal CMFile[] files=introDir.listFiles();\n\t\t\t\t\t\t\tfinal List<String> choices=new ArrayList<String>();\n\t\t\t\t\t\t\tfor (final CMFile file : files)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif(file.getName().toLowerCase().startsWith("intro")\n\t\t\t\t\t\t\t\t&&file.getName().toLowerCase().endsWith(".txt"))\n\t\t\t\t\t\t\t\t\tchoices.add("text/"+file.getName());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(choices.size()>0)\n\t\t\t\t\t\t\t\tintroFilename=choices.get(CMLib.dice().roll(1,choices.size(),-1));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tStringBuffer introText=Resources.getFileResource(introFilename,true);\n\t\t\t\t\t\ttry\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tintroText = CMLib.webMacroFilter().virtualPageFilter(introText);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (final Exception ex)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfinal Session S=(Session)CMClass.getCommon("DefaultSession");\n\t\t\t\t\t\tS.initializeSession(sock, threadGroup().getName(), introText != null ? introText.toString() : null);\n\t\t\t\t\t\tCMLib.sessions().add(S);\n\t\t\t\t\t\tsock = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\tif((CMLib.database()!=null)\n\t\t\t\t&&(CMLib.database().isConnected())\n\t\t\t\t&&(CMLib.encoder()!=null))\n\t\t\t\t{\n\t\t\t\t\tStringBuffer rejectText;\n\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\trejectText = Resources.getFileResource("text/offline.txt",true);\n\t\t\t\t\t}\n\t\t\t\t\tcatch(final java.lang.NullPointerException npe)\n\t\t\t\t\t{\n\t\t\t\t\t\trejectText=new StringBuffer("");\n\t\t\t\t\t}\n\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal PrintWriter out = new PrintWriter(sock.getOutputStream());\n\t\t\t\t\t\tout.println("\\n\\rOFFLINE: " + CMProps.getVar(CMProps.Str.MUDSTATUS)+"\\n\\r");\n\t\t\t\t\t\tout.println(rejectText);\n\t\t\t\t\t\tout.flush();\n\n\t\t\t\t\t\tcheckedSleep(1000);\n\t\t\t\t\t\tout.close();\n\t\t\t\t\t}\n\t\t\t\t\tcatch(final IOException e)\n\t\t\t\t\t{\n\t\t\t\t\t\t// dont say anything, just eat it.\n\t\t\t\t\t}\n\t\t\t\t\tsock = null;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tsock.close();\n\t\t\t\t\t}\n\t\t\t\t\tcatch (final Exception e)\n\t\t\t\t\t{\n\t\t\t\t\t}\n\t\t\t\t\tsock = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally\n\t\t\t{\n\t\t\t\tstartTime=0;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic long activeTimeMillis()\n\t\t{\n\t\t\treturn (startTime > 0) ? System.currentTimeMillis() - startTime : 0;\n\t\t}\n\t}\n\n\t@Override\n\tpublic String getLanguage()\n\t{\n\t\tfinal String lang = CMProps.instance().getStr("LANGUAGE").toUpperCase().trim();\n\t\tif(lang.length()==0)\n\t\t\treturn "English";\n\t\tfor (final String[] element : LanguageLibrary.ISO_LANG_CODES)\n\t\t{\n\t\t\tif(lang.equals(element[0]))\n\t\t\t\treturn element[1];\n\t\t}\n\t\treturn "English";\n\t}\n\n\tpublic void setState(final MudState st)\n\t{\n\t\tif(st!=state)\n\t\t\tstate=st;\n\t}\n\n\t@Override\n\tpublic void run()\n\t{\n\t\tsetState(MudState.STARTING);\n\t\tint q_len = 6;\n\t\tSocket sock=null;\n\n\t\tInetAddress bindAddr = null;\n\n\t\tif (CMProps.getIntVar(CMProps.Int.MUDBACKLOG) > 0)\n\t\t\tq_len = CMProps.getIntVar(CMProps.Int.MUDBACKLOG);\n\n\t\tif (CMProps.getVar(CMProps.Str.MUDBINDADDRESS).length() > 0)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tbindAddr = InetAddress.getByName(CMProps.getVar(CMProps.Str.MUDBINDADDRESS));\n\t\t\t}\n\t\t\tcatch (final UnknownHostException e)\n\t\t\t{\n\t\t\t\tLog.errOut(Thread.currentThread().getName(),"ERROR: MUD Server could not bind to address " + CMProps.getVar(CMProps.Str.MUDBINDADDRESS));\n\t\t\t}\n\t\t}\n\n\t\ttry\n\t\t{\n\t\t\tservsock=new ServerSocket(port, q_len, bindAddr);\n\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"MUD Server started on port: "+port);\n\t\t\tif (bindAddr != null)\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"MUD Server bound to: "+bindAddr.toString());\n\t\t\tCMLib.hosts().add(this);\n\t\t\twhile(servsock!=null)\n\t\t\t{\n\t\t\t\tsetState(MudState.WAITING);\n\t\t\t\tsock=servsock.accept();\n\t\t\t\tacceptConnection(sock);\n\t\t\t}\n\t\t}\n\t\tcatch(final Exception t)\n\t\t{\n\t\t\tif((!(t instanceof java.net.SocketException))\n\t\t\t||(t.getMessage()==null)\n\t\t\t||(t.getMessage().toLowerCase().indexOf("socket closed")<0))\n\t\t\t{\n\t\t\t\tLog.errOut(Thread.currentThread().getName(),t);\n\t\t\t}\n\t\t}\n\n\t\tLog.sysOut(Thread.currentThread().getName(),"Server cleaning up.");\n\n\t\ttry\n\t\t{\n\t\t\tif(servsock!=null)\n\t\t\t\tservsock.close();\n\t\t\tif(sock!=null)\n\t\t\t\tsock.close();\n\t\t}\n\t\tcatch(final IOException e)\n\t\t{\n\t\t}\n\n\t\tLog.sysOut(Thread.currentThread().getName(),"MUD on port "+port+" stopped!");\n\t\tsetState(MudState.STOPPED);\n\t\tCMLib.hosts().remove(this);\n\t}\n\n\t@Override\n\tpublic String getStatus()\n\t{\n\t\tif(CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN))\n\t\t\treturn CMProps.getVar(CMProps.Str.MUDSTATUS);\n\t\tif(!CMProps.getBoolVar(CMProps.Bool.MUDSTARTED))\n\t\t\treturn CMProps.getVar(CMProps.Str.MUDSTATUS);\n\t\treturn state.toString();\n\t}\n\n\t@Override\n\tpublic void shutdown(final Session S, final boolean keepItDown, final String externalCommand)\n\t{\n\t\tglobalShutdown(S,keepItDown,externalCommand);\n\t\tinterrupt(); // kill the damn archon thread.\n\t}\n\n\tpublic static void defaultShutdown()\n\t{\n\t\tglobalShutdown(null,true,null);\n\t}\n\n\tprivate static void shutdownMemReport(final String blockName)\n\t{\n\t\ttry\n\t\t{\n\t\t\tObject obj = new Object();\n\t\t\tfinal WeakReference<Object> ref = new WeakReference<Object>(obj);\n\t\t\tobj = null;\n\t\t\tSystem.gc();\n\t\t\tSystem.runFinalization();\n\t\t\twhile(ref.get() != null)\n\t\t\t{\n\t\t\t\tSystem.gc();\n\t\t\t}\n\t\t\tcheckedSleep(3000);\n\t\t}\n\t\tcatch (final Exception e)\n\t\t{\n\t\t}\n\t\tfinal long free=Runtime.getRuntime().freeMemory()/1024;\n\t\tfinal long total=Runtime.getRuntime().totalMemory()/1024;\n\t\tLog.debugOut("Memory: "+blockName+": "+(total-free)+"/"+total);\n\t}\n\n\tpublic static void globalShutdown(final Session S, final boolean keepItDown, final String externalCommand)\n\t{\n\t\tCMProps.setBoolAllVar(CMProps.Bool.MUDSTARTED,false);\n\t\tCMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN,true);\n\t\tbootSync.set(false);\n\t\tfinal AtomicLong shutdownStateTime = new AtomicLong(System.currentTimeMillis());\n\t\tfinal long shutdownTimeout = 5 * 60 * 1000;\n\t\tfinal Thread currentShutdownThread=Thread.currentThread();\n\t\tfinal Thread shutdownWatchThread = new Thread(new Runnable()\n\t\t{\n\t\t\t@Override\n\t\t\tpublic void run()\n\t\t\t{\n\t\t\t\twhile(shutdownStateTime.get()!=0)\n\t\t\t\t{\n\t\t\t\t\tfinal long ellapsed=System.currentTimeMillis()-shutdownStateTime.get();\n\t\t\t\t\tif(ellapsed > shutdownTimeout)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(externalCommand!=null)\n\t\t\t\t\t\t\tMUD.execExternalRestart(externalCommand);\n\t\t\t\t\t\tLog.errOut("** Shutdown timeout. **");\n\t\t\t\t\t\tfinal StringBuilder lines=new StringBuilder("");\n\t\t\t\t\t\tlines.append("\\n\\r^HThread: ^N"+currentShutdownThread.getName()+"\\n\\r");\n\t\t\t\t\t\tfinal java.lang.StackTraceElement[] s=currentShutdownThread.getStackTrace();\n\t\t\t\t\t\tfor (final StackTraceElement element : s)\n\t\t\t\t\t\t\tlines.append("\\n   "+element.getClassName()+": "+element.getMethodName()+"("+element.getFileName()+": "+element.getLineNumber()+")");\n\t\t\t\t\t\tLog.errOut(lines.toString());\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tCMLib.s_sleep(10 * 1000);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tshutdownWatchThread.start();\n\n\t\tfinal boolean debugMem = CMSecurity.isDebugging(CMSecurity.DbgFlag.SHUTDOWN);\n\t\tif(debugMem) shutdownMemReport("BaseLine");\n\t\tserviceEngine.suspendAll(null);\n\t\tif(S!=null)\n\t\t\tS.print(CMLib.lang().L("Closing MUD listeners to new connections..."));\n\t\tfor(int i=0;i<CMLib.hosts().size();i++)\n\t\t\tCMLib.hosts().get(i).setAcceptConnections(false);\n\t\tLog.sysOut(Thread.currentThread().getName(),"New Connections are now closed");\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("Done."));\n\n\t\tif(!CMSecurity.isSaveFlag(CMSecurity.SaveFlag.NOPLAYERS))\n\t\t{\n\t\t\tif(S!=null)\n\t\t\t\tS.print(CMLib.lang().L("Saving players..."));\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Saving players...");\n\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.SESSIONS);e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal SessionsList list=((SessionsList)e.nextElement());\n\t\t\t\tfor(final Session S2 : list.allIterable())\n\t\t\t\t{\n\t\t\t\t\tfinal MOB M = S2.mob();\n\t\t\t\t\tif((M!=null)&&(M.playerStats()!=null))\n\t\t\t\t\t{\n\t\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\t\t\t\tM.playerStats().setLastDateTime(System.currentTimeMillis());\n\t\t\t\t\t\t// important! shutdown their affects!\n\t\t\t\t\t\tfor(int a=M.numAllEffects()-1;a>=0;a--) // reverse enumeration\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttry\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfinal Ability A=M.fetchEffect(a);\n\t\t\t\t\t\t\t\tif((A!=null)&&(A.canBeUninvoked()))\n\t\t\t\t\t\t\t\t\tA.unInvoke();\n\t\t\t\t\t\t\t\tif((A!=null)&&(!A.isSavable()))\n\t\t\t\t\t\t\t\t\tM.delEffect(A);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (final Throwable ex)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tLog.errOut(ex);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry\n\t\t\t{\n\t\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.PLAYERS);e.hasMoreElements();)\n\t\t\t\t{\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal PlayerLibrary lib = (PlayerLibrary)e.nextElement();\n\t\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis()+(lib.numPlayers()*(60 * 1000)));\n\t\t\t\t\t\tlib.savePlayers();\n\t\t\t\t\t}\n\t\t\t\t\tcatch (final Throwable ex)\n\t\t\t\t\t{\n\t\t\t\t\t\tLog.errOut(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (final Throwable ex)\n\t\t\t{\n\t\t\t\tLog.errOut(ex);\n\t\t\t}\n\t\t\tif(S!=null)\n\t\t\t\tS.println(CMLib.lang().L("done"));\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"All users saved.");\n\t\t}\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tif(S!=null)\n\t\t\tS.print(CMLib.lang().L("Saving stats..."));\n\t\ttry\n\t\t{\n\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.STATS);e.hasMoreElements();)\n\t\t\t\t((StatisticsLibrary)e.nextElement()).update();\n\t\t}\n\t\tcatch (final Throwable ex)\n\t\t{\n\t\t\tLog.errOut(ex);\n\t\t}\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("done"));\n\t\tLog.sysOut(Thread.currentThread().getName(),"Stats saved.");\n\t\tif(debugMem)\n\t\t\tshutdownMemReport("Saves");\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down" + (keepItDown? "..." : " and restarting..."));\n\t\tLog.sysOut(Thread.currentThread().getName(),"Notifying all objects of shutdown...");\n\t\tif(S!=null)\n\t\t\tS.print(CMLib.lang().L("Notifying all objects of shutdown..."));\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Notifying Objects");\n\t\tfinal MOB mob=(S!=null)?S.mob():CMClass.getFactoryMOB();\n\t\tfinal CMMsg msg=CMClass.getMsg(mob,null,CMMsg.MSG_SHUTDOWN,null);\n\t\tfinal List<Room> roomSet=new ArrayList<Room>();\n\t\ttry\n\t\t{\n\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.MAP);e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal WorldMap map=((WorldMap)e.nextElement());\n\t\t\t\tfor(final Enumeration<Area> a=map.areas();a.hasMoreElements();)\n\t\t\t\t\ta.nextElement().setAreaState(Area.State.STOPPED);\n\t\t\t}\n\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.MAP);e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal WorldMap map=((WorldMap)e.nextElement());\n\t\t\t\tfor(final Enumeration<Room> r=map.rooms();r.hasMoreElements();)\n\t\t\t\t{\n\t\t\t\t\t// single threadding is important here.\n\t\t\t\t\tfinal Room R=r.nextElement();\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tR.send(mob,msg);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (final Throwable ex)\n\t\t\t\t\t{\n\t\t\t\t\t\tLog.errOut(ex);\n\t\t\t\t\t}\n\t\t\t\t\troomSet.add(R);\n\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (final NoSuchElementException e)\n\t\t{\n\t\t}\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("done"));\n\t\tif(debugMem) shutdownMemReport("Notifications");\n\t\tfinal CMLib.Library[][] libraryShutdownLists=\n\t\t{\n\t\t\t{CMLib.Library.QUEST,CMLib.Library.TECH,CMLib.Library.SESSIONS},\n\t\t\t{CMLib.Library.STATS,CMLib.Library.THREADS},\n\t\t\t{CMLib.Library.SOCIALS,CMLib.Library.CLANS,CMLib.Library.CHANNELS,CMLib.Library.JOURNALS,\n\t\t\t\tCMLib.Library.POLLS,CMLib.Library.HELP,CMLib.Library.CATALOG,CMLib.Library.MAP,\n\t\t\t\tCMLib.Library.PLAYERS\n\t\t\t}\n\t\t};\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tfor(final CMLib.Library lib : libraryShutdownLists[0])\n\t\t{\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down "+CMStrings.capitalizeAndLower(lib.name())+"...");\n\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(lib);e.hasMoreElements();)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis()+(5*shutdownTimeout));\n\t\t\t\t\tfinal CMLibrary library = e.nextElement();\n\t\t\t\t\tlibrary.shutdown();\n\t\t\t\t\tif(debugMem) shutdownMemReport(library.ID());\n\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\t\t}\n\t\t\t\tcatch(final Throwable t)\n\t\t\t\t{\n\t\t\t\t\tLog.errOut(t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("Save thread stopped"));\n\n\t\tif(CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMMOBS)\n\t\t||CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMITEMS)\n\t\t||CMSecurity.isSaveFlag(CMSecurity.SaveFlag.ROOMSHOPS))\n\t\t{\n\t\t\tif(S!=null)\n\t\t\t\tS.print(CMLib.lang().L("Saving room data..."));\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Rejuving the dead");\n\t\t\tserviceEngine.tickAllTickers(null);\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Map Update");\n\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.MAP);e.hasMoreElements();)\n\t\t\t{\n\t\t\t\tfinal WorldMap map=((WorldMap)e.nextElement());\n\t\t\t\tfor(final Enumeration<Area> a=map.areas();a.hasMoreElements();)\n\t\t\t\t\ta.nextElement().setAreaState(Area.State.STOPPED);\n\t\t\t}\n\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\tint roomCounter=0;\n\t\t\tRoom R=null;\n\t\t\tfor(final Iterator<Room> e=roomSet.iterator();e.hasNext();)\n\t\t\t{\n\t\t\t\tif(((++roomCounter)%200)==0)\n\t\t\t\t{\n\t\t\t\t\tif(S!=null)\n\t\t\t\t\t\tS.print(".");\n\t\t\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Map Update ("+roomCounter+")");\n\t\t\t\t}\n\t\t\t\tR=e.next();\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tif(R.roomID().length()>0)\n\t\t\t\t\t\tR.executeMsg(mob,CMClass.getMsg(mob,R,null,CMMsg.MSG_EXPIRE,null));\n\t\t\t\t}\n\t\t\t\tcatch (final Throwable ex)\n\t\t\t\t{\n\t\t\t\t\tLog.errOut(ex);\n\t\t\t\t}\n\t\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\t}\n\t\t\tif(S!=null)\n\t\t\t\tS.println(CMLib.lang().L("done"));\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"Map data saved.");\n\t\t}\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...CM1Servers");\n\t\tfor(final CM1Server cm1server : cm1Servers)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tcm1server.shutdown();\n\t\t\t}\n\t\t\tcatch (final Throwable ex)\n\t\t\t{\n\t\t\t\tLog.errOut(ex);\n\t\t\t}\n\t\t\tfinally\n\t\t\t{\n\t\t\t\tif(S!=null)\n\t\t\t\t\tS.println(CMLib.lang().L("@x1 stopped",cm1server.getName()));\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),cm1server.getName()+" stopped");\n\t\t\t\tif(debugMem) shutdownMemReport("CM1Server");\n\t\t\t}\n\t\t}\n\t\tcm1Servers.clear();\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tif(i3server!=null)\n\t\t{\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...I3Server");\n\t\t\ttry\n\t\t\t{\n\t\t\t\tI3Server.shutdown();\n\t\t\t}\n\t\t\tcatch (final Throwable ex)\n\t\t\t{\n\t\t\t\tLog.errOut(ex);\n\t\t\t}\n\t\t\ti3server=null;\n\t\t\tif(S!=null)\n\t\t\t\tS.println(CMLib.lang().L("I3Server stopped"));\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"I3Server stopped");\n\t\t\tif(debugMem) shutdownMemReport("I3Server");\n\t\t}\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tif(imc2server!=null)\n\t\t{\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...IMC2Server");\n\t\t\ttry\n\t\t\t{\n\t\t\t\timc2server.shutdown();\n\t\t\t}\n\t\t\tcatch (final Throwable ex)\n\t\t\t{\n\t\t\t\tLog.errOut(ex);\n\t\t\t}\n\t\t\timc2server=null;\n\t\t\tif(S!=null)\n\t\t\t\tS.println(CMLib.lang().L("IMC2Server stopped"));\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"IMC2Server stopped");\n\t\t\tif(debugMem) shutdownMemReport("IMC2Server");\n\t\t}\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tif(S!=null)\n\t\t\tS.print(CMLib.lang().L("Stopping player Sessions..."));\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Stopping sessions");\n\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(CMLib.Library.SESSIONS);e.hasMoreElements();)\n\t\t{\n\t\t\tfinal SessionsList list=((SessionsList)e.nextElement());\n\t\t\tfor(final Session S2 : list.allIterable())\n\t\t\t{\n\t\t\t\tif((S!=null)&&(S2==S))\n\t\t\t\t{\n\t\t\t\t\tif(mob!=null)\n\t\t\t\t\t\tmob.removeFromGame(true, false);\n\t\t\t\t\tlist.remove(S2);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\t\t\tS2.stopSession(true,true,false);\n\t\t\t\t}\n\t\t\t\tif(S!=null)\n\t\t\t\t\tS.print(".");\n\t\t\t}\n\t\t}\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...Done stopping sessions");\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("All users logged off"));\n\t\tcheckedSleep(3000);\n\t\t/* give sessions a few seconds to inform the map */\n\t\tLog.sysOut(Thread.currentThread().getName(),"All users logged off.");\n\t\tif(debugMem) shutdownMemReport("Sessions");\n\n\t\tif(smtpServerThread!=null)\n\t\t{\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...smtp server");\n\t\t\tsmtpServerThread.shutdown();\n\t\t\tsmtpServerThread = null;\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"SMTP Server stopped.");\n\t\t\tif(S!=null)\n\t\t\t\tS.println(CMLib.lang().L("SMTP Server stopped"));\n\t\t\tif(debugMem) shutdownMemReport("SMTP Server");\n\t\t}\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tif(S!=null)\n\t\t\tS.print(CMLib.lang().L("Stopping all threads..."));\n\t\tfor(final CMLib.Library lib : libraryShutdownLists[1])\n\t\t{\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down "+CMStrings.capitalizeAndLower(lib.name())+"...");\n\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(lib);e.hasMoreElements();)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis()+(5*shutdownTimeout));\n\t\t\t\t\tfinal CMLibrary library = e.nextElement();\n\t\t\t\t\tif(S!=null)\n\t\t\t\t\t\tS.print(library.name()+"...");\n\t\t\t\t\tlibrary.shutdown();\n\t\t\t\t\tif(S!=null)\n\t\t\t\t\t\tS.println("shut down.");\n\t\t\t\t}\n\t\t\t\tcatch (final Throwable ex)\n\t\t\t\t{\n\t\t\t\t\tLog.errOut(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("done"));\n\t\tif(debugMem) shutdownMemReport("Map Threads");\n\t\tLog.sysOut(Thread.currentThread().getName(),"Map Threads Stopped.");\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down services...");\n\t\tfor(final CMLib.Library lib : libraryShutdownLists[2])\n\t\t{\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down "+CMStrings.capitalizeAndLower(lib.name())+"...");\n\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(lib);e.hasMoreElements();)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis()+(5*shutdownTimeout));\n\t\t\t\t\tfinal CMLibrary library=e.nextElement();\n\t\t\t\t\tif(S!=null)\n\t\t\t\t\t\tS.print(library.name()+"...");\n\t\t\t\t\tlibrary.shutdown();\n\t\t\t\t\tif(S!=null)\n\t\t\t\t\t\tS.println("shut down.");\n\t\t\t\t\tif(debugMem)\n\t\t\t\t\t\tshutdownMemReport(library.ID());\n\t\t\t\t}\n\t\t\t\tcatch (final Throwable ex)\n\t\t\t\t{\n\t\t\t\t\tLog.errOut(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tfor(final CMLib.Library lib : CMLib.Library.values())\n\t\t{\n\t\t\tboolean found=false;\n\t\t\tfor(final CMLib.Library[] prevSet : libraryShutdownLists)\n\t\t\t\tfound=found||CMParms.contains(prevSet, lib);\n\t\t\tif(!found)\n\t\t\t{\n\t\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down "+CMStrings.capitalizeAndLower(lib.name())+"...");\n\t\t\t\tfor(final Enumeration<CMLibrary> e=CMLib.libraries(lib);e.hasMoreElements();)\n\t\t\t\t{\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tshutdownStateTime.set(System.currentTimeMillis()+(5*shutdownTimeout));\n\t\t\t\t\t\tfinal CMLibrary library=e.nextElement();\n\t\t\t\t\t\tif(S!=null)\n\t\t\t\t\t\t\tS.print(library.name()+"...");\n\t\t\t\t\t\tlibrary.shutdown();\n\t\t\t\t\t\tif(S!=null)\n\t\t\t\t\t\t\tS.println("shut down.");\n\t\t\t\t\t\tif(debugMem)\n\t\t\t\t\t\t\tshutdownMemReport(library.ID());\n\t\t\t\t\t}\n\t\t\t\t\tcatch (final Throwable ex)\n\t\t\t\t\t{\n\t\t\t\t\t\tLog.errOut(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...unloading resources");\n\t\tResources.shutdown();\n\n\t\tLog.sysOut(Thread.currentThread().getName(),"Resources Cleared.");\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("All resources unloaded"));\n\t\tif(debugMem) shutdownMemReport("Resources");\n\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...closing db connections");\n\t\tfor(int d=0;d<databases.size();d++)\n\t\t\tdatabases.get(d).killConnections();\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("Database connections closed"));\n\t\tLog.sysOut(Thread.currentThread().getName(),"Database connections closed.");\n\t\tif(debugMem) shutdownMemReport("Database Connections");\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tfor(int i=0;i<webServers.size();i++)\n\t\t{\n\t\t\tfinal WebServer webServerThread=webServers.get(i);\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down web server "+webServerThread.getName()+"...");\n\t\t\ttry\n\t\t\t{\n\t\t\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\t\t\twebServerThread.close();\n\t\t\t}\n\t\t\tcatch (final Throwable ex)\n\t\t\t{\n\t\t\t\tLog.errOut(ex);\n\t\t\t}\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"Web server "+webServerThread.getName()+" stopped.");\n\t\t\tif(S!=null)\n\t\t\t\tS.println(CMLib.lang().L("Web server @x1 stopped",webServerThread.getName()));\n\t\t\tif(debugMem) shutdownMemReport("Web Server "+webServerThread.getName());\n\t\t}\n\t\twebServers.clear();\n\n\t\tshutdownStateTime.set(System.currentTimeMillis());\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...unloading macros");\n\t\tCMLib.lang().clear();\n\t\tif(debugMem) shutdownMemReport("Macros");\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down...unloading classes");\n\t\ttry\n\t\t{\n\t\t\tCMClass.shutdown();\n\t\t}\n\t\tcatch (final Throwable ex)\n\t\t{\n\t\t\tLog.errOut(ex);\n\t\t}\n\t\tif(debugMem) shutdownMemReport("Java Classes");\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down" + (keepItDown? "..." : " and restarting..."));\n\n\t\tcheckedSleep(500);\n\t\tLog.sysOut(Thread.currentThread().getName(),"CoffeeMud shutdown complete.");\n\t\tif(S!=null)\n\t\t\tS.println(CMLib.lang().L("CoffeeMud shutdown complete."));\n\t\tbringDown=keepItDown;\n\t\tserviceEngine.resumeAll();\n\t\tif(!keepItDown)\n\t\t{\n\t\t\tif(S!=null)\n\t\t\t\tS.println(CMLib.lang().L("Restarting..."));\n\t\t}\n\t\tshutdownStateTime.set(0);\n\t\tshutdownWatchThread.interrupt();\n\t\tcheckedSleep(500);\n\t\tSystem.gc();\n\t\tSystem.runFinalization();\n\t\tcheckedSleep(500);\n\t\tif(debugMem) shutdownMemReport("Complete");\n\n\t\texecExternalCommand=externalCommand;\n\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutdown: you are the special lucky chosen one!");\n\t\tfor(int m=CMLib.hosts().size()-1;m>=0;m--)\n\t\t{\n\t\t\tif(CMLib.hosts().get(m) instanceof Thread)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tCMLib.killThread((Thread)CMLib.hosts().get(m),100,30);\n\t\t\t\t}\n\t\t\t\tcatch (final Throwable t)\n\t\t\t\t{\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tshutdownStateTime.set(0);\n\t\tCMLib.hosts().clear();\n\t\tCMSecurity.unloadAll();\n\t\tif(!keepItDown)\n\t\t\tCMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN,false);\n\t\tLog.debugOut("Used memory = "+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));\n\t}\n\n\tprivate static boolean startWebServer(final CMProps page, final String serverName)\n\t{\n\t\ttry\n\t\t{\n\t\t\tfinal StringBuffer commonProps=new CMFile("web/common.ini", null, CMFile.FLAG_LOGERRORS).text();\n\t\t\tfinal StringBuffer finalProps=new CMFile("web/"+serverName+".ini", null, CMFile.FLAG_LOGERRORS).text();\n\t\t\tcommonProps.append("\\n").append(finalProps.toString());\n\t\t\tfinal CWConfig config=new CWConfig();\n\t\t\tconfig.setFileManager(new CMFile.CMFileManager());\n\t\t\tWebServer.initConfig(config, Log.instance(), new ByteArrayInputStream(commonProps.toString().getBytes()));\n\t\t\tif(CMSecurity.isDebugging(DbgFlag.HTTPREQ))\n\t\t\t\tconfig.setDebugFlag(page.getStr("DBGMSGS"));\n\t\t\tif(CMSecurity.isDebugging(DbgFlag.HTTPACCESS))\n\t\t\t\tconfig.setAccessLogFlag(page.getStr("ACCMSGS"));\n\t\t\tfinal WebServer webServer=new WebServer(serverName+Thread.currentThread().getThreadGroup().getName().charAt(0),config);\n\t\t\tconfig.setCoffeeWebServer(webServer);\n\t\t\twebServer.start();\n\t\t\twebServers.add(webServer);\n\t\t\treturn true;\n\t\t}\n\t\tcatch(final Exception e)\n\t\t{\n\t\t\tLog.errOut("HTTP server "+serverName+" NOT started: "+e.getMessage());\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate static boolean stopWebServer(final String serverName)\n\t{\n\t\ttry\n\t\t{\n\t\t\tfor(int i=0;i<webServers.size();i++)\n\t\t\t{\n\t\t\t\tfinal WebServer webServerThread=webServers.get(i);\n\t\t\t\tif((webServerThread.getName().length() < 1)||(webServerThread.getName().indexOf(\'-\')<0))\n\t\t\t\t\tcontinue;\n\t\t\t\tfinal String name = webServerThread.getName().substring(webServerThread.getName().indexOf(\'-\')+1,webServerThread.getName().length()-1);\n\t\t\t\tif(name.equals(serverName))\n\t\t\t\t{\n\t\t\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"Shutting down web server "+webServerThread.getName()+"...");\n\t\t\t\t\twebServerThread.close();\n\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Web server "+webServerThread.getName()+" stopped.");\n\t\t\t\t\twebServers.remove(webServerThread);\n\t\t\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"OK");\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch(final Exception e)\n\t\t{\n\t\t\tLog.errOut("HTTP server "+serverName+" NOT stopped: "+e.getMessage());\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static void startIntermud3()\n\t{\n\t\tfinal char tCode=Thread.currentThread().getThreadGroup().getName().charAt(0);\n\t\tfinal CMProps page=CMProps.instance();\n\t\ttry\n\t\t{\n\t\t\tif(page.getBoolean("RUNI3SERVER")&&(tCode==MAIN_HOST)&&(!CMSecurity.isDisabled(CMSecurity.DisFlag.I3)))\n\t\t\t{\n\t\t\t\tif(i3server!=null)\n\t\t\t\t\tI3Server.shutdown();\n\t\t\t\ti3server=null;\n\t\t\t\tString playstate=page.getStr("MUDSTATE");\n\t\t\t\tif((playstate==null)||(playstate.length()==0))\n\t\t\t\t\tplaystate=page.getStr("I3STATE");\n\t\t\t\tif((playstate==null)||(!CMath.isInteger(playstate)))\n\t\t\t\t\tplaystate="Development";\n\t\t\t\telse\n\t\t\t\tswitch(CMath.s_int(playstate.trim()))\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tplaystate = "MudLib Development";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tplaystate = "Restricted Access";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tplaystate = "Beta Testing";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tplaystate = "Open to the public";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tplaystate = "MudLib Development";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfinal IMudInterface imud=new IMudInterface(CMProps.getVar(CMProps.Str.MUDNAME),\n\t\t\t\t\t\t\t\t\t\t\t\t\t "CoffeeMud v"+CMProps.getVar(CMProps.Str.MUDVER),\n\t\t\t\t\t\t\t\t\t\t\t\t\t CMLib.mud(0).getPort(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t playstate,\n\t\t\t\t\t\t\t\t\t\t\t\t\t CMLib.channels().getI3ChannelsList());\n\t\t\t\ti3server=new I3Server();\n\t\t\t\tint i3port=page.getInt("I3PORT");\n\t\t\t\tif(i3port==0)\n\t\t\t\t\ti3port=27766;\n\t\t\t\tI3Server.start(CMProps.getVar(CMProps.Str.MUDNAME),i3port,imud);\n\t\t\t}\n\t\t}\n\t\tcatch(final Exception e)\n\t\t{\n\t\t\tif(i3server!=null)\n\t\t\t\tI3Server.shutdown();\n\t\t\ti3server=null;\n\t\t}\n\t}\n\n\tprivate static boolean stopCM1()\n\t{\n\t\ttry\n\t\t{\n\t\t\tfor(final CM1Server s : cm1Servers)\n\t\t\t{\n\t\t\t\ts.shutdown();\n\t\t\t\tcm1Servers.remove(s);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\tcatch(final Exception e)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate static boolean startCM1()\n\t{\n\t\tfinal char tCode=Thread.currentThread().getThreadGroup().getName().charAt(0);\n\t\tfinal CMProps page=CMProps.instance();\n\t\tCM1Server cm1server = null;\n\t\ttry\n\t\t{\n\t\t\tfinal String runcm1=page.getPrivateStr("RUNCM1SERVER");\n\t\t\tif((runcm1!=null)&&(runcm1.equalsIgnoreCase("TRUE")))\n\t\t\t{\n\t\t\t\tfinal String iniFile = page.getStr("CM1CONFIG");\n\t\t\t\tfor(final CM1Server s : cm1Servers)\n\t\t\t\t{\n\t\t\t\t\tif(s.getINIFilename().equalsIgnoreCase(iniFile))\n\t\t\t\t\t{\n\t\t\t\t\t\ts.shutdown();\n\t\t\t\t\t\tcm1Servers.remove(s);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcm1server=new CM1Server("CM1Server"+tCode,iniFile);\n\t\t\t\tcm1server.start();\n\t\t\t\tcm1Servers.add(cm1server);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\tcatch(final Exception e)\n\t\t{\n\t\t\tif(cm1server!=null)\n\t\t\t{\n\t\t\t\tcm1server.shutdown();\n\t\t\t\tcm1Servers.remove(cm1server);\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate static void startIntermud2()\n\t{\n\t\tfinal char tCode=Thread.currentThread().getThreadGroup().getName().charAt(0);\n\t\tfinal CMProps page=CMProps.instance();\n\t\ttry\n\t\t{\n\t\t\tif(page.getBoolean("RUNIMC2CLIENT")&&(tCode==MAIN_HOST)&&(!CMSecurity.isDisabled(CMSecurity.DisFlag.IMC2)))\n\t\t\t{\n\t\t\t\timc2server=new IMC2Driver();\n\t\t\t\tif(!imc2server.imc_startup(false,\n\t\t\t\t\t\t\t\t\t\t\tpage.getStr("IMC2LOGIN").trim(),\n\t\t\t\t\t\t\t\t\t\t\tCMProps.getVar(CMProps.Str.MUDNAME),\n\t\t\t\t\t\t\t\t\t\t\tpage.getStr("IMC2MYEMAIL").trim(),\n\t\t\t\t\t\t\t\t\t\t\tpage.getStr("IMC2MYWEB").trim(),\n\t\t\t\t\t\t\t\t\t\t\tpage.getStr("IMC2HUBNAME").trim(),\n\t\t\t\t\t\t\t\t\t\t\tpage.getInt("IMC2HUBPORT"),\n\t\t\t\t\t\t\t\t\t\t\tpage.getStr("IMC2PASS1").trim(),\n\t\t\t\t\t\t\t\t\t\t\tpage.getStr("IMC2PASS2").trim(),\n\t\t\t\t\t\t\t\t\t\t\tCMLib.channels().getIMC2ChannelsList()))\n\t\t\t\t{\n\t\t\t\t\tLog.errOut(Thread.currentThread().getName(),"IMC2 Failed to start!");\n\t\t\t\t\timc2server=null;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tCMLib.intermud().registerIMC2(imc2server);\n\t\t\t\t\timc2server.start();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch(final Exception e)\n\t\t{\n\t\t\tLog.errOut(e);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void interrupt()\n\t{\n\t\tif(servsock!=null)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tservsock.close();\n\t\t\t\tservsock = null;\n\t\t\t}\n\t\t\tcatch(final IOException e)\n\t\t\t{\n\t\t\t}\n\t\t}\n\t\tsuper.interrupt();\n\t}\n\n\tpublic static int activeThreadCount(final ThreadGroup tGroup, final boolean nonDaemonsOnly)\n\t{\n\t\tint realAC=0;\n\t\tfinal int ac = tGroup.activeCount();\n\t\tfinal Thread tArray[] = new Thread [ac+1];\n\t\ttGroup.enumerate(tArray);\n\t\tfor (int i = 0; i<ac; ++i)\n\t\t{\n\t\t\tif((tArray[i] != null)\n\t\t\t&& tArray[i].isAlive()\n\t\t\t&&(tArray[i] != Thread.currentThread())\n\t\t\t&&((!nonDaemonsOnly)||(!tArray[i].isDaemon())))\n\t\t\t\trealAC++;\n\t\t}\n\t\treturn realAC;\n\t}\n\n\tprivate static int killCount(final ThreadGroup tGroup, final boolean nonDaemonsOnly)\n\t{\n\t\tint killed=0;\n\n\t\tfinal int ac = tGroup.activeCount();\n\t\tfinal Thread tArray[] = new Thread [ac+1];\n\t\ttGroup.enumerate(tArray);\n\t\tfor (int i = 0; i<ac; ++i)\n\t\t{\n\t\t\tif ((tArray[i] != null)\n\t\t\t&& tArray[i].isAlive()\n\t\t\t&&(tArray[i] != Thread.currentThread())\n\t\t\t&&((!nonDaemonsOnly)||(!tArray[i].isDaemon())))\n\t\t\t{\n\t\t\t\tCMLib.killThread(tArray[i],500,10);\n\t\t\t\tkilled++;\n\t\t\t}\n\t\t}\n\t\treturn killed;\n\t}\n\n\tprivate static void threadList(final ThreadGroup tGroup, final boolean nonDaemonsOnly)\n\t{\n\t\tif(tGroup==null)\n\t\t\treturn;\n\t\tfinal int ac = tGroup.activeCount();\n\t\tfinal Thread tArray[] = new Thread [ac+1];\n\t\ttGroup.enumerate(tArray);\n\t\tfor (int i = 0; i<ac; ++i)\n\t\t{\n\t\t\tif (tArray[i] != null && tArray[i].isAlive() && (tArray[i] != Thread.currentThread()) && ((!nonDaemonsOnly)||(!tArray[i].isDaemon())))\n\t\t\t{\n\t\t\t\tString summary;\n\t\t\t\tif(tArray[i] instanceof MudHost)\n\t\t\t\t\tsummary=": "+CMClass.classID(tArray[i])+": "+((MudHost)tArray[i]).getStatus();\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfinal Runnable R=serviceEngine.findRunnableByThread(tArray[i]);\n\t\t\t\t\tif(R instanceof TickableGroup)\n\t\t\t\t\t\tsummary=": "+((TickableGroup)R).getName()+": "+((TickableGroup)R).getStatus();\n\t\t\t\t\telse\n\t\t\t\t\tif(R instanceof Session)\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal Session S=(Session)R;\n\t\t\t\t\t\tfinal MOB mob=S.mob();\n\t\t\t\t\t\tfinal String mobName=(mob==null)?"null":mob.Name();\n\t\t\t\t\t\tsummary=": session "+mobName+": "+S.getStatus().toString()+": "+CMParms.combineQuoted(S.getPreviousCMD(),0);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\tif(R instanceof CMRunnable)\n\t\t\t\t\t\tsummary=": "+CMClass.classID(R)+": active for "+((CMRunnable)R).activeTimeMillis()+"ms";\n\t\t\t\t\telse\n\t\t\t\t\tif(CMClass.classID(R).length()>0)\n\t\t\t\t\t\tsummary=": "+CMClass.classID(R);\n\t\t\t\t\telse\n\t\t\t\t\t\tsummary="";\n\t\t\t\t}\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(), "-->Thread: "+tArray[i].getName() + summary+"\\n\\r");\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic String getHost()\n\t{\n\t\treturn CMProps.getVar(Str.MUDDOMAIN);\n\t}\n\n\t@Override\n\tpublic int getPort()\n\t{\n\t\treturn port;\n\t}\n\n\t@Override\n\tpublic String geWebHostUrl()\n\t{\n\t\tWebServer server=null;\n\t\tfor(final WebServer serv : webServers)\n\t\t{\n\t\t\tif(!CMath.s_bool(serv.getConfig().getMiscProp("ADMIN")))\n\t\t\t{\n\t\t\t\tserver=serv;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif((server == null) && (webServers.size()>0))\n\t\t\tserver = webServers.get(0);\n\t\tif(server == null)\n\t\t\treturn "/";\n\t\tfinal int[] ports = server.getConfig().getHttpListenPorts();\n\t\tif((ports == null)||(ports.length==0))\n\t\t\treturn "/";\n\t\tif(CMParms.contains(ports, 80))\n\t\t\treturn "http://" + CMProps.getVar(Str.MUDDOMAIN)+"/";\n\t\treturn "http://" + CMProps.getVar(Str.MUDDOMAIN)+":"+ports[0]+"/";\n\t}\n\n\tprivate static class HostGroup extends Thread\n\t{\n\t\tprivate String\tname\t\t= null;\n\t\tprivate String\tiniFile\t\t= null;\n\t\tprivate String\tlogName\t\t= null;\n\t\tprivate char\tthreadCode\t= MAIN_HOST;\n\t\tprivate boolean\thostStarted\t= false;\n\t\tprivate boolean\tfailedStart\t= false;\n\t\t//protected ThreadGroup threadGroup;\n\n\t\tpublic HostGroup(final ThreadGroup G, final String mudName, final String iniFileName)\n\t\t{\n\t\t\tsuper(G,"HOST"+grpid);\n\t\t\t//threadGroup=G;\n\t\t\tsynchronized(CMClass.getSync("HostGroupInit"))\n\t\t\t{\n\t\t\t\tlogName="mud"+((grpid>0)?("."+grpid):"");\n\t\t\t\tgrpid++;\n\t\t\t\tiniFile=iniFileName;\n\t\t\t\tname=mudName;\n\t\t\t\tsetDaemon(true);\n\t\t\t\tthreadCode=G.getName().charAt(0);\n\t\t\t}\n\t\t}\n\n\t\tpublic boolean isStarted()\n\t\t{\n\t\t\treturn hostStarted;\n\t\t}\n\n\t\tpublic boolean failedToStart()\n\t\t{\n\t\t\treturn failedStart;\n\t\t}\n\n\t\tpublic void fatalStartupError(final Thread t, final int type)\n\t\t{\n\t\t\tString errorInternal=null;\n\t\t\tswitch(type)\n\t\t\t{\n\t\t\tcase 1:\n\t\t\t\terrorInternal="ERROR: initHost() will not run without properties. Exiting.";\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\terrorInternal="Map is empty?! Exiting.";\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\terrorInternal="Database init failed. Exiting.";\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\terrorInternal="Fatal exception. Exiting.";\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\terrorInternal="MUD Server did not start. Exiting.";\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\terrorInternal="Fatal error loading classes.  Make sure you start up coffeemud from the directory containing the class files.";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tLog.errOut(Thread.currentThread().getName(),errorInternal);\n\t\t\tbringDown=true;\n\n\t\t\tCMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN,true);\n\t\t\t//CMLib.killThread(t,100,1);\n\t\t}\n\n\t\tprotected boolean initHost()\n\t\t{\n\t\t\tfinal Thread t=Thread.currentThread();\n\t\t\tfinal CMProps page=CMProps.instance();\n\n\t\t\tif ((page == null) || (!page.isLoaded()))\n\t\t\t{\n\t\t\t\tfatalStartupError(t,1);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfinal char tCode=Thread.currentThread().getThreadGroup().getName().charAt(0);\n\t\t\tfinal boolean checkPrivate=(tCode!=MAIN_HOST);\n\n\t\t\tfinal List<String> compress=CMParms.parseCommas(page.getStr("COMPRESS").toUpperCase(),true);\n\t\t\tCMProps.setBoolVar(CMProps.Bool.ITEMDCOMPRESS,compress.contains("ITEMDESC"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.MOBCOMPRESS,compress.contains("GENMOBS"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.ROOMDCOMPRESS,compress.contains("ROOMDESC"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.MOBDCOMPRESS,compress.contains("MOBDESC"));\n\t\t\tResources.setCompression(compress.contains("RESOURCES"));\n\t\t\tfinal List<String> nocache=CMParms.parseCommas(page.getStr("NOCACHE").toUpperCase(),true);\n\t\t\tCMProps.setBoolVar(CMProps.Bool.MOBNOCACHE,nocache.contains("GENMOBS"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.ROOMDNOCACHE,nocache.contains("ROOMDESC"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.FILERESOURCENOCACHE, nocache.contains("FILERESOURCES"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.CATALOGNOCACHE, nocache.contains("CATALOG"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.MAPFINDSNOCACHE,nocache.contains("MAPFINDERS"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.ACCOUNTSNOCACHE,nocache.contains("ACCOUNTS"));\n\t\t\tCMProps.setBoolVar(CMProps.Bool.PLAYERSNOCACHE,nocache.contains("PLAYERS"));\n\n\t\t\tDBConnector currentDBconnector=null;\n\t\t\tString dbClass=page.getStr("DBCLASS");\n\t\t\tif(tCode!=MAIN_HOST)\n\t\t\t{\n\t\t\t\tDatabaseEngine baseEngine=(DatabaseEngine)CMLib.library(MAIN_HOST,CMLib.Library.DATABASE);\n\t\t\t\twhile((!MUD.bringDown)\n\t\t\t\t&&((baseEngine==null)||(!baseEngine.isConnected())))\n\t\t\t\t{\n\t\t\t\t\tif(!checkedSleep(500))\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tbaseEngine=(DatabaseEngine)CMLib.library(MAIN_HOST,CMLib.Library.DATABASE);\n\t\t\t\t}\n\t\t\t\tif(MUD.bringDown)\n\t\t\t\t\treturn false;\n\n\t\t\t\tif(page.getPrivateStr("DBCLASS").length()==0)\n\t\t\t\t{\n\t\t\t\t\tCMLib.registerLibrary(baseEngine);\n\t\t\t\t\tdbClass="";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(dbClass.length()>0)\n\t\t\t{\n\t\t\t\tfinal String dbService=page.getStr("DBSERVICE");\n\t\t\t\tfinal String dbUser=page.getStr("DBUSER");\n\t\t\t\tfinal String dbPass=page.getStr("DBPASS");\n\t\t\t\tfinal int dbConns=page.getInt("DBCONNECTIONS");\n\t\t\t\tfinal int dbPingIntMins=page.getInt("DBPINGINTERVALMINS");\n\t\t\t\tfinal Map<String,String> dbParms=CMParms.parseEQParms(page.getStr("DBPARMS"),CMParms.spaceDelimiter,false);\n\t\t\t\tif(dbConns == 0)\n\t\t\t\t{\n\t\t\t\t\tLog.errOut(Thread.currentThread().getName(),"Fatal error: DBCONNECTIONS in INI file is "+dbConns);\n\t\t\t\t\tSystem.exit(-1);\n\t\t\t\t}\n\t\t\t\tfinal boolean dbReuse=page.getBoolean("DBREUSE");\n\t\t\t\tfinal boolean dbTransact=page.getBoolean("DBTRANSACT");\n\t\t\t\tfinal boolean useQue=!CMSecurity.isDisabled(CMSecurity.DisFlag.DBERRORQUE);\n\t\t\t\tfinal boolean useQueStart=!CMSecurity.isDisabled(CMSecurity.DisFlag.DBERRORQUESTART);\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: connecting to database");\n\t\t\t\tcurrentDBconnector=new DBConnector(dbClass,dbService,dbUser,dbPass,dbParms,dbConns,dbPingIntMins,dbReuse,dbTransact,useQue,useQueStart);\n\t\t\t\tcurrentDBconnector.reconnect();\n\t\t\t\tCMLib.registerLibrary(new DBInterface(currentDBconnector,CMProps.getPrivateSubSet("DB.*")));\n\n\t\t\t\tfinal DBConnection DBTEST=currentDBconnector.DBFetchTest();\n\t\t\t\tif(DBTEST!=null)\n\t\t\t\t\tcurrentDBconnector.DBDone(DBTEST);\n\t\t\t\tif((DBTEST!=null)&&(currentDBconnector.amIOk())&&(CMLib.database().isConnected()))\n\t\t\t\t{\n\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Connected to "+currentDBconnector.service());\n\t\t\t\t\tdatabases.add(currentDBconnector);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfinal String DBerrors=currentDBconnector.errorStatus().toString();\n\t\t\t\t\tLog.errOut(Thread.currentThread().getName(),"Fatal database error: "+DBerrors);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\tif(CMLib.database()==null)\n\t\t\t{\n\t\t\t\tLog.errOut(Thread.currentThread().getName(),"No registered database!");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// test the database\n\t\t\ttry\n\t\t\t{\n\t\t\t\tfinal CMFile F = new CMFile("/test.the.database",null);\n\t\t\t\tif(F.exists())\n\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Test file found .. hmm.. that was unexpected.");\n\n\t\t\t}\n\t\t\tcatch(final Exception e)\n\t\t\t{\n\t\t\t\tLog.errOut(e);\n\t\t\t\tLog.errOut("Database error! Panic shutdown!");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tString webServersList=page.getPrivateStr("RUNWEBSERVERS");\n\t\t\tif(webServersList.equalsIgnoreCase("true"))\n\t\t\t\twebServersList="pub,admin";\n\t\t\tif((webServersList.length()>0)&&(!webServersList.equalsIgnoreCase("false")))\n\t\t\t{\n\t\t\t\tfinal List<String> serverNames=CMParms.parseCommas(webServersList,true);\n\t\t\t\tfor(int s=0;s<serverNames.size();s++)\n\t\t\t\t{\n\t\t\t\t\tfinal String serverName=serverNames.get(s);\n\t\t\t\t\tstartWebServer(page, serverName);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsmtpServerThread = new SMTPserver(CMLib.mud(0)); // initializes variables, even if it\'s not used\n\t\t\tif(page.getPrivateStr("RUNSMTPSERVER").equalsIgnoreCase("true"))\n\t\t\t{\n\t\t\t\tsmtpServerThread.start();\n\t\t\t\tserviceEngine.startTickDown(Thread.currentThread().getThreadGroup(),smtpServerThread,Tickable.TICKID_EMAIL,CMProps.getTickMillis(),(int)CMProps.getTicksPerMinute() * 5);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsmtpServerThread = null;\n\t\t\t\tCMProps.setBoolAllVar(CMProps.Bool.EMAILFORWARDING,false);\n\t\t\t}\n\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading base classes");\n\t\t\t// wait for baseC\n\t\t\twhile((tCode!=MudHost.MAIN_HOST)\n\t\t\t&&(!bootSync.get())\n\t\t\t&&(CMLib.s_sleep(500)))\n\t\t\t{}\n\t\t\tif(!CMClass.loadAllCoffeeMudClasses(page))\n\t\t\t{\n\t\t\t\tfatalStartupError(t,0);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading factions");\n\t\t\tif((tCode==MAIN_HOST)\n\t\t\t||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.FACTIONS.name())))\n\t\t\t\tCMLib.factions().reloadFactions(CMProps.getVar(CMProps.Str.PREFACTIONS));\n\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: initializing classes");\n\t\t\tCMClass.instance().intializeClasses();\n\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading expertises");\n\t\t\tif((tCode==MudHost.MAIN_HOST)||(CMProps.isPrivateToMe(CMLib.Library.EXPERTISES.name())))\n\t\t\t{\n\t\t\t\tCMLib.expertises().recompileExpertises();\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Expertises defined: "+CMLib.expertises().numExpertises());\n\t\t\t}\n\n\t\t\tCMLib.lang().setLocale(CMLib.props().getStr("LANGUAGE"),CMLib.props().getStr("COUNTRY"));\n\t\t\tif((threadCode==MudHost.MAIN_HOST)\n\t\t\t||(CMLib.time()!=CMLib.library(MudHost.MAIN_HOST, CMLib.Library.TIME)))\n\t\t\t\tCMLib.time().globalClock().initializeINIClock(page);\n\t\t\telse\n\t\t\t{\n\t\t\t\tCMProps.setIntVar(CMProps.Int.TICKSPERMUDDAY,""+((CMProps.getMillisPerMudHour()*CMLib.time().globalClock().getHoursInDay()/CMProps.getTickMillis())));\n\t\t\t\tCMProps.setIntVar(CMProps.Int.TICKSPERMUDMONTH,""+((CMProps.getMillisPerMudHour()*CMLib.time().globalClock().getHoursInDay()*CMLib.time().globalClock().getDaysInMonth()/CMProps.getTickMillis())));\n\t\t\t}\n\n\t\t\tif(tCode==MudHost.MAIN_HOST)\n\t\t\t\tbootSync.set(true);\n\n\t\t\tif((tCode==MAIN_HOST)\n\t\t\t||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.CHANNELS.name()))\n\t\t\t||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.JOURNALS.name())))\n\t\t\t{\n\t\t\t\tint numChannelsLoaded=0;\n\t\t\t\tint numJournalsLoaded=0;\n\t\t\t\tif((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.CHANNELS.name())))\n\t\t\t\t{\n\t\t\t\t\tfinal String normalChannels=page.getStr("CHANNELS");\n\t\t\t\t\tfinal String i3Channels=page.getBoolean("RUNI3SERVER") ? page.getStr("ICHANNELS") : "";\n\t\t\t\t\tfinal String imc2Channels=page.getBoolean("RUNIMC2CLIENT") ? page.getStr("IMC2CHANNELS") : "";\n\t\t\t\t\tnumChannelsLoaded=CMLib.channels().loadChannels(normalChannels, i3Channels, imc2Channels);\n\t\t\t\t}\n\t\t\t\tif((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.JOURNALS.name())))\n\t\t\t\t{\n\t\t\t\t\tnumJournalsLoaded=CMLib.journals().loadCommandJournals(page.getStr("COMMANDJOURNALS"));\n\t\t\t\t\tnumJournalsLoaded+=CMLib.journals().loadForumJournals(page.getStr("FORUMJOURNALS"));\n\t\t\t\t}\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Channels loaded   : "+(numChannelsLoaded+numJournalsLoaded));\n\t\t\t}\n\n\t\t\tif((tCode==MAIN_HOST)\n\t\t\t||(page.getRawPrivateStr("SYSOPMASK")!=null)\n\t\t\t||(checkPrivate&&CMProps.isPrivateToMe("SECURITY"))\n\t\t\t) // needs to be after journals, for journal flags\n\t\t\t{\n\t\t\t\tCMSecurity.setSysOp(page.getStr("SYSOPMASK")); // requires all classes be loaded\n\t\t\t\tCMSecurity.parseGroups(page);\n\t\t\t}\n\t\t\telse\n\t\t\t\tCMSecurity.shareWith(MAIN_HOST);\n\n\t\t\tif((tCode==MAIN_HOST)\n\t\t\t||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.SOCIALS.name())))\n\t\t\t{\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading socials");\n\t\t\t\tCMLib.socials().unloadSocials();\n\t\t\t\tfinal List<String> list = CMLib.socials().getSocialsBaseList();\n\t\t\t\tif(list.size()==0)\n\t\t\t\t\tLog.errOut(Thread.currentThread().getName(),"WARNING: Unable to load socials from socials.txt!");\n\t\t\t\telse\n\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Socials loaded    : "+list.size());\n\t\t\t}\n\n\t\t\tfinal Map<String,Clan> clanPostLoads=new TreeMap<String,Clan>();\n\t\t\tif((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.CLANS.name())))\n\t\t\t{\n\t\t\t\tfinal List<Clan> clans = CMLib.database().DBReadAllClans();\n\t\t\t\tfor(final Clan C : clans)\n\t\t\t\t{\n\t\t\t\t\tCMLib.clans().addClan(C);\n\t\t\t\t\tclanPostLoads.put(C.clanID(), C);\n\t\t\t\t}\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Clans loaded      : "+CMLib.clans().numClans());\n\t\t\t}\n\n\t\t\tif((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.FACTIONS.name())))\n\t\t\t\tserviceEngine.startTickDown(Thread.currentThread().getThreadGroup(),CMLib.factions(),Tickable.TICKID_MOB,CMProps.getTickMillis(),10);\n\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Starting CM1");\n\t\t\tstartCM1();\n\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Starting I3");\n\t\t\tstartIntermud3();\n\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Starting IMC2");\n\t\t\tstartIntermud2();\n\n\t\t\tcheckedSleep(500);\n\n\t\t\tif((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.CATALOG.name())))\n\t\t\t{\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Loading catalog...");\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading catalog....");\n\t\t\t\tCMLib.database().DBReadCatalogs();\n\t\t\t}\n\n\t\t\tif((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.MAP.name())))\n\t\t\t{\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Loading map...");\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading rooms....");\n\t\t\t\tCMLib.database().DBReadAllRooms(null);\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: loading space....");\n\t\t\t\tCMLib.database().DBReadSpace();\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: preparing map....");\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Preparing map...");\n\t\t\t\tCMLib.database().DBReadArtifacts();\n\t\t\t\tfor(final Enumeration<Area> a=CMLib.map().areas();a.hasMoreElements();)\n\t\t\t\t{\n\t\t\t\t\tfinal Area A=a.nextElement();\n\t\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: filling map ("+A.Name()+")");\n\t\t\t\t\tA.fillInAreaRooms();\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tfinal MOB mob=CMClass.getFactoryMOB();\n\t\t\t\t\tfinal CMMsg msg=CMClass.getMsg(mob,null,CMMsg.MSG_STARTUP,null);\n\t\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Sending room startup.");\n\t\t\t\t\tfor(final Enumeration<Room> a=CMLib.map().rooms();a.hasMoreElements();)\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal Room R=a.nextElement();\n\t\t\t\t\t\tif(R!=null)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmsg.setTarget(R);\n\t\t\t\t\t\t\tR.send(mob, msg);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmob.destroy();\n\t\t\t\t}\n\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Map Load Complete.");\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Mapped rooms      : "+CMLib.map().numRooms()+" in "+CMLib.map().numAreas()+" areas");\n\t\t\t\tif(CMLib.space().numSpaceObjects()>0)\n\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Space objects     : "+CMLib.space().numSpaceObjects());\n\n\t\t\t\tif(!CMLib.map().roomIDs().hasMoreElements())\n\t\t\t\t{\n\t\t\t\t\tLog.sysOut("NO MAPPED ROOM?!  I\'ll make ya one!");\n\t\t\t\t\tfinal String id="START";//New Area#0";\n\t\t\t\t\tfinal Area newArea=CMClass.getAreaType("StdArea");\n\t\t\t\t\tnewArea.setName(CMLib.lang().L("New Area"));\n\t\t\t\t\tCMLib.map().addArea(newArea);\n\t\t\t\t\tCMLib.database().DBCreateArea(newArea);\n\t\t\t\t\tfinal Room room=CMClass.getLocale("StdRoom");\n\t\t\t\t\troom.setRoomID(id);\n\t\t\t\t\troom.setArea(newArea);\n\t\t\t\t\troom.setDisplayText(CMLib.lang().L("New Room"));\n\t\t\t\t\troom.setDescription(CMLib.lang().L("Brand new database room! You need to change this text with the MODIFY ROOM command.  If your character is not an Archon, pick up the book you see here and read it immediately!"));\n\t\t\t\t\tCMLib.map().registerWorldObjectLoaded(newArea, null, newArea);\n\t\t\t\t\tCMLib.database().DBCreateRoom(room);\n\t\t\t\t\tfinal Item I=CMClass.getMiscMagic("ManualArchon");\n\t\t\t\t\troom.addItem(I);\n\t\t\t\t\tCMLib.database().DBUpdateItems(room);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(clanPostLoads.size()>0)\n\t\t\t{\n\t\t\t\tfinal int num = CMLib.database().DBReadClanItems(clanPostLoads);\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Clan owned items  : "+num);\n\t\t\t}\n\n\t\t\tif((tCode==MAIN_HOST)||(checkPrivate&&CMProps.isPrivateToMe(CMLib.Library.QUEST.name())))\n\t\t\t{\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Loading Quests");\n\t\t\t\tCMLib.quests().shutdown();\n\t\t\t\tfor(final Quest Q : CMLib.database().DBReadQuests())\n\t\t\t\t\tCMLib.quests().addQuest(Q);\n\t\t\t\tif(CMLib.quests().numQuests()>0)\n\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Quests loaded     : "+CMLib.quests().numQuests());\n\t\t\t}\n\n\t\t\tif(tCode!=MAIN_HOST)\n\t\t\t{\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: Waiting for HOST0");\n\t\t\t\twhile((!MUD.bringDown)\n\t\t\t\t&&(!CMProps.getBoolVar(CMProps.Bool.MUDSTARTED))\n\t\t\t\t&&(!CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN)))\n\t\t\t\t{\n\t\t\t\t\tif(!checkedSleep(500))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif((MUD.bringDown)\n\t\t\t\t||(!CMProps.getBoolVar(CMProps.Bool.MUDSTARTED))\n\t\t\t\t||(CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN)))\n\t\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t\tif((tCode==MAIN_HOST)\n\t\t\t||(checkPrivate\n\t\t\t\t&& CMProps.isPrivateToMe(CMLib.Library.LOGIN.name())))\n\t\t\t{\n\t\t\t\tCMLib.login().initStartRooms(page);\n\t\t\t\tCMLib.login().initDeathRooms(page);\n\t\t\t\tCMLib.login().initBodyRooms(page);\n\t\t\t}\n\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting: readying for connections.");\n\t\t\ttry\n\t\t\t{\n\t\t\t\tCMLib.activateLibraries();\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Services and utilities started");\n\t\t\t}\n\t\t\tcatch (final Throwable th)\n\t\t\t{\n\t\t\t\tLog.errOut(Thread.currentThread().getName(),"CoffeeMud Server initHost() failed");\n\t\t\t\tLog.errOut(Thread.currentThread().getName(),th);\n\t\t\t\tfatalStartupError(t,4);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfinal StringBuffer str=new StringBuffer("");\n\t\t\tfor(int m=0;m<CMLib.hosts().size();m++)\n\t\t\t{\n\t\t\t\tfinal MudHost mud=CMLib.hosts().get(m);\n\t\t\t\tstr.append(" "+mud.getPort());\n\t\t\t}\n\t\t\tCMProps.setVar(CMProps.Str.MUDPORTS,str.toString());\n\t\t\tCMProps.setBoolAllVar(CMProps.Bool.MUDSTARTED,true);\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"OK");\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"Host#"+threadCode+" initializated.");\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run()\n\t\t{\n\t\t\tCMLib.initialize(); // initialize the lib\n\t\t\tCMClass.initialize(); // initialize the classes\n\t\t\tLog.shareWith(MudHost.MAIN_HOST);\n\t\t\tResources.shareWith(MudHost.MAIN_HOST);\n\n\t\t\t// wait for ini to be loaded, and for other matters\n\t\t\tif(threadCode!=MAIN_HOST)\n\t\t\t{\n\t\t\t\twhile((CMLib.library(MAIN_HOST,CMLib.Library.INTERMUD)==null)&&(!MUD.bringDown))\n\t\t\t\t{\n\t\t\t\t\tif(!checkedSleep(500))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif(MUD.bringDown)\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t\tfinal CMProps page=CMProps.loadPropPage("//"+iniFile);\n\t\t\tif ((page==null)||(!page.isLoaded()))\n\t\t\t{\n\t\t\t\tLog.errOut(Thread.currentThread().getName(),"ERROR: Unable to read ini file: \'"+iniFile+"\'.");\n\t\t\t\tSystem.err.println("MUD/ERROR: Unable to read ini file: \'"+iniFile+"\'.");\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"A terminal error has occured!");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpage.resetSystemVars();\n\t\t\tCMProps.setBoolAllVar(CMProps.Bool.MUDSTARTED,false);\n\t\t\tserviceEngine.activate();\n\n\t\t\tif(threadCode!=MAIN_HOST)\n\t\t\t{\n\t\t\t\tif(CMath.isInteger(page.getPrivateStr("NUMLOGS")))\n\t\t\t\t{\n\t\t\t\t\tLog.newInstance();\n\t\t\t\t\tLog.instance().configureLogFile(logName,page.getInt("NUMLOGS"));\n\t\t\t\t\tLog.instance().configureLog(Log.Type.info, page.getStr("SYSMSGS"));\n\t\t\t\t\tLog.instance().configureLog(Log.Type.error, page.getStr("ERRMSGS"));\n\t\t\t\t\tLog.instance().configureLog(Log.Type.warning, page.getStr("WRNMSGS"));\n\t\t\t\t\tLog.instance().configureLog(Log.Type.debug, page.getStr("DBGMSGS"));\n\t\t\t\t\tLog.instance().configureLog(Log.Type.help, page.getStr("HLPMSGS"));\n\t\t\t\t\tLog.instance().configureLog(Log.Type.kills, page.getStr("KILMSGS"));\n\t\t\t\t\tLog.instance().configureLog(Log.Type.combat, page.getStr("CBTMSGS"));\n\t\t\t\t\tLog.instance().configureLog(Log.Type.access, page.getStr("ACCMSGS"));\n\t\t\t\t}\n\t\t\t\tif((page.getRawPrivateStr("SYSOPMASK")!=null)\n\t\t\t\t||(page.getRawPrivateStr("DISABLE")!=null)\n\t\t\t\t||(page.getRawPrivateStr("ENABLE")!=null)\n\t\t\t\t||(page.getRawPrivateStr("DEBUG")!=null)\n\t\t\t\t||(page.getRawPrivateStr("SAVE")!=null))\n\t\t\t\t{\n\t\t\t\t\t//page.resetSecurityVars();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tCMSecurity.instance().markShared();\n\t\t\t}\n\n\t\t\tif(page.getStr("DISABLE").trim().length()>0)\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Disabled subsystems: "+page.getStr("DISABLE"));\n\t\t\tif(page.getStr("DEBUG").trim().length()>0)\n\t\t\t{\n\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Debugging messages: "+page.getStr("DEBUG"));\n\t\t\t\tif(!Log.debugChannelOn())\n\t\t\t\t\tLog.errOut(Thread.currentThread().getName(),"Debug logging is disabled! Check your DBGMSGS flag!");\n\t\t\t}\n\n\t\t\tfinal DBConnector currentDBconnector=new DBConnector();\n\t\t\tCMLib.registerLibrary(new DBInterface(currentDBconnector,CMProps.getPrivateSubSet("DB.*")));\n\t\t\tCMProps.setVar(CMProps.Str.MUDVER, HOST_VERSION);\n\n\t\t\t// an arbitrary dividing line. After threadCode 0\n\t\t\tif(threadCode==MAIN_HOST)\n\t\t\t{\n\t\t\t\tCMLib.registerLibrary(serviceEngine);\n\t\t\t\tCMLib.registerLibrary(new IMudClient());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCMLib.registerLibrary(CMLib.library(MAIN_HOST,CMLib.Library.THREADS));\n\t\t\t\tCMLib.registerLibrary(CMLib.library(MAIN_HOST,CMLib.Library.INTERMUD));\n\t\t\t}\n\t\t\tCMProps.setVar(CMProps.Str.INIPATH,iniFile,false);\n\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDNAME,name.replace(\'\\\'\',\'`\'));\n\t\t\ttry\n\t\t\t{\n\t\t\t\tCMProps.setUpLowVar(CMProps.Str.MUDSTATUS,"Booting");\n\t\t\t\tCMProps.setVar(CMProps.Str.MUDBINDADDRESS,page.getStr("BIND"));\n\t\t\t\tCMProps.setIntVar(CMProps.Int.MUDBACKLOG,page.getInt("BACKLOG"));\n\n\t\t\t\tfinal LinkedList<MUD> hostMuds=new LinkedList<MUD>();\n\t\t\t\tString ports=page.getProperty("PORT");\n\t\t\t\tif((ports==null)||(ports.length()==0))\n\t\t\t\t{\n\t\t\t\t\tLog.errOut("HOST#"+this.threadCode+" could not start any listeners.");\n\t\t\t\t\tfailedStart=true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tint pdex=ports.indexOf(\',\');\n\t\t\t\twhile(pdex>0)\n\t\t\t\t{\n\t\t\t\t\tfinal MUD mud=new MUD("MUD@"+ports.substring(0,pdex));\n\t\t\t\t\tmud.setState(MudState.STARTING);\n\t\t\t\t\tmud.acceptConns=false;\n\t\t\t\t\tmud.port=CMath.s_int(ports.substring(0,pdex));\n\t\t\t\t\tports=ports.substring(pdex+1);\n\t\t\t\t\thostMuds.add(mud);\n\t\t\t\t\tmud.start();\n\t\t\t\t\tpdex=ports.indexOf(\',\');\n\t\t\t\t}\n\t\t\t\tfinal MUD mud=new MUD("MUD@"+ports);\n\t\t\t\tmud.setState(MudState.STARTING);\n\t\t\t\tmud.acceptConns=false;\n\t\t\t\tmud.port=CMath.s_int(ports);\n\t\t\t\thostMuds.add(mud);\n\t\t\t\tmud.start();\n\n\t\t\t\tif(hostMuds.size()==0)\n\t\t\t\t{\n\t\t\t\t\tLog.errOut("HOST#"+this.threadCode+" could not start any listeners.");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tboolean oneStarted=false;\n\t\t\t\tfinal long timeout=System.currentTimeMillis()+60000;\n\t\t\t\twhile((!oneStarted) && (System.currentTimeMillis()<timeout))\n\t\t\t\t{\n\t\t\t\t\tint numStopped=0;\n\t\t\t\t\tfor(final MUD m : hostMuds)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(m.state==MudState.STOPPED)\n\t\t\t\t\t\t\tnumStopped++;\n\t\t\t\t\t\telse\n\t\t\t\t\t\tif(m.state!=MudState.STARTING)\n\t\t\t\t\t\t\toneStarted=true;\n\t\t\t\t\t}\n\t\t\t\t\tif(numStopped==hostMuds.size())\n\t\t\t\t\t{\n\t\t\t\t\t\tLog.errOut("HOST#"+this.threadCode+" could not start any listeners.");\n\t\t\t\t\t\tfailedStart=true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcheckedSleep(100);\n\t\t\t\t}\n\t\t\t\tif(!oneStarted)\n\t\t\t\t{\n\t\t\t\t\tLog.errOut("HOST#"+this.threadCode+" could not start any listeners.");\n\t\t\t\t\tfailedStart=true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif(initHost())\n\t\t\t\t{\n\t\t\t\t\tThread joinable=null;\n\t\t\t\t\tfor(int i=0;i<CMLib.hosts().size();i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(CMLib.hosts().get(i) instanceof Thread)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tjoinable=(Thread)CMLib.hosts().get(i);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(joinable!=null)\n\t\t\t\t\t{\n\t\t\t\t\t\thostStarted=true;\n\t\t\t\t\t\tjoinable.join();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tfailedStart=true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfailedStart=true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch(final InterruptedException e)\n\t\t\t{\n\t\t\t\tLog.errOut(Thread.currentThread().getName(),e);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic List<Runnable> getOverdueThreads()\n\t{\n\t\tfinal Vector<Runnable> V=new Vector<Runnable>();\n\t\tfor(int w=0;w<webServers.size();w++)\n\t\t\tV.addAll(webServers.get(w).getOverdueThreads());\n\t\treturn V;\n\t}\n\n\tpublic static void main(final String a[])\n\t{\n\t\tString nameID="";\n\t\tThread.currentThread().setName(("MUD"));\n\t\tfinal Vector<String> iniFiles=new Vector<String>();\n\t\tif(a.length>0)\n\t\t{\n\t\t\tfor (final String element : a)\n\t\t\t\tnameID+=" "+element;\n\t\t\tnameID=nameID.trim();\n\t\t\tfinal List<String> V=CMParms.cleanParameterList(nameID);\n\t\t\tfor(int v=0;v<V.size();v++)\n\t\t\t{\n\t\t\t\tfinal String s=V.get(v);\n\t\t\t\tif(s.toUpperCase().startsWith("BOOT=")&&(s.length()>5))\n\t\t\t\t{\n\t\t\t\t\tiniFiles.addElement(s.substring(5));\n\t\t\t\t\tV.remove(v);\n\t\t\t\t\tv--;\n\t\t\t\t}\n\t\t\t}\n\t\t\tnameID=CMParms.combine(V,0);\n\t\t}\n\t\tCMLib.initialize(); // initialize this threads libs\n\n\t\tif(iniFiles.size()==0)\n\t\t\tiniFiles.addElement("coffeemud.ini");\n\t\tif((nameID.length()==0)||(nameID.equalsIgnoreCase( "CoffeeMud" ))||nameID.equalsIgnoreCase("Your Muds Name"))\n\t\t{\n\t\t\tnameID="Unnamed_CoffeeMUD#";\n\t\t\tlong idNumber=new Random(System.currentTimeMillis()).nextLong();\n\t\t\ttry\n\t\t\t{\n\t\t\t\tidNumber=0;\n\t\t\t\tfor(final Enumeration<NetworkInterface> e=NetworkInterface.getNetworkInterfaces();e.hasMoreElements();)\n\t\t\t\t{\n\t\t\t\t\tfinal NetworkInterface n=e.nextElement();\n\t\t\t\t\tidNumber^=n.getDisplayName().hashCode();\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tfinal Method m=n.getClass().getMethod("getHardwareAddress");\n\t\t\t\t\t\tfinal Object o=m.invoke(n);\n\t\t\t\t\t\tif(o instanceof byte[])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor(int i=0;i<((byte[])o).length;i++)\n\t\t\t\t\t\t\t\tidNumber^=((byte[])o)[0] << (i*8);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (final Exception e1)\n\t\t\t\t\t{\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (final Exception e1)\n\t\t\t{\n\t\t\t}\n\t\t\tif(idNumber<0)\n\t\t\t\tidNumber=idNumber*-1;\n\t\t\tnameID=nameID+idNumber;\n\t\t\tSystem.err.println("*** Please give your mud a unique name in mud.bat or mudUNIX.sh!! ***");\n\t\t}\n\t\telse\n\t\tif(nameID.equalsIgnoreCase( "TheRealCoffeeMudCopyright2000-2022ByBoZimmerman" ))\n\t\t\tnameID="CoffeeMud";\n\t\tString iniFile=iniFiles.firstElement();\n\t\tfinal CMProps page=CMProps.loadPropPage("//"+iniFile);\n\t\tif ((page==null)||(!page.isLoaded()))\n\t\t{\n\t\t\tLog.instance().configureLogFile("mud",1);\n\t\t\tLog.instance().configureLog(Log.Type.info, "BOTH");\n\t\t\tLog.instance().configureLog(Log.Type.error, "BOTH");\n\t\t\tLog.instance().configureLog(Log.Type.warning, "BOTH");\n\t\t\tLog.instance().configureLog(Log.Type.debug, "BOTH");\n\t\t\tLog.instance().configureLog(Log.Type.help, "BOTH");\n\t\t\tLog.instance().configureLog(Log.Type.kills, "BOTH");\n\t\t\tLog.instance().configureLog(Log.Type.combat, "BOTH");\n\t\t\tLog.instance().configureLog(Log.Type.access, "BOTH");\n\t\t\tLog.errOut(Thread.currentThread().getName(),"ERROR: Unable to read ini file: \'"+iniFile+"\'.");\n\t\t\tSystem.err.println("MUD/ERROR: Unable to read ini file: \'"+iniFile+"\'.");\n\t\t\tCMProps.setUpAllLowVar(CMProps.Str.MUDSTATUS,"A terminal error has occured!");\n\t\t\tSystem.exit(-1);\n\t\t\treturn;\n\t\t}\n\t\tLog.shareWith(MudHost.MAIN_HOST);\n\t\tLog.instance().configureLogFile("mud",page.getInt("NUMLOGS"));\n\t\tLog.instance().configureLog(Log.Type.info, page.getStr("SYSMSGS"));\n\t\tLog.instance().configureLog(Log.Type.error, page.getStr("ERRMSGS"));\n\t\tLog.instance().configureLog(Log.Type.warning, page.getStr("WRNMSGS"));\n\t\tLog.instance().configureLog(Log.Type.debug, page.getStr("DBGMSGS"));\n\t\tLog.instance().configureLog(Log.Type.help, page.getStr("HLPMSGS"));\n\t\tLog.instance().configureLog(Log.Type.kills, page.getStr("KILMSGS"));\n\t\tLog.instance().configureLog(Log.Type.combat, page.getStr("CBTMSGS"));\n\t\tLog.instance().configureLog(Log.Type.access, page.getStr("ACCMSGS"));\n\n\t\tfinal Thread shutdownHook=new Thread("ShutdownHook")\n\t\t{\n\t\t\t@Override\n\t\t\tpublic void run()\n\t\t\t{\n\t\t\t\tif(!CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN))\n\t\t\t\t{\n\t\t\t\t\tServiceEngine.panicDumpAllThreads();\n\t\t\t\t\tMUD.globalShutdown(null,true,null);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\twhile(!bringDown)\n\t\t{\n\t\t\tfinal PrintStream eolStream = System.out;\n\t\t\teolStream.println();\n\t\t\tgrpid=0;\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"CoffeeMud v"+HOST_VERSION);\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"(C) 2000-2022 Bo Zimmerman");\n\t\t\tLog.sysOut(Thread.currentThread().getName(),"http://www.coffeemud.org");\n\t\t\tCMLib.hosts().clear();\n\t\t\tfinal LinkedList<HostGroup> myGroups=new LinkedList<HostGroup>();\n\t\t\tHostGroup mainHostGroup=null;\n\t\t\tThreadGroup mainThreadGroup = null;\n\t\t\tfor(int i=0;i<iniFiles.size();i++)\n\t\t\t{\n\t\t\t\tiniFile=iniFiles.elementAt(i);\n\t\t\t\tfinal ThreadGroup G=new ThreadGroup(i+"-MUD");\n\t\t\t\tfinal HostGroup H=new HostGroup(G,nameID,iniFile);\n\t\t\t\tif((mainHostGroup==null)||(mainThreadGroup == null))\n\t\t\t\t{\n\t\t\t\t\tmainHostGroup=H;\n\t\t\t\t\tmainThreadGroup=G;\n\t\t\t\t}\n\t\t\t\tmyGroups.add(H);\n\t\t\t\tH.start();\n\t\t\t}\n\t\t\tif(mainHostGroup==null)\n\t\t\t{\n\t\t\t\tLog.errOut("CoffeeMud failed to start.");\n\t\t\t\tMUD.bringDown=true;\n\t\t\t\tCMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN, true);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfinal long timeout=System.currentTimeMillis()+1800000; /// 30 mins\n\t\t\t\tint numPending=1;\n\t\t\t\twhile((numPending>0)&&(System.currentTimeMillis()<timeout))\n\t\t\t\t{\n\t\t\t\t\tnumPending=0;\n\t\t\t\t\tfor(final HostGroup g : myGroups)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(!g.failedToStart() && !g.isStarted())\n\t\t\t\t\t\t\tnumPending++;\n\t\t\t\t\t}\n\t\t\t\t\tif(mainHostGroup.failedToStart())\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcheckedSleep(100);\n\t\t\t\t}\n\t\t\t\tif(mainHostGroup.failedToStart())\n\t\t\t\t{\n\t\t\t\t\tLog.errOut("CoffeeMud failed to start.");\n\t\t\t\t\tMUD.bringDown=true;\n\t\t\t\t\tCMProps.setBoolAllVar(CMProps.Bool.MUDSHUTTINGDOWN, true);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tRuntime.getRuntime().addShutdownHook(shutdownHook);\n\t\t\t\t\tfor(int i=0;i<CMLib.hosts().size();i++)\n\t\t\t\t\t\tCMLib.hosts().get(i).setAcceptConnections(true);\n\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"Initialization complete.");\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tmainHostGroup.join();\n\t\t\t\t\t}\n\t\t\t\t\tcatch(final Exception e)\n\t\t\t\t\t{\n\t\t\t\t\t\te.printStackTrace(); Log.errOut(Thread.currentThread().getName(),e);\n\t\t\t\t\t}\n\t\t\t\t\tRuntime.getRuntime().removeShutdownHook(shutdownHook);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tSystem.gc();\n\t\t\tcheckedSleep(1000);\n\t\t\tSystem.runFinalization();\n\t\t\tcheckedSleep(1000);\n\n\t\t\tif(activeThreadCount(Thread.currentThread().getThreadGroup(),true)>1)\n\t\t\t{\n\t\t\t\tcheckedSleep(1000);\n\t\t\t\tkillCount(Thread.currentThread().getThreadGroup(),true);\n\t\t\t\tcheckedSleep(1000);\n\t\t\t\tif(activeThreadCount(Thread.currentThread().getThreadGroup(),true)>1)\n\t\t\t\t{\n\t\t\t\t\tLog.sysOut(Thread.currentThread().getName(),"WARNING: "\n\t\t\t\t\t\t+ activeThreadCount(Thread.currentThread().getThreadGroup(),true)\n\t\t\t\t\t\t+" other thread(s) are still active!");\n\t\t\t\t\tthreadList(Thread.currentThread().getThreadGroup(),true);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!bringDown)\n\t\t\t{\n\t\t\t\tif(execExternalCommand!=null)\n\t\t\t\t{\n\t\t\t\t\texecExternalRestart(execExternalCommand);\n\t\t\t\t\texecExternalCommand=null;\n\t\t\t\t\tbringDown=true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void execExternalRestart(final String command)\n\t{\n\t\tfinal Runtime r=Runtime.getRuntime();\n\t\ttry\n\t\t{\n\t\t\tif((command==null) || (command.equalsIgnoreCase("hard")))\n\t\t\t{\n\t\t\t\tif(new File("./restart.sh").exists())\n\t\t\t\t{\n\t\t\t\t\tr.exec("sh restart.sh");\n\t\t\t\t\tLog.sysOut("Attempted to execute \'restart.sh\' in "+new File(".").getCanonicalPath());\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\tif(new File(".\\\\restart.bat").exists())\n\t\t\t\t{\n\t\t\t\t\tr.exec("cmd.exe /c start \\"\\" restart.bat");\n\t\t\t\t\tLog.sysOut("Attempted to execute \'restart.bat\' in "+new File(".").getCanonicalPath());\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\tif(System.getProperty("os.name").toLowerCase().indexOf("windows")>=0)\n\t\t\t{\n\t\t\t\tr.exec("cmd.exe /c start \\"\\" "+command);\n\t\t\t\tLog.sysOut("Attempted to execute \'"+command+"\' in "+new File(".").getCanonicalPath());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tr.exec("sh "+command);\n\t\t\t\tLog.sysOut("Attempted to execute \'"+command+"\' in "+new File(".").getCanonicalPath());\n\t\t\t}\n\t\t}\n\t\tcatch (final IOException e)\n\t\t{\n\t\t\tLog.errOut(e);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void setAcceptConnections(final boolean truefalse)\n\t{\n\t\tacceptConns=truefalse;\n\t}\n\n\t@Override\n\tpublic boolean isAcceptingConnections()\n\t{\n\t\treturn acceptConns;\n\t}\n\n\t@Override\n\tpublic long getUptimeSecs()\n\t{\n\t\treturn (System.currentTimeMillis()-startupTime)/1000;\n\t}\n\n\t@Override\n\tpublic String executeCommand(final String cmd) throws Exception\n\t{\n\t\tfinal List<String> V=CMParms.parse(cmd);\n\t\tif(V.size()==0)\n\t\t\tthrow new CMException("Unknown command!");\n\t\tfinal String word=V.get(0);\n\t\tif(word.equalsIgnoreCase("GET")&&(V.size()>1))\n\t\t{\n\t\t\tfinal String what=V.get(1);\n\t\t\tif(what.equalsIgnoreCase("CM1SERVER")&&(V.size()>2))\n\t\t\t{\n\t\t\t\tfinal String what2=V.get(2);\n\t\t\t\tif(cm1Servers.size()==0)\n\t\t\t\t\treturn "Failure";\n\t\t\t\tfinal CM1Server svr=cm1Servers.get(0);\n\t\t\t\tif(what2.equalsIgnoreCase("PORT"))\n\t\t\t\t\treturn ""+svr.getPort();\n\t\t\t\telse\n\t\t\t\tif(what2.equalsIgnoreCase("NAME"))\n\t\t\t\t\treturn ""+svr.getName();\n\t\t\t\treturn "Failure";\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn "Failure";\n\t\t}\n\t\telse\n\t\tif(word.equalsIgnoreCase("TICK")&&(V.size()>1))\n\t\t{\n\t\t\tfinal String what=V.get(1);\n\t\t\tif(what.equalsIgnoreCase("SMTP"))\n\t\t\t{\n\t\t\t\tif((smtpServerThread != null)\n\t\t\t\t&&(smtpServerThread.tick(smtpServerThread, Tickable.TICKID_EMAIL)))\n\t\t\t\t\treturn "Done";\n\t\t\t\telse\n\t\t\t\t\treturn "Failure";\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn "Failure";\n\t\t}\n\t\telse\n\t\tif(word.equalsIgnoreCase("START")&&(V.size()>1))\n\t\t{\n\t\t\tfinal String what=V.get(1);\n\t\t\tif(what.equalsIgnoreCase("I3"))\n\t\t\t{\n\t\t\t\tstartIntermud3();\n\t\t\t\treturn "Done";\n\t\t\t}\n\t\t\telse\n\t\t\tif(what.equalsIgnoreCase("IMC2"))\n\t\t\t{\n\t\t\t\tstartIntermud2();\n\t\t\t\treturn "Done";\n\t\t\t}\n\t\t\telse\n\t\t\tif(what.equalsIgnoreCase("WEB"))\n\t\t\t{\n\t\t\t\tif(V.size()<3)\n\t\t\t\t\treturn "Need Server Name";\n\t\t\t\tif(startWebServer(CMProps.instance(),V.get(2)))\n\t\t\t\t\treturn "Done";\n\t\t\t\telse\n\t\t\t\t\treturn "Failure";\n\t\t\t}\n\t\t\telse\n\t\t\tif(what.equalsIgnoreCase("CM1"))\n\t\t\t{\n\t\t\t\tif(V.size()<3)\n\t\t\t\t\treturn "Need Server Name";\n\t\t\t\tif(startCM1())\n\t\t\t\t\treturn "Done";\n\t\t\t\telse\n\t\t\t\t\treturn "Failure";\n\t\t\t}\n\t\t\telse\n\t\t\tif(what.equalsIgnoreCase("SMTP"))\n\t\t\t{\n\t\t\t\tif(smtpServerThread==null)\n\t\t\t\t{\n\t\t\t\t\tsmtpServerThread = new SMTPserver(CMLib.mud(0)); // initializes variables, even if it\'s not used\n\t\t\t\t\tsmtpServerThread.start();\n\t\t\t\t\tserviceEngine.startTickDown(Thread.currentThread().getThreadGroup(),smtpServerThread,Tickable.TICKID_EMAIL,CMProps.getTickMillis(),(int)CMProps.getTicksPerMinute() * 5);\n\t\t\t\t\treturn "Done";\n\t\t\t\t}\n\t\t\t\treturn "Failure";\n\t\t\t}\n\t\t}\n\t\telse\n\t\tif(word.equalsIgnoreCase("STOP")&&(V.size()>1))\n\t\t{\n\t\t\tfinal String what=V.get(1);\n\t\t\tif(what.equalsIgnoreCase("WEB"))\n\t\t\t{\n\t\t\t\tif(V.size()<3)\n\t\t\t\t\treturn "Need Server Name";\n\t\t\t\tif(stopWebServer(V.get(2)))\n\t\t\t\t\treturn "Done";\n\t\t\t\telse\n\t\t\t\t\treturn "Failure";\n\t\t\t}\n\t\t\telse\n\t\t\tif(what.equalsIgnoreCase("I3"))\n\t\t\t{\n\t\t\t\tif(i3server!=null)\n\t\t\t\t\tI3Server.shutdown();\n\t\t\t\ti3server=null;\n\t\t\t\treturn "Done";\n\t\t\t}\n\t\t\telse\n\t\t\tif(what.equalsIgnoreCase("IMC2"))\n\t\t\t{\n\t\t\t\tif(imc2server!=null)\n\t\t\t\t\timc2server.shutdown();\n\t\t\t\treturn "Done";\n\t\t\t}\n\t\t\telse\n\t\t\tif(what.equalsIgnoreCase("CM1"))\n\t\t\t{\n\t\t\t\tif(stopCM1())\n\t\t\t\t\treturn "Done";\n\t\t\t\telse\n\t\t\t\t\treturn "Failure";\n\t\t\t}\n\t\t\telse\n\t\t\tif(what.equalsIgnoreCase("SMTP"))\n\t\t\t{\n\t\t\t\tif(smtpServerThread!=null)\n\t\t\t\t{\n\t\t\t\t\tsmtpServerThread.shutdown();\n\t\t\t\t\tserviceEngine.deleteAllTicks(smtpServerThread);\n\t\t\t\t\tsmtpServerThread = null;\n\t\t\t\t\treturn "Done";\n\t\t\t\t}\n\t\t\t\treturn "Failure";\n\t\t\t}\n\t\t}\n\t\telse\n\t\tif(word.equalsIgnoreCase("WEBSERVER")&&(V.size()>2))\n\t\t{\n\t\t\tfinal String var = V.get(2);\n\t\t\tWebServer server=null;\n\t\t\tfor(final WebServer serv : webServers)\n\t\t\t{\n\t\t\t\tif(serv.getName().equalsIgnoreCase(V.get(1)))\n\t\t\t\t{\n\t\t\t\t\tserver=serv;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\tif(CMath.s_bool(serv.getConfig().getMiscProp("ADMIN")))\n\t\t\t\t{\n\t\t\t\t\tif(V.get(1).equalsIgnoreCase("ADMIN"))\n\t\t\t\t\t{\n\t\t\t\t\t\tserver=serv;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif(V.get(1).equalsIgnoreCase("PUB"))\n\t\t\t\t\t{\n\t\t\t\t\t\tserver=serv;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(server==null)\n\t\t\t\tthrow new CMException("Unknown server: "+var);\n\t\t\tif(var.equalsIgnoreCase("PORT"))\n\t\t\t{\n\t\t\t\tfinal int[] ports = server.getConfig().getHttpListenPorts();\n\t\t\t\tif(ports.length==0)\n\t\t\t\t\treturn "";\n\t\t\t\treturn Integer.toString(ports[0]);\n\t\t\t}\n\t\t\telse\n\t\t\tif((V.size()>3)&&(var.equalsIgnoreCase("DEBUG")))\n\t\t\t\tserver.getConfig().setDebugFlag(V.get(3));\n\t\t\telse\n\t\t\tif((V.size()>3)&&(var.equalsIgnoreCase("ACCESS")))\n\t\t\t\tserver.getConfig().setDebugFlag(V.get(3));\n\t\t\telse\n\t\t\t\tthrow new CMException("Unknown variable: "+var);\n\t\t\treturn "";\n\t\t}\n\t\tthrow new CMException("Unknown command: "+word);\n\t}\n}\n', 'message': '\n\ngit-svn-id: svn://192.168.1.10/public/CoffeeMud@1320 0d6f1817-ed0e-0410-87c9-987e46238f29\n', 'author_name': 'bozimmerman', 'lang': 'java'}