migrating Orbot codebase from old repo and updating to 0.0.3a
svn:r21593
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
	<classpathentry kind="src" path="src"/>
 | 
			
		||||
	<classpathentry kind="src" path="gen"/>
 | 
			
		||||
	<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
 | 
			
		||||
	<classpathentry kind="lib" path="libs/jsocks.jar"/>
 | 
			
		||||
	<classpathentry combineaccessrules="false" kind="src" path="/jtorctrl"/>
 | 
			
		||||
	<classpathentry kind="lib" path="libs/asocks.jar"/>
 | 
			
		||||
	<classpathentry kind="output" path="bin"/>
 | 
			
		||||
</classpath>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,26 +1,42 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
      package="org.torproject.android"
 | 
			
		||||
      android:versionCode="1"
 | 
			
		||||
      android:versionName="1.0">
 | 
			
		||||
        <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
        <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 | 
			
		||||
      android:versionName="011301.2" android:versionCode="2">
 | 
			
		||||
       
 | 
			
		||||
       <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
 <uses-permission android:name="android.permission.WRITE_SETTINGS" />
 | 
			
		||||
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 | 
			
		||||
 
 | 
			
		||||
    <application android:icon="@drawable/icon" android:label="@string/app_name"
 | 
			
		||||
    	android:debuggable="false">
 | 
			
		||||
        <activity android:name=".TorControlPanel"
 | 
			
		||||
    <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="false">
 | 
			
		||||
        <activity android:name=".Orbot"
 | 
			
		||||
                  android:label="@string/app_name">
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="android.intent.action.MAIN" />
 | 
			
		||||
                <category android:name="android.intent.category.LAUNCHER" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
          </intent-filter>
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
            <action android:name="android.intent.action.VIEW" />
 | 
			
		||||
            <category android:name="android.intent.category.DEFAULT" />
 | 
			
		||||
            <category android:name="android.intent.category.BROWSABLE" />
 | 
			
		||||
        </intent-filter>
 | 
			
		||||
        </activity>
 | 
			
		||||
        <activity android:name=".SettingsPreferences"  android:label="@string/app_name">
 | 
			
		||||
        </activity>
 | 
			
		||||
           
 | 
			
		||||
           
 | 
			
		||||
           
 | 
			
		||||
           <service android:name=".TorService" android:enabled="true" android:exported="true"/>
 | 
			
		||||
 | 
			
		||||
    	<service android:name=".service.TorService" android:process=":remote">
 | 
			
		||||
	            <intent-filter>
 | 
			
		||||
	                <action android:name="org.torproject.android.service.ITorService" />
 | 
			
		||||
	              	<action android:name="org.torproject.android.service.TOR_SERVICE" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
    	</service>
 | 
			
		||||
    	
 | 
			
		||||
    	
 | 
			
		||||
    </application>
 | 
			
		||||
    <uses-sdk android:minSdkVersion="3"/>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</manifest> 
 | 
			
		||||
							
								
								
									
										24
									
								
								BUILD
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -7,7 +7,8 @@ Please install the following prerequisites (instructions for each follows):
 | 
			
		|||
	droid-wrapper: http://github.com/tmurakam/droid-wrapper
 | 
			
		||||
	libevent source (1.4.12-stable from svn)
 | 
			
		||||
	Tor source (most recent git master branch)
 | 
			
		||||
 | 
			
		||||
    Privoxy source (http://sourceforge.net/projects/ijbswa/)
 | 
			
		||||
    
 | 
			
		||||
Install and prepare the Android OS SDK ( http://source.android.com/download )
 | 
			
		||||
on Debian Lenny:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -42,14 +43,27 @@ Install droid-wrapper:
 | 
			
		|||
	sudo make install
 | 
			
		||||
 | 
			
		||||
zlib and OpenSSL are included with the Android OS SDK. You'll need to build
 | 
			
		||||
libevent and finally Tor. We'll create an externals directory for this code:
 | 
			
		||||
libevent, Privoxy and finally Tor. We'll create an externals directory for this code:
 | 
			
		||||
 | 
			
		||||
	mkdir -p ~/mydroid/external/{libevent,tor}
 | 
			
		||||
	mkdir -p ~/mydroid/external/{libevent,tor,privoxy}
 | 
			
		||||
 | 
			
		||||
We need to set to environment variables for droid-gcc:
 | 
			
		||||
	export DROID_ROOT=~/mydroid/
 | 
			
		||||
	export DROID_TARGET=generic
 | 
			
		||||
 | 
			
		||||
Fetch and build Privoxy:
 | 
			
		||||
	cd ~/mydroid/external/privoxy
 | 
			
		||||
	wget http://sourceforge.net/projects/ijbswa/files/Sources/3.0.12%20%28stable%29/privoxy-3.0.12-stable-src.tar.gz/download
 | 
			
		||||
	tar xzvf privoxy-3.0.12-stable-src.tar.gz
 | 
			
		||||
	cd privoxy-3.0.12-stable
 | 
			
		||||
	autoheader
 | 
			
		||||
	autoconf
 | 
			
		||||
	#need to disable setpgrp check in configure
 | 
			
		||||
	export ac_cv_func_setpgrp_void=yes 
 | 
			
		||||
	CC=droid-gcc LD=droid-ld ./configure --host=arm-none-linux-gnueabi
 | 
			
		||||
	#don't mind the "unrecognized option '-pthred'" error message that you'll see when you run make
 | 
			
		||||
	make 
 | 
			
		||||
	
 | 
			
		||||
Fetch and build libevent:
 | 
			
		||||
 | 
			
		||||
	cd ~/mydroid/external/libevent
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +76,6 @@ Fetch and build libevent:
 | 
			
		|||
	make
 | 
			
		||||
 | 
			
		||||
Copy over the libevent library:
 | 
			
		||||
 | 
			
		||||
	cp .libs/libevent.a ~/mydroid/out/target/product/generic/obj/lib
 | 
			
		||||
 | 
			
		||||
Fetch and build Tor:
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +84,7 @@ Fetch and build Tor:
 | 
			
		|||
	export ZLIBDIR=`cd ~/mydroid/external/zlib && pwd`
 | 
			
		||||
 | 
			
		||||
	cd ~/mydroid/external/tor
 | 
			
		||||
	git clone https://git.torproject.org/git/tor.git
 | 
			
		||||
	git clone git://git.torproject.org/git/tor.git
 | 
			
		||||
	cd tor/
 | 
			
		||||
	./autogen.sh
 | 
			
		||||
	CC=droid-gcc LD=droid-ld ./configure --host=arm-none-linux-gnueabi \
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +118,7 @@ Finally, we'll make a proper Android package with ant and the Android App SDK:
 | 
			
		|||
 | 
			
		||||
	export APP_SDK=~/Documents/projects/android/android-sdk-linux_x86-1.5_r3/tools
 | 
			
		||||
	cd ../Orbot/
 | 
			
		||||
	cp ~/mydroid/external/privoxy/privoxy-3.0.12-stable/privoxy assets/privoxy
 | 
			
		||||
	cp ~/mydroid/external/tor/tor/src/or/tor assets/tor
 | 
			
		||||
	$APP_SDK/android update project --name Orbot --target 1 --path .
 | 
			
		||||
	ant release
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,10 @@
 | 
			
		|||
0.0.3a - 2010-02-07
 | 
			
		||||
- Integrated iptables support for transparenty proxying of outbound port 80 and DNS
 | 
			
		||||
- Privoxy is now used as HTTP Proxy server (cross-compiled to ARM)
 | 
			
		||||
- New UI layout and graphics
 | 
			
		||||
- Android settings screen for generated torrc file
 | 
			
		||||
- Improved performance and error handling
 | 
			
		||||
 | 
			
		||||
0.0.2a - 2009-11-30
 | 
			
		||||
- Update user interace layout and graphics
 | 
			
		||||
- Modified service launch, shutdown and handling
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										174
									
								
								LICENSE
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -94,108 +94,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		|||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
===============================================================================
 | 
			
		||||
src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
 | 
			
		||||
under the following license:
 | 
			
		||||
 | 
			
		||||
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
			
		||||
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
			
		||||
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
			
		||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
 | 
			
		||||
under the following license:
 | 
			
		||||
 | 
			
		||||
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
			
		||||
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
			
		||||
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
			
		||||
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
			
		||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
 | 
			
		||||
under the following license:
 | 
			
		||||
 | 
			
		||||
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCD FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
			
		||||
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
			
		||||
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
			
		||||
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
 | 
			
		||||
under the following license:
 | 
			
		||||
 | 
			
		||||
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
			
		||||
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
			
		||||
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
			
		||||
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
			
		||||
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
 | 
			
		||||
under the following license:
 | 
			
		||||
| 
						 | 
				
			
			@ -230,79 +128,7 @@ If you got Tor as a static binary with OpenSSL included, then you should know:
 | 
			
		|||
 "This product includes software developed by the OpenSSL Project
 | 
			
		||||
 for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 | 
			
		||||
===============================================================================
 | 
			
		||||
"This program uses the IP-to-Country Database provided by
 | 
			
		||||
WebHosting.Info (http://www.webhosting.info), available from
 | 
			
		||||
http://ip-to-country.webhosting.info."
 | 
			
		||||
See the src/config/geoip file in particular.
 | 
			
		||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
 | 
			
		||||
under the following license:
 | 
			
		||||
 | 
			
		||||
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
			
		||||
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
			
		||||
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
			
		||||
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
			
		||||
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
===============================================================================
 | 
			
		||||
If you got Tor as a static binary with OpenSSL included, then you should know:
 | 
			
		||||
 "This product includes software developed by the OpenSSL Project
 | 
			
		||||
 for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 | 
			
		||||
===============================================================================
 | 
			
		||||
"This program uses the IP-to-Country Database provided by
 | 
			
		||||
WebHosting.Info (http://www.webhosting.info), available from
 | 
			
		||||
http://ip-to-country.webhosting.info."
 | 
			
		||||
See the src/config/geoip file in particular.
 | 
			
		||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
 | 
			
		||||
under the following license:
 | 
			
		||||
 | 
			
		||||
 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
			
		||||
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 | 
			
		||||
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
			
		||||
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
			
		||||
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
			
		||||
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
			
		||||
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
===============================================================================
 | 
			
		||||
If you got Tor as a static binary with OpenSSL included, then you should know:
 | 
			
		||||
 "This product includes software developed by the OpenSSL Project
 | 
			
		||||
 for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 | 
			
		||||
===============================================================================
 | 
			
		||||
"This program uses the IP-to-Country Database provided by
 | 
			
		||||
WebHosting.Info (http://www.webhosting.info), available from
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,48 +0,0 @@
 | 
			
		|||
 | 
			
		||||
<html>
 | 
			
		||||
  <head>
 | 
			
		||||
    <title>help.html</title>
 | 
			
		||||
	
 | 
			
		||||
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
 | 
			
		||||
    <meta http-equiv="description" content="this is my page">
 | 
			
		||||
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
 | 
			
		||||
    
 | 
			
		||||
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
 | 
			
		||||
<style>
 | 
			
		||||
body
 | 
			
		||||
{
 | 
			
		||||
background:black;
 | 
			
		||||
color:white;
 | 
			
		||||
font-family:arial;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a, a:link, a:visited
 | 
			
		||||
{
 | 
			
		||||
color:#00ff00;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
  </head>
 | 
			
		||||
  
 | 
			
		||||
  <body>
 | 
			
		||||
   <h2>ORbot</h2>
 | 
			
		||||
   <i>Onion Routing Robot - v0.0.2a / November 30, 2009</i><br/>
 | 
			
		||||
   <hr/>
 | 
			
		||||
   <h3>How to use ORbot</h3>
 | 
			
		||||
   Simply touch the Orbot icon on the main screen and wait for it to fully connect to the Tor network. You can use the Menu -> Log option to view 
 | 
			
		||||
   more detailed information about the attempt to connect to the network.
 | 
			
		||||
   <h3>How to surf anonymously</h3>
 | 
			
		||||
   Once you have Orbot running and connected to the Tor network, you can utilize the anonymous proxy service in multiple ways:
 | 
			
		||||
   <ul>
 | 
			
		||||
   <li>Set your Android APN Proxy (Settings -> Wireless Networks -> Mobile networks -> Access Point Names) to 127.0.0.1/8118</li>
 | 
			
		||||
   <li>Tell your application to use Web Proxy: 127.0.0.1:8118</li>
 | 
			
		||||
   <li>Download and use the 'Shadow' browser from the Android Market</li>
 | 
			
		||||
   </ul>
 | 
			
		||||
   You can always visit <a href="http://check.torproject.org">http://check.torproject.org</a> to ensure that you are properly connected to the Tor network.
 | 
			
		||||
  <h3>Bridges and Other Settings</h3>
 | 
			
		||||
  You can modify the TORRC settings file using the Menu -> Settings option. This is where you can copy and paste in Tor Bridge node addresses
 | 
			
		||||
  if they are needed in your local area.
 | 
			
		||||
  <h3>Even More Information!</h3>
 | 
			
		||||
  If you'd like to learn more about the Tor Project, please visit <a href="http://torproject.org">http://torproject.org</a>.
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
# Generally, this file goes in /etc/privoxy/config
 | 
			
		||||
#
 | 
			
		||||
# Tor listens as a SOCKS4a proxy here:
 | 
			
		||||
forward-socks4a / 127.0.0.1:9050 .
 | 
			
		||||
confdir /data/data/org.torproject.android
 | 
			
		||||
logdir /data/data/org.torproject.android
 | 
			
		||||
# actionsfile standard  # Internal purpose, recommended
 | 
			
		||||
#actionsfile default.action   # Main actions file
 | 
			
		||||
#actionsfile user.action      # User customizations
 | 
			
		||||
#filterfile default.filter
 | 
			
		||||
 | 
			
		||||
# Don't log interesting things, only startup messages, warnings and errors
 | 
			
		||||
#logfile logfile
 | 
			
		||||
#jarfile jarfile
 | 
			
		||||
#debug 1
 | 
			
		||||
#debug   0    # show each GET/POST/CONNECT request
 | 
			
		||||
#debug   4096 # Startup banner and warnings
 | 
			
		||||
#debug   8192 # Errors - *we highly recommended enabling this*
 | 
			
		||||
 | 
			
		||||
#user-manual /usr/share/doc/privoxy/user-manual
 | 
			
		||||
listen-address  127.0.0.1:8118
 | 
			
		||||
toggle  1
 | 
			
		||||
accept-intercepted-requests 1 
 | 
			
		||||
enable-remote-toggle 0
 | 
			
		||||
enable-edit-actions 0
 | 
			
		||||
enable-remote-http-toggle 0
 | 
			
		||||
buffer-limit 4096
 | 
			
		||||
							
								
								
									
										179
									
								
								assets/torrc
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -1,169 +1,16 @@
 | 
			
		|||
## Configuration file for a typical Tor user
 | 
			
		||||
## Last updated 16 July 2009 for Tor 0.2.2.1-alpha.
 | 
			
		||||
## (May or may not work for much older or much newer versions of Tor.)
 | 
			
		||||
##
 | 
			
		||||
## Lines that begin with "## " try to explain what's going on. Lines
 | 
			
		||||
## that begin with just "#" are disabled commands: you can enable them
 | 
			
		||||
## by removing the "#" symbol.
 | 
			
		||||
##
 | 
			
		||||
## See 'man tor', or https://www.torproject.org/tor-manual.html,
 | 
			
		||||
## for more options you can use in this file.
 | 
			
		||||
##
 | 
			
		||||
## Tor will look for this file in various places based on your platform:
 | 
			
		||||
## https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#torrc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Replace this with "SocksPort 0" if you plan to run Tor only as a
 | 
			
		||||
## relay, and not make any local application connections yourself.
 | 
			
		||||
SocksPort 9050 # what port to open for local application connections
 | 
			
		||||
SocksListenAddress 127.0.0.1 # accept connections only from localhost
 | 
			
		||||
SocksListenAddress 127.0.0.1:1080 # listen on this IP:port also
 | 
			
		||||
 | 
			
		||||
## Entry policies to allow/deny SOCKS requests based on IP address.
 | 
			
		||||
## First entry that matches wins. If no SocksPolicy is set, we accept
 | 
			
		||||
## all (and only) requests from SocksListenAddress.
 | 
			
		||||
#SocksPolicy accept 192.168.0.0/16
 | 
			
		||||
#SocksPolicy reject *
 | 
			
		||||
 | 
			
		||||
## Logs go to stdout at level "notice" unless redirected by something
 | 
			
		||||
## else, like one of the below lines. You can have as many Log lines as
 | 
			
		||||
## you want.
 | 
			
		||||
##
 | 
			
		||||
## We advise using "notice" in most cases, since anything more verbose
 | 
			
		||||
## may provide sensitive information to an attacker who obtains the logs.
 | 
			
		||||
##
 | 
			
		||||
## Send all messages of level 'notice' or higher to @LOCALSTATEDIR@/log/tor/notices.log
 | 
			
		||||
Log notice file /data/data/org.torproject.android/notices.log
 | 
			
		||||
## Send every possible message to @LOCALSTATEDIR@/log/tor/debug.log
 | 
			
		||||
#Log debug file /data/data/org.torproject.android/debug.log
 | 
			
		||||
## Use the system log instead of Tor's logfiles
 | 
			
		||||
#Log notice syslog
 | 
			
		||||
## To send all messages to stderr:
 | 
			
		||||
#Log debug stderr
 | 
			
		||||
 | 
			
		||||
## Uncomment this to start the process in the background... or use
 | 
			
		||||
## --runasdaemon 1 on the command line. This is ignored on Windows;
 | 
			
		||||
## see the FAQ entry if you want Tor to run as an NT service.
 | 
			
		||||
#RunAsDaemon 1
 | 
			
		||||
 | 
			
		||||
## The directory for keeping all the keys/etc. By default, we store
 | 
			
		||||
## things in $HOME/.tor on Unix, and in Application Data\tor on Windows.
 | 
			
		||||
SocksPort 9050
 | 
			
		||||
SocksListenAddress 127.0.0.1
 | 
			
		||||
SafeSocks 1
 | 
			
		||||
DNSPort 5400
 | 
			
		||||
Log notice stdout
 | 
			
		||||
Log debug syslog
 | 
			
		||||
DataDirectory /data/data/org.torproject.android/data
 | 
			
		||||
 | 
			
		||||
## The port on which Tor will listen for local connections from Tor
 | 
			
		||||
## controller applications, as documented in control-spec.txt.
 | 
			
		||||
ControlPort 9051
 | 
			
		||||
## If you enable the controlport, be sure to enable one of these
 | 
			
		||||
## authentication methods, to prevent attackers from accessing it.
 | 
			
		||||
#HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C
 | 
			
		||||
CookieAuthentication 1
 | 
			
		||||
 | 
			
		||||
############### This section is just for location-hidden services ###
 | 
			
		||||
 | 
			
		||||
## Once you have configured a hidden service, you can look at the
 | 
			
		||||
## contents of the file ".../hidden_service/hostname" for the address
 | 
			
		||||
## to tell people.
 | 
			
		||||
##
 | 
			
		||||
## HiddenServicePort x y:z says to redirect requests on port x to the
 | 
			
		||||
## address y:z.
 | 
			
		||||
 | 
			
		||||
#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/hidden_service/
 | 
			
		||||
#HiddenServicePort 80 127.0.0.1:80
 | 
			
		||||
 | 
			
		||||
#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/other_hidden_service/
 | 
			
		||||
#HiddenServicePort 80 127.0.0.1:80
 | 
			
		||||
#HiddenServicePort 22 127.0.0.1:22
 | 
			
		||||
 | 
			
		||||
################ This section is just for relays #####################
 | 
			
		||||
#
 | 
			
		||||
## See https://www.torproject.org/docs/tor-doc-relay for details.
 | 
			
		||||
 | 
			
		||||
## Required: what port to advertise for incoming Tor connections.
 | 
			
		||||
#ORPort 9001
 | 
			
		||||
## If you want to listen on a port other than the one advertised
 | 
			
		||||
## in ORPort (e.g. to advertise 443 but bind to 9090), uncomment the
 | 
			
		||||
## line below too. You'll need to do ipchains or other port forwarding
 | 
			
		||||
## yourself to make this work.
 | 
			
		||||
#ORListenAddress 0.0.0.0:9090
 | 
			
		||||
 | 
			
		||||
## A handle for your relay, so people don't have to refer to it by key.
 | 
			
		||||
#Nickname ididnteditheconfig
 | 
			
		||||
 | 
			
		||||
## The IP address or full DNS name for your relay. Leave commented out
 | 
			
		||||
## and Tor will guess.
 | 
			
		||||
#Address noname.example.com
 | 
			
		||||
 | 
			
		||||
## Define these to limit how much relayed traffic you will allow. Your
 | 
			
		||||
## own traffic is still unthrottled. Note that RelayBandwidthRate must
 | 
			
		||||
## be at least 20 KBytes.
 | 
			
		||||
#RelayBandwidthRate 100 KBytes  # Throttle traffic to 100KB/s (800Kbps)
 | 
			
		||||
#RelayBandwidthBurst 200 KBytes # But allow bursts up to 200KB/s (1600Kbps)
 | 
			
		||||
 | 
			
		||||
## Use these to restrict the maximum traffic per day, week, or month.
 | 
			
		||||
## Note that this threshold applies to sent _and_ to received bytes,
 | 
			
		||||
## not to their sum: Setting "4 GBytes" may allow up to 8 GBytes
 | 
			
		||||
## total before hibernating.
 | 
			
		||||
##
 | 
			
		||||
## Set a maximum of 4 gigabytes each way per period.
 | 
			
		||||
#AccountingMax 4 GBytes
 | 
			
		||||
## Each period starts daily at midnight (AccountingMax is per day)
 | 
			
		||||
#AccountingStart day 00:00
 | 
			
		||||
## Each period starts on the 3rd of the month at 15:00 (AccountingMax
 | 
			
		||||
## is per month)
 | 
			
		||||
#AccountingStart month 3 15:00
 | 
			
		||||
 | 
			
		||||
## Contact info to be published in the directory, so we can contact you
 | 
			
		||||
## if your relay is misconfigured or something else goes wrong. Google
 | 
			
		||||
## indexes this, so spammers might also collect it.
 | 
			
		||||
#ContactInfo Random Person <nobody AT example dot com>
 | 
			
		||||
## You might also include your PGP or GPG fingerprint if you have one:
 | 
			
		||||
#ContactInfo 1234D/FFFFFFFF Random Person <nobody AT example dot com>
 | 
			
		||||
 | 
			
		||||
## Uncomment this to mirror directory information for others. Please do
 | 
			
		||||
## if you have enough bandwidth.
 | 
			
		||||
#DirPort 9030 # what port to advertise for directory connections
 | 
			
		||||
## If you want to listen on a port other than the one advertised
 | 
			
		||||
## in DirPort (e.g. to advertise 80 but bind to 9091), uncomment the line
 | 
			
		||||
## below too. You'll need to do ipchains or other port forwarding yourself
 | 
			
		||||
## to make this work.
 | 
			
		||||
#DirListenAddress 0.0.0.0:9091
 | 
			
		||||
## Uncomment to return an arbitrary blob of html on your DirPort. Now you
 | 
			
		||||
## can explain what Tor is if anybody wonders why your IP address is
 | 
			
		||||
## contacting them. See contrib/tor-exit-notice.html for a sample.
 | 
			
		||||
#DirPortFrontPage /etc/tor/exit-notice.html
 | 
			
		||||
 | 
			
		||||
## Uncomment this if you run more than one Tor relay, and add the identity
 | 
			
		||||
## key fingerprint of each Tor relay you control, even if they're on
 | 
			
		||||
## different networks. You declare it here so Tor clients can avoid
 | 
			
		||||
## using more than one of your relays in a single circuit. See
 | 
			
		||||
## https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#MultipleServers
 | 
			
		||||
#MyFamily $keyid,$keyid,...
 | 
			
		||||
 | 
			
		||||
## A comma-separated list of exit policies. They're considered first
 | 
			
		||||
## to last, and the first match wins. If you want to _replace_
 | 
			
		||||
## the default exit policy, end this with either a reject *:* or an
 | 
			
		||||
## accept *:*. Otherwise, you're _augmenting_ (prepending to) the
 | 
			
		||||
## default exit policy. Leave commented to just use the default, which is
 | 
			
		||||
## described in the man page or at
 | 
			
		||||
## https://www.torproject.org/documentation.html
 | 
			
		||||
##
 | 
			
		||||
## Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses
 | 
			
		||||
## for issues you might encounter if you use the default exit policy.
 | 
			
		||||
##
 | 
			
		||||
## If certain IPs and ports are blocked externally, e.g. by your firewall,
 | 
			
		||||
## you should update your exit policy to reflect this -- otherwise Tor
 | 
			
		||||
## users will be told that those destinations are down.
 | 
			
		||||
##
 | 
			
		||||
#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports but no more
 | 
			
		||||
#ExitPolicy accept *:119 # accept nntp as well as default exit policy
 | 
			
		||||
#ExitPolicy reject *:* # no exits allowed
 | 
			
		||||
#
 | 
			
		||||
## Bridge relays (or "bridges") are Tor relays that aren't listed in the
 | 
			
		||||
## main directory. Since there is no complete public list of them, even if an
 | 
			
		||||
## ISP is filtering connections to all the known Tor relays, they probably
 | 
			
		||||
## won't be able to block all the bridges. Also, websites won't treat you
 | 
			
		||||
## differently because they won't know you're running Tor. If you can
 | 
			
		||||
## be a real relay, please do; but if not, be a bridge!
 | 
			
		||||
#BridgeRelay 1
 | 
			
		||||
#ExitPolicy reject *:*
 | 
			
		||||
 | 
			
		||||
RelayBandwidthRate 20 KBytes
 | 
			
		||||
RelayBandwidthBurst 20 KBytes
 | 
			
		||||
UseBridges 0
 | 
			
		||||
UpdateBridgesFromAuthority 1
 | 
			
		||||
bridge 74.82.1.191:19030
 | 
			
		||||
bridge 221.31.40.135:4430
 | 
			
		||||
bridge 24.110.168.130:443
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,8 +7,8 @@
 | 
			
		|||
# "build.properties", and override values to adapt the script to your
 | 
			
		||||
# project structure.
 | 
			
		||||
 | 
			
		||||
apk-configurations=
 | 
			
		||||
# Project target.
 | 
			
		||||
target=android-4
 | 
			
		||||
# Indicates whether an apk should be generated for each density.
 | 
			
		||||
split.density=false
 | 
			
		||||
# Project target.
 | 
			
		||||
target=android-4
 | 
			
		||||
apk-configurations=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 Before Width: | Height: | Size: 7.2 KiB  | 
| 
		 Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 10 KiB  | 
| 
		 Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 14 KiB  | 
| 
		 Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 25 KiB  | 
| 
		 Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 19 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,89 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:orientation="vertical"
 | 
			
		||||
    android:layout_width="fill_parent"
 | 
			
		||||
    android:layout_height="fill_parent">
 | 
			
		||||
	<ScrollView android:id="@+id/aboutscrollview" 
 | 
			
		||||
		android:orientation="vertical"
 | 
			
		||||
		android:layout_width="fill_parent" 
 | 
			
		||||
		android:layout_height="fill_parent">    
 | 
			
		||||
		<LinearLayout
 | 
			
		||||
		    android:orientation="vertical"
 | 
			
		||||
		    android:layout_width="fill_parent"
 | 
			
		||||
		    android:layout_height="fill_parent">
 | 
			
		||||
			<TextView android:text="Version: "
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:paddingTop="15px"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textStyle="bold"
 | 
			
		||||
				android:textColor="#ffffff" />
 | 
			
		||||
			<TextView android:text="- Unkown -"
 | 
			
		||||
				android:id="@+id/versionName"
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:paddingLeft="15px"		
 | 
			
		||||
				android:layout_gravity="center_vertical"
 | 
			
		||||
				android:textColor="#ffffff" />	
 | 
			
		||||
			<TextView android:text="Project-Home: "
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"		
 | 
			
		||||
				android:paddingTop="15px"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textStyle="bold"
 | 
			
		||||
				android:textColor="#ffffff" />
 | 
			
		||||
			<TextView android:text="http://torproject.org/orbot"
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:autoLink="web"
 | 
			
		||||
				android:textColorLink="#ffffff"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textSize="12sp"					
 | 
			
		||||
				android:textColor="#ffffff" />
 | 
			
		||||
			<TextView android:text="License: "
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:paddingTop="15px"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textStyle="bold"
 | 
			
		||||
				android:textColor="#ffffff" />	
 | 
			
		||||
			<TextView android:text="The Tor License"
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:paddingLeft="15px"								
 | 
			
		||||
				android:textColor="#ffffff" />	
 | 
			
		||||
			<TextView android:text="http://torproject.org"
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:autoLink="web"
 | 
			
		||||
				android:textColorLink="#ffffff"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textSize="12sp"					
 | 
			
		||||
				android:textColor="#ffffff" />				
 | 
			
		||||
			<TextView android:text="3rd-Party-Software: "
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"		
 | 
			
		||||
				android:paddingTop="15px"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textStyle="bold"
 | 
			
		||||
				android:textColor="#ffffff" />	
 | 
			
		||||
			<TextView android:text="Tor vX.x: http://www.torproject.org"
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:autoLink="web"
 | 
			
		||||
				android:textColorLink="#ffffff"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textSize="12sp"					
 | 
			
		||||
				android:textColor="#ffffff" />				
 | 
			
		||||
			<TextView android:text="LibEvent vX.x: http://www.monkey.org/~provos/libevent/"
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:autoLink="web"
 | 
			
		||||
				android:textColorLink="#ffffff"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textSize="12sp"					
 | 
			
		||||
				android:textColor="#ffffff" />	
 | 
			
		||||
							
 | 
			
		||||
			</LinearLayout>
 | 
			
		||||
		</ScrollView>			
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:orientation="vertical"
 | 
			
		||||
    android:layout_width="fill_parent"
 | 
			
		||||
    android:layout_height="fill_parent">
 | 
			
		||||
	<ScrollView android:id="@+id/helpscrollview" 
 | 
			
		||||
		android:orientation="vertical"
 | 
			
		||||
		android:layout_width="fill_parent" 
 | 
			
		||||
		android:layout_height="fill_parent">    
 | 
			
		||||
		<LinearLayout
 | 
			
		||||
		    android:orientation="vertical"
 | 
			
		||||
		    android:layout_width="fill_parent"
 | 
			
		||||
		    android:layout_height="fill_parent">
 | 
			
		||||
			<TextView android:text="@string/help_text"
 | 
			
		||||
				android:layout_width="fill_parent" 
 | 
			
		||||
				android:layout_height="wrap_content"
 | 
			
		||||
				android:paddingTop="15px"
 | 
			
		||||
				android:paddingLeft="15px"
 | 
			
		||||
				android:textColor="#ffffff" />				
 | 
			
		||||
			</LinearLayout>
 | 
			
		||||
		</ScrollView>			
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,27 +1,19 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:orientation="vertical"
 | 
			
		||||
    android:layout_width="fill_parent"
 | 
			
		||||
    android:layout_height="fill_parent">
 | 
			
		||||
    
 | 
			
		||||
     
 | 
			
		||||
        <ScrollView  android:layout_height="380px"
 | 
			
		||||
            android:layout_width="fill_parent"  android:id="@+id/logScrollView">
 | 
			
		||||
            
 | 
			
		||||
            <TextView android:id="@+id/messageLog"
 | 
			
		||||
            android:layout_height="fill_parent"
 | 
			
		||||
            android:layout_width="fill_parent"
 | 
			
		||||
            android:layout_weight="1.0"
 | 
			
		||||
            android:textSize="11px"
 | 
			
		||||
            />	
 | 
			
		||||
            
 | 
			
		||||
        </ScrollView>
 | 
			
		||||
            
 | 
			
		||||
         
 | 
			
		||||
 <Button android:id="@+id/btnLogClear" 
 | 
			
		||||
            android:layout_height="40px" 
 | 
			
		||||
             android:text="Clear Log"        
 | 
			
		||||
             android:layout_margin="0sp"
 | 
			
		||||
            android:layout_width="fill_parent"/>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
     
 | 
			
		||||
     <ScrollView  android:orientation="vertical"
 | 
			
		||||
      android:layout_height="480px"
 | 
			
		||||
         android:layout_width="fill_parent"  android:id="@+id/logScrollView"
 | 
			
		||||
          xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
         >
 | 
			
		||||
         
 | 
			
		||||
         <TextView android:id="@+id/messageLog"
 | 
			
		||||
         android:layout_height="wrap_content"
 | 
			
		||||
         android:layout_width="wrap_content"
 | 
			
		||||
         android:layout_x="2px"
 | 
			
		||||
android:layout_y="2px"
 | 
			
		||||
         android:textSize="12px"
 | 
			
		||||
         />	
 | 
			
		||||
         
 | 
			
		||||
     </ScrollView>
 | 
			
		||||
      
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,13 +3,40 @@
 | 
			
		|||
    android:orientation="vertical"
 | 
			
		||||
    android:layout_width="fill_parent"
 | 
			
		||||
    android:layout_height="fill_parent"
 | 
			
		||||
    android:background="@drawable/bgdarkdroid">
 | 
			
		||||
    android:background="@drawable/background">
 | 
			
		||||
    
 | 
			
		||||
    	<RelativeLayout android:id="@+id/layoutHeaderMain"
 | 
			
		||||
		android:layout_width="fill_parent"
 | 
			
		||||
		android:layout_height="30dp"
 | 
			
		||||
		android:layout_gravity="center_horizontal"
 | 
			
		||||
		android:background="#A0909090">
 | 
			
		||||
        <ImageView android:id="@+id/radioModeImage"
 | 
			
		||||
 		    android:layout_width="wrap_content"
 | 
			
		||||
		    android:layout_height="wrap_content"
 | 
			
		||||
			android:layout_marginTop="3px"
 | 
			
		||||
			android:layout_marginRight="3px"
 | 
			
		||||
			android:gravity="right"
 | 
			
		||||
			android:layout_toRightOf="@+id/radioModeLabel"
 | 
			
		||||
			android:layout_alignParentRight="true"
 | 
			
		||||
			android:layout_alignParentTop="true"
 | 
			
		||||
			android:src="@drawable/tor25"
 | 
			
		||||
			/>
 | 
			
		||||
		<TextView android:id="@+id/radioModeText"
 | 
			
		||||
 		    android:layout_width="wrap_content"
 | 
			
		||||
		    android:layout_height="wrap_content"           
 | 
			
		||||
            android:text="powered by the tor project  "
 | 
			
		||||
			android:layout_marginTop="8px"
 | 
			
		||||
			android:layout_marginRight="0px"
 | 
			
		||||
			android:gravity="right"
 | 
			
		||||
			android:layout_toLeftOf="@+id/radioModeImage"
 | 
			
		||||
            android:textColor="#cccccc" />
 | 
			
		||||
	</RelativeLayout>
 | 
			
		||||
    
 | 
			
		||||
   <ScrollView android:id="@+id/mainview" 
 | 
			
		||||
		android:orientation="vertical"
 | 
			
		||||
		android:layout_width="fill_parent" 
 | 
			
		||||
		android:layout_height="fill_parent">
 | 
			
		||||
   <TableLayout android:id="@+id/mainLayout"
 | 
			
		||||
   		<TableLayout android:id="@+id/mainLayout"
 | 
			
		||||
			android:layout_gravity="center"
 | 
			
		||||
			android:layout_height="wrap_content" 
 | 
			
		||||
			android:layout_width="wrap_content">
 | 
			
		||||
| 
						 | 
				
			
			@ -19,30 +46,28 @@
 | 
			
		|||
					android:layout_height="wrap_content" 
 | 
			
		||||
					android:layout_width="wrap_content">
 | 
			
		||||
					<TableRow>
 | 
			
		||||
					
 | 
			
		||||
							
 | 
			
		||||
							<ImageView
 | 
			
		||||
android:id="@+id/imgStatus"
 | 
			
		||||
android:layout_width="wrap_content"
 | 
			
		||||
android:layout_height="wrap_content"
 | 
			
		||||
android:src="@drawable/toroff"/>
 | 
			
		||||
							android:id="@+id/imgStatus"
 | 
			
		||||
							android:layout_width="wrap_content"
 | 
			
		||||
							android:layout_height="wrap_content"
 | 
			
		||||
							android:src="@drawable/toroff"/>
 | 
			
		||||
					</TableRow>
 | 
			
		||||
					<TableRow>
 | 
			
		||||
						<TextView android:id="@+id/lblStatus"
 | 
			
		||||
							android:text=" \n "
 | 
			
		||||
							android:paddingTop="15px"
 | 
			
		||||
							android:text="- Press to enable - "
 | 
			
		||||
							android:layout_gravity="center_horizontal"
 | 
			
		||||
							android:gravity="center_horizontal"
 | 
			
		||||
							android:textStyle="bold"
 | 
			
		||||
							android:width="240px"
 | 
			
		||||
							android:height="100px"
 | 
			
		||||
							android:textColor="#ffffff" />
 | 
			
		||||
							android:textColor="#ffffff"
 | 
			
		||||
							 />
 | 
			
		||||
					</TableRow>
 | 
			
		||||
				</TableLayout>
 | 
			
		||||
			</TableRow>
 | 
			
		||||
			
 | 
			
		||||
		</TableLayout>
 | 
			
		||||
</ScrollView>
 | 
			
		||||
	</ScrollView>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
       
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,35 +0,0 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
/*
 | 
			
		||||
**
 | 
			
		||||
** Copyright 2008, Google Inc.
 | 
			
		||||
**
 | 
			
		||||
** 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.
 | 
			
		||||
*/
 | 
			
		||||
-->
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:orientation="vertical"
 | 
			
		||||
    android:layout_width="fill_parent"
 | 
			
		||||
    android:layout_height="fill_parent"
 | 
			
		||||
    >
 | 
			
		||||
    
 | 
			
		||||
    <WebView
 | 
			
		||||
        android:id="@+id/webview"
 | 
			
		||||
    	android:layout_width="fill_parent" 
 | 
			
		||||
    	android:layout_height="fill_parent"
 | 
			
		||||
    	android:layout_weight="1"
 | 
			
		||||
    	/>
 | 
			
		||||
    	
 | 
			
		||||
    	
 | 
			
		||||
    	
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,45 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<resources>
 | 
			
		||||
    <string name="app_name">ORbot</string>
 | 
			
		||||
    <string name="app_version">0.0.2a</string>
 | 
			
		||||
    <string name="app_name">Orbot</string>
 | 
			
		||||
    <string name="app_version">0.0.3a</string>
 | 
			
		||||
    <string name="internal_web_url">http://orbot/</string>
 | 
			
		||||
    <string name="default_web_url">http://check.torproject.org</string>
 | 
			
		||||
    <string name="control_permission_label">start and stop the anonymous data connection</string>
 | 
			
		||||
    <string name="tor_proxy_service_process">torproxyservice</string>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
<string name="status_starting_up">Starting up...</string>
 | 
			
		||||
<string name="status_activated">"Orbot is Activated\n<< TOUCH TO DISCONNECT >></string>
 | 
			
		||||
<string name="status_disabled">"Orbot is Disabled\n<< TOUCH TO START >></string>
 | 
			
		||||
<string name="status_shutting_down">Orbot is shutting down</string>
 | 
			
		||||
 | 
			
		||||
<string name="tor_process_connecting">Starting Tor engine...</string>
 | 
			
		||||
<string name="tor_process_connecting_step2">authenticating...</string>
 | 
			
		||||
<string name="tor_process_connecting_step3">complete.</string>
 | 
			
		||||
<string name="tor_process_connecting_step4">waiting.</string>
 | 
			
		||||
 | 
			
		||||
<string name="menu_home">Home</string>
 | 
			
		||||
<string name="menu_browse">Browse</string>
 | 
			
		||||
<string name="menu_settings">Settings</string>
 | 
			
		||||
<string name="menu_log">Log</string>
 | 
			
		||||
<string name="menu_info">Info</string>
 | 
			
		||||
 | 
			
		||||
<string name="button_help">Help</string>
 | 
			
		||||
<string name="button_close">Close</string>
 | 
			
		||||
<string name="button_about">About</string>
 | 
			
		||||
 | 
			
		||||
<string name="help_text">Orbot requires different configuration depending on the Android operating system version it is used on.
 | 
			
		||||
\n\n
 | 
			
		||||
For non-rooted Android 1.x devices (G1, MyTouch3G, Hero): Please use the "ProxySurf" browser available in the Android Market, and set 
 | 
			
		||||
the HTTP Proxy to 127.0.0.1 and port 8118. For Instant Messsaging, try "Beem" in the market, and set the HTTP or SOCKS5 proxy (to port 9050).
 | 
			
		||||
\n\n
 | 
			
		||||
For Android 2.x devices, you MUST ROOT your device in order for Orbot to work transparently for all web and DNS traffic. Otherwise, the "Beem" app will allow
 | 
			
		||||
you to set the SOCKS5 proxy to 127.0.0.1 and port 9050. You should also enable SSL to protect your username and password.
 | 
			
		||||
\n\n
 | 
			
		||||
If you root your device, whether it is 1.x or 2.x based, Orbot will automatically, transparently proxy all web traffic on port 80
 | 
			
		||||
and all DNS requests. This includes the built-in Browser, Gmail, YouTube, Maps and any other application that uses standard port 80
 | 
			
		||||
traffic.
 | 
			
		||||
\n\n
 | 
			
		||||
At this time, Orbot cannot proxy standard HTTPS traffic unless the application supports proxy via HTTP or SOCKS.
 | 
			
		||||
</string>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,639 +0,0 @@
 | 
			
		|||
package org.torproject.android;
 | 
			
		||||
/* <!-- in case someone opens this in a browser... --> <pre> */
 | 
			
		||||
/*
 | 
			
		||||
 * This is a simple multi-threaded Java proxy server
 | 
			
		||||
 * for HTTP requests (HTTPS doesn't seem to work, because
 | 
			
		||||
 * the CONNECT requests aren't always handled properly).
 | 
			
		||||
 * I implemented the class as a thread so you can call it 
 | 
			
		||||
 * from other programs and kill it, if necessary (by using 
 | 
			
		||||
 * the closeSocket() method).
 | 
			
		||||
 *
 | 
			
		||||
 * We'll call this the 1.1 version of this class. All I 
 | 
			
		||||
 * changed was to separate the HTTP header elements with
 | 
			
		||||
 * \r\n instead of just \n, to comply with the official
 | 
			
		||||
 * HTTP specification.
 | 
			
		||||
 *  
 | 
			
		||||
 * This can be used either as a direct proxy to other
 | 
			
		||||
 * servers, or as a forwarding proxy to another proxy
 | 
			
		||||
 * server. This makes it useful if you want to monitor
 | 
			
		||||
 * traffic going to and from a proxy server (for example,
 | 
			
		||||
 * you can run this on your local machine and set the
 | 
			
		||||
 * fwdServer and fwdPort to a real proxy server, and then
 | 
			
		||||
 * tell your browser to use "localhost" as the proxy, and
 | 
			
		||||
 * you can watch the browser traffic going in and out).
 | 
			
		||||
 *
 | 
			
		||||
 * One limitation of this implementation is that it doesn't 
 | 
			
		||||
 * close the ProxyThread socket if the client disconnects
 | 
			
		||||
 * or the server never responds, so you could end up with
 | 
			
		||||
 * a bunch of loose threads running amuck and waiting for
 | 
			
		||||
 * connections. As a band-aid, you can set the server socket
 | 
			
		||||
 * to timeout after a certain amount of time (use the
 | 
			
		||||
 * setTimeout() method in the ProxyThread class), although
 | 
			
		||||
 * this can cause false timeouts if a remote server is simply
 | 
			
		||||
 * slow to respond.
 | 
			
		||||
 *
 | 
			
		||||
 * Another thing is that it doesn't limit the number of
 | 
			
		||||
 * socket threads it will create, so if you use this on a
 | 
			
		||||
 * really busy machine that processed a bunch of requests,
 | 
			
		||||
 * you may have problems. You should use thread pools if
 | 
			
		||||
 * you're going to try something like this in a "real"
 | 
			
		||||
 * application.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that if you're using the "main" method to run this
 | 
			
		||||
 * by itself and you don't need the debug output, it will
 | 
			
		||||
 * run a bit faster if you pipe the std output to 'nul'.
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this code as you wish, just don't pretend 
 | 
			
		||||
 * that you wrote it yourself, and don't hold me liable for 
 | 
			
		||||
 * anything that it does or doesn't do. If you're feeling 
 | 
			
		||||
 * especially honest, please include a link to nsftools.com
 | 
			
		||||
 * along with the code. Thanks, and good luck.
 | 
			
		||||
 *
 | 
			
		||||
 * Julian Robichaux -- http://www.nsftools.com
 | 
			
		||||
 */
 | 
			
		||||
import java.io.BufferedInputStream;
 | 
			
		||||
import java.io.BufferedOutputStream;
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.io.PrintStream;
 | 
			
		||||
import java.lang.reflect.Array;
 | 
			
		||||
import java.net.ServerSocket;
 | 
			
		||||
import java.net.Socket;
 | 
			
		||||
import java.net.UnknownHostException;
 | 
			
		||||
 | 
			
		||||
import net.sourceforge.jsocks.socks.Socks5Proxy;
 | 
			
		||||
import net.sourceforge.jsocks.socks.SocksSocket;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class HttpProxy extends Thread
 | 
			
		||||
{
 | 
			
		||||
	public static final int DEFAULT_PORT = 8888;
 | 
			
		||||
	
 | 
			
		||||
	private ServerSocket server = null;
 | 
			
		||||
	private int thisPort = DEFAULT_PORT;
 | 
			
		||||
	private String fwdServer = "";
 | 
			
		||||
	private int fwdPort = 0;
 | 
			
		||||
	private int ptTimeout = ProxyThread.DEFAULT_TIMEOUT;
 | 
			
		||||
	private int debugLevel = 1;
 | 
			
		||||
	private PrintStream debugOut = System.out;
 | 
			
		||||
	private boolean keepRunning = true;
 | 
			
		||||
	private boolean doSocks = false;
 | 
			
		||||
	
 | 
			
		||||
	private Socks5Proxy sProxy = null;
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the doSocks
 | 
			
		||||
	 */
 | 
			
		||||
	public boolean isDoSocks() {
 | 
			
		||||
		return doSocks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param doSocks the doSocks to set
 | 
			
		||||
	 */
 | 
			
		||||
	public void setDoSocks(boolean doSocks) {
 | 
			
		||||
		this.doSocks = doSocks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* here's a main method, in case you want to run this by itself */
 | 
			
		||||
	public static void main (String args[])
 | 
			
		||||
	{
 | 
			
		||||
		int port = 0;
 | 
			
		||||
		String fwdProxyServer = "";
 | 
			
		||||
		int fwdProxyPort = 0;
 | 
			
		||||
		
 | 
			
		||||
		if (args.length == 0)
 | 
			
		||||
		{
 | 
			
		||||
			System.err.println("USAGE: java jProxy <port number> [<fwd proxy> <fwd port>]");
 | 
			
		||||
			System.err.println("  <port number>   the port this service listens on");
 | 
			
		||||
			System.err.println("  <fwd proxy>     optional proxy server to forward requests to");
 | 
			
		||||
			System.err.println("  <fwd port>      the port that the optional proxy server is on");
 | 
			
		||||
			System.err.println("\nHINT: if you don't want to see all the debug information flying by,");
 | 
			
		||||
			System.err.println("you can pipe the output to a file or to 'nul' using \">\". For example:");
 | 
			
		||||
			System.err.println("  to send output to the file prox.txt: java jProxy 8080 > prox.txt");
 | 
			
		||||
			System.err.println("  to make the output go away: java jProxy 8080 > nul");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// get the command-line parameters
 | 
			
		||||
		port = Integer.parseInt(args[0]);
 | 
			
		||||
		if (args.length > 2)
 | 
			
		||||
		{
 | 
			
		||||
			fwdProxyServer = args[1];
 | 
			
		||||
			fwdProxyPort = Integer.parseInt(args[2]);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// create and start the jProxy thread, using a 20 second timeout
 | 
			
		||||
		// value to keep the threads from piling up too much
 | 
			
		||||
		System.err.println("  **  Starting jProxy on port " + port + ". Press CTRL-C to end.  **\n");
 | 
			
		||||
		HttpProxy jp = new HttpProxy(port, fwdProxyServer, fwdProxyPort, 20);
 | 
			
		||||
		jp.setDebug(1, System.out);		// or set the debug level to 2 for tons of output
 | 
			
		||||
		jp.start();
 | 
			
		||||
		
 | 
			
		||||
		// run forever; if you were calling this class from another
 | 
			
		||||
		// program and you wanted to stop the jProxy thread at some
 | 
			
		||||
		// point, you could write a loop that waits for a certain
 | 
			
		||||
		// condition and then calls jProxy.closeSocket() to kill
 | 
			
		||||
		// the running jProxy thread
 | 
			
		||||
		while (true)
 | 
			
		||||
		{
 | 
			
		||||
			try { Thread.sleep(3000); } catch (Exception e) {}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// if we ever had a condition that stopped the loop above,
 | 
			
		||||
		// we'd want to do this to kill the running thread
 | 
			
		||||
		//jp.closeSocket();
 | 
			
		||||
		//return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	/* the proxy server just listens for connections and creates
 | 
			
		||||
	 * a new thread for each connection attempt (the ProxyThread
 | 
			
		||||
	 * class really does all the work)
 | 
			
		||||
	 */
 | 
			
		||||
	public HttpProxy (int port)
 | 
			
		||||
	{
 | 
			
		||||
		thisPort = port;
 | 
			
		||||
		
 | 
			
		||||
		try {
 | 
			
		||||
			sProxy = new Socks5Proxy(TorConstants.IP_LOCALHOST,TorConstants.PORT_SOCKS);
 | 
			
		||||
		} catch (UnknownHostException e) {
 | 
			
		||||
			// TODO Auto-generated catch block
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
		}
 | 
			
		||||
		sProxy.resolveAddrLocally(false);
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public HttpProxy (int port, String proxyServer, int proxyPort)
 | 
			
		||||
	{
 | 
			
		||||
		thisPort = port;
 | 
			
		||||
		fwdServer = proxyServer;
 | 
			
		||||
		fwdPort = proxyPort;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public HttpProxy (int port, String proxyServer, int proxyPort, int timeout)
 | 
			
		||||
	{
 | 
			
		||||
		thisPort = port;
 | 
			
		||||
		fwdServer = proxyServer;
 | 
			
		||||
		fwdPort = proxyPort;
 | 
			
		||||
		ptTimeout = timeout;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	/* allow the user to decide whether or not to send debug
 | 
			
		||||
	 * output to the console or some other PrintStream
 | 
			
		||||
	 */
 | 
			
		||||
	public void setDebug (int level, PrintStream out)
 | 
			
		||||
	{
 | 
			
		||||
		debugLevel = level;
 | 
			
		||||
		debugOut = out;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	/* get the port that we're supposed to be listening on
 | 
			
		||||
	 */
 | 
			
		||||
	public int getPort ()
 | 
			
		||||
	{
 | 
			
		||||
		return thisPort;
 | 
			
		||||
	}
 | 
			
		||||
	 
 | 
			
		||||
	
 | 
			
		||||
	/* return whether or not the socket is currently open
 | 
			
		||||
	 */
 | 
			
		||||
	public boolean isRunning ()
 | 
			
		||||
	{
 | 
			
		||||
		if (server == null)
 | 
			
		||||
			return false;
 | 
			
		||||
		else
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
	 
 | 
			
		||||
	
 | 
			
		||||
	/* closeSocket will close the open ServerSocket; use this
 | 
			
		||||
	 * to halt a running jProxy thread
 | 
			
		||||
	 */
 | 
			
		||||
	public void closeSocket ()
 | 
			
		||||
	{
 | 
			
		||||
		try {
 | 
			
		||||
			keepRunning = false;
 | 
			
		||||
			// close the open server socket
 | 
			
		||||
			server.close();
 | 
			
		||||
			// send it a message to make it stop waiting immediately
 | 
			
		||||
			// (not really necessary)
 | 
			
		||||
			/*Socket s = new Socket("localhost", thisPort);
 | 
			
		||||
			OutputStream os = s.getOutputStream();
 | 
			
		||||
			os.write((byte)0);
 | 
			
		||||
			os.close();
 | 
			
		||||
			s.close();*/
 | 
			
		||||
		}  catch(Exception e)  { 
 | 
			
		||||
			if (debugLevel > 0)
 | 
			
		||||
				debugOut.println(e);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		server = null;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	public void run()
 | 
			
		||||
	{
 | 
			
		||||
		try {
 | 
			
		||||
			// create a server socket, and loop forever listening for
 | 
			
		||||
			// client connections
 | 
			
		||||
			server = new ServerSocket(thisPort);
 | 
			
		||||
			
 | 
			
		||||
			while (keepRunning)
 | 
			
		||||
			{
 | 
			
		||||
				Socket client = server.accept();
 | 
			
		||||
				ProxyThread t = new ProxyThread(client, doSocks, sProxy);
 | 
			
		||||
				//t.setDebug(debugLevel, debugOut);
 | 
			
		||||
				//t.setTimeout(ptTimeout);
 | 
			
		||||
				t.start();
 | 
			
		||||
			}
 | 
			
		||||
		}  catch (Exception e)  {
 | 
			
		||||
			if (debugLevel > 0)
 | 
			
		||||
				debugOut.println("jProxy Thread error: " + e);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		closeSocket();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * The ProxyThread will take an HTTP request from the client
 | 
			
		||||
 * socket and send it to either the server that the client is
 | 
			
		||||
 * trying to contact, or another proxy server
 | 
			
		||||
 */
 | 
			
		||||
class ProxyThread extends Thread
 | 
			
		||||
{
 | 
			
		||||
	private Socket pSocket;
 | 
			
		||||
	private String fwdServer = "";
 | 
			
		||||
	private int fwdPort = 0;
 | 
			
		||||
	private int debugLevel = 0;
 | 
			
		||||
	private PrintStream debugOut = System.out;
 | 
			
		||||
	
 | 
			
		||||
	// the socketTimeout is used to time out the connection to
 | 
			
		||||
	// the remote server after a certain period of inactivity;
 | 
			
		||||
	// the value is in milliseconds -- use zero if you don't want 
 | 
			
		||||
	// a timeout
 | 
			
		||||
	public static final int DEFAULT_TIMEOUT = 20 * 1000;
 | 
			
		||||
	private int socketTimeout = DEFAULT_TIMEOUT;
 | 
			
		||||
	
 | 
			
		||||
	private boolean doSocks = false;
 | 
			
		||||
	
 | 
			
		||||
	private static Socks5Proxy sProxy = null;
 | 
			
		||||
	
 | 
			
		||||
	public ProxyThread(Socket s, boolean doSocks, Socks5Proxy sProxy)
 | 
			
		||||
	{
 | 
			
		||||
		pSocket = s;
 | 
			
		||||
		
 | 
			
		||||
		this.sProxy = sProxy;
 | 
			
		||||
		this.doSocks = doSocks;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public ProxyThread(Socket s, String proxy, int port)
 | 
			
		||||
	{
 | 
			
		||||
		pSocket = s;
 | 
			
		||||
		fwdServer = proxy;
 | 
			
		||||
		fwdPort = port;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	public void setTimeout (int timeout)
 | 
			
		||||
	{
 | 
			
		||||
		// assume that the user will pass the timeout value
 | 
			
		||||
		// in seconds (because that's just more intuitive)
 | 
			
		||||
		socketTimeout = timeout * 1000;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public void setDebug (int level, PrintStream out)
 | 
			
		||||
	{
 | 
			
		||||
		debugLevel = level;
 | 
			
		||||
		debugOut = out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public void run()
 | 
			
		||||
	{
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			long startTime = System.currentTimeMillis();
 | 
			
		||||
			
 | 
			
		||||
			// client streams (make sure you're using streams that use
 | 
			
		||||
			// byte arrays, so things like GIF and JPEG files and file
 | 
			
		||||
			// downloads will transfer properly)
 | 
			
		||||
			BufferedInputStream clientIn = new BufferedInputStream(pSocket.getInputStream());
 | 
			
		||||
			BufferedOutputStream clientOut = new BufferedOutputStream(pSocket.getOutputStream());
 | 
			
		||||
			
 | 
			
		||||
			// the socket to the remote server
 | 
			
		||||
			Socket server = null;
 | 
			
		||||
			
 | 
			
		||||
			// other variables
 | 
			
		||||
			byte[] request = null;
 | 
			
		||||
			byte[] response = null;
 | 
			
		||||
			int requestLength = 0;
 | 
			
		||||
			int responseLength = 0;
 | 
			
		||||
			int pos = -1;
 | 
			
		||||
			StringBuffer host = new StringBuffer("");
 | 
			
		||||
			String hostName = "";
 | 
			
		||||
			int hostPort = 80;
 | 
			
		||||
			
 | 
			
		||||
			// get the header info (the web browser won't disconnect after
 | 
			
		||||
			// it's sent a request, so make sure the waitForDisconnect
 | 
			
		||||
			// parameter is false)
 | 
			
		||||
			request = getHTTPData(clientIn, host, false);
 | 
			
		||||
			requestLength = Array.getLength(request);
 | 
			
		||||
			
 | 
			
		||||
			// separate the host name from the host port, if necessary
 | 
			
		||||
			// (like if it's "servername:8000")
 | 
			
		||||
			hostName = host.toString();
 | 
			
		||||
			pos = hostName.indexOf(":");
 | 
			
		||||
			if (pos > 0)
 | 
			
		||||
			{
 | 
			
		||||
				try { hostPort = Integer.parseInt(hostName.substring(pos + 1)); 
 | 
			
		||||
					}  catch (Exception e)  { }
 | 
			
		||||
				hostName = hostName.substring(0, pos);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// either forward this request to another proxy server or
 | 
			
		||||
			// send it straight to the Host
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				
 | 
			
		||||
				if (!doSocks)
 | 
			
		||||
				{
 | 
			
		||||
					if ((fwdServer.length() > 0) && (fwdPort > 0))
 | 
			
		||||
					{
 | 
			
		||||
						server = new Socket(fwdServer, fwdPort);
 | 
			
		||||
					}  else  {
 | 
			
		||||
						server = new Socket(hostName, hostPort);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					
 | 
			
		||||
					server =  new SocksSocket(sProxy,hostName, hostPort);
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
			}  catch (Exception e)  {
 | 
			
		||||
				// tell the client there was an error
 | 
			
		||||
				String errMsg = "HTTP/1.0 500\nContent Type: text/plain\n\n" + 
 | 
			
		||||
								"Error connecting to the server:\n" + e + "\n";
 | 
			
		||||
				clientOut.write(errMsg.getBytes(), 0, errMsg.length());
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (server != null)
 | 
			
		||||
			{
 | 
			
		||||
				server.setSoTimeout(socketTimeout);
 | 
			
		||||
				BufferedInputStream serverIn = new BufferedInputStream(server.getInputStream());
 | 
			
		||||
				BufferedOutputStream serverOut = new BufferedOutputStream(server.getOutputStream());
 | 
			
		||||
				
 | 
			
		||||
				// send the request out
 | 
			
		||||
				serverOut.write(request, 0, requestLength);
 | 
			
		||||
				serverOut.flush();
 | 
			
		||||
				
 | 
			
		||||
				// and get the response; if we're not at a debug level that
 | 
			
		||||
				// requires us to return the data in the response, just stream
 | 
			
		||||
				// it back to the client to save ourselves from having to
 | 
			
		||||
				// create and destroy an unnecessary byte array. Also, we
 | 
			
		||||
				// should set the waitForDisconnect parameter to 'true',
 | 
			
		||||
				// because some servers (like Google) don't always set the
 | 
			
		||||
				// Content-Length header field, so we have to listen until
 | 
			
		||||
				// they decide to disconnect (or the connection times out).
 | 
			
		||||
				if (debugLevel > 1)
 | 
			
		||||
				{
 | 
			
		||||
					response = getHTTPData(serverIn, true);
 | 
			
		||||
					responseLength = Array.getLength(response);
 | 
			
		||||
				}  else  {
 | 
			
		||||
					responseLength = streamHTTPData(serverIn, clientOut, true);
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				serverIn.close();
 | 
			
		||||
				serverOut.close();
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// send the response back to the client, if we haven't already
 | 
			
		||||
			if (debugLevel > 1)
 | 
			
		||||
				clientOut.write(response, 0, responseLength);
 | 
			
		||||
			
 | 
			
		||||
			// if the user wants debug info, send them debug info; however,
 | 
			
		||||
			// keep in mind that because we're using threads, the output won't
 | 
			
		||||
			// necessarily be synchronous
 | 
			
		||||
			if (debugLevel > 0)
 | 
			
		||||
			{
 | 
			
		||||
				long endTime = System.currentTimeMillis();
 | 
			
		||||
				debugOut.println("Request from " + pSocket.getInetAddress().getHostAddress() + 
 | 
			
		||||
									" on Port " + pSocket.getLocalPort() + 
 | 
			
		||||
									" to host " + hostName + ":" + hostPort + 
 | 
			
		||||
									"\n  (" + requestLength + " bytes sent, " + 
 | 
			
		||||
									responseLength + " bytes returned, " + 
 | 
			
		||||
									Long.toString(endTime - startTime) + " ms elapsed)");
 | 
			
		||||
				debugOut.flush();
 | 
			
		||||
			}
 | 
			
		||||
			if (debugLevel > 1)
 | 
			
		||||
			{
 | 
			
		||||
				debugOut.println("REQUEST:\n" + (new String(request)));
 | 
			
		||||
				debugOut.println("RESPONSE:\n" + (new String(response)));
 | 
			
		||||
				debugOut.flush();
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// close all the client streams so we can listen again
 | 
			
		||||
			clientOut.close();
 | 
			
		||||
			clientIn.close();
 | 
			
		||||
			pSocket.close();
 | 
			
		||||
		}  catch (Exception e)  {
 | 
			
		||||
			if (debugLevel > 0)
 | 
			
		||||
				debugOut.println("Error in ProxyThread: " + e);
 | 
			
		||||
			//e.printStackTrace();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	private byte[] getHTTPData (InputStream in, boolean waitForDisconnect)
 | 
			
		||||
	{
 | 
			
		||||
		// get the HTTP data from an InputStream, and return it as
 | 
			
		||||
		// a byte array
 | 
			
		||||
		// the waitForDisconnect parameter tells us what to do in case
 | 
			
		||||
		// the HTTP header doesn't specify the Content-Length of the
 | 
			
		||||
		// transmission
 | 
			
		||||
		StringBuffer foo = new StringBuffer("");
 | 
			
		||||
		return getHTTPData(in, foo, waitForDisconnect);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	private byte[] getHTTPData (InputStream in, StringBuffer host, boolean waitForDisconnect)
 | 
			
		||||
	{
 | 
			
		||||
		// get the HTTP data from an InputStream, and return it as
 | 
			
		||||
		// a byte array, and also return the Host entry in the header,
 | 
			
		||||
		// if it's specified -- note that we have to use a StringBuffer
 | 
			
		||||
		// for the 'host' variable, because a String won't return any
 | 
			
		||||
		// information when it's used as a parameter like that
 | 
			
		||||
		ByteArrayOutputStream bs = new ByteArrayOutputStream();
 | 
			
		||||
		streamHTTPData(in, bs, host, waitForDisconnect);
 | 
			
		||||
		return bs.toByteArray();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	private int streamHTTPData (InputStream in, OutputStream out, boolean waitForDisconnect)
 | 
			
		||||
	{
 | 
			
		||||
		StringBuffer foo = new StringBuffer("");
 | 
			
		||||
		return streamHTTPData(in, out, foo, waitForDisconnect);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private int streamHTTPData (InputStream in, OutputStream out, 
 | 
			
		||||
									StringBuffer host, boolean waitForDisconnect)
 | 
			
		||||
	{
 | 
			
		||||
		// get the HTTP data from an InputStream, and send it to
 | 
			
		||||
		// the designated OutputStream
 | 
			
		||||
		StringBuffer header = new StringBuffer("");
 | 
			
		||||
		String data = "";
 | 
			
		||||
		int responseCode = 200;
 | 
			
		||||
		int contentLength = 0;
 | 
			
		||||
		int pos = -1;
 | 
			
		||||
		int byteCount = 0;
 | 
			
		||||
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			// get the first line of the header, so we know the response code
 | 
			
		||||
			data = readLine(in);
 | 
			
		||||
			if (data != null)
 | 
			
		||||
			{
 | 
			
		||||
				header.append(data + "\r\n");
 | 
			
		||||
				pos = data.indexOf(" ");
 | 
			
		||||
				if ((data.toLowerCase().startsWith("http")) && 
 | 
			
		||||
					(pos >= 0) && (data.indexOf(" ", pos+1) >= 0))
 | 
			
		||||
				{
 | 
			
		||||
					String rcString = data.substring(pos+1, data.indexOf(" ", pos+1));
 | 
			
		||||
					try
 | 
			
		||||
					{
 | 
			
		||||
						responseCode = Integer.parseInt(rcString);
 | 
			
		||||
					}  catch (Exception e)  {
 | 
			
		||||
						if (debugLevel > 0)
 | 
			
		||||
							debugOut.println("Error parsing response code " + rcString);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// get the rest of the header info
 | 
			
		||||
			while ((data = readLine(in)) != null)
 | 
			
		||||
			{
 | 
			
		||||
				// the header ends at the first blank line
 | 
			
		||||
				if (data.length() == 0)
 | 
			
		||||
					break;
 | 
			
		||||
				header.append(data + "\r\n");
 | 
			
		||||
				
 | 
			
		||||
				// check for the Host header
 | 
			
		||||
				pos = data.toLowerCase().indexOf("host:");
 | 
			
		||||
				if (pos >= 0)
 | 
			
		||||
				{
 | 
			
		||||
					host.setLength(0);
 | 
			
		||||
					host.append(data.substring(pos + 5).trim());
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				// check for the Content-Length header
 | 
			
		||||
				pos = data.toLowerCase().indexOf("content-length:");
 | 
			
		||||
				if (pos >= 0)
 | 
			
		||||
					contentLength = Integer.parseInt(data.substring(pos + 15).trim());
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			// add a blank line to terminate the header info
 | 
			
		||||
			header.append("\r\n");
 | 
			
		||||
			
 | 
			
		||||
			// convert the header to a byte array, and write it to our stream
 | 
			
		||||
			out.write(header.toString().getBytes(), 0, header.length());
 | 
			
		||||
			
 | 
			
		||||
			// if the header indicated that this was not a 200 response,
 | 
			
		||||
			// just return what we've got if there is no Content-Length,
 | 
			
		||||
			// because we may not be getting anything else
 | 
			
		||||
			if ((responseCode != 200) && (contentLength == 0))
 | 
			
		||||
			{
 | 
			
		||||
				out.flush();
 | 
			
		||||
				return header.length();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// get the body, if any; we try to use the Content-Length header to
 | 
			
		||||
			// determine how much data we're supposed to be getting, because 
 | 
			
		||||
			// sometimes the client/server won't disconnect after sending us
 | 
			
		||||
			// information...
 | 
			
		||||
			if (contentLength > 0)
 | 
			
		||||
				waitForDisconnect = false;
 | 
			
		||||
			
 | 
			
		||||
			if ((contentLength > 0) || (waitForDisconnect))
 | 
			
		||||
			{
 | 
			
		||||
				try {
 | 
			
		||||
					byte[] buf = new byte[4096];
 | 
			
		||||
					int bytesIn = 0;
 | 
			
		||||
					while ( ((byteCount < contentLength) || (waitForDisconnect)) 
 | 
			
		||||
							&& ((bytesIn = in.read(buf)) >= 0) )
 | 
			
		||||
					{
 | 
			
		||||
						out.write(buf, 0, bytesIn);
 | 
			
		||||
						byteCount += bytesIn;
 | 
			
		||||
					}
 | 
			
		||||
				}  catch (Exception e)  {
 | 
			
		||||
					String errMsg = "Error getting HTTP body: " + e;
 | 
			
		||||
					if (debugLevel > 0)
 | 
			
		||||
						debugOut.println(errMsg);
 | 
			
		||||
					//bs.write(errMsg.getBytes(), 0, errMsg.length());
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}  catch (Exception e)  {
 | 
			
		||||
			if (debugLevel > 0)
 | 
			
		||||
				debugOut.println("Error getting HTTP data: " + e);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		//flush the OutputStream and return
 | 
			
		||||
		try  {  out.flush();  }  catch (Exception e)  {}
 | 
			
		||||
		return (header.length() + byteCount);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	private String readLine (InputStream in)
 | 
			
		||||
	{
 | 
			
		||||
		// reads a line of text from an InputStream
 | 
			
		||||
		StringBuffer data = new StringBuffer("");
 | 
			
		||||
		int c;
 | 
			
		||||
		
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			// if we have nothing to read, just return null
 | 
			
		||||
			in.mark(1);
 | 
			
		||||
			if (in.read() == -1)
 | 
			
		||||
				return null;
 | 
			
		||||
			else
 | 
			
		||||
				in.reset();
 | 
			
		||||
			
 | 
			
		||||
			while ((c = in.read()) >= 0)
 | 
			
		||||
			{
 | 
			
		||||
				// check for an end-of-line character
 | 
			
		||||
				if ((c == 0) || (c == 10) || (c == 13))
 | 
			
		||||
					break;
 | 
			
		||||
				else
 | 
			
		||||
					data.append((char)c);
 | 
			
		||||
			}
 | 
			
		||||
		
 | 
			
		||||
			// deal with the case where the end-of-line terminator is \r\n
 | 
			
		||||
			if (c == 13)
 | 
			
		||||
			{
 | 
			
		||||
				in.mark(1);
 | 
			
		||||
				if (in.read() != 10)
 | 
			
		||||
					in.reset();
 | 
			
		||||
			}
 | 
			
		||||
		}  catch (Exception e)  {
 | 
			
		||||
			if (debugLevel > 0)
 | 
			
		||||
				debugOut.println("Error getting header: " + e);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// and return what we have
 | 
			
		||||
		return data.toString();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,642 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
 | 
			
		||||
package org.torproject.android;
 | 
			
		||||
 | 
			
		||||
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.TorServiceConstants;
 | 
			
		||||
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.app.AlertDialog;
 | 
			
		||||
import android.app.ProgressDialog;
 | 
			
		||||
import android.content.ComponentName;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.DialogInterface;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.ServiceConnection;
 | 
			
		||||
import android.content.SharedPreferences;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.os.Handler;
 | 
			
		||||
import android.os.IBinder;
 | 
			
		||||
import android.os.Message;
 | 
			
		||||
import android.os.RemoteException;
 | 
			
		||||
import android.preference.PreferenceManager;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.KeyEvent;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.Menu;
 | 
			
		||||
import android.view.MenuItem;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.View.OnClickListener;
 | 
			
		||||
import android.widget.ImageView;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
public class Orbot extends Activity implements OnClickListener, TorConstants
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	/* Useful UI bits */
 | 
			
		||||
	private TextView txtMessageLog = null; //the full screen log view of Tor control messages
 | 
			
		||||
	private TextView lblStatus = null; //the main text display widget
 | 
			
		||||
	private ImageView imgStatus = null; //the main touchable image for activating Orbot
 | 
			
		||||
	private ProgressDialog progressDialog;
 | 
			
		||||
	
 | 
			
		||||
	/* Some tracking bits */
 | 
			
		||||
	private int torStatus = STATUS_REQUIRES_DEMAND; //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
 | 
			
		||||
    public void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
    	setTheme(android.R.style.Theme_Black);
 | 
			
		||||
    	setTitle(getString(R.string.app_name) + ' ' + getString(R.string.app_version));
 | 
			
		||||
        showMain();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
   /*
 | 
			
		||||
    * Create the UI Options Menu (non-Javadoc)
 | 
			
		||||
    * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
 | 
			
		||||
    */
 | 
			
		||||
    public boolean onCreateOptionsMenu(Menu menu) {
 | 
			
		||||
        super.onCreateOptionsMenu(menu);
 | 
			
		||||
        
 | 
			
		||||
        MenuItem mItem = null;
 | 
			
		||||
        
 | 
			
		||||
        mItem = menu.add(0, 1, Menu.NONE, getString(R.string.menu_home));
 | 
			
		||||
        mItem.setIcon(R.drawable.ic_menu_home);
 | 
			
		||||
 | 
			
		||||
        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_settings));
 | 
			
		||||
        mItem.setIcon(R.drawable.ic_menu_register);
 | 
			
		||||
        
 | 
			
		||||
        mItem =  menu.add(0, 4, 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;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* When a menu item is selected launch the appropriate view or activity
 | 
			
		||||
     * (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onMenuItemSelected(int, android.view.MenuItem)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
 | 
			
		||||
		
 | 
			
		||||
		super.onMenuItemSelected(featureId, item);
 | 
			
		||||
		
 | 
			
		||||
		if (item.getItemId() == 1)
 | 
			
		||||
		{
 | 
			
		||||
			this.showMain();
 | 
			
		||||
		}
 | 
			
		||||
		else if (item.getItemId() == 3)
 | 
			
		||||
		{
 | 
			
		||||
			this.showSettings();
 | 
			
		||||
		}
 | 
			
		||||
		else if (item.getItemId() == 4)
 | 
			
		||||
		{
 | 
			
		||||
			this.showMessageLog();
 | 
			
		||||
		}
 | 
			
		||||
		else if (item.getItemId() == 2)
 | 
			
		||||
		{
 | 
			
		||||
			openBrowser(URL_TOR_CHECK);
 | 
			
		||||
		}
 | 
			
		||||
		else if (item.getItemId() == 5)
 | 
			
		||||
		{
 | 
			
		||||
			showHelp();
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
        return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Return to the main view when the back key is pressed
 | 
			
		||||
	 * (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
 | 
			
		||||
	 */
 | 
			
		||||
	public boolean onKeyDown(int keyCode, KeyEvent event){
 | 
			
		||||
		
 | 
			
		||||
		if(keyCode==KeyEvent.KEYCODE_BACK){
 | 
			
		||||
 | 
			
		||||
			if(currentView != R.layout.layout_main){
 | 
			
		||||
					
 | 
			
		||||
					showMain ();
 | 
			
		||||
					return true;
 | 
			
		||||
			}
 | 
			
		||||
			else{
 | 
			
		||||
				return super.onKeyDown(keyCode, event);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
		return super.onKeyDown(keyCode, event);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
    /* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onPause()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onPause() {
 | 
			
		||||
		super.onPause();
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onResume()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onResume() {
 | 
			
		||||
		super.onResume();
 | 
			
		||||
		
 | 
			
		||||
		updateStatus (""); //update the status, which checks the service status
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onStart()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onStart() {
 | 
			
		||||
		super.onStart();
 | 
			
		||||
		
 | 
			
		||||
		//if Tor binary is not running, then start the service up
 | 
			
		||||
		startService(new Intent(INTENT_TOR_SERVICE));
 | 
			
		||||
		bindService ();
 | 
			
		||||
		
 | 
			
		||||
		updateStatus ("");
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onStop()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onStop() {
 | 
			
		||||
		super.onStop();
 | 
			
		||||
		
 | 
			
		||||
		unbindService();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Show the main form UI
 | 
			
		||||
	 */
 | 
			
		||||
	private void showMain ()
 | 
			
		||||
    {
 | 
			
		||||
		bindService(); //connect the UI activity to the remote service
 | 
			
		||||
		
 | 
			
		||||
		currentView = R.layout.layout_main;
 | 
			
		||||
		setContentView(currentView);
 | 
			
		||||
		
 | 
			
		||||
		//add touch listeners for the image and the text label
 | 
			
		||||
    	findViewById(R.id.imgStatus).setOnClickListener(this); 
 | 
			
		||||
    	findViewById(R.id.lblStatus).setOnClickListener(this);
 | 
			
		||||
    	
 | 
			
		||||
    	lblStatus = (TextView)findViewById(R.id.lblStatus);
 | 
			
		||||
    	imgStatus = (ImageView)findViewById(R.id.imgStatus);
 | 
			
		||||
    	
 | 
			
		||||
    	updateStatus("");
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Launch the system activity for Uri viewing with the provided url
 | 
			
		||||
	 */
 | 
			
		||||
	private void openBrowser(String url)
 | 
			
		||||
	{
 | 
			
		||||
		startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Show the about view - a popup dialog
 | 
			
		||||
	 */
 | 
			
		||||
	private void showAbout ()
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		LayoutInflater li = LayoutInflater.from(this);
 | 
			
		||||
        View view = li.inflate(R.layout.layout_about, null); 
 | 
			
		||||
        TextView versionName = (TextView)view.findViewById(R.id.versionName);
 | 
			
		||||
        versionName.setText(R.string.app_version);    
 | 
			
		||||
        
 | 
			
		||||
		new AlertDialog.Builder(this)
 | 
			
		||||
        .setTitle(getString(R.string.menu_info))
 | 
			
		||||
        .setView(view)
 | 
			
		||||
        .setNeutralButton(getString(R.string.button_help), new DialogInterface.OnClickListener() {
 | 
			
		||||
                public void onClick(DialogInterface dialog, int whichButton) {
 | 
			
		||||
                      showHelp();
 | 
			
		||||
                }
 | 
			
		||||
        })
 | 
			
		||||
        .setNegativeButton(getString(R.string.button_close), new DialogInterface.OnClickListener() {
 | 
			
		||||
                public void onClick(DialogInterface dialog, int whichButton) {
 | 
			
		||||
                    //    Log.d(TAG, "Close pressed");
 | 
			
		||||
                }
 | 
			
		||||
        })
 | 
			
		||||
        .show();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Show the help view - a popup dialog
 | 
			
		||||
	 */
 | 
			
		||||
	private void showHelp ()
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		LayoutInflater li = LayoutInflater.from(this);
 | 
			
		||||
        View view = li.inflate(R.layout.layout_help, null); 
 | 
			
		||||
        
 | 
			
		||||
		new AlertDialog.Builder(this)
 | 
			
		||||
        .setTitle(getString(R.string.menu_info))
 | 
			
		||||
        .setView(view)
 | 
			
		||||
        .setNeutralButton(getString(R.string.button_about), new DialogInterface.OnClickListener() {
 | 
			
		||||
                public void onClick(DialogInterface dialog, int whichButton) {
 | 
			
		||||
                   
 | 
			
		||||
                	showAbout();
 | 
			
		||||
                }
 | 
			
		||||
        })
 | 
			
		||||
        .setNegativeButton(getString(R.string.button_close), new DialogInterface.OnClickListener() {
 | 
			
		||||
                public void onClick(DialogInterface dialog, int whichButton) {
 | 
			
		||||
                    //    Log.d(TAG, "Close pressed");
 | 
			
		||||
                }
 | 
			
		||||
        })
 | 
			
		||||
        .show();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Show the message log UI
 | 
			
		||||
	 */
 | 
			
		||||
	private void showMessageLog ()
 | 
			
		||||
	{
 | 
			
		||||
		currentView = R.layout.layout_log;
 | 
			
		||||
		setContentView(currentView);
 | 
			
		||||
		
 | 
			
		||||
		txtMessageLog = (TextView)findViewById(R.id.messageLog);
 | 
			
		||||
    	txtMessageLog.setText(logBuffer.toString());
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
		    
 | 
			
		||||
    
 | 
			
		||||
	
 | 
			
		||||
    /*
 | 
			
		||||
     * Load the basic settings application to display torrc
 | 
			
		||||
     */
 | 
			
		||||
	private void showSettings ()
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		startActivity(new Intent(this, SettingsPreferences.class));
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Read in the Preferences and write then to the .torrc file
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	private void processSettings ()
 | 
			
		||||
	{
 | 
			
		||||
		StringBuffer torrcText = new StringBuffer();
 | 
			
		||||
		
 | 
			
		||||
		torrcText.append(TorConstants.TORRC_DEFAULT);
 | 
			
		||||
		
 | 
			
		||||
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
 | 
			
		||||
		
 | 
			
		||||
		boolean useBridges = prefs.getBoolean(PREF_BRIDGES_ENABLED, false);
 | 
			
		||||
		
 | 
			
		||||
		boolean autoUpdateBridges = prefs.getBoolean(PREF_BRIDGES_UPDATED, false);
 | 
			
		||||
			
 | 
			
		||||
		String bridgeList = prefs.getString(PREF_BRIDGES_LIST,"");
 | 
			
		||||
 | 
			
		||||
		if (useBridges)
 | 
			
		||||
		{
 | 
			
		||||
			torrcText.append("UseBridges 1");
 | 
			
		||||
			torrcText.append('\n');		
 | 
			
		||||
 | 
			
		||||
			torrcText.append("UpdateBridgesFromAuthority ");
 | 
			
		||||
			
 | 
			
		||||
			if (autoUpdateBridges)
 | 
			
		||||
				torrcText.append("1");
 | 
			
		||||
			else
 | 
			
		||||
				torrcText.append("0");
 | 
			
		||||
			
 | 
			
		||||
			torrcText.append('\n');		
 | 
			
		||||
			
 | 
			
		||||
			String bridgeDelim = "\n";
 | 
			
		||||
			
 | 
			
		||||
			if (bridgeList.indexOf(",") != -1)
 | 
			
		||||
			{
 | 
			
		||||
				bridgeDelim = ",";
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			StringTokenizer st = new StringTokenizer(bridgeList,bridgeDelim);
 | 
			
		||||
			while (st.hasMoreTokens())
 | 
			
		||||
			{
 | 
			
		||||
				torrcText.append("bridge ");
 | 
			
		||||
				torrcText.append(st.nextToken());
 | 
			
		||||
				torrcText.append('\n');		
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			torrcText.append("UseBridges 0");
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		Utils.saveTextFile(TorServiceConstants.TORRC_INSTALL_PATH, torrcText.toString());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
    /*
 | 
			
		||||
     * Set the state of the running/not running graphic and label
 | 
			
		||||
     */
 | 
			
		||||
    public void updateStatus (String torServiceMsg)
 | 
			
		||||
    {
 | 
			
		||||
    	try
 | 
			
		||||
    	{
 | 
			
		||||
    		
 | 
			
		||||
    		if (mService != null)
 | 
			
		||||
    			torStatus = mService.getStatus();
 | 
			
		||||
	    	
 | 
			
		||||
 | 
			
		||||
	    	if (imgStatus != null)
 | 
			
		||||
	    	{
 | 
			
		||||
	    		
 | 
			
		||||
		    	if (torStatus == STATUS_ON)
 | 
			
		||||
		    	{
 | 
			
		||||
		    		imgStatus.setImageResource(R.drawable.toron);
 | 
			
		||||
		    	
 | 
			
		||||
		    		lblStatus.setText(getString(R.string.status_activated));
 | 
			
		||||
		    		
 | 
			
		||||
		    		if (progressDialog != null)
 | 
			
		||||
		    		{
 | 
			
		||||
		    			
 | 
			
		||||
		    			progressDialog.cancel();
 | 
			
		||||
		    			progressDialog.hide();
 | 
			
		||||
		    			progressDialog = null;
 | 
			
		||||
		    		}
 | 
			
		||||
		    		
 | 
			
		||||
		    		if (torServiceMsg != null && torServiceMsg.length()>0)
 | 
			
		||||
		    			Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show();
 | 
			
		||||
		    		
 | 
			
		||||
		    	
 | 
			
		||||
		    	}
 | 
			
		||||
		    	else if (torStatus == STATUS_CONNECTING)
 | 
			
		||||
		    	{
 | 
			
		||||
		    		
 | 
			
		||||
		    		imgStatus.setImageResource(R.drawable.torstarting);
 | 
			
		||||
		    		lblStatus.setText(getString(R.string.status_starting_up));
 | 
			
		||||
		    		
 | 
			
		||||
		    		if (progressDialog == null)
 | 
			
		||||
		    		{
 | 
			
		||||
			    		progressDialog = new ProgressDialog(this);
 | 
			
		||||
			    		progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
 | 
			
		||||
			    		progressDialog.setCancelable(true);
 | 
			
		||||
			    		progressDialog.setMessage(getString(R.string.status_starting_up));
 | 
			
		||||
			    		progressDialog.show();
 | 
			
		||||
			    		
 | 
			
		||||
			    		progressDialog.setProgress(10);
 | 
			
		||||
 | 
			
		||||
		    		}
 | 
			
		||||
		    			
 | 
			
		||||
	    			progressDialog.setMessage(torServiceMsg);
 | 
			
		||||
	    			
 | 
			
		||||
	    			int idx = torServiceMsg.indexOf("%");
 | 
			
		||||
	    			
 | 
			
		||||
	    			if (idx != -1)
 | 
			
		||||
	    			{	
 | 
			
		||||
	    				String pComp = torServiceMsg.substring(idx-2,idx).trim();
 | 
			
		||||
	    				int ipComp = Integer.parseInt(pComp);
 | 
			
		||||
	    				progressDialog.setProgress(ipComp);
 | 
			
		||||
	    			}
 | 
			
		||||
		    			
 | 
			
		||||
		    	}
 | 
			
		||||
		    	else if (torStatus == STATUS_UNAVAILABLE)
 | 
			
		||||
		    	{
 | 
			
		||||
		    		imgStatus.setImageResource(R.drawable.torstopping);
 | 
			
		||||
		    		lblStatus.setText(getString(R.string.status_shutting_down));
 | 
			
		||||
		    		
 | 
			
		||||
		    		if (torServiceMsg != null && torServiceMsg.length()>0)
 | 
			
		||||
		    			Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show();
 | 
			
		||||
		    		
 | 
			
		||||
		    	
 | 
			
		||||
		    		
 | 
			
		||||
		    	}
 | 
			
		||||
		    	else
 | 
			
		||||
		    	{
 | 
			
		||||
 | 
			
		||||
		    		if (torServiceMsg != null && torServiceMsg.length()>0)
 | 
			
		||||
		    			Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show();
 | 
			
		||||
		    		
 | 
			
		||||
		    	
 | 
			
		||||
		    		if (progressDialog != null)
 | 
			
		||||
		    		{
 | 
			
		||||
		    			
 | 
			
		||||
		    			progressDialog.cancel();
 | 
			
		||||
		    			progressDialog.hide();
 | 
			
		||||
		    			progressDialog = null;
 | 
			
		||||
		    		}
 | 
			
		||||
		    		
 | 
			
		||||
		    		
 | 
			
		||||
		    		imgStatus.setImageResource(R.drawable.toroff);
 | 
			
		||||
		    		lblStatus.setText(getString(R.string.status_disabled));
 | 
			
		||||
		    		
 | 
			
		||||
		    	}
 | 
			
		||||
	    	}
 | 
			
		||||
		    	
 | 
			
		||||
    	}
 | 
			
		||||
    	catch (RemoteException e)
 | 
			
		||||
    	{
 | 
			
		||||
    		e.printStackTrace();
 | 
			
		||||
    	}
 | 
			
		||||
    	
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /*
 | 
			
		||||
     * (non-Javadoc)
 | 
			
		||||
     * @see android.view.View.OnClickListener#onClick(android.view.View)
 | 
			
		||||
     */
 | 
			
		||||
	public void onClick(View view) {
 | 
			
		||||
		
 | 
			
		||||
		// the start button
 | 
			
		||||
		if (view.getId()==R.id.imgStatus || view.getId()==R.id.lblStatus)
 | 
			
		||||
		{
 | 
			
		||||
			try
 | 
			
		||||
			{
 | 
			
		||||
				if (mService == null)
 | 
			
		||||
				{
 | 
			
		||||
				
 | 
			
		||||
				}
 | 
			
		||||
				else if (mService.getStatus() == STATUS_REQUIRES_DEMAND)
 | 
			
		||||
				{
 | 
			
		||||
					processSettings();
 | 
			
		||||
					mService.setProfile(PROFILE_ON);
 | 
			
		||||
 | 
			
		||||
					if (hasRoot)
 | 
			
		||||
					{
 | 
			
		||||
						TorRoot.enableDNSProxying();
 | 
			
		||||
						TorRoot.enabledWebProxying();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					
 | 
			
		||||
					mService.setProfile(PROFILE_ONDEMAND);	
 | 
			
		||||
				
 | 
			
		||||
					if (hasRoot)
 | 
			
		||||
					{
 | 
			
		||||
						TorRoot.purgeNatIptables();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			catch (Exception e)
 | 
			
		||||
			{
 | 
			
		||||
				Log.i(TAG,"error onclick",e);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
    /**
 | 
			
		||||
     * This implementation is used to receive callbacks from the remote
 | 
			
		||||
     * service.
 | 
			
		||||
     */
 | 
			
		||||
    private ITorServiceCallback mCallback = new ITorServiceCallback.Stub() {
 | 
			
		||||
        /**
 | 
			
		||||
         * This is called by the remote service regularly to tell us about
 | 
			
		||||
         * new values.  Note that IPC calls are dispatched through a thread
 | 
			
		||||
         * pool running in each process, so the code executing here will
 | 
			
		||||
         * NOT be running in our main thread like most other things -- so,
 | 
			
		||||
         * to update the UI, we need to use a Handler to hop over there.
 | 
			
		||||
         */
 | 
			
		||||
        public void statusChanged(String value) {
 | 
			
		||||
           
 | 
			
		||||
        	Message msg = mHandler.obtainMessage(BUMP_MSG);
 | 
			
		||||
        	msg.getData().putString(HANDLER_TOR_MSG, value);
 | 
			
		||||
        	mHandler.sendMessage(msg);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    private static final int BUMP_MSG = 1;
 | 
			
		||||
    
 | 
			
		||||
    	
 | 
			
		||||
    private Handler mHandler = new Handler() {
 | 
			
		||||
        @Override public void handleMessage(Message msg) {
 | 
			
		||||
            switch (msg.what) {
 | 
			
		||||
                case BUMP_MSG:
 | 
			
		||||
 | 
			
		||||
                	String torServiceMsg = (String)msg.getData().getString(HANDLER_TOR_MSG);
 | 
			
		||||
                	
 | 
			
		||||
                	logBuffer.append(torServiceMsg);
 | 
			
		||||
                	logBuffer.append('\n');
 | 
			
		||||
                	
 | 
			
		||||
                	updateStatus(torServiceMsg);
 | 
			
		||||
                	
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    super.handleMessage(msg);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Class for interacting with the main interface of the service.
 | 
			
		||||
     */
 | 
			
		||||
    private ServiceConnection mConnection = new ServiceConnection() {
 | 
			
		||||
        public void onServiceConnected(ComponentName className,
 | 
			
		||||
                IBinder service) {
 | 
			
		||||
            // This is called when the connection with the service has been
 | 
			
		||||
            // established, giving us the service object we can use to
 | 
			
		||||
            // interact with the service.  We are communicating with our
 | 
			
		||||
            // service through an IDL interface, so get a client-side
 | 
			
		||||
            // representation of that from the raw service object.
 | 
			
		||||
            mService = ITorService.Stub.asInterface(service);
 | 
			
		||||
       
 | 
			
		||||
            updateStatus ("");
 | 
			
		||||
            
 | 
			
		||||
            // We want to monitor the service for as long as we are
 | 
			
		||||
            // connected to it.
 | 
			
		||||
            try {
 | 
			
		||||
                mService.registerCallback(mCallback);
 | 
			
		||||
            } catch (RemoteException e) {
 | 
			
		||||
                // In this case the service has crashed before we could even
 | 
			
		||||
                // do anything with it; we can count on soon being
 | 
			
		||||
                // disconnected (and then reconnected if it can be restarted)
 | 
			
		||||
                // so there is no need to do anything here.
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
          
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void onServiceDisconnected(ComponentName className) {
 | 
			
		||||
            // This is called when the connection with the service has been
 | 
			
		||||
            // unexpectedly disconnected -- that is, its process crashed.
 | 
			
		||||
            mService = null;
 | 
			
		||||
          
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    boolean mIsBound = false;
 | 
			
		||||
    boolean hasRoot = false;
 | 
			
		||||
    
 | 
			
		||||
    private void bindService ()
 | 
			
		||||
    {
 | 
			
		||||
    	 bindService(new Intent(ITorService.class.getName()),
 | 
			
		||||
                 mConnection, Context.BIND_AUTO_CREATE);
 | 
			
		||||
    	 
 | 
			
		||||
    	 mIsBound = true;
 | 
			
		||||
    
 | 
			
		||||
    	 hasRoot = TorRoot.hasRootAccess();
 | 
			
		||||
 | 
			
		||||
    	
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void unbindService ()
 | 
			
		||||
    {
 | 
			
		||||
    	if (mIsBound) {
 | 
			
		||||
            // If we have received the service, and hence registered with
 | 
			
		||||
            // it, then now is the time to unregister.
 | 
			
		||||
            if (mService != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    mService.unregisterCallback(mCallback);
 | 
			
		||||
                } catch (RemoteException e) {
 | 
			
		||||
                    // There is nothing special we need to do if the service
 | 
			
		||||
                    // has crashed.
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Detach our existing connection.
 | 
			
		||||
            unbindService(mConnection);
 | 
			
		||||
            mIsBound = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
 | 
			
		||||
package org.torproject.android;
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.preference.PreferenceActivity;
 | 
			
		||||
 | 
			
		||||
public class SettingsPreferences 
 | 
			
		||||
		extends PreferenceActivity {
 | 
			
		||||
 | 
			
		||||
	protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
		super.onCreate(savedInstanceState);
 | 
			
		||||
		addPreferencesFromResource(R.xml.preferences);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,75 +1,37 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* Copyright (c) 2009, Nathan Freitas, Orbot/The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
 | 
			
		||||
package org.torproject.android;
 | 
			
		||||
 | 
			
		||||
public interface TorConstants {
 | 
			
		||||
 | 
			
		||||
	//home directory of Android application
 | 
			
		||||
	public final static String TOR_HOME = "/data/data/org.torproject.android/";
 | 
			
		||||
	public final static String TAG = "Orbot";
 | 
			
		||||
 | 
			
		||||
	//name of the tor C binary
 | 
			
		||||
	public final static String TOR_BINARY_ASSET_KEY = "tor";	
 | 
			
		||||
	
 | 
			
		||||
	//path to install the Tor binary too
 | 
			
		||||
	public final static String TOR_BINARY_INSTALL_PATH = TOR_HOME + TOR_BINARY_ASSET_KEY;
 | 
			
		||||
	
 | 
			
		||||
	//key of the tor binary in the Zip file
 | 
			
		||||
	public final static String TOR_BINARY_ZIP_KEY = "assets/" + TOR_BINARY_ASSET_KEY;
 | 
			
		||||
	
 | 
			
		||||
	//torrc file name
 | 
			
		||||
	public final static String TORRC_ASSET_KEY = "torrc";
 | 
			
		||||
	
 | 
			
		||||
	//path to install torrc to within the android app data folder
 | 
			
		||||
	public final static String TORRC_INSTALL_PATH = TOR_HOME + TORRC_ASSET_KEY;
 | 
			
		||||
	
 | 
			
		||||
	//key of the torrc file in the Zip file
 | 
			
		||||
	public final static String TORRC_ZIP_KEY = "assets/" + TORRC_ASSET_KEY;
 | 
			
		||||
 | 
			
		||||
	//where to send the notices log
 | 
			
		||||
	public final static String TOR_LOG_PATH = TOR_HOME + "notices.log";
 | 
			
		||||
	
 | 
			
		||||
	//control port cookie path
 | 
			
		||||
	public final static String TOR_CONTROL_AUTH_COOKIE = TOR_HOME + "data/control_auth_cookie";
 | 
			
		||||
 | 
			
		||||
	//how to launch tor
 | 
			
		||||
	public final static String TOR_COMMAND_LINE_ARGS = "-f " + TORRC_INSTALL_PATH;
 | 
			
		||||
	
 | 
			
		||||
	//various console cmds
 | 
			
		||||
	public final static String SHELL_CMD_CHMOD = "/system/bin/chmod";
 | 
			
		||||
	public final static String SHELL_CMD_KILL = "/system/bin/kill";
 | 
			
		||||
	public final static String SHELL_CMD_RM = "/system/bin/rm";
 | 
			
		||||
	public final static String SHELL_CMD_PS = "ps";
 | 
			
		||||
	public final static String CHMOD_EXE_VALUE = "777";
 | 
			
		||||
	
 | 
			
		||||
	//path of the installed APK file
 | 
			
		||||
	public final static String APK_PATH = "/data/app/org.torproject.android.apk";
 | 
			
		||||
	public final static int FILE_WRITE_BUFFER_SIZE = 2048;
 | 
			
		||||
	
 | 
			
		||||
	//path to check Tor against
 | 
			
		||||
	public final static String URL_TOR_CHECK = "http://check.torproject.org";
 | 
			
		||||
	
 | 
			
		||||
	public final static int FILE_WRITE_BUFFER_SIZE = 2048;
 | 
			
		||||
	
 | 
			
		||||
	//HTTP Proxy server port
 | 
			
		||||
	public final static int PORT_HTTP = 8118; //just like Privoxy!
 | 
			
		||||
	
 | 
			
		||||
	//Socks port client connects to, server is the Tor binary
 | 
			
		||||
	public final static int PORT_SOCKS = 9050;
 | 
			
		||||
	
 | 
			
		||||
	//what is says!
 | 
			
		||||
	public final static String IP_LOCALHOST = "127.0.0.1";
 | 
			
		||||
	public final static int TOR_CONTROL_PORT = 9051;
 | 
			
		||||
	public final static int UPDATE_TIMEOUT = 3000;
 | 
			
		||||
	
 | 
			
		||||
	public final static String DEFAULT_HOME_PAGE = "file:///android_asset/help.html";// "http://check.torproject.org";
 | 
			
		||||
	
 | 
			
		||||
	//status to communicate state
 | 
			
		||||
    public final static int STATUS_OFF = 0;
 | 
			
		||||
    public final static int STATUS_UNAVAILABLE = -1;
 | 
			
		||||
    public final static int STATUS_REQUIRES_DEMAND = 0;
 | 
			
		||||
    public final static int STATUS_ON = 1;
 | 
			
		||||
    public final static int STATUS_STARTING_UP = 2;
 | 
			
		||||
    public final static int STATUS_SHUTTING_DOWN = 3;
 | 
			
		||||
    public final static int STATUS_CONNECTING = 2;
 | 
			
		||||
    
 | 
			
		||||
    //control port 
 | 
			
		||||
    public final static String TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE = "Bootstrapped 100%";
 | 
			
		||||
    public final static int PROFILE_OFF = -1;
 | 
			
		||||
    public final static int PROFILE_ONDEMAND = 0;
 | 
			
		||||
    public final static int PROFILE_ON = 1;
 | 
			
		||||
    
 | 
			
		||||
    public final static String NEWLINE = "\n";
 | 
			
		||||
    
 | 
			
		||||
    public final static String TORRC_DEFAULT = 
 | 
			
		||||
    		"SocksPort 9050\nSocksListenAddress 127.0.0.1\nSafeSocks 1\nDNSPort 5400\nLog notice stdout\nLog debug syslog\nDataDirectory /data/data/org.torproject.android/data\n"
 | 
			
		||||
    	+ "ControlPort 9051\nCookieAuthentication 1\nRelayBandwidthRate 20 KBytes\nRelayBandwidthBurst 20 KBytes\n";
 | 
			
		||||
    	
 | 
			
		||||
    public final static String INTENT_TOR_SERVICE = "org.torproject.android.service.TOR_SERVICE";
 | 
			
		||||
    	
 | 
			
		||||
    public final static String HANDLER_TOR_MSG = "torServiceMsg";
 | 
			
		||||
	
 | 
			
		||||
	public final static String PREF_BRIDGES_ENABLED = "pref_bridges_enabled";
 | 
			
		||||
	public final static String PREF_BRIDGES_UPDATED = "pref_bridges_enabled";
 | 
			
		||||
	public final static String PREF_BRIDGES_LIST = "pref_bridges_list";
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,587 +0,0 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
 | 
			
		||||
package org.torproject.android;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileReader;
 | 
			
		||||
import java.io.FileWriter;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import net.freehaven.tor.control.EventHandler;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.os.Handler;
 | 
			
		||||
import android.os.Message;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.view.KeyEvent;
 | 
			
		||||
import android.view.Menu;
 | 
			
		||||
import android.view.MenuItem;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.view.View.OnClickListener;
 | 
			
		||||
import android.webkit.JsResult;
 | 
			
		||||
import android.webkit.WebChromeClient;
 | 
			
		||||
import android.webkit.WebSettings;
 | 
			
		||||
import android.webkit.WebView;
 | 
			
		||||
import android.widget.Button;
 | 
			
		||||
import android.widget.ImageView;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
public class TorControlPanel extends Activity implements OnClickListener, TorConstants, EventHandler
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	private final static String TAG = "Tor";
 | 
			
		||||
	
 | 
			
		||||
	private static Intent torService = null;
 | 
			
		||||
	
 | 
			
		||||
	private boolean updateLog = false;
 | 
			
		||||
	private boolean updateStatus = false;
 | 
			
		||||
	
 | 
			
		||||
	private TextView lblStatus = null;
 | 
			
		||||
	private ImageView imgStatus = null;
 | 
			
		||||
	private String txtStatus = "";
 | 
			
		||||
	private int torStatus = STATUS_OFF;
 | 
			
		||||
	
 | 
			
		||||
	private Thread threadStatus = null;
 | 
			
		||||
	
 | 
			
		||||
    private WebView mWebView;
 | 
			
		||||
 | 
			
		||||
	private int currentView = 0;
 | 
			
		||||
	
 | 
			
		||||
    /** Called when the activity is first created. */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
    	setTheme(android.R.style.Theme_Black);
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        showMain();
 | 
			
		||||
 | 
			
		||||
      
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    public boolean onCreateOptionsMenu(Menu menu) {
 | 
			
		||||
        super.onCreateOptionsMenu(menu);
 | 
			
		||||
        
 | 
			
		||||
        MenuItem mItem = menu.add(0, 1, Menu.NONE, "Home");
 | 
			
		||||
        MenuItem mItem2 = menu.add(0, 2, Menu.NONE, "Settings");
 | 
			
		||||
        MenuItem mItem3 = menu.add(0, 3, Menu.NONE, "Log");
 | 
			
		||||
       MenuItem mItem4 = menu.add(0, 4, Menu.NONE, "Help");
 | 
			
		||||
       
 | 
			
		||||
      mItem.setIcon(R.drawable.ic_menu_home);
 | 
			
		||||
       mItem2.setIcon(R.drawable.ic_menu_register);
 | 
			
		||||
       mItem3.setIcon(R.drawable.ic_menu_reports);
 | 
			
		||||
       mItem4.setIcon(R.drawable.ic_menu_about);
 | 
			
		||||
       
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onMenuItemSelected(int, android.view.MenuItem)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
 | 
			
		||||
		
 | 
			
		||||
		super.onMenuItemSelected(featureId, item);
 | 
			
		||||
		
 | 
			
		||||
		if (item.getItemId() == 1)
 | 
			
		||||
		{
 | 
			
		||||
			this.showMain();
 | 
			
		||||
		}
 | 
			
		||||
		else if (item.getItemId() == 2)
 | 
			
		||||
		{
 | 
			
		||||
			this.showSettings();
 | 
			
		||||
		}
 | 
			
		||||
		else if (item.getItemId() == 3)
 | 
			
		||||
		{
 | 
			
		||||
			this.showMessageLog();
 | 
			
		||||
		}
 | 
			
		||||
		else if (item.getItemId() == 4)
 | 
			
		||||
		{
 | 
			
		||||
			this.showWeb(DEFAULT_HOME_PAGE);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
        return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public boolean onKeyDown(int keyCode, KeyEvent event){
 | 
			
		||||
		if(keyCode==KeyEvent.KEYCODE_BACK){
 | 
			
		||||
			if(currentView != R.layout.layout_main){
 | 
			
		||||
					
 | 
			
		||||
					showMain ();
 | 
			
		||||
					
 | 
			
		||||
					return true;
 | 
			
		||||
			}
 | 
			
		||||
			else{
 | 
			
		||||
				return super.onKeyDown(keyCode, event);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
		return super.onKeyDown(keyCode, event);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
    /* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onPause()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onPause() {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		super.onPause();
 | 
			
		||||
		
 | 
			
		||||
		TorService.setStatus(torStatus);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onResume()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onResume() {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		super.onResume();
 | 
			
		||||
		
 | 
			
		||||
		torStatus = TorService.getStatus();
 | 
			
		||||
		
 | 
			
		||||
		updateStatus ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onStart()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onStart() {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		super.onStart();
 | 
			
		||||
		
 | 
			
		||||
		torStatus = TorService.getStatus();
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		updateStatus ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Activity#onStop()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	protected void onStop() {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		super.onStop();
 | 
			
		||||
		
 | 
			
		||||
		TorService.setStatus(torStatus);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Show the main form UI
 | 
			
		||||
	 */
 | 
			
		||||
	private void showMain ()
 | 
			
		||||
    {
 | 
			
		||||
		updateLog = false;
 | 
			
		||||
		updateStatus = true;
 | 
			
		||||
		
 | 
			
		||||
		currentView = R.layout.layout_main;
 | 
			
		||||
    	setContentView(currentView);
 | 
			
		||||
    	
 | 
			
		||||
    	findViewById(R.id.imgStatus).setOnClickListener(this);
 | 
			
		||||
    	
 | 
			
		||||
    	lblStatus = (TextView)findViewById(R.id.lblStatus);
 | 
			
		||||
    	imgStatus = (ImageView)findViewById(R.id.imgStatus);
 | 
			
		||||
    	
 | 
			
		||||
    	updateStatus();
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
	private void showWeb (String url)
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
		currentView =R.layout.layout_web;
 | 
			
		||||
		 setContentView(currentView);
 | 
			
		||||
	        
 | 
			
		||||
	        mWebView = (WebView) findViewById(R.id.webview);
 | 
			
		||||
 | 
			
		||||
	        WebSettings webSettings = mWebView.getSettings();
 | 
			
		||||
	        webSettings.setSavePassword(false);
 | 
			
		||||
	        webSettings.setSaveFormData(false);
 | 
			
		||||
	        webSettings.setJavaScriptEnabled(true);
 | 
			
		||||
	      
 | 
			
		||||
 | 
			
		||||
	        mWebView.setWebChromeClient(new MyWebChromeClient());
 | 
			
		||||
	        
 | 
			
		||||
	        mWebView.loadUrl(url);
 | 
			
		||||
	
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Show the message log UI
 | 
			
		||||
	 */
 | 
			
		||||
	private void showMessageLog ()
 | 
			
		||||
	{
 | 
			
		||||
		currentView = R.layout.layout_log;
 | 
			
		||||
		setContentView(currentView);
 | 
			
		||||
		((Button)findViewById(R.id.btnLogClear)).setOnClickListener(this);
 | 
			
		||||
 | 
			
		||||
		updateStatus = false;
 | 
			
		||||
		updateLog = true;
 | 
			
		||||
		
 | 
			
		||||
		Thread thread = new Thread ()
 | 
			
		||||
		{
 | 
			
		||||
			public void run ()
 | 
			
		||||
			{
 | 
			
		||||
				
 | 
			
		||||
				while (updateLog)
 | 
			
		||||
				{
 | 
			
		||||
					
 | 
			
		||||
					try {
 | 
			
		||||
						Thread.sleep(UPDATE_TIMEOUT);
 | 
			
		||||
					} catch (InterruptedException e) {
 | 
			
		||||
						// TODO Auto-generated catch block
 | 
			
		||||
						e.printStackTrace();
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
					handler.sendEmptyMessage(0);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		thread.start();
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Load the Tor log and display it in a text field
 | 
			
		||||
	 */
 | 
			
		||||
	private void updateMessageLog ()
 | 
			
		||||
	{
 | 
			
		||||
				
 | 
			
		||||
		TextView tvLog = (TextView)findViewById(R.id.messageLog);
 | 
			
		||||
    	
 | 
			
		||||
		if (tvLog != null)
 | 
			
		||||
		{
 | 
			
		||||
			String output = loadTextFile(TOR_LOG_PATH);
 | 
			
		||||
		
 | 
			
		||||
			tvLog.setText(output);
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Handle to reload Tor debug log every few seconds while viewing it
 | 
			
		||||
	 */
 | 
			
		||||
	private Handler handler = new Handler() {
 | 
			
		||||
	
 | 
			
		||||
	        @Override
 | 
			
		||||
		    public void handleMessage(Message msg) {
 | 
			
		||||
	
 | 
			
		||||
	        	updateMessageLog ();
 | 
			
		||||
	
 | 
			
		||||
	        }
 | 
			
		||||
	
 | 
			
		||||
	    };
 | 
			
		||||
	    
 | 
			
		||||
	    /*
 | 
			
		||||
		 * Handle to reload Tor debug log every few seconds while viewing it
 | 
			
		||||
		 */
 | 
			
		||||
		private Handler handlerStatus = new Handler() {
 | 
			
		||||
		
 | 
			
		||||
		        @Override
 | 
			
		||||
			    public void handleMessage(Message msg) {
 | 
			
		||||
		
 | 
			
		||||
		        	updateStatus();
 | 
			
		||||
		        	
 | 
			
		||||
		        	// Toast.makeText(this,txtStatus, Toast.LENGTH_SHORT).show();
 | 
			
		||||
		        }
 | 
			
		||||
		
 | 
			
		||||
		    };
 | 
			
		||||
		
 | 
			
		||||
	
 | 
			
		||||
    /*
 | 
			
		||||
     * Load the basic settings application to display torrc
 | 
			
		||||
     * TODO: these needs to be improved into an actual form GUI
 | 
			
		||||
     */
 | 
			
		||||
	private void showSettings ()
 | 
			
		||||
	{
 | 
			
		||||
		updateStatus = false;
 | 
			
		||||
		updateLog = false;
 | 
			
		||||
		
 | 
			
		||||
		currentView = R.layout.layout_settings;
 | 
			
		||||
		setContentView(currentView);
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		String output = loadTextFile(TORRC_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
		TextView tvSettings = (TextView)findViewById(R.id.textSettings);
 | 
			
		||||
    	((Button)findViewById(R.id.btnSettingsSave)).setOnClickListener(this);
 | 
			
		||||
		tvSettings.setText(output);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
    /*
 | 
			
		||||
     * Set the state of the running/not running graphic and label
 | 
			
		||||
     */
 | 
			
		||||
    public void updateStatus ()
 | 
			
		||||
    {
 | 
			
		||||
    	
 | 
			
		||||
    	if (imgStatus != null)
 | 
			
		||||
    	{
 | 
			
		||||
    		
 | 
			
		||||
	    	if (torStatus == STATUS_ON)
 | 
			
		||||
	    	{
 | 
			
		||||
	    		imgStatus.setImageResource(R.drawable.toron);
 | 
			
		||||
	    		lblStatus.setText("ORbot is running\n- touch the bot to stop -");
 | 
			
		||||
	    		updateStatus = false;
 | 
			
		||||
	    	}
 | 
			
		||||
	    	else if (torStatus == STATUS_STARTING_UP)
 | 
			
		||||
	    	{
 | 
			
		||||
	    		imgStatus.setImageResource(R.drawable.torstarting);
 | 
			
		||||
	    		
 | 
			
		||||
	    		lblStatus.setText("ORbot reports:\n\"" + txtStatus + "\"");
 | 
			
		||||
	    		
 | 
			
		||||
	    	
 | 
			
		||||
	    	}
 | 
			
		||||
	    	else if (torStatus == STATUS_SHUTTING_DOWN)
 | 
			
		||||
	    	{
 | 
			
		||||
	    		imgStatus.setImageResource(R.drawable.torstopping);
 | 
			
		||||
	    		lblStatus.setText("ORbot is shutting down\nplease wait...");
 | 
			
		||||
	    		
 | 
			
		||||
	    	}
 | 
			
		||||
	    	else
 | 
			
		||||
	    	{
 | 
			
		||||
	    		imgStatus.setImageResource(R.drawable.toroff);
 | 
			
		||||
	    		lblStatus.setText("ORbot is not running\n- touch the bot to start -");
 | 
			
		||||
	    		updateStatus = false;
 | 
			
		||||
	    	}
 | 
			
		||||
    	}
 | 
			
		||||
    	
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /*
 | 
			
		||||
     * (non-Javadoc)
 | 
			
		||||
     * @see android.view.View.OnClickListener#onClick(android.view.View)
 | 
			
		||||
     */
 | 
			
		||||
	public void onClick(View view) {
 | 
			
		||||
		
 | 
			
		||||
		// the start button
 | 
			
		||||
		if (view.getId()==R.id.imgStatus)
 | 
			
		||||
		{
 | 
			
		||||
			//if Tor binary is not running, then start the service up
 | 
			
		||||
			if (TorService.getStatus()==STATUS_OFF)
 | 
			
		||||
			{
 | 
			
		||||
				torStatus = STATUS_STARTING_UP;
 | 
			
		||||
				txtStatus = "Connecting to Tor...";
 | 
			
		||||
				updateStatus();
 | 
			
		||||
				
 | 
			
		||||
				startTorService ();
 | 
			
		||||
				
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				
 | 
			
		||||
				torStatus = STATUS_SHUTTING_DOWN;
 | 
			
		||||
				updateStatus();
 | 
			
		||||
				
 | 
			
		||||
				stopService(torService);
 | 
			
		||||
				
 | 
			
		||||
				torStatus = STATUS_OFF;
 | 
			
		||||
				
 | 
			
		||||
				updateStatus();
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
		else if (view.getId()==R.id.btnLogClear)
 | 
			
		||||
		{
 | 
			
		||||
		
 | 
			
		||||
			saveTextFile(TOR_LOG_PATH,"");
 | 
			
		||||
		}
 | 
			
		||||
		else if (view.getId()==R.id.btnSettingsSave)
 | 
			
		||||
		{
 | 
			
		||||
		
 | 
			
		||||
			TextView tvSettings = (TextView)findViewById(R.id.textSettings);
 | 
			
		||||
			String newSettings =  tvSettings.getText().toString();
 | 
			
		||||
			saveTextFile(TORRC_INSTALL_PATH, newSettings);
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private void startTorService ()
 | 
			
		||||
	{
 | 
			
		||||
		if (torService == null)
 | 
			
		||||
		{
 | 
			
		||||
			torService = new Intent(this, TorService.class);
 | 
			
		||||
			//torService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 | 
			
		||||
			TorService.setActivity(this);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		startService(torService);
 | 
			
		||||
		
 | 
			
		||||
	
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Load the log file text
 | 
			
		||||
	 */
 | 
			
		||||
	 public static String loadTextFile (String path)
 | 
			
		||||
	    {
 | 
			
		||||
	    	String line = null;
 | 
			
		||||
	    
 | 
			
		||||
	    	StringBuffer out = new StringBuffer();
 | 
			
		||||
	    	
 | 
			
		||||
	    	try {
 | 
			
		||||
		    	BufferedReader reader = new BufferedReader((new FileReader(new File(path))));
 | 
			
		||||
 | 
			
		||||
				while ((line = reader.readLine()) != null)
 | 
			
		||||
				{
 | 
			
		||||
					out.append(line);
 | 
			
		||||
					out.append('\n');
 | 
			
		||||
					
 | 
			
		||||
				}
 | 
			
		||||
			} catch (IOException e) {
 | 
			
		||||
				// TODO Auto-generated catch block
 | 
			
		||||
				e.printStackTrace();
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			return out.toString();
 | 
			
		||||
	    	
 | 
			
		||||
	    }
 | 
			
		||||
	 
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Load the log file text
 | 
			
		||||
		 */
 | 
			
		||||
		 public static boolean saveTextFile (String path, String contents)
 | 
			
		||||
		    {
 | 
			
		||||
			 	
 | 
			
		||||
		    	try {
 | 
			
		||||
		    		
 | 
			
		||||
		    		 FileWriter writer = new FileWriter( path, false );
 | 
			
		||||
                     writer.write( contents );
 | 
			
		||||
                     
 | 
			
		||||
                     writer.close();
 | 
			
		||||
 | 
			
		||||
                     
 | 
			
		||||
		    		
 | 
			
		||||
		    		return true;
 | 
			
		||||
			    	
 | 
			
		||||
				} catch (IOException e) {
 | 
			
		||||
				//	Log.i(TAG, "error writing file: " + path, e);
 | 
			
		||||
						e.printStackTrace();
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				
 | 
			
		||||
		    	
 | 
			
		||||
		    }
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void bandwidthUsed(long read, long written) {
 | 
			
		||||
		Log.i(TAG,"BW Used: read=" + read + " written=" + written);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void circuitStatus(String status, String circID, String path) {
 | 
			
		||||
		Log.i(TAG,"CircuitStatus=" + status + ": " + circID);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void message(String severity, String msg) {
 | 
			
		||||
		
 | 
			
		||||
        	 // Log.println(priority, tag, msg)("["+severity+"] "+msg);
 | 
			
		||||
              //Toast.makeText(, text, duration)
 | 
			
		||||
        //      Toast.makeText(ACTIVITY, severity + ": " + msg, Toast.LENGTH_SHORT);
 | 
			
		||||
              Log.i(TAG, "[Tor Control Port] " + severity + ": " + msg);
 | 
			
		||||
              
 | 
			
		||||
              if (msg.indexOf(TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)!=-1)
 | 
			
		||||
              {
 | 
			
		||||
            	  torStatus = STATUS_ON;
 | 
			
		||||
            	  
 | 
			
		||||
            	  
 | 
			
		||||
            	  
 | 
			
		||||
            	  //setupWebProxy(true);
 | 
			
		||||
 | 
			
		||||
              }
 | 
			
		||||
              
 | 
			
		||||
      
 | 
			
		||||
              txtStatus = msg;
 | 
			
		||||
              handlerStatus.sendEmptyMessage(0);
 | 
			
		||||
	
 | 
			
		||||
             
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void newDescriptors(List<String> orList) {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void orConnStatus(String status, String orName) {
 | 
			
		||||
		
 | 
			
		||||
		Log.i(TAG,"OrConnStatus=" + status + ": " + orName);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void streamStatus(String status, String streamID, String target) {
 | 
			
		||||
		Log.i(TAG,"StreamStatus=" + status + ": " + streamID);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void unrecognized(String type, String msg) {
 | 
			
		||||
		Log.i(TAG,"unrecognized log=" + type + ": " + msg);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	 
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
     * Provides a hook for calling "alert" from javascript. Useful for
 | 
			
		||||
     * debugging your javascript.
 | 
			
		||||
     */
 | 
			
		||||
    final class MyWebChromeClient extends WebChromeClient {
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
 | 
			
		||||
            Log.d(TAG, message);
 | 
			
		||||
            result.confirm();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,617 +0,0 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
 | 
			
		||||
package org.torproject.android;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.FileReader;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.net.ConnectException;
 | 
			
		||||
import java.net.Socket;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.StringTokenizer;
 | 
			
		||||
import java.util.Timer;
 | 
			
		||||
import java.util.TimerTask;
 | 
			
		||||
 | 
			
		||||
import net.freehaven.tor.control.EventHandler;
 | 
			
		||||
import net.freehaven.tor.control.NullEventHandler;
 | 
			
		||||
import net.freehaven.tor.control.TorControlConnection;
 | 
			
		||||
import net.sourceforge.jsocks.socks.Proxy;
 | 
			
		||||
import android.app.Service;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.IBinder;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
import android.widget.Toast;
 | 
			
		||||
 | 
			
		||||
public class TorService extends Service implements TorConstants
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	private static TorControlPanel ACTIVITY = null;
 | 
			
		||||
	
 | 
			
		||||
	private final static String TAG = "TorService";
 | 
			
		||||
	
 | 
			
		||||
	private static HttpProxy webProxy = null;
 | 
			
		||||
	
 | 
			
		||||
	private static int currentStatus = STATUS_OFF;
 | 
			
		||||
	
 | 
			
		||||
	private TorControlConnection conn = null;
 | 
			
		||||
	
 | 
			
		||||
	private Timer timer = new Timer ();
 | 
			
		||||
	private final static int UPDATE_INTERVAL = 60000;
 | 
			
		||||
	
 | 
			
		||||
    /** Called when the activity is first created. */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate() {
 | 
			
		||||
    	super.onCreate();
 | 
			
		||||
       
 | 
			
		||||
    	Log.i(TAG,"TorService: onCreate");
 | 
			
		||||
    	
 | 
			
		||||
    	 timer.scheduleAtFixedRate(
 | 
			
		||||
    		      new TimerTask() {
 | 
			
		||||
    		        public void run() {
 | 
			
		||||
    		         
 | 
			
		||||
    		        	//do nothing
 | 
			
		||||
    		        //	Log.i(TAG,"TorService: task is running");
 | 
			
		||||
    		        }
 | 
			
		||||
    		      },
 | 
			
		||||
    		      0,
 | 
			
		||||
    		      UPDATE_INTERVAL);
 | 
			
		||||
    	 
 | 
			
		||||
    	 
 | 
			
		||||
    	 int procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
 		if (procId != -1)
 | 
			
		||||
 		{
 | 
			
		||||
 			Log.i(TAG,"Found existing Tor process");
 | 
			
		||||
 			
 | 
			
		||||
 			try {
 | 
			
		||||
 				currentStatus = STATUS_STARTING_UP;
 | 
			
		||||
				
 | 
			
		||||
 				initControlConnection();
 | 
			
		||||
				
 | 
			
		||||
				getTorStatus();
 | 
			
		||||
				
 | 
			
		||||
				if (webProxy != null)
 | 
			
		||||
				{
 | 
			
		||||
					if (webProxy.isRunning())
 | 
			
		||||
					{
 | 
			
		||||
						//do nothing
 | 
			
		||||
						Log.i(TAG, "Web Proxy is already running");
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
						//do nothing
 | 
			
		||||
						Log.i(TAG, "killing Web Proxy");
 | 
			
		||||
						webProxy.closeSocket();
 | 
			
		||||
						setupWebProxy(true);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else  //do something
 | 
			
		||||
				{
 | 
			
		||||
					setupWebProxy(true);
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				currentStatus = STATUS_ON;
 | 
			
		||||
				
 | 
			
		||||
			} catch (RuntimeException e) {
 | 
			
		||||
				Log.i(TAG,"Unable to connect to existing Tor instance,",e);
 | 
			
		||||
				currentStatus = STATUS_OFF;
 | 
			
		||||
				this.stopTor();
 | 
			
		||||
				
 | 
			
		||||
			} catch (Exception e) {
 | 
			
		||||
				Log.i(TAG,"Unable to connect to existing Tor instance,",e);
 | 
			
		||||
				currentStatus = STATUS_OFF;
 | 
			
		||||
				this.stopTor();
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
 		}
 | 
			
		||||
    	 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Service#onLowMemory()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onLowMemory() {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		super.onLowMemory();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Service#onUnbind(android.content.Intent)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean onUnbind(Intent intent) {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		return super.onUnbind(intent);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public static int getStatus ()
 | 
			
		||||
    {
 | 
			
		||||
    	
 | 
			
		||||
    	return currentStatus;
 | 
			
		||||
    	
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
	public static void setStatus (int newStatus)
 | 
			
		||||
	{
 | 
			
		||||
		currentStatus = newStatus;
 | 
			
		||||
	}
 | 
			
		||||
   
 | 
			
		||||
    
 | 
			
		||||
    /* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Service#onRebind(android.content.Intent)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onRebind(Intent intent) {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		super.onRebind(intent);
 | 
			
		||||
		
 | 
			
		||||
		  Log.i(TAG,"on rebind");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Service#onStart(android.content.Intent, int)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onStart(Intent intent, int startId) {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		super.onStart(intent, startId);
 | 
			
		||||
		
 | 
			
		||||
	     Log.i(TAG,"onStart called");
 | 
			
		||||
	     
 | 
			
		||||
		   initTor();
 | 
			
		||||
		   
 | 
			
		||||
		   setupWebProxy (true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
    public void onDestroy ()
 | 
			
		||||
    {
 | 
			
		||||
    	super.onDestroy();
 | 
			
		||||
    	
 | 
			
		||||
    	Log.i(TAG,"onDestroy called");
 | 
			
		||||
	     
 | 
			
		||||
    	if (timer != null) timer.cancel();
 | 
			
		||||
 | 
			
		||||
    	stopTor();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void stopTor ()
 | 
			
		||||
    {
 | 
			
		||||
    	currentStatus = STATUS_SHUTTING_DOWN;
 | 
			
		||||
    	
 | 
			
		||||
    	setupWebProxy(false);  
 | 
			
		||||
    			
 | 
			
		||||
		killTorProcess ();
 | 
			
		||||
				
 | 
			
		||||
		currentStatus = STATUS_OFF;
 | 
			
		||||
    	
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 
 | 
			
		||||
    public static void setActivity(TorControlPanel activity) {
 | 
			
		||||
    	ACTIVITY = activity;
 | 
			
		||||
    }
 | 
			
		||||
   
 | 
			
		||||
    private void setupWebProxy (boolean enabled)
 | 
			
		||||
    {
 | 
			
		||||
    	if (enabled)
 | 
			
		||||
    	{
 | 
			
		||||
    		
 | 
			
		||||
    		if (webProxy != null)
 | 
			
		||||
    		{
 | 
			
		||||
    			webProxy.closeSocket();
 | 
			
		||||
    			webProxy = null;
 | 
			
		||||
    			
 | 
			
		||||
    		}
 | 
			
		||||
    		
 | 
			
		||||
	    	Log.i(TAG,"Starting up Web Proxy on port: " + PORT_HTTP);
 | 
			
		||||
	    	//httpd s
 | 
			
		||||
	    	webProxy = new HttpProxy(PORT_HTTP);
 | 
			
		||||
	    	webProxy.setDoSocks(true);
 | 
			
		||||
	    	webProxy.start();
 | 
			
		||||
	    	
 | 
			
		||||
	    	//socks
 | 
			
		||||
	    	try
 | 
			
		||||
	    	{
 | 
			
		||||
	    		
 | 
			
		||||
	    		Proxy.setDefaultProxy(IP_LOCALHOST,PORT_SOCKS);
 | 
			
		||||
	    		
 | 
			
		||||
	    		
 | 
			
		||||
	    	}
 | 
			
		||||
	    	catch (Exception e)
 | 
			
		||||
	    	{
 | 
			
		||||
	    		Log.w(TAG,e.getMessage());
 | 
			
		||||
	    	}
 | 
			
		||||
	    	
 | 
			
		||||
	    	Log.i(TAG,"Web Proxy enabled...");
 | 
			
		||||
 | 
			
		||||
    	
 | 
			
		||||
	    	//Settings.System.putString(getContentResolver(), Settings.System.HTTP_PROXY, proxySetting);//enable proxy
 | 
			
		||||
	    	//	Settings.Secure.putString(getContentResolver(), Settings.Secure.HTTP_PROXY, proxySetting);//enable proxy
 | 
			
		||||
    		
 | 
			
		||||
    	}
 | 
			
		||||
    	else
 | 
			
		||||
    	{
 | 
			
		||||
	    	//Log.i(TAG,"Turning off Socks/Tor routing on Web Proxy");
 | 
			
		||||
 | 
			
		||||
    		if (webProxy != null)
 | 
			
		||||
    		{
 | 
			
		||||
    			//logNotice("Tor is disabled - browsing is not anonymous!");
 | 
			
		||||
    			//webProxy.setDoSocks(false);
 | 
			
		||||
    			
 | 
			
		||||
    			webProxy.closeSocket();
 | 
			
		||||
    			webProxy = null;
 | 
			
		||||
    			Log.i(TAG,"WebProxy ServerSocket closed");
 | 
			
		||||
    		}
 | 
			
		||||
    	}
 | 
			
		||||
    	
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void reloadConfig ()
 | 
			
		||||
    {
 | 
			
		||||
    	try
 | 
			
		||||
		{
 | 
			
		||||
	    	if (conn == null)
 | 
			
		||||
			{
 | 
			
		||||
				initControlConnection ();
 | 
			
		||||
			}
 | 
			
		||||
		
 | 
			
		||||
			if (conn != null)
 | 
			
		||||
			{
 | 
			
		||||
				 conn.signal("RELOAD");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
    	catch (Exception e)
 | 
			
		||||
    	{
 | 
			
		||||
    		Log.i(TAG,"Unable to reload configuration",e);
 | 
			
		||||
    	}
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void killTorProcess ()
 | 
			
		||||
    {
 | 
			
		||||
		
 | 
			
		||||
    	if (conn != null)
 | 
			
		||||
		{
 | 
			
		||||
			try {
 | 
			
		||||
				Log.i(TAG,"sending SHUTDOWN signal");
 | 
			
		||||
				conn.signal("SHUTDOWN");
 | 
			
		||||
			} catch (IOException e) {
 | 
			
		||||
				// TODO Auto-generated catch block
 | 
			
		||||
				Log.i(TAG,"error shutting down Tor via connection",e);
 | 
			
		||||
			}
 | 
			
		||||
			conn = null;
 | 
			
		||||
		}
 | 
			
		||||
    	
 | 
			
		||||
    	try {
 | 
			
		||||
			Thread.sleep(500);
 | 
			
		||||
		} catch (InterruptedException e) {
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
    	
 | 
			
		||||
		int procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
		while (procId != -1)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
			Log.i(TAG,"Found Tor PID=" + procId + " - killing now...");
 | 
			
		||||
			
 | 
			
		||||
			doCommand(SHELL_CMD_KILL, procId + "");
 | 
			
		||||
 | 
			
		||||
			procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
    }
 | 
			
		||||
   
 | 
			
		||||
    private static void logNotice (String msg)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    	Log.i(TAG, msg);
 | 
			
		||||
		
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void checkBinary ()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
		boolean binaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
 | 
			
		||||
		
 | 
			
		||||
		if (!binaryExists)
 | 
			
		||||
		{
 | 
			
		||||
			killTorProcess ();
 | 
			
		||||
			
 | 
			
		||||
			TorBinaryInstaller installer = new TorBinaryInstaller(); 
 | 
			
		||||
			installer.start(true);
 | 
			
		||||
		
 | 
			
		||||
			binaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
 | 
			
		||||
    		if (binaryExists)
 | 
			
		||||
    		{
 | 
			
		||||
    			logNotice("Tor binary installed!");
 | 
			
		||||
    			
 | 
			
		||||
    		}
 | 
			
		||||
    		else
 | 
			
		||||
    		{
 | 
			
		||||
    			logNotice("Tor binary install FAILED!");
 | 
			
		||||
    			return;
 | 
			
		||||
    		}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		Log.i(TAG,"Setting permission on Tor binary");
 | 
			
		||||
		doCommand(SHELL_CMD_CHMOD, CHMOD_EXE_VALUE + ' ' + TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void initTor ()
 | 
			
		||||
    {
 | 
			
		||||
    	try {
 | 
			
		||||
    		
 | 
			
		||||
    		currentStatus = STATUS_STARTING_UP;
 | 
			
		||||
 | 
			
		||||
    		killTorProcess ();
 | 
			
		||||
    		
 | 
			
		||||
    		checkBinary ();
 | 
			
		||||
    		
 | 
			
		||||
    		doCommand(SHELL_CMD_RM,TOR_LOG_PATH);
 | 
			
		||||
    		
 | 
			
		||||
    		Log.i(TAG,"Starting tor process");
 | 
			
		||||
    		doCommand(TOR_BINARY_INSTALL_PATH, TOR_COMMAND_LINE_ARGS);
 | 
			
		||||
		
 | 
			
		||||
    		int procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
    		if (procId == -1)
 | 
			
		||||
    		{
 | 
			
		||||
    			doCommand(TOR_BINARY_INSTALL_PATH, TOR_COMMAND_LINE_ARGS);
 | 
			
		||||
    			procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
    		}
 | 
			
		||||
    		
 | 
			
		||||
    		Log.i(TAG,"Tor process id=" + procId);
 | 
			
		||||
    		
 | 
			
		||||
    		currentStatus = STATUS_STARTING_UP;
 | 
			
		||||
    		logNotice("Tor is starting up...");
 | 
			
		||||
			
 | 
			
		||||
			Thread.sleep(500);
 | 
			
		||||
			initControlConnection ();
 | 
			
		||||
		
 | 
			
		||||
    	} catch (Exception e) {
 | 
			
		||||
			
 | 
			
		||||
			Log.w(TAG,"unable to start Tor Process",e);
 | 
			
		||||
		
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
    	
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static void logStream (InputStream is)
 | 
			
		||||
    {
 | 
			
		||||
    	BufferedReader reader = new BufferedReader(new InputStreamReader(is));
 | 
			
		||||
    	String line = null;
 | 
			
		||||
    
 | 
			
		||||
    	
 | 
			
		||||
    	try {
 | 
			
		||||
			while ((line = reader.readLine()) != null)
 | 
			
		||||
			{
 | 
			
		||||
				Log.i(TAG, line);
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
		} catch (IOException e) {
 | 
			
		||||
			// TODO Auto-generated catch block
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
    	
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
	public IBinder onBind(Intent arg0) {
 | 
			
		||||
		// TODO Auto-generated method stub
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static int findProcessId(String command) 
 | 
			
		||||
	{
 | 
			
		||||
		int procId = -1;
 | 
			
		||||
		
 | 
			
		||||
		Runtime r = Runtime.getRuntime();
 | 
			
		||||
		    	
 | 
			
		||||
		Process procPs = null;
 | 
			
		||||
		
 | 
			
		||||
        try {
 | 
			
		||||
            
 | 
			
		||||
            procPs = r.exec(SHELL_CMD_PS);
 | 
			
		||||
            
 | 
			
		||||
            BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
 | 
			
		||||
            String line = null;
 | 
			
		||||
            
 | 
			
		||||
            while ((line = reader.readLine())!=null)
 | 
			
		||||
            {
 | 
			
		||||
            	if (line.indexOf(command)!=-1)
 | 
			
		||||
            	{
 | 
			
		||||
            		
 | 
			
		||||
            		StringTokenizer st = new StringTokenizer(line," ");
 | 
			
		||||
            		st.nextToken(); //proc owner
 | 
			
		||||
            		
 | 
			
		||||
            		procId = Integer.parseInt(st.nextToken().trim());
 | 
			
		||||
            		
 | 
			
		||||
            		break;
 | 
			
		||||
            	}
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            Log.e(TAG, "error: " + e.getMessage(), e);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return procId;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static Process doCommand(String command, String arg1) 
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		Runtime r = Runtime.getRuntime();
 | 
			
		||||
		    	
 | 
			
		||||
		Process child = null;
 | 
			
		||||
		
 | 
			
		||||
        try {
 | 
			
		||||
            if(child != null) {
 | 
			
		||||
            	child.destroy();
 | 
			
		||||
            	child = null;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            child = r.exec(command + ' ' + arg1);
 | 
			
		||||
            
 | 
			
		||||
            
 | 
			
		||||
            
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            Log.e(TAG, "error: " + e.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return child;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static String generateHashPassword ()
 | 
			
		||||
	{
 | 
			
		||||
		/*
 | 
			
		||||
		PasswordDigest d = PasswordDigest.generateDigest();
 | 
			
		||||
	      byte[] s = d.getSecret(); // pass this to authenticate
 | 
			
		||||
	      String h = d.getHashedPassword(); // pass this to the Tor on startup.
 | 
			
		||||
*/
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void initControlConnection () throws Exception, RuntimeException
 | 
			
		||||
	{
 | 
			
		||||
			for (int i = 0; i < 50; i++)
 | 
			
		||||
			{
 | 
			
		||||
				try
 | 
			
		||||
				{
 | 
			
		||||
					Log.i(TAG,"Connecting to control port: " + TOR_CONTROL_PORT);
 | 
			
		||||
					Socket s = new Socket(IP_LOCALHOST, TOR_CONTROL_PORT);
 | 
			
		||||
			        conn = TorControlConnection.getConnection(s);
 | 
			
		||||
			      //  conn.authenticate(new byte[0]); // See section 3.2
 | 
			
		||||
			        
 | 
			
		||||
			        Log.i(TAG,"SUCCESS connected to control port");
 | 
			
		||||
			        
 | 
			
		||||
			        //
 | 
			
		||||
			        File fileCookie = new File(TOR_CONTROL_AUTH_COOKIE);
 | 
			
		||||
			        byte[] cookie = new byte[(int)fileCookie.length()];
 | 
			
		||||
			        new FileInputStream(new File(TOR_CONTROL_AUTH_COOKIE)).read(cookie);
 | 
			
		||||
			        conn.authenticate(cookie);
 | 
			
		||||
			        
 | 
			
		||||
			        Log.i(TAG,"SUCCESS authenticated to control port");
 | 
			
		||||
			        
 | 
			
		||||
			        addEventHandler();
 | 
			
		||||
			        
 | 
			
		||||
			        break; //don't need to retry
 | 
			
		||||
				}
 | 
			
		||||
				catch (ConnectException ce)
 | 
			
		||||
				{
 | 
			
		||||
					Log.i(TAG,"Attempt " + i + ": Error connecting to control port; retrying...");
 | 
			
		||||
					Thread.sleep(1000);
 | 
			
		||||
				}	
 | 
			
		||||
			}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void modifyConf () throws IOException
 | 
			
		||||
	{
 | 
			
		||||
	       // Get one configuration variable.
 | 
			
		||||
	       List options = conn.getConf("contact");
 | 
			
		||||
	       // Get a set of configuration variables.
 | 
			
		||||
	      // List options = conn.getConf(Arrays.asList(new String[]{
 | 
			
		||||
	           //   "contact", "orport", "socksport"}));
 | 
			
		||||
	       // Change a single configuration variable
 | 
			
		||||
	       conn.setConf("BandwidthRate", "1 MB");
 | 
			
		||||
	       // Change several configuration variables
 | 
			
		||||
	       conn.setConf(Arrays.asList(new String[]{
 | 
			
		||||
	              "HiddenServiceDir /home/tor/service1",
 | 
			
		||||
	              "HiddenServicePort 80",
 | 
			
		||||
	       }));
 | 
			
		||||
	       // Reset some variables to their defaults
 | 
			
		||||
	       conn.resetConf(Arrays.asList(new String[]{
 | 
			
		||||
	              "contact", "socksport"
 | 
			
		||||
	       }));
 | 
			
		||||
	       // Flush the configuration to disk.
 | 
			
		||||
	       conn.saveConf();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private void getTorStatus () throws IOException
 | 
			
		||||
	{
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			 
 | 
			
		||||
			
 | 
			
		||||
			
 | 
			
		||||
		
 | 
			
		||||
			if (conn != null)
 | 
			
		||||
			{
 | 
			
		||||
				 // get a single value.
 | 
			
		||||
			      
 | 
			
		||||
			       // get several values
 | 
			
		||||
			       
 | 
			
		||||
			       if (currentStatus == STATUS_STARTING_UP)
 | 
			
		||||
			       {
 | 
			
		||||
				       //Map vals = conn.getInfo(Arrays.asList(new String[]{
 | 
			
		||||
				         // "status/bootstrap-phase", "status","version"}));
 | 
			
		||||
			
 | 
			
		||||
				       String bsPhase = conn.getInfo("status/bootstrap-phase");
 | 
			
		||||
				    //   Log.i(TAG, "bootstrap-phase: " + bsPhase);
 | 
			
		||||
				       
 | 
			
		||||
				       if (bsPhase.indexOf("PROGRESS=100")!=-1)
 | 
			
		||||
				       {
 | 
			
		||||
				    	   currentStatus = STATUS_ON;
 | 
			
		||||
				       }
 | 
			
		||||
			       }
 | 
			
		||||
			       else
 | 
			
		||||
			       {
 | 
			
		||||
			    	 //  String status = conn.getInfo("status/circuit-established");
 | 
			
		||||
			    	 //  Log.i(TAG, "status/circuit-established=" + status);
 | 
			
		||||
			       }
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				currentStatus = STATUS_OFF;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (Exception e)
 | 
			
		||||
		{
 | 
			
		||||
			Log.i(TAG, "Unable to get Tor status from control port");
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	public void addEventHandler () throws IOException
 | 
			
		||||
	{
 | 
			
		||||
	       // We extend NullEventHandler so that we don't need to provide empty
 | 
			
		||||
	       // implementations for all the events we don't care about.
 | 
			
		||||
	       // ...
 | 
			
		||||
        Log.i(TAG,"adding control port event handler");
 | 
			
		||||
 | 
			
		||||
		conn.setEventHandler(ACTIVITY);
 | 
			
		||||
	    
 | 
			
		||||
		conn.setEvents(Arrays.asList(new String[]{
 | 
			
		||||
	          "ORCONN", "CIRC", "NOTICE", "ERR"}));
 | 
			
		||||
	      // conn.setEvents(Arrays.asList(new String[]{
 | 
			
		||||
	        //  "DEBUG", "INFO", "NOTICE", "WARN", "ERR"}));
 | 
			
		||||
 | 
			
		||||
	    Log.i(TAG,"SUCCESS added control port event handler");
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,73 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
package org.torproject.android;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileReader;
 | 
			
		||||
import java.io.FileWriter;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
public class Utils {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Load the log file text
 | 
			
		||||
	 */
 | 
			
		||||
	 public static String loadTextFile (String path)
 | 
			
		||||
	    {
 | 
			
		||||
	    	String line = null;
 | 
			
		||||
	    
 | 
			
		||||
	    	StringBuffer out = new StringBuffer();
 | 
			
		||||
	    	
 | 
			
		||||
	    	try {
 | 
			
		||||
		    	BufferedReader reader = new BufferedReader((new FileReader(new File(path))));
 | 
			
		||||
 | 
			
		||||
				while ((line = reader.readLine()) != null)
 | 
			
		||||
				{
 | 
			
		||||
					out.append(line);
 | 
			
		||||
					out.append('\n');
 | 
			
		||||
					
 | 
			
		||||
				}
 | 
			
		||||
			} catch (IOException e) {
 | 
			
		||||
				// TODO Auto-generated catch block
 | 
			
		||||
				e.printStackTrace();
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			return out.toString();
 | 
			
		||||
	    	
 | 
			
		||||
	    }
 | 
			
		||||
	 
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Load the log file text
 | 
			
		||||
		 */
 | 
			
		||||
		 public static boolean saveTextFile (String path, String contents)
 | 
			
		||||
		    {
 | 
			
		||||
			 	
 | 
			
		||||
		    	try {
 | 
			
		||||
		    		
 | 
			
		||||
		    		 FileWriter writer = new FileWriter( path, false );
 | 
			
		||||
                     writer.write( contents );
 | 
			
		||||
                     
 | 
			
		||||
                     writer.close();
 | 
			
		||||
 | 
			
		||||
                     
 | 
			
		||||
		    		
 | 
			
		||||
		    		return true;
 | 
			
		||||
			    	
 | 
			
		||||
				} catch (IOException e) {
 | 
			
		||||
				//	Log.i(TAG, "error writing file: " + path, e);
 | 
			
		||||
						e.printStackTrace();
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				
 | 
			
		||||
		    	
 | 
			
		||||
		    }
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,28 +1,45 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
 | 
			
		||||
/** SOCKS aware echo client*/
 | 
			
		||||
 | 
			
		||||
package org.torproject.android;
 | 
			
		||||
package org.torproject.android.net;
 | 
			
		||||
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.net.InetAddress;
 | 
			
		||||
import java.net.Socket;
 | 
			
		||||
import java.net.UnknownHostException;
 | 
			
		||||
 | 
			
		||||
import net.sourceforge.jsocks.socks.*;
 | 
			
		||||
import net.sourceforge.jsocks.socks.InetRange;
 | 
			
		||||
import net.sourceforge.jsocks.socks.Proxy;
 | 
			
		||||
import net.sourceforge.jsocks.socks.SocksException;
 | 
			
		||||
import net.sourceforge.jsocks.socks.SocksSocket;
 | 
			
		||||
 | 
			
		||||
import org.torproject.android.TorConstants;
 | 
			
		||||
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class SocksClient implements Runnable {
 | 
			
		||||
  
 | 
			
		||||
	   @SuppressWarnings("unused")
 | 
			
		||||
   private int port;
 | 
			
		||||
	   
 | 
			
		||||
	   @SuppressWarnings("unused")
 | 
			
		||||
   private InetAddress hostIP;
 | 
			
		||||
 | 
			
		||||
   private Socket ss;
 | 
			
		||||
   private InputStream in;
 | 
			
		||||
   private OutputStream out;
 | 
			
		||||
 | 
			
		||||
   private static final int BUF_SIZE = 1024;
 | 
			
		||||
 | 
			
		||||
   @SuppressWarnings("unused")
 | 
			
		||||
private static final int BUF_SIZE = 1024;
 | 
			
		||||
   private static final String IP_LOCALHOST = "127.0.0.1";
 | 
			
		||||
   
 | 
			
		||||
   public SocksClient(String host,int port) 
 | 
			
		||||
	  throws IOException,UnknownHostException,SocksException{
 | 
			
		||||
      this.port = port;
 | 
			
		||||
| 
						 | 
				
			
			@ -30,9 +47,9 @@ public class SocksClient implements Runnable {
 | 
			
		|||
      ss = new SocksSocket(host, port);
 | 
			
		||||
      out = ss.getOutputStream();
 | 
			
		||||
      in  = ss.getInputStream();
 | 
			
		||||
      System.out.println("Connected...");
 | 
			
		||||
      System.out.println("TO: "+host+":"+port);
 | 
			
		||||
      System.out.println("ViaProxy: "+ss.getLocalAddress().getHostAddress()
 | 
			
		||||
      Log.i(getClass().getName(),"Connected...");
 | 
			
		||||
      Log.i(getClass().getName(),"TO: "+host+":"+port);
 | 
			
		||||
      Log.i(getClass().getName(),"ViaProxy: "+ss.getLocalAddress().getHostAddress()
 | 
			
		||||
                                 +":"+ss.getLocalPort());
 | 
			
		||||
 | 
			
		||||
   }
 | 
			
		||||
| 
						 | 
				
			
			@ -75,11 +92,11 @@ public class SocksClient implements Runnable {
 | 
			
		|||
	     port = Integer.parseInt(args[1]);
 | 
			
		||||
 | 
			
		||||
	     proxyPort =(args.length > 3)? Integer.parseInt(args[3])	     
 | 
			
		||||
	                                 : TorConstants.PORT_SOCKS;
 | 
			
		||||
	                                 : 9050;
 | 
			
		||||
 | 
			
		||||
	     host = args[0];
 | 
			
		||||
	     proxyHost =(args.length > 2)? args[2]
 | 
			
		||||
	                                 : TorConstants.IP_LOCALHOST;
 | 
			
		||||
	                                 : IP_LOCALHOST;
 | 
			
		||||
 | 
			
		||||
	     Proxy.setDefaultProxy(proxyHost,proxyPort,"KOUKY001");
 | 
			
		||||
	     //Proxy.setDefaultProxy(proxyHost,proxyPort);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
package org.torproject.android.service;
 | 
			
		||||
 | 
			
		||||
import org.torproject.android.service.ITorServiceCallback;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * an interface for calling on to a remote service
 | 
			
		||||
 */
 | 
			
		||||
interface ITorService {
 | 
			
		||||
    /**
 | 
			
		||||
     * Often you want to allow a service to call back to its clients.
 | 
			
		||||
     * This shows how to do so, by registering a callback interface with
 | 
			
		||||
     * the service.
 | 
			
		||||
     */
 | 
			
		||||
    void registerCallback(ITorServiceCallback cb);
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Remove a previously registered callback interface.
 | 
			
		||||
     */
 | 
			
		||||
    void unregisterCallback(ITorServiceCallback cb);
 | 
			
		||||
    
 | 
			
		||||
    int getStatus();
 | 
			
		||||
    
 | 
			
		||||
    void setProfile(int profile);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
package org.torproject.android.service;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Callback interface used to send
 | 
			
		||||
 * synchronous notifications back to its clients.  Note that this is a
 | 
			
		||||
 * one-way interface so the server does not block waiting for the client.
 | 
			
		||||
 */
 | 
			
		||||
oneway interface ITorServiceCallback {
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when the service has a new value for you.
 | 
			
		||||
     */
 | 
			
		||||
    void statusChanged(String value);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
 | 
			
		||||
package org.torproject.android;
 | 
			
		||||
package org.torproject.android.service;
 | 
			
		||||
 | 
			
		||||
import java.io.DataInputStream;
 | 
			
		||||
import java.io.DataOutputStream;
 | 
			
		||||
| 
						 | 
				
			
			@ -14,9 +14,7 @@ import java.util.zip.ZipFile;
 | 
			
		|||
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
public class TorBinaryInstaller implements TorConstants {
 | 
			
		||||
 | 
			
		||||
	private final static String LOG_TAG = "Tor";
 | 
			
		||||
public class TorBinaryInstaller implements TorServiceConstants {
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	public TorBinaryInstaller ()
 | 
			
		||||
| 
						 | 
				
			
			@ -28,11 +26,13 @@ public class TorBinaryInstaller implements TorConstants {
 | 
			
		|||
	 */
 | 
			
		||||
	public void start (boolean force)
 | 
			
		||||
	{
 | 
			
		||||
		boolean binaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
 | 
			
		||||
		boolean torBinaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
 | 
			
		||||
		Log.i(TAG,"Tor binary exists=" + torBinaryExists);
 | 
			
		||||
		
 | 
			
		||||
		Log.i(LOG_TAG,"Tor binary exists=" + binaryExists);
 | 
			
		||||
		boolean privoxyBinaryExists = new File(PRIVOXY_INSTALL_PATH).exists();
 | 
			
		||||
		Log.i(TAG,"Privoxy binary exists=" + privoxyBinaryExists);
 | 
			
		||||
		
 | 
			
		||||
		if (!binaryExists || force)
 | 
			
		||||
		if (!(torBinaryExists && privoxyBinaryExists) || force)
 | 
			
		||||
			installFromZip ();
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -53,14 +53,21 @@ public class TorBinaryInstaller implements TorConstants {
 | 
			
		|||
			zipen = zip.getEntry(TORRC_ZIP_KEY);
 | 
			
		||||
			streamToFile(zip.getInputStream(zipen),TORRC_INSTALL_PATH);
 | 
			
		||||
			
 | 
			
		||||
			zipen = zip.getEntry(PRIVOXY_ZIP_KEY);
 | 
			
		||||
			streamToFile(zip.getInputStream(zipen),PRIVOXY_INSTALL_PATH);
 | 
			
		||||
			
 | 
			
		||||
			zipen = zip.getEntry(PRIVOXYCONFIG_ZIP_KEY);
 | 
			
		||||
			streamToFile(zip.getInputStream(zipen),PRIVOXYCONFIG_INSTALL_PATH);
 | 
			
		||||
			
 | 
			
		||||
			
 | 
			
		||||
			zip.close();
 | 
			
		||||
			
 | 
			
		||||
			Log.i(LOG_TAG,"SUCCESS: unzipped tor binary from apk");
 | 
			
		||||
			Log.i(TAG,"SUCCESS: unzipped tor, privoxy binaries from apk");
 | 
			
		||||
	
 | 
			
		||||
		}
 | 
			
		||||
		catch (IOException ioe)
 | 
			
		||||
		{
 | 
			
		||||
			Log.i(LOG_TAG,"FAIL: unable to unzip tor binary from apk",ioe);
 | 
			
		||||
			Log.i(TAG,"FAIL: unable to unzip binaries from apk",ioe);
 | 
			
		||||
		
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +98,7 @@ public class TorBinaryInstaller implements TorConstants {
 | 
			
		|||
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
        	Log.i(LOG_TAG,"Error opening output file " + targetFilename,e);
 | 
			
		||||
        	Log.i(TAG,"Error opening output file " + targetFilename,e);
 | 
			
		||||
 | 
			
		||||
        	return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +125,7 @@ public class TorBinaryInstaller implements TorConstants {
 | 
			
		|||
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            Log.i(LOG_TAG,"Error writing output file '" + targetFilename + "': " + e.toString());
 | 
			
		||||
            Log.i(TAG,"Error writing output file '" + targetFilename + "': " + e.toString());
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -135,12 +142,15 @@ public class TorBinaryInstaller implements TorConstants {
 | 
			
		|||
			DataOutputStream out = new DataOutputStream(new FileOutputStream(outputFile));
 | 
			
		||||
			DataInputStream in = new DataInputStream(is);
 | 
			
		||||
			
 | 
			
		||||
			int b;
 | 
			
		||||
			int b = -1;
 | 
			
		||||
			byte[] data = new byte[1024];
 | 
			
		||||
			
 | 
			
		||||
			while ((b = in.read(data)) != -1) {
 | 
			
		||||
				out.write(data);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if (b == -1); //rejoice
 | 
			
		||||
			
 | 
			
		||||
			//
 | 
			
		||||
			out.flush();
 | 
			
		||||
			out.close();
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +160,7 @@ public class TorBinaryInstaller implements TorConstants {
 | 
			
		|||
			
 | 
			
		||||
			
 | 
			
		||||
		} catch (IOException ex) {
 | 
			
		||||
			Log.e(LOG_TAG, "error copying binary", ex);
 | 
			
		||||
			Log.e(TAG, "error copying binary", ex);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,228 @@
 | 
			
		|||
/* 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 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_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);
 | 
			
		||||
			
 | 
			
		||||
			/*
 | 
			
		||||
			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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,721 @@
 | 
			
		|||
/* 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.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.Socket;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import net.freehaven.tor.control.ConfigEntry;
 | 
			
		||||
import net.freehaven.tor.control.EventHandler;
 | 
			
		||||
import net.freehaven.tor.control.TorControlConnection;
 | 
			
		||||
 | 
			
		||||
import org.torproject.android.Orbot;
 | 
			
		||||
import org.torproject.android.R;
 | 
			
		||||
 | 
			
		||||
import android.app.Notification;
 | 
			
		||||
import android.app.NotificationManager;
 | 
			
		||||
import android.app.PendingIntent;
 | 
			
		||||
import android.app.Service;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.IBinder;
 | 
			
		||||
import android.os.RemoteCallbackList;
 | 
			
		||||
import android.os.RemoteException;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
public class TorService extends Service implements TorServiceConstants, Runnable, EventHandler
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	private static int currentStatus = STATUS_REQUIRES_DEMAND;
 | 
			
		||||
		
 | 
			
		||||
	private TorControlConnection conn = null;
 | 
			
		||||
	
 | 
			
		||||
	private static TorService _torInstance;
 | 
			
		||||
	
 | 
			
		||||
	private static final int NOTIFY_ID = 1;
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
    /** Called when the activity is first created. */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate() {
 | 
			
		||||
    	super.onCreate();
 | 
			
		||||
       
 | 
			
		||||
    	Log.i(TAG,"TorService: onCreate");
 | 
			
		||||
    	
 | 
			
		||||
    	checkTorBinaries();
 | 
			
		||||
    	
 | 
			
		||||
    	findExistingProc ();
 | 
			
		||||
    	
 | 
			
		||||
    	_torInstance = this;
 | 
			
		||||
 | 
			
		||||
    	 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private boolean findExistingProc ()
 | 
			
		||||
    {
 | 
			
		||||
    	 int procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
 		if (procId != -1)
 | 
			
		||||
 		{
 | 
			
		||||
 			Log.i(TAG,"Found existing Tor process");
 | 
			
		||||
 			
 | 
			
		||||
            sendCallbackMessage ("found existing Tor process...");
 | 
			
		||||
 | 
			
		||||
 			try {
 | 
			
		||||
 				currentStatus = STATUS_CONNECTING;
 | 
			
		||||
				
 | 
			
		||||
 				initControlConnection();
 | 
			
		||||
				
 | 
			
		||||
				
 | 
			
		||||
				currentStatus = STATUS_ON;
 | 
			
		||||
				
 | 
			
		||||
				return true;
 | 
			
		||||
 						
 | 
			
		||||
			} catch (RuntimeException e) {
 | 
			
		||||
				Log.i(TAG,"Unable to connect to existing Tor instance,",e);
 | 
			
		||||
				currentStatus = STATUS_REQUIRES_DEMAND;
 | 
			
		||||
				this.stopTor();
 | 
			
		||||
				
 | 
			
		||||
			} catch (Exception e) {
 | 
			
		||||
				Log.i(TAG,"Unable to connect to existing Tor instance,",e);
 | 
			
		||||
				currentStatus = STATUS_REQUIRES_DEMAND;
 | 
			
		||||
				this.stopTor();
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
 		}
 | 
			
		||||
 		
 | 
			
		||||
 		return false;
 | 
			
		||||
    	 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Service#onLowMemory()
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onLowMemory() {
 | 
			
		||||
		super.onLowMemory();
 | 
			
		||||
		
 | 
			
		||||
		Log.i(TAG, "Low Memory Called");
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Service#onUnbind(android.content.Intent)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean onUnbind(Intent intent) {
 | 
			
		||||
		
 | 
			
		||||
		Log.i(TAG, "onUnbind Called: " + intent.getAction());
 | 
			
		||||
		
 | 
			
		||||
		return super.onUnbind(intent);
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public int getTorStatus ()
 | 
			
		||||
    {
 | 
			
		||||
    	
 | 
			
		||||
    	return currentStatus;
 | 
			
		||||
    	
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
   
 | 
			
		||||
	private void showToolbarNotification (String title, String notifyMsg, int icon)
 | 
			
		||||
	{
 | 
			
		||||
		
 | 
			
		||||
		NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		CharSequence tickerText = title;
 | 
			
		||||
		long when = System.currentTimeMillis();
 | 
			
		||||
 | 
			
		||||
		Notification notification = new Notification(icon, tickerText, when);
 | 
			
		||||
		
 | 
			
		||||
		Context context = getApplicationContext();
 | 
			
		||||
		CharSequence contentTitle = title;
 | 
			
		||||
		CharSequence contentText = notifyMsg;
 | 
			
		||||
		
 | 
			
		||||
		Intent notificationIntent = new Intent(this, Orbot.class);
 | 
			
		||||
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
 | 
			
		||||
 | 
			
		||||
		notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		mNotificationManager.notify(NOTIFY_ID, notification);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
    
 | 
			
		||||
    /* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Service#onRebind(android.content.Intent)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onRebind(Intent intent) {
 | 
			
		||||
		super.onRebind(intent);
 | 
			
		||||
		
 | 
			
		||||
		 Log.i(TAG,"on rebind");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* (non-Javadoc)
 | 
			
		||||
	 * @see android.app.Service#onStart(android.content.Intent, int)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public void onStart(Intent intent, int startId) {
 | 
			
		||||
		super.onStart(intent, startId);
 | 
			
		||||
		
 | 
			
		||||
	    /*
 | 
			
		||||
	     if (currentStatus == STATUS_ON && conn != null && webProxy != null)
 | 
			
		||||
	     {
 | 
			
		||||
	    	 //we are good to go
 | 
			
		||||
		     Log.i(TAG,"onStart: Tor is running");
 | 
			
		||||
 | 
			
		||||
	     }
 | 
			
		||||
	     else
 | 
			
		||||
	     {
 | 
			
		||||
		     Log.i(TAG,"onStart: Starting up Tor");
 | 
			
		||||
 | 
			
		||||
	    	 new Thread(this).start();
 | 
			
		||||
	     }
 | 
			
		||||
	     */
 | 
			
		||||
	}
 | 
			
		||||
	 
 | 
			
		||||
	public void run ()
 | 
			
		||||
	{
 | 
			
		||||
		boolean isRunning = _torInstance.findExistingProc ();
 | 
			
		||||
		
 | 
			
		||||
		if (!isRunning)
 | 
			
		||||
		{
 | 
			
		||||
	     try
 | 
			
		||||
	     {
 | 
			
		||||
		   initTor();
 | 
			
		||||
		   
 | 
			
		||||
		   
 | 
			
		||||
	     }
 | 
			
		||||
	     catch (Exception e)
 | 
			
		||||
	     {
 | 
			
		||||
	    	 currentStatus = STATUS_REQUIRES_DEMAND;
 | 
			
		||||
	    	 this.showToolbarNotification("Orbot", "Unable to start Tor", R.drawable.tornotification);
 | 
			
		||||
	    	 Log.i(TAG,"Unable to start Tor: " + e.getMessage(),e);
 | 
			
		||||
	     }
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
    public void onDestroy ()
 | 
			
		||||
    {
 | 
			
		||||
    	super.onDestroy();
 | 
			
		||||
    	
 | 
			
		||||
    	  // Unregister all callbacks.
 | 
			
		||||
        mCallbacks.kill();
 | 
			
		||||
      
 | 
			
		||||
        
 | 
			
		||||
    	Log.i(TAG,"onDestroy called");
 | 
			
		||||
	     
 | 
			
		||||
    	stopTor();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void stopTor ()
 | 
			
		||||
    {
 | 
			
		||||
    	currentStatus = STATUS_UNAVAILABLE;
 | 
			
		||||
    	
 | 
			
		||||
    		
 | 
			
		||||
    	sendCallbackMessage("Web proxy shutdown");
 | 
			
		||||
    	
 | 
			
		||||
		killTorProcess ();
 | 
			
		||||
				
 | 
			
		||||
		currentStatus = STATUS_REQUIRES_DEMAND;
 | 
			
		||||
    	
 | 
			
		||||
		showToolbarNotification ("Orbot","Anonymous browsing is disabled",R.drawable.tornotificationoff);
 | 
			
		||||
    	sendCallbackMessage("Anonymous browsing is disabled");
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 
 | 
			
		||||
   
 | 
			
		||||
    
 | 
			
		||||
    public void reloadConfig ()
 | 
			
		||||
    {
 | 
			
		||||
    	try
 | 
			
		||||
		{
 | 
			
		||||
	    	if (conn == null)
 | 
			
		||||
			{
 | 
			
		||||
				initControlConnection ();
 | 
			
		||||
			}
 | 
			
		||||
		
 | 
			
		||||
			if (conn != null)
 | 
			
		||||
			{
 | 
			
		||||
				 conn.signal("RELOAD");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
    	catch (Exception e)
 | 
			
		||||
    	{
 | 
			
		||||
    		Log.i(TAG,"Unable to reload configuration",e);
 | 
			
		||||
    	}
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private void killTorProcess ()
 | 
			
		||||
    {
 | 
			
		||||
		
 | 
			
		||||
    	if (conn != null)
 | 
			
		||||
		{
 | 
			
		||||
			try {
 | 
			
		||||
				Log.i(TAG,"sending SHUTDOWN signal");
 | 
			
		||||
				conn.signal("SHUTDOWN");
 | 
			
		||||
			} catch (Exception e) {
 | 
			
		||||
				Log.i(TAG,"error shutting down Tor via connection",e);
 | 
			
		||||
			}
 | 
			
		||||
			conn = null;
 | 
			
		||||
		}
 | 
			
		||||
    	
 | 
			
		||||
    	
 | 
			
		||||
		int procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
		while (procId != -1)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
			Log.i(TAG,"Found Tor PID=" + procId + " - killing now...");
 | 
			
		||||
			
 | 
			
		||||
			TorServiceUtils.doCommand(SHELL_CMD_KILL, procId + "");
 | 
			
		||||
 | 
			
		||||
			procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		procId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
		while (procId != -1)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
			Log.i(TAG,"Found Privoxy PID=" + procId + " - killing now...");
 | 
			
		||||
			
 | 
			
		||||
			TorServiceUtils.doCommand(SHELL_CMD_KILL, procId + "");
 | 
			
		||||
 | 
			
		||||
			procId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
    }
 | 
			
		||||
   
 | 
			
		||||
    private void logNotice (String msg)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    	Log.i(TAG, msg);
 | 
			
		||||
		
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private boolean checkTorBinaries ()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
		boolean torBinaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
 | 
			
		||||
		boolean privoxyBinaryExists = new File(PRIVOXY_INSTALL_PATH).exists();
 | 
			
		||||
 | 
			
		||||
		if (!(torBinaryExists && privoxyBinaryExists))
 | 
			
		||||
		{
 | 
			
		||||
			killTorProcess ();
 | 
			
		||||
			
 | 
			
		||||
			TorBinaryInstaller installer = new TorBinaryInstaller(); 
 | 
			
		||||
			installer.start(true);
 | 
			
		||||
		
 | 
			
		||||
			torBinaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
 | 
			
		||||
			privoxyBinaryExists = new File(PRIVOXY_INSTALL_PATH).exists();
 | 
			
		||||
			
 | 
			
		||||
    		if (torBinaryExists && privoxyBinaryExists)
 | 
			
		||||
    		{
 | 
			
		||||
    			logNotice("Tor, Privoxy, IPtables binaries installed!");
 | 
			
		||||
    	
 | 
			
		||||
    			this.showToolbarNotification("Orbot Installed!", "The Tor binary was successfully extracted and installed", R.drawable.tornotification);
 | 
			
		||||
    		
 | 
			
		||||
    		}
 | 
			
		||||
    		else
 | 
			
		||||
    		{
 | 
			
		||||
    			logNotice("Binary install FAILED!");
 | 
			
		||||
    			
 | 
			
		||||
    			this.showToolbarNotification("Orbot FAIL!", "The binaries were unable to be installed", R.drawable.tornotification);
 | 
			
		||||
 | 
			
		||||
    		
 | 
			
		||||
    			return false;
 | 
			
		||||
    		}
 | 
			
		||||
    		
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
		Log.i(TAG,"Setting permission on Tor binary");
 | 
			
		||||
		TorServiceUtils.doCommand(SHELL_CMD_CHMOD, CHMOD_EXE_VALUE + ' ' + TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
		
 | 
			
		||||
		Log.i(TAG,"Setting permission on Privoxy binary");
 | 
			
		||||
		TorServiceUtils.doCommand(SHELL_CMD_CHMOD, CHMOD_EXE_VALUE + ' ' + PRIVOXY_INSTALL_PATH);
 | 
			
		||||
				
 | 
			
		||||
		return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void initTor () throws Exception
 | 
			
		||||
    {
 | 
			
		||||
    		
 | 
			
		||||
    		currentStatus = STATUS_CONNECTING;
 | 
			
		||||
 | 
			
		||||
    		logNotice("Tor is starting up...");
 | 
			
		||||
    		this.sendCallbackMessage("starting...");
 | 
			
		||||
    		
 | 
			
		||||
    		killTorProcess ();
 | 
			
		||||
    		
 | 
			
		||||
    		checkTorBinaries ();
 | 
			
		||||
    		
 | 
			
		||||
    		
 | 
			
		||||
    		Log.i(TAG,"Starting tor process");
 | 
			
		||||
    		
 | 
			
		||||
    		TorServiceUtils.doCommand(TOR_BINARY_INSTALL_PATH, TOR_COMMAND_LINE_ARGS);
 | 
			
		||||
		
 | 
			
		||||
    		int procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
    		while (procId == -1)
 | 
			
		||||
    		{
 | 
			
		||||
    			TorServiceUtils.doCommand(TOR_BINARY_INSTALL_PATH, TOR_COMMAND_LINE_ARGS);
 | 
			
		||||
    			procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
 | 
			
		||||
    			
 | 
			
		||||
    			if (procId == -1)
 | 
			
		||||
    			{
 | 
			
		||||
    				this.sendCallbackMessage("Couldn't start Tor process... retrying...");
 | 
			
		||||
    				Thread.sleep(3000);
 | 
			
		||||
    			}
 | 
			
		||||
    		}
 | 
			
		||||
    		
 | 
			
		||||
    		Log.i(TAG,"Tor process id=" + procId);
 | 
			
		||||
    		
 | 
			
		||||
    		showToolbarNotification("Orbot starting...", "Orbot is starting up", R.drawable.tornotification);
 | 
			
		||||
			
 | 
			
		||||
			initControlConnection ();
 | 
			
		||||
			
 | 
			
		||||
			int privoxyProcId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH);
 | 
			
		||||
 | 
			
		||||
    		while (privoxyProcId == -1)
 | 
			
		||||
    		{
 | 
			
		||||
    			TorServiceUtils.doCommand(PRIVOXY_INSTALL_PATH, PRIVOXY_COMMAND_LINE_ARGS);
 | 
			
		||||
    			privoxyProcId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH);
 | 
			
		||||
    			
 | 
			
		||||
    			if (privoxyProcId == -1)
 | 
			
		||||
    			{
 | 
			
		||||
    				this.sendCallbackMessage("Couldn't start Privoxy process... retrying...");
 | 
			
		||||
    				Thread.sleep(3000);
 | 
			
		||||
    			}
 | 
			
		||||
    		}
 | 
			
		||||
    		
 | 
			
		||||
    		Log.i(TAG,"Privoxy process id=" + privoxyProcId);
 | 
			
		||||
			
 | 
			
		||||
    		
 | 
			
		||||
    		
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	public String generateHashPassword ()
 | 
			
		||||
	{
 | 
			
		||||
		/*
 | 
			
		||||
		PasswordDigest d = PasswordDigest.generateDigest();
 | 
			
		||||
	      byte[] s = d.getSecret(); // pass this to authenticate
 | 
			
		||||
	      String h = d.getHashedPassword(); // pass this to the Tor on startup.
 | 
			
		||||
*/
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void initControlConnection () throws Exception, RuntimeException
 | 
			
		||||
	{
 | 
			
		||||
			while (true)
 | 
			
		||||
			{
 | 
			
		||||
				try
 | 
			
		||||
				{
 | 
			
		||||
					Log.i(TAG,"Connecting to control port: " + TOR_CONTROL_PORT);
 | 
			
		||||
					
 | 
			
		||||
					String baseMessage = getString(R.string.tor_process_connecting);
 | 
			
		||||
					sendCallbackMessage(baseMessage);
 | 
			
		||||
					
 | 
			
		||||
					Socket s = new Socket(IP_LOCALHOST, TOR_CONTROL_PORT);
 | 
			
		||||
			        conn = TorControlConnection.getConnection(s);
 | 
			
		||||
			      //  conn.authenticate(new byte[0]); // See section 3.2
 | 
			
		||||
			        
 | 
			
		||||
					sendCallbackMessage(baseMessage + ' ' + getString(R.string.tor_process_connecting_step2));
 | 
			
		||||
 | 
			
		||||
			        Log.i(TAG,"SUCCESS connected to control port");
 | 
			
		||||
			        
 | 
			
		||||
			        File fileCookie = new File(TOR_CONTROL_AUTH_COOKIE);
 | 
			
		||||
			        byte[] cookie = new byte[(int)fileCookie.length()];
 | 
			
		||||
			        new FileInputStream(new File(TOR_CONTROL_AUTH_COOKIE)).read(cookie);
 | 
			
		||||
			        conn.authenticate(cookie);
 | 
			
		||||
			        
 | 
			
		||||
			        Log.i(TAG,"SUCCESS authenticated to control port");
 | 
			
		||||
			        
 | 
			
		||||
					sendCallbackMessage(baseMessage + ' ' + getString(R.string.tor_process_connecting_step3));
 | 
			
		||||
 | 
			
		||||
			        addEventHandler();
 | 
			
		||||
			        
 | 
			
		||||
			        break; //don't need to retry
 | 
			
		||||
				}
 | 
			
		||||
				catch (Exception ce)
 | 
			
		||||
				{
 | 
			
		||||
					conn = null;
 | 
			
		||||
					Log.i(TAG,"Attempt: Error connecting to control port: " + ce.getLocalizedMessage(),ce);
 | 
			
		||||
					
 | 
			
		||||
					sendCallbackMessage(getString(R.string.tor_process_connecting_step4));
 | 
			
		||||
 | 
			
		||||
					Thread.sleep(1000);
 | 
			
		||||
					
 | 
			
		||||
					
 | 
			
		||||
				}	
 | 
			
		||||
			}
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void modifyConf () throws IOException
 | 
			
		||||
	{
 | 
			
		||||
	       // Get one configuration variable.
 | 
			
		||||
	       List<ConfigEntry> options = conn.getConf("contact"); 
 | 
			
		||||
	       options.size();
 | 
			
		||||
	       // Get a set of configuration variables.
 | 
			
		||||
	      // List options = conn.getConf(Arrays.asList(new String[]{
 | 
			
		||||
	           //   "contact", "orport", "socksport"}));
 | 
			
		||||
	       // Change a single configuration variable
 | 
			
		||||
	       conn.setConf("BandwidthRate", "1 MB");
 | 
			
		||||
	       // Change several configuration variables
 | 
			
		||||
	       conn.setConf(Arrays.asList(new String[]{
 | 
			
		||||
	              "HiddenServiceDir /home/tor/service1",
 | 
			
		||||
	              "HiddenServicePort 80",
 | 
			
		||||
	       }));
 | 
			
		||||
	       // Reset some variables to their defaults
 | 
			
		||||
	       conn.resetConf(Arrays.asList(new String[]{
 | 
			
		||||
	              "contact", "socksport"
 | 
			
		||||
	       }));
 | 
			
		||||
	       // Flush the configuration to disk.
 | 
			
		||||
	       conn.saveConf();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	private void getTorStatus () throws IOException
 | 
			
		||||
	{
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			 
 | 
			
		||||
			if (conn != null)
 | 
			
		||||
			{
 | 
			
		||||
				 // get a single value.
 | 
			
		||||
			      
 | 
			
		||||
			       // get several values
 | 
			
		||||
			       
 | 
			
		||||
			       if (currentStatus == STATUS_CONNECTING)
 | 
			
		||||
			       {
 | 
			
		||||
				       //Map vals = conn.getInfo(Arrays.asList(new String[]{
 | 
			
		||||
				         // "status/bootstrap-phase", "status","version"}));
 | 
			
		||||
			
 | 
			
		||||
				       String bsPhase = conn.getInfo("status/bootstrap-phase");
 | 
			
		||||
				       Log.i(TAG, "bootstrap-phase: " + bsPhase);
 | 
			
		||||
				       
 | 
			
		||||
				       
 | 
			
		||||
			       }
 | 
			
		||||
			       else
 | 
			
		||||
			       {
 | 
			
		||||
			    	 //  String status = conn.getInfo("status/circuit-established");
 | 
			
		||||
			    	 //  Log.i(TAG, "status/circuit-established=" + status);
 | 
			
		||||
			       }
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (Exception e)
 | 
			
		||||
		{
 | 
			
		||||
			Log.i(TAG, "Unable to get Tor status from control port");
 | 
			
		||||
			currentStatus = STATUS_UNAVAILABLE;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}*/
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	public void addEventHandler () throws IOException
 | 
			
		||||
	{
 | 
			
		||||
	       // We extend NullEventHandler so that we don't need to provide empty
 | 
			
		||||
	       // implementations for all the events we don't care about.
 | 
			
		||||
	       // ...
 | 
			
		||||
        Log.i(TAG,"adding control port event handler");
 | 
			
		||||
 | 
			
		||||
		conn.setEventHandler(this);
 | 
			
		||||
	    
 | 
			
		||||
		conn.setEvents(Arrays.asList(new String[]{
 | 
			
		||||
	          "ORCONN", "CIRC", "NOTICE", "ERR"}));
 | 
			
		||||
	      // conn.setEvents(Arrays.asList(new String[]{
 | 
			
		||||
	        //  "DEBUG", "INFO", "NOTICE", "WARN", "ERR"}));
 | 
			
		||||
 | 
			
		||||
	    Log.i(TAG,"SUCCESS added control port event handler");
 | 
			
		||||
	    
 | 
			
		||||
	    
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
		/**
 | 
			
		||||
		 * Returns the port number that the HTTP proxy is running on
 | 
			
		||||
		 */
 | 
			
		||||
		public int getHTTPPort() throws RemoteException {
 | 
			
		||||
			return TorServiceConstants.PORT_HTTP;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Returns the port number that the SOCKS proxy is running on
 | 
			
		||||
		 */
 | 
			
		||||
		public int getSOCKSPort() throws RemoteException {
 | 
			
		||||
			return TorServiceConstants.PORT_SOCKS;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
		public int getProfile() throws RemoteException {
 | 
			
		||||
			//return mProfile;
 | 
			
		||||
			return PROFILE_ON;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		public void setTorProfile(int profile)  {
 | 
			
		||||
			
 | 
			
		||||
			if (profile == PROFILE_ON)
 | 
			
		||||
			{
 | 
			
		||||
 				currentStatus = STATUS_CONNECTING;
 | 
			
		||||
	            sendCallbackMessage ("starting...");
 | 
			
		||||
 | 
			
		||||
	            new Thread(_torInstance).start();
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				currentStatus = STATUS_UNAVAILABLE;
 | 
			
		||||
	            sendCallbackMessage ("shutting down...");
 | 
			
		||||
	            
 | 
			
		||||
				_torInstance.stopTor();
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void message(String severity, String msg) {
 | 
			
		||||
		
 | 
			
		||||
              Log.i(TAG, "[Tor Control Port] " + severity + ": " + msg);
 | 
			
		||||
              
 | 
			
		||||
              if (msg.indexOf(TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)!=-1)
 | 
			
		||||
              {
 | 
			
		||||
            	  currentStatus = STATUS_ON;
 | 
			
		||||
            	  showToolbarNotification ("Orbot","Anonymous browsing is enabled",R.drawable.tornotification);
 | 
			
		||||
      			  
 | 
			
		||||
              }
 | 
			
		||||
              else
 | 
			
		||||
              {
 | 
			
		||||
            	  showToolbarNotification("Orbot", msg, R.drawable.tornotification);
 | 
			
		||||
 | 
			
		||||
              }
 | 
			
		||||
             
 | 
			
		||||
              sendCallbackMessage (msg);
 | 
			
		||||
             
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void newDescriptors(List<String> orList) {
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void orConnStatus(String status, String orName) {
 | 
			
		||||
		
 | 
			
		||||
		Log.i(TAG,"OrConnStatus=" + status + ": " + orName);
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void streamStatus(String status, String streamID, String target) {
 | 
			
		||||
		Log.i(TAG,"StreamStatus=" + status + ": " + streamID);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void unrecognized(String type, String msg) {
 | 
			
		||||
		Log.i(TAG,"unrecognized log=" + type + ": " + msg);
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void bandwidthUsed(long read, long written) {
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void circuitStatus(String status, String circID, String path) {
 | 
			
		||||
	
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	 @Override
 | 
			
		||||
    public IBinder onBind(Intent intent) {
 | 
			
		||||
        // Select the interface to return.  If your service only implements
 | 
			
		||||
        // a single interface, you can just return it here without checking
 | 
			
		||||
        // the Intent.
 | 
			
		||||
        if (ITorService.class.getName().equals(intent.getAction())) {
 | 
			
		||||
            return mBinder;
 | 
			
		||||
        }
 | 
			
		||||
      
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
	
 | 
			
		||||
    /**
 | 
			
		||||
     * This is a list of callbacks that have been registered with the
 | 
			
		||||
     * service.  Note that this is package scoped (instead of private) so
 | 
			
		||||
     * that it can be accessed more efficiently from inner classes.
 | 
			
		||||
     */
 | 
			
		||||
    final RemoteCallbackList<ITorServiceCallback> mCallbacks
 | 
			
		||||
            = new RemoteCallbackList<ITorServiceCallback>();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The IRemoteInterface is defined through IDL
 | 
			
		||||
     */
 | 
			
		||||
    private final ITorService.Stub mBinder = new ITorService.Stub() {
 | 
			
		||||
        public void registerCallback(ITorServiceCallback cb) {
 | 
			
		||||
            if (cb != null) mCallbacks.register(cb);
 | 
			
		||||
        }
 | 
			
		||||
        public void unregisterCallback(ITorServiceCallback cb) {
 | 
			
		||||
            if (cb != null) mCallbacks.unregister(cb);
 | 
			
		||||
        }
 | 
			
		||||
        public int getStatus () {
 | 
			
		||||
        	return getTorStatus();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        public void setProfile (int profile)
 | 
			
		||||
        {
 | 
			
		||||
        	setTorProfile(profile);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    private void sendCallbackMessage (String status)
 | 
			
		||||
    {
 | 
			
		||||
    	 
 | 
			
		||||
        // Broadcast to all clients the new value.
 | 
			
		||||
        final int N = mCallbacks.beginBroadcast();
 | 
			
		||||
        for (int i=0; i<N; i++) {
 | 
			
		||||
            try {
 | 
			
		||||
                mCallbacks.getBroadcastItem(i).statusChanged(status);
 | 
			
		||||
            } catch (RemoteException e) {
 | 
			
		||||
                // The RemoteCallbackList will take care of removing
 | 
			
		||||
                // the dead object for us.
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        mCallbacks.finishBroadcast();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
 | 
			
		||||
/* See LICENSE for licensing information */
 | 
			
		||||
package org.torproject.android.service;
 | 
			
		||||
 | 
			
		||||
public interface TorServiceConstants {
 | 
			
		||||
 | 
			
		||||
	public final static String TAG = "TOR_SERVICE";
 | 
			
		||||
 | 
			
		||||
	//home directory of Android application
 | 
			
		||||
	public final static String TOR_HOME = "/data/data/org.torproject.android/";
 | 
			
		||||
 | 
			
		||||
	//name of the tor C binary
 | 
			
		||||
	public final static String TOR_BINARY_ASSET_KEY = "tor";	
 | 
			
		||||
	public final static String TOR_BINARY_INSTALL_PATH = TOR_HOME + TOR_BINARY_ASSET_KEY; //path to install the Tor binary too
 | 
			
		||||
	public final static String TOR_BINARY_ZIP_KEY = "assets/" + TOR_BINARY_ASSET_KEY;//key of the tor binary in the Zip file
 | 
			
		||||
	
 | 
			
		||||
	//torrc (tor config file)
 | 
			
		||||
	public final static String TORRC_ASSET_KEY = "torrc";
 | 
			
		||||
	public final static String TORRC_INSTALL_PATH = TOR_HOME + TORRC_ASSET_KEY; //path to install torrc to within the android app data folder
 | 
			
		||||
	public final static String TORRC_ZIP_KEY = "assets/" + TORRC_ASSET_KEY; //key of the torrc file in the Zip file
 | 
			
		||||
	//how to launch tor
 | 
			
		||||
	public final static String TOR_COMMAND_LINE_ARGS = "-f " + TORRC_INSTALL_PATH;
 | 
			
		||||
		
 | 
			
		||||
	//privoxy
 | 
			
		||||
	public final static String PRIVOXY_ASSET_KEY = "privoxy";
 | 
			
		||||
	public final static String PRIVOXY_INSTALL_PATH = TOR_HOME + PRIVOXY_ASSET_KEY; //path to install privoxy to within the android app data folder
 | 
			
		||||
	public final static String PRIVOXY_ZIP_KEY = "assets/" + PRIVOXY_ASSET_KEY; //key of the privoxy file in the Zip file
 | 
			
		||||
	
 | 
			
		||||
	//privoxy.config
 | 
			
		||||
	public final static String PRIVOXYCONFIG_ASSET_KEY = "privoxy.config";
 | 
			
		||||
	public final static String PRIVOXYCONFIG_INSTALL_PATH = TOR_HOME + PRIVOXYCONFIG_ASSET_KEY; //path to install privoxy to within the android app data folder
 | 
			
		||||
	public final static String PRIVOXYCONFIG_ZIP_KEY = "assets/" + PRIVOXYCONFIG_ASSET_KEY; //key of the privoxy file in the Zip file
 | 
			
		||||
	
 | 
			
		||||
	//how to launch privoxy
 | 
			
		||||
	public final static String PRIVOXY_COMMAND_LINE_ARGS = ' ' + PRIVOXYCONFIG_INSTALL_PATH;
 | 
			
		||||
 | 
			
		||||
	//where to send the notices log
 | 
			
		||||
	public final static String TOR_LOG_PATH = TOR_HOME + "notices.log";
 | 
			
		||||
	
 | 
			
		||||
	//control port cookie path
 | 
			
		||||
	public final static String TOR_CONTROL_AUTH_COOKIE = TOR_HOME + "data/control_auth_cookie";
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	//various console cmds
 | 
			
		||||
	public final static String SHELL_CMD_CHMOD = "chmod";
 | 
			
		||||
	public final static String SHELL_CMD_KILL = "kill";
 | 
			
		||||
	public final static String SHELL_CMD_RM = "rm";
 | 
			
		||||
	public final static String SHELL_CMD_PS = "ps";
 | 
			
		||||
	public final static String CHMOD_EXE_VALUE = "777";
 | 
			
		||||
	
 | 
			
		||||
	//path of the installed APK file
 | 
			
		||||
	public final static String APK_PATH = "/data/app/org.torproject.android.apk";
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	public final static int FILE_WRITE_BUFFER_SIZE = 2048;
 | 
			
		||||
	
 | 
			
		||||
	//HTTP Proxy server port
 | 
			
		||||
	public final static int PORT_HTTP = 8118; //just like Privoxy!
 | 
			
		||||
	
 | 
			
		||||
	//Socks port client connects to, server is the Tor binary
 | 
			
		||||
	public final static int PORT_SOCKS = 9050;
 | 
			
		||||
	
 | 
			
		||||
	//what is says!
 | 
			
		||||
	public final static String IP_LOCALHOST = "127.0.0.1";
 | 
			
		||||
	public final static int TOR_CONTROL_PORT = 9051;
 | 
			
		||||
	public final static int UPDATE_TIMEOUT = 1000;
 | 
			
		||||
	
 | 
			
		||||
	//path to check Tor against
 | 
			
		||||
	public final static String URL_TOR_CHECK = "http://check.torproject.org";
 | 
			
		||||
		
 | 
			
		||||
    //IPTABLES
 | 
			
		||||
//	public final static String CMD_IPTABLES_PREROUTING = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to 127.0.0.1:8118 || exit\n";
 | 
			
		||||
	//public final static String CMD_IPTABLES_PREROUTING_FLUSH = "iptables -t nat -F || exit\n";
 | 
			
		||||
 | 
			
		||||
    //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_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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,153 @@
 | 
			
		|||
/* 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.BufferedReader;
 | 
			
		||||
import java.io.InputStreamReader;
 | 
			
		||||
import java.io.OutputStreamWriter;
 | 
			
		||||
import java.util.StringTokenizer;
 | 
			
		||||
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
public class TorServiceUtils implements TorServiceConstants {
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	public static int findProcessId(String command) 
 | 
			
		||||
	{
 | 
			
		||||
		int procId = -1;
 | 
			
		||||
		
 | 
			
		||||
		Runtime r = Runtime.getRuntime();
 | 
			
		||||
		    	
 | 
			
		||||
		Process procPs = null;
 | 
			
		||||
		
 | 
			
		||||
        try {
 | 
			
		||||
            
 | 
			
		||||
            procPs = r.exec(SHELL_CMD_PS);
 | 
			
		||||
            
 | 
			
		||||
            BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
 | 
			
		||||
            String line = null;
 | 
			
		||||
            
 | 
			
		||||
            while ((line = reader.readLine())!=null)
 | 
			
		||||
            {
 | 
			
		||||
            	if (line.indexOf(command)!=-1)
 | 
			
		||||
            	{
 | 
			
		||||
            		
 | 
			
		||||
            		StringTokenizer st = new StringTokenizer(line," ");
 | 
			
		||||
            		st.nextToken(); //proc owner
 | 
			
		||||
            		
 | 
			
		||||
            		procId = Integer.parseInt(st.nextToken().trim());
 | 
			
		||||
            		
 | 
			
		||||
            		break;
 | 
			
		||||
            	}
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            Log.e(TAG, "error: " + e.getMessage(), e);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return procId;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static Process doCommand(String command, String arg1) 
 | 
			
		||||
	{
 | 
			
		||||
		Log.i(TAG,"executing command: " + command + ' ' + arg1);
 | 
			
		||||
		
 | 
			
		||||
		Runtime r = Runtime.getRuntime();
 | 
			
		||||
		    	
 | 
			
		||||
		Process proc = null;
 | 
			
		||||
		
 | 
			
		||||
		StringBuilder log = new StringBuilder();
 | 
			
		||||
		
 | 
			
		||||
        try {
 | 
			
		||||
            
 | 
			
		||||
        	proc = r.exec(command + ' ' + arg1);
 | 
			
		||||
            
 | 
			
		||||
/*
 | 
			
		||||
			final char buf[] = new char[1024];
 | 
			
		||||
			// Consume the "stdout"
 | 
			
		||||
			InputStreamReader reader = new InputStreamReader(proc.getInputStream());
 | 
			
		||||
			int read=0;
 | 
			
		||||
			while ((read=reader.read(buf)) != -1) {
 | 
			
		||||
				if (log != null) log.append(buf, 0, read);
 | 
			
		||||
			}
 | 
			
		||||
			// Consume the "stderr"
 | 
			
		||||
			reader = new InputStreamReader(proc.getErrorStream());
 | 
			
		||||
			read=0;
 | 
			
		||||
			while ((read=reader.read(buf)) != -1) {
 | 
			
		||||
				if (log != null) log.append(buf, 0, read);
 | 
			
		||||
			}*/
 | 
			
		||||
            
 | 
			
		||||
            Log.i(TAG,"command process exit value: " + proc.exitValue());
 | 
			
		||||
            Log.i(TAG, "shell cmd output: " + log.toString());
 | 
			
		||||
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            Log.e(TAG, "error: " + e.getMessage());
 | 
			
		||||
            Log.e(TAG, "shell cmd output: " + log.toString());
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        return proc;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static boolean hasRoot ()
 | 
			
		||||
	{
 | 
			
		||||
		String[] cmds = {"exit 0"};
 | 
			
		||||
		
 | 
			
		||||
		int code = doRootCommand(cmds,null);
 | 
			
		||||
		
 | 
			
		||||
		return (code == 0);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public static int doRootCommand(String[] cmds, StringBuilder log) 
 | 
			
		||||
	{
 | 
			
		||||
		Log.i(TAG,"executing commands: " + cmds.length);
 | 
			
		||||
		
 | 
			
		||||
		Runtime runtime = Runtime.getRuntime();
 | 
			
		||||
		    	
 | 
			
		||||
		Process proc = null;
 | 
			
		||||
		int exitCode = -1;
 | 
			
		||||
		
 | 
			
		||||
        try {
 | 
			
		||||
            
 | 
			
		||||
        	proc = runtime.exec(cmds[0]);
 | 
			
		||||
 | 
			
		||||
            OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream());
 | 
			
		||||
            
 | 
			
		||||
            for (int i = 1; i < cmds.length; i++)
 | 
			
		||||
            {
 | 
			
		||||
            	out.write(cmds[i]);
 | 
			
		||||
            	out.write("\n");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            out.flush();
 | 
			
		||||
			out.write("exit\n");
 | 
			
		||||
			
 | 
			
		||||
			final char buf[] = new char[1024];
 | 
			
		||||
			// Consume the "stdout"
 | 
			
		||||
			InputStreamReader reader = new InputStreamReader(proc.getInputStream());
 | 
			
		||||
			int read=0;
 | 
			
		||||
			while ((read=reader.read(buf)) != -1) {
 | 
			
		||||
				if (log != null) log.append(buf, 0, read);
 | 
			
		||||
			}
 | 
			
		||||
			// Consume the "stderr"
 | 
			
		||||
			reader = new InputStreamReader(proc.getErrorStream());
 | 
			
		||||
			read=0;
 | 
			
		||||
			while ((read=reader.read(buf)) != -1) {
 | 
			
		||||
				if (log != null) log.append(buf, 0, read);
 | 
			
		||||
			}
 | 
			
		||||
            
 | 
			
		||||
			exitCode = proc.waitFor();
 | 
			
		||||
			
 | 
			
		||||
            Log.i(TAG,"command process exit value: " + exitCode);
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            Log.e(TAG, "Error executing shell cmd: " + e.getMessage(),e);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return exitCode;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||