[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r21761: {projects} added transproxy app chooser view (in projects/android/trunk/Orbot/src/org/torproject/android: . service)



Author: n8fr8
Date: 2010-02-27 23:56:46 +0000 (Sat, 27 Feb 2010)
New Revision: 21761

Added:
   projects/android/trunk/Orbot/src/org/torproject/android/TorifiedApp.java
   projects/android/trunk/Orbot/src/org/torproject/android/service/TorTransProxy.java
Removed:
   projects/android/trunk/Orbot/src/org/torproject/android/service/TorRoot.java
Modified:
   projects/android/trunk/Orbot/src/org/torproject/android/Orbot.java
   projects/android/trunk/Orbot/src/org/torproject/android/SettingsPreferences.java
   projects/android/trunk/Orbot/src/org/torproject/android/TorConstants.java
   projects/android/trunk/Orbot/src/org/torproject/android/service/TorService.java
   projects/android/trunk/Orbot/src/org/torproject/android/service/TorServiceConstants.java
   projects/android/trunk/Orbot/src/org/torproject/android/service/TorServiceUtils.java
Log:
added transproxy app chooser view

Modified: projects/android/trunk/Orbot/src/org/torproject/android/Orbot.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/Orbot.java	2010-02-27 01:21:22 UTC (rev 21760)
+++ projects/android/trunk/Orbot/src/org/torproject/android/Orbot.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -3,11 +3,14 @@
 
 package org.torproject.android;
 
+import java.util.Arrays;
+import java.util.Comparator;
 import java.util.StringTokenizer;
 
 import org.torproject.android.service.ITorService;
 import org.torproject.android.service.ITorServiceCallback;
-import org.torproject.android.service.TorRoot;
+import org.torproject.android.service.TorServiceUtils;
+import org.torproject.android.service.TorTransProxy;
 import org.torproject.android.service.TorServiceConstants;
 
 import android.app.Activity;
@@ -32,12 +35,19 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
 import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
+import android.widget.CompoundButton.OnCheckedChangeListener;
 
-public class Orbot extends Activity implements OnClickListener, TorConstants
+public class Orbot extends Activity implements OnClickListener, TorConstants, OnCheckedChangeListener
 {
 	
 	/* Useful UI bits */
@@ -45,18 +55,17 @@
 	private TextView lblStatus = null; //the main text display widget
 	private ImageView imgStatus = null; //the main touchable image for activating Orbot
 	private ProgressDialog progressDialog;
+	private ListView listApps;
+	private boolean showingSettings = false;
 	
 	/* Some tracking bits */
-	private int torStatus = STATUS_REQUIRES_DEMAND; //latest status reported from the tor service
+	private int torStatus = STATUS_READY; //latest status reported from the tor service
 	private int currentView = 0; //the currently displayed UI view
 	private StringBuffer logBuffer = new StringBuffer(); //the output of the service log messages
-	private String lastUrl = null;
 	
 	/* Tor Service interaction */
 		/* The primary interface we will be calling on the service. */
     ITorService mService = null;
-
-    
 	
     /** Called when the activity is first created. */
     @Override
@@ -83,15 +92,22 @@
 
         mItem = menu.add(0, 2, Menu.NONE, getString(R.string.menu_browse));
         mItem.setIcon(R.drawable.ic_menu_goto);
+
+        mItem = menu.add(0, 3, Menu.NONE, getString(R.string.menu_info));
+        mItem.setIcon(R.drawable.ic_menu_about);
         
-        mItem = menu.add(0, 3, Menu.NONE, getString(R.string.menu_settings));
+        mItem = menu.add(0, 4, Menu.NONE, getString(R.string.menu_settings));
         mItem.setIcon(R.drawable.ic_menu_register);
+       
+        mItem = menu.add(0, 5, Menu.NONE, getString(R.string.menu_apps));
+        mItem.setIcon(R.drawable.ic_menu_register);
+
+        if (!TorServiceUtils.hasRoot())
+        	mItem.setEnabled(false);
         
-        mItem =  menu.add(0, 4, Menu.NONE, getString(R.string.menu_log));
+        mItem =  menu.add(0,6, Menu.NONE, getString(R.string.menu_log));
         mItem.setIcon(R.drawable.ic_menu_reports);
 
-        mItem = menu.add(0, 5, Menu.NONE, getString(R.string.menu_info));
-        mItem.setIcon(R.drawable.ic_menu_about);
       
         return true;
     }
@@ -109,11 +125,11 @@
 		{
 			this.showMain();
 		}
-		else if (item.getItemId() == 3)
+		else if (item.getItemId() == 4)
 		{
 			this.showSettings();
 		}
-		else if (item.getItemId() == 4)
+		else if (item.getItemId() == 6)
 		{
 			this.showMessageLog();
 		}
@@ -121,10 +137,14 @@
 		{
 			openBrowser(URL_TOR_CHECK);
 		}
-		else if (item.getItemId() == 5)
+		else if (item.getItemId() == 3)
 		{
 			showHelp();
 		}
+		else if (item.getItemId() == 5)
+		{
+			showApps();
+		}
 		
         return true;
 	}
@@ -158,11 +178,9 @@
 	protected void onPause() {
 		super.onPause();
 		
+
 	}
 
-
-
-
 	/* (non-Javadoc)
 	 * @see android.app.Activity#onResume()
 	 */
@@ -171,6 +189,17 @@
 		super.onResume();
 		
 		updateStatus (""); //update the status, which checks the service status
+		
+		if (showingSettings)
+		{
+			
+			showingSettings = false;
+			processSettings();
+		
+		}
+		
+		
+		
 	}
 
 	/* (non-Javadoc)
@@ -198,6 +227,8 @@
 	protected void onStop() {
 		super.onStop();
 		
+		TorServiceUtils.saveAppSettings(this);
+		
 		unbindService();
 	}
 
@@ -210,6 +241,24 @@
     {
 		bindService(); //connect the UI activity to the remote service
 		
+		if (currentView == R.layout.layout_apps)
+		{
+			if (hasRoot)
+			{
+				
+				TorServiceUtils.saveAppSettings(this);
+				
+				if (enableTransparentProxy)
+				{
+					TorTransProxy.purgeNatIptables();
+					TorTransProxy.setDNSProxying();
+					TorTransProxy.setTransparentProxying(this, TorServiceUtils.getApps(this));
+				}
+				
+				
+			}
+		}
+		
 		currentView = R.layout.layout_main;
 		setContentView(currentView);
 		
@@ -232,6 +281,67 @@
 		
 	}
 	
+	private void loadApps ()
+	{
+        final TorifiedApp[] apps = TorServiceUtils.getApps(this);
+        
+        Arrays.sort(apps, new Comparator<TorifiedApp>() {
+			@Override
+			public int compare(TorifiedApp o1, TorifiedApp o2) {
+				if (o1.isTorified() == o2.isTorified()) return o1.getName().compareTo(o2.getName());
+				if (o1.isTorified()) return -1;
+				return 1;
+			}
+        });
+        
+        final LayoutInflater inflater = getLayoutInflater();
+		
+        final ListAdapter adapter = new ArrayAdapter<TorifiedApp>(this,R.layout.layout_apps_item,R.id.itemtext,apps) {
+        	@Override
+        	public View getView(int position, View convertView, ViewGroup parent) {
+       			ListEntry entry;
+        		if (convertView == null) {
+        			// Inflate a new view
+        			convertView = inflater.inflate(R.layout.layout_apps_item, parent, false);
+       				entry = new ListEntry();
+       				entry.box = (CheckBox) convertView.findViewById(R.id.itemcheck);
+       				entry.text = (TextView) convertView.findViewById(R.id.itemtext);
+       				convertView.setTag(entry);
+       				entry.box.setOnCheckedChangeListener(Orbot.this);
+        		} else {
+        			// Convert an existing view
+        			entry = (ListEntry) convertView.getTag();
+        		}
+        		final TorifiedApp app = apps[position];
+        		entry.text.setText(app.getName());
+        		final CheckBox box = entry.box;
+        		box.setTag(app);
+        		box.setChecked(app.isTorified());
+       			return convertView;
+        	}
+        };
+        this.listApps.setAdapter(adapter);
+		   
+	}
+	
+	/**
+	 * Called an application is check/unchecked
+	 */
+	@Override
+	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+		final TorifiedApp app = (TorifiedApp) buttonView.getTag();
+		if (app != null) {
+			app.setTorified(isChecked);
+		}
+		
+		TorServiceUtils.saveAppSettings(this);
+
+	}
+	
+	private static class ListEntry {
+		private CheckBox box;
+		private TextView text;
+	}
 	/*
 	 * Show the about view - a popup dialog
 	 */
@@ -285,7 +395,16 @@
         .show();
 	}
 	
+	private void showApps ()
+	{
+		currentView = R.layout.layout_apps;
+		setContentView(currentView);
 	
+		listApps = (ListView)findViewById(R.id.applistview);
+		
+		loadApps();
+		
+	}
 	/*
 	 * Show the message log UI
 	 */
@@ -308,6 +427,7 @@
 	private void showSettings ()
 	{
 		
+		showingSettings = true;
 		startActivity(new Intent(this, SettingsPreferences.class));
 
 		
@@ -331,6 +451,19 @@
 		
 		enableTransparentProxy = prefs.getBoolean(PREF_TRANSPARENT, false);
 		
+		if (hasRoot)
+		{
+			if (enableTransparentProxy)
+			{
+				TorTransProxy.setDNSProxying();
+				TorTransProxy.setTransparentProxying(this, TorServiceUtils.getApps(this));
+			}
+			else
+			{
+				TorTransProxy.purgeNatIptables();
+			}
+			
+		}
 		String bridgeList = prefs.getString(PREF_BRIDGES_LIST,"");
 
 		if (useBridges)
@@ -436,7 +569,7 @@
 	    			}
 		    			
 		    	}
-		    	else if (torStatus == STATUS_UNAVAILABLE)
+		    	else if (torStatus == STATUS_OFF)
 		    	{
 		    		imgStatus.setImageResource(R.drawable.torstopping);
 		    		lblStatus.setText(getString(R.string.status_shutting_down));
@@ -493,15 +626,16 @@
 				{
 				
 				}
-				else if (mService.getStatus() == STATUS_REQUIRES_DEMAND)
+				else if (mService.getStatus() == STATUS_READY)
 				{
 					processSettings();
 					mService.setProfile(PROFILE_ON);
 
 					if (hasRoot && enableTransparentProxy)
 					{
-						TorRoot.enableDNSProxying();
-						TorRoot.enabledWebProxying();
+						
+						TorTransProxy.setDNSProxying();
+						TorTransProxy.setTransparentProxying(this,TorServiceUtils.getApps(this));
 					}
 				}
 				else
@@ -511,7 +645,9 @@
 				
 					if (hasRoot && enableTransparentProxy)
 					{
-						TorRoot.purgeNatIptables();
+						TorTransProxy.purgeNatIptables();
+						//TorRoot.setDNSProxying(false);
+						//TorRoot.setTransparentProxying(this,false);
 					}
 				}
 			}
@@ -617,7 +753,7 @@
     	 
     	 mIsBound = true;
     
-    	 hasRoot = TorRoot.hasRootAccess();
+    	 hasRoot = TorTransProxy.hasRootAccess();
 
     	
     }

Modified: projects/android/trunk/Orbot/src/org/torproject/android/SettingsPreferences.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/SettingsPreferences.java	2010-02-27 01:21:22 UTC (rev 21760)
+++ projects/android/trunk/Orbot/src/org/torproject/android/SettingsPreferences.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -5,6 +5,7 @@
 
 import android.os.Bundle;
 import android.preference.PreferenceActivity;
+import android.util.Log;
 
 public class SettingsPreferences 
 		extends PreferenceActivity {
@@ -13,4 +14,15 @@
 		super.onCreate(savedInstanceState);
 		addPreferencesFromResource(R.xml.preferences);
 	}
+	
+	/* (non-Javadoc)
+	 * @see android.app.Activity#onStop()
+	 */
+	@Override
+	protected void onStop() {
+		super.onStop();
+		
+		Log.i(getClass().getName(),"Exiting Preferences");
+	}
+
 }

Modified: projects/android/trunk/Orbot/src/org/torproject/android/TorConstants.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/TorConstants.java	2010-02-27 01:21:22 UTC (rev 21760)
+++ projects/android/trunk/Orbot/src/org/torproject/android/TorConstants.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -12,8 +12,8 @@
 	//path to check Tor against
 	public final static String URL_TOR_CHECK = "https://check.torproject.org";;
 	
-    public final static int STATUS_UNAVAILABLE = -1;
-    public final static int STATUS_REQUIRES_DEMAND = 0;
+    public final static int STATUS_OFF = -1;
+    public final static int STATUS_READY = 0;
     public final static int STATUS_ON = 1;
     public final static int STATUS_CONNECTING = 2;
     

Added: projects/android/trunk/Orbot/src/org/torproject/android/TorifiedApp.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/TorifiedApp.java	                        (rev 0)
+++ projects/android/trunk/Orbot/src/org/torproject/android/TorifiedApp.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -0,0 +1,100 @@
+package org.torproject.android;
+
+public class TorifiedApp {
+
+	private boolean enabled;
+	private int uid;
+	private String username;
+	private String procname;
+	private String name;
+	
+	private boolean torified = false;
+	
+	/**
+	 * @return the torified
+	 */
+	public boolean isTorified() {
+		return torified;
+	}
+	/**
+	 * @param torified the torified to set
+	 */
+	public void setTorified(boolean torified) {
+		this.torified = torified;
+	}
+	private int[] enabledPorts;
+	
+	/**
+	 * @return the enabledPorts
+	 */
+	public int[] getEnabledPorts() {
+		return enabledPorts;
+	}
+	/**
+	 * @param enabledPorts the enabledPorts to set
+	 */
+	public void setEnabledPorts(int[] enabledPorts) {
+		this.enabledPorts = enabledPorts;
+	}
+	/**
+	 * @return the enabled
+	 */
+	public boolean isEnabled() {
+		return enabled;
+	}
+	/**
+	 * @param enabled the enabled to set
+	 */
+	public void setEnabled(boolean enabled) {
+		this.enabled = enabled;
+	}
+	/**
+	 * @return the uid
+	 */
+	public int getUid() {
+		return uid;
+	}
+	/**
+	 * @param uid the uid to set
+	 */
+	public void setUid(int uid) {
+		this.uid = uid;
+	}
+	/**
+	 * @return the username
+	 */
+	public String getUsername() {
+		return username;
+	}
+	/**
+	 * @param username the username to set
+	 */
+	public void setUsername(String username) {
+		this.username = username;
+	}
+	/**
+	 * @return the procname
+	 */
+	public String getProcname() {
+		return procname;
+	}
+	/**
+	 * @param procname the procname to set
+	 */
+	public void setProcname(String procname) {
+		this.procname = procname;
+	}
+	/**
+	 * @return the name
+	 */
+	public String getName() {
+		return name;
+	}
+	/**
+	 * @param name the name to set
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+}

Deleted: projects/android/trunk/Orbot/src/org/torproject/android/service/TorRoot.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/service/TorRoot.java	2010-02-27 01:21:22 UTC (rev 21760)
+++ projects/android/trunk/Orbot/src/org/torproject/android/service/TorRoot.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -1,259 +0,0 @@
-/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
-/* See LICENSE for licensing information */
-package org.torproject.android.service;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.util.Iterator;
-import java.util.List;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.util.Log;
-
-/**
- * Contains shared programming interfaces.
- * All iptables "communication" is handled by this class.
- */
-public final class TorRoot {
-	private final static String TAG = "TOR_ROOT";
-	
-	// Do we have root access?
-	private static boolean hasroot = false;
-
-	private final static String CMD_NAT_FLUSH = "iptables -t nat -F || exit\n";
-	private final static String CMD_NAT_IPTABLES_80 = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to 127.0.0.1:8118 || exit\n";
-	private final static String CMD_NAT_IPTABLES_443 = "iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to 127.0.0.1:9040 || exit\n";
-
-	private final static String CMD_DNS_PROXYING = "iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to 127.0.0.1:5400 || exit\n";
-	
-	public static boolean enableDNSProxying ()
-	{
-		
-    	final StringBuilder script = new StringBuilder();
-    	int code;
-    	
-    	//Enable UDP Proxying
-    	script.append(CMD_DNS_PROXYING);
-		StringBuilder res = new StringBuilder();
-		
-		try
-		{
-			code = runScriptAsRoot(script.toString(), res);
-			
-			if (code != 0)
-			{
-				Log.w(TAG, "error apply DNS proxying: " + res.toString());
-
-			}
-		} catch (Exception e) {
-			Log.w(TAG, "error apply DNS proxying: " + res.toString(), e);
-			return false;
-		}
-		
-		return true;
-	}
-	
-	/**
-     * Purge and re-add all rules (internal implementation).
-     * @param ctx application context (mandatory)
-     * @param uids list of selected uids to allow or disallow (depending on the working mode)
-     * @param showErrors indicates if errors should be alerted
-     */
-	public static boolean enabledWebProxying() {
-		
-    	final StringBuilder script = new StringBuilder();
-		try {
-			int code;
-			
-			script.append(CMD_NAT_IPTABLES_80);
-			script.append(CMD_NAT_IPTABLES_443);
-			/*
-			int uid = android.os.Process.getUidForName("dhcp");
-			if (uid != -1) script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j ACCEPT || exit\n");
-			uid = android.os.Process.getUidForName("wifi");
-			if (uid != -1) script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j ACCEPT || exit\n");
-			*/
-			
-	    	StringBuilder res = new StringBuilder();
-			code = runScriptAsRoot(script.toString(), res);
-			
-				String msg = res.toString();
-				Log.e(TAG, msg);
-			
-		} catch (Exception e) {
-			Log.w(TAG, "error refreshing iptables: " + e);
-		}
-		return false;
-    }
-   
-   
-    /**
-     * Purge all iptables rules.
-     * @return true if the rules were purged
-     */
-	public static boolean purgeNatIptables() {
-    	StringBuilder res = new StringBuilder();
-		try {
-			int code = runScriptAsRoot(CMD_NAT_FLUSH, res);
-			if (code != 0) {
-				Log.w(TAG, "error purging iptables. exit code: " + code + "\n" + res);
-				return false;
-			}
-			return true;
-		} catch (Exception e) {
-			Log.w(TAG,"error purging iptables: " + e);
-			return false;
-		}
-    }
-	
-  
-	/**
-	 * Check if we have root access
-	 * @return boolean true if we have root
-	 */
-	public static boolean hasRootAccess() {
-		if (hasroot) return true;
-		try {
-			// Run an empty script just to check root access
-			if (runScriptAsRoot("exit 0", null, 20000) == 0) {
-				hasroot = true;
-				return true;
-			}
-		} catch (Exception e) {
-		}
-		Log.w(TAG, "Could not acquire root access.");
-		return false;
-	}
-	
-    /**
-     * Runs a script as root (multiple commands separated by "\n").
-     * 
-     * @param script the script to be executed
-     * @param res the script output response (stdout + stderr)
-     * @param timeout timeout in milliseconds (-1 for none)
-     * @return the script exit code
-     */
-	public static int runScriptAsRoot(String script, StringBuilder res, final long timeout) {
-		Log.i(TAG,"executing script: " + script);
-		final ScriptRunner runner = new ScriptRunner(script, res);
-		runner.start();
-		try {
-			if (timeout > 0) {
-				runner.join(timeout);
-			} else {
-				runner.join();
-			}
-			if (runner.isAlive()) {
-				// Timed-out
-				runner.interrupt();
-				runner.destroy();
-				runner.join(50);
-			}
-		} catch (InterruptedException ex) {}
-		return runner.exitcode;
-    }
-	
-    /**
-     * Runs a script as root (multiple commands separated by "\n") with a default timeout of 5 seconds.
-     * 
-     * @param script the script to be executed
-     * @param res the script output response (stdout + stderr)
-     * @param timeout timeout in milliseconds (-1 for none)
-     * @return the script exit code
-     * @throws IOException on any error executing the script, or writing it to disk
-     */
-	public static int runScriptAsRoot(String script, StringBuilder res) throws IOException {
-		return runScriptAsRoot(script, res, 5000);
-	}
-	
-	/**
-	 * Internal thread used to execute scripts as root.
-	 */
-	private static final class ScriptRunner extends Thread {
-		private final String script;
-		private final StringBuilder res;
-		public int exitcode = -1;
-		private Process exec;
-		
-		/**
-		 * Creates a new script runner.
-		 * @param script script to run
-		 * @param res response output
-		 */
-		public ScriptRunner(String script, StringBuilder res) {
-			this.script = script;
-			this.res = res;
-		}
-		@Override
-		public void run() {
-			try {
-				// Create the "su" request to run the command
-				// note that this will create a shell that we must interact to (using stdin/stdout)
-				exec = Runtime.getRuntime().exec("su");
-				final OutputStreamWriter out = new OutputStreamWriter(exec.getOutputStream());
-				// Write the script to be executed
-				out.write(script);
-				// Ensure that the last character is an "enter"
-				if (!script.endsWith("\n")) out.write("\n");
-				out.flush();
-				// Terminate the "su" process
-				out.write("exit\n");
-				out.flush();
-				final char buf[] = new char[1024];
-				// Consume the "stdout"
-				InputStreamReader r = new InputStreamReader(exec.getInputStream());
-				int read=0;
-				while ((read=r.read(buf)) != -1) {
-					if (res != null) res.append(buf, 0, read);
-				}
-				// Consume the "stderr"
-				r = new InputStreamReader(exec.getErrorStream());
-				read=0;
-				while ((read=r.read(buf)) != -1) {
-					if (res != null) res.append(buf, 0, read);
-				}
-				// get the process exit code
-				if (exec != null) this.exitcode = exec.waitFor();
-			} catch (InterruptedException ex) {
-				if (res != null) res.append("\nOperation timed-out");
-			} catch (Exception ex) {
-				if (res != null) res.append("\n" + ex);
-			} finally {
-				destroy();
-			}
-		}
-		/**
-		 * Destroy this script runner
-		 */
-		public synchronized void destroy() {
-			if (exec != null) exec.destroy();
-			exec = null;
-		}
-	}
-	
-	public void getApps (Context context)
-	{
-		PackageManager pMgr = context.getPackageManager();
-		
-		List<ApplicationInfo> lAppInfo = pMgr.getInstalledApplications(0);
-		
-		Iterator<ApplicationInfo> itAppInfo = lAppInfo.iterator();
-		
-		ApplicationInfo aInfo = null;
-		
-		while (itAppInfo.hasNext())
-		{
-			aInfo = itAppInfo.next();
-			
-			boolean appEnabled = aInfo.enabled;
-			int uid = aInfo.uid; //-m owner --uid-owner 
-			String username = pMgr.getNameForUid(uid);
-			String procName = aInfo.processName;
-			String name = aInfo.name;
-			
-		}
-	}
-}

Modified: projects/android/trunk/Orbot/src/org/torproject/android/service/TorService.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/service/TorService.java	2010-02-27 01:21:22 UTC (rev 21760)
+++ projects/android/trunk/Orbot/src/org/torproject/android/service/TorService.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -32,7 +32,7 @@
 	
 	
 	
-	private static int currentStatus = STATUS_REQUIRES_DEMAND;
+	private static int currentStatus = STATUS_READY;
 		
 	private TorControlConnection conn = null;
 	
@@ -80,12 +80,12 @@
  						
 			} catch (RuntimeException e) {
 				Log.i(TAG,"Unable to connect to existing Tor instance,",e);
-				currentStatus = STATUS_REQUIRES_DEMAND;
+				currentStatus = STATUS_OFF;
 				this.stopTor();
 				
 			} catch (Exception e) {
 				Log.i(TAG,"Unable to connect to existing Tor instance,",e);
-				currentStatus = STATUS_REQUIRES_DEMAND;
+				currentStatus = STATUS_OFF;
 				this.stopTor();
 				
 			}
@@ -203,7 +203,7 @@
 	     }
 	     catch (Exception e)
 	     {
-	    	 currentStatus = STATUS_REQUIRES_DEMAND;
+	    	 currentStatus = STATUS_OFF;
 	    	 this.showToolbarNotification("Orbot", "Unable to start Tor", R.drawable.tornotification);
 	    	 Log.i(TAG,"Unable to start Tor: " + e.getMessage(),e);
 	     }
@@ -226,14 +226,14 @@
     
     private void stopTor ()
     {
-    	currentStatus = STATUS_UNAVAILABLE;
+    	currentStatus = STATUS_OFF;
     	
     		
     	sendCallbackMessage("Web proxy shutdown");
     	
 		killTorProcess ();
 				
-		currentStatus = STATUS_REQUIRES_DEMAND;
+		currentStatus = STATUS_READY;
     	
 		showToolbarNotification ("Orbot","Anonymous browsing is disabled",R.drawable.tornotificationoff);
     	sendCallbackMessage("Anonymous browsing is disabled");
@@ -591,7 +591,7 @@
 			}
 			else
 			{
-				currentStatus = STATUS_UNAVAILABLE;
+				currentStatus = STATUS_OFF;
 	            sendCallbackMessage ("shutting down...");
 	            
 				_torInstance.stopTor();

Modified: projects/android/trunk/Orbot/src/org/torproject/android/service/TorServiceConstants.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/service/TorServiceConstants.java	2010-02-27 01:21:22 UTC (rev 21760)
+++ projects/android/trunk/Orbot/src/org/torproject/android/service/TorServiceConstants.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -76,12 +76,11 @@
     //control port 
     public final static String TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE = "Bootstrapped 100%";
     
-    public final static int STATUS_UNAVAILABLE = -1;
-    public final static int STATUS_REQUIRES_DEMAND = 0;
+    public final static int STATUS_OFF = -1;
+    public final static int STATUS_READY = 0;
     public final static int STATUS_ON = 1;
     public final static int STATUS_CONNECTING = 2;
     
     public final static int PROFILE_OFF = -1;
-    public final static int PROFILE_ONDEMAND = 0;
     public final static int PROFILE_ON = 1;
 }

Modified: projects/android/trunk/Orbot/src/org/torproject/android/service/TorServiceUtils.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/service/TorServiceUtils.java	2010-02-27 01:21:22 UTC (rev 21760)
+++ projects/android/trunk/Orbot/src/org/torproject/android/service/TorServiceUtils.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -5,13 +5,110 @@
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
 import java.util.StringTokenizer;
 
+import org.torproject.android.TorifiedApp;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.util.Log;
 
 public class TorServiceUtils implements TorServiceConstants {
 
+	private static TorifiedApp[] apps = null;
 	
+	private final static String PREFS_KEY = "OrbotPrefs";
+	private final static String PREFS_KEY_TORIFIED = "PrefTord";
+	
+	public static void saveAppSettings (Context context)
+	{
+		if (apps == null)
+			return;
+		
+		final SharedPreferences prefs = context.getSharedPreferences(PREFS_KEY, 0);
+
+		StringBuilder tordApps = new StringBuilder();
+		
+		for (int i = 0; i < apps.length; i++)
+		{
+			if (apps[i].isTorified())
+			{
+				tordApps.append(apps[i].getUsername());
+				tordApps.append("|");
+			}
+		}
+		
+		Editor edit = prefs.edit();
+		edit.putString(PREFS_KEY_TORIFIED, tordApps.toString());
+		edit.commit();
+		
+	}
+	
+	public static TorifiedApp[] getApps (Context context)
+	{
+		if (apps != null)
+			return apps;
+	
+		final SharedPreferences prefs = context.getSharedPreferences(PREFS_KEY, 0);
+
+		String tordAppString = prefs.getString(PREFS_KEY_TORIFIED, "");
+		String[] tordApps;
+		
+		StringTokenizer st = new StringTokenizer(tordAppString,"|");
+		tordApps = new String[st.countTokens()];
+		int tordIdx = 0;
+		while (st.hasMoreTokens())
+		{
+			tordApps[tordIdx++] = st.nextToken();
+		}
+		
+		Arrays.sort(tordApps);
+		
+		//else load the apps up
+		PackageManager pMgr = context.getPackageManager();
+		
+		List<ApplicationInfo> lAppInfo = pMgr.getInstalledApplications(0);
+		
+		Iterator<ApplicationInfo> itAppInfo = lAppInfo.iterator();
+		
+		apps = new TorifiedApp[lAppInfo.size()];
+		
+		ApplicationInfo aInfo = null;
+		
+		int appIdx = 0;
+		
+		while (itAppInfo.hasNext())
+		{
+			aInfo = itAppInfo.next();
+			apps[appIdx] = new TorifiedApp();
+			
+			apps[appIdx].setEnabled(aInfo.enabled);
+			apps[appIdx].setUid(aInfo.uid);
+			apps[appIdx].setUsername(pMgr.getNameForUid(apps[appIdx].getUid()));
+			apps[appIdx].setProcname(aInfo.processName);
+			apps[appIdx].setName(pMgr.getApplicationLabel(aInfo).toString());
+			
+			// check if this application is allowed
+			if (Arrays.binarySearch(tordApps, apps[appIdx].getUsername()) >= 0) {
+				apps[appIdx].setTorified(true);
+			}
+			else
+			{
+				apps[appIdx].setTorified(false);
+			}
+			
+			appIdx++;
+		}
+		
+		return apps;
+	}
+	
 	public static int findProcessId(String command) 
 	{
 		int procId = -1;
@@ -104,18 +201,17 @@
 	{
 		Log.i(TAG,"executing commands: " + cmds.length);
 		
-		Runtime runtime = Runtime.getRuntime();
-		    	
+		 	
 		Process proc = null;
 		int exitCode = -1;
 		
         try {
             
-        	proc = runtime.exec(cmds[0]);
-
+        	proc = Runtime.getRuntime().exec("su");
+			
             OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream());
             
-            for (int i = 1; i < cmds.length; i++)
+            for (int i = 0; i < cmds.length; i++)
             {
             	out.write(cmds[i]);
             	out.write("\n");
@@ -123,7 +219,8 @@
             
             out.flush();
 			out.write("exit\n");
-			
+			out.flush();
+			/*
 			final char buf[] = new char[1024];
 			// Consume the "stdout"
 			InputStreamReader reader = new InputStreamReader(proc.getInputStream());
@@ -136,7 +233,7 @@
 			read=0;
 			while ((read=reader.read(buf)) != -1) {
 				if (log != null) log.append(buf, 0, read);
-			}
+			}*/
             
 			exitCode = proc.waitFor();
 			

Added: projects/android/trunk/Orbot/src/org/torproject/android/service/TorTransProxy.java
===================================================================
--- projects/android/trunk/Orbot/src/org/torproject/android/service/TorTransProxy.java	                        (rev 0)
+++ projects/android/trunk/Orbot/src/org/torproject/android/service/TorTransProxy.java	2010-02-27 23:56:46 UTC (rev 21761)
@@ -0,0 +1,124 @@
+package org.torproject.android.service;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.torproject.android.TorifiedApp;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+public class TorTransProxy {
+	
+	private final static String TAG = "TorTransProxy";
+	
+	private final static String CMD_NAT_FLUSH = "iptables -t nat -F || exit\n";
+//	private final static String CMD_NAT_IPTABLES_ALL = "iptables -t nat -A OUTPUT -j DNAT --to 127.0.0.1:9040 || exit\n";
+	
+	private final static String CMD_DNS_PROXYING_ADD = "iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to 127.0.0.1:5400 || exit\n";
+	private final static String CMD_DNS_PROXYING_DELETE = "iptables -t nat -D PREROUTING -p udp --dport 53 -j DNAT --to 127.0.0.1:5400 || exit\n";
+
+	private final static String IPTABLES_ADD = " -A ";
+	private final static String IPTABLES_DELETE = " -D ";
+
+	private static boolean hasRoot = false;
+	
+	/**
+	 * Check if we have root access
+	 * @return boolean true if we have root
+	 */
+	public static boolean hasRootAccess() {
+		if (hasRoot) return true;
+		try {
+			// Run an empty script just to check root access
+			String[] cmd = {"exit 0"};
+			if (TorServiceUtils.doRootCommand(cmd, null) == 0) {
+				hasRoot = true;
+				return true;
+			}
+		} catch (Exception e) {
+		}
+		Log.w(TAG, "Could not acquire root access.");
+		return false;
+	}
+	
+	public static int setDNSProxying ()
+	{
+		
+    	final StringBuilder log = new StringBuilder();
+    	int code;
+    	
+    	String[] cmds = {CMD_DNS_PROXYING_ADD};
+    	
+    
+    	code = TorServiceUtils.doRootCommand(cmds, log);
+    	
+    	return code;
+    	
+    	
+	}
+	
+	public static boolean purgeNatIptables() {
+    	StringBuilder res = new StringBuilder();
+		try {
+			String[] cmds = {CMD_NAT_FLUSH};
+			int code = TorServiceUtils.doRootCommand(cmds, res);
+			if (code != 0) {
+				Log.w(TAG, "error purging iptables. exit code: " + code + "\n" + res);
+				return false;
+			}
+			return true;
+		} catch (Exception e) {
+			Log.w(TAG,"error purging iptables: " + e);
+			return false;
+		}
+    }
+	
+	public static boolean setTransparentProxying(Context context, TorifiedApp[] apps) {
+		
+		String command = null;
+		
+		command = IPTABLES_ADD; //ADD
+		
+    	final StringBuilder script = new StringBuilder();
+    	
+		try {
+			int code;
+			
+			for (int i = 0; i < apps.length; i++)
+			{
+				
+				if (apps[i].getUsername().startsWith("org.torproject.android")) //we never want to Tor this!
+					continue;
+				
+				if (apps[i].isTorified())
+				{
+					Log.i(TAG,"enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")");
+				 
+					script.append("iptables -t nat");
+					script.append(command);
+					script.append("OUTPUT -p tcp -m owner --uid-owner ");
+					script.append(apps[i].getUid());
+					script.append(" -j DNAT --to 127.0.0.1:9040");
+					script.append(" || exit\n");
+				}		
+			}
+			
+	    	StringBuilder res = new StringBuilder();
+	    	
+	    	String[] cmd = {script.toString()};
+	    	
+			code = TorServiceUtils.doRootCommand(cmd, res);
+			
+				String msg = res.toString();
+				Log.e(TAG, msg);
+			
+		} catch (Exception e) {
+			Log.w(TAG, "error refreshing iptables: " + e);
+		}
+		return false;
+    }	
+
+}