context: using System;
  using Server;
  using System.Text;
  using System.Collections;
  using Server.Accounting;
  using Server.Network;
  
  namespace Server.Admin
  {
  	public class AdminNetwork
  	{
  		private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  
  		private static ArrayList m_Auth = new ArrayList();
  		private static bool m_NewLine = true;
  		private static StringBuilder m_ConsoleData = new StringBuilder();
  
  		private const string DateFormat = "MMMM dd hh:mm:ss.f tt";
  
  		public static void Configure()
  		{
  			Stub.m_IsAuth += IsAuth;
  
  			PacketHandlers.Register( 0xF1, 0, false, new OnPacketReceive( OnReceive ) );
  
  			Core.MultiConsoleOut.Add( new EventTextWriter( new EventTextWriter.OnConsoleChar( OnConsoleChar ), new EventTextWriter.OnConsoleLine( OnConsoleLine ), new EventTextWriter.OnConsoleStr( OnConsoleString ) ) );
  			Timer.DelayCall( TimeSpan.FromMinutes( 2.5 ), TimeSpan.FromMinutes( 2.5 ), new TimerCallback( CleanUp ) );
  		}
  
  		public static void OnConsoleString( string str )
  		{
  			string outStr;
  			if ( m_NewLine )
  			{
  				outStr = String.Format( "[{0}]: {1}", Core.Now.ToString( DateFormat ), str );
  				m_NewLine = false;
  			}
  			else
  			{
  				outStr = str;
  			}
  
  			m_ConsoleData.Append( outStr );
  			if ( m_ConsoleData.Length >= 4096 )
  				m_ConsoleData.Remove( 0, 2048 );
  
  			for (int i=0;i<m_Auth.Count;i++)
  				((NetState)m_Auth[i]).Send( new ConsoleData( str ) );
  		}
  
  		public static void OnConsoleChar( char ch )
  		{
  			if ( m_NewLine )
  			{
  				string outStr;
  				outStr = String.Format( "[{0}]: {1}", Core.Now.ToString( DateFormat ), ch );
  
  				m_ConsoleData.Append( outStr );
  
  				for (int i=0;i<m_Auth.Count;i++)
  					((NetState)m_Auth[i]).Send( new ConsoleData( outStr ) );
  
  				m_NewLine = false;
  			}
  			else
  			{
  				m_ConsoleData.Append( ch );
  
  				for (int i=0;i<m_Auth.Count;i++)
  					((NetState)m_Auth[i]).Send( new ConsoleData( ch ) );
  			}
  
  			if ( m_ConsoleData.Length >= 4096 )
  				m_ConsoleData.Remove( 0, 2048 );
  		}
  
  		public static void OnConsoleLine( string line )
  		{
  			string outStr;
  			if ( m_NewLine )
  				outStr = String.Format( "[{0}]: {1}{2}", Core.Now.ToString( DateFormat ), line, Console.Out.NewLine );
  			else
  				outStr = String.Format( "{0}{1}", line, Console.Out.NewLine );
  
  			m_ConsoleData.Append( outStr );
  			if ( m_ConsoleData.Length >= 4096 )
  				m_ConsoleData.Remove( 0, 2048 );
  
  			for (int i=0;i<m_Auth.Count;i++)
  				((NetState)m_Auth[i]).Send( new ConsoleData( outStr ) );
  
  			m_NewLine = true;
  		}
  
  		public static void OnReceive( NetState state, PacketReader pvSrc )
  		{
  			byte cmd = pvSrc.ReadByte();
  			if ( cmd == 0x02 )
  			{
  				Authenticate( state, pvSrc );
  			}
  			else if ( cmd == 0xFF )
  			{
  				string statStr = String.Format( ", Name={0}, Age={1}, Clients={2}, Items={3}, Chars={4}, Mem={5}K", Server.Misc.ServerList.ServerName, (int)(Core.Now-Server.Items.Clock.ServerStart).TotalHours, NetState.Instances.Count, World.Items.Count, World.Mobiles.Count, (int)(System.GC.GetTotalMemory(false)/1024) );
  				state.Send( new UOGInfo( statStr ) );
  				state.Dispose();
  			}
  			else if ( !IsAuth( state ) )
  			{
  				log.Warn(String.Format("ADMIN: Unauthorized packet from {0}, disconnecting",
  									   state));
  				Disconnect( state );
  			}
  			else
  			{
  				if ( !RemoteAdminHandlers.Handle( cmd, state, pvSrc ) )
  					Disconnect( state );
  			}
  		}
  
  		private static void DelayedDisconnect( NetState state )
  		{
  			Timer.DelayCall( TimeSpan.FromSeconds( 15.0 ), new TimerStateCallback( Disconnect ), state );
  		}
  		
  		private static void Disconnect( object state )
  		{
  			m_Auth.Remove( state );
  			((NetState)state).Dispose();
  		}
  		
  		public static void Authenticate( NetState state, PacketReader pvSrc )
  		{
  			string user = pvSrc.ReadString( 30 );
  			string pw = pvSrc.ReadString( 30 );
  
  			Account a = Accounts.GetAccount( user );
  			if ( a == null )
  			{
  				state.Send( new Login( LoginResponse.NoUser ) );
  				log.Warn(String.Format("ADMIN: Invalid username '{0}' from {1}",
  									   user, state));
  				DelayedDisconnect( state );
  			}
  			else if ( !a.HasAccess( state ) )
  			{
  				state.Send( new Login( LoginResponse.BadIP ) );
  				log.Warn(String.Format("ADMIN: Access to '{0}' from {1} denied.",
  									   user, state));
  				DelayedDisconnect( state );
  			}
  			else if ( !a.CheckPassword( pw ) )
  			{
  				state.Send( new Login( LoginResponse.BadPass ) );
  				log.Warn(String.Format("ADMIN: Invalid password '{0}' for user '{1}' from {2}",
  									   pw, user, state));
  				DelayedDisconnect( state );
  			}
  			else if ( a.AccessLevel != AccessLevel.Administrator || a.Banned )
  			{
  				log.Warn(String.Format("ADMIN: Account '{0}' does not have admin access. Connection Denied.",
  									   user));
  				state.Send( new Login( LoginResponse.NoAccess ) ); 
  				DelayedDisconnect( state );
  			}
  			else
  			{
  				log.Warn(String.Format("ADMIN: Access granted to '{0}' from {1}",
  									   user, state));
  				state.Account = a;
  				a.LogAccess( state );
  				a.LastLogin = Core.Now;
  
  				state.Send( new Login( LoginResponse.OK ) );
  				state.Send( Compress( new ConsoleData( m_ConsoleData.ToString() ) ) );
  				m_Auth.Add( state );
  			}
  		}
  
  		public static bool IsAuth( NetState state )
  		{
  			return m_Auth.Contains( state );
  		}
  
  		private static void CleanUp()
  		{//remove dead instances from m_Auth
  			ArrayList list = new ArrayList();
  			for (int i=0;i<m_Auth.Count;i++)
  			{
  				NetState ns = (NetState) m_Auth[i];
  				if ( ns.Running )
  					list.Add( ns );
  			}
  
  			m_Auth = list;
  		}
  
  		public static Packet Compress( Packet p )
  		{
  			byte[] source = p.Compile( false );
  
  			if ( source.Length > 100 && source.Length < 60000 )
  			{
  
gt: 				byte[] dest = new byte[(int)(source.Length*1.001)+1];