/*
 * GNU.FREE 2002
 *
 * Copyright (c) 1999, 2000, 2001, 2002
 * The Free Software Foundation (www.fsf.org)
 *
 * GNU.FREE Co-ordinator: Jason Kitcat <jeep@free-project.org>
 *
 * GNU site: http://www.gnu.org/software/free/
 * 
 * FREE e-democracy site: http://www.free-project.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program (COPYING); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
  
package FreeClient;
 
import java.util.*;
import Free.util.*;

/**
 * ClientProtocol receives Strings of data from <code>TCPClient</code> and 
 * implements the logic to process these strings and formulate the appropriate
 * replies.
 *
 * The source code is extremely readable and best explains the full functionality.
 *
 * @version 1.1 1 December 2001
 * @author Jason Kitcat
 */
public class ClientProtocol {

	/**
	 * process analyses packets and responds appropriately.
	 *
	 * @param inputData   Contains the contents of a received packet
	 * @returns		String with a packet to return to client
	 * @throws		<code>Exception</code>, all errors are handled by <code>TCPClient</code>
	 *				which has the ability to gracefully close the connection.  
	 */
	protected static String[] process(String inputData) throws Exception {

		String[] outputData = new String[] {" "," "}; // field one for control data, two for rest
		FClient.comms.setSequence_number(FClient.comms.getSequence_number()+1); // increment as we've just got a packet!

		if (inputData.charAt(0) == 'A') {
			/* auth request */
			Packet p = new Packet(inputData);

			if (AuthSys.checkHMAC(p,FClient.comms.getServer_hmac_key(),FClient.comms.getSequence_number())) {  // tamper check
			
				// split message
				String[] pp = p.splitMessage();
				String authFlag = pp[0];
				String authKey = pp[1];
			
				if (authFlag.equals("TRUE")) {
					FClient.comms.setERAuthKey(authKey);
					FClient.frame4.showInfo(FClient.messages.getString("auth_yes"));
					FClient.frame4.status=true;
					FClient.frame4.jButton1.setEnabled(true);
					FClient.frame4.showInfo(FClient.messages.getString("ok_continue"));
				} else {
					FClient.frame4.showError(FClient.messages.getString("auth_failed"));
					FClient.frame4.status=false;
					FClient.frame4.jButton1.setEnabled(true);
					FClient.frame4.jButton2.setEnabled(true);
					FClient.frame4.showInfo(FClient.messages.getString("try_again"));
				}
				
				FClient.comms.setSequence_number(FClient.comms.getSequence_number()+1); // incement as we send another packet
				outputData[0] = "X"; // ending connection
				outputData[1] = new Packet('X',"OK",FClient.comms.getsession_key(),FClient.comms.er_public_key,FClient.comms.getClient_hmac_key(),FClient.comms.getSequence_number()).toCryptString(true);

			} else {
				outputData[1] = "ERROR";
				FClient.frame4.showError(FClient.messages.getString("packet_alter"));
				FClient.frame4.status=false;
				FClient.frame4.jButton1.setEnabled(true);
				FClient.frame4.jButton2.setEnabled(true);
				FClient.frame4.showInfo(FClient.messages.getString("try_again"));
			}
			

		} else if (inputData.charAt(0) == 'C') {
			/* confirm */
			Packet p = new Packet(inputData);

			if (AuthSys.checkHMAC(p,FClient.comms.getServer_hmac_key(),FClient.comms.getSequence_number())) {  // tamper check
			
				if (p.getMessage().equals("STAMP")) {
					if (FClient.comms.getCheck() != null) {
						FClient.comms.setSequence_number(FClient.comms.getSequence_number()+1); // incement as we send another packet
						String data = FClient.comms.getERAuthKey()+"-"+FClient.comms.getCheck().toString();
						outputData[1] = new Packet('C',data,FClient.comms.getsession_key(),FClient.comms.rt_public_key,FClient.comms.getClient_hmac_key(),FClient.comms.getSequence_number()).toCryptString(true);
						FClient.frame.showInfo(FClient.messages.getString("stamp_sent"));		
					} else {
						FClient.frame.showError(FClient.messages.getString("vote_sec_err"));
						outputData[1] = "ERROR";
					}
				} else if (p.getMessage().equals("OK")) {  //everything went fine
					FClient.frame.showInfo(FClient.messages.getString("vote_conf"));
					FClient.comms.setSequence_number(FClient.comms.getSequence_number()+1); // incement as we send another packet
					outputData[0] = "X"; // ending connection
					outputData[1] = new Packet('X',"OK",FClient.comms.getsession_key(),FClient.comms.rt_public_key,FClient.comms.getClient_hmac_key(),FClient.comms.getSequence_number()).toCryptString(true);
					FClient.comms.noCheck();  // just in case, we clear the check date
					FClient.frame.voteOK();
				} else {
					FClient.frame.showError(FClient.messages.getString("unrec"));
					outputData[1] = "ERROR";
					FClient.frame.voteErr();
				}
			} else {
				FClient.frame.showError(FClient.messages.getString("packet_alter"));
				outputData[1] = "ERROR";
				FClient.frame.voteErr();
			}			
							
		} else if (inputData.charAt(0) == 'D') {
			/* diagnostic */
			Packet p = new Packet(inputData);

			if (AuthSys.checkHMAC(p,FClient.comms.getServer_hmac_key(),FClient.comms.getSequence_number())) {  // tamper check

				FClient.frame.showInfo(FClient.messages.getString("diag_rec"));
				FClient.comms.setSequence_number(FClient.comms.getSequence_number()+1); // incement as we send another packet
				outputData[0] = "X"; // ending connection
				outputData[1] = new Packet('X',"OK",FClient.comms.getsession_key(),FClient.comms.er_public_key,FClient.comms.getClient_hmac_key(),FClient.comms.getSequence_number()).toCryptString(true);
			
			} else {
				outputData[1] = "ERROR";
				throw new Exception(FClient.messages.getString("packet_alter"));
			}
			
		} else if (inputData.charAt(0) == 'I') {
			/* initialisation */
			Packet p = new Packet(inputData);
			
			// parse to get seperate data fields
			String[] pp = p.splitMessage();
			String seed2 = pp[0];
			String clientmac = pp[1];

			if (AuthSys.checkHMAC(p,FClient.comms.getServer_hmac_key(),FClient.comms.getSequence_number())) {  // tamper check
			
				if (AuthSys.checkHMAC(new Packet("I|"+FClient.comms.getClient_hmac_seed()+"|"+clientmac),FClient.comms.getClient_hmac_key(),0)) {  // authentication check of server's key

					FClient.comms.setServer_hmac_seed(seed2);  // initialise protocol values
					FClient.comms.setServer_hmac_key(AuthSys.seedToKey(FClient.comms.getServer_hmac_seed()));
					
					FClient.comms.setSequence_number(FClient.comms.getSequence_number()+1); // increment
					outputData[1] = FClient.comms.getMessage_two();  // now send real data
				
				} else {
					outputData[1] = "ERROR";
					throw new Exception(FClient.messages.getString("packet_alter"));
				}
			} else {
				outputData[1] = "ERROR";
				throw new Exception(FClient.messages.getString("packet_alter"));
			}

		} else {
			outputData[1] = "ERROR";
			if (FClient.ercheck) {  // make sure we're sending errors to the right screen
				FClient.frame4.showError(FClient.messages.getString("unrec"));
			} else {
				FClient.frame.showError(FClient.messages.getString("unrec"));
			}
		}
		
		return outputData;

	} //EOF process()

} //EOF Class