diff --git a/briar-android/libs/jtorctl-briar.jar b/briar-android/libs/jtorctl-briar.jar
index 1f90213fca321569b1bb89cb8b566c2dcc24be2f..f5753c6337180ddae63602370594f05745b3af22 100644
Binary files a/briar-android/libs/jtorctl-briar.jar and b/briar-android/libs/jtorctl-briar.jar differ
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
index f8c225e9eed02f03f2eb02af0cb96376a2c97e05..cdf700b85a235983573eb8e0d8e9d41314c4c8f6 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
@@ -21,7 +21,6 @@ import java.net.Socket;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 import java.util.Scanner;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -546,34 +545,14 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 		throw new UnsupportedOperationException();
 	}
 
-	public void circuitStatus(String status, String id, List<String> path,
-			Map<String, String> info) {
-		if(LOG.isLoggable(INFO)) {
-			String msg = "Circuit " + id + " " + status;
-			String purpose = info.get("PURPOSE");
-			if(purpose != null) msg += ", purpose: " + purpose;
-			String hsState = info.get("HS_STATE");
-			if(hsState != null) msg += ", state: " + hsState;
-			String rendQuery = info.get("REND_QUERY");
-			if(rendQuery != null) msg += ", service: " + rendQuery;
-			if(!path.isEmpty()) msg += ", path: " + shortenPath(path);
-			LOG.info(msg);
-		}
+	public void circuitStatus(String status, String id, String path) {
+		if(LOG.isLoggable(INFO)) LOG.info("Circuit " + id + " " + status);
 		if(status.equals("BUILT") && !circuitBuilt.getAndSet(true)) {
 			LOG.info("First circuit built");
 			if(isRunning()) callback.pollNow();
 		}
 	}
 
-	private String shortenPath(List<String> path) {
-		StringBuilder s = new StringBuilder();
-		for(String id : path) {
-			if(s.length() > 0) s.append(',');
-			s.append(id.substring(1, 7));
-		}
-		return s.toString();
-	}
-
 	public void streamStatus(String status, String id, String target) {}
 
 	public void orConnStatus(String status, String orName) {
diff --git a/jtorctl.patch b/jtorctl.patch
index 2375100a8046947f981112f921cb1e0fb6fcfa4e..80fee4767a7498bad56cd2d11b95c85189f09774 100644
--- a/jtorctl.patch
+++ b/jtorctl.patch
@@ -1,1064 +1,16 @@
-diff -Bbur jtorctl/net/freehaven/tor/control/EventHandler.java jtorctl-briar/net/freehaven/tor/control/EventHandler.java
---- jtorctl/net/freehaven/tor/control/EventHandler.java	2014-04-02 11:26:56.000000000 +0100
-+++ jtorctl-briar/net/freehaven/tor/control/EventHandler.java	2014-05-14 16:54:29.291301601 +0100
-@@ -2,6 +2,9 @@
- // See LICENSE file for copying information
- package net.freehaven.tor.control;
- 
-+import java.util.List;
-+import java.util.Map;
-+
- /**
-  * Abstract interface whose methods are invoked when Tor sends us an event.
-  *
-@@ -20,10 +23,21 @@
-      *   <li>"CLOSED"   :  circuit closed (was built)</li>
-      *	</ul>
-      * 
--     * <b>circID</b> is the alphanumeric identifier of the affected circuit,
--     * and <b>path</b> is a comma-separated list of alphanumeric ServerIDs.
-+     * <b>circID</b> is the alphanumeric identifier of the affected circuit.
-+     * <b>path</b> contains the alphanumeric ServerIDs of the circuit's routers.
-+     * <b>info</b> may include some or all of the following entries:
-+     * <ul>
-+     *   <li>BUILD_FLAGS: a comma-separated list of the circuit's build
-+     *   flags.</li>
-+     *   <li>PURPOSE: the purpose of the circuit.</li>
-+     *   <li>HS_STATE: the state of the circuit if it is a hidden service
-+     *   circuit.</li>
-+     *   <li>REND_QUERY: the hidden service address if the circuit is a
-+     *   hidden service circuit.</li>
-+     * </ul>
-      */
--    public void circuitStatus(String status, String circID, String path);
-+    public void circuitStatus(String status, String circID, List<String> path,
-+                              Map<String, String> info);
-     /**
-      * Invoked when a stream's status has changed.
-      * Possible values for <b>status</b> are:
-diff -Bbur jtorctl/net/freehaven/tor/control/examples/DebuggingEventHandler.java jtorctl-briar/net/freehaven/tor/control/examples/DebuggingEventHandler.java
---- jtorctl/net/freehaven/tor/control/examples/DebuggingEventHandler.java	2014-04-02 11:26:56.000000000 +0100
-+++ jtorctl-briar/net/freehaven/tor/control/examples/DebuggingEventHandler.java	2014-04-02 11:31:48.000000000 +0100
-@@ -3,12 +3,12 @@
- package net.freehaven.tor.control.examples;
- 
- import java.io.PrintWriter;
--import java.util.Iterator;
-+import java.util.List;
- import net.freehaven.tor.control.EventHandler;
- 
- public class DebuggingEventHandler implements EventHandler {
- 
--    protected PrintWriter out;
-+    private final PrintWriter out;
- 
-     public DebuggingEventHandler(PrintWriter p) {
-         out = p;
-@@ -27,11 +30,13 @@
-         out.println("Bandwidth usage: "+read+" bytes read; "+
-                     written+" bytes written.");
-     }
--    public void newDescriptors(java.util.List<String> orList) {
-+
-+    public void newDescriptors(List<String> orList) {
-         out.println("New descriptors for routers:");
--        for (Iterator<String> i = orList.iterator(); i.hasNext(); )
--            out.println("   "+i.next());
-+        for (String or : orList)
-+            out.println("   "+or);
-     }
-+
-     public void message(String type, String msg) {
-         out.println("["+type+"] "+msg.trim());
-     }
-diff -Bbur jtorctl/net/freehaven/tor/control/examples/Main.java jtorctl-briar/net/freehaven/tor/control/examples/Main.java
---- jtorctl/net/freehaven/tor/control/examples/Main.java	2014-04-02 11:26:56.000000000 +0100
-+++ jtorctl-briar/net/freehaven/tor/control/examples/Main.java	2014-04-02 11:56:39.000000000 +0100
-@@ -2,14 +2,17 @@
- // See LICENSE file for copying information
- package net.freehaven.tor.control.examples;
- 
--import net.freehaven.tor.control.*;
- import java.io.PrintWriter;
-+import java.io.EOFException;
- import java.io.IOException;
-+import java.io.PrintWriter;
-+import java.net.Socket;
- import java.util.ArrayList;
--import java.util.List;
- import java.util.Arrays;
-+import java.util.List;
- import java.util.Map;
--import java.util.Iterator;
-+
-+import net.freehaven.tor.control.*;
- 
- public class Main implements TorControlCommands {
- 
-@@ -34,27 +37,22 @@
-             } else {
-                 System.err.println("Unrecognized command: "+args[0]);
-             }
--        } catch (java.io.EOFException ex) {
-+        } catch (EOFException ex) {
-             System.out.println("Control socket closed by Tor.");
-+        } catch (TorControlError ex) {
-+            System.err.println("Error from Tor process: "+
-+                               ex+" ["+ex.getErrorMsg()+"]");
-         } catch (IOException ex) {
-             System.err.println("IO exception when talking to Tor process: "+
-                                ex);
-             ex.printStackTrace(System.err);
--        } catch (TorControlError ex) {
--            System.err.println("Error from Tor process: "+
--                               ex+" ["+ex.getErrorMsg()+"]");
-         }
-     }
- 
-     private static TorControlConnection getConnection(String[] args,
--                                                      boolean daemon)
--        throws IOException {
--        TorControlConnection conn = TorControlConnection.getConnection(
--                                    new java.net.Socket("127.0.0.1", 9100));
--        //if (conn instanceof TorControlConnection1) {
--        //    System.err.println("Debugging");
--        //    ((TorControlConnection1)conn).setDebugging(System.err);
--        //}
-+        boolean daemon) throws IOException {
-+        Socket s = new Socket("127.0.0.1", 9100);
-+	TorControlConnection conn = new TorControlConnection(s);
-         conn.launchThread(daemon);
-         conn.authenticate(new byte[0]);
-         return conn;
-@@ -87,9 +85,9 @@
-     public static void getConfig(String[] args) throws IOException {
-         // Usage: get-config key key key
-         TorControlConnection conn = getConnection(args);
--        List<ConfigEntry> lst = conn.getConf(Arrays.asList(args).subList(1,args.length));
--        for (Iterator<ConfigEntry> i = lst.iterator(); i.hasNext(); ) {
--            ConfigEntry e = i.next();
-+        List<String> keys = Arrays.asList(args).subList(1, args.length);
-+        List<ConfigEntry> lst = conn.getConf(keys);
-+        for (ConfigEntry e : lst) {
-             System.out.println("KEY: "+e.key);
-             System.out.println("VAL: "+e.value);
-         }
-@@ -97,9 +95,9 @@
- 
-     public static void getInfo(String[] args) throws IOException {
-         TorControlConnection conn = getConnection(args);
--        Map<String,String> m = conn.getInfo(Arrays.asList(args).subList(1,args.length));
--        for (Iterator<Map.Entry<String, String>> i = m.entrySet().iterator(); i.hasNext(); ) {
--            Map.Entry<String,String> e = i.next();
-+        List<String> keys = Arrays.asList(args).subList(1, args.length);
-+        Map<String,String> m = conn.getInfo(keys);
-+        for (Map.Entry<String,String> e : m.entrySet()) {
-             System.out.println("KEY: "+e.getKey());
-             System.out.println("VAL: "+e.getValue());
-         }
-@@ -108,10 +106,7 @@
-     public static void listenForEvents(String[] args) throws IOException {
-         // Usage: listen [circ|stream|orconn|bw|newdesc|info|notice|warn|error]*
-         TorControlConnection conn = getConnection(args, false);
--        ArrayList<String> lst = new ArrayList<String>();
--        for (int i = 1; i < args.length; ++i) {
--            lst.add(args[i]);
--        }
-+        List<String> lst = Arrays.asList(args).subList(1, args.length);
-         conn.setEventHandler(
-             new DebuggingEventHandler(new PrintWriter(System.out, true)));
-         conn.setEvents(lst);
-@@ -130,17 +125,13 @@
-     }
- 
-     public static void authDemo(String[] args) throws IOException {
--
-         PasswordDigest pwd = PasswordDigest.generateDigest();
--        java.net.Socket s = new java.net.Socket("127.0.0.1", 9100);
--        TorControlConnection conn = TorControlConnection.getConnection(s);
-+        Socket s = new java.net.Socket("127.0.0.1", 9100);
-+        TorControlConnection conn = new TorControlConnection(s);
-         conn.launchThread(true);
-         conn.authenticate(new byte[0]);
--
-         conn.setConf("HashedControlPassword", pwd.getHashedPassword());
--
--        conn = TorControlConnection.getConnection(
--                                    new java.net.Socket("127.0.0.1", 9100));
-+        conn = new TorControlConnection(new Socket("127.0.0.1", 9100));
-         conn.launchThread(true);
-         conn.authenticate(pwd.getSecret());
-     }
-diff -Bbur jtorctl/net/freehaven/tor/control/NullEventHandler.java jtorctl-briar/net/freehaven/tor/control/NullEventHandler.java
---- jtorctl/net/freehaven/tor/control/NullEventHandler.java	2014-04-02 11:26:56.000000000 +0100
-+++ jtorctl-briar/net/freehaven/tor/control/NullEventHandler.java	2014-05-14 16:54:43.219370671 +0100
-@@ -2,12 +2,16 @@
- // See LICENSE file for copying information
- package net.freehaven.tor.control;
- 
-+import java.util.List;
-+import java.util.Map;
-+
- /**
-  * Implementation of EventHandler that ignores all events.  Useful
-  * when you only want to override one method.
-  */
- public class NullEventHandler implements EventHandler {
--    public void circuitStatus(String status, String circID, String path) {}
-+    public void circuitStatus(String status, String circID, List<String> path,
-+                              Map<String, String> info) {}
-     public void streamStatus(String status, String streamID, String target) {}
-     public void orConnStatus(String status, String orName) {}
-     public void bandwidthUsed(long read, long written) {}
-diff -Bbur jtorctl/net/freehaven/tor/control/PasswordDigest.java jtorctl-briar/net/freehaven/tor/control/PasswordDigest.java
---- jtorctl/net/freehaven/tor/control/PasswordDigest.java	2014-04-02 11:26:56.000000000 +0100
-+++ jtorctl-briar/net/freehaven/tor/control/PasswordDigest.java	2014-04-02 12:29:20.000000000 +0100
-@@ -2,6 +2,7 @@
- // See LICENSE file for copying information
- package net.freehaven.tor.control;
- 
-+import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import java.security.MessageDigest;
- 
-@@ -13,8 +14,8 @@
-  */
- public class PasswordDigest {
- 
--    byte[] secret;
--    String hashedKey;
-+    private final byte[] secret;
-+    private final String hashedKey;
- 
-     /** Return a new password digest with a random secret and salt. */
-     public static PasswordDigest generateDigest() {
-@@ -41,7 +42,7 @@
-             rng.nextBytes(specifier);
-             specifier[8] = 96;
-         }
--        hashedKey = "16:"+encodeBytes(secretToKey(secret, specifier));
-+        hashedKey = "16:"+Bytes.hex(secretToKey(secret, specifier));
-     }
- 
-     /** Return the secret used to generate this password hash.
-@@ -63,7 +64,7 @@
-         MessageDigest d;
-         try {
-             d = MessageDigest.getInstance("SHA-1");
--        } catch (java.security.NoSuchAlgorithmException ex) {
-+        } catch (NoSuchAlgorithmException ex) {
-             throw new RuntimeException("Can't run without sha-1.");
-         }
-         int c = (specifier[8])&0xff;
-@@ -86,12 +87,5 @@
-         System.arraycopy(specifier, 0, key, 0, 9);
-         return key;
-     }
--
--    /** Return a hexadecimal encoding of a byte array. */
--    // XXX There must be a better way to do this in Java.
--    private static final String encodeBytes(byte[] ba) {
--        return Bytes.hex(ba);
--    }
--
- }
- 
 diff -Bbur jtorctl/net/freehaven/tor/control/TorControlConnection.java jtorctl-briar/net/freehaven/tor/control/TorControlConnection.java
---- jtorctl/net/freehaven/tor/control/TorControlConnection.java	2014-04-02 11:26:56.000000000 +0100
-+++ jtorctl-briar/net/freehaven/tor/control/TorControlConnection.java	2014-05-14 16:59:18.428735366 +0100
-@@ -2,96 +2,94 @@
- // See LICENSE file for copying information
- package net.freehaven.tor.control;
- 
-+import java.io.BufferedReader;
- import java.io.IOException;
--import java.net.SocketException;
-+import java.io.InputStream;
-+import java.io.InputStreamReader;
-+import java.io.OutputStream;
-+import java.io.OutputStreamWriter;
-+import java.io.PrintStream;
-+import java.io.PrintWriter;
-+import java.io.Reader;
-+import java.io.Writer;
-+import java.net.Socket;
- import java.util.ArrayList;
-+import java.util.Arrays;
- import java.util.Collection;
-+import java.util.Collections;
- import java.util.HashMap;
--import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.StringTokenizer;
--import java.util.concurrent.CancellationException;
- 
- /** A connection to a running Tor process as specified in control-spec.txt. */
--public class TorControlConnection implements TorControlCommands
--{
-+public class TorControlConnection implements TorControlCommands {
- 
--    protected EventHandler handler;
-+    private final LinkedList<Waiter> waiters;
-+    private final BufferedReader input;
-+    private final Writer output;
- 
--    protected LinkedList<Waiter> waiters;
-+    private ControlParseThread thread; // Locking: this
- 
--    protected ControlParseThread thread;
-+    private volatile EventHandler handler;
-+    private volatile PrintWriter debugOutput;
-+    private volatile IOException parseThreadException;
- 
--    protected java.io.BufferedReader input;
-+    private static class Waiter {
-     
--    protected java.io.Writer output;
--    
--    protected java.io.PrintWriter debugOutput;
--    
--    static class Waiter {
-         List<ReplyLine> response;
--        public synchronized List<ReplyLine> getResponse() {
--            try {
-+
-+        synchronized List<ReplyLine> getResponse() throws InterruptedException {
-                 while (response == null) {
-                     wait();
-                 }
--            } catch (InterruptedException ex) {
--                throw new CancellationException(
--                    "Please don't interrupt library calls.");
--            }
-             return response;
-         }
--        public synchronized void setResponse(List<ReplyLine> response) {
-+
-+        synchronized void setResponse(List<ReplyLine> response) {
-             this.response = response;
-             notifyAll();
-         }
-     }
- 
--    static class ReplyLine {
--        public String status;
--        public String msg;
--        public String rest;
-+    private static class ReplyLine {
-+
-+        final String status;
-+        final String msg;
-+        final String rest;
- 
-         ReplyLine(String status, String msg, String rest) {
--            this.status = status; this.msg = msg; this.rest = rest;
-+            this.status = status;
-+            this.msg = msg;
-+            this.rest = rest;
-         }
-     }
-     
--    public static TorControlConnection getConnection(java.net.Socket sock)
--        throws IOException
--    {
--        return new TorControlConnection(sock);
--    }
--
-     /** Create a new TorControlConnection to communicate with Tor over
-      * a given socket.  After calling this constructor, it is typical to
-      * call launchThread and authenticate. */
--    public TorControlConnection(java.net.Socket connection)
--        throws IOException {
--        this(connection.getInputStream(), connection.getOutputStream());
-+    public TorControlConnection(Socket s) throws IOException {
-+        this(s.getInputStream(), s.getOutputStream());
-     }
- 
-     /** Create a new TorControlConnection to communicate with Tor over
-      * an arbitrary pair of data streams.
-      */
--    public TorControlConnection(java.io.InputStream i, java.io.OutputStream o) {
--        this(new java.io.InputStreamReader(i),
--             new java.io.OutputStreamWriter(o));
-+    public TorControlConnection(InputStream i, OutputStream o) {
-+        this(new InputStreamReader(i), new OutputStreamWriter(o));
-     }
- 
--    public TorControlConnection(java.io.Reader i, java.io.Writer o) {
--        this.output = o;
--        if (i instanceof java.io.BufferedReader)
--            this.input = (java.io.BufferedReader) i;
-+    public TorControlConnection(Reader i, Writer o) {
-+        if (i instanceof BufferedReader)
-+            input = (BufferedReader) i;
-         else
--            this.input = new java.io.BufferedReader(i);
--
--        this.waiters = new LinkedList<Waiter>();
-+            input = new BufferedReader(i);
-+        output = o;
-+        waiters = new LinkedList<Waiter>();
-     }
- 
--    protected final void writeEscaped(String s) throws IOException {
-+    private final void writeEscaped(String s) throws IOException {
-         StringTokenizer st = new StringTokenizer(s, "\n");
-         while (st.hasMoreTokens()) {
-             String line = st.nextToken();
-@@ -110,12 +108,11 @@
-             debugOutput.print(">> .\n");
-     }
- 
--    protected static final String quote(String s) {
--        StringBuffer sb = new StringBuffer("\"");
-+    private static final String quote(String s) {
-+        StringBuilder sb = new StringBuilder("\"");
-         for (int i = 0; i < s.length(); ++i) {
-             char c = s.charAt(i);
--            switch (c)
--                {
-+            switch (c) {
-                 case '\r':
-                 case '\n':
-                 case '\\':
-@@ -128,7 +125,7 @@
-         return sb.toString();
-     }
- 
--    protected final ArrayList<ReplyLine> readReply() throws IOException {
-+    private ArrayList<ReplyLine> readReply() throws IOException {
-         ArrayList<ReplyLine> reply = new ArrayList<ReplyLine>();
-         char c;
-         do {
-@@ -153,7 +150,7 @@
-             String msg = line.substring(4);
-             String rest = null;
-             if (c == '+') {
--                StringBuffer data = new StringBuffer();
-+                StringBuilder data = new StringBuilder();
-                 while (true) {
-                     line = input.readLine();
-                     if (debugOutput != null)
-@@ -172,8 +169,9 @@
-         return reply;
+--- jtorctl/net/freehaven/tor/control/TorControlConnection.java	2014-10-03 12:21:51.883098440 +0100
++++ jtorctl-briar/net/freehaven/tor/control/TorControlConnection.java	2014-10-03 12:17:07.429687913 +0100
+@@ -728,5 +728,12 @@
+         sendAndWaitForResponse("CLOSECIRCUIT "+circID+
+                                (ifUnused?" IFUNUSED":"")+"\r\n", null);
      }
- 
--    protected synchronized List<ReplyLine> sendAndWaitForResponse(String s,String rest)
--        throws IOException {
-+    private synchronized List<ReplyLine> sendAndWaitForResponse(String s,
-+        String rest) throws IOException {
-+        if (parseThreadException != null) throw parseThreadException;
-         checkThread();
-         Waiter w = new Waiter();
-         if (debugOutput != null)
-@@ -185,38 +183,58 @@
-             output.flush();
-             waiters.addLast(w);
-         }
--        List<ReplyLine> lst = w.getResponse();
--        for (Iterator<ReplyLine> i = lst.iterator(); i.hasNext(); ) {
--            ReplyLine c = i.next();
--            if (! c.status.startsWith("2"))
--                throw new TorControlError("Error reply: "+c.msg);
-+        List<ReplyLine> lst;
-+        try {
-+            lst = w.getResponse();
-+        } catch (InterruptedException ex) {
-+            throw new IOException(ex.toString());
-+        }
-+        for (ReplyLine line : lst) {
-+            if (! line.status.startsWith("2"))
-+                throw new TorControlError("Error reply: "+line.msg);
-         }
-         return lst;
-     }
- 
-     /** Helper: decode a CMD_EVENT command and dispatch it to our
-      * EventHandler (if any). */
--    protected void handleEvent(ArrayList<ReplyLine> events) {
-+    private void handleEvent(ArrayList<ReplyLine> events) {
-         if (handler == null)
-             return;
- 
--        for (Iterator<ReplyLine> i = events.iterator(); i.hasNext(); ) {
--            ReplyLine line = i.next();
-+        for (ReplyLine line : events) {
-             int idx = line.msg.indexOf(' ');
-+            if (idx == -1)
-+                continue;
-             String tp = line.msg.substring(0, idx).toUpperCase();
-             String rest = line.msg.substring(idx+1);
-             if (tp.equals("CIRC")) {
-                 List<String> lst = Bytes.splitStr(null, rest);
--                handler.circuitStatus(lst.get(1),
--                                      lst.get(0),
--                                      lst.get(1).equals("LAUNCHED")
--                                          || lst.size() < 2 ? ""
--                                          : lst.get(2));
-+                int size = lst.size(), firstKeyValue;
-+                List<String> path;
-+                if (size < 3 || lst.get(1).equals("LAUNCHED")) {
-+                    path = Collections.emptyList();
-+                    firstKeyValue = 2;
-+                } else {
-+                    path = Arrays.asList(lst.get(2).split(","));
-+                    path = Collections.unmodifiableList(path);
-+                    firstKeyValue = 3;
-+                }
-+                Map<String, String> info = new HashMap<String, String>();
-+                for (int i = firstKeyValue; i < size; i++) {
-+                    String kv = lst.get(i);
-+                    idx = kv.indexOf('=');
-+                    if (idx >= 0) {
-+                        String key = kv.substring(0, idx);
-+                        String value = kv.substring(idx+1);
-+                        info.put(key, value);
-+                    }
-+                }
-+                info = Collections.unmodifiableMap(info);
-+                handler.circuitStatus(lst.get(1), lst.get(0), path, info);
-             } else if (tp.equals("STREAM")) {
-                 List<String> lst = Bytes.splitStr(null, rest);
--                handler.streamStatus(lst.get(1),
--                                     lst.get(0),
--                                     lst.get(3));
-+                handler.streamStatus(lst.get(1), lst.get(0), lst.get(3));
-                 // XXXX circID.
-             } else if (tp.equals("ORCONN")) {
-                 List<String> lst = Bytes.splitStr(null, rest);
-@@ -240,23 +258,22 @@
-         }
-     }
- 
--
-     /** Sets <b>w</b> as the PrintWriter for debugging output, 
-     * which writes out all messages passed between Tor and the controller.  
--    * Outgoing messages are preceded by "\>\>" and incoming messages are preceded
--    * by "\<\<"
-+    * Outgoing messages are preceded by "\>\>" and incoming messages are
-+    * preceded by "\<\<"
-     */
--    public void setDebugging(java.io.PrintWriter w) {
-+    public void setDebugging(PrintWriter w) {
-         debugOutput = w;
-     }
-     
-     /** Sets <b>s</b> as the PrintStream for debugging output, 
-     * which writes out all messages passed between Tor and the controller.  
--    * Outgoing messages are preceded by "\>\>" and incoming messages are preceded
--    * by "\<\<"
-+    * Outgoing messages are preceded by "\>\>" and incoming messages are
-+    * preceded by "\<\<"
-     */
--    public void setDebugging(java.io.PrintStream s) {
--        debugOutput = new java.io.PrintWriter(s, true);
-+    public void setDebugging(PrintStream s) {
-+        debugOutput = new PrintWriter(s, true);
-     }
- 
-     /** Set the EventHandler object that will be notified of any
-@@ -271,50 +288,43 @@
-      * This is necessary to handle asynchronous events and synchronous
-      * responses that arrive independantly over the same socket.
-      */
--    public Thread launchThread(boolean daemon) {
-+    public synchronized Thread launchThread(boolean daemon) {
-     	ControlParseThread th = new ControlParseThread();
-         if (daemon)
-             th.setDaemon(true);
-         th.start();
--        this.thread = th;
-+        thread = th;
-         return th;
-     }
- 
--    protected class ControlParseThread extends Thread {
--    	boolean stopped = false;
-+    private class ControlParseThread extends Thread {
-+
-         @Override
-     	public void run() {
-             try {
-                 react();
--            } catch (SocketException ex) {
--            	if (stopped) // we expected this exception
--                    return;
--                throw new RuntimeException(ex);
-             } catch (IOException ex) {
--                throw new RuntimeException(ex);
--            }
-+                parseThreadException = ex;
-         }
--        public void stopListening() {
--            this.stopped = true;
-         }
-     }
- 
--    protected final void checkThread() {
-+    private synchronized void checkThread() {
-         if (thread == null)
-             launchThread(true);
-     }
- 
-     /** helper: implement the main background loop. */
--    protected void react() throws IOException {
-+    private void react() throws IOException {
-         while (true) {
-             ArrayList<ReplyLine> lst = readReply();
-             if (lst.isEmpty()) {
-                 // connection has been closed remotely! end the loop!
-                 return;
-             }
--            if ((lst.get(0)).status.startsWith("6"))
-+            if ((lst.get(0)).status.startsWith("6")) {
-                 handleEvent(lst);
--            else {
-+            } else {
-                 Waiter w;
-                 synchronized (waiters) {
-                     w = waiters.removeFirst();
-@@ -324,20 +334,16 @@
-         }
-     }
- 
--    /** Change the value of the configuration option 'key' to 'val'.
--     */
-+    /** Change the value of the configuration option 'key' to 'val'. */
-     public void setConf(String key, String value) throws IOException {
--        List<String> lst = new ArrayList<String>();
--        lst.add(key+" "+value);
--        setConf(lst);
-+        setConf(Arrays.asList(key+" "+value));
-     }
- 
-     /** Change the values of the configuration options stored in kvMap. */
-     public void setConf(Map<String, String> kvMap) throws IOException {
-         List<String> lst = new ArrayList<String>();
--        for (Iterator<Map.Entry<String,String>> it = kvMap.entrySet().iterator(); it.hasNext(); ) {
--            Map.Entry<String,String> ent = it.next();
--            lst.add(ent.getKey()+" "+ent.getValue()+"\n");
-+        for (Map.Entry<String,String> e : kvMap.entrySet()) {
-+            lst.add(e.getKey()+" "+e.getValue()+"\n");
-         }
-         setConf(lst);
-     }
-@@ -345,34 +351,33 @@
-     /** Changes the values of the configuration options stored in
-      * <b>kvList</b>.  Each list element in <b>kvList</b> is expected to be
-      * String of the format "key value".
--     *
-+     * <p>
-      * Tor behaves as though it had just read each of the key-value pairs
-      * from its configuration file.  Keywords with no corresponding values have
-      * their configuration values reset to their defaults.  setConf is
-      * all-or-nothing: if there is an error in any of the configuration settings,
-      * Tor sets none of them.
--     *
-+     * <p>
-      * When a configuration option takes multiple values, or when multiple
-      * configuration keys form a context-sensitive group (see getConf below), then
-      * setting any of the options in a setConf command is taken to reset all of
-      * the others.  For example, if two ORBindAddress values are configured, and a
-      * command arrives containing a single ORBindAddress value, the new
-      * command's value replaces the two old values.
--     * 
-+     * <p>
-      * To remove all settings for a given option entirely (and go back to its
-      * default value), include a String in <b>kvList</b> containing the key and no value.
-      */
-     public void setConf(Collection<String> kvList) throws IOException {
-         if (kvList.size() == 0)
-             return;
--        StringBuffer b = new StringBuffer("SETCONF");
--        for (Iterator<String> it = kvList.iterator(); it.hasNext(); ) {
--            String kv = it.next();
-+        StringBuilder b = new StringBuilder("SETCONF");
-+        for (String kv : kvList) {
-             int i = kv.indexOf(' ');
-             if (i == -1)
-                 b.append(" ").append(kv);
--            b.append(" ").append(kv.substring(0,i)).append("=")
--                .append(quote(kv.substring(i+1)));
-+            b.append(" ").append(kv.substring(0,i)).append("=");
-+            b.append(quote(kv.substring(i+1)));
-         }
-         b.append("\r\n");
-         sendAndWaitForResponse(b.toString(), null);
-@@ -384,9 +389,8 @@
-     public void resetConf(Collection<String> keys) throws IOException {
-         if (keys.size() == 0)
-             return;
--        StringBuffer b = new StringBuffer("RESETCONF");
--        for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
--            String key = it.next();
-+        StringBuilder b = new StringBuilder("RESETCONF");
-+        for (String key : keys) {
-             b.append(" ").append(key);
-         }
-         b.append("\r\n");
-@@ -402,10 +406,10 @@
- 
-     /** Requests the values of the configuration variables listed in <b>keys</b>.
-      * Results are returned as a list of ConfigEntry objects.
--     * 
-+     * <p>
-      * If an option appears multiple times in the configuration, all of its
-      * key-value pairs are returned in order.
--     *
-+     * <p>
-      * Some options are context-sensitive, and depend on other options with
-      * different keywords.  These cannot be fetched directly.  Currently there
-      * is only one such option: clients should use the "HiddenServiceOptions"
-@@ -413,61 +417,63 @@
-      * HiddenServiceNodes, and HiddenServiceExcludeNodes option settings.
-      */
-     public List<ConfigEntry> getConf(Collection<String> keys) throws IOException {
--        StringBuffer sb = new StringBuffer("GETCONF");
--        for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
--            String key = it.next();
-+        StringBuilder sb = new StringBuilder("GETCONF");
-+        for (String key : keys) {
-             sb.append(" ").append(key);
-         }
-         sb.append("\r\n");
-         List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
-         List<ConfigEntry> result = new ArrayList<ConfigEntry>();
--        for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
--            String kv = (it.next()).msg;
-+        for (ReplyLine line : lst) {
-+            String kv = line.msg;
-             int idx = kv.indexOf('=');
--            if (idx >= 0)
--                result.add(new ConfigEntry(kv.substring(0, idx),
--                                           kv.substring(idx+1)));
--            else
-+            if (idx >= 0) {
-+                String key = kv.substring(0, idx);
-+                String value = kv.substring(idx+1);
-+                result.add(new ConfigEntry(key, value));
-+            } else {
-                 result.add(new ConfigEntry(kv));
-         }
-+        }
-         return result;
-     }
- 
-     /** Request that the server inform the client about interesting events.
-      * Each element of <b>events</b> is one of the following Strings: 
--     * ["CIRC" | "STREAM" | "ORCONN" | "BW" | "DEBUG" |
--     *  "INFO" | "NOTICE" | "WARN" | "ERR" | "NEWDESC" | "ADDRMAP"] .
--     * 
-+     * ["CIRC" | "STREAM" | "ORCONN" | "BW" | "DEBUG" | "INFO" | "NOTICE" |
-+     *  "WARN" | "ERR" | "NEWDESC" | "ADDRMAP"] .
-+     * <p>
-      * Any events not listed in the <b>events</b> are turned off; thus, calling
-      * setEvents with an empty <b>events</b> argument turns off all event reporting.
-      */
-     public void setEvents(List<String> events) throws IOException {
--        StringBuffer sb = new StringBuffer("SETEVENTS");
--        for (Iterator<String> it = events.iterator(); it.hasNext(); ) {
--            sb.append(" ").append(it.next());
-+        StringBuilder sb = new StringBuilder("SETEVENTS");
-+        for (String event : events) {
-+            sb.append(" ").append(event);
-         }
-         sb.append("\r\n");
-         sendAndWaitForResponse(sb.toString(), null);
-     }
- 
-     /** Authenticates the controller to the Tor server.
--     *
-+     * <p>
-      * By default, the current Tor implementation trusts all local users, and 
-      * the controller can authenticate itself by calling authenticate(new byte[0]).
--     *
-+     * <p>
-      * If the 'CookieAuthentication' option is true, Tor writes a "magic cookie"
-      * file named "control_auth_cookie" into its data directory.  To authenticate,
-      * the controller must send the contents of this file in <b>auth</b>.
--     * 
-+     * <p>
-      * If the 'HashedControlPassword' option is set, <b>auth</b> must contain the salted
-      * hash of a secret password.  The salted hash is computed according to the
-      * S2K algorithm in RFC 2440 (OpenPGP), and prefixed with the s2k specifier.
-      * This is then encoded in hexadecimal, prefixed by the indicator sequence
-      * "16:".
--     *
-+     * <p>
-      * You can generate the salt of a password by calling
--     *       'tor --hash-password <password>'
-+     * <tt>'tor --hash-password &lt;password&gt;'</tt>
-      * or by using the provided PasswordDigest class.
-+     * <p>
-      * To authenticate under this scheme, the controller sends Tor the original
-      * secret that was used to generate the password.
-      */
-@@ -505,9 +511,6 @@
-         Waiter w = new Waiter();
-         if (debugOutput != null)
-             debugOutput.print(">> "+s);
--        if (this.thread != null) {
--            this.thread.stopListening();
--    	}
-         synchronized (waiters) {
-             output.write(s);
-             output.flush();
-@@ -519,7 +522,7 @@
-      * addresses should be replaced with connections to the specified replacement
-      * addresses.  Each element of <b>kvLines</b> is a String of the form
-      * "old-address new-address".  This function returns the new address mapping.
--     *
-+     * <p>
-      * The client may decline to provide a body for the original address, and
-      * instead send a special null address ("0.0.0.0" for IPv4, "::0" for IPv6, or
-      * "." for hostname), signifying that the server should choose the original
-@@ -527,56 +530,52 @@
-      * should ensure that it returns an element of address space that is unlikely
-      * to be in actual use.  If there is already an address mapped to the
-      * destination address, the server may reuse that mapping.
--     * 
-+     * <p>
-      * If the original address is already mapped to a different address, the old
-      * mapping is removed.  If the original address and the destination address
-      * are the same, the server removes any mapping in place for the original
-      * address.
--     *
-+     * <p>
-      * Mappings set by the controller last until the Tor process exits:
-      * they never expire. If the controller wants the mapping to last only
-      * a certain time, then it must explicitly un-map the address when that
-      * time has elapsed.
-      */
-     public Map<String,String> mapAddresses(Collection<String> kvLines) throws IOException {
--        StringBuffer sb = new StringBuffer("MAPADDRESS");
--        for (Iterator<String> it = kvLines.iterator(); it.hasNext(); ) {
--            String kv = it.next();
-+        StringBuilder sb = new StringBuilder("MAPADDRESS");
-+        for (String kv : kvLines) {
-             int i = kv.indexOf(' ');
--            sb.append(" ").append(kv.substring(0,i)).append("=")
--                .append(quote(kv.substring(i+1)));
-+            sb.append(" ").append(kv.substring(0,i)).append("=");
-+            sb.append(quote(kv.substring(i+1)));
-         }
-         sb.append("\r\n");
-         List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
-         Map<String,String> result = new HashMap<String,String>();
--        for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
--            String kv = (it.next()).msg;
-+        for (ReplyLine line : lst) {
-+            String kv = line.msg;
-             int idx = kv.indexOf('=');
--            result.put(kv.substring(0, idx),
--                       kv.substring(idx+1));
-+            result.put(kv.substring(0, idx), kv.substring(idx+1));
-         }
-         return result;
-     }
- 
-     public Map<String,String> mapAddresses(Map<String,String> addresses) throws IOException {
-         List<String> kvList = new ArrayList<String>();
--        for (Iterator<Map.Entry<String, String>> it = addresses.entrySet().iterator(); it.hasNext(); ) {
--            Map.Entry<String,String> e = it.next();
-+        for (Map.Entry<String,String> e : addresses.entrySet()) {
-             kvList.add(e.getKey()+" "+e.getValue());
-         }
-         return mapAddresses(kvList);
-     }
- 
-     public String mapAddress(String fromAddr, String toAddr) throws IOException {
--        List<String> lst = new ArrayList<String>();
--        lst.add(fromAddr+" "+toAddr+"\n");
--        Map<String,String> m = mapAddresses(lst);
-+        String s = fromAddr+" "+toAddr+"\n";
-+        Map<String,String> m = mapAddresses(Arrays.asList(s));
-         return m.get(fromAddr);
-     }
- 
-     /** Queries the Tor server for keyed values that are not stored in the torrc
-      * configuration file.  Returns a map of keys to values.
--     *
-+     * <p>
-      * Recognized keys include:
-      * <ul>
-      * <li>"version" : The version of the server's software, including the name
-@@ -605,17 +604,16 @@
-      * </ul>
-      */
-     public Map<String,String> getInfo(Collection<String> keys) throws IOException {
--        StringBuffer sb = new StringBuffer("GETINFO");
--        for (Iterator<String> it = keys.iterator(); it.hasNext(); ) {
--            sb.append(" ").append(it.next());
-+        StringBuilder sb = new StringBuilder("GETINFO");
-+        for (String key : keys) {
-+            sb.append(" ").append(key);
-         }
-         sb.append("\r\n");
-         List<ReplyLine> lst = sendAndWaitForResponse(sb.toString(), null);
-         Map<String,String> m = new HashMap<String,String>();
--        for (Iterator<ReplyLine> it = lst.iterator(); it.hasNext(); ) {
--            ReplyLine line = it.next();
-+        for (ReplyLine line : lst) {
-             int idx = line.msg.indexOf('=');
--            if (idx<0)
-+            if (idx == -1)
-                 break;
-             String k = line.msg.substring(0,idx);
-             String v;
-@@ -629,13 +627,9 @@
-         return m;
-     }
-     
--    
--    
--    /** Return the value of the information field 'key' */
-+    /** Returns the value of the information field 'key' */
-     public String getInfo(String key) throws IOException {
--        List<String> lst = new ArrayList<String>();
--        lst.add(key);
--        Map<String,String> m = getInfo(lst);
-+        Map<String,String> m = getInfo(Arrays.asList(key));
-         return  m.get(key);
-     }
- 
-@@ -644,40 +638,39 @@
-      * to the specified path, or the <b>circID</b> is nonzero, in which case it is a
-      * request for the server to extend an existing circuit with that ID according
-      * to the specified <b>path</b>.
--     *
-+     * <p>
-      * If successful, returns the Circuit ID of the (maybe newly created) circuit.
-      */
-     public String extendCircuit(String circID, String path) throws IOException {
-         List<ReplyLine> lst = sendAndWaitForResponse(
-                           "EXTENDCIRCUIT "+circID+" "+path+"\r\n", null);
--        return (lst.get(0)).msg;
-+        return lst.get(0).msg;
-     }
-     
-     /** Informs the Tor server that the stream specified by <b>streamID</b> should be
-      * associated with the circuit specified by <b>circID</b>.  
--     * 
-+     * <p>
-      * Each stream may be associated with
-      * at most one circuit, and multiple streams may share the same circuit.
-      * Streams can only be attached to completed circuits (that is, circuits that
-      * have sent a circuit status "BUILT" event or are listed as built in a
-      * getInfo circuit-status request).
--     * 
-+     * <p>
-      * If <b>circID</b> is 0, responsibility for attaching the given stream is
-      * returned to Tor.
--     * 
-+     * <p>
-      * By default, Tor automatically attaches streams to
-      * circuits itself, unless the configuration variable
-      * "__LeaveStreamsUnattached" is set to "1".  Attempting to attach streams
-      * via TC when "__LeaveStreamsUnattached" is false may cause a race between
-      * Tor and the controller, as both attempt to attach streams to circuits.
-      */
--    public void attachStream(String streamID, String circID)
--        throws IOException {
-+    public void attachStream(String streamID, String circID) throws IOException {
-         sendAndWaitForResponse("ATTACHSTREAM "+streamID+" "+circID+"\r\n", null);
-     }
- 
-     /** Tells Tor about the server descriptor in <b>desc</b>.
--     * 
-+     * <p>
-      * The descriptor, when parsed, must contain a number of well-specified
-      * fields, including fields for its nickname and identity.
-      */
-@@ -685,12 +678,12 @@
-     // No need for return value?  control-spec.txt says reply is merely "250 OK" on success...
-     public String postDescriptor(String desc) throws IOException {
-         List<ReplyLine> lst = sendAndWaitForResponse("+POSTDESCRIPTOR\r\n", desc);
--        return (lst.get(0)).msg;
-+        return lst.get(0).msg;
-     }
- 
-     /** Tells Tor to change the exit address of the stream identified by <b>streamID</b>
-      * to <b>address</b>. No remapping is performed on the new provided address.
--     * 
-+     * <p>
-      * To be sure that the modified address will be used, this event must be sent
-      * after a new stream event is received, and before attaching this stream to
-      * a circuit.
-@@ -720,8 +713,7 @@
-      *
-      * Tor may hold the stream open for a while to flush any data that is pending.
-      */
--    public void closeStream(String streamID, byte reason)
--        throws IOException {
-+    public void closeStream(String streamID, byte reason) throws IOException {
-         sendAndWaitForResponse("CLOSESTREAM "+streamID+" "+reason+"\r\n",null);
-     }
- 
-@@ -729,8 +721,15 @@
-      * If <b>ifUnused</b> is true, do not close the circuit unless it is unused.
-      */
-     public void closeCircuit(String circID, boolean ifUnused) throws IOException {
--        sendAndWaitForResponse("CLOSECIRCUIT "+circID+
--                               (ifUnused?" IFUNUSED":"")+"\r\n", null);
-+        String arg = ifUnused ? " IFUNUSED" : "";
-+        sendAndWaitForResponse("CLOSECIRCUIT "+circID+arg+"\r\n", null);
-+    }
 +
 +    /** Tells Tor to exit when this control connection is closed. This command
 +     * was added in Tor 0.2.2.28-beta.
 +     */
 +    public void takeOwnership() throws IOException {
 +        sendAndWaitForResponse("TAKEOWNERSHIP\r\n", null);
-     }
++    }
  }
  
-diff -Bbur jtorctl/net/freehaven/tor/control/TorControlError.java jtorctl-briar/net/freehaven/tor/control/TorControlError.java
---- jtorctl/net/freehaven/tor/control/TorControlError.java	2014-04-02 11:26:56.000000000 +0100
-+++ jtorctl-briar/net/freehaven/tor/control/TorControlError.java	2014-04-02 12:28:01.000000000 +0100
-@@ -2,13 +2,17 @@
- // See LICENSE file for copying information
- package net.freehaven.tor.control;
- 
-+import java.io.IOException;
-+
- /**
-  * An exception raised when Tor tells us about an error.
-  */
--public class TorControlError extends RuntimeException {
--    static final long serialVersionUID = 2;
-+public class TorControlError extends IOException {
-+
-+    private static final long serialVersionUID = 3;
-+
-+    private final int errorType;
- 
--    int errorType;
-     public TorControlError(int type, String s) {
-         super(s);
-         errorType = type;
-diff -Bbur jtorctl/net/freehaven/tor/control/TorControlSyntaxError.java jtorctl-briar/net/freehaven/tor/control/TorControlSyntaxError.java
---- jtorctl/net/freehaven/tor/control/TorControlSyntaxError.java	2014-04-02 11:26:56.000000000 +0100
-+++ jtorctl-briar/net/freehaven/tor/control/TorControlSyntaxError.java	2014-04-02 12:27:52.000000000 +0100
-@@ -2,12 +2,16 @@
- // See LICENSE file for copying information
- package net.freehaven.tor.control;
- 
-+import java.io.IOException;
-+
- /**
-  * An exception raised when Tor behaves in an unexpected way.
-  */
--public class TorControlSyntaxError extends RuntimeException {
--    static final long serialVersionUID = 2;
-+public class TorControlSyntaxError extends IOException {
- 
--    public TorControlSyntaxError(String s) { super(s); }
--}
-+    private static final long serialVersionUID = 3;
- 
-+    public TorControlSyntaxError(String s) {
-+        super(s);
-+    }
-+}