/************************************************
* Columbia University CS Department
* Network Security Lab
*
* Open and Survivable Embedded Systems (OASES)
*
* Structured Policy Command Language (SPCL)
*
*
* This software is provided as is without any
* warranty or guarantee of merchantibility
* or fitness for a particular purpose. This
* software is released under the terms of the
* GNU General Public License (GPL).
*
* Last updated: March 27, 2003
*
***********************************************/

package spcl.client;

import spcl.data.*;
import java.net.*;
import java.io.*;
import java.util.*;

/** 
 * A basic utility for communicating with
 * the policyengine. Starts up an 
 * interactive command line interpreter
 *
 * @author locasto@cs.columbia.edu
 *
*/
public class PolicyEngineClient{

	private Socket client;
	private ObjectInputStream oin;
	private ObjectOutputStream oout;
	private InputStreamReader isr;
	private BufferedReader keyboard;


	public PolicyEngineClient() throws Exception{
		//prompt user for 'connect ip port'

		String command = "";
		Vector args = new Vector( 7 );
		isr = new InputStreamReader(System.in);
		keyboard = new BufferedReader(isr);
		System.out.print( "\npec> " );
		command = keyboard.readLine();
		command = command.trim();
		if( command==null || command.equals( "" ) || command.equalsIgnoreCase( "bye" ) || command.equalsIgnoreCase( "quit" ) || command.equalsIgnoreCase( "exit" ) ){
			System.out.println( "PolicyEngine client exiting..." );
			System.exit( 0 );
		}else if( command.equalsIgnoreCase( "help" ) ){
			System.out.println( "\nHELP:\n\tbye,exit,quit,help,connect [host] [port]\n" );
		}else if( command.startsWith( "connect " ) ){
			StringTokenizer tokens = new StringTokenizer( command, "\t\f\n ", false );
			String ipaddr = "0.0.0.0";
			int port = -1;
			while( tokens.hasMoreTokens() ){
				args.addElement( tokens.nextToken() );
			}
			if( args.size() == 3 ){
				ipaddr = ((String)args.elementAt( 1 ));
				port = Integer.parseInt( ((String)args.elementAt( 2 )) );
				
				client = new Socket( InetAddress.getByName( ipaddr ), port );
				oout = new ObjectOutputStream( client.getOutputStream() );
				oout.flush();
				oin = new ObjectInputStream( client.getInputStream() );
				PolicyRequest request = new PolicyRequest();
				request.setContent( "hello" );
				oout.writeObject( request );
				
				PolicyResponse response = (PolicyResponse)oin.readObject();
				System.out.println( response.toString() );

				runUI();

			}else{
				throw new Exception( "bad args." );
			}


		}else{
		   System.out.println( "Unrecognized command." );
		   System.exit( -1 );
		}

	}


	private void runUI(){

		PolicyRequest request;
		PolicyResponse response;
		boolean die = false;
		int num=0;
		System.out.println( "" );
		String input = "";

		while( !die ){
			request = new PolicyRequest();
			response = null;
			System.out.print( "pec["+num+"] " );

			try{

				input = keyboard.readLine();
                
				/* if readLine() == null, die */
				if( input == null || input.equals( "bye" ) || input.equals( "exit" ) ){
					die=true;
					keyboard.close();
					request.setContent( "bye" );

				}else{

					request.setContent( input );

				}

				response = send( request );
				System.out.println( response.toString() );

			}catch( Exception e ){
			  System.err.println( "Problem with command: "+e.getMessage() );
			}
			num++;
		}
		
		try{
			if( oin!=null )
				oin.close();
			if( oout!=null ){
				oout.flush();
				oout.close();
			}
			if( client!=null && !client.isClosed() )
				client.close();
		}catch( Exception ex ){
			System.err.println( "Problem closing connection: "+ex.getMessage() );
		}finally{
			oin=null;
			oout=null;
			keyboard = null;
			client = null;
		}
		System.exit( 0 );
	}
	
	private PolicyResponse send( PolicyRequest request ) throws Exception{

		oout.writeObject( request );
		oout.flush();

		return ((PolicyResponse)oin.readObject());

	}

	/**
	 * SPCL client commands:
	 * server returns "hi, allow, no, deny, bye"
	 * 
	 * 'switch zone [zone]' : search this collection of policies
	 *                        this cmd only succeeds if the s-o client is
	                          recognized in this zone
	 * 'switch policy [policy]' : search this policy for rules first
	 * 'switch object [systemobject]' : become another system object (if it exists)
	 * 'context' or 'current' : prints out current zone and policy namespace
	 * 'can [principal] do [action] on [systemobject/me] with (param1=x AND param2=y);'
	 * 'list [active|suspended] rules'
	 * 'list groups'
	 * 'list zones'
	 * 'list objects'
	 * 'list principals'
	 * 'list policies'
	 * 'exit' 'bye' : end client session
	 * 'kill' : shutdown server
	 * eventually, we will provide 'install [fooinstaller.class]' where the 
	 *   policyengine takes the name of a client-local file, reads the bytes over
	 *   the network and writes them to a file in SPCL_HOME/conf/policy, and then uses
	 *   its install() method to load the policy in like normal.
	 *
	*/
	public static void main( String [] args ){
		//we could accept command line args, but for right now, prompt user
		try{
			new PolicyEngineClient();
		}catch( Exception e ){
			System.err.println( "PolicyEngineClient::main() problem="+e.getMessage() );
		}

	}

}
