diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java
index 385c62a2842a9b901f4273c10cb28ed6406da2f7..aaa2ea9a58a1b8155143c5ea2f370eb1dd076ee0 100644
--- a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java
+++ b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java
@@ -136,19 +136,21 @@ public class Daemon {
         while (iter.hasNext()) {
             // yes, the EepGet fetch() is done in next()
             long start = System.currentTimeMillis();
-            AddressBook sub = iter.next();
+            AddressBook addressbook = iter.next();
             // SubscriptionIterator puts in a dummy AddressBook with no location if no fetch is done
-            if (DEBUG && log != null && sub.getLocation() != null) {
+            if (DEBUG && log != null && addressbook.getLocation() != null) {
                 long end = System.currentTimeMillis();
-                log.append("Fetch of " + sub.getLocation() + " took " + (end - start));
+                log.append("Fetch of " + addressbook.getLocation() + " took " + (end - start));
                 start = end;
             }
             int old = 0, nnew = 0, invalid = 0, conflict = 0, total = 0;
-            for (Iterator<Map.Entry<String, HostTxtEntry>> eIter = sub.iterator(); eIter.hasNext(); ) {
-                Map.Entry<String, HostTxtEntry> entry = eIter.next();
+            int deleted = 0;
+            for (Map.Entry<String, HostTxtEntry> entry : addressbook) {
+                total++;
                 String key = entry.getKey();
                 boolean isKnown;
-                Destination oldDest = null;
+                // NOT set for text file NamingService
+                Destination oldDest;
                 if (isTextFile) {
                     if (knownNames == null) {
                         // load the hostname set
@@ -156,27 +158,34 @@ public class Daemon {
                         opts.setProperty("file", "hosts.txt");
                         knownNames = router.getNames(opts);
                     }
+                    oldDest = null;
                     isKnown = knownNames.contains(key);
                 } else {
                     oldDest = router.lookup(key);
                     isKnown = oldDest != null;
                 }
                 try {
-                    if (!isKnown) {
+                    HostTxtEntry he = entry.getValue();
+                    Properties hprops = he.getProps();
+                    boolean mustValidate = MUST_VALIDATE || hprops != null;
+                    String action = hprops != null ? hprops.getProperty(HostTxtEntry.PROP_ACTION) : null;
+                    if (mustValidate && !he.hasValidSig()) {
+                        if (log != null) {
+                            if (isKnown)
+                                log.append("Bad signature for old key " + key);
+                            else
+                                log.append("Bad signature for new key " + key);
+                        }
+                        invalid++;
+                    } else if (action != null || !isKnown) {
                         if (AddressBook.isValidKey(key)) {
-                            HostTxtEntry he = entry.getValue();
                             Destination dest = new Destination(he.getDest());
                             Properties props = new OrderedProperties();
-                            props.setProperty("s", sub.getLocation());
-                            if (he.hasValidSig()) {
+                            props.setProperty("s", addressbook.getLocation());
+                            if (mustValidate) {
+                                // sig checked above
                                 props.setProperty("v", "true");
-                            } else if (MUST_VALIDATE) {
-                                // TODO
-                                //if (log != null)
-                                //    log.append("Bad signature for new key " + key);
-                                continue;
                             }
-                            Properties hprops = he.getProps();
                             if (hprops != null) {
                                 // merge in all the received properties
                                 for (Map.Entry<Object, Object> e : hprops.entrySet()) {
@@ -184,11 +193,394 @@ public class Daemon {
                                     props.setProperty(RCVD_PROP_PREFIX + e.getKey(), (String) e.getValue());
                                 }
                             }
+                            if (action != null) {
+                                // Process commands. hprops is non-null.
+                                // Must handle isKnown in each case.
+                                if (action.equals(HostTxtEntry.ACTION_ADDDEST)) {
+                                    // Add an alternate destination (new crypto) for existing hostname
+                                    // Requires new NamingService support if the key exists
+                                    String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
+                                    if (polddest != null) {
+                                        Destination pod = new Destination(polddest);
+                                        // fill in oldDest for .txt naming service
+                                        if (isKnown && isTextFile)
+                                            oldDest = router.lookup(key);
+                                        if (pod.equals(dest)) {
+                                            // invalid
+                                            if (log != null)
+                                                log.append("Action: " + action + " failed because" +
+                                                           " identical old and new destinations for " + key +
+                                                           " from " + addressbook.getLocation());
+                                            invalid++;
+                                            continue;
+                                        } else if (!isKnown) {
+                                            // we didn't know it before, so we'll add it
+                                        } else if (dest.equals(oldDest)) {
+                                            // we knew it before, with the same dest
+                                            old++;
+                                            continue;
+                                        } else if (pod.equals(oldDest)) {
+                                            // checks out, so verify the inner sig
+                                            if (!he.hasValidInnerSig()) {
+                                                if (log != null)
+                                                    log.append("Action: " + action + " failed because" +
+                                                               " inner signature for key " + key +
+                                                               " failed" +
+                                                               " from " + addressbook.getLocation());
+                                                invalid++;
+                                                continue;
+                                            }
+                                            // TODO Requires NamingService support
+                                            // if (isTextFile), do we replace or not? check sigType.isAvailable()
+                                            // router.addAltDest(dest)
+                                            if (log != null)
+                                                log.append("Action: " + action + " unimplemented" +
+                                                           " from " + addressbook.getLocation());
+                                            invalid++;
+                                            continue;
+                                        }
+                                    } else {
+                                        if (log != null)
+                                            log.append("Action: " + action + " failed, missing required parameters");
+                                        invalid++;
+                                        continue;
+                                    }
+                                } else if (action.equals(HostTxtEntry.ACTION_ADDNAME)) {
+                                    // Add an alias for an existing hostname, same dest
+                                    if (isKnown) {
+                                        // could be same or different dest
+                                        old++;
+                                        continue;
+                                    }
+                                    String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
+                                    if (poldname != null) {
+                                        Destination pod = router.lookup(poldname);
+                                        if (pod == null) {
+                                            // we didn't have the old one, so we'll add the new one
+                                        } else if (pod.equals(dest)) {
+                                            // checks out, so we'll add the new one
+                                        } else {
+                                            // mismatch, disallow
+                                            if (log != null)
+                                                log.append("Action: " + action + " failed because" +
+                                                           " destination for old name " + poldname +
+                                                           " does not match" +
+                                                           " from " + addressbook.getLocation());
+                                            invalid++;
+                                            continue;
+                                        }
+                                    } else {
+                                        if (log != null)
+                                            log.append("Action: " + action + " failed, missing required parameters" +
+                                                       " from " + addressbook.getLocation());
+                                        invalid++;
+                                        continue;
+                                    }
+                                } else if (action.equals(HostTxtEntry.ACTION_ADDSUBDOMAIN)) {
+                                    // add a subdomain with verification
+                                    if (isKnown) {
+                                        old++;
+                                        continue;
+                                    }
+                                    String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
+                                    String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
+                                    if (polddest != null && poldname != null) {
+                                        // check for valid subdomain
+                                        if (!AddressBook.isValidKey(poldname) ||
+                                            key.indexOf('.' + poldname) <= 0) {
+                                            if (log != null)
+                                                log.append("Action: " + action + " failed because" +
+                                                           " old name " + poldname +
+                                                           " is invalid" +
+                                                           " from " + addressbook.getLocation());
+                                            invalid++;
+                                            continue;
+                                        }
+                                        Destination pod = new Destination(polddest);
+                                        Destination pod2 = router.lookup(poldname);
+                                        if (pod2 == null) {
+                                            // we didn't have the old name
+                                        } else if (pod.equals(pod2)) {
+                                            // checks out, so verify the inner sig
+                                            if (!he.hasValidInnerSig()) {
+                                                if (log != null)
+                                                    log.append("Action: " + action + " failed because" +
+                                                               " inner signature for old name " + poldname +
+                                                               " failed" +
+                                                               " from " + addressbook.getLocation());
+                                                invalid++;
+                                                continue;
+                                            }
+                                        } else {
+                                            // mismatch, disallow
+                                            if (log != null)
+                                                log.append("Action: " + action + " failed because" +
+                                                           " destination for old name " + poldname +
+                                                           " does not match provided" +
+                                                           " from " + addressbook.getLocation());
+                                            invalid++;
+                                            continue;
+                                        }
+                                    } else {
+                                        if (log != null)
+                                            log.append("Action: " + action + " failed, missing required parameters" +
+                                                       " from " + addressbook.getLocation());
+                                        invalid++;
+                                        continue;
+                                    }
+                                } else if (action.equals(HostTxtEntry.ACTION_CHANGEDEST)) {
+                                    // change destination on an existing entry
+                                    String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
+                                    if (polddest != null) {
+                                        Destination pod = new Destination(polddest);
+                                        // fill in oldDest for .txt naming service
+                                        if (isKnown && isTextFile)
+                                            oldDest = router.lookup(key);
+                                        if (!isKnown) {
+                                            // we didn't have the old name
+                                        } else if (pod.equals(oldDest)) {
+                                            // checks out, so verify the inner sig
+                                            if (!he.hasValidInnerSig()) {
+                                                if (log != null)
+                                                    log.append("Action: " + action + " failed because" +
+                                                               " inner signature for key " + key +
+                                                               " failed" +
+                                                               " from " + addressbook.getLocation());
+                                                invalid++;
+                                                continue;
+                                            }
+                                            // TODO set flag to do non-putifabsent for published below
+                                        } else {
+                                            // mismatch, disallow
+                                            if (log != null)
+                                                log.append("Action: " + action + " failed because" +
+                                                           " destination for key " + key +
+                                                           " does not match provided" +
+                                                           " from " + addressbook.getLocation());
+                                            invalid++;
+                                            continue;
+                                        }
+                                    } else {
+                                        if (log != null)
+                                            log.append("Action: " + action + " failed, missing required parameters" +
+                                                       " from " + addressbook.getLocation());
+                                        invalid++;
+                                        continue;
+                                    }
+                                } else if (action.equals(HostTxtEntry.ACTION_CHANGENAME)) {
+                                    // Delete old name, replace with new
+                                    if (isKnown) {
+                                        old++;
+                                        continue;
+                                    }
+                                    String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
+                                    if (poldname != null) {
+                                        Destination pod = router.lookup(poldname);
+                                        if (pod == null) {
+                                            // we didn't have the old name
+                                        } else if (pod.equals(dest)) {
+                                            // checks out, so we'll delete it
+                                            if (knownNames != null)
+                                                knownNames.remove(poldname);
+                                            boolean success = router.remove(poldname);
+                                            if (success)
+                                                deleted++;
+                                            if (log != null) {
+                                                if (success)
+                                                    log.append("Removed: " + poldname +
+                                                               " to be replaced with " + key +
+                                                               " from " + addressbook.getLocation());
+                                                else
+                                                    log.append("Remove failed for: " + poldname +
+                                                               " to be replaced with " + key +
+                                                               " from " + addressbook.getLocation());
+                                            }
+                                            // now update the published addressbook
+                                            if (published != null) {
+                                                if (publishedNS == null)
+                                                    publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
+                                                success = publishedNS.remove(poldname);
+                                                if (log != null && !success)
+                                                    log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
+                                            }
+                                        } else {
+                                            // mismatch, disallow
+                                            if (log != null)
+                                                log.append("Action: " + action + " failed because" +
+                                                           " destination for old name " + poldname +
+                                                           " does not match new name " + key +
+                                                           " from " + addressbook.getLocation());
+                                            invalid++;
+                                            continue;
+                                        }
+                                    } else {
+                                        if (log != null)
+                                            log.append("Action: " + action + " failed, missing required parameters" +
+                                                       " from " + addressbook.getLocation());
+                                        invalid++;
+                                        continue;
+                                    }
+                                } else if (action.equals(HostTxtEntry.ACTION_REMOVE)) {
+                                    // FIXME can't get here, no key or dest
+                                    // delete this entry
+                                    if (!isKnown) {
+                                        old++;
+                                        continue;
+                                    }
+                                    String polddest = hprops.getProperty(HostTxtEntry.PROP_DEST);
+                                    String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
+                                    if (polddest != null && poldname != null) {
+                                        Destination pod = new Destination(polddest);
+                                        Destination pod2 = router.lookup(poldname);
+                                        if (pod.equals(pod2)) {
+                                            if (knownNames != null)
+                                                knownNames.remove(poldname);
+                                            boolean success = router.remove(poldname);
+                                            if (success)
+                                                deleted++;
+                                            if (log != null) {
+                                                if (success)
+                                                    log.append("Removed: " + poldname +
+                                                               " as requested" +
+                                                               " from " + addressbook.getLocation());
+                                                else
+                                                    log.append("Remove failed for: " + poldname +
+                                                               " as requested" +
+                                                               " from " + addressbook.getLocation());
+                                            }
+                                            // now update the published addressbook
+                                            if (published != null) {
+                                                if (publishedNS == null)
+                                                    publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
+                                                success = publishedNS.remove(poldname);
+                                                if (log != null && !success)
+                                                    log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
+                                            }
+                                        } else if (pod2 != null) {
+                                            // mismatch, disallow
+                                            if (log != null)
+                                                log.append("Action: " + action + " failed because" +
+                                                           " destination for " + poldname +
+                                                           " does not match" +
+                                                           " from " + addressbook.getLocation());
+                                            invalid++;
+                                        }
+                                    } else {
+                                        if (log != null)
+                                            log.append("Action: " + action + " failed, missing required parameters" +
+                                                       " from " + addressbook.getLocation());
+                                        invalid++;
+                                    }
+                                    continue;
+                                } else if (action.equals(HostTxtEntry.ACTION_REMOVEALL)) {
+                                    // FIXME can't get here, no key or dest
+                                    // delete all entries with this destination
+                                    if (!isKnown) {
+                                        old++;
+                                        continue;
+                                    }
+                                    String polddest = hprops.getProperty(HostTxtEntry.PROP_DEST);
+                                    // oldname is optional, but nice because not all books support reverse lookup
+                                    if (polddest != null) {
+                                        Destination pod = new Destination(polddest);
+                                        String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
+                                        if (poldname != null) {
+                                            Destination pod2 = router.lookup(poldname);
+                                            if (pod.equals(pod2)) {
+                                                if (knownNames != null)
+                                                    knownNames.remove(poldname);
+                                                boolean success = router.remove(poldname);
+                                                if (success)
+                                                    deleted++;
+                                                if (log != null) {
+                                                    if (success)
+                                                        log.append("Removed: " + poldname +
+                                                                   " as requested" +
+                                                                   " from " + addressbook.getLocation());
+                                                    else
+                                                        log.append("Remove failed for: " + poldname +
+                                                                   " as requested" +
+                                                                   " from " + addressbook.getLocation());
+                                                }
+                                                // now update the published addressbook
+                                                if (published != null) {
+                                                    if (publishedNS == null)
+                                                        publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
+                                                    success = publishedNS.remove(poldname);
+                                                    if (log != null && !success)
+                                                        log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
+                                                }
+                                            } else if (pod2 != null) {
+                                                // mismatch, disallow
+                                                if (log != null)
+                                                    log.append("Action: " + action + " failed because" +
+                                                               " destination for " + poldname +
+                                                               " does not match" +
+                                                               " from " + addressbook.getLocation());
+                                                invalid++;
+                                            }
+                                        }
+                                        // reverse lookup, delete all
+                                        // There's no NamingService API to get a list of all reverse
+                                        String rev;
+                                        String rev2 = null;
+                                        while ((rev = router.reverseLookup(pod)) != null) {
+                                            // prevent getting stuck from buggy NS
+                                            if (rev.equals(rev2))
+                                                break;
+                                            rev2 = rev;
+                                            // forward check in case hash collision or something
+                                            Destination fwd = router.lookup(rev);
+                                            if (!pod.equals(fwd))
+                                                break;  // can't go around again, fail
+                                            if (knownNames != null)
+                                                knownNames.remove(rev);
+                                            boolean success = router.remove(rev);
+                                            if (success)
+                                                deleted++;
+                                            if (log != null) {
+                                                if (success)
+                                                    log.append("Removed: " + rev +
+                                                               " as requested" +
+                                                               " from " + addressbook.getLocation());
+                                                else
+                                                    log.append("Remove failed for: " + rev +
+                                                               " as requested" +
+                                                               " from " + addressbook.getLocation());
+                                            }
+                                            // now update the published addressbook
+                                            if (published != null) {
+                                                if (publishedNS == null)
+                                                    publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
+                                                success = publishedNS.remove(rev);
+                                                if (log != null && !success)
+                                                    log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + rev);
+                                            }
+                                        }
+                                    } else {
+                                        if (log != null)
+                                            log.append("Action: " + action + " failed, missing required parameters" +
+                                                       " from " + addressbook.getLocation());
+                                        invalid++;
+                                    }
+                                    continue;
+                                } else if (action.equals(HostTxtEntry.ACTION_UPDATE)) {
+                                    if (isKnown) {
+                                        // TODO set flag to do non-putifabsent for published below
+                                    }
+                                } else {
+                                    if (log != null)
+                                        log.append("Action: " + action + " unrecognized" +
+                                                   " from " + addressbook.getLocation());
+                                    invalid++;
+                                    continue;
+                                }
+                            }
                             boolean success = router.put(key, dest, props);
                             if (log != null) {
                                 if (success)
                                     log.append("New address " + key +
-                                               " added to address book. From: " + sub.getLocation());
+                                               " added to address book. From: " + addressbook.getLocation());
                                 else
                                     log.append("Save to naming service " + router + " failed for new key " + key);
                             }
@@ -198,9 +590,7 @@ public class Daemon {
                                     publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
                                 success = publishedNS.putIfAbsent(key, dest, props);
                                 if (log != null && !success) {
-                                    try {
-                                        log.append("Save to published address book " + published.getCanonicalPath() + " failed for new key " + key);
-                                    } catch (IOException ioe) {}
+                                    log.append("Save to published address book " + published.getAbsolutePath() + " failed for new key " + key);
                                 }
                             }
                             if (isTextFile)
@@ -209,43 +599,45 @@ public class Daemon {
                             nnew++;
                         } else if (log != null) {
                             log.append("Bad hostname " + key + " from "
-                                   + sub.getLocation());
+                                   + addressbook.getLocation());
                             invalid++;
                         }        
+                  /****
                     } else if (false && DEBUG && log != null) {
                         // lookup the conflict if we haven't yet (O(n**2) for text file)
                         if (isTextFile)
                             oldDest = router.lookup(key);
                         if (oldDest != null && !oldDest.toBase64().equals(entry.getValue())) {
                             log.append("Conflict for " + key + " from "
-                                       + sub.getLocation()
+                                       + addressbook.getLocation()
                                        + ". Destination in remote address book is "
                                        + entry.getValue());
                             conflict++;
                         } else {
                             old++;
                         }
+                   ****/
                     } else {
                         old++;
                     }
                 } catch (DataFormatException dfe) {
                     if (log != null)
-                        log.append("Invalid b64 for " + key + " From: " + sub.getLocation());
+                        log.append("Invalid b64 for " + key + " From: " + addressbook.getLocation());
                     invalid++;
                 }
-                total++;
             }
             if (DEBUG && log != null && total > 0) {
-                log.append("Merge of " + sub.getLocation() + " into " + router +
+                log.append("Merge of " + addressbook.getLocation() + " into " + router +
                            " took " + (System.currentTimeMillis() - start) + " ms with " +
                            total + " total, " +
                            nnew + " new, " +
                            old + " old, " +
+                           deleted + " deleted, " +
                            invalid + " invalid, " +
                            conflict + " conflicts");
-            }
-            sub.delete();
-        }
+            }  // entries
+            addressbook.delete();
+        }  // subscriptions
         subscriptions.write();
     }
 
diff --git a/apps/addressbook/java/src/net/i2p/addressbook/HostTxtEntry.java b/apps/addressbook/java/src/net/i2p/addressbook/HostTxtEntry.java
index 1540e36c369944572d8bee8de138290c03a35fce..f1934cc3c76512b581246af3b17f512282e9acda 100644
--- a/apps/addressbook/java/src/net/i2p/addressbook/HostTxtEntry.java
+++ b/apps/addressbook/java/src/net/i2p/addressbook/HostTxtEntry.java
@@ -138,6 +138,9 @@ class HostTxtEntry {
         out.newLine();
     }
 
+    /**
+     * Verify with the dest public key using the "sig" property
+     */
     public boolean hasValidSig() {
         if (props == null)
             return false;
@@ -195,6 +198,76 @@ class HostTxtEntry {
         return isValid;
     }
 
+    /**
+     * Verify with the "olddest" property's public key using the "oldsig" property
+     */
+    public boolean hasValidInnerSig() {
+        if (props == null)
+            return false;
+        boolean rv = false;
+        // don't cache result
+        if (true) {
+            StringBuilder buf = new StringBuilder(1024);
+            String sig = null;
+            String olddest = null;
+            buf.append(name);
+            buf.append(KV_SEPARATOR);
+            buf.append(dest);
+            boolean started = false;
+            for (Map.Entry<Object, Object> e : props.entrySet()) {
+                String k = (String) e.getKey();
+                String v = (String) e.getValue();
+                if (k.equals(PROP_SIG)) {
+                    continue;
+                }
+                if (k.equals(PROP_OLDSIG)) {
+                    if (sig != null)
+                        return false;
+                    sig = v;
+                    // remove from the written data
+                    continue;
+                }
+                if (k.equals(PROP_OLDDEST)) {
+                    if (olddest != null)
+                        return false;
+                    olddest = v;
+                }
+                if (started) {
+                    buf.append(PROP_SEPARATOR);
+                } else {
+                    started = true;
+                    buf.append(PROPS_SEPARATOR);
+                }
+                buf.append(k);
+                buf.append(KV_SEPARATOR);
+                buf.append(v);
+            }
+            if (sig == null || olddest == null)
+                return false;
+            byte[] sdata = Base64.decode(sig);
+            if (sdata == null)
+                return false;
+            Destination d;
+            try {
+                d = new Destination(olddest);
+            } catch (DataFormatException dfe) {
+                return false;
+            }
+            SigningPublicKey spk = d.getSigningPublicKey();
+            SigType type = spk.getType();
+            if (type == null)
+                return false;
+            Signature s;
+            try {
+                s = new Signature(type, sdata);
+            } catch (IllegalArgumentException iae) {
+                return false;
+            }
+            rv = DSAEngine.getInstance().verifySignature(s, DataHelper.getUTF8(buf.toString()), spk);
+        }
+        return rv;
+    }
+
     @Override
     public int hashCode() {
         return dest.hashCode();
@@ -213,16 +286,29 @@ class HostTxtEntry {
         return dest.equals(he.getDest());
     }
 
-    /** for testing only */
+    /**
+     * Sign and set the "sig" property
+     * for testing only
+     */
     private void sign(SigningPrivateKey spk) {
+        signIt(spk, PROP_SIG);
+    }
+
+    /**
+     * Sign and set the "oldsig" property
+     * for testing only
+     */
+    private void signInner(SigningPrivateKey spk) {
+        signIt(spk, PROP_OLDSIG);
+    }
+
+    /**
+     * for testing only
+     * @param sigprop The signature property to set
+     */
+    private void signIt(SigningPrivateKey spk, String sigprop) {
         if (props == null)
             throw new IllegalStateException();
-        Destination d;
-        try {
-            d = new Destination(dest);
-        } catch (DataFormatException dfe) {
-            throw new IllegalStateException("bah", dfe);
-        }
         StringBuilder buf = new StringBuilder(1024);
         buf.append(name);
         buf.append(KV_SEPARATOR);
@@ -231,7 +317,7 @@ class HostTxtEntry {
         for (Map.Entry<Object, Object> e : props.entrySet()) {
             String k = (String) e.getKey();
             String v = (String) e.getValue();
-            if (k.equals(PROP_SIG))
+            if (k.equals(sigprop))
                 throw new IllegalStateException();
             if (started) {
                 buf.append(PROP_SEPARATOR);
@@ -246,26 +332,37 @@ class HostTxtEntry {
         Signature s = DSAEngine.getInstance().sign(DataHelper.getUTF8(buf.toString()), spk);
         if (s == null)
             throw new IllegalArgumentException("sig failed");
-        props.setProperty(PROP_SIG, s.toBase64());
+        props.setProperty(sigprop, s.toBase64());
     }
 
     public static void main(String[] args) throws Exception {
+        // outer
         File f = new File("tmp-eepPriv.dat");
+        // inner
+        File f2 = new File("tmp-eepPriv2.dat");
         PrivateKeyFile pkf = new PrivateKeyFile(f);
+        PrivateKeyFile pkf2 = new PrivateKeyFile(f2);
         pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519);
+        pkf2.createIfAbsent(SigType.DSA_SHA1);
         OrderedProperties props = new OrderedProperties();
         props.setProperty("c", "ccccccccccc");
         props.setProperty("a", "aaaa");
+        props.setProperty(PROP_OLDDEST, pkf2.getDestination().toBase64());
         HostTxtEntry he = new HostTxtEntry("foo.i2p", pkf.getDestination().toBase64(), props);
         BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
         out.write("Before signing:\n");
         he.write(out);
         out.flush();
         SigningPrivateKey priv = pkf.getSigningPrivKey();
+        SigningPrivateKey priv2 = pkf2.getSigningPrivKey();
+        he.signInner(priv2);
+        out.write("After signing inner:\n");
+        he.write(out);
         he.sign(priv);
         out.write("After signing:\n");
         he.write(out);
         out.flush();
+        System.out.println("Orig has valid inner sig? " + he.hasValidInnerSig());
         System.out.println("Orig has valid sig? " + he.hasValidSig());
         // now create 2nd, read in
         StringWriter sw = new StringWriter(1024);
@@ -275,7 +372,9 @@ class HostTxtEntry {
         String line = sw.toString();
         line = line.substring(line.indexOf(PROPS_SEPARATOR) + 2);
         HostTxtEntry he2 = new HostTxtEntry("foo.i2p", pkf.getDestination().toBase64(), line);
+        System.out.println("Dupl. has valid inner sig? " + he2.hasValidInnerSig());
         System.out.println("Dupl. has valid sig? " + he2.hasValidSig());
         f.delete();
+        f2.delete();
     }
 }