From ce043943d96cb3e2220e571b404c706a91baf3e0 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 23 Mar 2019 16:42:37 +0000 Subject: [PATCH] SusiDNS: Add import feature (ticket #2447) Box overlap issue remains todo, see ticket #2419 --- apps/susidns/src/build.xml | 13 +++ .../src/i2p/susi/dns/NamingServiceBean.java | 92 ++++++++++++++++++- apps/susidns/src/jsp/addressbook.jsp | 41 ++++++++- .../naming/SingleFileNamingService.java | 4 +- .../resources/themes/susidns/dark/susidns.css | 14 +-- .../themes/susidns/light/susidns.css | 17 ++-- 6 files changed, 159 insertions(+), 22 deletions(-) diff --git a/apps/susidns/src/build.xml b/apps/susidns/src/build.xml index 4957c0638..d50d0fb8b 100644 --- a/apps/susidns/src/build.xml +++ b/apps/susidns/src/build.xml @@ -97,6 +97,19 @@ + + + + + + + + diff --git a/apps/susidns/src/java/src/i2p/susi/dns/NamingServiceBean.java b/apps/susidns/src/java/src/i2p/susi/dns/NamingServiceBean.java index 4426bed4e..330b54795 100644 --- a/apps/susidns/src/java/src/i2p/susi/dns/NamingServiceBean.java +++ b/apps/susidns/src/java/src/i2p/susi/dns/NamingServiceBean.java @@ -21,7 +21,11 @@ package i2p.susi.dns; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.Writer; import java.util.Arrays; import java.util.ArrayList; @@ -34,9 +38,11 @@ import java.util.Properties; import java.util.SortedMap; import net.i2p.client.naming.NamingService; +import net.i2p.client.naming.SingleFileNamingService; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; +import net.i2p.servlet.RequestWrapper; /** * Talk to the NamingService API instead of modifying the hosts.txt files directly, @@ -356,7 +362,7 @@ public class NamingServiceBean extends AddressbookBean action = null; if( message.length() > 0 ) - message = "

" + message + "

"; + message = styleMessage(message); return message; } @@ -494,6 +500,90 @@ public class NamingServiceBean extends AddressbookBean // No post-filtering for hosts.txt naming services. It is what it is. } + /** + * @return messages about this action + * @since 0.9.40 + */ + public String importFile(RequestWrapper wrequest) throws IOException { + String message = ""; + InputStream in = wrequest.getInputStream("file"); + OutputStream out = null; + File tmp = null; + SingleFileNamingService sfns = null; + try { + // non-null but zero bytes if no file entered, don't know why + if (in == null || in.available() <= 0) { + return styleMessage(_t("You must enter a file")); + } + // copy to temp file + tmp = new File(_context.getTempDir(), "susidns-import-" + _context.random().nextLong() + ".txt"); + out = new FileOutputStream(tmp); + DataHelper.copy(in, out); + in.close(); + in = null; + out.close(); + out = null; + // new SingleFileNamingService + sfns = new SingleFileNamingService(_context, tmp.getAbsolutePath()); + // getEntries, copy over + Map entries = sfns.getEntries(); + int count = entries.size(); + if (count <= 0) { + return styleMessage(_t("No entries found in file")); + } else { + NamingService service = getNamingService(); + int added = 0, dup = 0; + Properties nsOptions = new Properties(); + nsOptions.setProperty("list", getFileName()); + String now = Long.toString(_context.clock().now()); + nsOptions.setProperty("m", now); + String filename = wrequest.getFilename("file"); + if (filename != null) + nsOptions.setProperty("s", _t("Imported from file {0}", filename)); + else + nsOptions.setProperty("s", _t("Imported from file")); + for (Map.Entry e : entries.entrySet()) { + String host = e.getKey(); + Destination dest = e.getValue(); + boolean ok = service.putIfAbsent(host, dest, nsOptions); + if (ok) + added++; + else + dup++; + } + StringBuilder buf = new StringBuilder(128); + if (added > 0) + buf.append(styleMessage(ngettext("Loaded {0} entry from file", + "Loaded {0} entries from file", + added))); + if (dup > 0) + buf.append(styleMessage(ngettext("Skipped {0} duplicate entry from file", + "Skipped {0} duplicate entries from file", + dup))); + return buf.toString(); + } + } catch (IOException ioe) { + return styleMessage(_t("Import from file failed") + " - " + ioe); + } finally { + if (in != null) + try { in.close(); } catch (IOException ioe) {} + if (out != null) + try { out.close(); } catch (IOException ioe) {} + // shutdown SFNS + if (sfns != null) + sfns.shutdown(); + if (tmp != null) + tmp.delete(); + } + } + + /** + * @since 0.9.40 + */ + private static String styleMessage(String message) { + return "

" + message + "

"; + } + /** * @since 0.9.34 */ diff --git a/apps/susidns/src/jsp/addressbook.jsp b/apps/susidns/src/jsp/addressbook.jsp index 8d25e46a5..02a8c1fb7 100644 --- a/apps/susidns/src/jsp/addressbook.jsp +++ b/apps/susidns/src/jsp/addressbook.jsp @@ -34,13 +34,18 @@ response.setHeader("Referrer-Policy", "no-referrer"); response.setHeader("Accept-Ranges", "none"); -%> -<%@page pageEncoding="UTF-8"%> -<%@ page contentType="text/html"%> -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +%><%@page pageEncoding="UTF-8" contentType="text/html" import="net.i2p.servlet.RequestWrapper" +%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<% + String importMessages = null; + if (intl._t("Import").equals(request.getParameter("action"))) { + RequestWrapper wrequest = new RequestWrapper(request); + importMessages = book.importFile(wrequest); + } +%> @@ -75,7 +80,11 @@

<%=intl._t("Storage")%>: ${book.displayName}

-
${book.messages}
+
${book.messages}<% + if (importMessages != null) { + %><%=importMessages%><% + } +%>
${book.loadBookMessages} @@ -254,6 +263,28 @@ ${book.loadBookMessages} +<% if (!book.getBook().equals("published")) { %> +
+ + + + +
+

<%=intl._t("Import from hosts.txt file")%>

+ + + + + +
<%=intl._t("File")%>
+

+" > +" > +

+
+
+<% } %> +