commit 9f61afcdefa56f5c4fe1d110bbeaedbf78d72021
Author: Nathan Freitas <nat...@freitas.net>
Date:   Mon Sep 26 11:39:07 2016 -0400

    improve tor service event handling and display
---
 .../android/service/TorEventHandler.java           | 328 ++++++++++++++
 .../org/torproject/android/service/TorService.java | 486 ++-------------------
 .../torproject/android/service/TorTransProxy.java  | 229 +++++++++-
 3 files changed, 602 insertions(+), 441 deletions(-)

diff --git 
a/orbotservice/src/main/java/org/torproject/android/service/TorEventHandler.java
 
b/orbotservice/src/main/java/org/torproject/android/service/TorEventHandler.java
new file mode 100644
index 0000000..2af74c8
--- /dev/null
+++ 
b/orbotservice/src/main/java/org/torproject/android/service/TorEventHandler.java
@@ -0,0 +1,328 @@
+package org.torproject.android.service;
+
+import android.text.TextUtils;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.text.NumberFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.torproject.android.control.ConfigEntry;
+import org.torproject.android.control.EventHandler;
+import org.torproject.android.control.TorControlConnection;
+
+/**
+ * Created by n8fr8 on 9/25/16.
+ */
+public class TorEventHandler implements EventHandler, TorServiceConstants {
+
+    private TorService mService;
+
+
+    private long lastRead = -1;
+    private long lastWritten = -1;
+    private long mTotalTrafficWritten = 0;
+    private long mTotalTrafficRead = 0;
+
+    private NumberFormat mNumberFormat = null;
+
+
+    private HashMap<String,Node> hmBuiltNodes = new HashMap<String,Node>();
+
+    public class Node
+    {
+        String status;
+        String id;
+        String name;
+        String ipAddress;
+        String country;
+        String organization;
+    }
+
+    public HashMap<String,Node> getNodes ()
+    {
+        return hmBuiltNodes;
+    }
+
+    public TorEventHandler (TorService service)
+    {
+        mService = service;
+        mNumberFormat = NumberFormat.getInstance(Locale.getDefault()); 
//localized numbers!
+
+    }
+
+    @Override
+    public void message(String severity, String msg) {
+        mService.logNotice(severity + ": " + msg);
+    }
+
+    @Override
+    public void newDescriptors(List<String> orList) {
+    }
+
+    @Override
+    public void orConnStatus(String status, String orName) {
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("orConnStatus (");
+        sb.append(parseNodeName(orName) );
+        sb.append("): ");
+        sb.append(status);
+
+        mService.debug(sb.toString());
+    }
+
+    @Override
+    public void streamStatus(String status, String streamID, String target) {
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("StreamStatus (");
+        sb.append((streamID));
+        sb.append("): ");
+        sb.append(status);
+
+        mService.logNotice(sb.toString());
+    }
+
+    @Override
+    public void unrecognized(String type, String msg) {
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("Message (");
+        sb.append(type);
+        sb.append("): ");
+        sb.append(msg);
+
+        mService.logNotice(sb.toString());
+    }
+
+    @Override
+    public void bandwidthUsed(long read, long written) {
+
+        if (read != lastRead || written != lastWritten)
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.append(formatCount(read));
+            sb.append(" \u2193");
+            sb.append(" / ");
+            sb.append(formatCount(written));
+            sb.append(" \u2191");
+
+            int iconId = R.drawable.ic_stat_tor;
+
+            if (read > 0 || written > 0)
+                iconId = R.drawable.ic_stat_tor_xfer;
+
+            if (mService.hasConnectivity() && Prefs.expandedNotifications())
+                mService.showToolbarNotification(sb.toString(), 
mService.getNotifyId(), iconId);
+
+            mTotalTrafficWritten += written;
+            mTotalTrafficRead += read;
+        }
+
+        lastWritten = written;
+        lastRead = read;
+
+        mService.sendCallbackBandwidth(lastWritten, lastRead, 
mTotalTrafficWritten, mTotalTrafficRead);
+    }
+
+    private String formatCount(long count) {
+        // Converts the supplied argument into a string.
+
+        // Under 2Mb, returns "xxx.xKb"
+        // Over 2Mb, returns "xxx.xxMb"
+        if (mNumberFormat != null)
+            if (count < 1e6)
+                return 
mNumberFormat.format(Math.round((float)((int)(count*10/1024))/10)) + "kbps";
+            else
+                return 
mNumberFormat.format(Math.round((float)((int)(count*100/1024/1024))/100)) + 
"mbps";
+        else
+            return "";
+
+        //return count+" kB";
+    }
+
+    public void circuitStatus(String status, String circID, String path) {
+
+        /* once the first circuit is complete, then announce that Orbot is on*/
+        if (mService.getCurrentStatus() == STATUS_STARTING && 
TextUtils.equals(status, "BUILT"))
+            mService.sendCallbackStatus(STATUS_ON);
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("Circuit (");
+        sb.append((circID));
+        sb.append(") ");
+        sb.append(status);
+        sb.append(": ");
+
+        StringTokenizer st = new StringTokenizer(path,",");
+        Node node = null;
+
+        while (st.hasMoreTokens())
+        {
+            String nodePath = st.nextToken();
+            node = new Node();
+
+            String[] nodeParts;
+
+            if (nodePath.contains("="))
+                nodeParts = nodePath.split("=");
+            else
+                nodeParts = nodePath.split("~");
+
+            if (nodeParts.length == 1)
+            {
+                node.id = nodeParts[0].substring(1);
+                node.name = node.id;
+            }
+            else if (nodeParts.length == 2)
+            {
+                node.id = nodeParts[0].substring(1);
+                node.name = nodeParts[1];
+            }
+
+            node.status = status;
+
+            sb.append(node.name);
+
+            if (st.hasMoreTokens())
+                sb.append (" > ");
+        }
+
+        if (Prefs.useDebugLogging())
+            mService.debug(sb.toString());
+        else if(status.equals("BUILT"))
+            mService.logNotice(sb.toString());
+        else if (status.equals("CLOSED"))
+            mService.logNotice(sb.toString());
+
+        if (Prefs.expandedNotifications())
+        {
+            //get IP from last nodename
+            if(status.equals("BUILT")){
+
+                if (node.ipAddress == null)
+                    mService.exec(new ExternalIPFetcher(node));
+
+                hmBuiltNodes.put(node.id, node);
+            }
+
+            if (status.equals("CLOSED"))
+            {
+                hmBuiltNodes.remove(node.id);
+
+            }
+        }
+
+    }
+
+    private class ExternalIPFetcher implements Runnable {
+
+        private Node mNode;
+        private int MAX_ATTEMPTS = 3;
+        private final static String ONIONOO_BASE_URL = 
"https://onionoo.torproject.org/details?fields=country_name,as_name,or_addresses&lookup=";;
+
+        public ExternalIPFetcher (Node node)
+        {
+            mNode = node;
+        }
+
+        public void run ()
+        {
+
+            for (int i = 0; i < MAX_ATTEMPTS; i++)
+            {
+                if (mService.getControlConnection() != null)
+                {
+                    try {
+
+                        URLConnection conn = null;
+
+                        Proxy proxy = new Proxy(Proxy.Type.HTTP, new 
InetSocketAddress("127.0.0.1", 8118));
+                        conn = new URL(ONIONOO_BASE_URL + 
mNode.id).openConnection(proxy);
+
+                        conn.setRequestProperty("Connection","Close");
+                        conn.setConnectTimeout(60000);
+                        conn.setReadTimeout(60000);
+
+                        InputStream is = conn.getInputStream();
+
+                        BufferedReader reader = new BufferedReader(new 
InputStreamReader(is));
+
+                        // getting JSON string from URL
+
+                        StringBuffer json = new StringBuffer();
+                        String line = null;
+
+                        while ((line = reader.readLine())!=null)
+                            json.append(line);
+
+                        JSONObject jsonNodeInfo = new 
org.json.JSONObject(json.toString());
+
+                        JSONArray jsonRelays = 
jsonNodeInfo.getJSONArray("relays");
+
+                        if (jsonRelays.length() > 0)
+                        {
+                            mNode.ipAddress = 
jsonRelays.getJSONObject(0).getJSONArray("or_addresses").getString(0).split(":")[0];
+                            mNode.country = 
jsonRelays.getJSONObject(0).getString("country_name");
+                            mNode.organization = 
jsonRelays.getJSONObject(0).getString("as_name");
+
+                            StringBuffer sbInfo = new StringBuffer();
+                            sbInfo.append(mNode.ipAddress);
+
+                            if (mNode.country != null)
+                                sbInfo.append(' ').append(mNode.country);
+
+                            if (mNode.organization != null)
+                                sbInfo.append(" 
(").append(mNode.organization).append(')');
+
+                            mService.logNotice(sbInfo.toString());
+
+                        }
+
+                        reader.close();
+                        is.close();
+
+                        break;
+
+                    } catch (Exception e) {
+
+                        mService.debug ("Error getting node details from 
onionoo: " + e.getMessage());
+
+
+                    }
+                }
+            }
+        }
+
+
+    }
+
+    private String parseNodeName(String node)
+    {
+        if (node.indexOf('=')!=-1)
+        {
+            return (node.substring(node.indexOf("=")+1));
+        }
+        else if (node.indexOf('~')!=-1)
+        {
+            return (node.substring(node.indexOf("~")+1));
+        }
+        else
+            return node;
+    }
+}
diff --git 
a/orbotservice/src/main/java/org/torproject/android/service/TorService.java 
b/orbotservice/src/main/java/org/torproject/android/service/TorService.java
index 4140b50..6a0b6ac 100644
--- a/orbotservice/src/main/java/org/torproject/android/service/TorService.java
+++ b/orbotservice/src/main/java/org/torproject/android/service/TorService.java
@@ -77,7 +77,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeoutException;
 
-public class TorService extends Service implements TorServiceConstants, 
OrbotConstants, EventHandler
+public class TorService extends Service implements TorServiceConstants, 
OrbotConstants
 {
     
     private String mCurrentStatus = STATUS_OFF;
@@ -106,14 +106,9 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
     
     private TorTransProxy mTransProxy;
 
-    private long mTotalTrafficWritten = 0;
-    private long mTotalTrafficRead = 0;
-    private boolean mConnectivity = true; 
+    private boolean mConnectivity = true;
     private int mNetworkType = -1;
 
-    private long lastRead = -1;
-    private long lastWritten = -1;
-    
     private NotificationManager mNotificationManager = null;
     private Notification.Builder mNotifyBuilder;
     private Notification mNotification;
@@ -123,8 +118,9 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
 
     private ExecutorService mExecutor = Executors.newFixedThreadPool(1);
 
-    private NumberFormat mNumberFormat = null;
-    
+
+    TorEventHandler mEventHandler;
+
   //  private OrbotVpnManager mVpnManager;
     
     public static File appBinHome;
@@ -133,7 +129,6 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
     public static File fileTor;
     public static File filePolipo;
     public static File fileObfsclient;
-    // public static File fileMeekclient;
     public static File fileXtables;
     public static File fileTorRc;
     public static File filePdnsd;
@@ -198,12 +193,12 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
             mNotificationManager.cancelAll();
         
 
-        hmBuiltNodes.clear();
+        mEventHandler.getNodes().clear();
         mNotificationShowing = false;
     }
                
     @SuppressLint("NewApi")
-    private void showToolbarNotification (String notifyMsg, int notifyType, 
int icon)
+    protected void showToolbarNotification (String notifyMsg, int notifyType, 
int icon)
      {        
          
          //Reusable code.
@@ -258,12 +253,12 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
                  expandedView.setTextViewText(R.id.info, notifyMsg);
              }
 
-             if (hmBuiltNodes.size() > 0)
+             if (mEventHandler.getNodes().size() > 0)
              {
-                 Set<String> itBuiltNodes = hmBuiltNodes.keySet();
+                 Set<String> itBuiltNodes = mEventHandler.getNodes().keySet();
                  for (String key : itBuiltNodes)
                  {
-                     Node node = hmBuiltNodes.get(key);
+                     TorEventHandler.Node node = 
mEventHandler.getNodes().get(key);
                      
                      if (node.ipAddress != null)
                      {
@@ -374,17 +369,6 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
         super.onDestroy();
     }
 
-    /**
-    @Override
-    public void onRevoke ()
-    {
-       //if (mVpnManager != null)
-       //      mVpnManager.onRevoke();
-       
-       super.onRevoke();
-
-    }**/
-
     private void stopTor ()
     {
         mExecutor.execute(new Runnable ()
@@ -515,31 +499,6 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
 
         }
 
-        // try these separately in case one fails, then it can try the next
-        /**
-        File cannotKillFile = null;
-        try {
-               TorServiceUtils.killProcess(fileObfsclient);
-        } catch (IOException e) {
-           // e.printStackTrace();
-            Log.w(OrbotConstants.TAG,"could not kill obfsclient",e);
-            cannotKillFile = fileObfsclient;
-        }
-
-        try {
-               TorServiceUtils.killProcess(filePolipo);
-        } catch (IOException e) {
-            Log.w(OrbotConstants.TAG,"could not kill polipo",e);
-            cannotKillFile = filePolipo;
-        }
-
-        try {
-            TorServiceUtils.killProcess(fileTor);
-        } catch (IOException e) {
-            Log.w(OrbotConstants.TAG,"could not kill tor",e);
-            cannotKillFile = fileTor;
-        }
-         */
     }
 
     private void requestTorRereadConfig() {
@@ -557,7 +516,7 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
         } 
     }
 
-        private void logNotice (String msg)
+    protected void logNotice (String msg)
     {
         if (msg != null && msg.trim().length() > 0)
         {
@@ -584,7 +543,6 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
             fileTorRc = new File(appBinHome, 
TorServiceConstants.TORRC_ASSET_KEY);
             filePdnsd = new File(appBinHome, 
TorServiceConstants.PDNSD_ASSET_KEY);
 
-            mNumberFormat = NumberFormat.getInstance(Locale.getDefault()); 
//localized numbers!
 
             if (mNotificationManager == null)
             {
@@ -627,6 +585,11 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
         Log.i("TorService", "onCreate end");
     }
 
+    protected String getCurrentStatus ()
+    {
+        return mCurrentStatus;
+    }
+
     private void torUpgradeAndConfig() throws IOException, TimeoutException {
         if (isTorUpgradeAndConfigComplete)
             return;
@@ -890,7 +853,7 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
         }
         else
         {
-            ArrayList<TorifiedApp> apps = getApps(this, 
TorServiceUtils.getSharedPrefs(getApplicationContext()));
+            ArrayList<TorifiedApp> apps = TorTransProxy.getApps(this, 
TorServiceUtils.getSharedPrefs(getApplicationContext()));
 
             code = mTransProxy.setTransparentProxyingByApp(this,apps, true);
         }
@@ -923,114 +886,6 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
         return true;
      }
 
-    public static ArrayList<TorifiedApp> getApps (Context context, 
SharedPreferences prefs)
-    {
-
-        String tordAppString = prefs.getString(PREFS_KEY_TORIFIED, "");
-        String[] tordApps;
-
-        StringTokenizer st = new StringTokenizer(tordAppString,"|");
-        tordApps = new String[st.countTokens()];
-        int tordIdx = 0;
-        while (st.hasMoreTokens())
-        {
-            tordApps[tordIdx++] = st.nextToken();
-        }
-
-        Arrays.sort(tordApps);
-
-        //else load the apps up
-        PackageManager pMgr = context.getPackageManager();
-
-        List<ApplicationInfo> lAppInfo = pMgr.getInstalledApplications(0);
-
-        Iterator<ApplicationInfo> itAppInfo = lAppInfo.iterator();
-
-        ArrayList<TorifiedApp> apps = new ArrayList<TorifiedApp>();
-
-        ApplicationInfo aInfo = null;
-
-        int appIdx = 0;
-        TorifiedApp app = null;
-
-        while (itAppInfo.hasNext())
-        {
-            aInfo = itAppInfo.next();
-
-            app = new TorifiedApp();
-
-            try {
-                PackageInfo pInfo = pMgr.getPackageInfo(aInfo.packageName, 
PackageManager.GET_PERMISSIONS);
-
-                if (pInfo != null && pInfo.requestedPermissions != null)
-                {
-                    for (String permInfo:pInfo.requestedPermissions)
-                    {
-                        if (permInfo.equals("android.permission.INTERNET"))
-                        {
-                            app.setUsesInternet(true);
-
-                        }
-                    }
-
-                }
-
-
-            } catch (Exception e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
-            }
-
-            if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1)
-            {
-                //System app
-                app.setUsesInternet(true);
-            }
-
-
-            if (!app.usesInternet())
-                continue;
-            else
-            {
-                apps.add(app);
-            }
-
-
-            app.setEnabled(aInfo.enabled);
-            app.setUid(aInfo.uid);
-            app.setUsername(pMgr.getNameForUid(app.getUid()));
-            app.setProcname(aInfo.processName);
-            app.setPackageName(aInfo.packageName);
-
-            try
-            {
-                app.setName(pMgr.getApplicationLabel(aInfo).toString());
-            }
-            catch (Exception e)
-            {
-                app.setName(aInfo.packageName);
-            }
-
-
-            //app.setIcon(pMgr.getApplicationIcon(aInfo));
-
-            // check if this application is allowed
-            if (Arrays.binarySearch(tordApps, app.getUsername()) >= 0) {
-                app.setTorified(true);
-            }
-            else
-            {
-                app.setTorified(false);
-            }
-
-            appIdx++;
-        }
-
-        Collections.sort(apps);
-
-        return apps;
-    }
-    
     /*
      * activate means whether to apply the users preferences
      * or clear them out
@@ -1046,7 +901,7 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
              mTransProxy = new TorTransProxy(this, fileXtables);
  
          mTransProxy.setTransparentProxyingAll(this, false);
-        ArrayList<TorifiedApp> apps = getApps(this, 
TorServiceUtils.getSharedPrefs(getApplicationContext()));
+        ArrayList<TorifiedApp> apps = TorTransProxy.getApps(this, 
TorServiceUtils.getSharedPrefs(getApplicationContext()));
         mTransProxy.setTransparentProxyingByApp(this, apps, false);
     
          return true;
@@ -1112,6 +967,12 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
         return true;
     }
 
+
+    protected void exec (Runnable runn)
+    {
+        mExecutor.execute(runn);
+    }
+
     private Process exec (String cmd, boolean wait) throws Exception
     {
         Process proc = Runtime.getRuntime().exec(cmd);
@@ -1157,6 +1018,11 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
         logNotice("Polipo is running");
             
     }
+
+    protected TorControlConnection getControlConnection ()
+    {
+        return conn;
+    }
     
     private int initControlConnection (int maxTries, boolean isReconnect) 
throws Exception, RuntimeException
     {
@@ -1298,7 +1164,8 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
            // ...
         logNotice( "adding control port event handler");
 
-        conn.setEventHandler(this);
+        mEventHandler = new TorEventHandler(this);
+        conn.setEventHandler(mEventHandler);
         
         conn.setEvents(Arrays.asList(new String[]{
               "ORCONN", "CIRC", "NOTICE", "WARN", "ERR","BW"}));
@@ -1361,278 +1228,9 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
                              
         }
 
-    @Override
-    public void message(String severity, String msg) {
-        logNotice(severity + ": " + msg);
-    }
 
-    @Override
-    public void newDescriptors(List<String> orList) {
-    }
-
-    @Override
-    public void orConnStatus(String status, String orName) {
-        
-            StringBuilder sb = new StringBuilder();
-            sb.append("orConnStatus (");
-            sb.append(parseNodeName(orName) );
-            sb.append("): ");
-            sb.append(status);
-            
-            debug(sb.toString());
-    }
-
-    @Override
-    public void streamStatus(String status, String streamID, String target) {
-        
-            StringBuilder sb = new StringBuilder();
-            sb.append("StreamStatus (");
-            sb.append((streamID));
-            sb.append("): ");
-            sb.append(status);
-            
-            logNotice(sb.toString());
-    }
-
-    @Override
-    public void unrecognized(String type, String msg) {
-        
-            StringBuilder sb = new StringBuilder();
-            sb.append("Message (");
-            sb.append(type);
-            sb.append("): ");
-            sb.append(msg);
-            
-            logNotice(sb.toString());
-    }
-
-    @Override
-    public void bandwidthUsed(long read, long written) {
     
-        if (read != lastRead || written != lastWritten)
-        {
-            StringBuilder sb = new StringBuilder();                
-            sb.append(formatCount(read));
-            sb.append(" \u2193");            
-            sb.append(" / ");
-            sb.append(formatCount(written));
-            sb.append(" \u2191");            
-               
-            int iconId = R.drawable.ic_stat_tor;
-            
-            if (read > 0 || written > 0)
-                iconId = R.drawable.ic_stat_tor_xfer;
-            
-            if (mConnectivity && Prefs.persistNotifications())
-                  showToolbarNotification(sb.toString(), NOTIFY_ID, iconId);
 
-            mTotalTrafficWritten += written;
-            mTotalTrafficRead += read;
-        }
-        
-        lastWritten = written;
-        lastRead = read;
-        
-        sendCallbackBandwidth(lastWritten, lastRead, mTotalTrafficWritten, 
mTotalTrafficRead);
-    }
-    
-    private String formatCount(long count) {
-        // Converts the supplied argument into a string.
-
-        // Under 2Mb, returns "xxx.xKb"
-        // Over 2Mb, returns "xxx.xxMb"
-       if (mNumberFormat != null)
-               if (count < 1e6)
-                       return 
mNumberFormat.format(Math.round((float)((int)(count*10/1024))/10)) + "kbps";
-               else
-                       return 
mNumberFormat.format(Math.round((float)((int)(count*100/1024/1024))/100)) + 
"mbps";
-       else
-               return "";
-        
-           //return count+" kB";
-    }
-    
-    public void circuitStatus(String status, String circID, String path) {
-        
-        /* once the first circuit is complete, then announce that Orbot is on*/
-        if (mCurrentStatus == STATUS_STARTING && TextUtils.equals(status, 
"BUILT"))
-            sendCallbackStatus(STATUS_ON);
-
-        StringBuilder sb = new StringBuilder();
-        sb.append("Circuit (");
-        sb.append((circID));
-        sb.append(") ");
-        sb.append(status);
-        sb.append(": ");
-        
-        StringTokenizer st = new StringTokenizer(path,",");
-        Node node = null;
-        
-        while (st.hasMoreTokens())
-        {
-            String nodePath = st.nextToken();
-            node = new Node();
-            
-            String[] nodeParts;
-            
-            if (nodePath.contains("="))
-                nodeParts = nodePath.split("=");
-            else
-                nodeParts = nodePath.split("~");
-            
-            if (nodeParts.length == 1)
-            {
-                node.id = nodeParts[0].substring(1);
-                node.name = node.id;
-            }
-            else if (nodeParts.length == 2)
-            {
-                node.id = nodeParts[0].substring(1);
-                node.name = nodeParts[1];
-            }
-            
-            node.status = status;
-            
-            sb.append(node.name);
-            
-            if (st.hasMoreTokens())
-                sb.append (" > ");
-        }
-        
-        if (Prefs.useDebugLogging())
-            debug(sb.toString());
-        else if(status.equals("BUILT"))
-            logNotice(sb.toString());
-        else if (status.equals("CLOSED"))
-            logNotice(sb.toString());
-
-        if (Prefs.expandedNotifications())
-        {
-            //get IP from last nodename
-            if(status.equals("BUILT")){
-                
-                if (node.ipAddress == null)
-                    mExecutor.execute(new ExternalIPFetcher(node));
-                
-                hmBuiltNodes.put(node.id, node);
-            }
-            
-            if (status.equals("CLOSED"))
-            {
-                hmBuiltNodes.remove(node.id);
-                
-            }
-        }
-    
-    }
-    
-    private HashMap<String,Node> hmBuiltNodes = new HashMap<String,Node>();
-    
-    class Node
-    {
-        String status;
-        String id;
-        String name;
-        String ipAddress;
-        String country;
-        String organization;
-    }
-    
-    private class ExternalIPFetcher implements Runnable {
-
-        private Node mNode;
-        private int MAX_ATTEMPTS = 3;
-        private final static String ONIONOO_BASE_URL = 
"https://onionoo.torproject.org/details?fields=country_name,as_name,or_addresses&lookup=";;
-        
-        public ExternalIPFetcher (Node node)
-        {
-            mNode = node;
-        }
-        
-        public void run ()
-        {
-            
-            for (int i = 0; i < MAX_ATTEMPTS; i++)
-            {
-                if (conn != null)
-                {
-                    try {
-
-                       URLConnection conn = null;
-                       
-                        Proxy proxy = new Proxy(Proxy.Type.HTTP, new 
InetSocketAddress("127.0.0.1", 8118));
-                        conn = new URL(ONIONOO_BASE_URL + 
mNode.id).openConnection(proxy);
-    
-                        conn.setRequestProperty("Connection","Close");
-                        conn.setConnectTimeout(60000);
-                        conn.setReadTimeout(60000);
-                        
-                        InputStream is = conn.getInputStream();
-                        
-                        BufferedReader reader = new BufferedReader(new 
InputStreamReader(is));
-    
-                        // getting JSON string from URL
-                        
-                        StringBuffer json = new StringBuffer();
-                        String line = null;
-    
-                        while ((line = reader.readLine())!=null)
-                            json.append(line);
-                        
-                        JSONObject jsonNodeInfo = new 
org.json.JSONObject(json.toString());
-                            
-                        JSONArray jsonRelays = 
jsonNodeInfo.getJSONArray("relays");
-                        
-                        if (jsonRelays.length() > 0)
-                        {
-                            mNode.ipAddress = 
jsonRelays.getJSONObject(0).getJSONArray("or_addresses").getString(0).split(":")[0];
-                            mNode.country = 
jsonRelays.getJSONObject(0).getString("country_name");
-                            mNode.organization = 
jsonRelays.getJSONObject(0).getString("as_name");
-                            
-                            StringBuffer sbInfo = new StringBuffer();
-                            sbInfo.append(mNode.ipAddress);
-                             
-                             if (mNode.country != null)
-                                 sbInfo.append(' ').append(mNode.country);
-                         
-                             if (mNode.organization != null)
-                                 sbInfo.append(" 
(").append(mNode.organization).append(')');
-                         
-                             logNotice(sbInfo.toString());
-                            
-                        }
-                        
-                        reader.close();
-                        is.close();
-                        
-                        break;
-                        
-                    } catch (Exception e) {
-                        
-                        debug ("Error getting node details from onionoo: " + 
e.getMessage());
-                        
-                        
-                    }
-                }
-            }
-        }
-        
-        
-    }
-    
-    private String parseNodeName(String node)
-    {
-        if (node.indexOf('=')!=-1)
-        {
-            return (node.substring(node.indexOf("=")+1));
-        }
-        else if (node.indexOf('~')!=-1)
-        {
-            return (node.substring(node.indexOf("~")+1));
-        }
-        else
-            return node;
-    }
 
         public void processTransparentProxying() {
             try{
@@ -1835,14 +1433,14 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
             return false;
         }
 
-    private void sendCallbackBandwidth(long upload, long download, long 
written, long read)    {
+    protected void sendCallbackBandwidth(long upload, long download, long 
written, long read)    {
         Intent intent = new Intent(LOCAL_ACTION_BANDWIDTH);
 
         intent.putExtra("up",upload);
-             intent.putExtra("down",download);
-             intent.putExtra("written",written);
-             intent.putExtra("read",read);
-             intent.putExtra(EXTRA_STATUS, mCurrentStatus);
+          intent.putExtra("down",download);
+          intent.putExtra("written",written);
+          intent.putExtra("read",read);
+          intent.putExtra(EXTRA_STATUS, mCurrentStatus);
 
         LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
     }
@@ -1859,7 +1457,7 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
 
     }
     
-    private void sendCallbackStatus(String currentStatus) {
+    protected void sendCallbackStatus(String currentStatus) {
         mCurrentStatus = currentStatus;
         Intent intent = getActionStatusIntent(currentStatus);
         // send for Orbot internals, using secure local broadcast
@@ -2401,4 +1999,14 @@ public class TorService extends Service implements 
TorServiceConstants, OrbotCon
 
     }
 
+    public boolean hasConnectivity ()
+    {
+        return mConnectivity;
+    }
+
+    public int getNotifyId ()
+    {
+        return NOTIFY_ID;
+    }
+
 }
diff --git 
a/orbotservice/src/main/java/org/torproject/android/service/TorTransProxy.java 
b/orbotservice/src/main/java/org/torproject/android/service/TorTransProxy.java
index 5f2b29f..86c872a 100644
--- 
a/orbotservice/src/main/java/org/torproject/android/service/TorTransProxy.java
+++ 
b/orbotservice/src/main/java/org/torproject/android/service/TorTransProxy.java
@@ -2,8 +2,17 @@ package org.torproject.android.service;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
 
 import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 
 public class TorTransProxy implements TorServiceConstants {
        
@@ -169,6 +178,114 @@ public class TorTransProxy implements TorServiceConstants 
{
                        script.append(" -t nat -m owner --uid-owner ");
                        script.append(tApp.getUid());
                        script.append(" -F || exit\n");
+    public static ArrayList<TorifiedApp> getApps (Context context, 
SharedPreferences prefs)
+    {
+
+        String tordAppString = prefs.getString(PREFS_KEY_TORIFIED, "");
+        String[] tordApps;
+
+        StringTokenizer st = new StringTokenizer(tordAppString,"|");
+        tordApps = new String[st.countTokens()];
+        int tordIdx = 0;
+        while (st.hasMoreTokens())
+        {
+            tordApps[tordIdx++] = st.nextToken();
+        }
+
+        Arrays.sort(tordApps);
+
+        //else load the apps up
+        PackageManager pMgr = context.getPackageManager();
+
+        List<ApplicationInfo> lAppInfo = pMgr.getInstalledApplications(0);
+
+        Iterator<ApplicationInfo> itAppInfo = lAppInfo.iterator();
+
+        ArrayList<TorifiedApp> apps = new ArrayList<TorifiedApp>();
+
+        ApplicationInfo aInfo = null;
+
+        int appIdx = 0;
+        TorifiedApp app = null;
+
+        while (itAppInfo.hasNext())
+        {
+            aInfo = itAppInfo.next();
+
+            app = new TorifiedApp();
+
+            try {
+                PackageInfo pInfo = pMgr.getPackageInfo(aInfo.packageName, 
PackageManager.GET_PERMISSIONS);
+
+                if (pInfo != null && pInfo.requestedPermissions != null)
+                {
+                    for (String permInfo:pInfo.requestedPermissions)
+                    {
+                        if (permInfo.equals("android.permission.INTERNET"))
+                        {
+                            app.setUsesInternet(true);
+
+                        }
+                    }
+
+                }
+
+
+            } catch (Exception e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+
+            if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1)
+            {
+                //System app
+                app.setUsesInternet(true);
+            }
+
+
+            if (!app.usesInternet())
+                continue;
+            else
+            {
+                apps.add(app);
+            }
+
+
+            app.setEnabled(aInfo.enabled);
+            app.setUid(aInfo.uid);
+            app.setUsername(pMgr.getNameForUid(app.getUid()));
+            app.setProcname(aInfo.processName);
+            app.setPackageName(aInfo.packageName);
+
+            try
+            {
+                app.setName(pMgr.getApplicationLabel(aInfo).toString());
+            }
+            catch (Exception e)
+            {
+                app.setName(aInfo.packageName);
+            }
+
+
+            //app.setIcon(pMgr.getApplicationIcon(aInfo));
+
+            // check if this application is allowed
+            if (Arrays.binarySearch(tordApps, app.getUsername()) >= 0) {
+                app.setTorified(true);
+            }
+            else
+            {
+                app.setTorified(false);
+            }
+
+            appIdx++;
+        }
+
+        Collections.sort(apps);
+
+        return apps;
+    }
+
                
                        script.append(ipTablesPath);
                        script.append(" -t filter -m owner --uid-owner ");
@@ -747,7 +864,115 @@ public class TorTransProxy implements TorServiceConstants 
{
        //      fixTransproxyLeak (context);
                
        return lastExit;
-       }       
-       
+       }
+
+
+       public static ArrayList<TorifiedApp> getApps (Context context, 
SharedPreferences prefs)
+       {
+
+               String tordAppString = 
prefs.getString(OrbotConstants.PREFS_KEY_TORIFIED, "");
+               String[] tordApps;
+
+               StringTokenizer st = new StringTokenizer(tordAppString,"|");
+               tordApps = new String[st.countTokens()];
+               int tordIdx = 0;
+               while (st.hasMoreTokens())
+               {
+                       tordApps[tordIdx++] = st.nextToken();
+               }
+
+               Arrays.sort(tordApps);
+
+               //else load the apps up
+               PackageManager pMgr = context.getPackageManager();
+
+               List<ApplicationInfo> lAppInfo = 
pMgr.getInstalledApplications(0);
+
+               Iterator<ApplicationInfo> itAppInfo = lAppInfo.iterator();
+
+               ArrayList<TorifiedApp> apps = new ArrayList<TorifiedApp>();
+
+               ApplicationInfo aInfo = null;
+
+               int appIdx = 0;
+               TorifiedApp app = null;
+
+               while (itAppInfo.hasNext())
+               {
+                       aInfo = itAppInfo.next();
+
+                       app = new TorifiedApp();
+
+                       try {
+                               PackageInfo pInfo = 
pMgr.getPackageInfo(aInfo.packageName, PackageManager.GET_PERMISSIONS);
+
+                               if (pInfo != null && pInfo.requestedPermissions 
!= null)
+                               {
+                                       for (String 
permInfo:pInfo.requestedPermissions)
+                                       {
+                                               if 
(permInfo.equals("android.permission.INTERNET"))
+                                               {
+                                                       
app.setUsesInternet(true);
+
+                                               }
+                                       }
+
+                               }
+
+
+                       } catch (Exception e) {
+                               // TODO Auto-generated catch block
+                               e.printStackTrace();
+                       }
+
+                       if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1)
+                       {
+                               //System app
+                               app.setUsesInternet(true);
+                       }
+
+
+                       if (!app.usesInternet())
+                               continue;
+                       else
+                       {
+                               apps.add(app);
+                       }
+
+
+                       app.setEnabled(aInfo.enabled);
+                       app.setUid(aInfo.uid);
+                       app.setUsername(pMgr.getNameForUid(app.getUid()));
+                       app.setProcname(aInfo.processName);
+                       app.setPackageName(aInfo.packageName);
+
+                       try
+                       {
+                               
app.setName(pMgr.getApplicationLabel(aInfo).toString());
+                       }
+                       catch (Exception e)
+                       {
+                               app.setName(aInfo.packageName);
+                       }
+
+
+                       //app.setIcon(pMgr.getApplicationIcon(aInfo));
+
+                       // check if this application is allowed
+                       if (Arrays.binarySearch(tordApps, app.getUsername()) >= 
0) {
+                               app.setTorified(true);
+                       }
+                       else
+                       {
+                               app.setTorified(false);
+                       }
+
+                       appIdx++;
+               }
+
+               Collections.sort(apps);
+
+               return apps;
+       }
 
 }



_______________________________________________
tor-commits mailing list
tor-commits@lists.torproject.org
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits

Reply via email to