/* ** j###t ########## #### #### ** j###t ########## #### #### ** j###T "###L J###" ** ######P' ########## ######### ** ######k, ########## T######T ** ####~###L #### ** #### q###L ########## .##### ** #### \###L ########## #####" ** ** $Id: ViewLog.java,v 1.1 1997/07/20 16:24:05 subtle Exp subtle $ ** ** Class History ** ** Date Name Description ** ---------|------------|----------------------------------------------- ** 19Jul97 subtle created this command ** */ package key.commands; import key.*; import java.io.*; import java.util.StringTokenizer; import java.util.Hashtable; public class ViewLog extends Command { private static final long serialVersionUID = 4263891712481759116L; public static final AtomicElement[] ELEMENTS = { // if this field is specified, it is used as the log file. // if this field ends with '/', what the player types as // an argument is appended to this name to get the path AtomicElement.construct( ViewLog.class, String.class, "logName", AtomicElement.PUBLIC_FIELD, "the name of the log file" ), }; public static final AtomicStructure STRUCTURE = new AtomicStructure( Command.STRUCTURE, ELEMENTS ); public String logName = ""; public ViewLog() { setKey( "vlog" ); usage = "<logname>"; } public AtomicStructure getDeclaredStructure() { return( STRUCTURE ); } public void run( Player p, StringTokenizer args, String fullLine, CategoryCommand caller, InteractiveConnection ic, Flags flags ) throws IOException { String thisLogname; boolean isnull = (logName == null); boolean islengthzero = false; boolean directory = false; if( !isnull ) { islengthzero = (logName.length() == 0); if( !islengthzero ) directory = (logName.endsWith( "/" )); } if( isnull || islengthzero || directory ) { if( args.hasMoreTokens() ) { String enteredName = args.nextToken(); if( directory ) thisLogname = logName + enteredName; else thisLogname = enteredName; } else { usage( ic ); return; } } else thisLogname = logName; try { File logsBasePath = Key.instance().getLogsBasePath(); File logFile = new File( logsBasePath, thisLogname ); if( !logFile.exists() || !logFile.canRead() ) { ic.sendError( "The log file '" + thisLogname + "' does not exist or is not readable." ); return; } else { // if this is a directory, check that the player // hasn't done something clever (ie, ".." or "/") to get // out of it. if( directory ) { File basePath = new File( logsBasePath, logName ); String lfc = logFile.getCanonicalPath(); // check to see if this is a valid path if( !lfc.startsWith( basePath.getCanonicalPath() ) ) { // this is not okay ic.sendError( "This is not a valid log file name." ); return; } } } FileReader fr = Log.viewLog( thisLogname ); BufferedReader br = new BufferedReader( fr ); // META: this is temporary. I want to eventually // be able to reverse the lines and display some of them // in reverse order, but this is way into the future. It'd // be nice if the pager was retro-active, too - allowing me // to pump in a page of data, and have no more requested until // they actually asked for more to be displayed. String l = br.readLine(); StringBuffer sb = new StringBuffer(); while( l != null ) { sb.append( l ); sb.append( '\n' ); l = br.readLine(); } ic.send( new TextParagraph( TextParagraph.LEFT, sb.toString() ) ); // make it easier to garbage collect all this quickly sb.setLength( 0 ); sb = null; } catch( IOException e ) { ic.sendFailure( "An error occurred trying to read the '" + thisLogname + "' log file" ); } } public void usage( InteractiveConnection ic ) { super.usage( ic ); ic.send( "\nThe following logs are available to be viewed:" ); File logsBasePath = Key.instance().getLogsBasePath(); File path; if( logName == null || logName.length() == 0 ) path = logsBasePath; else path = new File( logsBasePath, logName ); String[] li = path.list(); ic.send( Grammar.commaSeperate( li ) ); } }