/* ** j###t ########## #### #### ** j###t ########## #### #### ** j###T "###L J###" ** ######P' ########## ######### ** ######k, ########## T######T ** ####~###L #### ** #### q###L ########## .##### ** #### \###L ########## #####" ** */ package key; import java.net.*; import java.io.*; import java.util.*; import java.lang.*; public class Main implements StartupHandler { /** * Set to true if you want to halve your disk space usage */ public static final boolean COMPRESS_DISK_FILES = false; public static final boolean CONNECT_TO_DATABASE = false; /** * Set to true if you want key to do automatic ident * lookups */ public static final boolean SOCKET_IDENT_LOOKUP = true; private File db; private Key key; private Registry registry; private boolean adminMode; public Main( boolean create, boolean admin ) { Key.creation = create; adminMode = admin; } public int doMenu( Menu m ) throws IOException { int choice; do { System.err.println( m.title ); int i; for( i = 0; i < m.options.length; i++ ) { MenuOption mo = m.options[i]; System.err.println( Integer.toString( mo.number ) + "] " + mo.title ); } System.err.println( "\n\n(enter displays this menu again)\nPlease select a menu option: " ); do { try { String s = getLine( "[1-" + i + "]: " ); if( s.length() > 0 ) { choice = Integer.parseInt( s ); if( choice > i || choice <= 0 ) { System.err.println( "Your choice must be between 1 and " + i + "." ); choice = -1; } } else choice = 0; } catch( NumberFormatException e ) { System.err.println( "Please make your choice using digits only." ); choice = -1; } } while( choice < 0 ); } while( choice <= 0 ); return( choice ); } public boolean findDB() { db = new File( "database" ); return( db.exists() ); } public boolean load() { if( db.exists() ) { Registry.baseDirectory = Key.confirmedDirectory( "distinct" ); Log.bootLog( "Loading '" + db.getPath() + "'..." ); registry = (Registry) Factory.loadObject( db ); key = Key.instance(); key.initFieldCache(); return true; } return( false ); } private Player getValidPlayer() throws IOException { Player p; do { String name = getValidName(); p = (Player) key.getResidents().getElement( name ); if( p != null ) return( p ); System.err.println( "\nCould not find player '" + name + "'. Please enter a different name." ); } while( true ); } private File getValidFile() throws IOException { File f; do { String name = getLine( "Filename: " ); f = new File( name ); if( f.exists() ) return( f ); System.err.println( "\nCould not find file '" + f.getAbsolutePath() + "'.\nPlease enter a different filename." ); } while( true ); } public void addRevoke() throws IOException { Player p = getValidPlayer(); if( p.isBeyond() ) { p.maybeClearBeyond(); System.err.println( p.getName() + " no longer has the beyond priviledge." ); } else { p.maybeSetBeyond(); System.err.println( p.getName() + " now has the beyond priviledge." ); } p.sync(); } public void doScript() throws IOException { System.err.println( "\n\n" + "Two things are required to execute a script. First, a player\n" + "name to execute the script as, and second, the filename of the\n" + "script itself." ); Player p = getValidPlayer(); File f = null; File file = getValidFile(); FileIC fic = new FileIC( file ); runScript( p, file, fic ); } public void doConsoleLogin() throws IOException { System.err.println( "\n\n" + "Enter a player name to execute the script as." ); Player p = getValidPlayer(); System.err.println( "\nConsole Login for " + p.getName() + "...\n" + "Press EOF <CONTROL-D on unix or CONTROL-Z on dos> to close the connection.\n" ); ConsoleIC cic = new ConsoleIC(); try { p.connectTo( cic ); cic.interactWith( p ); p.run( cic ); System.err.println( "Connection terminated." ); } catch( BadKeyException e ) { e.printStackTrace(); } catch( NonUniqueKeyException e ) { e.printStackTrace(); } } public void runScript( Player p, File file, FileIC fic ) throws IOException { System.err.println( "\nWould you like to watch the output of the script scroll past?" ); fic.setDisplay( yesNo() ); System.err.println( "\nExecuting script '" + file.getAbsolutePath() + "'..." ); try { p.connectTo( fic ); fic.interactWith( p ); p.run( fic ); System.err.println( "Script complete." ); } catch( BadKeyException e ) { e.printStackTrace(); } catch( NonUniqueKeyException e ) { e.printStackTrace(); } catch( NetworkException e ) { System.out.println( e.getMessage() ); } catch( Error e ) { e.printStackTrace(); } } public String getValidName() throws IOException { int len; boolean con; String name; System.err.println(); do { con = false; name = getLine( "Administrator name: " ); len = name.length(); if( len < Player.MIN_NAME ) { System.err.println( "Key requires that names are at least " + Player.MIN_NAME + " characters long." ); con = true; } else if( len > Player.MAX_NAME ) { System.err.println( "Key requires that names are less than " + Player.MAX_NAME + " characters long." ); con = true; } else if( !Grammar.isStringCompletelyAlphabetical( name ) ) { System.err.println( "Names must contain only alphabetical characters." ); con = true; } else if( name.equalsIgnoreCase( "quit" ) ) { System.err.println( "You wouldn't be able to log in with this name." ); con = true; } } while( con ); return( name ); } public void create( Class cl ) throws IOException { Key.creation = true; adminMode = true; Registry.baseDirectory = Key.confirmedDirectory( "distinct" ); registry = new Registry(); key = (Key) Factory.makeAtom( cl ); key.initFieldCache(); // set up the initial admin player System.err.println(); System.err.println( "It is necessary to create a single administration account in order to\n" + "allow you to set up the server. You will now be prompted for the name\n" + "and password of this account." ); String name; String password; Player admin = null; do { name = getValidName(); password = getLine( "Password (will echo): " ); System.err.println(); System.err.println( "Administrator name: " + name + ", password: " + password + ". Okay?" ); } while( !yesNo() ); System.err.println(); try { admin = (Player) Factory.makeAtom( Player.class, name ); admin.setPassword( password ); admin.maybeSetBeyond(); admin.canSave = true; key.getResidents().add( admin ); admin.sync(); if( registry.getStorageTypeIndex( admin.index, admin.timestamp ) != Registry.STORAGE_LOADED ) { System.err.println( "An error has occurred creating this character: it has not been sync'd." ); System.exit( 1 ); } } catch( BadKeyException e ) { System.err.println( "The name you have selected is not appropriate: " + e.toString() ); System.exit( 1 ); } catch( NonUniqueKeyException e ) { System.err.println( "The name you have selected is in use for something else: " + e.toString() ); System.exit( 1 ); } key.sync(); System.err.println( "Created new Administrator '" + name + "'." ); System.err.println(); File setupDirectory = new File( "setup" ); File basicSetup = new File( setupDirectory, "basic.ks" ); File standardSetup = new File( setupDirectory, "standard.ks" ); if( basicSetup.exists() && standardSetup.exists() ) { int mo = doMenu( seedMenu ); switch( mo ) { case 1: case 2: case 3: File use; if( mo == 1 ) use = basicSetup; else if( mo == 2 ) use = standardSetup; else { System.err.println(); use = getValidFile(); } FileIC fic = new FileIC( use ); runScript( admin, use, fic ); break; case 4: return; } } else { if( basicSetup.exists() || standardSetup.exists() ) { System.err.println( "Unfortunately, this distribution of key seems to be missing one of these\n" + "ready-made setup scripts. They normally reside in the 'setup' directory\n" + "of the distribution, and are called 'standard.ks' and 'basic.ks'." ); } else { System.err.println( "Unfortunately, Key is either not running in its distribution directory, or\n" + "these scripts have been inadvertently erased." ); } System.err.println( "\n" + "This means that it is impossible at this time to automatically seed the\n" + "database: you will need to set it up by hand." ); } // this code doesn't get executed if they choose to go // straight to the administration menu from option 4, above System.err.println( "\n" + "We will now proceed to the administration menu.\n" + "Press any key to continue." ); getLine( "" ); } public void boot() { //System.setSecurityManager( Security.instance ); key.start(); } public void acceptControl( Main m ) { try { if( findDB() ) { if( load() ) { if( !adminMode ) { boot(); return; } } } else { System.err.println( "Database file '" + db.getPath() + "' does not exist." ); System.err.println(); System.err.println( "Would you like to store Key's files in '" + System.getProperty( "user.dir", "" ) + "'?" ); if( !yesNo() ) { System.err.println(); System.err.println( "Please run this program from the directory you wish to store the files in." ); String home = System.getProperty( "user.home", null ); String sep = System.getProperty( "file.separator", null ); if( home != null && sep != null ) System.err.println( "For instance, you may wish to run this program from '" + home + sep + "key'." ); return; } else System.err.println(); // at the moment, this is hard coded. we might // change it in the future. create( Forest.class ); } while( adminMode ) { switch( doMenu( mainMenu ) ) { case 1: adminMode = false; System.err.println( "\n" ); break; case 2: addRevoke(); break; case 3: doScript(); break; case 4: doConsoleLogin(); break; case 5: System.err.println( "\n" ); key.shutdown(); System.exit( 0 ); break; } } boot(); } catch( Exception e ) { e.printStackTrace(); } } public boolean yesNo() throws IOException { String yn = getLine( "(y/N): " ); if( yn.length() > 0 ) { char c = yn.charAt( 0 ); if( c == 'y' || c == 'Y' ) return( true ); } return false; } BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) ); public String getLine( String prompt ) throws IOException { System.err.print( prompt ); System.err.flush(); return( br.readLine() ); } public static void main( String args[] ) { boolean admin = false; boolean gui = false; boolean creation = false; for( int i = 0; i < args.length; i++ ) { if( args[i].equalsIgnoreCase( "admin" ) ) admin = true; else if( args[i].equalsIgnoreCase( "swing" ) ) gui = true; else if( args[i].equalsIgnoreCase( "creation" ) ) creation = true; else { System.err.println( "Unknown argument '" + args[i] + "'" ); System.err.println( "Available arguments:\n" + "\n" + "\tadmin \tStarts the program in an interactive mode\n" + "\tswing \tAllows program monitoring with a Swing GUI\n" + "\tcreation\tAllows the program to create directories as needed\n" ); return; } } System.err.println( Key.copyright ); System.err.println(); try { StartupHandler sh = null; if( gui ) { try { Class c = Class.forName( "key.swing.Startup" ); sh = (StartupHandler) c.newInstance(); } catch( Exception e ) { System.err.println( "Could not initialise swing interface:" ); e.printStackTrace( System.err ); } } Main m = new Main( creation, admin ); if( sh == null ) sh = m; sh.acceptControl( m ); } catch( ExceptionInInitializerError e ) { System.out.println( e.toString() + ":" ); Throwable t = e.getException(); t.printStackTrace(); } catch( Exception e ) { System.out.println( e.toString() ); e.printStackTrace( System.out ); } } static MenuOption[] mainMenuOptions = { new MenuOption( 1, "Start Key" ), new MenuOption( 2, "Add or Revoke Administrator priviledges" ), new MenuOption( 3, "Execute a KeyScript" ), new MenuOption( 4, "Log in on the console" ), new MenuOption( 5, "Exit" ) }; static Menu mainMenu = new Menu( "\n\nKey Administration Menu\n", mainMenuOptions ); static MenuOption[] seedMenuOptions = { new MenuOption( 1, "Basic (commands and ranks only)" ), new MenuOption( 2, "Standard (basic + sample room descriptions & help files)" ), new MenuOption( 3, "A custom script" ), new MenuOption( 4, "Exit to the administration menu" ) }; static Menu seedMenu = new Menu( "A brand new Key database is generally fairly sparse and unusable. It is\n" + "strongly recommended that you seed the initial database using one of the\n" + "provided setup scripts.\n", seedMenuOptions ); } class MenuOption { String title; int number; MenuOption( int n, String t ) { number = n; title = t; } } class Menu { MenuOption[] options; String title; Menu( String t, MenuOption[] o ) { title = t; options = o; } }