content: /*******************************************************************************
   * Copyright 2011 Alexandros Schillings
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   ******************************************************************************/
  package aws.apps.wifiKeyRecovery.util;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Map.Entry;
  
  import android.content.Context;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Message;
  import android.util.Log;
  import aws.apps.wifiKeyRecovery.R;
  import aws.apps.wifiKeyRecovery.containers.NetInfo;
  import aws.apps.wifiKeyRecovery.util.ExecTerminal.ExecResult;
  
  public class ExecuteThread extends Thread {
  	private final static String WIFI_BLOCK_START = "network={";
  	private final static String WIFI_BLOCK_END = "}";
  	private final static int RESULT_TITLE_LENGTH = 14;
  
  	public final static int STATE_DONE = 0;
  	public final static int STATE_RUNNING = 1;
  
  	public final static int WORK_COMPLETED = 50;
  	public final static int WORK_INTERUPTED = 51;
  
  	private final String TAG = this.getClass().getName();
  
  	private Handler mHandler;
  	private Context mContext;
  	private UsefulBits mUsefulBits;
  	private int mState;
  	private boolean mIsRooted;
  
  	public ExecuteThread(Handler h,
  			Context ctx,
  			Bundle b) {
  
  		this.mHandler = h;
  		this.mContext = ctx;
  		this.mUsefulBits = new UsefulBits(mContext);
  
  		this.mIsRooted = new ExecTerminal().checkSu();
  	}
  
  	private String appendBlanks(String text, int size) {
  		String res = text.trim();
  
  		if (res.length() < size) {
  			final int change = size - res.length();
  
  			for (int i = 0; i < change; i++) {
  				res += " ";
  			}
  
  			return res;
  		} else {
  			return res;
  		}
  
  	}
  
  	private String execute(String cmd) {
  		final ExecTerminal et = new ExecTerminal();
  		final ExecResult res;
  
  		if (mIsRooted) {
  			res = et.execSu(cmd);
  		} else {
  			res = et.exec(cmd);
  		}
  
  		return res.getStdOut();
  	}
  
  	private ArrayList<NetInfo> getWiFiPasswordList() {
  		final String[] shellCommands = mContext.getResources().getStringArray(R.array.shellCommands);
  		ArrayList<NetInfo> l = new ArrayList<NetInfo>();
  
  		for (int i = 0; i < shellCommands.length; i++) {
  			String result = execute(shellCommands[i]);
  			if (result.trim().length() > 0) {
  				l = parseWifiPasswords(l, result);
  				return l;
  			}
  		}
  
  		l.add(new NetInfo(mContext.getString(R.string.could_not_find_password_files)));
  		return l;
  	}
  
  	private ArrayList<NetInfo> parseWifiPasswords(ArrayList<NetInfo> l, String wifiPasswordString) {
  		final String passwordBlocks[] = wifiPasswordString.split("\n\n");
  		final Map<String, String> passKeys = new HashMap<String, String>();
  		final Map<String, String> settings = new HashMap<String, String>();
  
  		String ssid = "";
  		String password = ""; // only one, for the qr code;
  		int type = -1;
  
  		if (wifiPasswordString.length() <= 0) {
  			return l;
  		}
  
  		for (int i = 0; i < passwordBlocks.length; i++) {
  			String block = passwordBlocks[i].trim();
  
  			if (block.startsWith(WIFI_BLOCK_START) && block.endsWith(WIFI_BLOCK_END)) {
  				passKeys.clear();
  				settings.clear();
  				ssid = "";
  
  				String blockLines[] = block.split("\n");
  
  				for (int j = 0; j < blockLines.length; j++) {
  					String line = blockLines[j].trim();
  
  					if (line.startsWith("ssid=")) {
  						ssid = line.replace("ssid=", "");
  
  						// Network Keys:
  					} else if (line.startsWith("psk=")) {
  						passKeys.put("psk", line.replace("psk=", ""));
  						password = line.replace("psk=", "");
  						type = NetInfo.TYPE_WPA;
  					} else if (line.startsWith("wep_key0=")) {
  						passKeys.put("WEP Key 0", line.replace("wep_key0=", ""));
  						password = line.replace("psk=", "");
  						type = NetInfo.TYPE_WEP;
  					} else if (line.startsWith("wep_key1=")) {
  						passKeys.put("WEP Key 1", line.replace("wep_key1=", ""));
  					} else if (line.startsWith("wep_key2=")) {
  						passKeys.put("WEP Key 2", line.replace("wep_key2=", ""));
  					} else if (line.startsWith("wep_key3=")) {
  						passKeys.put("WEP Key 3", line.replace("wep_key3=", ""));
  					} else if (line.startsWith("password=")) {
  						passKeys.put("Password", line.replace("password=", ""));
  						password = line.replace("psk=", "");
  
  						// Settings:
  					} else if (line.startsWith("key_mgmt=")) {
  						settings.put("Key MGMT", line.replace("key_mgmt=", ""));
  					} else if (line.startsWith("group=")) {
  						settings.put("Group", line.replace("group=", ""));
  					} else if (line.startsWith("auth_alg=")) {
  						settings.put("Algorithm", line.replace("auth_alg=", ""));
  					} else if (line.startsWith("eap=")) {
  						settings.put("EAP", line.replace("eap=", ""));
  					} else if (line.startsWith("identity=")) {
  						settings.put("Identity", line.replace("identity=", ""));
  					} else if (line.startsWith("anonymous_identity=")) {
  						settings.put("Anonymous ID", line.replace("anonymous_identity=", ""));
  					} else if (line.startsWith("phase2=")) {
  						settings.put("Phase2 Auth", line.replace("phase2=", ""));
  					}
  				}
  
  				String result = "";
  
  				if (!passKeys.isEmpty()) {
  					if (ssid.length() > 0) {
  						result += appendBlanks("SSID:", RESULT_TITLE_LENGTH) + ssid + "\n";
  					}
  
  					Iterator<Entry<String, String>> it = passKeys.entrySet().iterator();
  					while (it.hasNext()) {
  						Map.Entry<String, String> pairs = (Map.Entry<String, String>) it.next();
  						result += appendBlanks(pairs.getKey() + ":", RESULT_TITLE_LENGTH) + pairs.getValue() + "\n";
  					}
  
  					it = settings.entrySet().iterator();
  					while (it.hasNext()) {
  						Map.Entry<String, String> pairs = (Map.Entry<String, String>) it.next();
  						result += appendBlanks(pairs.getKey() + ":", RESULT_TITLE_LENGTH) + pairs.getValue() + "\n";
  					}
  
  				}
  				if (result.trim().length() > 0) {
  					NetInfo ni = new NetInfo(result.trim());
  					ni.setQrCodeInfo(ssid, password, type);
  					l.add(ni);
  				}
  			}
  		}
  		// l.add("Protected Networks: " + protectedNetworkCount);
  		return l;
  	}
  
  	public void run() {
  		mState = STATE_RUNNING;
  		Bundle b = new Bundle();
  		Message msg = new Message();
  
  		Log.d(TAG, "^ Thread: Thread Started");
  
  		while (mState == STATE_RUNNING) {
  			try {
  				Thread.sleep(100);
  				b.clear();
  
  				b.putParcelableArrayList("passwords", getWiFiPasswordList());
  
  				msg = new Message();
  				msg.what = WORK_COMPLETED;
  				msg.setData(b);
  				mHandler.sendMessage(msg);
  
  				this.setState(STATE_DONE);
  			} catch (InterruptedException e) {
  				Log.e(TAG, "^ Thread: Thread Interrupted");
  				b.clear();
  				int what = WORK_INTERUPTED;
  				msg.what = what;
  				msg.setData(b);
  				mHandler.sendMessage(msg);
  				this.setState(STATE_DONE);
  			} catch (Exception e) {
  				Log.e(TAG, "^ Thread: exception " + e.getMessage());
  				msg = new Message();
  				b.clear();
  				int what = WORK_INTERUPTED;
  				msg.what = what;
  				msg.setData(b);
  				mHandler.sendMessage(msg);
  				this.setState(STATE_DONE);
  			}
  		}
  		Log.d(TAG, "^ Thread: Thread Exited");
  	}
  
  	/*
  	 * sets the current state for the thread, used to stop the thread
  	 */
  	public void setState(int state) {
  		mState = state;
  	}
  	// //////////////////////////////////////////////////////////////////////////////////////////////////////
  }
  