SusiDNS: Add import feature (ticket #2447)

Box overlap issue remains todo, see ticket #2419
This commit is contained in:
zzz
2019-03-23 16:42:37 +00:00
parent fea5bd4ada
commit ce043943d9
6 changed files with 159 additions and 22 deletions

View File

@@ -97,6 +97,19 @@
<replace file="WEB-INF/web-out.xml">
<replacefilter token="&lt;!-- precompiled servlets --&gt;" value="${jspc.web.fragment}" />
</replace>
<!-- Add multipart config to servlets that need them -->
<property name="__match1" value="&lt;servlet-class&gt;i2p.susi.dns.jsp." />
<property name="__match2" value="_jsp&lt;/servlet-class&gt;" />
<property name="__class1" value="${__match1}addressbook${__match2}" />
<property name="__multipart" value="&#10;
&lt;multipart-config&gt;&#10;
&lt;max-file-size&gt;67108864&lt;/max-file-size&gt;&#10;
&lt;max-request-size&gt;67108864&lt;/max-request-size&gt;&#10;
&lt;file-size-threshold&gt;262144&lt;/file-size-threshold&gt;&#10;
&lt;/multipart-config&gt;" />
<replace file="WEB-INF/web-out.xml">
<replacefilter token="${__class1}" value="${__class1}${__multipart}" />
</replace>
</target>
<uptodate property="precompilejsp.uptodate" targetfile="WEB-INF/web-out.xml">

View File

@@ -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 = "<p class=\"messages\">" + message + "</p>";
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<String, Destination> 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<String, Destination> 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 "<p class=\"messages\">" + message + "</p>";
}
/**
* @since 0.9.34
*/

View File

@@ -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"%>
<jsp:useBean id="version" class="i2p.susi.dns.VersionBean" scope="application" />
<jsp:useBean id="book" class="i2p.susi.dns.NamingServiceBean" scope="session" />
<jsp:useBean id="intl" class="i2p.susi.dns.Messages" scope="application" />
<%
String importMessages = null;
if (intl._t("Import").equals(request.getParameter("action"))) {
RequestWrapper wrequest = new RequestWrapper(request);
importMessages = book.importFile(wrequest);
}
%>
<jsp:setProperty name="book" property="*" />
<jsp:setProperty name="book" property="resetDeletionMarks" value="1"/>
<c:forEach items="${paramValues.checked}" var="checked">
@@ -75,7 +80,11 @@
<h4><%=intl._t("Storage")%>: ${book.displayName}</h4>
</div>
<div id="messages">${book.messages}</div>
<div id="messages">${book.messages}<%
if (importMessages != null) {
%><%=importMessages%><%
}
%></div>
${book.loadBookMessages}
@@ -254,6 +263,28 @@ ${book.loadBookMessages}
</div>
</form>
<% if (!book.getBook().equals("published")) { %>
<form method="POST" action="addressbook" enctype="multipart/form-data" accept-charset="UTF-8">
<input type="hidden" name="book" value="${book.book}">
<input type="hidden" name="serial" value="<%=susiNonce%>">
<input type="hidden" name="begin" value="0">
<input type="hidden" name="end" value="49">
<div id="import">
<h3><%=intl._t("Import from hosts.txt file")%></h3>
<table>
<tr>
<td><b><%=intl._t("File")%></b></td>
<td><input name="file" type="file" accept=".txt" value="" /></td>
</tr>
</table>
<p class="buttons">
<input class="cancel" type="reset" value="<%=intl._t("Cancel")%>" >
<input class="download" type="submit" name="action" value="<%=intl._t("Import")%>" >
</p>
</div>
</form>
<% } %>
<div id="footer">
<hr>
<p class="footer">susidns v${version.version} &copy; <a href="${version.url}" target="_top">susi</a> 2005</p>