diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
index 9df86b3b975fe0f0310433489a86526f3c9ab135..64a0ddb0562aac8a9db9966f0d4071109947ccaa 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -1047,19 +1047,20 @@ public class I2PSnarkServlet extends BasicServlet {
                             File f = new File(name);
                             f.delete();
                             _manager.addMessage(_("Torrent file deleted: {0}", f.getAbsolutePath()));
+                            Storage storage = snark.getStorage();
+                            if (storage == null)
+                                break;
                             List<List<String>> files = meta.getFiles();
-                            String dataFile = snark.getBaseName();
-                            f = new File(_manager.getDataDir(), dataFile);
                             if (files == null) { // single file torrent
-                                if (f.delete())
-                                    _manager.addMessage(_("Data file deleted: {0}", f.getAbsolutePath()));
-                                else
-                                    _manager.addMessage(_("Data file could not be deleted: {0}", f.getAbsolutePath()));
+                                for (File df : storage.getFiles()) {
+                                    // should be only one
+                                    if (df.delete())
+                                        _manager.addMessage(_("Data file deleted: {0}", df.getAbsolutePath()));
+                                    else
+                                        _manager.addMessage(_("Data file could not be deleted: {0}", df.getAbsolutePath()));
+                                }
                                 break;
                             }
-                            Storage storage = snark.getStorage();
-                            if (storage == null)
-                                break;
                             // step 1 delete files
                             for (File df : storage.getFiles()) {
                                 if (df.delete()) {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
index c9a9ab3f35f09c4504d79b3747e4ad4c504a9d76..2766b1e0776f3f551d5148a2a8cb671b99237544 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
@@ -14,7 +14,6 @@ import net.i2p.data.Destination;
 public class UDPSink implements Sink {
 
     /**
-     *  @param src ignored
      *  @throws IllegalArgumentException on DatagramSocket IOException
      */
     public UDPSink(InetAddress host, int port) {
diff --git a/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateChecker.java b/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateChecker.java
index 9d3cb4f8e9e3ca9d7e15915b70f3fd09034323af..1e392053afbb5d8244d13dbb18cd578b8701d295 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateChecker.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateChecker.java
@@ -76,7 +76,7 @@ class DevSU3UpdateChecker extends UpdateRunner {
             _mgr.notifyVersionAvailable(this, _currentURI, UpdateType.ROUTER_DEV_SU3, "", UpdateMethod.HTTP,
                                         _urls, newVersion, RouterVersion.FULL_VERSION);
         } else {
-            updateStatus("<b>" + _("No new version found at {0}", linkify(url)) + "</b>");
+            //updateStatus("<b>" + _("No new version found at {0}", linkify(url)) + "</b>");
             if (_log.shouldWarn())
                 _log.warn("Found old version \"" + newVersion + "\" at " + url);
         }
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigHomeHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigHomeHandler.java
index 16bccdfafd95d9848d8b919964577f5c92e2316b..5e426988e770051042eb3c2a384291c6f9f16cea 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigHomeHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigHomeHandler.java
@@ -58,18 +58,21 @@ public class ConfigHomeHandler extends FormHandler {
             else
                 apps = HomeHelper.buildApps(_context, config);
             if (adding) {
-                String name = getJettyString("name");
+                String name = getJettyString("nofilter_name");
                 if (name == null || name.length() <= 0) {
                     addFormError(_("No name entered"));
                     return;
                 }
-                String url = getJettyString("url");
+                String url = getJettyString("nofilter_url");
                 if (url == null || url.length() <= 0) {
                     addFormError(_("No URL entered"));
                     return;
                 }
-                name = DataHelper.escapeHTML(name).replace(",", "&#44;");   // HomeHelper.S
-                url = DataHelper.escapeHTML(url).replace(",", "&#44;");
+                // these would get double-escaped so we can't do it this way...
+                //name = DataHelper.escapeHTML(name).replace(",", "&#44;");
+                //url = DataHelper.escapeHTML(url).replace(",", "&#44;");
+                name = name.replace(",", ".");
+                url = url.replace(",", "."); // fail
                 HomeHelper.App app = null;
                 if ("1".equals(group))
                     app = new HomeHelper.App(name, "", url, "/themes/console/images/eepsite.png");
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java
index 1569ebc9bb152c20c1099abc96ca3f280a5c7c43..114441e5c15817f4128202497688a5525cce4aaa 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java
@@ -7,6 +7,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 
+import net.i2p.data.DataHelper;
 import net.i2p.router.RouterContext;
 import net.i2p.util.PortMapper;
 
@@ -209,17 +210,22 @@ public class HomeHelper extends HelperBase {
                 buf.append("<img height=\"16\" alt=\"\" src=\"").append(app.icon).append("\">");
             }
             buf.append("</td><td align=\"left\">")
-               .append(app.name)
-               .append("</td><td align=\"left\"><a href=\"")
-               .append(app.url.replace("&", "&amp;"))
-               .append("\">")
-               .append(app.url.replace("&", "&amp;"))
-               .append("</a></td></tr>\n");
+               .append(DataHelper.escapeHTML(app.name))
+               .append("</td><td align=\"left\"><a href=\"");
+            String url = DataHelper.escapeHTML(app.url);
+            buf.append(url)
+               .append("\">");
+            // truncate before escaping
+            if (app.url.length() > 50)
+                buf.append(DataHelper.escapeHTML(app.url.substring(0, 48))).append("&hellip;");
+            else
+                buf.append(url);
+            buf.append("</a></td></tr>\n");
         }
         buf.append("<tr><td colspan=\"2\" align=\"center\"><b>")
            .append(_("Add")).append(":</b>" +
-                   "</td><td align=\"left\"><input type=\"text\" name=\"name\"></td>" +
-                   "<td align=\"left\"><input type=\"text\" size=\"40\" name=\"url\"></td></tr>");
+                   "</td><td align=\"left\"><input type=\"text\" name=\"nofilter_name\"></td>" +
+                   "<td align=\"left\"><input type=\"text\" size=\"40\" name=\"nofilter_url\"></td></tr>");
         buf.append("</table>\n");
         return buf.toString();
     }
diff --git a/core/java/src/net/i2p/data/PrivateKeyFile.java b/core/java/src/net/i2p/data/PrivateKeyFile.java
index 4e1a6d74a71124000f808026e9c71ebdadcbf8dc..96cc8a47b0c220fd4382df9e45008534ed4d1701 100644
--- a/core/java/src/net/i2p/data/PrivateKeyFile.java
+++ b/core/java/src/net/i2p/data/PrivateKeyFile.java
@@ -41,7 +41,7 @@ import net.i2p.util.SecureFileOutputStream;
  *     - Certificate if length != 0
  *  - Private key (256 bytes)
  *  - Signing Private key (20 bytes, or length specified by key certificate)
- * Total 663 bytes
+ * Total: 663 or more bytes
  *</pre>
  *
  * @author welterde, zzz
diff --git a/history.txt b/history.txt
index 79b0fdfd3fcc33bfc3aaec0b6afdd0264689120b..2fa0625154443f59e49c50547ea991c842af5da4 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,8 @@
+2015-05-13 zzz
+ * Console: Fix URLs caught in XSS filter on /confighome (ticket #1569)
+ * i2psnark: Fix deletion of single-file torrent outside snark dir (ticket #1544)
+ * NTCP: Catch race in Reader (ticket #1534)
+
 2015-02-12 dg
  * Job Queue/stats: add stat/graph for amount of scheduled jobs (router.tunnelBacklog)
  * FloodfillMonitorJob:
diff --git a/installer/resources/certificates/plugin/cacapo_at_mail.i2p.crt b/installer/resources/certificates/plugin/cacapo_at_mail.i2p.crt
new file mode 100644
index 0000000000000000000000000000000000000000..f56b88d6bda8b3fca95fb50972b8c30dadeccb3d
--- /dev/null
+++ b/installer/resources/certificates/plugin/cacapo_at_mail.i2p.crt
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFfTCCA2WgAwIBAgIEUTjHEzANBgkqhkiG9w0BAQ0FADBvMQswCQYDVQQGEwJY
+WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
+b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEYMBYGA1UEAwwPY2FjYXBvQG1haWwu
+aTJwMB4XDTE1MDIwOTEyNTQxOFoXDTI1MDIwODEyNTQxOFowbzELMAkGA1UEBhMC
+WFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFub255
+bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGDAWBgNVBAMMD2NhY2Fwb0BtYWls
+LmkycDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJjVqyjEJqCCufjO
+E80hXMPZiQZCiBjSKiA27dTX5rKABI26eLzcKl7e80Ooe9wEGBXEHZCxGIXAFt8x
+EHBP4W2u1dmBLpnz6cGxZRMvlTuCKHAbzdJwsWblruXgRg6EQCrtewJ9yuY5SypM
+WyJEkL68XMiTeg6fsU367ifWeuPnaO9wqL45pjt9raJMYzXZb3dc6WNUIhg0u7w0
+GA4z7X3CZc3f58/4F5ivKOmDd3FqM/suIH6qZJHvQQJZqLtfReLquD5TlqQjcZ1I
+vtfYJWsx3Mx3tyXU4x7CHlXyxM4hEGOgMb041GR8td7AvqM0PLuexvNUHO1wDyWF
+C6lydNlBwOOUXqPZCG5afgjliwAIIt0WoASEUqSFDiRmhaQZyShQ9P7NUg7jo8x1
+SK/YL6agSRfyARvKG+lVoSPlVMdwuP4SGYHW9OA0wlI1fO3aY+q71iP3DFfWsLCh
+hE/KXKzruDdGe0tIQdWaz5Xrv4bLN8Ot5a79TYRFUeY7lCyFP7vqert+l31hiyZS
+gVugjF6zz91F/gtLsjG+y2HdbdlD3TR/+I/dZFuoiZoVPtXGla36CHLrzyTmKPg9
+nZLtrVmOKAfUW1ejYjSeO9Rv05hOsGtPtdi70jw1b7WkUC7Ic8L4HzJE0zDzKwEk
+ESVZiLX9G9b0O9CDQnKxRluuZDmVAgMBAAGjITAfMB0GA1UdDgQWBBT9cbSyt2cH
+nN9RnC6o9TOoPH5QWTANBgkqhkiG9w0BAQ0FAAOCAgEAVMpgq3aTTv4v3ZmSJ1P6
+jZBXX85IdnRUvadXX0HDgqpqs8k3Sm67C0UwpLQHeYw5t6ilSJocCw62pMCgfxwf
+dmJ9VEcFoQSd30BdCMXNmPxAnQ+/INUBPzmcZwe+KlI07IQUsjoEPtRG9LBxwric
+PifjxKzzVgOlPPb5XGNmVLdlncY9Z4v5McZPQx6+hG4CqNULEOrx/xRpQDTsGUem
+AXR/ocHm7dDwUIQrkRPkbPK+urEtqKS+RL5ttQ4myzJWasCiDoAdlDv15X7u2G+i
+E8rTSohtr4Crd4DbNpT11aQHtnympNJCAc7PyRLcQRV3FASXvDUsvwT4dMcPN+M1
+ZR5oatbo9hxy/MPyhQun4awMRvaF7HSKrPI8XJRdJzzufusv662N6A7UX31i5W82
+rnSxfP/haklNfwcBAQ0R3R/MkoURYanJYoHnr2WuAx0yfxNIYlJMX7hfPdWOW6a4
+7nQQAkrgW3knQGlKwCEypjm0tdK0bsUrQ0F91wUUYSUSFuPDPb19ifKXklBoCVlB
+6u3ckHu7LG/YZcHmtsxMRMuT+6LtIs/huFnfs4YhJYggswFJHjEX5PcBfsiQklz+
+ahs+UsJAb+lbMOlWj+LYDdyC4T7ZHT+Ii/JZdBN3WNXiBzNuXGC7bd0KWBgCaFuU
+ZAPV0YlmPjsGRaSl7vfh+cI=
+-----END CERTIFICATE-----
diff --git a/router/java/src/net/i2p/router/transport/ntcp/Reader.java b/router/java/src/net/i2p/router/transport/ntcp/Reader.java
index d16ea85b7da675e0a50a1e64e46a1fb334489c94..1e7746d212061d0c73f33666d24980b9757beffd 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/Reader.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/Reader.java
@@ -98,8 +98,10 @@ class Reader {
                         if (keepReading) {
                             // keep on reading the same one
                         } else {
-                            _liveReads.remove(con);
-                            con = null;
+                            if (con != null) {
+                                _liveReads.remove(con);
+                                con = null;
+                            }
                             if (_pendingConnections.isEmpty()) {
                                 _pendingConnections.wait();
                             } else {
@@ -116,6 +118,10 @@ class Reader {
                         _log.debug("begin read for " + con);
                     try {
                         processRead(con);
+                    } catch (IllegalStateException ise) {
+                        // FailedEstablishState.receive() (race - see below)
+                        if (_log.shouldWarn())
+                            _log.warn("Error in the ntcp reader", ise);
                     } catch (RuntimeException re) {
                         _log.log(Log.CRIT, "Error in the ntcp reader", re);
                     }
@@ -153,6 +159,7 @@ class Reader {
                 EventPumper.releaseBuf(buf);
                 break;
             }
+            // FIXME call est.isCorrupt() before also? throws ISE here... see above
             est.receive(buf);
             EventPumper.releaseBuf(buf);
             if (est.isCorrupt()) {